From 01bfa8f692737bd14422f7dc2eae11ed00c19048 Mon Sep 17 00:00:00 2001 From: erinleigh90 <106691284+erinleigh90@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:47:35 -0700 Subject: [PATCH] feat: custom user agent Geo changes for UI handoff (#11632) --- packages/analytics/package.json | 4 +- packages/api-rest/package.json | 2 +- packages/api/package.json | 2 +- packages/auth/package.json | 2 +- packages/core/package.json | 2 +- packages/core/src/Platform/types.ts | 9 +- packages/datastore/package.json | 2 +- packages/geo/internals/package.json | 8 + packages/geo/package.json | 5 +- packages/geo/src/Geo.ts | 214 +--------- .../AmazonLocationServiceProvider.ts | 59 ++- packages/geo/src/internals/InternalGeo.ts | 393 ++++++++++++++++++ packages/geo/src/internals/index.ts | 3 + packages/geo/src/internals/utils.ts | 15 + packages/geo/src/types/Provider.ts | 30 +- packages/notifications/package.json | 4 +- packages/predictions/package.json | 4 +- packages/pubsub/package.json | 4 +- packages/storage/package.json | 2 +- 19 files changed, 516 insertions(+), 248 deletions(-) create mode 100644 packages/geo/internals/package.json create mode 100644 packages/geo/src/internals/InternalGeo.ts create mode 100644 packages/geo/src/internals/index.ts create mode 100644 packages/geo/src/internals/utils.ts diff --git a/packages/analytics/package.json b/packages/analytics/package.json index d177ee66b9e..82f99135a31 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -66,13 +66,13 @@ "name": "Analytics (Pinpoint)", "path": "./lib-esm/index.js", "import": "{ Amplify, Analytics, AWSPinpointProvider }", - "limit": "31.1 kB" + "limit": "31.5 kB" }, { "name": "Analytics (Kinesis)", "path": "./lib-esm/index.js", "import": "{ Amplify, Analytics, AWSKinesisProvider }", - "limit": "60.4 kB" + "limit": "60.5 kB" } ], "jest": { diff --git a/packages/api-rest/package.json b/packages/api-rest/package.json index 33c3fe87385..e62def0ea5a 100644 --- a/packages/api-rest/package.json +++ b/packages/api-rest/package.json @@ -56,7 +56,7 @@ "name": "API (rest client)", "path": "./lib-esm/index.js", "import": "{ Amplify, RestAPI }", - "limit": "31 kB" + "limit": "31.5 kB" } ], "jest": { diff --git a/packages/api/package.json b/packages/api/package.json index c82030025f1..b845608871d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -67,7 +67,7 @@ "name": "API (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, API }", - "limit": "89 kB" + "limit": "89.07 kB" } ], "jest": { diff --git a/packages/auth/package.json b/packages/auth/package.json index cc72002e4e1..07c7f146aba 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -59,7 +59,7 @@ "name": "Auth (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Auth }", - "limit": "55.1 kB" + "limit": "55.15 kB" } ], "jest": { diff --git a/packages/core/package.json b/packages/core/package.json index d368885c82e..34130f26432 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -104,7 +104,7 @@ "name": "Core (Credentials)", "path": "./lib-esm/index.js", "import": "{ Credentials }", - "limit": "13.33 kB" + "limit": "13.45 kB" }, { "name": "Core (Signer)", diff --git a/packages/core/src/Platform/types.ts b/packages/core/src/Platform/types.ts index 09b1bdf5fa7..a4901e1d2e1 100644 --- a/packages/core/src/Platform/types.ts +++ b/packages/core/src/Platform/types.ts @@ -94,7 +94,14 @@ export enum DataStoreAction { GraphQl = '2', } export enum GeoAction { - None = '0', + SearchByText = '1', + SearchForSuggestions = '2', + SearchByPlaceId = '3', + SearchByCoordinates = '4', + SaveGeofences = '5', + GetGeofence = '6', + ListGeofences = '7', + DeleteGeofences = '8', } export enum InAppMessagingAction { None = '0', diff --git a/packages/datastore/package.json b/packages/datastore/package.json index c3dda9eb2a1..999596f124a 100644 --- a/packages/datastore/package.json +++ b/packages/datastore/package.json @@ -72,7 +72,7 @@ "name": "DataStore (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, DataStore }", - "limit": "137 kB" + "limit": "137.1 kB" } ], "jest": { diff --git a/packages/geo/internals/package.json b/packages/geo/internals/package.json new file mode 100644 index 00000000000..0b47f7d5742 --- /dev/null +++ b/packages/geo/internals/package.json @@ -0,0 +1,8 @@ +{ + "name": "@aws-amplify/geo/internals", + "types": "../lib-esm/internals/index.d.ts", + "main": "../lib/internals/index.js", + "module": "../lib-esm/internals/index.js", + "react-native": "../lib-esm/internals/index.js", + "sideEffects": false +} diff --git a/packages/geo/package.json b/packages/geo/package.json index fee59489db0..887736dd1b9 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -43,7 +43,8 @@ "files": [ "lib", "lib-esm", - "src" + "src", + "internals" ], "dependencies": { "@aws-amplify/core": "5.7.0", @@ -57,7 +58,7 @@ "name": "Geo (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Geo }", - "limit": "51.75 kB" + "limit": "52.1 kB" } ], "jest": { diff --git a/packages/geo/src/Geo.ts b/packages/geo/src/Geo.ts index 77c5ecca2f4..3e692cef103 100644 --- a/packages/geo/src/Geo.ts +++ b/packages/geo/src/Geo.ts @@ -1,22 +1,11 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { - Amplify, - ConsoleLogger as Logger, - parseAWSExports, -} from '@aws-amplify/core'; -import { AmazonLocationServiceProvider } from './Providers/AmazonLocationServiceProvider'; - -import { validateCoordinates } from './util'; - +import { Amplify, ConsoleLogger as Logger } from '@aws-amplify/core'; import { Place, - GeoConfig, Coordinates, SearchByTextOptions, SearchByCoordinatesOptions, - GeoProvider, - MapStyle, GeofenceId, GeofenceInput, GeofenceOptions, @@ -27,23 +16,10 @@ import { DeleteGeofencesResults, searchByPlaceIdOptions, } from './types'; +import { InternalGeoClass } from './internals/InternalGeo'; -const logger = new Logger('Geo'); - -const DEFAULT_PROVIDER = 'AmazonLocationService'; -export class GeoClass { +export class GeoClass extends InternalGeoClass { static MODULE = 'Geo'; - /** - * @private - */ - private _config: GeoConfig; - private _pluggables: GeoProvider[]; - - constructor() { - this._config = {}; - this._pluggables = []; - logger.debug('Geo Options', this._config); - } /** * get the name of the module category @@ -53,91 +29,6 @@ export class GeoClass { return GeoClass.MODULE; } - /** - * add plugin into Geo category - * @param {Object} pluggable - an instance of the plugin - */ - public addPluggable(pluggable: GeoProvider) { - if (pluggable && pluggable.getCategory() === 'Geo') { - this._pluggables.push(pluggable); - const config = pluggable.configure( - this._config[pluggable.getProviderName()] - ); - - return config; - } - } - - /** - * Get the plugin object - * @param providerName - the name of the plugin - */ - public getPluggable(providerName: string) { - const pluggable = this._pluggables.find( - pluggable => pluggable.getProviderName() === providerName - ); - if (pluggable === undefined) { - logger.debug('No plugin found with providerName', providerName); - throw new Error('No plugin found in Geo for the provider'); - } else return pluggable; - } - - /** - * Remove the plugin object - * @param providerName - the name of the plugin - */ - public removePluggable(providerName: string) { - this._pluggables = this._pluggables.filter( - pluggable => pluggable.getProviderName() !== providerName - ); - return; - } - - /** - * Configure Geo - * @param {Object} config - Configuration object for Geo - * @return {Object} - Current configuration - */ - configure(config?) { - logger.debug('configure Geo'); - - if (!config) return this._config; - - const amplifyConfig = parseAWSExports(config); - this._config = Object.assign({}, this._config, amplifyConfig.Geo, config); - - this._pluggables.forEach(pluggable => { - pluggable.configure(this._config[pluggable.getProviderName()]); - }); - - if (this._pluggables.length === 0) { - this.addPluggable(new AmazonLocationServiceProvider()); - } - return this._config; - } - - /** - * Get the map resources that are currently available through the provider - * @param {string} provider - * @returns - Array of available map resources - */ - public getAvailableMaps(provider = DEFAULT_PROVIDER): MapStyle[] { - const prov = this.getPluggable(provider); - - return prov.getAvailableMaps(); - } - - /** - * Get the map resource set as default in amplify config - * @param {string} provider - * @returns - Map resource set as the default in amplify config - */ - public getDefaultMap(provider = DEFAULT_PROVIDER): MapStyle { - const prov = this.getPluggable(provider); - - return prov.getDefaultMap(); - } - /** * Search by text input with optional parameters * @param {string} text - The text string that is to be searched for @@ -148,15 +39,7 @@ export class GeoClass { text: string, options?: SearchByTextOptions ): Promise { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - try { - return await prov.searchByText(text, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.searchByText(text, options); } /** @@ -169,15 +52,7 @@ export class GeoClass { text: string, options?: SearchByTextOptions ) { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - try { - return await prov.searchForSuggestions(text, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.searchForSuggestions(text, options); } /** @@ -190,15 +65,7 @@ export class GeoClass { placeId: string, options?: searchByPlaceIdOptions ) { - const providerName = DEFAULT_PROVIDER; - const prov = this.getPluggable(providerName); - - try { - return await prov.searchByPlaceId(placeId, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.searchByPlaceId(placeId, options); } /** @@ -211,17 +78,7 @@ export class GeoClass { coordinates: Coordinates, options?: SearchByCoordinatesOptions ): Promise { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - const [lng, lat] = coordinates; - try { - validateCoordinates(lng, lat); - return await prov.searchByCoordinates(coordinates, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.searchByCoordinates(coordinates, options); } /** @@ -236,23 +93,7 @@ export class GeoClass { geofences: GeofenceInput | GeofenceInput[], options?: GeofenceOptions ): Promise { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - // If single geofence input, make it an array for batch call - let geofenceInputArray; - if (!Array.isArray(geofences)) { - geofenceInputArray = [geofences]; - } else { - geofenceInputArray = geofences; - } - - try { - return await prov.saveGeofences(geofenceInputArray, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.saveGeofences(geofences, options); } /** @@ -265,15 +106,7 @@ export class GeoClass { geofenceId: GeofenceId, options?: GeofenceOptions ): Promise { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - try { - return await prov.getGeofence(geofenceId, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.getGeofence(geofenceId, options); } /** @@ -286,15 +119,7 @@ export class GeoClass { public async listGeofences( options?: ListGeofenceOptions ): Promise { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - try { - return await prov.listGeofences(options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.listGeofences(options); } /** @@ -309,24 +134,7 @@ export class GeoClass { geofenceIds: string | string[], options?: GeofenceOptions ): Promise { - const { providerName = DEFAULT_PROVIDER } = options || {}; - const prov = this.getPluggable(providerName); - - // If single geofence input, make it an array for batch call - let geofenceIdsInputArray; - if (!Array.isArray(geofenceIds)) { - geofenceIdsInputArray = [geofenceIds]; - } else { - geofenceIdsInputArray = geofenceIds; - } - - // Delete geofences - try { - return await prov.deleteGeofences(geofenceIdsInputArray, options); - } catch (error) { - logger.debug(error); - throw error; - } + return super.deleteGeofences(geofenceIds, options); } } diff --git a/packages/geo/src/Providers/AmazonLocationServiceProvider.ts b/packages/geo/src/Providers/AmazonLocationServiceProvider.ts index 918ef822e13..69594e981ce 100644 --- a/packages/geo/src/Providers/AmazonLocationServiceProvider.ts +++ b/packages/geo/src/Providers/AmazonLocationServiceProvider.ts @@ -6,6 +6,7 @@ import { ConsoleLogger as Logger, Credentials, getAmplifyUserAgentObject, + CustomUserAgentDetails, } from '@aws-amplify/core'; import { Place as PlaceResult, @@ -147,11 +148,13 @@ export class AmazonLocationServiceProvider implements GeoProvider { * Search by text input with optional parameters * @param {string} text - The text string that is to be searched for * @param {SearchByTextOptions} options? - Optional parameters to the search + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details * @returns {Promise} - Promise resolves to a list of Places that match search parameters */ public async searchByText( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -181,7 +184,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); const command = new SearchPlaceIndexForTextCommand(locationServiceInput); @@ -212,12 +215,14 @@ export class AmazonLocationServiceProvider implements GeoProvider { * Search for suggestions based on the input text * @param {string} text - The text string that is to be searched for * @param {SearchByTextOptions} options? - Optional parameters to the search + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details * @returns {Promise} - Resolves to an array of search suggestion strings */ public async searchForSuggestions( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -247,7 +252,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); const command = new SearchPlaceIndexForSuggestionsCommand( locationServiceInput @@ -282,7 +287,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { public async searchByPlaceId( placeId: string, - options?: searchByPlaceIdOptions + options?: searchByPlaceIdOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -295,7 +301,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); const searchByPlaceIdInput: GetPlaceCommandInput = { @@ -329,7 +335,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { */ public async searchByCoordinates( coordinates: Coordinates, - options?: SearchByCoordinatesOptions + options?: SearchByCoordinatesOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -353,7 +360,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); const command = new SearchPlaceIndexForPositionCommand( locationServiceInput @@ -384,13 +391,15 @@ export class AmazonLocationServiceProvider implements GeoProvider { * Create geofences inside of a geofence collection * @param geofences - Array of geofence objects to create * @param options? - Optional parameters for creating geofences + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details * @returns {Promise} - Promise that resolves to an object with: * successes: list of geofences successfully created * errors: list of geofences that failed to create */ public async saveGeofences( geofences: GeofenceInput[], - options?: AmazonLocationServiceGeofenceOptions + options?: AmazonLocationServiceGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { if (geofences.length < 1) { throw new Error('Geofence input array is empty'); @@ -442,7 +451,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { try { response = await this._AmazonLocationServiceBatchPutGeofenceCall( batch, - options?.collectionName || this._config.geofenceCollections.default + options?.collectionName || this._config.geofenceCollections.default, + customUserAgentDetails ); } catch (error) { // If the API call fails, add the geofences to the errors array and move to next batch @@ -492,11 +502,13 @@ export class AmazonLocationServiceProvider implements GeoProvider { * Get geofence from a geofence collection * @param geofenceId:string * @param options?: Optional parameters for getGeofence + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details * @returns {Promise} - Promise that resolves to a geofence object */ public async getGeofence( geofenceId: GeofenceId, - options?: AmazonLocationServiceGeofenceOptions + options?: AmazonLocationServiceGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -517,7 +529,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); // Create Amazon Location Service command @@ -555,12 +567,14 @@ export class AmazonLocationServiceProvider implements GeoProvider { /** * List geofences from a geofence collection * @param options?: ListGeofenceOptions + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details * @returns {Promise} - Promise that resolves to an object with: * entries: list of geofences - 100 geofences are listed per page * nextToken: token for next page of geofences */ public async listGeofences( - options?: AmazonLocationServiceListGeofenceOptions + options?: AmazonLocationServiceListGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -579,7 +593,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); // Create Amazon Location Service input @@ -636,13 +650,15 @@ export class AmazonLocationServiceProvider implements GeoProvider { * Delete geofences from a geofence collection * @param geofenceIds: string|string[] * @param options?: GeofenceOptions + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details * @returns {Promise} - Promise that resolves to an object with: * successes: list of geofences successfully deleted * errors: list of geofences that failed to delete */ public async deleteGeofences( geofenceIds: string[], - options?: AmazonLocationServiceGeofenceOptions + options?: AmazonLocationServiceGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { if (geofenceIds.length < 1) { throw new Error('GeofenceId input array is empty'); @@ -685,7 +701,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { try { response = await this._AmazonLocationServiceBatchDeleteGeofenceCall( batch, - options?.collectionName || this._config.geofenceCollections.default + options?.collectionName || this._config.geofenceCollections.default, + customUserAgentDetails ); } catch (error) { // If the API call fails, add the geofences to the errors array and move to next batch @@ -772,7 +789,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { private async _AmazonLocationServiceBatchPutGeofenceCall( PascalGeofences: BatchPutGeofenceRequestEntry[], - collectionName?: string + collectionName?: string, + customUserAgentDetails?: CustomUserAgentDetails ) { // Create the BatchPutGeofence input const geofenceInput: BatchPutGeofenceCommandInput = { @@ -784,7 +802,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); const command = new BatchPutGeofenceCommand(geofenceInput); @@ -799,7 +817,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { private async _AmazonLocationServiceBatchDeleteGeofenceCall( geofenceIds: string[], - collectionName?: string + collectionName?: string, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { // Create the BatchDeleteGeofence input const deleteGeofencesInput: BatchDeleteGeofenceCommandInput = { @@ -811,7 +830,7 @@ export class AmazonLocationServiceProvider implements GeoProvider { const client = new LocationClient({ credentials: this._config.credentials, region: this._config.region, - customUserAgent: getAmplifyUserAgentObject(), + customUserAgent: getAmplifyUserAgentObject(customUserAgentDetails), }); const command = new BatchDeleteGeofenceCommand(deleteGeofencesInput); diff --git a/packages/geo/src/internals/InternalGeo.ts b/packages/geo/src/internals/InternalGeo.ts new file mode 100644 index 00000000000..65b7cd7cfef --- /dev/null +++ b/packages/geo/src/internals/InternalGeo.ts @@ -0,0 +1,393 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { + Amplify, + CustomUserAgentDetails, + GeoAction, + ConsoleLogger as Logger, + parseAWSExports, +} from '@aws-amplify/core'; +import { AmazonLocationServiceProvider } from '../Providers/AmazonLocationServiceProvider'; + +import { validateCoordinates } from '../util'; + +import { + Place, + GeoConfig, + Coordinates, + SearchByTextOptions, + SearchByCoordinatesOptions, + GeoProvider, + MapStyle, + GeofenceId, + GeofenceInput, + GeofenceOptions, + SaveGeofencesResults, + Geofence, + ListGeofenceOptions, + ListGeofenceResults, + DeleteGeofencesResults, + searchByPlaceIdOptions, +} from '../types'; +import { getGeoUserAgentDetails } from './utils'; + +const logger = new Logger('Geo'); + +const DEFAULT_PROVIDER = 'AmazonLocationService'; +export class InternalGeoClass { + static MODULE = 'InternalGeo'; + /** + * @private + */ + private _config: GeoConfig; + private _pluggables: GeoProvider[]; + + constructor() { + this._config = {}; + this._pluggables = []; + logger.debug('Geo Options', this._config); + } + + /** + * get the name of the module category + * @returns {string} name of the module category + */ + public getModuleName() { + return InternalGeoClass.MODULE; + } + + /** + * add plugin into Geo category + * @param {Object} pluggable - an instance of the plugin + */ + public addPluggable(pluggable: GeoProvider) { + if (pluggable && pluggable.getCategory() === 'Geo') { + this._pluggables.push(pluggable); + const config = pluggable.configure( + this._config[pluggable.getProviderName()] + ); + + return config; + } + } + + /** + * Get the plugin object + * @param providerName - the name of the plugin + */ + public getPluggable(providerName: string) { + const pluggable = this._pluggables.find( + pluggable => pluggable.getProviderName() === providerName + ); + if (pluggable === undefined) { + logger.debug('No plugin found with providerName', providerName); + throw new Error('No plugin found in Geo for the provider'); + } else return pluggable; + } + + /** + * Remove the plugin object + * @param providerName - the name of the plugin + */ + public removePluggable(providerName: string) { + this._pluggables = this._pluggables.filter( + pluggable => pluggable.getProviderName() !== providerName + ); + return; + } + + /** + * Configure Geo + * @param {Object} config - Configuration object for Geo + * @return {Object} - Current configuration + */ + configure(config?) { + logger.debug('configure Geo'); + + if (!config) return this._config; + + const amplifyConfig = parseAWSExports(config); + this._config = Object.assign({}, this._config, amplifyConfig.Geo, config); + + this._pluggables.forEach(pluggable => { + pluggable.configure(this._config[pluggable.getProviderName()]); + }); + + if (this._pluggables.length === 0) { + this.addPluggable(new AmazonLocationServiceProvider()); + } + return this._config; + } + + /** + * Get the map resources that are currently available through the provider + * @param {string} provider + * @returns - Array of available map resources + */ + public getAvailableMaps(provider = DEFAULT_PROVIDER): MapStyle[] { + const prov = this.getPluggable(provider); + + return prov.getAvailableMaps(); + } + + /** + * Get the map resource set as default in amplify config + * @param {string} provider + * @returns - Map resource set as the default in amplify config + */ + public getDefaultMap(provider = DEFAULT_PROVIDER): MapStyle { + const prov = this.getPluggable(provider); + + return prov.getDefaultMap(); + } + + /** + * Search by text input with optional parameters + * @param {string} text - The text string that is to be searched for + * @param {SearchByTextOptions} options? - Optional parameters to the search + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Promise resolves to a list of Places that match search parameters + */ + public async searchByText( + text: string, + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + try { + return await prov.searchByText( + text, + options, + getGeoUserAgentDetails(GeoAction.SearchByText, customUserAgentDetails) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Search for search term suggestions based on input text + * @param {string} text - The text string that is to be search for + * @param {SearchByTextOptions} options? - Optional parameters to the search + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Resolves to an array of search suggestion strings + */ + public async searchForSuggestions( + text: string, + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails + ) { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + try { + return await prov.searchForSuggestions( + text, + options, + getGeoUserAgentDetails( + GeoAction.SearchForSuggestions, + customUserAgentDetails + ) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Search for location by unique ID + * @param {string} placeId - Unique ID of the location that is to be searched for + * @param {searchByPlaceIdOptions} options? - Optional parameters to the search + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Resolves to a place with the given placeId + */ + public async searchByPlaceId( + placeId: string, + options?: searchByPlaceIdOptions, + customUserAgentDetails?: CustomUserAgentDetails + ) { + const providerName = DEFAULT_PROVIDER; + const prov = this.getPluggable(providerName); + + try { + return await prov.searchByPlaceId( + placeId, + options, + getGeoUserAgentDetails( + GeoAction.SearchByPlaceId, + customUserAgentDetails + ) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Reverse geocoding search via a coordinate point on the map + * @param coordinates - Coordinates array for the search input + * @param options - Options parameters for the search + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Promise that resolves to a place matching search coordinates + */ + public async searchByCoordinates( + coordinates: Coordinates, + options?: SearchByCoordinatesOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + const [lng, lat] = coordinates; + try { + validateCoordinates(lng, lat); + return await prov.searchByCoordinates( + coordinates, + options, + getGeoUserAgentDetails(GeoAction.SearchByCoordinates) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Create geofences + * @param geofences - Single or array of geofence objects to create + * @param options? - Optional parameters for creating geofences + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Promise that resolves to an object with: + * successes: list of geofences successfully created + * errors: list of geofences that failed to create + */ + public async saveGeofences( + geofences: GeofenceInput | GeofenceInput[], + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + // If single geofence input, make it an array for batch call + let geofenceInputArray; + if (!Array.isArray(geofences)) { + geofenceInputArray = [geofences]; + } else { + geofenceInputArray = geofences; + } + + try { + return await prov.saveGeofences( + geofenceInputArray, + options, + getGeoUserAgentDetails(GeoAction.SaveGeofences, customUserAgentDetails) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Get a single geofence by geofenceId + * @param geofenceId: GeofenceId - The string id of the geofence to get + * @param options?: GeofenceOptions - Optional parameters for getting a geofence + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns Promise - Promise that resolves to a geofence object + */ + public async getGeofence( + geofenceId: GeofenceId, + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + try { + return await prov.getGeofence( + geofenceId, + options, + getGeoUserAgentDetails(GeoAction.GetGeofence, customUserAgentDetails) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * List geofences + * @param options?: ListGeofenceOptions + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Promise that resolves to an object with: + * entries: list of geofences - 100 geofences are listed per page + * nextToken: token for next page of geofences + */ + public async listGeofences( + options?: ListGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + try { + return await prov.listGeofences( + options, + getGeoUserAgentDetails(GeoAction.ListGeofences, customUserAgentDetails) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Delete geofences + * @param geofenceIds: string|string[] + * @param options?: GeofenceOptions + * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details + * @returns {Promise} - Promise that resolves to an object with: + * successes: list of geofences successfully deleted + * errors: list of geofences that failed to delete + */ + public async deleteGeofences( + geofenceIds: string | string[], + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + // If single geofence input, make it an array for batch call + let geofenceIdsInputArray; + if (!Array.isArray(geofenceIds)) { + geofenceIdsInputArray = [geofenceIds]; + } else { + geofenceIdsInputArray = geofenceIds; + } + + // Delete geofences + try { + return await prov.deleteGeofences( + geofenceIdsInputArray, + options, + getGeoUserAgentDetails( + GeoAction.DeleteGeofences, + customUserAgentDetails + ) + ); + } catch (error) { + logger.debug(error); + throw error; + } + } +} + +export const InternalGeo = new InternalGeoClass(); +Amplify.register(InternalGeo); diff --git a/packages/geo/src/internals/index.ts b/packages/geo/src/internals/index.ts new file mode 100644 index 00000000000..fe42b92c29f --- /dev/null +++ b/packages/geo/src/internals/index.ts @@ -0,0 +1,3 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +export { InternalGeo } from './InternalGeo'; diff --git a/packages/geo/src/internals/utils.ts b/packages/geo/src/internals/utils.ts new file mode 100644 index 00000000000..65412e68320 --- /dev/null +++ b/packages/geo/src/internals/utils.ts @@ -0,0 +1,15 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { Category, CustomUserAgentDetails, GeoAction } from '@aws-amplify/core'; + +export const getGeoUserAgentDetails = ( + action: GeoAction, + customUserAgentDetails?: CustomUserAgentDetails +): CustomUserAgentDetails => { + return { + category: Category.Geo, + action, + ...customUserAgentDetails, + }; +}; diff --git a/packages/geo/src/types/Provider.ts b/packages/geo/src/types/Provider.ts index 847033784b3..563ecbfcb8f 100644 --- a/packages/geo/src/types/Provider.ts +++ b/packages/geo/src/types/Provider.ts @@ -1,5 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { CustomUserAgentDetails } from '@aws-amplify/core'; import { SearchByTextOptions, SearchByCoordinatesOptions, @@ -35,42 +36,55 @@ export interface GeoProvider { getDefaultMap(): MapStyle; // search by a text string and return a list of places - searchByText(text: string, options?: SearchByTextOptions): Promise; + searchByText( + text: string, + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise; // search by coordinates and return a matching place searchByCoordinates( coordinates: Coordinates, - options?: SearchByCoordinatesOptions + options?: SearchByCoordinatesOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise; searchForSuggestions( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise; searchByPlaceId( placeId: string, - options?: searchByPlaceIdOptions + options?: searchByPlaceIdOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise; // create geofences saveGeofences( geofences: GeofenceInput[], - options?: GeofenceOptions + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise; // get a single geofence getGeofence( geofenceId: GeofenceId, - options?: ListGeofenceOptions + options?: ListGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise; // list all geofences - listGeofences(options?: ListGeofenceOptions): Promise; + listGeofences( + options?: ListGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails + ): Promise; // Delete geofences deleteGeofences( geofenceIds: string[], - options?: GeofenceOptions + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise; } diff --git a/packages/notifications/package.json b/packages/notifications/package.json index 05964175d49..cecb1a7bd53 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -65,13 +65,13 @@ "name": "Notifications (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Notifications }", - "limit": "29.95 kB" + "limit": "30.5 kB" }, { "name": "Notifications (with Analytics)", "path": "./lib-esm/index.js", "import": "{ Amplify, Notifications, Analytics }", - "limit": "29.95 kB" + "limit": "30.5 kB" } ] } diff --git a/packages/predictions/package.json b/packages/predictions/package.json index 1a1f0cdac92..9b22c430c89 100644 --- a/packages/predictions/package.json +++ b/packages/predictions/package.json @@ -69,13 +69,13 @@ "name": "Predictions (Convert provider)", "path": "./lib-esm/index.js", "import": "{ Amplify, Predictions, AmazonAIConvertPredictionsProvider }", - "limit": "57.9 kB" + "limit": "58 kB" }, { "name": "Predictions (Identify provider)", "path": "./lib-esm/index.js", "import": "{ Amplify, Predictions, AmazonAIIdentifyPredictionsProvider }", - "limit": "73.2 kB" + "limit": "73.3 kB" }, { "name": "Predictions (Interpret provider)", diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 328583c84af..22f6d474c17 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -65,13 +65,13 @@ "name": "PubSub (IoT provider)", "path": "./lib-esm/index.js", "import": "{ Amplify, PubSub, AWSIoTProvider }", - "limit": "80.1 kB" + "limit": "80.2 kB" }, { "name": "PubSub (Mqtt provider)", "path": "./lib-esm/index.js", "import": "{ Amplify, PubSub, MqttOverWSProvider }", - "limit": "80 kB" + "limit": "80.05 kB" } ], "jest": { diff --git a/packages/storage/package.json b/packages/storage/package.json index dec3c04208d..5b5a3c15437 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -58,7 +58,7 @@ "name": "Storage (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Storage }", - "limit": "38.49 kB" + "limit": "38.6 kB" } ], "jest": {