UNPKG

universal-geocoder

Version:

Universal geocoding abstraction server-side and client-side with multiple built-in providers

376 lines 17.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var provider_1 = require("./.."); var AdminLevel_1 = __importDefault(require("../../AdminLevel")); var error_1 = require("../../error"); var utils_1 = require("../../utils"); var GoogleMapsProvider = /** @class */ (function () { function GoogleMapsProvider(_externalLoader, options) { if (options === void 0) { options = provider_1.defaultProviderOptions; } this.externalLoader = _externalLoader; this.options = __assign(__assign({}, provider_1.defaultProviderOptions), options); if (!this.options.apiKey && !this.options.clientId) { throw new Error('An API key or a client ID is required for the Google Maps provider. Please add it in the "apiKey" or the "clientId" option.'); } if (this.options.clientId && !this.options.secret) { throw new Error('An URL signing secret is required if you use a client ID (Premium only). Please add it in the "secret" option.'); } if (this.options.secret && utils_1.isBrowser()) { throw new Error('The "secret" option cannot be used in a browser environment.'); } if (this.options.countryCodes && this.options.countryCodes.length !== 1) { throw new Error('The "countryCodes" option must have only one country code top-level domain.'); } } GoogleMapsProvider.prototype.geocode = function (query, callback, errorCallback) { var _this = this; var _a, _b, _c, _d, _e, _f, _g; var geocodeQuery = provider_1.ProviderHelpers.getGeocodeQueryFromParameter(query, provider_1.GoogleMapsGeocodeQuery); if (geocodeQuery.getIp()) { throw new Error("The GoogleMaps provider does not support IP geolocation, only location geocoding."); } this.externalLoader.setOptions({ protocol: this.options.useSsl ? "https" : "http", host: "maps.googleapis.com", pathname: "maps/api/geocode/json", }); var params = this.withCommonParams({ address: geocodeQuery.getText(), bounds: geocodeQuery.getBounds() ? ((_a = geocodeQuery.getBounds()) === null || _a === void 0 ? void 0 : _a.latitudeSW) + "," + ((_b = geocodeQuery.getBounds()) === null || _b === void 0 ? void 0 : _b.longitudeSW) + "|" + ((_c = geocodeQuery.getBounds()) === null || _c === void 0 ? void 0 : _c.latitudeNE) + "," + ((_d = geocodeQuery.getBounds()) === null || _d === void 0 ? void 0 : _d.longitudeNE) : undefined, components: geocodeQuery.getComponents() ? (_e = geocodeQuery .getComponents()) === null || _e === void 0 ? void 0 : _e.map(function (component) { return component.name + ":" + component.value; }).join("|") : undefined, region: geocodeQuery.getCountryCodes() ? (_f = geocodeQuery.getCountryCodes()) === null || _f === void 0 ? void 0 : _f.join(",") : (_g = this.options.countryCodes) === null || _g === void 0 ? void 0 : _g.join(","), }, geocodeQuery); if (!callback) { return new Promise(function (resolve, reject) { return _this.executeRequest(params, function (results) { return resolve(results); }, {}, {}, function (error) { return reject(error); }); }); } return this.executeRequest(params, callback, {}, {}, errorCallback); }; GoogleMapsProvider.prototype.geodecode = function (latitudeOrQuery, longitudeOrCallback, callbackOrErrorCallback, errorCallback) { var _this = this; var _a, _b; var reverseQuery = provider_1.ProviderHelpers.getReverseQueryFromParameters(latitudeOrQuery, longitudeOrCallback, provider_1.GoogleMapsReverseQuery); var reverseCallback = provider_1.ProviderHelpers.getCallbackFromParameters(longitudeOrCallback, callbackOrErrorCallback); var reverseErrorCallback = provider_1.ProviderHelpers.getErrorCallbackFromParameters(longitudeOrCallback, callbackOrErrorCallback, errorCallback); this.externalLoader.setOptions({ protocol: this.options.useSsl ? "https" : "http", host: "maps.googleapis.com", pathname: "maps/api/geocode/json", }); var params = this.withCommonParams({ latlng: reverseQuery.getCoordinates().latitude + "," + reverseQuery.getCoordinates().longitude, result_type: reverseQuery.getTypes() ? (_a = reverseQuery.getTypes()) === null || _a === void 0 ? void 0 : _a.join("|") : undefined, location_type: reverseQuery.getPrecisions() ? (_b = reverseQuery.getPrecisions()) === null || _b === void 0 ? void 0 : _b.join("|") : undefined, }, reverseQuery); if (!reverseCallback) { return new Promise(function (resolve, reject) { return _this.executeRequest(params, function (results) { return resolve(results); }, {}, {}, function (error) { return reject(error); }); }); } return this.executeRequest(params, reverseCallback, {}, {}, reverseErrorCallback); }; GoogleMapsProvider.prototype.withCommonParams = function (params, query) { var withCommonParams = __assign(__assign({}, params), { key: this.options.apiKey, client: this.options.clientId, channel: query.getChannel(), language: query.getLocale(), limit: query.getLimit().toString() }); if (this.options.secret) { withCommonParams = __assign(__assign({}, withCommonParams), { signature: GoogleMapsProvider.signQuery(this.options.secret, this.externalLoader.getOptions().pathname || "", withCommonParams) }); } return withCommonParams; }; GoogleMapsProvider.prototype.executeRequest = function (params, callback, headers, body, errorCallback) { var limit = params.limit, externalLoaderParams = __rest(params, ["limit"]); this.externalLoader.executeRequest(externalLoaderParams, function (data) { var errorMessage; switch (data.status) { case "REQUEST_DENIED": errorMessage = "Request has been denied"; if (data.error_message) { errorMessage += ": " + data.error_message; } break; case "OVER_QUERY_LIMIT": errorMessage = "Exceeded daily quota when attempting geocoding request"; if (data.error_message) { errorMessage += ": " + data.error_message; } break; case "OVER_DAILY_LIMIT": errorMessage = "API usage has been limited"; if (data.error_message) { errorMessage += ": " + data.error_message; } break; case "INVALID_REQUEST": errorMessage = "The request is invalid"; if (data.error_message) { errorMessage += ": " + data.error_message; } break; case "UNKNOWN_ERROR": errorMessage = "Unknown error"; if (data.error_message) { errorMessage += ": " + data.error_message; } break; default: // Intentionnaly left empty } if (errorMessage && errorCallback) { errorCallback(new error_1.ResponseError(errorMessage, data)); return; } if (errorMessage) { setTimeout(function () { throw new Error(errorMessage); }); return; } var results = data.results; var resultsToRemove = results.length - parseInt(limit || results.length.toString(), 10); if (resultsToRemove > 0) { results.splice(-resultsToRemove); } callback(results.map(function (result) { return GoogleMapsProvider.mapToGeocoded(result); })); }, headers, body, errorCallback); }; GoogleMapsProvider.mapToGeocoded = function (result) { var latitude = result.geometry.location.lat; var longitude = result.geometry.location.lng; var formattedAddress = result.formatted_address; var streetNumber; var streetName; var subLocality; var locality; var postalCode; var region; var country; var countryCode; var adminLevels = []; var placeId = result.place_id; var partialMatch = result.partial_match; var types = result.types; var precision = result.geometry.location_type; var streetAddress; var intersection; var political; var colloquialArea; var ward; var neighborhood; var premise; var subpremise; var naturalFeature; var airport; var park; var pointOfInterest; var establishment; var postalCodeSuffix; var subLocalityLevels = []; result.address_components.forEach(function (addressComponent) { addressComponent.types.forEach(function (type) { switch (type) { case "street_number": streetNumber = addressComponent.long_name; break; case "route": streetName = addressComponent.long_name; break; case "sublocality": subLocality = addressComponent.long_name; break; case "locality": case "postal_town": locality = addressComponent.long_name; break; case "postal_code": postalCode = addressComponent.long_name; break; case "administrative_area_level_1": case "administrative_area_level_2": case "administrative_area_level_3": case "administrative_area_level_4": case "administrative_area_level_5": if (type === "administrative_area_level_1") { region = addressComponent.long_name; } adminLevels.push(AdminLevel_1.default.create({ level: parseInt(type.substr(-1), 10), name: addressComponent.long_name, code: addressComponent.short_name, })); break; case "sublocality_level_1": case "sublocality_level_2": case "sublocality_level_3": case "sublocality_level_4": case "sublocality_level_5": subLocalityLevels.push(AdminLevel_1.default.create({ level: parseInt(type.substr(-1), 10), name: addressComponent.long_name, code: addressComponent.short_name, })); break; case "country": country = addressComponent.long_name; countryCode = addressComponent.short_name; break; case "street_address": streetAddress = addressComponent.long_name; break; case "intersection": intersection = addressComponent.long_name; break; case "political": political = addressComponent.long_name; break; case "colloquial_area": colloquialArea = addressComponent.long_name; break; case "ward": ward = addressComponent.long_name; break; case "neighborhood": neighborhood = addressComponent.long_name; break; case "premise": premise = addressComponent.long_name; break; case "subpremise": subpremise = addressComponent.long_name; break; case "natural_feature": naturalFeature = addressComponent.long_name; break; case "airport": airport = addressComponent.long_name; break; case "park": park = addressComponent.long_name; break; case "point_of_interest": pointOfInterest = addressComponent.long_name; break; case "establishment": establishment = addressComponent.long_name; break; case "postal_code_suffix": postalCodeSuffix = addressComponent.long_name; break; default: } }); }); var geocoded = provider_1.GoogleMapsGeocoded.create({ coordinates: { latitude: latitude, longitude: longitude, }, formattedAddress: formattedAddress, streetNumber: streetNumber, streetName: streetName, subLocality: subLocality, locality: locality, postalCode: postalCode, region: region, country: country, countryCode: countryCode, adminLevels: adminLevels, placeId: placeId, partialMatch: partialMatch, types: types, precision: precision, streetAddress: streetAddress, intersection: intersection, political: political, colloquialArea: colloquialArea, ward: ward, neighborhood: neighborhood, premise: premise, subpremise: subpremise, naturalFeature: naturalFeature, airport: airport, park: park, pointOfInterest: pointOfInterest, establishment: establishment, postalCodeSuffix: postalCodeSuffix, subLocalityLevels: subLocalityLevels, }); if (result.geometry.bounds) { var bounds = result.geometry.bounds; geocoded = geocoded.withBounds({ latitudeSW: bounds.southwest.lat, longitudeSW: bounds.southwest.lng, latitudeNE: bounds.northeast.lat, longitudeNE: bounds.northeast.lng, }); } else if (result.geometry.viewport) { var viewport = result.geometry.viewport; geocoded = geocoded.withBounds({ latitudeSW: viewport.southwest.lat, longitudeSW: viewport.southwest.lng, latitudeNE: viewport.northeast.lat, longitudeNE: viewport.northeast.lng, }); } else if (precision === "ROOFTOP") { // Fake bounds geocoded = geocoded.withBounds({ latitudeSW: latitude, longitudeSW: longitude, latitudeNE: latitude, longitudeNE: longitude, }); } return geocoded; }; GoogleMapsProvider.signQuery = function (secret, pathname, params) { var crypto = utils_1.getRequireFunc()("crypto"); var filteredRequestParams = utils_1.filterUndefinedObjectValues(params); var safeSecret = utils_1.decodeBase64(utils_1.decodeUrlSafeBase64(secret)); var toSign = pathname + "?" + new URLSearchParams(filteredRequestParams).toString(); var hashedSignature = utils_1.encodeUrlSafeBase64(crypto.createHmac("sha1", safeSecret).update(toSign).digest("base64")); return hashedSignature; }; return GoogleMapsProvider; }()); exports.default = GoogleMapsProvider; //# sourceMappingURL=GoogleMapsProvider.js.map