Skip to content

Commit b4e8aff

Browse files
nan-licursoragent
andauthored
feat: [JWT-5] bind each Delta to the user that owns it (#1710)
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 272bb2c commit b4e8aff

13 files changed

Lines changed: 405 additions & 29 deletions

‎iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@
299299
475F474A2B8E3B4600EC05B3 /* OneSignalLiveActivities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 475F471E2B8E398D00EC05B3 /* OneSignalLiveActivities.framework */; platformFilter = ios; };
300300
475F474F2B8E3B5400EC05B3 /* OneSignalLiveActivities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 475F471E2B8E398D00EC05B3 /* OneSignalLiveActivities.framework */; };
301301
475F47502B8E3B5400EC05B3 /* OneSignalLiveActivities.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 475F471E2B8E398D00EC05B3 /* OneSignalLiveActivities.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
302+
4E8E880086C66B4120CC0CD4 /* OSDeltaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557653D2007BFF86EA8342E4 /* OSDeltaTests.swift */; };
302303
5B053FBC2CAE07EB002F30C4 /* OneSignalOSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C115161289A259500565C41 /* OneSignalOSCore.framework */; };
303304
5B053FC32CAE0843002F30C4 /* OSConsistencyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC1DE672C90C23E00CA8807 /* OSConsistencyManagerTests.swift */; };
304305
5B58E4F8237CE7B4009401E0 /* UIDeviceOverrider.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B58E4F6237CE7B4009401E0 /* UIDeviceOverrider.m */; };
@@ -383,6 +384,7 @@
383384
91F60F7D1E80E4E400706E60 /* UncaughtExceptionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 91F60F7C1E80E4E400706E60 /* UncaughtExceptionHandler.m */; };
384385
9224347AAE3E092B5743380D /* UserJwtApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80DC5517E6EB5B26CF980CC5 /* UserJwtApiTests.swift */; };
385386
94D9F5AFE86B16453A36C9A2 /* MockUserJwtInvalidatedListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F214EE6C5FE133672D6622F /* MockUserJwtInvalidatedListener.swift */; };
387+
99B1615D0132AFAA981A9AD3 /* DeltaOwnershipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3881024646E7F0DE05158442 /* DeltaOwnershipTests.swift */; };
386388
9D3300FA23149DAE000F0A83 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D3300F923149DAE000F0A83 /* CoreGraphics.framework */; };
387389
9D348537233C669E00EB81C9 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D348536233C669E00EB81C9 /* CoreLocation.framework */; };
388390
9D34853A233D2E3600EB81C9 /* OneSignalLocationOverrider.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D348539233D2E3600EB81C9 /* OneSignalLocationOverrider.m */; };
@@ -1376,6 +1378,7 @@
13761378
2F2FC6C922FF8104F3197DD4 /* OSUserJwtInvalidatedEvent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OSUserJwtInvalidatedEvent.swift; sourceTree = "<group>"; };
13771379
37747F9319147D6500558FAD /* libOneSignal.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libOneSignal.a; sourceTree = BUILT_PRODUCTS_DIR; };
13781380
37E6B2BA19D9CAF300D0C601 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
1381+
3881024646E7F0DE05158442 /* DeltaOwnershipTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DeltaOwnershipTests.swift; sourceTree = "<group>"; };
13791382
3C01518E2C2E298E0079E076 /* OneSignalInAppMessagesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OneSignalInAppMessagesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
13801383
3C01519B2C2E29F90079E076 /* IAMRequestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IAMRequestTests.m; sourceTree = "<group>"; };
13811384
3C0EF49D28A1DBCB00E5434B /* OSUserInternalImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSUserInternalImpl.swift; sourceTree = "<group>"; };
@@ -1560,6 +1563,7 @@
15601563
475F47202B8E398E00EC05B3 /* OneSignalLiveActivities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalLiveActivities.h; sourceTree = "<group>"; };
15611564
475F47482B8E3A4400EC05B3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
15621565
4CCE2C93100CAFEE8EB39C77 /* OneSignalUserManagerImpl+Jwt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "OneSignalUserManagerImpl+Jwt.swift"; sourceTree = "<group>"; };
1566+
557653D2007BFF86EA8342E4 /* OSDeltaTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OSDeltaTests.swift; sourceTree = "<group>"; };
15631567
5953656ACCC21358BC0CF2F0 /* OSIdentityModelTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OSIdentityModelTests.swift; sourceTree = "<group>"; };
15641568
5B053FB82CAE07EB002F30C4 /* OneSignalOSCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OneSignalOSCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
15651569
5B58E4F3237CE7B3009401E0 /* UIDeviceOverrider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIDeviceOverrider.h; sourceTree = "<group>"; };
@@ -2488,6 +2492,7 @@
24882492
5953656ACCC21358BC0CF2F0 /* OSIdentityModelTests.swift */,
24892493
B5809B47EB4F2478099697CE /* OSUserJwtRepoTests.swift */,
24902494
80DC5517E6EB5B26CF980CC5 /* UserJwtApiTests.swift */,
2495+
3881024646E7F0DE05158442 /* DeltaOwnershipTests.swift */,
24912496
);
24922497
path = OneSignalUserTests;
24932498
sourceTree = "<group>";
@@ -2659,6 +2664,7 @@
26592664
3C23A21C2FCE0A83001D32E3 /* OSModelStoreRefreshTests.swift */,
26602665
FF4B19D1EC31C0750F13065A /* OSIamFetchReadyConditionTests.swift */,
26612666
5B47CE0CE255AC7128442FFF /* Jwt */,
2667+
557653D2007BFF86EA8342E4 /* OSDeltaTests.swift */,
26622668
);
26632669
path = OneSignalOSCoreTests;
26642670
sourceTree = "<group>";
@@ -4657,6 +4663,7 @@
46574663
B5FBED8247288744EB484CB5 /* OSIdentityModelTests.swift in Sources */,
46584664
2DB99C76F3532383C3B81D09 /* OSUserJwtRepoTests.swift in Sources */,
46594665
9224347AAE3E092B5743380D /* UserJwtApiTests.swift in Sources */,
4666+
99B1615D0132AFAA981A9AD3 /* DeltaOwnershipTests.swift in Sources */,
46604667
);
46614668
runOnlyForDeploymentPostprocessing = 0;
46624669
};
@@ -4739,6 +4746,7 @@
47394746
DD2A89A8052E2D1912B0038B /* OSIamFetchReadyConditionTests.swift in Sources */,
47404747
9FF50E2A40C88E4533033A38 /* OSIdentityVerificationServiceTests.swift in Sources */,
47414748
8E949FF4C7A7A2C7182E53EA /* OSUserJwtConfigTests.swift in Sources */,
4749+
4E8E880086C66B4120CC0CD4 /* OSDeltaTests.swift in Sources */,
47424750
);
47434751
runOnlyForDeploymentPostprocessing = 0;
47444752
};

