diff --git a/.vscode/settings.json b/.vscode/settings.json index 4f6369bff..8ee1cf0eb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,31 +3,31 @@ "source.fixAll.eslint": "explicit", "source.organizeImports": "always" }, + "editor.rename.enablePreview": false, // a macro to rename a variable to _variable "macros": { "rename_": [ { "javascript": [ - "const ed = vscode.window.activeTextEditor;", - "if (!ed) return;", + "const ed = vscode.window.activeTextEditor; if (!ed) return;", "const pos = ed.selection.active;", - "const rng = ed.document.getWordRangeAtPosition(pos);", - "if (!rng) return;", - "const oldName = ed.document.getText(rng);", - "// if it already starts with '_', do nothing (remove this guard if you always want to re-run)", - "if (oldName.startsWith('_')) return;", + "const rng = ed.document.getWordRangeAtPosition(pos); if (!rng) return;", + "const oldName = ed.document.getText(rng); if (oldName.startsWith('_')) return;", "const newName = '_' + oldName;", - "// Ask VS Code for a rename edit at this position", - "const edit = await vscode.commands.executeCommand(", - " 'vscode.executeDocumentRenameProvider',", - " ed.document.uri,", - " pos,", - " newName", - ");", - "if (edit) await vscode.workspace.applyEdit(edit);", - "await new Promise(resolve => setTimeout(resolve, 100));", - "await vscode.commands.executeCommand('workbench.action.files.saveAll');" + "const edit = await vscode.commands.executeCommand('vscode.executeDocumentRenameProvider', ed.document.uri, pos, newName);", + "if (!edit) return;", + "await vscode.workspace.applyEdit(edit);", + "(async () => {", + " for (let attempt = 0; attempt < 5; attempt++) {", + " let remaining = 0;", + " for (const doc of vscode.workspace.textDocuments) {", + " try { if (doc.isDirty) { remaining++; await doc.save(); } } catch (_) {}", + " }", + " if (remaining === 0) break;", + " await new Promise(r => setTimeout(r, 80));", + " }", + "})();" ] } ] diff --git a/__test__/support/environment/TestEnvironmentHelpers.ts b/__test__/support/environment/TestEnvironmentHelpers.ts index f75fde1ce..f8a2c6eaf 100644 --- a/__test__/support/environment/TestEnvironmentHelpers.ts +++ b/__test__/support/environment/TestEnvironmentHelpers.ts @@ -95,7 +95,7 @@ export const setupSubModelStore = async ({ pushModel.web_p256 = web_p256; } await setPushToken(pushModel.token); - OneSignal._coreDirector._subscriptionModelStore.replaceAll( + OneSignal._coreDirector._subscriptionModelStore._replaceAll( [pushModel], ModelChangeTags.NO_PROPAGATE, ); diff --git a/__test__/support/helpers/executors.ts b/__test__/support/helpers/executors.ts index 0b333b1d7..2bdf02530 100644 --- a/__test__/support/helpers/executors.ts +++ b/__test__/support/helpers/executors.ts @@ -5,23 +5,23 @@ export class SomeOperation extends Operation { super('some-operation'); } - get applyToRecordId() { + get _applyToRecordId() { return ''; } - get createComparisonKey() { + get _createComparisonKey() { return ''; } - get modifyComparisonKey() { + get _modifyComparisonKey() { return ''; } - get groupComparisonType() { + get _groupComparisonType() { return GroupComparisonType.CREATE; } - get canStartExecute() { + get _canStartExecute() { return true; } } diff --git a/__test__/support/helpers/setup.ts b/__test__/support/helpers/setup.ts index 1b7ce035a..818ff5c34 100644 --- a/__test__/support/helpers/setup.ts +++ b/__test__/support/helpers/setup.ts @@ -63,7 +63,7 @@ export const setupIdentityModel = async ( onesignalID: string = ONESIGNAL_ID, ) => { const newIdentityModel = new IdentityModel(); - newIdentityModel.onesignalId = onesignalID; + newIdentityModel._onesignalId = onesignalID; OneSignal._coreDirector._identityModelStore.replace( newIdentityModel, ModelChangeTags.NO_PROPAGATE, @@ -77,7 +77,7 @@ export const setupPropertiesModel = async ( onesignalID: string = ONESIGNAL_ID, ) => { const newPropertiesModel = new PropertiesModel(); - newPropertiesModel.onesignalId = onesignalID; + newPropertiesModel._onesignalId = onesignalID; OneSignal._coreDirector._propertiesModelStore.replace( newPropertiesModel, ModelChangeTags.NO_PROPAGATE, @@ -126,7 +126,7 @@ export const setupSubscriptionModel = async ( const subscriptionModel = new SubscriptionModel(); subscriptionModel.id = id || ''; subscriptionModel.token = token || ''; - OneSignal._coreDirector._subscriptionModelStore.replaceAll( + OneSignal._coreDirector._subscriptionModelStore._replaceAll( [subscriptionModel], ModelChangeTags.NO_PROPAGATE, ); diff --git a/__test__/unit/user/user.test.ts b/__test__/unit/user/user.test.ts index da3d88b9d..a0554938b 100644 --- a/__test__/unit/user/user.test.ts +++ b/__test__/unit/user/user.test.ts @@ -28,7 +28,7 @@ describe('User tests', () => { const tagsSample = { key1: 'value1' }; const propModel = OneSignal._coreDirector._getPropertiesModel(); - propModel.tags = tagsSample; + propModel._tags = tagsSample; const user = User._createOrGetInstance(); const tags = user.getTags(); @@ -42,7 +42,7 @@ describe('User tests', () => { const languageSample = 'fr'; const propModel = OneSignal._coreDirector._getPropertiesModel(); - propModel.language = languageSample; + propModel._language = languageSample; const user = User._createOrGetInstance(); const language = user.getLanguage(); @@ -59,6 +59,6 @@ describe('User tests', () => { user.setLanguage(languageSample); const propModel = OneSignal._coreDirector._getPropertiesModel(); - expect(propModel.language).toBe(languageSample); + expect(propModel._language).toBe(languageSample); }); }); diff --git a/package.json b/package.json index 1741f1c04..2eb20dacf 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ }, { "path": "./build/releases/OneSignalSDK.page.es6.js", - "limit": "47.886 kB", + "limit": "47.565 kB", "gzip": true }, { diff --git a/src/core/CoreModuleDirector.ts b/src/core/CoreModuleDirector.ts index dc8c1031c..d325fbbfe 100644 --- a/src/core/CoreModuleDirector.ts +++ b/src/core/CoreModuleDirector.ts @@ -1,5 +1,6 @@ import FuturePushSubscriptionRecord from 'src/page/userModel/FuturePushSubscriptionRecord'; import { getPushToken } from 'src/shared/database/subscription'; +import { isPushSubscriptionType } from 'src/shared/helpers/subscription'; import { IDManager } from 'src/shared/managers/IDManager'; import { SubscriptionChannel, @@ -7,7 +8,6 @@ import { } from 'src/shared/subscriptions/constants'; import type { SubscriptionChannelValue } from 'src/shared/subscriptions/types'; import { logMethodCall } from 'src/shared/utils/utils'; -import SubscriptionHelper from '../../src/shared/helpers/SubscriptionHelper'; import MainHelper from '../shared/helpers/MainHelper'; import { RawPushSubscription } from '../shared/models/RawPushSubscription'; import CoreModule from './CoreModule'; @@ -108,9 +108,7 @@ export class CoreModuleDirector { public _getAllPushSubscriptionModels(): SubscriptionModel[] { logMethodCall('CoreModuleDirector.getAllPushSubscriptionModels'); const subscriptions = this._core._subscriptionModelStore.list(); - return subscriptions.filter((s) => - SubscriptionHelper.isPushSubscriptionType(s.type), - ); + return subscriptions.filter((s) => isPushSubscriptionType(s.type)); } async _getPushSubscriptionModelByCurrentToken(): Promise< diff --git a/src/core/controllers/CustomEventController.ts b/src/core/controllers/CustomEventController.ts index 63b8f1806..5186c3c51 100644 --- a/src/core/controllers/CustomEventController.ts +++ b/src/core/controllers/CustomEventController.ts @@ -27,8 +27,8 @@ export class CustomEventController implements ICustomEventController { const op = new TrackCustomEventOperation({ appId, - onesignalId: identityModel.onesignalId, - externalId: identityModel.externalId, + onesignalId: identityModel._onesignalId, + externalId: identityModel._externalId, timestamp: new Date().toISOString(), event, }); diff --git a/src/core/executors/CustomEventOperationExecutor.ts b/src/core/executors/CustomEventOperationExecutor.ts index e9e6fb9e3..84a78a222 100644 --- a/src/core/executors/CustomEventOperationExecutor.ts +++ b/src/core/executors/CustomEventOperationExecutor.ts @@ -50,10 +50,10 @@ export class CustomEventsOperationExecutor implements IOperationExecutor { } const response = await sendCustomEvent( - { appId: operation.appId }, + { appId: operation._appId }, { name: operation.event.name, - onesignal_id: operation.onesignalId, + onesignal_id: operation._onesignalId, external_id: operation.externalId, timestamp: operation.timestamp, payload: { diff --git a/src/core/executors/IdentityOperationExecutor.test.ts b/src/core/executors/IdentityOperationExecutor.test.ts index ccce3c235..7c384072e 100644 --- a/src/core/executors/IdentityOperationExecutor.test.ts +++ b/src/core/executors/IdentityOperationExecutor.test.ts @@ -61,7 +61,7 @@ describe('IdentityOperationExecutor', () => { ); getRebuildOpsSpy = vi.spyOn( rebuildUserService, - 'getRebuildOperationsIfCurrentUser', + '_getRebuildOperationsIfCurrentUser', ); }); @@ -158,20 +158,20 @@ describe('IdentityOperationExecutor', () => { expect(res5.retryAfterSeconds).toBeUndefined(); // with rebuild ops - identityModelStore.model.onesignalId = ONESIGNAL_ID; + identityModelStore.model._onesignalId = ONESIGNAL_ID; const res7 = await executor._execute(ops); expect(res7.result).toBe(ExecutionResult.FAIL_RETRY); expect(res7.retryAfterSeconds).toBeUndefined(); expect(res7.operations).toMatchObject([ { - name: 'login-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'login-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, { - name: 'refresh-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'refresh-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, ]); diff --git a/src/core/executors/IdentityOperationExecutor.ts b/src/core/executors/IdentityOperationExecutor.ts index afbc682e7..ce15b3ebe 100644 --- a/src/core/executors/IdentityOperationExecutor.ts +++ b/src/core/executors/IdentityOperationExecutor.ts @@ -77,18 +77,18 @@ export class IdentityOperationExecutor implements IOperationExecutor { const isSetAlias = lastOperation instanceof SetAliasOperation; const request = isSetAlias ? addAlias( - { appId: lastOperation.appId }, + { appId: lastOperation._appId }, { label: IdentityConstants.ONESIGNAL_ID, - id: lastOperation.onesignalId, + id: lastOperation._onesignalId, }, { [lastOperation.label]: lastOperation.value }, ) : deleteAlias( - { appId: lastOperation.appId }, + { appId: lastOperation._appId }, { label: IdentityConstants.ONESIGNAL_ID, - id: lastOperation.onesignalId, + id: lastOperation._onesignalId, }, lastOperation.label, ); @@ -96,7 +96,8 @@ export class IdentityOperationExecutor implements IOperationExecutor { const { ok, status, retryAfterSeconds } = await request; if (ok) { if ( - this._identityModelStore.model.onesignalId === lastOperation.onesignalId + this._identityModelStore.model._onesignalId === + lastOperation._onesignalId ) { this._identityModelStore.model._setProperty( lastOperation.label, @@ -136,7 +137,7 @@ export class IdentityOperationExecutor implements IOperationExecutor { if ( status === 404 && this._newRecordState._isInMissingRetryWindow( - lastOperation.onesignalId, + lastOperation._onesignalId, ) ) return new ExecutionResponse( @@ -146,9 +147,9 @@ export class IdentityOperationExecutor implements IOperationExecutor { if (isSetAlias) { const rebuildOps = - await this._buildUserService.getRebuildOperationsIfCurrentUser( - lastOperation.appId, - lastOperation.onesignalId, + await this._buildUserService._getRebuildOperationsIfCurrentUser( + lastOperation._appId, + lastOperation._onesignalId, ); if (rebuildOps == null) diff --git a/src/core/executors/LoginUserOperationExecutor.test.ts b/src/core/executors/LoginUserOperationExecutor.test.ts index c6fd8ba35..377209977 100644 --- a/src/core/executors/LoginUserOperationExecutor.test.ts +++ b/src/core/executors/LoginUserOperationExecutor.test.ts @@ -98,7 +98,7 @@ describe('LoginUserOperationExecutor', () => { const ops = [someOp]; const result = executor._execute(ops); await expect(() => result).rejects.toThrow( - `Unrecognized operation: ${someOp.name}`, + `Unrecognized operation: ${someOp._name}`, ); }); @@ -125,7 +125,7 @@ describe('LoginUserOperationExecutor', () => { const ops2 = [loginOp, transferSubOp, someOp]; const res2 = executor._execute(ops2); await expect(res2).rejects.toThrow( - `Unrecognized operation: ${someOp.name}`, + `Unrecognized operation: ${someOp._name}`, ); }); diff --git a/src/core/executors/LoginUserOperationExecutor.ts b/src/core/executors/LoginUserOperationExecutor.ts index cba31ed6b..b0a51bcb0 100644 --- a/src/core/executors/LoginUserOperationExecutor.ts +++ b/src/core/executors/LoginUserOperationExecutor.ts @@ -70,7 +70,7 @@ export class LoginUserOperationExecutor implements IOperationExecutor { if (startingOp instanceof LoginUserOperation) return this._loginUser(startingOp, operations.slice(1)); - throw new Error(`Unrecognized operation: ${startingOp.name}`); + throw new Error(`Unrecognized operation: ${startingOp._name}`); } private async _loginUser( @@ -86,7 +86,7 @@ export class LoginUserOperationExecutor implements IOperationExecutor { const result = await this._identityOperationExecutor._execute([ new SetAliasOperation( - loginUserOp.appId, + loginUserOp._appId, loginUserOp.existingOnesignalId, IdentityConstants.EXTERNAL_ID, loginUserOp.externalId, @@ -96,9 +96,9 @@ export class LoginUserOperationExecutor implements IOperationExecutor { switch (result.result) { case ExecutionResult.SUCCESS: { const backendOneSignalId = loginUserOp.existingOnesignalId; - const opOneSignalId = loginUserOp.onesignalId; + const opOneSignalId = loginUserOp._onesignalId; - if (this._identityModelStore.model.onesignalId === opOneSignalId) { + if (this._identityModelStore.model._onesignalId === opOneSignalId) { this._identityModelStore.model._setProperty( IdentityConstants.ONESIGNAL_ID, backendOneSignalId, @@ -106,7 +106,7 @@ export class LoginUserOperationExecutor implements IOperationExecutor { ); } - if (this._propertiesModelStore.model.onesignalId === opOneSignalId) { + if (this._propertiesModelStore.model._onesignalId === opOneSignalId) { this._propertiesModelStore.model._setProperty( 'onesignalId', backendOneSignalId, @@ -118,7 +118,7 @@ export class LoginUserOperationExecutor implements IOperationExecutor { undefined, undefined, { - [loginUserOp.onesignalId]: backendOneSignalId, + [loginUserOp._onesignalId]: backendOneSignalId, }, ); } @@ -165,13 +165,13 @@ export class LoginUserOperationExecutor implements IOperationExecutor { subscriptions, ); } else { - throw new Error(`Unrecognized operation: ${operation.name}`); + throw new Error(`Unrecognized operation: ${operation._name}`); } } const subscriptionList = Object.entries(subscriptions); const response = await createNewUser( - { appId: createUserOperation.appId }, + { appId: createUserOperation._appId }, { identity, subscriptions: subscriptionList.map(([, sub]) => sub), @@ -181,13 +181,13 @@ export class LoginUserOperationExecutor implements IOperationExecutor { if (response.ok) { const backendOneSignalId = response.result.identity.onesignal_id; - const opOneSignalId = createUserOperation.onesignalId; + const opOneSignalId = createUserOperation._onesignalId; const idTranslations: Record = { - [createUserOperation.onesignalId]: backendOneSignalId, + [createUserOperation._onesignalId]: backendOneSignalId, }; - if (this._identityModelStore.model.onesignalId === opOneSignalId) { + if (this._identityModelStore.model._onesignalId === opOneSignalId) { this._identityModelStore.model._setProperty( IdentityConstants.ONESIGNAL_ID, backendOneSignalId, @@ -195,7 +195,7 @@ export class LoginUserOperationExecutor implements IOperationExecutor { ); } - if (this._propertiesModelStore.model.onesignalId === opOneSignalId) { + if (this._propertiesModelStore.model._onesignalId === opOneSignalId) { this._propertiesModelStore.model._setProperty( 'onesignalId', backendOneSignalId, @@ -238,7 +238,7 @@ export class LoginUserOperationExecutor implements IOperationExecutor { Object.keys(identity).length > 0 ? [ new RefreshUserOperation( - createUserOperation.appId, + createUserOperation._appId, backendOneSignalId, ), ] diff --git a/src/core/executors/RefreshUserOperationExecutor.test.ts b/src/core/executors/RefreshUserOperationExecutor.test.ts index 9bd7fc229..1b7abec60 100644 --- a/src/core/executors/RefreshUserOperationExecutor.test.ts +++ b/src/core/executors/RefreshUserOperationExecutor.test.ts @@ -58,7 +58,7 @@ describe('RefreshUserOperationExecutor', () => { ); getRebuildOpsSpy = vi.spyOn( buildUserService, - 'getRebuildOperationsIfCurrentUser', + '_getRebuildOperationsIfCurrentUser', ); }); @@ -108,7 +108,7 @@ describe('RefreshUserOperationExecutor', () => { const result = await executor._execute([refreshOp]); expect(result.result).toBe(ExecutionResult.SUCCESS); - expect(propertiesModelStore.model.language).not.toBe('fr'); + expect(propertiesModelStore.model._language).not.toBe('fr'); }); test('should handle successful user retrieval and update models', async () => { @@ -152,18 +152,18 @@ describe('RefreshUserOperationExecutor', () => { ); // Check properties model updates - expect(propertiesModelStore.model.country).toBe('US'); - expect(propertiesModelStore.model.language).toBe('en'); - expect(propertiesModelStore.model.tags).toEqual({ + expect(propertiesModelStore.model._country).toBe('US'); + expect(propertiesModelStore.model._language).toBe('en'); + expect(propertiesModelStore.model._tags).toEqual({ test_tag: 'test_value', test_tag_2: 'test_value_2', }); - expect(propertiesModelStore.model.timezone_id).toBe('America/New_York'); + expect(propertiesModelStore.model._timezone_id).toBe('America/New_York'); // Check subscription model updates const subscriptions = subscriptionModelStore.list(); expect(subscriptions.length).toBe(1); - expect(subscriptions[0]).toMatchObject({ + expect(subscriptions[0].toJSON()).toMatchObject({ id: SUB_ID, notification_types: NotificationType.UserOptedOut, enabled: false, @@ -181,7 +181,7 @@ describe('RefreshUserOperationExecutor', () => { pushSubModel.id = SUB_ID_2; pushSubModel.type = SubscriptionType.ChromePush; pushSubModel.token = PUSH_TOKEN; - pushSubModel.notification_types = NotificationType.Subscribed; + pushSubModel._notification_types = NotificationType.Subscribed; subscriptionModelStore.add(pushSubModel, ModelChangeTags.NO_PROPAGATE); await setPushToken(PUSH_TOKEN); @@ -262,14 +262,14 @@ describe('RefreshUserOperationExecutor', () => { retryAfterSeconds: 5, operations: [ { - name: 'login-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'login-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, { - name: 'refresh-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'refresh-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, ], }); diff --git a/src/core/executors/RefreshUserOperationExecutor.ts b/src/core/executors/RefreshUserOperationExecutor.ts index 4cdd90ffd..ba218cefb 100644 --- a/src/core/executors/RefreshUserOperationExecutor.ts +++ b/src/core/executors/RefreshUserOperationExecutor.ts @@ -2,7 +2,7 @@ import { getResponseStatusType, ResponseStatusType, } from 'src/shared/helpers/NetworkUtils'; -import SubscriptionHelper from 'src/shared/helpers/SubscriptionHelper'; +import { isPushSubscriptionType } from 'src/shared/helpers/subscription'; import Log from 'src/shared/libraries/Log'; import { NotificationType } from 'src/shared/subscriptions/constants'; import { IdentityConstants, OPERATION_NAME } from '../constants'; @@ -69,16 +69,16 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { private async _getUser(op: RefreshUserOperation): Promise { const response = await getUserByAlias( - { appId: op.appId }, + { appId: op._appId }, { label: IdentityConstants.ONESIGNAL_ID, - id: op.onesignalId, + id: op._onesignalId, }, ); const { ok, result, retryAfterSeconds, status } = response; if (ok) { - if (op.onesignalId !== this._identityModelStore.model.onesignalId) { + if (op._onesignalId !== this._identityModelStore.model._onesignalId) { return new ExecutionResponse(ExecutionResult.SUCCESS); } @@ -88,7 +88,7 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { } const propertiesModel = new PropertiesModel(); - propertiesModel.onesignalId = op.onesignalId; + propertiesModel._onesignalId = op._onesignalId; const { properties = {}, subscriptions = [] } = result; @@ -102,19 +102,19 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion model.id = sub.id!; model.token = sub.token ?? ''; - model.notification_types = + model._notification_types = sub.notification_types ?? NotificationType.Subscribed; model.type = sub.type; model.enabled = - model.notification_types !== NotificationType.UserOptedOut; + model._notification_types !== NotificationType.UserOptedOut; model.sdk = sub.sdk; model.device_os = sub.device_os; model.device_model = sub.device_model; - model.onesignalId = op.onesignalId; + model._onesignalId = op._onesignalId; // We only add a non-push subscriptions. For push, the device is the source of truth // so we don't want to cache these subscriptions from the backend. - if (!SubscriptionHelper.isPushSubscriptionType(model.type)) { + if (!isPushSubscriptionType(model.type)) { subscriptionModels.push(model); } } @@ -122,7 +122,7 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { const pushModel = await OneSignal._coreDirector._getPushSubscriptionModel(); if (pushModel) { - pushModel.onesignalId = op.onesignalId; + pushModel._onesignalId = op._onesignalId; subscriptionModels.push(pushModel); } @@ -131,7 +131,7 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { propertiesModel, ModelChangeTags.HYDRATE, ); - this._subscriptionsModelStore.replaceAll( + this._subscriptionsModelStore._replaceAll( subscriptionModels, ModelChangeTags.HYDRATE, ); @@ -154,7 +154,7 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { case ResponseStatusType.MISSING: { if ( status === 404 && - this._newRecordState._isInMissingRetryWindow(op.onesignalId) + this._newRecordState._isInMissingRetryWindow(op._onesignalId) ) return new ExecutionResponse( ExecutionResult.FAIL_RETRY, @@ -162,9 +162,9 @@ export class RefreshUserOperationExecutor implements IOperationExecutor { ); const rebuildOps = - await this._buildUserService.getRebuildOperationsIfCurrentUser( - op.appId, - op.onesignalId, + await this._buildUserService._getRebuildOperationsIfCurrentUser( + op._appId, + op._onesignalId, ); return rebuildOps ? new ExecutionResponse( diff --git a/src/core/executors/SubscriptionOperationExecutor.test.ts b/src/core/executors/SubscriptionOperationExecutor.test.ts index 6d1623e1c..1a7c76fc9 100644 --- a/src/core/executors/SubscriptionOperationExecutor.test.ts +++ b/src/core/executors/SubscriptionOperationExecutor.test.ts @@ -70,7 +70,7 @@ describe('SubscriptionOperationExecutor', () => { ); getRebuildOpsSpy = vi.spyOn( buildUserService, - 'getRebuildOperationsIfCurrentUser', + '_getRebuildOperationsIfCurrentUser', ); }); @@ -294,23 +294,23 @@ describe('SubscriptionOperationExecutor', () => { retryAfterSeconds: 5, operations: [ { - name: 'login-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'login-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, { - name: 'create-subscription', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'create-subscription', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, type: SubscriptionType.ChromePush, token: pushSubscription.token, enabled: true, subscriptionId: pushSubscription.id, }, { - name: 'refresh-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'refresh-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, ], }); diff --git a/src/core/executors/SubscriptionOperationExecutor.ts b/src/core/executors/SubscriptionOperationExecutor.ts index 140241c11..ca22e0a14 100644 --- a/src/core/executors/SubscriptionOperationExecutor.ts +++ b/src/core/executors/SubscriptionOperationExecutor.ts @@ -107,10 +107,10 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { }; const response = await createSubscriptionByAlias( - { appId: createOperation.appId }, + { appId: createOperation._appId }, { label: IdentityConstants.ONESIGNAL_ID, - id: createOperation.onesignalId, + id: createOperation._onesignalId, }, { subscription }, ); @@ -131,7 +131,7 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { ); subscriptionModel?._setProperty( 'onesignalId', - createOperation.onesignalId, + createOperation._onesignalId, ModelChangeTags.HYDRATE, ); } @@ -142,8 +142,8 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { !backendSubscriptionId ? [ new RefreshUserOperation( - createOperation.appId, - createOperation.onesignalId, + createOperation._appId, + createOperation._onesignalId, ), ] : undefined, @@ -178,7 +178,7 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { if ( status === 404 && this._newRecordState._isInMissingRetryWindow( - createOperation.onesignalId, + createOperation._onesignalId, ) ) { return new ExecutionResponse( @@ -188,9 +188,9 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { } const rebuildOps = - await this._buildUserService.getRebuildOperationsIfCurrentUser( - createOperation.appId, - createOperation.onesignalId, + await this._buildUserService._getRebuildOperationsIfCurrentUser( + createOperation._appId, + createOperation._onesignalId, ); if (!rebuildOps) return new ExecutionResponse(ExecutionResult.FAIL_NORETRY); @@ -220,7 +220,7 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { }; const response = await updateSubscriptionById( - { appId: lastOp.appId }, + { appId: lastOp._appId }, lastOp.subscriptionId, subscription, ); @@ -241,7 +241,7 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { case ResponseStatusType.MISSING: if ( status === 404 && - [lastOp.onesignalId, lastOp.subscriptionId].some((id) => + [lastOp._onesignalId, lastOp.subscriptionId].some((id) => this._newRecordState._isInMissingRetryWindow(id), ) ) { @@ -253,10 +253,10 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { return new ExecutionResponse(ExecutionResult.FAIL_NORETRY, undefined, [ new CreateSubscriptionOperation({ - appId: lastOp.appId, + appId: lastOp._appId, enabled: lastOp.enabled, notification_types: lastOp.notification_types, - onesignalId: lastOp.onesignalId, + onesignalId: lastOp._onesignalId, subscriptionId: lastOp.subscriptionId, token: lastOp.token, type: lastOp.type, @@ -271,9 +271,9 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { op: TransferSubscriptionOperation, ): Promise { const response = await transferSubscriptionById( - { appId: op.appId }, + { appId: op._appId }, op.subscriptionId, - { onesignal_id: op.onesignalId }, + { onesignal_id: op._onesignalId }, false, ); @@ -300,7 +300,7 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { op: DeleteSubscriptionOperation, ): Promise { const response = await deleteSubscriptionById( - { appId: op.appId }, + { appId: op._appId }, op.subscriptionId, ); @@ -318,7 +318,7 @@ export class SubscriptionOperationExecutor implements IOperationExecutor { switch (type) { case ResponseStatusType.MISSING: if ( - [op.onesignalId, op.subscriptionId].some((id) => + [op._onesignalId, op.subscriptionId].some((id) => this._newRecordState._isInMissingRetryWindow(id), ) ) { diff --git a/src/core/executors/UpdateUserOperationExecutor.test.ts b/src/core/executors/UpdateUserOperationExecutor.test.ts index 333c98151..8084b7130 100644 --- a/src/core/executors/UpdateUserOperationExecutor.test.ts +++ b/src/core/executors/UpdateUserOperationExecutor.test.ts @@ -43,7 +43,7 @@ describe('UpdateUserOperationExecutor', () => { ); getRebuildOpsSpy = vi.spyOn( buildUserService, - 'getRebuildOperationsIfCurrentUser', + '_getRebuildOperationsIfCurrentUser', ); // Set up initial model state @@ -91,7 +91,7 @@ describe('UpdateUserOperationExecutor', () => { const result = await executor._execute([setPropertyOp]); expect(result.result).toBe(ExecutionResult.SUCCESS); - expect(propertiesModelStore.model.language).toBe('fr'); + expect(propertiesModelStore.model._language).toBe('fr'); }); test('can set tags', async () => { @@ -105,7 +105,7 @@ describe('UpdateUserOperationExecutor', () => { const result = await executor._execute([setPropertyOp]); expect(result.result).toBe(ExecutionResult.SUCCESS); - expect(propertiesModelStore.model.tags).toEqual({ + expect(propertiesModelStore.model._tags).toEqual({ tagA: 'valueA', tagB: 'valueB', }); @@ -150,14 +150,14 @@ describe('UpdateUserOperationExecutor', () => { retryAfterSeconds: 5, operations: [ { - name: 'login-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'login-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, { - name: 'refresh-user', - appId: APP_ID, - onesignalId: ONESIGNAL_ID, + _name: 'refresh-user', + _appId: APP_ID, + _onesignalId: ONESIGNAL_ID, }, ], }); diff --git a/src/core/executors/UpdateUserOperationExecutor.ts b/src/core/executors/UpdateUserOperationExecutor.ts index 7e456e1cf..29e4f3efc 100644 --- a/src/core/executors/UpdateUserOperationExecutor.ts +++ b/src/core/executors/UpdateUserOperationExecutor.ts @@ -2,7 +2,6 @@ import { getResponseStatusType, ResponseStatusType, } from 'src/shared/helpers/NetworkUtils'; -import { PropertyOperationHelper } from 'src/shared/helpers/PropertyOperationHelper'; import Log from 'src/shared/libraries/Log'; import { IdentityConstants, OPERATION_NAME } from '../constants'; import { type IPropertiesModelKeys } from '../models/PropertiesModel'; @@ -51,14 +50,13 @@ export class UpdateUserOperationExecutor implements IOperationExecutor { for (const operation of operations) { if (operation instanceof SetPropertyOperation) { if (!appId) { - appId = operation.appId; - onesignalId = operation.onesignalId; + appId = operation._appId; + onesignalId = operation._onesignalId; } - propertiesObject = - PropertyOperationHelper.createPropertiesFromOperation( - operation, - propertiesObject, - ); + propertiesObject = createPropertiesFromOperation( + operation, + propertiesObject, + ); } else { throw new Error(`Unrecognized operation: ${operation}`); } @@ -100,7 +98,7 @@ export class UpdateUserOperationExecutor implements IOperationExecutor { ): op is SetPropertyOperation<'tags'> => op.property === 'tags'; if (ok) { - if (this._identityModelStore.model.onesignalId === onesignalId) { + if (this._identityModelStore.model._onesignalId === onesignalId) { for (const operation of operations) { if (operation instanceof SetPropertyOperation) { // removing empty string tags from operation.value to save space in IndexedDB and local memory. @@ -146,7 +144,7 @@ export class UpdateUserOperationExecutor implements IOperationExecutor { ); } const rebuildOps = - await this._buildUserService.getRebuildOperationsIfCurrentUser( + await this._buildUserService._getRebuildOperationsIfCurrentUser( appId, onesignalId, ); @@ -166,3 +164,22 @@ export class UpdateUserOperationExecutor implements IOperationExecutor { } } } + +function createPropertiesFromOperation( + operation: Operation, + properties: PropertiesObject, +): PropertiesObject { + if (operation instanceof SetPropertyOperation) { + const propertyKey = operation.property; + const allowedKeys = Object.keys(properties); + if (allowedKeys.includes(propertyKey)) { + return new PropertiesObject({ + ...properties, + [propertyKey]: operation.value, + }); + } + return new PropertiesObject({ ...properties }); + } + + throw new Error(`Unsupported operation type: ${operation._name}`); +} diff --git a/src/core/listeners/IdentityModelStoreListener.ts b/src/core/listeners/IdentityModelStoreListener.ts index 9421bc629..ad8c11101 100644 --- a/src/core/listeners/IdentityModelStoreListener.ts +++ b/src/core/listeners/IdentityModelStoreListener.ts @@ -30,12 +30,12 @@ export class IdentityModelStoreListener extends SingletonModelStoreListener, IModelChangedHandler { - public readonly modelName: IDBStoreName; - private changeSubscription: EventProducer> = + public readonly _modelName: IDBStoreName; + private _changeSubscription: EventProducer> = new EventProducer(); - private models: TModel[] = []; - private hasLoadedFromCache = false; + private _models: TModel[] = []; + private _hasLoadedFromCache = false; /** * @param modelName The persistable name of the model store. If not specified no persisting will occur. */ constructor(modelName: IDBStoreName) { - this.modelName = modelName; + this._modelName = modelName; } /** * Create a model from JSON data */ - abstract create(json?: DBModel | null): TModel | null; + abstract _create(json?: DBModel | null): TModel | null; add(model: TModel, tag: ModelChangeTagValue = ModelChangeTags.NORMAL): void { - const oldModel = this.models.find((m) => m._modelId === model._modelId); - if (oldModel) this.removeItem(oldModel, tag); - this.addItem(model, tag); + const oldModel = this._models.find((m) => m._modelId === model._modelId); + if (oldModel) this._removeItem(oldModel, tag); + this._addItem(model, tag); } addAt( @@ -72,86 +72,86 @@ export abstract class ModelStore< model: TModel, tag: ModelChangeTagValue = ModelChangeTags.NORMAL, ): void { - const oldModel = this.models.find((m) => m._modelId === model._modelId); - if (oldModel) this.removeItem(oldModel, tag); - this.addItem(model, tag, index); + const oldModel = this._models.find((m) => m._modelId === model._modelId); + if (oldModel) this._removeItem(oldModel, tag); + this._addItem(model, tag, index); } /** * @returns list of read-only models, cloned for thread safety */ list(): TModel[] { - return this.models; + return this._models; } get(id: string): TModel | undefined { - return this.models.find((m) => m._modelId === id); + return this._models.find((m) => m._modelId === id); } remove(id: string, tag: ModelChangeTagValue = ModelChangeTags.NORMAL): void { - const model = this.models.find((m) => m._modelId === id); + const model = this._models.find((m) => m._modelId === id); if (!model) return; - this.removeItem(model, tag); + this._removeItem(model, tag); } _onChanged(args: ModelChangedArgs, tag: string): void { - this.persist(); - this.changeSubscription.fire((handler) => + this._persist(); + this._changeSubscription.fire((handler) => handler._onModelUpdated(args, tag), ); } - replaceAll( + _replaceAll( newModels: TModel[], tag: ModelChangeTagValue = ModelChangeTags.NORMAL, ) { - this.clear(tag); + this._clear(tag); for (const model of newModels) { this.add(model, tag); } } - clear(tag: ModelChangeTagValue = ModelChangeTags.NORMAL): void { - for (const item of this.models) { + _clear(tag: ModelChangeTagValue = ModelChangeTags.NORMAL): void { + for (const item of this._models) { // no longer listen for changes to this model item._unsubscribe(this); - this.changeSubscription.fire((handler) => + this._changeSubscription.fire((handler) => handler._onModelRemoved(item, tag), ); - db.delete(this.modelName, item._modelId); + db.delete(this._modelName, item._modelId); } - this.models = []; + this._models = []; } - private addItem(model: TModel, tag: string, index?: number): void { + private _addItem(model: TModel, tag: string, index?: number): void { if (index !== undefined) { - this.models.splice(index, 0, model); + this._models.splice(index, 0, model); } else { - this.models.push(model); + this._models.push(model); } // listen for changes to this model model._subscribe(this); - this.persist(); + this._persist(); - this.changeSubscription.fire((handler) => + this._changeSubscription.fire((handler) => handler._onModelAdded(model, tag), ); } - private async removeItem(model: TModel, tag: string): Promise { - const index = this.models.findIndex((m) => m._modelId === model._modelId); - if (index !== -1) this.models.splice(index, 1); + private async _removeItem(model: TModel, tag: string): Promise { + const index = this._models.findIndex((m) => m._modelId === model._modelId); + if (index !== -1) this._models.splice(index, 1); // no longer listen for changes to this model model._unsubscribe(this); - await db.delete(this.modelName, model._modelId); - this.persist(); + await db.delete(this._modelName, model._modelId); + this._persist(); - this.changeSubscription.fire((handler) => + this._changeSubscription.fire((handler) => handler._onModelRemoved(model, tag), ); } @@ -160,27 +160,29 @@ export abstract class ModelStore< * When models are loaded from the cache, they are added to the front of existing models. * This is primarily to address operations which can enqueue before this method is called. */ - protected async load(): Promise { - if (!this.modelName) return; + protected async _load(): Promise { + if (!this._modelName) return; - const jsonArray = (await db.getAll(this.modelName)) as unknown as DBModel[]; + const jsonArray = (await db.getAll( + this._modelName, + )) as unknown as DBModel[]; - const shouldRePersist = this.models.length > 0; + const shouldRePersist = this._models.length > 0; for (let index = jsonArray.length - 1; index >= 0; index--) { - const newModel = this.create(jsonArray[index]); + const newModel = this._create(jsonArray[index]); if (!newModel) continue; - this.models.unshift(newModel); + this._models.unshift(newModel); // listen for changes to this model newModel._subscribe(this); } - this.hasLoadedFromCache = true; + this._hasLoadedFromCache = true; // optimization only: to avoid unnecessary writes if (shouldRePersist) { - this.persist(); + this._persist(); } } @@ -189,27 +191,27 @@ export abstract class ModelStore< * The time between any changes and loading from cache should be minuscule so lack of persistence is safe. * This is primarily to address operations which can enqueue before load() is called. */ - async persist(): Promise { - if (!this.modelName || !this.hasLoadedFromCache) return; + async _persist(): Promise { + if (!this._modelName || !this._hasLoadedFromCache) return; - for (const model of this.models) { - await db.put(this.modelName, { + for (const model of this._models) { + await db.put(this._modelName, { modelId: model._modelId, - modelName: this.modelName, // TODO: ModelName is a legacy property, could be removed sometime after web refactor launch + modelName: this._modelName, // TODO: ModelName is a legacy property, could be removed sometime after web refactor launch ...model.toJSON(), - } as IndexedDBSchema[typeof this.modelName]['value']); + } as IndexedDBSchema[typeof this._modelName]['value']); } } _subscribe(handler: IModelStoreChangeHandler): void { - this.changeSubscription._subscribe(handler); + this._changeSubscription._subscribe(handler); } _unsubscribe(handler: IModelStoreChangeHandler): void { - this.changeSubscription._unsubscribe(handler); + this._changeSubscription._unsubscribe(handler); } get _hasSubscribers(): boolean { - return this.changeSubscription._hasSubscribers; + return this._changeSubscription._hasSubscribers; } } diff --git a/src/core/modelRepo/OperationModelStore.ts b/src/core/modelRepo/OperationModelStore.ts index c896604c4..8883b5669 100644 --- a/src/core/modelRepo/OperationModelStore.ts +++ b/src/core/modelRepo/OperationModelStore.ts @@ -21,17 +21,17 @@ export class OperationModelStore extends ModelStore { super('operations' satisfies IDBStoreName); } - async loadOperations(): Promise { - return this.load(); + async _loadOperations(): Promise { + return this._load(); } - create(jsonObject?: { name?: string } | null): Operation | null { + _create(jsonObject?: { name?: string } | null): Operation | null { if (jsonObject === null) { Log._error('null jsonObject sent to OperationModelStore.create'); return null; } - if (!this.isValidOperation(jsonObject)) { + if (!this._isValidOperation(jsonObject)) { return null; } @@ -87,7 +87,7 @@ export class OperationModelStore extends ModelStore { * * @param object The JSON object that represents an Operation */ - private isValidOperation(object?: { + private _isValidOperation(object?: { name?: string; onesignalId?: string; }): object is { diff --git a/src/core/modelRepo/RebuildUserService.ts b/src/core/modelRepo/RebuildUserService.ts index 65ec637ee..457296bb4 100644 --- a/src/core/modelRepo/RebuildUserService.ts +++ b/src/core/modelRepo/RebuildUserService.ts @@ -27,7 +27,7 @@ export class RebuildUserService implements IRebuildUserService { this._subscriptionsModelStore = _subscriptionsModelStore; } - async getRebuildOperationsIfCurrentUser( + async _getRebuildOperationsIfCurrentUser( appId: string, onesignalId: string, ): Promise { @@ -47,13 +47,13 @@ export class RebuildUserService implements IRebuildUserService { subscriptionModels.push(subscriptionModel); } - if (identityModel.onesignalId !== onesignalId) { + if (identityModel._onesignalId !== onesignalId) { return null; } const operations: Operation[] = []; operations.push( - new LoginUserOperation(appId, onesignalId, identityModel.externalId), + new LoginUserOperation(appId, onesignalId, identityModel._externalId), ); const pushSubscription = @@ -67,7 +67,7 @@ export class RebuildUserService implements IRebuildUserService { type: pushSubscription.type, enabled: pushSubscription.enabled, token: pushSubscription.token, - notification_types: pushSubscription.notification_types, + notification_types: pushSubscription._notification_types, }), ); } diff --git a/src/core/modelStores/SimpleModelStore.ts b/src/core/modelStores/SimpleModelStore.ts index 7ea04a7b6..8596b19e5 100644 --- a/src/core/modelStores/SimpleModelStore.ts +++ b/src/core/modelStores/SimpleModelStore.ts @@ -10,20 +10,20 @@ import type { IDBStoreName } from 'src/shared/database/types'; * which provides a basic create() method using the passed-in factory. */ export class SimpleModelStore extends ModelStore { - private readonly _create: () => TModel; + private readonly _createFn: () => TModel; /** - * @param _create A factory function used to instantiate a new model instance. + * @param _createFn A factory function used to instantiate a new model instance. * @param modelName Name for persistence. */ - constructor(_create: () => TModel, modelName: IDBStoreName) { + constructor(createFn: () => TModel, modelName: IDBStoreName) { super(modelName); - this._create = _create; - this.load(); // Automatically load on construction + this._createFn = createFn; + this._load(); // Automatically load on construction } - override create(modelData?: DatabaseModel): TModel { - const model = this._create(); + override _create(modelData?: DatabaseModel): TModel { + const model = this._createFn(); if (modelData != null) { model._initializeFromJson(modelData); } diff --git a/src/core/modelStores/SingletonModelStore.ts b/src/core/modelStores/SingletonModelStore.ts index ae10e5f02..ff85d1dd2 100644 --- a/src/core/modelStores/SingletonModelStore.ts +++ b/src/core/modelStores/SingletonModelStore.ts @@ -27,7 +27,7 @@ export class SingletonModelStore const model = this.store.list()[0]; if (model) return model; - const createdModel = this.store.create(); + const createdModel = this.store._create(); if (!createdModel) throw new Error(`Unable to initialize model from store ${this.store}`); @@ -38,7 +38,7 @@ export class SingletonModelStore replace(model: TModel, tag?: ModelChangeTagValue): void { const existingModel = this.model; existingModel._initializeFromModel(existingModel._modelId, model); - this.store.persist(); + this.store._persist(); this.changeSubscription.fire((handler) => handler._onModelReplaced(existingModel, tag), ); diff --git a/src/core/modelStores/SubscriptionModelStore.ts b/src/core/modelStores/SubscriptionModelStore.ts index 5c39bd9f6..b7efb23d8 100644 --- a/src/core/modelStores/SubscriptionModelStore.ts +++ b/src/core/modelStores/SubscriptionModelStore.ts @@ -4,7 +4,7 @@ import { type ModelChangeTagValue, } from 'src/core/types/models'; import type { IDBStoreName } from 'src/shared/database/types'; -import SubscriptionHelper from 'src/shared/helpers/SubscriptionHelper'; +import { isPushSubscriptionType } from 'src/shared/helpers/subscription'; import { SubscriptionModel } from '../models/SubscriptionModel'; // Implements logic similar to Android SDK's SubscriptionModelStore @@ -21,17 +21,17 @@ export class SubscriptionModelStore extends SimpleModelStore return super.list().find((m) => m.id === subscriptionId); } - override replaceAll( + override _replaceAll( models: SubscriptionModel[], tag?: ModelChangeTagValue, ): void { if (tag !== ModelChangeTags.HYDRATE) { - return super.replaceAll(models, tag); + return super._replaceAll(models, tag); } // When hydrating, preserve properties from existing PUSH subscription for (const model of models) { - if (SubscriptionHelper.isPushSubscriptionType(model.type)) { + if (isPushSubscriptionType(model.type)) { const existingPushModel = this.get(model._modelId); if (existingPushModel) { model.sdk = existingPushModel.sdk; @@ -41,6 +41,6 @@ export class SubscriptionModelStore extends SimpleModelStore } } - super.replaceAll(models, tag); + super._replaceAll(models, tag); } } diff --git a/src/core/models/IdentityModel.ts b/src/core/models/IdentityModel.ts index 07ffe6f82..330402393 100644 --- a/src/core/models/IdentityModel.ts +++ b/src/core/models/IdentityModel.ts @@ -13,22 +13,22 @@ export class IdentityModel extends Model { * WARNING: This *might* be a local ID depending on whether the user has been * successfully created on the backend or not. */ - get onesignalId(): string { + get _onesignalId(): string { return this._getProperty(IdentityConstants.ONESIGNAL_ID); } - set onesignalId(value: string) { + set _onesignalId(value: string) { this._setProperty(IdentityConstants.ONESIGNAL_ID, value); } /** * The (developer-managed) identifier that uniquely identifies this user. */ - get externalId(): string | undefined { + get _externalId(): string | undefined { return this._getProperty(IdentityConstants.EXTERNAL_ID); } - set externalId(value: string | undefined) { + set _externalId(value: string | undefined) { this._setProperty(IdentityConstants.EXTERNAL_ID, value); } } diff --git a/src/core/models/PropertiesModel.ts b/src/core/models/PropertiesModel.ts index 5688d1b4e..a97a2654a 100644 --- a/src/core/models/PropertiesModel.ts +++ b/src/core/models/PropertiesModel.ts @@ -20,45 +20,45 @@ export class PropertiesModel extends Model { super(); } - get onesignalId(): string { + get _onesignalId(): string { return this._getProperty('onesignalId'); } - set onesignalId(value: string) { + set _onesignalId(value: string) { this._setProperty('onesignalId', value); } - get ip(): string | undefined { + get _ip(): string | undefined { return this._getProperty('ip'); } - set ip(value: string | undefined) { + set _ip(value: string | undefined) { this._setProperty('ip', value); } - get country(): string | undefined { + get _country(): string | undefined { return this._getProperty('country'); } - set country(value: string | undefined) { + set _country(value: string | undefined) { this._setProperty('country', value); } - get language(): string | undefined { + get _language(): string | undefined { return this._getProperty('language'); } - set language(value: string | undefined) { + set _language(value: string | undefined) { this._setProperty('language', value); } - get timezone_id(): string | undefined { + get _timezone_id(): string | undefined { return this._getProperty('timezone_id'); } - set timezone_id(value: string | undefined) { + set _timezone_id(value: string | undefined) { this._setProperty('timezone_id', value); } - get tags(): Record { + get _tags(): Record { return this._getProperty('tags') ?? {}; } - set tags(value: Record) { + set _tags(value: Record) { this._setProperty('tags', value); } } diff --git a/src/core/models/SubscriptionModel.ts b/src/core/models/SubscriptionModel.ts index f5d4352b3..fef1e1d94 100644 --- a/src/core/models/SubscriptionModel.ts +++ b/src/core/models/SubscriptionModel.ts @@ -36,10 +36,10 @@ export class SubscriptionModel extends Model { /** * This is a legacy property, could be removed sometime after web refactor launch */ - get onesignalId(): string | undefined { + get _onesignalId(): string | undefined { return this._getProperty('onesignalId'); } - set onesignalId(value: string | undefined) { + set _onesignalId(value: string | undefined) { this._setProperty('onesignalId', value); } @@ -76,10 +76,10 @@ export class SubscriptionModel extends Model { } // Android SDK refers to this as status - get notification_types(): NotificationTypeValue | undefined { + get _notification_types(): NotificationTypeValue | undefined { return this._getProperty('notification_types'); } - set notification_types(value: NotificationTypeValue | undefined) { + set _notification_types(value: NotificationTypeValue | undefined) { this._setProperty('notification_types', value); } diff --git a/src/core/operationRepo/OperationRepo.test.ts b/src/core/operationRepo/OperationRepo.test.ts index 5165fe6d9..6e5f348c5 100644 --- a/src/core/operationRepo/OperationRepo.test.ts +++ b/src/core/operationRepo/OperationRepo.test.ts @@ -19,7 +19,7 @@ import { OP_REPO_POST_CREATE_DELAY, } from './constants'; import { NewRecordsState } from './NewRecordsState'; -import { OperationQueueItem, OperationRepo } from './OperationRepo'; +import { OperationRepo } from './OperationRepo'; vi.spyOn(Log, '_error').mockImplementation((msg) => { if (typeof msg === 'string' && msg.includes('Operation execution failed')) @@ -30,7 +30,7 @@ vi.spyOn(Log, '_error').mockImplementation((msg) => { vi.useFakeTimers(); // for the sake of testing, we want to use a simple mock operation and execturo -vi.spyOn(OperationModelStore.prototype, 'create').mockImplementation(() => { +vi.spyOn(OperationModelStore.prototype, '_create').mockImplementation(() => { return null; }); @@ -224,43 +224,49 @@ describe('OperationRepo', () => { const singleOp = new Operation('1', GroupComparisonType.NONE); const groupedOps = getGroupedOp(); - let op = new OperationQueueItem({ + let op = { operation: singleOp, bucket: 0, - }); + retries: 0, + }; // single operation should be returned as is expect(opRepo._getGroupableOperations(op)).toEqual([op]); // can group operations by same create comparison key - op = new OperationQueueItem({ + op = { operation: groupedOps[0], bucket: 0, - }); - let op2 = new OperationQueueItem({ + retries: 0, + }; + let op2 = { operation: groupedOps[1], bucket: 0, - }); + retries: 0, + }; opRepo._enqueue(op2.operation); expect(opRepo._getGroupableOperations(op)).toEqual([op, op2]); // can group operations by same modify comparison key - op = new OperationQueueItem({ + op = { operation: new Operation('1', GroupComparisonType.ALTER, '', 'abc'), bucket: 0, - }); - op2 = new OperationQueueItem({ + retries: 0, + }; + op2 = { operation: new Operation('2', GroupComparisonType.ALTER, '', 'abc'), bucket: 0, - }); + retries: 0, + }; opRepo._enqueue(op2.operation); expect(opRepo._getGroupableOperations(op)).toEqual([op, op2]); // throws for no comparison keys - op = new OperationQueueItem({ + op = { operation: new Operation('1', GroupComparisonType.CREATE), bucket: 0, - }); + retries: 0, + }; opRepo._enqueue(op2.operation); expect(() => opRepo._getGroupableOperations(op)).toThrow( 'Both comparison keys cannot be blank!', @@ -271,10 +277,11 @@ describe('OperationRepo', () => { const records = opRepo._records; records.set(blockedId, Date.now()); - op = new OperationQueueItem({ + op = { operation: new Operation('1', GroupComparisonType.CREATE, 'def'), bucket: 0, - }); + retries: 0, + }; op2.operation._setProperty('onesignalId', blockedId); opRepo._enqueue(op2.operation); @@ -446,7 +453,7 @@ describe('OperationRepo', () => { const executeOperationsSpy = vi.spyOn(opRepo, '_executeOperations'); const newOp = new Operation('2', GroupComparisonType.NONE); - const opTranslateIdsSpy = vi.spyOn(newOp, 'translateIds'); + const opTranslateIdsSpy = vi.spyOn(newOp, '_translateIds'); opRepo._enqueue(mockOperation); opRepo._enqueue(newOp); @@ -504,11 +511,11 @@ describe('OperationRepo', () => { const translateIdsFn = vi.fn(); class Operation extends OperationBase<{ value: string }> { - private _groupComparisonTypeValue: GroupComparisonValue; - private _createComparisonKey: string; - private _modifyComparisonKey: string; - private _applyToRecordId: string; - private _canStartExecute: boolean; + private __groupComparisonTypeValue: GroupComparisonValue; + private __createComparisonKey: string; + private __modifyComparisonKey: string; + private __applyToRecordId: string; + private __canStartExecute: boolean; constructor( value: string, @@ -520,11 +527,11 @@ class Operation extends OperationBase<{ value: string }> { ) { super('mock-op', APP_ID, ONESIGNAL_ID); this.value = value; - this._groupComparisonTypeValue = groupComparisonTypeValue; - this._createComparisonKey = createComparisonKey; - this._modifyComparisonKey = modifyComparisonKey; - this._applyToRecordId = applyToRecordId; - this._canStartExecute = canStartExecute; + this.__groupComparisonTypeValue = groupComparisonTypeValue; + this.__createComparisonKey = createComparisonKey; + this.__modifyComparisonKey = modifyComparisonKey; + this.__applyToRecordId = applyToRecordId; + this.__canStartExecute = canStartExecute; } get value(): string { @@ -534,31 +541,31 @@ class Operation extends OperationBase<{ value: string }> { this._setProperty('value', value); } - get groupComparisonType(): GroupComparisonValue { - return this._groupComparisonTypeValue; + get _groupComparisonType(): GroupComparisonValue { + return this.__groupComparisonTypeValue; } - get createComparisonKey(): string { - return this._createComparisonKey; + get _createComparisonKey(): string { + return this.__createComparisonKey; } - get modifyComparisonKey(): string { - return this._modifyComparisonKey; + get _modifyComparisonKey(): string { + return this.__modifyComparisonKey; } - get applyToRecordId(): string { - return this._applyToRecordId; + get _applyToRecordId(): string { + return this.__applyToRecordId; } - set applyToRecordId(value: string) { - this._applyToRecordId = value; + set _applyToRecordId(value: string) { + this.__applyToRecordId = value; } - get canStartExecute(): boolean { - return this._canStartExecute; + get _canStartExecute(): boolean { + return this.__canStartExecute; } - translateIds() { + _translateIds() { translateIdsFn(); } } @@ -575,6 +582,6 @@ const executeFn: Mock = vi.fn(async () => ({ })); const mockExecutor: IOperationExecutor = { - _operations: [mockOperation.name], + _operations: [mockOperation._name], _execute: executeFn, }; diff --git a/src/core/operationRepo/OperationRepo.ts b/src/core/operationRepo/OperationRepo.ts index 8584191e4..b9cd05bc7 100644 --- a/src/core/operationRepo/OperationRepo.ts +++ b/src/core/operationRepo/OperationRepo.ts @@ -22,27 +22,11 @@ const removeOpFromDB = (op: Operation) => { // Implements logic similar to Android SDK's OperationRepo & OperationQueueItem // Reference: https://github.com/OneSignal/OneSignal-Android-SDK/blob/5.1.31/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt -export class OperationQueueItem { - public operation: Operation; - public bucket: number; - public retries: number; - public resolver?: (value: boolean) => void; - - constructor(props: { - operation: Operation; - bucket: number; - retries?: number; - resolver?: (value: boolean) => void; - }) { - this.operation = props.operation; - this.bucket = props.bucket; - this.retries = props.retries ?? 0; - this.resolver = props.resolver; - } - - toString(): string { - return `bucket:${this.bucket}, retries:${this.retries}, operation:${this.operation}\n`; - } +export interface OperationQueueItem { + operation: Operation; + bucket: number; + retries: number; + resolver?: (value: boolean) => void; } // OperationRepo Class @@ -103,10 +87,11 @@ export class OperationRepo implements IOperationRepo, IStartableService { Log._debug(`OperationRepo.enqueue(operation: ${operation})`); this._internalEnqueue( - new OperationQueueItem({ + { operation, bucket: this._enqueueIntoBucket, - }), + retries: 0, + }, true, ); } @@ -116,11 +101,12 @@ export class OperationRepo implements IOperationRepo, IStartableService { await new Promise((resolve, reject) => { this._internalEnqueue( - new OperationQueueItem({ + { operation, bucket: this._enqueueIntoBucket, + retries: 0, resolver: (value) => (value ? resolve() : reject()), - }), + }, true, ); }); @@ -174,11 +160,11 @@ export class OperationRepo implements IOperationRepo, IStartableService { public async _executeOperations(ops: OperationQueueItem[]): Promise { try { const startingOp = ops[0]; - const executor = this._executorsMap.get(startingOp.operation.name); + const executor = this._executorsMap.get(startingOp.operation._name); if (!executor) { throw new Error( - `Could not find executor for operation ${startingOp.operation.name}`, + `Could not find executor for operation ${startingOp.operation._name}`, ); } @@ -190,9 +176,9 @@ export class OperationRepo implements IOperationRepo, IStartableService { // Handle ID translations if (idTranslations) { - ops.forEach((op) => op.operation.translateIds(idTranslations)); + ops.forEach((op) => op.operation._translateIds(idTranslations)); this._queue.forEach((item) => - item.operation.translateIds(idTranslations), + item.operation._translateIds(idTranslations), ); Object.values(idTranslations).forEach((id) => @@ -258,10 +244,11 @@ export class OperationRepo implements IOperationRepo, IStartableService { // Handle additional operations from the response if (response.operations) { for (const op of [...response.operations].reverse()) { - const queueItem = new OperationQueueItem({ + const queueItem = { operation: op, bucket: 0, - }); + retries: 0, + }; this._queue.unshift(queueItem); this._operationModelStore.addAt(0, queueItem.operation); } @@ -304,8 +291,8 @@ export class OperationRepo implements IOperationRepo, IStartableService { public _getNextOps(bucketFilter: number): OperationQueueItem[] | null { const startingOpIndex = this._queue.findIndex( (item) => - item.operation.canStartExecute && - this._newRecordState._canAccess(item.operation.applyToRecordId) && + item.operation._canStartExecute && + this._newRecordState._canAccess(item.operation._applyToRecordId) && item.bucket <= bucketFilter, ); @@ -323,27 +310,27 @@ export class OperationRepo implements IOperationRepo, IStartableService { ): OperationQueueItem[] { const ops = [startingOp]; - if (startingOp.operation.groupComparisonType === GroupComparisonType.NONE) + if (startingOp.operation._groupComparisonType === GroupComparisonType.NONE) return ops; const startingKey = - startingOp.operation.groupComparisonType === GroupComparisonType.CREATE - ? startingOp.operation.createComparisonKey - : startingOp.operation.modifyComparisonKey; + startingOp.operation._groupComparisonType === GroupComparisonType.CREATE + ? startingOp.operation._createComparisonKey + : startingOp.operation._modifyComparisonKey; // Create a copy of queue to avoid modification during iteration const queueCopy = [...this._queue]; for (const item of queueCopy) { const itemKey = - startingOp.operation.groupComparisonType === GroupComparisonType.CREATE - ? item.operation.createComparisonKey - : item.operation.modifyComparisonKey; + startingOp.operation._groupComparisonType === GroupComparisonType.CREATE + ? item.operation._createComparisonKey + : item.operation._modifyComparisonKey; if (itemKey === '' && startingKey === '') throw new Error('Both comparison keys cannot be blank!'); - if (!this._newRecordState._canAccess(item.operation.applyToRecordId)) + if (!this._newRecordState._canAccess(item.operation._applyToRecordId)) continue; if (itemKey === startingKey) { @@ -359,15 +346,16 @@ export class OperationRepo implements IOperationRepo, IStartableService { } public async _loadSavedOperations(): Promise { - await this._operationModelStore.loadOperations(); + await this._operationModelStore._loadOperations(); const operations = [...this._operationModelStore.list()].reverse(); for (const operation of operations) { this._internalEnqueue( - new OperationQueueItem({ + { operation, bucket: this._enqueueIntoBucket, - }), + retries: 0, + }, false, 0, ); diff --git a/src/core/operations/BaseSubscriptionOperation.ts b/src/core/operations/BaseSubscriptionOperation.ts index 67ea1714f..97d12c568 100644 --- a/src/core/operations/BaseSubscriptionOperation.ts +++ b/src/core/operations/BaseSubscriptionOperation.ts @@ -33,27 +33,27 @@ export abstract class BaseSubscriptionOperation< this._setProperty('subscriptionId', value); } - override get createComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}`; + override get _createComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}`; } - override get modifyComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}.Subscription.${this.subscriptionId}`; + override get _modifyComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}.Subscription.${this.subscriptionId}`; } - override get canStartExecute(): boolean { + override get _canStartExecute(): boolean { return ( - !IDManager._isLocalId(this.onesignalId) && + !IDManager._isLocalId(this._onesignalId) && !IDManager._isLocalId(this.subscriptionId) ); } - override get applyToRecordId(): string { + override get _applyToRecordId(): string { return this.subscriptionId; } - override translateIds(map: Record): void { - super.translateIds(map); + override _translateIds(map: Record): void { + super._translateIds(map); if (map[this.subscriptionId]) { this.subscriptionId = map[this.subscriptionId]; } diff --git a/src/core/operations/BaseTagOperation.ts b/src/core/operations/BaseTagOperation.ts index b174c2183..03cf87605 100644 --- a/src/core/operations/BaseTagOperation.ts +++ b/src/core/operations/BaseTagOperation.ts @@ -31,7 +31,7 @@ export abstract class BaseTagOperation< this._setProperty('key', value); } - override get modifyComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}`; + override get _modifyComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}`; } } diff --git a/src/core/operations/CreateSubscriptionOperation.ts b/src/core/operations/CreateSubscriptionOperation.ts index 6e022ab0c..6d64da11c 100644 --- a/src/core/operations/CreateSubscriptionOperation.ts +++ b/src/core/operations/CreateSubscriptionOperation.ts @@ -19,17 +19,17 @@ export class CreateSubscriptionOperation extends BaseFullSubscriptionOperation { ); } - override get canStartExecute(): boolean { - return !IDManager._isLocalId(this.onesignalId); + override get _canStartExecute(): boolean { + return !IDManager._isLocalId(this._onesignalId); } - override get applyToRecordId(): string { - return this.onesignalId; + override get _applyToRecordId(): string { + return this._onesignalId; } - override translateIds(map: Record): void { - if (map[this.onesignalId]) { - this.onesignalId = map[this.onesignalId]; + override _translateIds(map: Record): void { + if (map[this._onesignalId]) { + this._onesignalId = map[this._onesignalId]; } } } diff --git a/src/core/operations/DeleteAliasOperation.ts b/src/core/operations/DeleteAliasOperation.ts index 9f36a25d9..9aa51eea6 100644 --- a/src/core/operations/DeleteAliasOperation.ts +++ b/src/core/operations/DeleteAliasOperation.ts @@ -11,11 +11,11 @@ export class DeleteAliasOperation extends BaseAliasOperation { super(OPERATION_NAME.DELETE_ALIAS, appId, onesignalId, label); } - override get modifyComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}.Alias.${this.label}`; + override get _modifyComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}.Alias.${this.label}`; } - override get groupComparisonType(): GroupComparisonValue { + override get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.NONE; } } diff --git a/src/core/operations/DeleteSubscriptionOperation.ts b/src/core/operations/DeleteSubscriptionOperation.ts index 09b9abbfd..62ecbfe7b 100644 --- a/src/core/operations/DeleteSubscriptionOperation.ts +++ b/src/core/operations/DeleteSubscriptionOperation.ts @@ -13,7 +13,7 @@ export class DeleteSubscriptionOperation extends BaseSubscriptionOperation { if (subscriptionId) this.subscriptionId = subscriptionId; } - override get groupComparisonType(): GroupComparisonValue { + override get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.NONE; } } diff --git a/src/core/operations/LoginUserOperation.ts b/src/core/operations/LoginUserOperation.ts index 96487a7ca..d6b03b547 100644 --- a/src/core/operations/LoginUserOperation.ts +++ b/src/core/operations/LoginUserOperation.ts @@ -59,30 +59,30 @@ export class LoginUserOperation extends Operation { this._setProperty('existingOnesignalId', value); } - override get createComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}`; + override get _createComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}`; } - override get modifyComparisonKey(): string { + override get _modifyComparisonKey(): string { return ''; } - override get groupComparisonType(): GroupComparisonValue { + override get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.CREATE; } - override get canStartExecute(): boolean { + override get _canStartExecute(): boolean { return ( !this.existingOnesignalId || !IDManager._isLocalId(this.existingOnesignalId) ); } - override get applyToRecordId(): string { - return this.existingOnesignalId ?? this.onesignalId; + override get _applyToRecordId(): string { + return this.existingOnesignalId ?? this._onesignalId; } - override translateIds(map: Record): void { + override _translateIds(map: Record): void { if (this.existingOnesignalId && map[this.existingOnesignalId]) { this.existingOnesignalId = map[this.existingOnesignalId]; } diff --git a/src/core/operations/Operation.ts b/src/core/operations/Operation.ts index 112c0aae0..716dd752e 100644 --- a/src/core/operations/Operation.ts +++ b/src/core/operations/Operation.ts @@ -22,32 +22,32 @@ export abstract class Operation< > extends Model { constructor(name: string, appId?: string, onesignalId?: string) { super(); - this.name = name; - if (appId) this.appId = appId; - if (onesignalId) this.onesignalId = onesignalId; + this._name = name; + if (appId) this._appId = appId; + if (onesignalId) this._onesignalId = onesignalId; } - get name(): string { + get _name(): string { return this._getProperty('name'); } - private set name(value: string) { + private set _name(value: string) { this._setProperty('name', value); } /** * The application ID this subscription will be created under. */ - get appId(): string { + get _appId(): string { return this._getProperty('appId'); } - protected set appId(value: string) { + protected set _appId(value: string) { this._setProperty('appId', value); } - get onesignalId(): string { + get _onesignalId(): string { return this._getProperty('onesignalId'); } - protected set onesignalId(value: string) { + protected set _onesignalId(value: string) { this._setProperty('onesignalId', value); } @@ -55,15 +55,15 @@ export abstract class Operation< * This is a unique id that points to a record this operation will affect. * Example: If the operation is updating tags on a User this will be the onesignalId. */ - get applyToRecordId(): string { - return this.onesignalId; + get _applyToRecordId(): string { + return this._onesignalId; } /** * The key of this operation for when the starting operation has a `groupComparisonType` * of `GroupComparisonType.CREATE` */ - get createComparisonKey(): string { + get _createComparisonKey(): string { return ''; } @@ -71,34 +71,30 @@ export abstract class Operation< * The key of this operation for when the starting operation has a `groupComparisonType` * of `GroupComparisonType.ALTER` */ - abstract get modifyComparisonKey(): string; + abstract get _modifyComparisonKey(): string; /** * The comparison type to use when this operation is the starting operation, in terms of * which operations can be grouped with it. */ - get groupComparisonType(): GroupComparisonValue { + get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.ALTER; } /** * Whether the operation can currently execute given its current state. */ - get canStartExecute(): boolean { - return !IDManager._isLocalId(this.onesignalId); + get _canStartExecute(): boolean { + return !IDManager._isLocalId(this._onesignalId); } /** * Called when an operation has resolved a local ID to a backend ID. * Any IDs within the operation that could be local should be translated at this time. */ - translateIds(map: Record): void { - if (map[this.onesignalId]) { - this.onesignalId = map[this.onesignalId]; + _translateIds(map: Record): void { + if (map[this._onesignalId]) { + this._onesignalId = map[this._onesignalId]; } } - - toString(): string { - return JSON.stringify(this.toJSON()); - } } diff --git a/src/core/operations/RefreshUserOperation.ts b/src/core/operations/RefreshUserOperation.ts index c507cce02..a7363c183 100644 --- a/src/core/operations/RefreshUserOperation.ts +++ b/src/core/operations/RefreshUserOperation.ts @@ -17,15 +17,15 @@ export class RefreshUserOperation extends Operation { super(OPERATION_NAME.REFRESH_USER, appId, onesignalId); } - override get createComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}.Refresh`; + override get _createComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}.Refresh`; } - override get modifyComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}.Refresh`; + override get _modifyComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}.Refresh`; } - override get groupComparisonType(): GroupComparisonValue { + override get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.CREATE; } } diff --git a/src/core/operations/SetAliasOperation.ts b/src/core/operations/SetAliasOperation.ts index 898afaf7c..583fd1f1c 100644 --- a/src/core/operations/SetAliasOperation.ts +++ b/src/core/operations/SetAliasOperation.ts @@ -27,7 +27,7 @@ export class SetAliasOperation extends BaseAliasOperation { this._setProperty('value', value); } - override get modifyComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}.Identity.${this.label}`; + override get _modifyComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}.Identity.${this.label}`; } } diff --git a/src/core/operations/SetPropertyOperation.ts b/src/core/operations/SetPropertyOperation.ts index 29064fc98..715a8cc0c 100644 --- a/src/core/operations/SetPropertyOperation.ts +++ b/src/core/operations/SetPropertyOperation.ts @@ -57,7 +57,7 @@ export class SetPropertyOperation< this._setProperty('value', _value); } - override get modifyComparisonKey(): string { - return `${this.appId}.User.${this.onesignalId}`; + override get _modifyComparisonKey(): string { + return `${this._appId}.User.${this._onesignalId}`; } } diff --git a/src/core/operations/TrackCustomEventOperation.ts b/src/core/operations/TrackCustomEventOperation.ts index 599e49260..b353bb512 100644 --- a/src/core/operations/TrackCustomEventOperation.ts +++ b/src/core/operations/TrackCustomEventOperation.ts @@ -63,30 +63,30 @@ export class TrackCustomEventOperation extends Operation { } private get key(): string { - return `${this.appId}.User.${this.onesignalId}.CustomEvent.${this.event.name}`; + return `${this._appId}.User.${this._onesignalId}.CustomEvent.${this.event.name}`; } - override get createComparisonKey(): string { + override get _createComparisonKey(): string { return this.key; } - override get modifyComparisonKey(): string { + override get _modifyComparisonKey(): string { return this.key; } // TODO: no batching of custom events until finalized - override get groupComparisonType(): GroupComparisonValue { + override get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.NONE; } - override get canStartExecute(): boolean { - return !IDManager._isLocalId(this.onesignalId); + override get _canStartExecute(): boolean { + return !IDManager._isLocalId(this._onesignalId); } - override get applyToRecordId(): string { - return this.onesignalId; + override get _applyToRecordId(): string { + return this._onesignalId; } - override translateIds(map: Record): void { - if (map[this.onesignalId]) { - this.onesignalId = map[this.onesignalId]; + override _translateIds(map: Record): void { + if (map[this._onesignalId]) { + this._onesignalId = map[this._onesignalId]; } } } diff --git a/src/core/operations/TransferSubscriptionOperation.ts b/src/core/operations/TransferSubscriptionOperation.ts index 5a42f32c0..ef7139362 100644 --- a/src/core/operations/TransferSubscriptionOperation.ts +++ b/src/core/operations/TransferSubscriptionOperation.ts @@ -13,11 +13,11 @@ export class TransferSubscriptionOperation extends BaseSubscriptionOperation { if (subscriptionId) this.subscriptionId = subscriptionId; } - override get groupComparisonType(): GroupComparisonValue { + override get _groupComparisonType(): GroupComparisonValue { return GroupComparisonType.NONE; } - override get modifyComparisonKey(): string { - return `${this.appId}.Subscription.${this.subscriptionId}.Transfer`; + override get _modifyComparisonKey(): string { + return `${this._appId}.Subscription.${this.subscriptionId}.Transfer`; } } diff --git a/src/core/types/models.ts b/src/core/types/models.ts index 4ec7c05fd..b1cb1fe10 100644 --- a/src/core/types/models.ts +++ b/src/core/types/models.ts @@ -63,7 +63,7 @@ export interface IModelStore< /** * Create a new instance of the model, optionally from a JSON object. */ - create(jsonObject?: DBModel | null): TModel | null; + _create(jsonObject?: DBModel | null): TModel | null; /** * List the models that are owned by this model store. @@ -89,12 +89,12 @@ export interface IModelStore< /** * Clear all models. */ - clear(tag?: string): void; + _clear(tag?: string): void; /** * Replace all models in the store. */ - replaceAll(models: TModel[], tag?: string): void; + _replaceAll(models: TModel[], tag?: string): void; } // SINGLETON MODEL STORE diff --git a/src/core/types/user.ts b/src/core/types/user.ts index b416f213e..4f0d4a985 100644 --- a/src/core/types/user.ts +++ b/src/core/types/user.ts @@ -12,7 +12,7 @@ export interface IRebuildUserService { * @param onesignalId - The ID of the user to retrieve operations for. * @returns A list of operations if the ID is for the current user, or null otherwise. */ - getRebuildOperationsIfCurrentUser( + _getRebuildOperationsIfCurrentUser( appId: string, onesignalId: string, ): Promise; diff --git a/src/onesignal/OneSignal.test.ts b/src/onesignal/OneSignal.test.ts index 1213e6f17..62b6d9bad 100644 --- a/src/onesignal/OneSignal.test.ts +++ b/src/onesignal/OneSignal.test.ts @@ -42,7 +42,7 @@ import { updateIdentityModel, } from '__test__/support/helpers/setup'; import { MockServiceWorker } from '__test__/support/mocks/MockServiceWorker'; -import { OperationQueueItem } from 'src/core/operationRepo/OperationRepo'; +import type { OperationQueueItem } from 'src/core/operationRepo/OperationRepo'; import { type ICreateUserSubscription } from 'src/core/types/api'; import { ModelChangeTags } from 'src/core/types/models'; import { db } from 'src/shared/database/client'; @@ -63,7 +63,7 @@ const setupEnv = (consentRequired: boolean) => { requiresUserPrivacyConsent: consentRequired, }, }); - OneSignal._coreDirector._subscriptionModelStore.replaceAll( + OneSignal._coreDirector._subscriptionModelStore._replaceAll( [], ModelChangeTags.NO_PROPAGATE, ); @@ -403,7 +403,7 @@ describe('OneSignal - No Consent Required', () => { }); const identityModel = OneSignal._coreDirector._getIdentityModel(); - expect(identityModel.externalId).toBe(externalId); + expect(identityModel._externalId).toBe(externalId); await vi.waitUntil( () => transferSubscriptionFn.mock.calls.length === 1, @@ -467,7 +467,7 @@ describe('OneSignal - No Consent Required', () => { }); const identityModel = OneSignal._coreDirector._getIdentityModel(); - expect(identityModel.externalId).toBe(newExternalId); + expect(identityModel._externalId).toBe(newExternalId); }); test('login conflict should keep old subscriptions', async () => { @@ -612,7 +612,7 @@ describe('OneSignal - No Consent Required', () => { const localId = IDManager._createLocalId(); setupIdentityModel(localId); - OneSignal._coreDirector._subscriptionModelStore.replaceAll( + OneSignal._coreDirector._subscriptionModelStore._replaceAll( [], ModelChangeTags.NO_PROPAGATE, ); @@ -690,7 +690,7 @@ describe('OneSignal - No Consent Required', () => { ], }); - OneSignal._coreDirector._subscriptionModelStore.replaceAll( + OneSignal._coreDirector._subscriptionModelStore._replaceAll( [], ModelChangeTags.NO_PROPAGATE, ); @@ -755,7 +755,7 @@ describe('OneSignal - No Consent Required', () => { describe('logout', () => { test('should not do anything if user has no external id', async () => { const identityModel = OneSignal._coreDirector._getIdentityModel(); - expect(identityModel.externalId).toBeUndefined(); + expect(identityModel._externalId).toBeUndefined(); OneSignal.logout(); expect(debugSpy).toHaveBeenCalledWith( @@ -779,7 +779,7 @@ describe('OneSignal - No Consent Required', () => { // identity model should be reset identityModel = OneSignal._coreDirector._getIdentityModel(); - const onesignalId = identityModel.onesignalId; + const onesignalId = identityModel._onesignalId; expect(identityModel.toJSON()).toEqual({ onesignal_id: expect.any(String), }); @@ -905,8 +905,8 @@ describe('OneSignal - No Consent Required', () => { const queue = await getQueue(2); // login and custom event should have matching id (via UserDirector reset user models) - const newLocalId = queue[0].operation.onesignalId; - expect(queue[1].operation.onesignalId).toBe(newLocalId); + const newLocalId = queue[0].operation._onesignalId; + expect(queue[1].operation._onesignalId).toBe(newLocalId); // should translate ids for the custom event await vi.waitUntil(() => createUserFn.mock.calls.length === 1, { @@ -945,9 +945,9 @@ describe('OneSignal - No Consent Required', () => { const queue = await getQueue(3); - expect(queue[0].operation.onesignalId).toBe(ONESIGNAL_ID); - const localID = queue[1].operation.onesignalId; - expect(queue[2].operation.onesignalId).toBe(localID); + expect(queue[0].operation._onesignalId).toBe(ONESIGNAL_ID); + const localID = queue[1].operation._onesignalId; + expect(queue[2].operation._onesignalId).toBe(localID); // first event should have been sent await vi.waitUntil(() => sendCustomEventFn.mock.calls.length === 1, { @@ -1015,9 +1015,9 @@ describe('OneSignal - No Consent Required', () => { }); const queue = await getQueue(3); - expect(queue[0].operation.onesignalId).toBe(ONESIGNAL_ID); - const localID = queue[1].operation.onesignalId; - expect(queue[2].operation.onesignalId).toBe(localID); + expect(queue[0].operation._onesignalId).toBe(ONESIGNAL_ID); + const localID = queue[1].operation._onesignalId; + expect(queue[2].operation._onesignalId).toBe(localID); // first event should have been sent await vi.waitUntil(() => sendCustomEventFn.mock.calls.length === 1, { @@ -1125,13 +1125,13 @@ describe('OneSignal - No Consent Required', () => { // its fine if login op is last since its the only one that can be executed const loginOp = queue[0]; - expect(loginOp.operation.name).toBe('login-user'); + expect(loginOp.operation._name).toBe('login-user'); const setPropertyOp = queue[1]; - expect(setPropertyOp.operation.name).toBe('set-property'); + expect(setPropertyOp.operation._name).toBe('set-property'); const transferOp = queue[2]; - expect(transferOp.operation.name).toBe('transfer-subscription'); + expect(transferOp.operation._name).toBe('transfer-subscription'); // tags should still be sync expect(tags).toEqual({ diff --git a/src/onesignal/User.ts b/src/onesignal/User.ts index 3fccb02cd..1139614ff 100644 --- a/src/onesignal/User.ts +++ b/src/onesignal/User.ts @@ -34,8 +34,8 @@ export default class User { const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); const onesignalId = - identityModel.onesignalId ?? IDManager._createLocalId(); - if (!identityModel.onesignalId) { + identityModel._onesignalId ?? IDManager._createLocalId(); + if (!identityModel._onesignalId) { identityModel._setProperty( IdentityConstants.ONESIGNAL_ID, onesignalId, @@ -43,7 +43,7 @@ export default class User { ); } - if (!propertiesModel.onesignalId) { + if (!propertiesModel._onesignalId) { propertiesModel._setProperty( 'onesignalId', onesignalId, @@ -66,7 +66,8 @@ export default class User { /* PUBLIC API METHODS */ get onesignalId(): string | undefined { - const onesignalId = OneSignal._coreDirector._getIdentityModel().onesignalId; + const onesignalId = + OneSignal._coreDirector._getIdentityModel()._onesignalId; return IDManager._isLocalId(onesignalId) ? undefined : onesignalId; } @@ -184,8 +185,8 @@ export default class User { if (isConsentRequiredButNotGiven()) return; const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - const newTags = { ...propertiesModel.tags, ...tags }; - propertiesModel.tags = newTags; + const newTags = { ...propertiesModel._tags, ...tags }; + propertiesModel._tags = newTags; } public removeTag(tagKey: string): void { @@ -204,18 +205,18 @@ export default class User { validateArray(tagKeys, 'tagKeys'); const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - const newTags = { ...propertiesModel.tags }; + const newTags = { ...propertiesModel._tags }; // need to set the tag to an empty string to remove it tagKeys.forEach((tagKey) => { newTags[tagKey] = ''; }); - propertiesModel.tags = newTags; + propertiesModel._tags = newTags; } public getTags(): { [key: string]: string } { logMethodCall('getTags'); - return OneSignal._coreDirector._getPropertiesModel().tags; + return OneSignal._coreDirector._getPropertiesModel()._tags; } public setLanguage(language: string): void { @@ -225,19 +226,20 @@ export default class User { validateStringLabel(language, 'language'); const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - propertiesModel.language = language; + propertiesModel._language = language; } public getLanguage(): string | undefined { logMethodCall('getLanguage'); - return OneSignal._coreDirector._getPropertiesModel().language; + return OneSignal._coreDirector._getPropertiesModel()._language; } public trackEvent(name: string, properties: Record = {}) { if (isConsentRequiredButNotGiven()) return; // login operation / non-local onesignalId is needed to send custom events - const onesignalId = OneSignal._coreDirector._getIdentityModel().onesignalId; + const onesignalId = + OneSignal._coreDirector._getIdentityModel()._onesignalId; if (IDManager._isLocalId(onesignalId) && !hasLoginOp(onesignalId)) { Log._error('User must be logged in first.'); return; @@ -260,7 +262,7 @@ function hasLoginOp(onesignalId: string) { return OneSignal._coreDirector._operationRepo._queue.find( (op) => op.operation instanceof LoginUserOperation && - op.operation.onesignalId === onesignalId, + op.operation._onesignalId === onesignalId, ); } @@ -277,7 +279,7 @@ function addSubscriptionToModels({ if (hasSubscription) return; const identityModel = OneSignal._coreDirector._getIdentityModel(); - const onesignalId = identityModel.onesignalId; + const onesignalId = identityModel._onesignalId; // Check if we need to enqueue a login operation for local IDs if (IDManager._isLocalId(onesignalId)) { @@ -285,7 +287,7 @@ function addSubscriptionToModels({ if (!hasLoginOp(onesignalId)) { OneSignal._coreDirector._operationRepo._enqueue( - new LoginUserOperation(appId, onesignalId, identityModel.externalId), + new LoginUserOperation(appId, onesignalId, identityModel._externalId), ); } } diff --git a/src/onesignal/UserDirector.ts b/src/onesignal/UserDirector.ts index d603340ca..a44cc1548 100644 --- a/src/onesignal/UserDirector.ts +++ b/src/onesignal/UserDirector.ts @@ -14,7 +14,7 @@ export default class UserDirector { const hasAnySubscription = OneSignal._coreDirector._subscriptionModelStore.list().length > 0; - const hasExternalId = !!identityModel.externalId; + const hasExternalId = !!identityModel._externalId; if (!hasAnySubscription && !hasExternalId) { Log._error( @@ -30,15 +30,15 @@ export default class UserDirector { OneSignal._coreDirector._operationRepo._enqueue( new LoginUserOperation( appId, - identityModel.onesignalId, - identityModel.externalId, + identityModel._onesignalId, + identityModel._externalId, ), ); await OneSignal._coreDirector._operationRepo._enqueueAndWait( new CreateSubscriptionOperation({ ...subData, appId, - onesignalId: identityModel.onesignalId, + onesignalId: identityModel._onesignalId, subscriptionId: pushOp.id!, }), ); @@ -46,8 +46,8 @@ export default class UserDirector { OneSignal._coreDirector._operationRepo._enqueue( new LoginUserOperation( appId, - identityModel.onesignalId, - identityModel.externalId, + identityModel._onesignalId, + identityModel._externalId, ), ); } @@ -61,8 +61,8 @@ export default class UserDirector { const newPropertiesModel = new PropertiesModel(); const sdkId = IDManager._createLocalId(); - newIdentityModel.onesignalId = sdkId; - newPropertiesModel.onesignalId = sdkId; + newIdentityModel._onesignalId = sdkId; + newPropertiesModel._onesignalId = sdkId; OneSignal._coreDirector._identityModelStore.replace(newIdentityModel); OneSignal._coreDirector._propertiesModelStore.replace(newPropertiesModel); diff --git a/src/onesignal/UserNamespace.test.ts b/src/onesignal/UserNamespace.test.ts index abfd91572..3d108201b 100644 --- a/src/onesignal/UserNamespace.test.ts +++ b/src/onesignal/UserNamespace.test.ts @@ -198,7 +198,7 @@ describe('Email Management', () => { test('can add an email subscription', async () => { const identityModel = OneSignal._coreDirector._getIdentityModel(); - identityModel.onesignalId = IDManager._createLocalId(); + identityModel._onesignalId = IDManager._createLocalId(); const email = 'test@example.com'; const addSubscriptionSpy = vi.spyOn( @@ -216,7 +216,7 @@ describe('Email Management', () => { test('should remove an email subscription', async () => { const identityModel = OneSignal._coreDirector._getIdentityModel(); - identityModel.onesignalId = IDManager._createLocalId(); + identityModel._onesignalId = IDManager._createLocalId(); const email = 'test@example.com'; @@ -248,7 +248,7 @@ describe('SMS Management', () => { test('should add an SMS subscription', async () => { const userNamespace = new UserNamespace(true); const identityModel = OneSignal._coreDirector._getIdentityModel(); - identityModel.onesignalId = IDManager._createLocalId(); + identityModel._onesignalId = IDManager._createLocalId(); const smsNumber = '+15551234567'; const addSubscriptionSpy = vi.spyOn( @@ -269,7 +269,7 @@ describe('SMS Management', () => { const smsNumber = '+15551234567'; const identityModel = OneSignal._coreDirector._getIdentityModel(); - identityModel.onesignalId = IDManager._createLocalId(); + identityModel._onesignalId = IDManager._createLocalId(); // First add the SMS await userNamespace.addSms(smsNumber); @@ -374,7 +374,7 @@ describe('Language Management', () => { const userNamespace = new UserNamespace(true); const language = 'es'; const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - propertiesModel.language = language; + propertiesModel._language = language; expect(userNamespace.getLanguage()).toBe(language); }); @@ -382,7 +382,7 @@ describe('Language Management', () => { test('should return empty string if language is not set', () => { const userNamespace = new UserNamespace(true); const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - propertiesModel.language = undefined; + propertiesModel._language = undefined; expect(userNamespace.getLanguage()).toBe(''); }); @@ -461,7 +461,7 @@ describe('Initialization', () => { const onesignalId = user.onesignalId; const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - expect(propertiesModel.onesignalId).toBe(onesignalId); + expect(propertiesModel._onesignalId).toBe(onesignalId); }); test('properties model should have onesignalId for new user', () => { @@ -470,12 +470,13 @@ describe('Initialization', () => { const user = new UserNamespace(true); expect(user.onesignalId).toBe(undefined); // since its local - const onesignalId = OneSignal._coreDirector._getIdentityModel().onesignalId; + const onesignalId = + OneSignal._coreDirector._getIdentityModel()._onesignalId; expect(IDManager._isLocalId(onesignalId)).toBe(true); // identity and properties models should have the same onesignalId const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - expect(propertiesModel.onesignalId).toBe(onesignalId); + expect(propertiesModel._onesignalId).toBe(onesignalId); }); }); diff --git a/src/onesignal/UserNamespace.ts b/src/onesignal/UserNamespace.ts index da01ef9e6..a4409bdc6 100644 --- a/src/onesignal/UserNamespace.ts +++ b/src/onesignal/UserNamespace.ts @@ -36,7 +36,7 @@ export default class UserNamespace extends EventListenerBase { get externalId(): string | undefined { const identityModel = OneSignal._coreDirector._getIdentityModel(); - return identityModel?.externalId; + return identityModel?._externalId; } public addAlias(label: string, id: string): void { diff --git a/src/page/managers/LoginManager.ts b/src/page/managers/LoginManager.ts index 0562fe149..f0a385d5d 100644 --- a/src/page/managers/LoginManager.ts +++ b/src/page/managers/LoginManager.ts @@ -26,10 +26,10 @@ export default class LoginManager { } let identityModel = OneSignal._coreDirector._getIdentityModel(); - const currentOneSignalId = !IDManager._isLocalId(identityModel.onesignalId) - ? identityModel.onesignalId + const currentOneSignalId = !IDManager._isLocalId(identityModel._onesignalId) + ? identityModel._onesignalId : undefined; - const currentExternalId = identityModel.externalId; + const currentExternalId = identityModel._externalId; // if the current externalId is the same as the one we're trying to set, do nothing if (currentExternalId === externalId) { @@ -47,7 +47,7 @@ export default class LoginManager { externalId, ModelChangeTags.HYDRATE, ); - const newIdentityOneSignalId = identityModel.onesignalId; + const newIdentityOneSignalId = identityModel._onesignalId; const appId = MainHelper._getAppId(); const promises: Promise[] = [ @@ -84,7 +84,7 @@ export default class LoginManager { // check if user is already logged out const identityModel = OneSignal._coreDirector._getIdentityModel(); - if (!identityModel.externalId) + if (!identityModel._externalId) return Log._debug('Logout: User is not logged in, skipping logout'); UserDirector._resetUserModels(); diff --git a/src/page/managers/slidedownManager/SlidedownManager.ts b/src/page/managers/slidedownManager/SlidedownManager.ts index 76d2b7570..19e8b8511 100644 --- a/src/page/managers/slidedownManager/SlidedownManager.ts +++ b/src/page/managers/slidedownManager/SlidedownManager.ts @@ -301,7 +301,7 @@ export class SlidedownManager { } const propertiesModel = OneSignal._coreDirector._getPropertiesModel(); - const existingTags = propertiesModel.tags; + const existingTags = propertiesModel._tags; if (options.isInUpdateMode && existingTags) { this._context._tagManager._storeRemotePlayerTags( diff --git a/src/shared/helpers/PropertyOperationHelper.ts b/src/shared/helpers/PropertyOperationHelper.ts deleted file mode 100644 index 509476032..000000000 --- a/src/shared/helpers/PropertyOperationHelper.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PropertiesObject } from 'src/core/objects/PropertiesObject'; -import { Operation } from 'src/core/operations/Operation'; -import { SetPropertyOperation } from 'src/core/operations/SetPropertyOperation'; - -export class PropertyOperationHelper { - static createPropertiesFromOperation( - operation: Operation, - properties: PropertiesObject, - ): PropertiesObject { - if (operation instanceof SetPropertyOperation) { - const propertyKey = operation.property; - const allowedKeys = Object.keys(properties); - if (allowedKeys.includes(propertyKey)) { - return new PropertiesObject({ - ...properties, - [propertyKey]: operation.value, - }); - } - return new PropertiesObject({ ...properties }); - } - - throw new Error(`Unsupported operation type: ${operation.name}`); - } -} diff --git a/src/shared/helpers/SubscriptionHelper.ts b/src/shared/helpers/SubscriptionHelper.ts deleted file mode 100755 index 11587e3c6..000000000 --- a/src/shared/helpers/SubscriptionHelper.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - SubscriptionChannel, - SubscriptionType, -} from 'src/shared/subscriptions/constants'; -import type { - SubscriptionChannelValue, - SubscriptionTypeValue, -} from 'src/shared/subscriptions/types'; -import Log from '../libraries/Log'; -import { checkAndTriggerSubscriptionChanged } from '../listeners'; -import { Subscription } from '../models/Subscription'; -import { SubscriptionStrategyKind } from '../models/SubscriptionStrategyKind'; -import { IS_SERVICE_WORKER } from '../utils/EnvVariables'; -import { incrementPageViewCount } from './pageview'; -import { triggerNotificationPermissionChanged } from './permissions'; - -export default class SubscriptionHelper { - public static async registerForPush(): Promise { - return await SubscriptionHelper.internalRegisterForPush(); - } - - public static async internalRegisterForPush(): Promise { - const context = OneSignal._context; - let subscription: Subscription | null = null; - - if (IS_SERVICE_WORKER) throw new Error('Unsupported environment'); - try { - const rawSubscription = await context._subscriptionManager._subscribe( - SubscriptionStrategyKind.ResubscribeExisting, - ); - subscription = - await context._subscriptionManager._registerSubscription( - rawSubscription, - ); - - incrementPageViewCount(); - - await triggerNotificationPermissionChanged(); - await checkAndTriggerSubscriptionChanged(); - } catch (e) { - Log._error(e); - } - return subscription; - } - - /** - * Helper that checks if a given SubscriptionType is a push subscription. - */ - public static isPushSubscriptionType(type: SubscriptionTypeValue): boolean { - switch (type) { - case SubscriptionType.ChromePush: - case SubscriptionType.SafariPush: - case SubscriptionType.SafariLegacyPush: - case SubscriptionType.FirefoxPush: - return true; - default: - return false; - } - } - - public static toSubscriptionChannel( - type: SubscriptionTypeValue, - ): SubscriptionChannelValue | undefined { - switch (type) { - case SubscriptionType.Email: - return SubscriptionChannel.Email; - case SubscriptionType.SMS: - return SubscriptionChannel.SMS; - default: - if (this.isPushSubscriptionType(type)) { - return SubscriptionChannel.Push; - } - return undefined; - } - } -} diff --git a/src/shared/helpers/init.ts b/src/shared/helpers/init.ts index c43f3491a..ab8903eaa 100755 --- a/src/shared/helpers/init.ts +++ b/src/shared/helpers/init.ts @@ -14,7 +14,7 @@ import { once } from '../utils/utils'; import MainHelper from './MainHelper'; import { incrementPageViewCount } from './pageview'; import { triggerNotificationPermissionChanged } from './permissions'; -import SubscriptionHelper from './SubscriptionHelper'; +import { registerForPush } from './subscription'; export async function internalInit() { Log._debug('Called internalInit()'); @@ -96,7 +96,7 @@ async function sessionInit(): Promise { } export async function registerForPushNotifications(): Promise { - return !!(await SubscriptionHelper.registerForPush()); + return !!(await registerForPush()); } /** @@ -383,7 +383,7 @@ async function handleAutoResubscribe(isOptedOut: boolean) { OneSignal._context._appConfig.safariWebId, ); if (currentPermission == 'granted') { - await SubscriptionHelper.registerForPush(); + await registerForPush(); } } } diff --git a/src/shared/helpers/subscription.ts b/src/shared/helpers/subscription.ts new file mode 100755 index 000000000..60e25b42b --- /dev/null +++ b/src/shared/helpers/subscription.ts @@ -0,0 +1,46 @@ +import { SubscriptionType } from 'src/shared/subscriptions/constants'; +import type { SubscriptionTypeValue } from 'src/shared/subscriptions/types'; +import Log from '../libraries/Log'; +import { checkAndTriggerSubscriptionChanged } from '../listeners'; +import { Subscription } from '../models/Subscription'; +import { SubscriptionStrategyKind } from '../models/SubscriptionStrategyKind'; +import { IS_SERVICE_WORKER } from '../utils/EnvVariables'; +import { incrementPageViewCount } from './pageview'; +import { triggerNotificationPermissionChanged } from './permissions'; + +export async function registerForPush(): Promise { + const context = OneSignal._context; + let subscription: Subscription | null = null; + + if (IS_SERVICE_WORKER) throw new Error('Unsupported environment'); + try { + const rawSubscription = await context._subscriptionManager._subscribe( + SubscriptionStrategyKind.ResubscribeExisting, + ); + subscription = + await context._subscriptionManager._registerSubscription(rawSubscription); + + incrementPageViewCount(); + + await triggerNotificationPermissionChanged(); + await checkAndTriggerSubscriptionChanged(); + } catch (e) { + Log._error(e); + } + return subscription; +} + +/** + * Helper that checks if a given SubscriptionType is a push subscription. + */ +export function isPushSubscriptionType(type: SubscriptionTypeValue): boolean { + switch (type) { + case SubscriptionType.ChromePush: + case SubscriptionType.SafariPush: + case SubscriptionType.SafariLegacyPush: + case SubscriptionType.FirefoxPush: + return true; + default: + return false; + } +} diff --git a/src/shared/listeners.ts b/src/shared/listeners.ts index 7deff931f..d5c0973b7 100644 --- a/src/shared/listeners.ts +++ b/src/shared/listeners.ts @@ -123,8 +123,8 @@ export async function checkAndTriggerUserChanged() { const { previousOneSignalId, previousExternalId } = userState; const identityModel = await OneSignal._coreDirector._getIdentityModel(); - const currentOneSignalId = identityModel?.onesignalId; - const currentExternalId = identityModel?.externalId; + const currentOneSignalId = identityModel?._onesignalId; + const currentExternalId = identityModel?._externalId; const didStateChange = currentOneSignalId !== previousOneSignalId || diff --git a/src/shared/managers/UpdateManager.ts b/src/shared/managers/UpdateManager.ts index aa76535ae..8c0b808c4 100644 --- a/src/shared/managers/UpdateManager.ts +++ b/src/shared/managers/UpdateManager.ts @@ -55,7 +55,7 @@ export class UpdateManager { await OneSignal._coreDirector._getPushSubscriptionModel(); if ( - subscriptionModel?.notification_types !== NotificationType.Subscribed && + subscriptionModel?._notification_types !== NotificationType.Subscribed && OneSignal.config?.enableOnSession !== true ) { return; diff --git a/src/shared/managers/sessionManager/SessionManager.ts b/src/shared/managers/sessionManager/SessionManager.ts index 95697ffc2..0b67db6a2 100644 --- a/src/shared/managers/sessionManager/SessionManager.ts +++ b/src/shared/managers/sessionManager/SessionManager.ts @@ -94,7 +94,7 @@ export class SessionManager implements ISessionManager { const pushSubscriptionModel = await OneSignal._coreDirector._getPushSubscriptionModel(); - if (!identityModel || !identityModel.onesignalId) { + if (!identityModel || !identityModel._onesignalId) { throw new Error('No identity'); } @@ -105,7 +105,7 @@ export class SessionManager implements ISessionManager { throw new Error('No subscription'); } - const { onesignalId } = identityModel; + const { _onesignalId: onesignalId } = identityModel; const { id: subscriptionId } = pushSubscriptionModel; return { onesignalId, subscriptionId }; @@ -361,7 +361,7 @@ export class SessionManager implements ISessionManager { } const identityModel = OneSignal._coreDirector._getIdentityModel(); - const onesignalId = identityModel.onesignalId; + const onesignalId = identityModel._onesignalId; if (!onesignalId) { Log._debug( @@ -373,7 +373,7 @@ export class SessionManager implements ISessionManager { const pushSubscription = await OneSignal._coreDirector._getPushSubscriptionModel(); if ( - pushSubscription?.notification_types !== NotificationType.Subscribed && + pushSubscription?._notification_types !== NotificationType.Subscribed && OneSignal.config?.enableOnSession !== true ) { return; diff --git a/src/shared/managers/subscription/page.ts b/src/shared/managers/subscription/page.ts index 0bdd0f5e8..918e8e9a0 100644 --- a/src/shared/managers/subscription/page.ts +++ b/src/shared/managers/subscription/page.ts @@ -101,7 +101,7 @@ export class SubscriptionManagerPage extends SubscriptionManagerBase