From ca34154e77e16ccf9c36036207259335a2d5bdd6 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Sun, 16 Jul 2023 21:27:13 -0700 Subject: [PATCH 01/10] chore: copy Geo code into InternalGeo --- packages/geo/src/internals/InternalGeo.ts | 334 ++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 packages/geo/src/internals/InternalGeo.ts diff --git a/packages/geo/src/internals/InternalGeo.ts b/packages/geo/src/internals/InternalGeo.ts new file mode 100644 index 00000000000..77c5ecca2f4 --- /dev/null +++ b/packages/geo/src/internals/InternalGeo.ts @@ -0,0 +1,334 @@ +// 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 { + Place, + GeoConfig, + Coordinates, + SearchByTextOptions, + SearchByCoordinatesOptions, + GeoProvider, + MapStyle, + GeofenceId, + GeofenceInput, + GeofenceOptions, + SaveGeofencesResults, + Geofence, + ListGeofenceOptions, + ListGeofenceResults, + DeleteGeofencesResults, + searchByPlaceIdOptions, +} from './types'; + +const logger = new Logger('Geo'); + +const DEFAULT_PROVIDER = 'AmazonLocationService'; +export class GeoClass { + 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 + * @returns {string} name of the module category + */ + public getModuleName() { + 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 + * @param {SearchByTextOptions} options? - Optional parameters to the search + * @returns {Promise} - Promise resolves to a list of Places that match search parameters + */ + public async searchByText( + 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; + } + } + + /** + * 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 + * @returns {Promise} - Resolves to an array of search suggestion strings + */ + public async searchForSuggestions( + 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; + } + } + + /** + * 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 + * @returns {Promise} - Resolves to a place with the given placeId + */ + public async searchByPlaceId( + 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; + } + } + + /** + * 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 + * @returns {Promise} - Promise that resolves to a place matching search coordinates + */ + public async searchByCoordinates( + 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; + } + } + + /** + * Create geofences + * @param geofences - Single or array of geofence objects to create + * @param options? - Optional parameters for creating geofences + * @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 + ): 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; + } + } + + /** + * 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 + * @returns Promise - Promise that resolves to a geofence object + */ + public async getGeofence( + 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; + } + } + + /** + * List geofences + * @param options?: ListGeofenceOptions + * @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 + ): Promise { + const { providerName = DEFAULT_PROVIDER } = options || {}; + const prov = this.getPluggable(providerName); + + try { + return await prov.listGeofences(options); + } catch (error) { + logger.debug(error); + throw error; + } + } + + /** + * Delete geofences + * @param geofenceIds: string|string[] + * @param options?: GeofenceOptions + * @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 + ): 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; + } + } +} + +export const Geo = new GeoClass(); +Amplify.register(Geo); From 04659fe273d069b83aa2a0bdcae39c220e347d42 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Sun, 16 Jul 2023 22:15:16 -0700 Subject: [PATCH 02/10] feat: add geo actions --- packages/core/src/Platform/types.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/core/src/Platform/types.ts b/packages/core/src/Platform/types.ts index 86929507b36..3801738f255 100644 --- a/packages/core/src/Platform/types.ts +++ b/packages/core/src/Platform/types.ts @@ -93,7 +93,13 @@ export enum DataStoreAction { GraphQl = '2', } export enum GeoAction { - None = '0', + SearchByText = '1', + SearchForSuggestions = '2', + SearchByPlaceId = '3', + SaveGeofences = '4', + GetGeofence = '5', + ListGeofences = '6', + DeleteGeofences = '7', } export enum InAppMessagingAction { None = '0', From db70cdbd68935bcea2a533698f8d2a16d915bbed Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Sun, 16 Jul 2023 22:15:48 -0700 Subject: [PATCH 03/10] feat: add customUserAgentDetails to geo provider --- .../AmazonLocationServiceProvider.ts | 53 ++++++++++++------- packages/geo/src/types/Provider.ts | 30 ++++++++--- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/packages/geo/src/Providers/AmazonLocationServiceProvider.ts b/packages/geo/src/Providers/AmazonLocationServiceProvider.ts index 918ef822e13..169e188ac58 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, @@ -151,7 +152,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { */ public async searchByText( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -181,7 +183,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); @@ -217,7 +219,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { public async searchForSuggestions( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -247,7 +250,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 +285,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 +299,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 +333,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 +358,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 @@ -390,7 +395,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { */ 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 +448,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 @@ -496,7 +503,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { */ public async getGeofence( geofenceId: GeofenceId, - options?: AmazonLocationServiceGeofenceOptions + options?: AmazonLocationServiceGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const credentialsOK = await this._ensureCredentials(); if (!credentialsOK) { @@ -517,7 +525,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 @@ -560,7 +568,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { * 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 +588,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 @@ -642,7 +651,8 @@ export class AmazonLocationServiceProvider implements GeoProvider { */ 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 +695,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 +783,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 +796,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 +811,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 +824,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/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; } From f590271222def423d1ee98b5b588666fb489277c Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Sun, 16 Jul 2023 22:17:53 -0700 Subject: [PATCH 04/10] feat: add customUserAgentDetails to public api's and send to service calls --- packages/geo/src/internals/InternalGeo.ts | 90 +++++++++++++++++------ packages/geo/src/internals/utils.ts | 15 ++++ 2 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 packages/geo/src/internals/utils.ts diff --git a/packages/geo/src/internals/InternalGeo.ts b/packages/geo/src/internals/InternalGeo.ts index 77c5ecca2f4..8b4caf72158 100644 --- a/packages/geo/src/internals/InternalGeo.ts +++ b/packages/geo/src/internals/InternalGeo.ts @@ -2,12 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify, + CustomUserAgentDetails, + GeoAction, ConsoleLogger as Logger, parseAWSExports, } from '@aws-amplify/core'; -import { AmazonLocationServiceProvider } from './Providers/AmazonLocationServiceProvider'; +import { AmazonLocationServiceProvider } from '../Providers/AmazonLocationServiceProvider'; -import { validateCoordinates } from './util'; +import { validateCoordinates } from '../util'; import { Place, @@ -26,13 +28,14 @@ import { ListGeofenceResults, DeleteGeofencesResults, searchByPlaceIdOptions, -} from './types'; +} from '../types'; +import { getGeoUserAgentDetails } from './utils'; const logger = new Logger('Geo'); const DEFAULT_PROVIDER = 'AmazonLocationService'; -export class GeoClass { - static MODULE = 'Geo'; +export class InternalGeoClass { + static MODULE = 'InternalGeo'; /** * @private */ @@ -50,7 +53,7 @@ export class GeoClass { * @returns {string} name of the module category */ public getModuleName() { - return GeoClass.MODULE; + return InternalGeoClass.MODULE; } /** @@ -146,13 +149,18 @@ export class GeoClass { */ public async searchByText( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); try { - return await prov.searchByText(text, options); + return await prov.searchByText( + text, + options, + getGeoUserAgentDetails(GeoAction.SearchByText, customUserAgentDetails) + ); } catch (error) { logger.debug(error); throw error; @@ -167,13 +175,21 @@ export class GeoClass { */ public async searchForSuggestions( text: string, - options?: SearchByTextOptions + options?: SearchByTextOptions, + customUserAgentDetails?: CustomUserAgentDetails ) { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); try { - return await prov.searchForSuggestions(text, options); + return await prov.searchForSuggestions( + text, + options, + getGeoUserAgentDetails( + GeoAction.SearchForSuggestions, + customUserAgentDetails + ) + ); } catch (error) { logger.debug(error); throw error; @@ -188,13 +204,21 @@ export class GeoClass { */ public async searchByPlaceId( placeId: string, - options?: searchByPlaceIdOptions + options?: searchByPlaceIdOptions, + customUserAgentDetails?: CustomUserAgentDetails ) { const providerName = DEFAULT_PROVIDER; const prov = this.getPluggable(providerName); try { - return await prov.searchByPlaceId(placeId, options); + return await prov.searchByPlaceId( + placeId, + options, + getGeoUserAgentDetails( + GeoAction.SearchByPlaceId, + customUserAgentDetails + ) + ); } catch (error) { logger.debug(error); throw error; @@ -234,7 +258,8 @@ export class GeoClass { */ public async saveGeofences( geofences: GeofenceInput | GeofenceInput[], - options?: GeofenceOptions + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); @@ -248,7 +273,11 @@ export class GeoClass { } try { - return await prov.saveGeofences(geofenceInputArray, options); + return await prov.saveGeofences( + geofenceInputArray, + options, + getGeoUserAgentDetails(GeoAction.SaveGeofences, customUserAgentDetails) + ); } catch (error) { logger.debug(error); throw error; @@ -263,13 +292,18 @@ export class GeoClass { */ public async getGeofence( geofenceId: GeofenceId, - options?: GeofenceOptions + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); try { - return await prov.getGeofence(geofenceId, options); + return await prov.getGeofence( + geofenceId, + options, + getGeoUserAgentDetails(GeoAction.GetGeofence, customUserAgentDetails) + ); } catch (error) { logger.debug(error); throw error; @@ -284,13 +318,17 @@ export class GeoClass { * nextToken: token for next page of geofences */ public async listGeofences( - options?: ListGeofenceOptions + options?: ListGeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); try { - return await prov.listGeofences(options); + return await prov.listGeofences( + options, + getGeoUserAgentDetails(GeoAction.ListGeofences, customUserAgentDetails) + ); } catch (error) { logger.debug(error); throw error; @@ -307,7 +345,8 @@ export class GeoClass { */ public async deleteGeofences( geofenceIds: string | string[], - options?: GeofenceOptions + options?: GeofenceOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); @@ -322,7 +361,14 @@ export class GeoClass { // Delete geofences try { - return await prov.deleteGeofences(geofenceIdsInputArray, options); + return await prov.deleteGeofences( + geofenceIdsInputArray, + options, + getGeoUserAgentDetails( + GeoAction.DeleteGeofences, + customUserAgentDetails + ) + ); } catch (error) { logger.debug(error); throw error; @@ -330,5 +376,5 @@ export class GeoClass { } } -export const Geo = new GeoClass(); -Amplify.register(Geo); +export const InternalGeo = new InternalGeoClass(); +Amplify.register(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, + }; +}; From 2144f2e07a09e9d0d0243ceaf3afccad946bf8d6 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Sun, 16 Jul 2023 22:21:21 -0700 Subject: [PATCH 05/10] feat: make Geo extend InternalGeo and override public API's --- packages/geo/src/Geo.ts | 214 +++------------------------------------- 1 file changed, 11 insertions(+), 203 deletions(-) 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); } } From cccf4599f21362b4f5a0beab4138ee247797f2d0 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Sun, 16 Jul 2023 22:24:14 -0700 Subject: [PATCH 06/10] build: export InternalGeo from scoped geo/internals path --- packages/geo/internals/package.json | 8 ++++++++ packages/geo/package.json | 3 ++- packages/geo/src/internals/index.ts | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 packages/geo/internals/package.json create mode 100644 packages/geo/src/internals/index.ts 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 197ce9f5ddc..956c11567af 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.6.0", 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'; From 7578ab1da2567cae9882d588531633aa859dc0b7 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Tue, 18 Jul 2023 11:40:14 -0700 Subject: [PATCH 07/10] chore: increase bundle size limits --- packages/geo/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/geo/package.json b/packages/geo/package.json index 5ee547b9e55..63e0aff9b2a 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -58,7 +58,7 @@ "name": "Geo (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Geo }", - "limit": "51.72 kB" + "limit": "51.73 kB" } ], "jest": { From b33bf8c88ae6e9bdae9497c7963b54c58da4cf04 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Tue, 18 Jul 2023 11:58:55 -0700 Subject: [PATCH 08/10] chore: increase bundle size limits --- packages/analytics/package.json | 4 ++-- packages/api-rest/package.json | 2 +- packages/core/package.json | 2 +- packages/geo/package.json | 2 +- packages/notifications/package.json | 4 ++-- packages/pubsub/package.json | 4 ++-- packages/storage/package.json | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/analytics/package.json b/packages/analytics/package.json index b8854540872..654eafa90f7 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 63e75543907..7d7d14fd110 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": "30.94 kB" + "limit": "31.5 kB" } ], "jest": { diff --git a/packages/core/package.json b/packages/core/package.json index 7030f0a1964..c76e7258b7e 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.39 kB" }, { "name": "Core (Signer)", diff --git a/packages/geo/package.json b/packages/geo/package.json index 63e0aff9b2a..964ecb41ad4 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -58,7 +58,7 @@ "name": "Geo (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Geo }", - "limit": "51.73 kB" + "limit": "52.1 kB" } ], "jest": { diff --git a/packages/notifications/package.json b/packages/notifications/package.json index fa7d57db0a2..732422567e9 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.92 kB" + "limit": "30.5 kB" }, { "name": "Notifications (with Analytics)", "path": "./lib-esm/index.js", "import": "{ Amplify, Notifications, Analytics }", - "limit": "29.93 kB" + "limit": "30.5 kB" } ] } diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 6e4e83ee214..20a5b17b0d4 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 36a521c1530..1c3b2ccbd13 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -59,7 +59,7 @@ "name": "Storage (top-level class)", "path": "./lib-esm/index.js", "import": "{ Amplify, Storage }", - "limit": "38.49 kB" + "limit": "38.6 kB" } ], "jest": { From 38af6b8d1360bd84766ff2b39ca7d924ec24bc6f Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Wed, 19 Jul 2023 04:06:55 -0400 Subject: [PATCH 09/10] feat: add user agent param to action that was missed --- packages/core/src/Platform/types.ts | 9 +++++---- packages/geo/src/internals/InternalGeo.ts | 9 +++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/core/src/Platform/types.ts b/packages/core/src/Platform/types.ts index 01dc6323bf2..a4901e1d2e1 100644 --- a/packages/core/src/Platform/types.ts +++ b/packages/core/src/Platform/types.ts @@ -97,10 +97,11 @@ export enum GeoAction { SearchByText = '1', SearchForSuggestions = '2', SearchByPlaceId = '3', - SaveGeofences = '4', - GetGeofence = '5', - ListGeofences = '6', - DeleteGeofences = '7', + SearchByCoordinates = '4', + SaveGeofences = '5', + GetGeofence = '6', + ListGeofences = '7', + DeleteGeofences = '8', } export enum InAppMessagingAction { None = '0', diff --git a/packages/geo/src/internals/InternalGeo.ts b/packages/geo/src/internals/InternalGeo.ts index 8b4caf72158..61f786d2a56 100644 --- a/packages/geo/src/internals/InternalGeo.ts +++ b/packages/geo/src/internals/InternalGeo.ts @@ -233,7 +233,8 @@ export class InternalGeoClass { */ public async searchByCoordinates( coordinates: Coordinates, - options?: SearchByCoordinatesOptions + options?: SearchByCoordinatesOptions, + customUserAgentDetails?: CustomUserAgentDetails ): Promise { const { providerName = DEFAULT_PROVIDER } = options || {}; const prov = this.getPluggable(providerName); @@ -241,7 +242,11 @@ export class InternalGeoClass { const [lng, lat] = coordinates; try { validateCoordinates(lng, lat); - return await prov.searchByCoordinates(coordinates, options); + return await prov.searchByCoordinates( + coordinates, + options, + getGeoUserAgentDetails(GeoAction.SearchByCoordinates) + ); } catch (error) { logger.debug(error); throw error; From e70f689c8d9cc9a2b48df9c556855d731c787216 Mon Sep 17 00:00:00 2001 From: Erin Beal Date: Wed, 19 Jul 2023 04:07:51 -0400 Subject: [PATCH 10/10] chore: update doc-strings with new param --- packages/geo/src/internals/InternalGeo.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/geo/src/internals/InternalGeo.ts b/packages/geo/src/internals/InternalGeo.ts index 61f786d2a56..65b7cd7cfef 100644 --- a/packages/geo/src/internals/InternalGeo.ts +++ b/packages/geo/src/internals/InternalGeo.ts @@ -145,6 +145,7 @@ export class InternalGeoClass { * 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( @@ -171,6 +172,7 @@ export class InternalGeoClass { * 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( @@ -200,6 +202,7 @@ export class InternalGeoClass { * 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( @@ -229,6 +232,7 @@ export class InternalGeoClass { * 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( @@ -257,6 +261,7 @@ export class InternalGeoClass { * 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 @@ -293,6 +298,7 @@ export class InternalGeoClass { * 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( @@ -318,6 +324,7 @@ export class InternalGeoClass { /** * 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 @@ -344,6 +351,7 @@ export class InternalGeoClass { * 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