diff --git a/Amplify/Resources/PrivacyInfo.xcprivacy b/Amplify/Resources/PrivacyInfo.xcprivacy index 74f8af8564..190d0d18e4 100644 --- a/Amplify/Resources/PrivacyInfo.xcprivacy +++ b/Amplify/Resources/PrivacyInfo.xcprivacy @@ -2,7 +2,9 @@ + NSPrivacyCollectedDataTypes + NSPrivacyAccessedAPITypes - + diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..5bb060da74 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,21 @@ + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..5bb060da74 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,21 @@ + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Resources/PrivacyInfo.xcprivacy index 0c69ba3b3a..185f477f93 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Resources/PrivacyInfo.xcprivacy @@ -1,17 +1,32 @@ - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - - - + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Core/AWSPluginsCore/Resources/PrivacyInfo.xcprivacy index 74f8af8564..1a3690cfcb 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Core/AWSPluginsCore/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,8 @@ + NSPrivacyCollectedDataTypes + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift b/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift index b0396a634c..f73d295a6d 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift @@ -15,7 +15,7 @@ import Amplify public class AmplifyAWSServiceConfiguration { /// - Tag: AmplifyAWSServiceConfiguration.amplifyVersion - public static let amplifyVersion = "2.27.0" + public static let amplifyVersion = "2.27.2" /// - Tag: AmplifyAWSServiceConfiguration.platformName public static let platformName = "amplify-swift" diff --git a/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Resources/PrivacyInfo.xcprivacy index 0c69ba3b3a..d8de9fff81 100644 --- a/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Resources/PrivacyInfo.xcprivacy @@ -1,17 +1,19 @@ - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - - - + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyCollectedDataTypes + + diff --git a/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Sync/SubscriptionSync/ReconcileAndLocalSave/RemoteSyncReconciler.swift b/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Sync/SubscriptionSync/ReconcileAndLocalSave/RemoteSyncReconciler.swift index 1bfc0852b1..df95b21a8a 100644 --- a/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Sync/SubscriptionSync/ReconcileAndLocalSave/RemoteSyncReconciler.swift +++ b/AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Sync/SubscriptionSync/ReconcileAndLocalSave/RemoteSyncReconciler.swift @@ -33,26 +33,41 @@ struct RemoteSyncReconciler { } } - /// Reconciles the incoming `remoteModels` against the local metadata to get the disposition /// + /// GroupBy the remoteModels by model identifier and apply only the latest version of the remoteModel + /// /// - Parameters: /// - remoteModels: models retrieved from the remote store /// - localMetadatas: metadata retrieved from the local store /// - Returns: disposition of models to apply locally - static func getDispositions(_ remoteModels: [RemoteModel], - localMetadatas: [LocalMetadata]) -> [Disposition] { - guard !remoteModels.isEmpty else { + static func getDispositions( + _ remoteModels: [RemoteModel], + localMetadatas: [LocalMetadata] + ) -> [Disposition] { + let remoteModelsGroupByIdentifier = remoteModels.reduce([String: [RemoteModel]]()) { + $0.merging([ + $1.model.identifier: ($0[$1.model.identifier] ?? []) + [$1] + ], uniquingKeysWith: { $1 }) + } + + let optimizedRemoteModels = remoteModelsGroupByIdentifier.values.compactMap { + $0.sorted(by: { $0.syncMetadata.version > $1.syncMetadata.version }).first + } + + guard !optimizedRemoteModels.isEmpty else { return [] } - + guard !localMetadatas.isEmpty else { - return remoteModels.compactMap { getDisposition($0, localMetadata: nil) } + return optimizedRemoteModels.compactMap { getDisposition($0, localMetadata: nil) } } - - let metadataBymodelId = localMetadatas.reduce(into: [:]) { $0[$1.modelId] = $1 } - let dispositions = remoteModels.compactMap { getDisposition($0, localMetadata: metadataBymodelId[$0.model.identifier]) } - + + let metadataByModelId = localMetadatas.reduce(into: [:]) { $0[$1.modelId] = $1 } + let dispositions = optimizedRemoteModels.compactMap { + getDisposition($0, localMetadata: metadataByModelId[$0.model.identifier]) + } + return dispositions } diff --git a/AmplifyPlugins/DataStore/Tests/AWSDataStorePluginTests/Sync/SubscriptionSync/RemoteSyncReconcilerTests.swift b/AmplifyPlugins/DataStore/Tests/AWSDataStorePluginTests/Sync/SubscriptionSync/RemoteSyncReconcilerTests.swift index 612947d04d..1584ed3897 100644 --- a/AmplifyPlugins/DataStore/Tests/AWSDataStorePluginTests/Sync/SubscriptionSync/RemoteSyncReconcilerTests.swift +++ b/AmplifyPlugins/DataStore/Tests/AWSDataStorePluginTests/Sync/SubscriptionSync/RemoteSyncReconcilerTests.swift @@ -179,6 +179,33 @@ class RemoteSyncReconcilerTests: XCTestCase { } waitForExpectations(timeout: 1) } + + func testGetDispositions_emptyLocal_singleModelAddedAndDeleted() { + let sameId = UUID().uuidString + + let remoteModels = [ + makeRemoteModel(modelId: sameId, deleted: false, version: 1), + makeRemoteModel(modelId: sameId, deleted: true, version: 2) + ] + + let dispositions = RemoteSyncReconciler.getDispositions(remoteModels, localMetadatas: []) + + XCTAssertTrue(dispositions.isEmpty) + } + + func testGetDispositions_emptyLocal_oneModelAdded_SecondModelAddedAndDeleted() { + let sameId = UUID().uuidString + + let remoteModels = [ + makeRemoteModel(deleted: false, version: 1), + makeRemoteModel(modelId: sameId, deleted: false, version: 1), + makeRemoteModel(modelId: sameId, deleted: true, version: 2) + ] + + let dispositions = RemoteSyncReconciler.getDispositions(remoteModels, localMetadatas: []) + + XCTAssertTrue(dispositions.count == 1) + } // MARK: - Utilities diff --git a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..5bb060da74 100644 --- a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,21 @@ + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Resources/PrivacyInfo.xcprivacy index 0c69ba3b3a..185f477f93 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Resources/PrivacyInfo.xcprivacy @@ -1,17 +1,32 @@ - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - - - + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Resources/PrivacyInfo.xcprivacy index 0c69ba3b3a..185f477f93 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Resources/PrivacyInfo.xcprivacy @@ -1,17 +1,32 @@ - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - - - + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + diff --git a/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..5bb060da74 100644 --- a/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,21 @@ + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSession.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSession.swift index 7e2adf5064..fa0ca0df9a 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSession.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSession.swift @@ -17,6 +17,11 @@ public final class FaceLivenessSession: LivenessService { let baseURL: URL var serverEventListeners: [LivenessEventKind.Server: (FaceLivenessSession.SessionConfiguration) -> Void] = [:] var onComplete: (ServerDisconnection) -> Void = { _ in } + + private let livenessServiceDispatchQueue = DispatchQueue( + label: "com.amazon.aws.amplify.liveness.service", + target: .global() + ) init( websocket: WebSocketSession, @@ -77,36 +82,38 @@ public final class FaceLivenessSession: LivenessService { public func send( _ event: LivenessEvent, - eventDate: () -> Date = Date.init + eventDate: @escaping () -> Date = Date.init ) { - let encodedPayload = eventStreamEncoder.encode( - payload: event.payload, - headers: [ - ":content-type": .string("application/json"), - ":event-type": .string(event.eventTypeHeader), - ":message-type": .string("event") - ] - ) - - let eventDate = eventDate() - - let signedPayload = signer.signWithPreviousSignature( - payload: encodedPayload, - dateHeader: (key: ":date", value: eventDate) - ) - - let encodedEvent = eventStreamEncoder.encode( - payload: encodedPayload, - headers: [ - ":date": .timestamp(eventDate), - ":chunk-signature": .data(signedPayload) - ] - ) - - websocket.send( - message: .data(encodedEvent), - onError: { _ in } - ) + livenessServiceDispatchQueue.async { + let encodedPayload = self.eventStreamEncoder.encode( + payload: event.payload, + headers: [ + ":content-type": .string("application/json"), + ":event-type": .string(event.eventTypeHeader), + ":message-type": .string("event") + ] + ) + + let eventDate = eventDate() + + let signedPayload = self.signer.signWithPreviousSignature( + payload: encodedPayload, + dateHeader: (key: ":date", value: eventDate) + ) + + let encodedEvent = self.eventStreamEncoder.encode( + payload: encodedPayload, + headers: [ + ":date": .timestamp(eventDate), + ":chunk-signature": .data(signedPayload) + ] + ) + + self.websocket.send( + message: .data(encodedEvent), + onError: { _ in } + ) + } } private func fallbackDecoding(_ message: EventStream.Message) -> Bool { diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSessionRepresentable.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSessionRepresentable.swift index 92001bc980..896ef5769b 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSessionRepresentable.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Liveness/Service/FaceLivenessSessionRepresentable.swift @@ -12,7 +12,7 @@ import Amplify public protocol LivenessService { func send( _ event: LivenessEvent, - eventDate: () -> Date + eventDate: @escaping () -> Date ) var onServiceException: (FaceLivenessSessionError) -> Void { get set } diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..5bb060da74 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,21 @@ + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Predictions/CoreMLPredictionsPlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Predictions/CoreMLPredictionsPlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..1a3690cfcb 100644 --- a/AmplifyPlugins/Predictions/CoreMLPredictionsPlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Predictions/CoreMLPredictionsPlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,8 @@ + NSPrivacyCollectedDataTypes + NSPrivacyAccessedAPITypes diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Resources/PrivacyInfo.xcprivacy b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Resources/PrivacyInfo.xcprivacy index 74f8af8564..5bb060da74 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Resources/PrivacyInfo.xcprivacy +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Resources/PrivacyInfo.xcprivacy @@ -2,6 +2,21 @@ + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + NSPrivacyAccessedAPITypes diff --git a/CHANGELOG.md b/CHANGELOG.md index cafd04ad64..111e7fec66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 2.27.2 (2024-03-11) + +### Bug Fixes + +- **DataStore**: created and deleted model on one device appears as created on the other (#3554) +- **predictions**: Serialize the dispatch of web socket events (#3558) + +## 2.27.1 (2024-03-07) + +### Bug Fixes + +- add collected data types to privacy manifests (#3531) +- **DataStore**: endless retry of mutation request when server responds with 401 error code (#3511) (#3512) +- **amplify-xcode**: Fixing errors during amplify pull (#3536) + ## 2.27.0 (2024-02-22) ### Features diff --git a/Package.resolved b/Package.resolved index befb7122de..5be60bbe90 100644 --- a/Package.resolved +++ b/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlCatchException.git", "state" : { - "revision" : "3b123999de19bf04905bc1dfdb76f817b0f2cc00", - "version" : "2.1.2" + "revision" : "3ef6999c73b6938cc0da422f2c912d0158abb0a0", + "version" : "2.2.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git", "state" : { - "revision" : "dc9af4781f2afdd1e68e90f80b8603be73ea7abc", - "version" : "2.2.0" + "revision" : "2ef56b2caf25f55fa7eef8784c30d5a767550f54", + "version" : "2.2.1" } }, {