From 91faff40dd5d09460a3ad3b22921c0018e667b78 Mon Sep 17 00:00:00 2001 From: AllanZhengYP Date: Tue, 17 Oct 2023 13:55:12 -0700 Subject: [PATCH 01/22] feat(deps): upgrade sha256-js to 5.2.0 with esm artifacts (#12326) --- packages/core/package.json | 2 +- yarn.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 90986256959..bb459809b5a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -55,7 +55,7 @@ "server" ], "dependencies": { - "@aws-crypto/sha256-js": "5.0.0", + "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/types": "3.398.0", "@smithy/util-hex-encoding": "2.0.0", "js-cookie": "^3.0.5", diff --git a/yarn.lock b/yarn.lock index 28c453e13be..89d0373ffbd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -49,14 +49,14 @@ "@aws-sdk/types" "^3.222.0" tslib "^1.11.1" -"@aws-crypto/sha256-js@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-5.0.0.tgz#fec6d5a9a097e812207eacaaa707bfa9191b3ad8" - integrity sha512-g+u9iKkaQVp9Mjoxq1IJSHj9NHGZF441+R/GIH0dn7u4mix5QQ4VqgpppHrNm1LzjUzb0BpcFGsBXP6cOVf+ZQ== +"@aws-crypto/sha256-js@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz#c4fdb773fdbed9a664fc1a95724e206cf3860042" + integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== dependencies: - "@aws-crypto/util" "^5.0.0" + "@aws-crypto/util" "^5.2.0" "@aws-sdk/types" "^3.222.0" - tslib "^1.11.1" + tslib "^2.6.2" "@aws-crypto/supports-web-crypto@^3.0.0": version "3.0.0" @@ -74,10 +74,10 @@ "@aws-sdk/util-utf8-browser" "^3.0.0" tslib "^1.11.1" -"@aws-crypto/util@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-5.1.0.tgz#6f9c4eac7f85b2dc8912d0af8ccebaebb9c5ba8d" - integrity sha512-TRSydv/0a4RTZYnCmbpx1F6fOfVlTostBFvLr9GCGPww2WhuIgMg5ZmWN35Wi/Cy6HuvZf82wfUN1F9gQkJ1mQ== +"@aws-crypto/util@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-5.2.0.tgz#71284c9cffe7927ddadac793c14f14886d3876da" + integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== dependencies: "@aws-sdk/types" "^3.222.0" "@smithy/util-utf8" "^2.0.0" From a35e8fa64d4dccb093bcce37b348dac7ab6afbb8 Mon Sep 17 00:00:00 2001 From: Jim Blanchard Date: Tue, 17 Oct 2023 19:53:57 -0500 Subject: [PATCH 02/22] chore: Remove I18n & Cache from global configuration (#12336) --- packages/core/src/Cache/StorageCacheCommon.ts | 4 ---- packages/core/src/I18n/I18n.ts | 7 +------ packages/core/src/index.ts | 2 +- packages/core/src/singleton/types.ts | 6 ------ 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/core/src/Cache/StorageCacheCommon.ts b/packages/core/src/Cache/StorageCacheCommon.ts index 9b2352f9fc8..126a0fb7462 100644 --- a/packages/core/src/Cache/StorageCacheCommon.ts +++ b/packages/core/src/Cache/StorageCacheCommon.ts @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { Amplify } from '../singleton'; import { ConsoleLogger as Logger } from '../Logger'; import { KeyValueStorageInterface } from '../types'; import { currentSizeKey, defaultConfig } from './constants'; @@ -31,11 +30,8 @@ export abstract class StorageCacheCommon { config?: CacheConfig; keyValueStorage: KeyValueStorageInterface; }) { - const globalCacheConfig = Amplify.getConfig().Cache ?? {}; - this.config = { ...defaultConfig, - ...globalCacheConfig, ...config, }; this.keyValueStorage = keyValueStorage; diff --git a/packages/core/src/I18n/I18n.ts b/packages/core/src/I18n/I18n.ts index a6ec4d982e4..ee35c63d94d 100644 --- a/packages/core/src/I18n/I18n.ts +++ b/packages/core/src/I18n/I18n.ts @@ -37,12 +37,7 @@ export class I18n { * Sets the default language from the configuration when required. */ setDefaultLanguage() { - if (!this._lang) { - const i18nConfig = Amplify.getConfig().I18n; - this._lang = i18nConfig?.language; - } - - // Default to window language if not set in config + // Default to window language if not set in instance if ( !this._lang && typeof window !== 'undefined' && diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 402afeba335..80144f47e66 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -24,7 +24,6 @@ export { AuthUserPoolConfig, AuthUserPoolAndIdentityPoolConfig, APIConfig, - CacheConfig, StorageAccessLevel, StorageConfig, GetCredentialsOptions, @@ -62,6 +61,7 @@ export { KeyValueStorageInterface } from './types'; // Cache exports export { Cache } from './Cache'; +export { CacheConfig } from './Cache/types'; // Internationalization utilities export { I18n } from './I18n'; diff --git a/packages/core/src/singleton/types.ts b/packages/core/src/singleton/types.ts index d16634c1014..fa286fc7abc 100644 --- a/packages/core/src/singleton/types.ts +++ b/packages/core/src/singleton/types.ts @@ -12,14 +12,12 @@ import { GetCredentialsOptions, CognitoIdentityPoolConfig, } from './Auth/types'; -import { CacheConfig } from './Cache/types'; import { GeoConfig } from './Geo/types'; import { LibraryStorageOptions, StorageAccessLevel, StorageConfig, } from './Storage/types'; -import { I18nConfig } from '../I18n/types'; import { NotificationsConfig } from './Notifications/types'; export type LegacyConfig = { @@ -33,9 +31,6 @@ export type ResourcesConfig = { API?: APIConfig; Analytics?: AnalyticsConfig; Auth?: AuthConfig; - Cache?: CacheConfig; - // DataStore?: {}; - I18n?: I18nConfig; // Interactions?: {}; Notifications?: NotificationsConfig; // Predictions?: {}; @@ -56,7 +51,6 @@ export { AuthUserPoolConfig, AuthIdentityPoolConfig, AuthUserPoolAndIdentityPoolConfig, - CacheConfig, GetCredentialsOptions, StorageAccessLevel, StorageConfig, From cb0d401668b87df7cffdc514af36842ab01cd5b6 Mon Sep 17 00:00:00 2001 From: Jim Blanchard Date: Wed, 18 Oct 2023 08:53:41 -0500 Subject: [PATCH 03/22] fix: Make Reachability node safe (#12335) --- packages/core/src/Reachability/Reachability.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/core/src/Reachability/Reachability.ts b/packages/core/src/Reachability/Reachability.ts index 1489a95c2b1..a80988ea6c7 100644 --- a/packages/core/src/Reachability/Reachability.ts +++ b/packages/core/src/Reachability/Reachability.ts @@ -1,7 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { CompletionObserver, Observable } from 'rxjs'; +import { CompletionObserver, Observable, from } from 'rxjs'; import { isWebWorker } from '../libraryUtils'; import { NetworkStatus } from './types'; @@ -9,7 +9,11 @@ export class Reachability { private static _observers: Array> = []; networkMonitor(_?: unknown): Observable { - const globalObj = isWebWorker() ? self : window; + const globalObj = isWebWorker() ? self : typeof window !== 'undefined' && window; + + if (!globalObj) { + return from([{ online: true }]); + } return new Observable(observer => { observer.next({ online: globalObj.navigator.onLine }); From a659d1e509fb676ad6e848d49a7aa9e23de34f59 Mon Sep 17 00:00:00 2001 From: Chris F <5827964+cshfang@users.noreply.github.com> Date: Wed, 18 Oct 2023 08:32:25 -0700 Subject: [PATCH 04/22] chore(notifications): Add initialization assertion to push apis (#12334) --- .../providers/pinpoint/apis/identifyUser.ts | 8 ++++---- .../src/pushNotifications/errors/errorHelpers.ts | 5 +++++ .../providers/pinpoint/apis/getBadgeCount.native.ts | 6 +++++- .../pinpoint/apis/getLaunchNotification.native.ts | 7 +++++-- .../pinpoint/apis/getPermissionStatus.native.ts | 7 +++++-- .../providers/pinpoint/apis/identifyUser.native.ts | 10 ++++------ .../apis/initializePushNotifications.native.ts | 8 +++++--- .../pinpoint/apis/onNotificationOpened.native.ts | 7 +++++-- .../apis/onNotificationReceivedInBackground.native.ts | 6 +++++- .../apis/onNotificationReceivedInForeground.native.ts | 6 +++++- .../providers/pinpoint/apis/onTokenReceived.native.ts | 7 +++++-- .../pinpoint/apis/requestPermissions.native.ts | 7 +++++-- .../providers/pinpoint/apis/setBadgeCount.native.ts | 6 +++++- .../pinpoint/utils/createMessageEventRecorder.ts | 3 +-- .../providers/pinpoint/utils/index.ts | 4 ---- .../notifications/src/pushNotifications/utils/index.ts | 7 +++++++ .../pinpoint => }/utils/initializationManager.ts | 0 .../{providers/pinpoint => }/utils/resolveConfig.ts | 2 +- .../pinpoint => }/utils/resolveCredentials.ts | 2 +- .../{providers/pinpoint => }/utils/tokenManager.ts | 0 20 files changed, 73 insertions(+), 35 deletions(-) create mode 100644 packages/notifications/src/pushNotifications/utils/index.ts rename packages/notifications/src/pushNotifications/{providers/pinpoint => }/utils/initializationManager.ts (100%) rename packages/notifications/src/pushNotifications/{providers/pinpoint => }/utils/resolveConfig.ts (97%) rename packages/notifications/src/pushNotifications/{providers/pinpoint => }/utils/resolveCredentials.ts (96%) rename packages/notifications/src/pushNotifications/{providers/pinpoint => }/utils/tokenManager.ts (100%) diff --git a/packages/notifications/src/inAppMessaging/providers/pinpoint/apis/identifyUser.ts b/packages/notifications/src/inAppMessaging/providers/pinpoint/apis/identifyUser.ts index c5d4a494720..25d59ba0f7b 100644 --- a/packages/notifications/src/inAppMessaging/providers/pinpoint/apis/identifyUser.ts +++ b/packages/notifications/src/inAppMessaging/providers/pinpoint/apis/identifyUser.ts @@ -59,10 +59,10 @@ import { assertIsInitialized } from '../../../utils'; * }, * options: { * address: 'device-address', - * optOut: 'NONE', - * userAttributes: { - * interests: ['food'] - * }, + * optOut: 'NONE', + * userAttributes: { + * interests: ['food'] + * }, * }, * }); */ diff --git a/packages/notifications/src/pushNotifications/errors/errorHelpers.ts b/packages/notifications/src/pushNotifications/errors/errorHelpers.ts index 4ef5857e443..bfd79b64d5e 100644 --- a/packages/notifications/src/pushNotifications/errors/errorHelpers.ts +++ b/packages/notifications/src/pushNotifications/errors/errorHelpers.ts @@ -6,6 +6,7 @@ import { AssertionFunction, createAssertionFunction, } from '@aws-amplify/core/internals/utils'; +import { isInitialized } from '../utils'; import { PushNotificationError } from './PushNotificationError'; export enum PushNotificationValidationErrorCode { @@ -38,3 +39,7 @@ export const assert: AssertionFunction = pushNotificationValidationErrorMap, PushNotificationError ); + +export const assertIsInitialized = () => { + assert(isInitialized(), PushNotificationValidationErrorCode.NotInitialized); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getBadgeCount.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getBadgeCount.native.ts index 3664ba32676..e2feeb46137 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getBadgeCount.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getBadgeCount.native.ts @@ -2,8 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { loadAmplifyPushNotification } from '@aws-amplify/react-native'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { GetBadgeCount } from '../types'; const { getBadgeCount: getBadgeCountNative } = loadAmplifyPushNotification(); -export const getBadgeCount: GetBadgeCount = async () => getBadgeCountNative(); +export const getBadgeCount: GetBadgeCount = async () => { + assertIsInitialized(); + return getBadgeCountNative(); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getLaunchNotification.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getLaunchNotification.native.ts index 8ca2d328ced..b5e4f2565b4 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getLaunchNotification.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getLaunchNotification.native.ts @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { loadAmplifyPushNotification } from '@aws-amplify/react-native'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { GetLaunchNotification } from '../types'; const { getLaunchNotification: getLaunchNotificationNative } = loadAmplifyPushNotification(); -export const getLaunchNotification: GetLaunchNotification = () => - getLaunchNotificationNative(); +export const getLaunchNotification: GetLaunchNotification = () => { + assertIsInitialized(); + return getLaunchNotificationNative(); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getPermissionStatus.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getPermissionStatus.native.ts index 25934c51676..ec2b45c8954 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getPermissionStatus.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/getPermissionStatus.native.ts @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { loadAmplifyPushNotification } from '@aws-amplify/react-native'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { GetPermissionStatus } from '../types'; const { getPermissionStatus: getPermissionStatusNative } = loadAmplifyPushNotification(); -export const getPermissionStatus: GetPermissionStatus = () => - getPermissionStatusNative(); +export const getPermissionStatus: GetPermissionStatus = () => { + assertIsInitialized(); + return getPermissionStatusNative(); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts index 0f1e9c4584b..4d7cfed9628 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts @@ -3,12 +3,9 @@ import { PushNotificationAction } from '@aws-amplify/core/internals/utils'; import { updateEndpoint } from '@aws-amplify/core/internals/providers/pinpoint'; -import { - getChannelType, - getPushNotificationUserAgentString, - resolveConfig, - resolveCredentials, -} from '../utils'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; +import { resolveConfig, resolveCredentials } from '../../../utils'; +import { getChannelType, getPushNotificationUserAgentString } from '../utils'; import { IdentifyUser } from '../types'; export const identifyUser: IdentifyUser = async ({ @@ -16,6 +13,7 @@ export const identifyUser: IdentifyUser = async ({ userProfile, options, }) => { + assertIsInitialized(); const { credentials, identityId } = await resolveCredentials(); const { appId, region } = resolveConfig(); const { address, optOut, userAttributes } = options ?? {}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts index 646ab2f548a..513bb71cb28 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts @@ -12,15 +12,17 @@ import { notifyEventListenersAndAwaitHandlers, } from '../../../../eventListeners'; import { - createMessageEventRecorder, - getChannelType, - getPushNotificationUserAgentString, getToken, initialize, isInitialized, resolveConfig, resolveCredentials, setToken, +} from '../../../utils'; +import { + createMessageEventRecorder, + getChannelType, + getPushNotificationUserAgentString, } from '../utils'; const { diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.ts index 290e87c9dcb..a2694b0a02a 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.ts @@ -2,7 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import { addEventListener } from '../../../../eventListeners'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { OnNotificationOpened } from '../types'; -export const onNotificationOpened: OnNotificationOpened = input => - addEventListener('notificationOpened', input); +export const onNotificationOpened: OnNotificationOpened = input => { + assertIsInitialized(); + return addEventListener('notificationOpened', input); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.ts index bab03838720..b43f561ef0e 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.ts @@ -2,7 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { addEventListener } from '../../../../eventListeners'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { OnNotificationReceivedInBackground } from '../types'; export const onNotificationReceivedInBackground: OnNotificationReceivedInBackground = - input => addEventListener('backgroundMessageReceived', input); + input => { + assertIsInitialized(); + return addEventListener('backgroundMessageReceived', input); + }; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.ts index b036ebc4481..6afd65e51bd 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.ts @@ -2,7 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { addEventListener } from '../../../../eventListeners'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { OnNotificationReceivedInForeground } from '../types'; export const onNotificationReceivedInForeground: OnNotificationReceivedInForeground = - input => addEventListener('foregroundMessageReceived', input); + input => { + assertIsInitialized(); + return addEventListener('foregroundMessageReceived', input); + }; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.ts index 44ce83348a3..2d688a438df 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.ts @@ -2,7 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 import { addEventListener } from '../../../../eventListeners'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { OnTokenReceived } from '../types'; -export const onTokenReceived: OnTokenReceived = input => - addEventListener('tokenReceived', input); +export const onTokenReceived: OnTokenReceived = input => { + assertIsInitialized(); + return addEventListener('tokenReceived', input); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/requestPermissions.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/requestPermissions.native.ts index a4ea4668f01..66c26033f70 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/requestPermissions.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/requestPermissions.native.ts @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { loadAmplifyPushNotification } from '@aws-amplify/react-native'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { RequestPermissions } from '../types'; const { requestPermissions: requestPermissionsNative } = loadAmplifyPushNotification(); -export const requestPermissions: RequestPermissions = input => - requestPermissionsNative(input); +export const requestPermissions: RequestPermissions = input => { + assertIsInitialized(); + return requestPermissionsNative(input); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.ts index 599272e94f5..dd8e3738d20 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.ts @@ -2,8 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { loadAmplifyPushNotification } from '@aws-amplify/react-native'; +import { assertIsInitialized } from '../../../errors/errorHelpers'; import { SetBadgeCount } from '../types'; const { setBadgeCount: setBadgeCountNative } = loadAmplifyPushNotification(); -export const setBadgeCount: SetBadgeCount = input => setBadgeCountNative(input); +export const setBadgeCount: SetBadgeCount = input => { + assertIsInitialized(); + setBadgeCountNative(input); +}; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.ts index 338f71f62f5..5fdeba4c3a3 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.ts @@ -11,8 +11,7 @@ import { } from '../../../types'; import { getAnalyticsEvent } from './getAnalyticsEvent'; import { getChannelType } from './getChannelType'; -import { resolveCredentials } from './resolveCredentials'; -import { resolveConfig } from './resolveConfig'; +import { resolveConfig, resolveCredentials } from '../../../utils'; const logger = new ConsoleLogger('PushNotification.recordMessageEvent'); diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/index.ts b/packages/notifications/src/pushNotifications/providers/pinpoint/utils/index.ts index 71607f182b1..20cc0f8dfb3 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/index.ts +++ b/packages/notifications/src/pushNotifications/providers/pinpoint/utils/index.ts @@ -4,7 +4,3 @@ export { createMessageEventRecorder } from './createMessageEventRecorder'; export { getChannelType } from './getChannelType'; export { getPushNotificationUserAgentString } from './getPushNotificationUserAgentString'; -export { initialize, isInitialized } from './initializationManager'; -export { resolveConfig } from './resolveConfig'; -export { resolveCredentials } from './resolveCredentials'; -export { getToken, setToken } from './tokenManager'; diff --git a/packages/notifications/src/pushNotifications/utils/index.ts b/packages/notifications/src/pushNotifications/utils/index.ts new file mode 100644 index 00000000000..7bc84303d98 --- /dev/null +++ b/packages/notifications/src/pushNotifications/utils/index.ts @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export { initialize, isInitialized } from './initializationManager'; +export { resolveConfig } from './resolveConfig'; +export { resolveCredentials } from './resolveCredentials'; +export { getToken, setToken } from './tokenManager'; diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/initializationManager.ts b/packages/notifications/src/pushNotifications/utils/initializationManager.ts similarity index 100% rename from packages/notifications/src/pushNotifications/providers/pinpoint/utils/initializationManager.ts rename to packages/notifications/src/pushNotifications/utils/initializationManager.ts diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/resolveConfig.ts b/packages/notifications/src/pushNotifications/utils/resolveConfig.ts similarity index 97% rename from packages/notifications/src/pushNotifications/providers/pinpoint/utils/resolveConfig.ts rename to packages/notifications/src/pushNotifications/utils/resolveConfig.ts index 8553e73e9a5..7f66fbaa5f6 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/resolveConfig.ts +++ b/packages/notifications/src/pushNotifications/utils/resolveConfig.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; -import { assert, PushNotificationValidationErrorCode } from '../../../errors'; +import { assert, PushNotificationValidationErrorCode } from '../errors'; /** * @internal diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/resolveCredentials.ts b/packages/notifications/src/pushNotifications/utils/resolveCredentials.ts similarity index 96% rename from packages/notifications/src/pushNotifications/providers/pinpoint/utils/resolveCredentials.ts rename to packages/notifications/src/pushNotifications/utils/resolveCredentials.ts index 9b3e31e0320..0f1f29e386e 100644 --- a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/resolveCredentials.ts +++ b/packages/notifications/src/pushNotifications/utils/resolveCredentials.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { fetchAuthSession } from '@aws-amplify/core'; -import { assert, PushNotificationValidationErrorCode } from '../../../errors'; +import { assert, PushNotificationValidationErrorCode } from '../errors'; /** * @internal diff --git a/packages/notifications/src/pushNotifications/providers/pinpoint/utils/tokenManager.ts b/packages/notifications/src/pushNotifications/utils/tokenManager.ts similarity index 100% rename from packages/notifications/src/pushNotifications/providers/pinpoint/utils/tokenManager.ts rename to packages/notifications/src/pushNotifications/utils/tokenManager.ts From c5ca240faf6e94bdb4c709ff434253096879d573 Mon Sep 17 00:00:00 2001 From: Jim Blanchard Date: Wed, 18 Oct 2023 11:39:50 -0500 Subject: [PATCH 05/22] feat: Pinpoint configureAutoTrack & tracker migration (#12322) --- .../pinpoint/apis/configureAutoTrack.test.ts | 160 ++++++++++++++++++ packages/analytics/package.json | 1 + packages/analytics/src/errors/validation.ts | 8 + packages/analytics/src/index.ts | 4 +- .../pinpoint/apis/configureAutoTrack.ts | 49 ++++++ .../src/providers/pinpoint/apis/index.ts | 1 + .../analytics/src/providers/pinpoint/index.ts | 13 +- .../src/providers/pinpoint/types/index.ts | 6 +- .../src/providers/pinpoint/types/inputs.ts | 10 +- .../analytics/src/trackers/EventTracker.ts | 135 +++++++++++++++ .../analytics/src/trackers/PageViewTracker.ts | 160 ++++++++++++++++++ .../src/trackers/SessionTracker.native.ts | 106 ++++++++++++ .../analytics/src/trackers/SessionTracker.ts | 106 ++++++++++++ packages/analytics/src/trackers/index.ts | 6 + packages/analytics/src/types/analytics.ts | 70 -------- packages/analytics/src/types/index.ts | 17 +- packages/analytics/src/types/inputs.ts | 25 +++ packages/analytics/src/types/trackers.ts | 35 ++++ packages/analytics/src/utils/index.ts | 2 + .../src/utils/trackerConfigHelpers.native.ts | 18 ++ .../src/utils/trackerConfigHelpers.ts | 19 +++ .../analytics/src/utils/trackerHelpers.ts | 57 +++++++ .../aws-amplify/__tests__/exports.test.ts | 2 + .../SessionListener.native.test.ts | 86 ++++++++++ .../sessionListener/SessionListener.test.ts | 68 ++++++++ packages/core/src/libraryUtils.ts | 4 + .../sessionListener/SessionListener.native.ts | 70 ++++++++ .../utils/sessionListener/SessionListener.ts | 74 ++++++++ .../core/src/utils/sessionListener/index.ts | 6 + .../core/src/utils/sessionListener/types.ts | 11 ++ packages/react-native/src/index.ts | 1 + .../react-native/src/moduleLoaders/index.ts | 1 + .../src/moduleLoaders/loadAppState.ts | 6 + 33 files changed, 1249 insertions(+), 88 deletions(-) create mode 100644 packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts create mode 100644 packages/analytics/src/providers/pinpoint/apis/configureAutoTrack.ts create mode 100644 packages/analytics/src/trackers/EventTracker.ts create mode 100644 packages/analytics/src/trackers/PageViewTracker.ts create mode 100644 packages/analytics/src/trackers/SessionTracker.native.ts create mode 100644 packages/analytics/src/trackers/SessionTracker.ts create mode 100644 packages/analytics/src/trackers/index.ts delete mode 100644 packages/analytics/src/types/analytics.ts create mode 100644 packages/analytics/src/types/trackers.ts create mode 100644 packages/analytics/src/utils/trackerConfigHelpers.native.ts create mode 100644 packages/analytics/src/utils/trackerConfigHelpers.ts create mode 100644 packages/analytics/src/utils/trackerHelpers.ts create mode 100644 packages/core/__tests__/utils/sessionListener/SessionListener.native.test.ts create mode 100644 packages/core/__tests__/utils/sessionListener/SessionListener.test.ts create mode 100644 packages/core/src/utils/sessionListener/SessionListener.native.ts create mode 100644 packages/core/src/utils/sessionListener/SessionListener.ts create mode 100644 packages/core/src/utils/sessionListener/index.ts create mode 100644 packages/core/src/utils/sessionListener/types.ts create mode 100644 packages/react-native/src/moduleLoaders/loadAppState.ts diff --git a/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts b/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts new file mode 100644 index 00000000000..90664582e73 --- /dev/null +++ b/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts @@ -0,0 +1,160 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { ConfigureAutoTrackInput } from '../../../../src/providers/pinpoint'; +import { + EventTracker, + PageViewTracker, + SessionTracker, +} from '../../../../src/trackers'; + +jest.mock('../../../../src/trackers'); + +const MOCK_INPUT = { + enable: true, + type: 'event', + options: { + attributes: { + 'custom-attr': 'val', + }, + }, +} as ConfigureAutoTrackInput; + +describe('Pinpoint API: configureAutoTrack', () => { + const MockEventTracker = EventTracker as jest.MockedClass< + typeof EventTracker + >; + const MockPageViewTracker = PageViewTracker as jest.MockedClass< + typeof PageViewTracker + >; + const MockSessionTracker = SessionTracker as jest.MockedClass< + typeof SessionTracker + >; + + beforeEach(() => { + MockEventTracker.mockClear(); + MockPageViewTracker.mockClear(); + MockSessionTracker.mockClear(); + }); + + it('Validates the tracker configuration', () => { + expect.assertions(1); + + jest.isolateModules(() => { + const { + configureAutoTrack, + } = require('../../../../src/providers/pinpoint/apis'); + + try { + configureAutoTrack({ + ...MOCK_INPUT, + type: 'invalidTracker', + } as any); + } catch (e) { + expect(e.message).toBe('Invalid tracker type specified.'); + } + }); + }); + + it('Creates a new Event tracker when required', () => { + jest.isolateModules(() => { + const { + configureAutoTrack, + } = require('../../../../src/providers/pinpoint/apis'); + + configureAutoTrack(MOCK_INPUT); + }); + + expect(MockEventTracker).toBeCalledWith( + expect.any(Function), + MOCK_INPUT.options + ); + }); + + it('Creates a new Session tracker when required', () => { + const testInput = { + ...MOCK_INPUT, + type: 'session', + } as ConfigureAutoTrackInput; + + jest.isolateModules(() => { + const { + configureAutoTrack, + } = require('../../../../src/providers/pinpoint/apis'); + + configureAutoTrack(testInput); + }); + + expect(MockSessionTracker).toBeCalledWith( + expect.any(Function), + testInput.options + ); + }); + + it('Creates a new PageView tracker when required', () => { + const testInput = { + ...MOCK_INPUT, + type: 'pageView', + } as ConfigureAutoTrackInput; + + jest.isolateModules(() => { + const { + configureAutoTrack, + } = require('../../../../src/providers/pinpoint/apis'); + + configureAutoTrack(testInput); + }); + + expect(MockPageViewTracker).toBeCalledWith( + expect.any(Function), + testInput.options + ); + }); + + it('Reconfigures an existing tracker', () => { + jest.isolateModules(() => { + const { + configureAutoTrack, + } = require('../../../../src/providers/pinpoint/apis'); + + // Enable the tracker + configureAutoTrack(MOCK_INPUT); + expect(MockEventTracker).toBeCalledWith( + expect.any(Function), + MOCK_INPUT.options + ); + + // Reconfigure the tracker + configureAutoTrack(MOCK_INPUT); + expect( + MockEventTracker.mock.instances[0].configure + ).toHaveBeenCalledTimes(1); + }); + }); + + it("Cleans up a tracker when it's disabled", () => { + const testInput = { + ...MOCK_INPUT, + enable: false, + } as ConfigureAutoTrackInput; + + jest.isolateModules(() => { + const { + configureAutoTrack, + } = require('../../../../src/providers/pinpoint/apis'); + + // Enable the tracker + configureAutoTrack(MOCK_INPUT); + expect(MockEventTracker).toBeCalledWith( + expect.any(Function), + MOCK_INPUT.options + ); + + // Disable the tracker + configureAutoTrack(testInput); + expect(MockEventTracker.mock.instances[0].cleanup).toHaveBeenCalledTimes( + 1 + ); + }); + }); +}); diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 35f5f23ea0a..41ce9d796a7 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -103,6 +103,7 @@ }, "devDependencies": { "@aws-amplify/core": "6.0.0", + "@aws-amplify/react-native": "^1.0.0", "@aws-sdk/types": "3.398.0", "typescript": "5.0.2" }, diff --git a/packages/analytics/src/errors/validation.ts b/packages/analytics/src/errors/validation.ts index 65bcc89d263..5ccafeabc44 100644 --- a/packages/analytics/src/errors/validation.ts +++ b/packages/analytics/src/errors/validation.ts @@ -8,6 +8,8 @@ export enum AnalyticsValidationErrorCode { NoCredentials = 'NoCredentials', NoEventName = 'NoEventName', NoRegion = 'NoRegion', + InvalidTracker = 'InvalidTracker', + UnsupportedPlatform = 'UnsupportedPlatform', NoTrackingId = 'NoTrackingId', InvalidFlushSize = 'InvalidFlushSize', } @@ -26,6 +28,12 @@ export const validationErrorMap: AmplifyErrorMap = [AnalyticsValidationErrorCode.NoRegion]: { message: 'Missing region.', }, + [AnalyticsValidationErrorCode.InvalidTracker]: { + message: 'Invalid tracker type specified.', + }, + [AnalyticsValidationErrorCode.UnsupportedPlatform]: { + message: 'Only session tracking is supported on React Native.', + }, [AnalyticsValidationErrorCode.InvalidFlushSize]: { message: 'Invalid FlushSize, it should be smaller than BufferSize', }, diff --git a/packages/analytics/src/index.ts b/packages/analytics/src/index.ts index 7f9732ce48a..f3e9a6ade46 100644 --- a/packages/analytics/src/index.ts +++ b/packages/analytics/src/index.ts @@ -4,9 +4,11 @@ export { record, identifyUser, + configureAutoTrack, + flushEvents, RecordInput, IdentifyUserInput, - flushEvents, + ConfigureAutoTrackInput, } from './providers/pinpoint'; export { enable, disable } from './apis'; export { AnalyticsError } from './errors'; diff --git a/packages/analytics/src/providers/pinpoint/apis/configureAutoTrack.ts b/packages/analytics/src/providers/pinpoint/apis/configureAutoTrack.ts new file mode 100644 index 00000000000..e50fe6002bd --- /dev/null +++ b/packages/analytics/src/providers/pinpoint/apis/configureAutoTrack.ts @@ -0,0 +1,49 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { AnalyticsValidationErrorCode } from '../../../errors'; +import { + TrackerType, + TrackerAttributes, + TrackerInterface, +} from '../../../types/trackers'; +import { + updateProviderTrackers, + validateTrackerConfiguration, +} from '../../../utils'; +import { ConfigureAutoTrackInput } from '../types'; +import { record } from './record'; + +// Configured Tracker instances for Pinpoint +const configuredTrackers: Partial> = {}; + +// Callback that will emit an appropriate event to Pinpoint when required by the Tracker +const emitTrackingEvent = ( + eventName: string, + attributes: TrackerAttributes +) => { + record({ + name: eventName, + attributes, + }); +}; + +/** + * Configures automatic event tracking for Pinpoint. This API will automatically transmit an analytic event when + * configured events are detected within your application. This can include: DOM element events (via the `event` + * tracker), session events (via the `session` tracker), and page view events (via the `pageView` tracker). + * + * @remark Only session tracking is currently supported on React Native. + * + * @param {ConfigureAutoTrackInput} params The input object to configure auto track behavior. + * + * @throws service: {@link UpdateEndpointException} - Thrown when the underlying Pinpoint service returns an error. + * @throws validation: {@link AnalyticsValidationErrorCode} - Thrown when the provided parameters or library + * configuration is incorrect. + */ +export const configureAutoTrack = (input: ConfigureAutoTrackInput): void => { + validateTrackerConfiguration(input); + + // Initialize or update this provider's trackers + updateProviderTrackers(input, emitTrackingEvent, configuredTrackers); +}; diff --git a/packages/analytics/src/providers/pinpoint/apis/index.ts b/packages/analytics/src/providers/pinpoint/apis/index.ts index 7c9583f8ca8..6451503dd6a 100644 --- a/packages/analytics/src/providers/pinpoint/apis/index.ts +++ b/packages/analytics/src/providers/pinpoint/apis/index.ts @@ -3,4 +3,5 @@ export { record } from './record'; export { identifyUser } from './identifyUser'; +export { configureAutoTrack } from './configureAutoTrack'; export { flushEvents } from './flushEvents'; diff --git a/packages/analytics/src/providers/pinpoint/index.ts b/packages/analytics/src/providers/pinpoint/index.ts index e8c93d6fd90..2fe89b8450d 100644 --- a/packages/analytics/src/providers/pinpoint/index.ts +++ b/packages/analytics/src/providers/pinpoint/index.ts @@ -1,5 +1,14 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -export { record, identifyUser, flushEvents } from './apis'; -export { RecordInput, IdentifyUserInput } from './types/inputs'; +export { + record, + identifyUser, + flushEvents, + configureAutoTrack +} from './apis'; +export { + RecordInput, + IdentifyUserInput, + ConfigureAutoTrackInput, +} from './types/inputs'; diff --git a/packages/analytics/src/providers/pinpoint/types/index.ts b/packages/analytics/src/providers/pinpoint/types/index.ts index 14cfc65df1f..5eed2fb4477 100644 --- a/packages/analytics/src/providers/pinpoint/types/index.ts +++ b/packages/analytics/src/providers/pinpoint/types/index.ts @@ -1,5 +1,9 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -export { RecordInput, IdentifyUserInput } from './inputs'; +export { + RecordInput, + IdentifyUserInput, + ConfigureAutoTrackInput, +} from './inputs'; export { IdentifyUserOptions } from './options'; diff --git a/packages/analytics/src/providers/pinpoint/types/inputs.ts b/packages/analytics/src/providers/pinpoint/types/inputs.ts index 6a84ed9722c..5dbd0880d50 100644 --- a/packages/analytics/src/providers/pinpoint/types/inputs.ts +++ b/packages/analytics/src/providers/pinpoint/types/inputs.ts @@ -3,7 +3,10 @@ import { PinpointAnalyticsEvent } from '@aws-amplify/core/internals/providers/pinpoint'; import { IdentifyUserOptions } from '.'; -import { AnalyticsIdentifyUserInput } from '../../../types'; +import { + AnalyticsConfigureAutoTrackInput, + AnalyticsIdentifyUserInput, +} from '../../../types'; /** * Input type for Pinpoint record API. @@ -14,3 +17,8 @@ export type RecordInput = PinpointAnalyticsEvent; * Input type for Pinpoint identifyUser API. */ export type IdentifyUserInput = AnalyticsIdentifyUserInput; + +/** + * Input type for Pinpoint configureAutoTrack API. + */ +export type ConfigureAutoTrackInput = AnalyticsConfigureAutoTrackInput; diff --git a/packages/analytics/src/trackers/EventTracker.ts b/packages/analytics/src/trackers/EventTracker.ts new file mode 100644 index 00000000000..68823b68ad2 --- /dev/null +++ b/packages/analytics/src/trackers/EventTracker.ts @@ -0,0 +1,135 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { + EventTrackingOptions, + DOMEvent, + TrackerEventRecorder, + TrackerInterface, +} from '../types/trackers'; +import { ConsoleLogger } from '@aws-amplify/core'; +import { isBrowser } from '@aws-amplify/core/internals/utils'; + +const DEFAULT_EVENTS = ['click'] as DOMEvent[]; +const DEFAULT_SELECTOR_PREFIX = 'data-amplify-analytics-'; +const DEFAULT_EVENT_NAME = 'event'; // Default event name as sent to the analytics provider + +const logger = new ConsoleLogger('EventTracker'); + +export class EventTracker implements TrackerInterface { + private trackerActive: boolean; + private options: EventTrackingOptions; + private eventRecorder: TrackerEventRecorder; + + constructor( + eventRecorder: TrackerEventRecorder, + options?: EventTrackingOptions + ) { + this.options = {}; + this.trackerActive = false; + this.eventRecorder = eventRecorder; + this.handleDocEvent = this.handleDocEvent.bind(this); + + this.configure(eventRecorder, options); + } + + public configure( + eventRecorder: TrackerEventRecorder, + options?: EventTrackingOptions + ) { + this.eventRecorder = eventRecorder; + + // Clean up any existing listeners + this.cleanup(); + + // Apply defaults + this.options = { + attributes: options?.attributes ?? undefined, + events: options?.events ?? DEFAULT_EVENTS, + selectorPrefix: options?.selectorPrefix ?? DEFAULT_SELECTOR_PREFIX, + }; + + // Register event listeners + if (isBrowser()) { + this.options.events?.forEach(targetEvent => { + document.addEventListener(targetEvent, this.handleDocEvent, { + capture: true, + }); + }); + + this.trackerActive = true; + } + } + + public cleanup() { + // No-op if document listener is not active + if (!this.trackerActive) { + return; + } + + // Clean up event listeners + this.options.events?.forEach(targetEvent => { + document.removeEventListener(targetEvent, this.handleDocEvent, { + capture: true, + }); + }); + } + + private handleDocEvent(event: Event) { + /** + * Example DOM element: + * + * ``` + *