‎iOS_SDK/OneSignalSDK/OneSignalOSCore/Source/OSDelta.swift‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ open class OSDelta: NSObject, NSCoding {
3636
public let deltaId: String
3737
public let timestamp: Date
3838
public let identityModelId: String
39+
/// The `external_id` of the user this change belongs to, `nil` if that user was anonymous.
40+
public let externalId: String?
3941
public var model: OSModel
4042
public let property: String
4143
public let value: Any
@@ -44,11 +46,12 @@ open class OSDelta: NSObject, NSCoding {
4446
return "<OSDelta \(name) with property: \(property) value: \(value)>"
4547
}
4648

47-
public init(name: String, identityModelId: String, model: OSModel, property: String, value: Any) {
49+
public init(name: String, identityModelId: String, externalId: String?, model: OSModel, property: String, value: Any) {
4850
self.name = name
4951
self.deltaId = UUID().uuidString
5052
self.timestamp = Date()
5153
self.identityModelId = identityModelId
54+
self.externalId = externalId
5255
self.model = model
5356
self.property = property
5457
self.value = value
@@ -59,6 +62,7 @@ open class OSDelta: NSObject, NSCoding {
5962
coder.encode(deltaId, forKey: "deltaId")
6063
coder.encode(timestamp, forKey: "timestamp")
6164
coder.encode(identityModelId, forKey: "identityModelId")
65+
coder.encode(externalId, forKey: "externalId")
6266
coder.encode(model, forKey: "model")
6367
coder.encode(property, forKey: "property")
6468
coder.encode(value, forKey: "value")
@@ -81,6 +85,7 @@ open class OSDelta: NSObject, NSCoding {
8185
self.deltaId = deltaId
8286
self.timestamp = timestamp
8387
self.identityModelId = identityModelId
88+
self.externalId = coder.decodeObject(forKey: "externalId") as? String
8489
self.model = model
8590
self.property = property
8691
self.value = value

‎iOS_SDK/OneSignalSDK/OneSignalOSCore/Source/OSModelStoreListener.swift‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ public protocol OSModelStoreListener: OSModelStoreChangedHandler {
3333

3434
var store: OSModelStore<TModel> { get }
3535

36-
init(store: OSModelStore<TModel>)
36+
// Injected: the shared enqueue below lives in OSCore, which cannot reach the User Manager.
37+
var operationRepo: OSOperationRepo { get }
38+
39+
init(store: OSModelStore<TModel>, operationRepo: OSOperationRepo)
3740

3841
func getAddModelDelta(_ model: TModel) -> OSDelta?
3942

@@ -57,13 +60,13 @@ extension OSModelStoreListener {
5760
return
5861
}
5962
if let delta = getAddModelDelta(addedModel) {
60-
OSOperationRepo.sharedInstance.enqueueDelta(delta)
63+
operationRepo.enqueueDelta(delta)
6164
}
6265
}
6366

6467
public func onUpdated(_ args: OSModelChangedArgs) {
6568
if let delta = getUpdateModelDelta(args) {
66-
OSOperationRepo.sharedInstance.enqueueDelta(delta)
69+
operationRepo.enqueueDelta(delta)
6770
}
6871
}
6972

@@ -74,7 +77,7 @@ extension OSModelStoreListener {
7477
return
7578
}
7679
if let delta = getRemoveModelDelta(removedModel) {
77-
OSOperationRepo.sharedInstance.enqueueDelta(delta)
80+
operationRepo.enqueueDelta(delta)
7881
}
7982
}
8083
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Modified MIT License
3+
4+
Copyright 2026 OneSignal
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
1. The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
2. All copies of substantial portions of the Software may only be used in connection
17+
with services provided by OneSignal.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
THE SOFTWARE.
26+
*/
27+
28+
import XCTest
29+
@testable import OneSignalOSCore
30+
31+
/// Covers `OSDelta` archive round trips, including the owning user's external ID.
32+
final class OSDeltaTests: XCTestCase {
33+
34+
private func makeDelta(externalId: String?) -> OSDelta {
35+
OSDelta(
36+
name: "test_delta",
37+
identityModelId: "identity-model-a",
38+
externalId: externalId,
39+
model: OSModel(changeNotifier: OSEventProducer()),
40+
property: "language",
41+
value: "en"
42+
)
43+
}
44+
45+
private func archiveThenUnarchive(_ delta: OSDelta) throws -> OSDelta {
46+
let data = try NSKeyedArchiver.archivedData(withRootObject: delta, requiringSecureCoding: false)
47+
let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
48+
unarchiver.requiresSecureCoding = false
49+
defer { unarchiver.finishDecoding() }
50+
return try XCTUnwrap(unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as? OSDelta)
51+
}
52+
53+
func testExternalIdSurvivesAnArchiveRoundTrip() throws {
54+
let delta = makeDelta(externalId: "user-a")
55+
56+
let decoded = try archiveThenUnarchive(delta)
57+
58+
XCTAssertEqual(decoded.externalId, "user-a")
59+
XCTAssertEqual(decoded.identityModelId, "identity-model-a")
60+
XCTAssertEqual(decoded.deltaId, delta.deltaId)
61+
}
62+
63+
/// Decode must succeed when externalId is absent, or queued work is dropped on upgrade.
64+
func testADeltaWithoutAnExternalIdStillDecodes() throws {
65+
let delta = makeDelta(externalId: nil)
66+
67+
let decoded = try archiveThenUnarchive(delta)
68+
69+
XCTAssertNil(decoded.externalId)
70+
XCTAssertEqual(decoded.identityModelId, "identity-model-a")
71+
XCTAssertEqual(decoded.property, "language")
72+
XCTAssertEqual(decoded.value as? String, "en")
73+
}
74+
}

‎iOS_SDK/OneSignalSDK/OneSignalOSCoreTests/OSOperationRepoFlushTests.swift‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ final class OSOperationRepoFlushTests: XCTestCase {
111111
OSDelta(
112112
name: name,
113113
identityModelId: UUID().uuidString,
114+
externalId: nil,
114115
model: OSModel(changeNotifier: OSEventProducer()),
115116
property: property,
116117
value: property

‎iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSIdentityModelStoreListener.swift‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ import OneSignalOSCore
3131

3232
class OSIdentityModelStoreListener: OSModelStoreListener {
3333
var store: OSModelStore<OSIdentityModel>
34+
let operationRepo: OSOperationRepo
3435

35-
required init(store: OSModelStore<OSIdentityModel>) {
36+
required init(store: OSModelStore<OSIdentityModel>, operationRepo: OSOperationRepo) {
3637
self.store = store
38+
self.operationRepo = operationRepo
3739
}
3840

3941
func getAddModelDelta(_ model: OSIdentityModel) -> OSDelta? {
@@ -50,6 +52,7 @@ class OSIdentityModelStoreListener: OSModelStoreListener {
5052
func getUpdateModelDelta(_ args: OSModelChangedArgs) -> OSDelta? {
5153
// TODO: Let users call addAliases with "" IDs? If so, this will change...
5254
guard
55+
let identityModel = args.model as? OSIdentityModel,
5356
let aliasesDict = args.newValue as? [String: String],
5457
let (_, id) = aliasesDict.first
5558
else {
@@ -60,8 +63,9 @@ class OSIdentityModelStoreListener: OSModelStoreListener {
6063

6164
return OSDelta(
6265
name: name,
63-
identityModelId: args.model.modelId,
64-
model: args.model,
66+
identityModelId: identityModel.modelId,
67+
externalId: identityModel.externalId,
68+
model: identityModel,
6569
property: args.property,
6670
value: args.newValue
6771
)

‎iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSPropertiesModelStoreListener.swift‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ import OneSignalOSCore
3131

3232
class OSPropertiesModelStoreListener: OSModelStoreListener {
3333
var store: OSModelStore<OSPropertiesModel>
34+
let operationRepo: OSOperationRepo
3435

35-
required init(store: OSModelStore<OSPropertiesModel>) {
36+
required init(store: OSModelStore<OSPropertiesModel>, operationRepo: OSOperationRepo) {
3637
self.store = store
38+
self.operationRepo = operationRepo
3739
}
3840

3941
func getAddModelDelta(_ model: OSPropertiesModel) -> OSDelta? {
@@ -45,15 +47,19 @@ class OSPropertiesModelStoreListener: OSModelStoreListener {
4547
}
4648

4749
func getUpdateModelDelta(_ args: OSModelChangedArgs) -> OSDelta? {
50+
// Drop if this isn't the current user's properties model, the user has switched since
4851
guard let _ = OSPropertiesSupportedProperty(rawValue: args.property),
49-
let userInstance = OneSignalUserManagerImpl.sharedInstance._user
52+
let userInstance = OneSignalUserManagerImpl.sharedInstance._user,
53+
userInstance.propertiesModel.modelId == args.model.modelId
5054
else {
51-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSPropertiesModelStoreListener.getUpdateModelDelta encountered unsupported property: \(args.property) or no user instance")
55+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSPropertiesModelStoreListener.getUpdateModelDelta encountered unsupported property: \(args.property), no user instance, or a properties model that is not the current user's")
5256
return nil
5357
}
58+
let identityModel = userInstance.identityModel
5459
return OSDelta(
5560
name: OS_UPDATE_PROPERTIES_DELTA,
56-
identityModelId: userInstance.identityModel.modelId,
61+
identityModelId: identityModel.modelId,
62+
externalId: identityModel.externalId,
5763
model: args.model,
5864
property: args.property,
5965
value: args.newValue

‎iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSSubscriptionModelStoreListener.swift‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,26 @@ import OneSignalOSCore
3131

3232
class OSSubscriptionModelStoreListener: OSModelStoreListener {
3333
var store: OSModelStore<OSSubscriptionModel>
34+
let operationRepo: OSOperationRepo
3435

35-
required init(store: OSModelStore<OSSubscriptionModel>) {
36+
required init(store: OSModelStore<OSSubscriptionModel>, operationRepo: OSOperationRepo) {
3637
self.store = store
38+
self.operationRepo = operationRepo
3739
}
3840

3941
func getAddModelDelta(_ model: OSSubscriptionModel) -> OSDelta? {
40-
guard let userInstance = OneSignalUserManagerImpl.sharedInstance._user else {
41-
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionModelStoreListener.getAddModelDelta has no user instance")
42+
// Stale - drop if the model is no longer in this store, the user has switched since
43+
guard let userInstance = OneSignalUserManagerImpl.sharedInstance._user,
44+
store.getModel(modelId: model.modelId) != nil
45+
else {
46+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionModelStoreListener.getAddModelDelta has no user instance or the model is not in the current store")
4247
return nil
4348
}
49+
let identityModel = userInstance.identityModel
4450
return OSDelta(
4551
name: OS_ADD_SUBSCRIPTION_DELTA,
46-
identityModelId: userInstance.identityModel.modelId,
52+
identityModelId: identityModel.modelId,
53+
externalId: identityModel.externalId,
4754
model: model,
4855
property: model.type.rawValue, // push, email, sms
4956
value: model.address ?? ""
@@ -52,15 +59,18 @@ class OSSubscriptionModelStoreListener: OSModelStoreListener {
5259

5360
/**
5461
The `property` and `value` is not needed for a remove operation, so just pass in some model data as placeholders.
62+
Stamps the current user: `onRemoved` runs after the model has left the store, so membership can't be checked.
5563
*/
5664
func getRemoveModelDelta(_ model: OSSubscriptionModel) -> OSDelta? {
5765
guard let userInstance = OneSignalUserManagerImpl.sharedInstance._user else {
5866
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionModelStoreListener.getRemoveModelDelta has no user instance")
5967
return nil
6068
}
69+
let identityModel = userInstance.identityModel
6170
return OSDelta(
6271
name: OS_REMOVE_SUBSCRIPTION_DELTA,
63-
identityModelId: userInstance.identityModel.modelId,
72+
identityModelId: identityModel.modelId,
73+
externalId: identityModel.externalId,
6474
model: model,
6575
property: model.type.rawValue, // push, email, sms
6676
value: model.address ?? ""
@@ -78,14 +88,16 @@ class OSSubscriptionModelStoreListener: OSModelStoreListener {
7888
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionModelStoreListener.getUpdateModelDelta has no user instance")
7989
return nil
8090
}
81-
if let onesignalId = userInstance.identityModel.onesignalId {
91+
let identityModel = userInstance.identityModel
92+
if let onesignalId = identityModel.onesignalId {
8293
let condition = OSIamFetchReadyCondition.sharedInstance(withId: onesignalId)
8394
condition.setSubscriptionUpdatePending(value: true)
8495
}
8596

8697
return OSDelta(
8798
name: OS_UPDATE_SUBSCRIPTION_DELTA,
88-
identityModelId: userInstance.identityModel.modelId,
99+
identityModelId: identityModel.modelId,
100+
externalId: identityModel.externalId,
89101
model: args.model,
90102
property: args.property,
91103
value: args.newValue

0 commit comments

Comments
 (0)