From a34660a30a3302c8cd3c98fbfcad8b5c786fbea6 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Wed, 12 Feb 2025 21:56:56 -0700 Subject: [PATCH 01/27] first examples of no identity available --- src/callbackManager.ts | 1 + src/integrationTests/options.test.ts | 26 +++++++++++++++++++++++++- src/sdkBase.ts | 22 +++++++++++++++++----- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index 954f962b..970dd23b 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -7,6 +7,7 @@ export enum EventType { IdentityUpdated = 'IdentityUpdated', SdkLoaded = 'SdkLoaded', OptoutReceived = 'OptoutReceived', + NoIdentityAvailable = 'NoIdentityAvailable', } export type CallbackPayload = SdkLoadedPayload | PayloadWithIdentity; diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index cae62615..7369895c 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, jest, test } from '@jest/globals'; import * as mocks from '../mocks'; -import { SdkOptions, sdkWindow, UID2 } from '../uid2Sdk'; +import { EventType, SdkOptions, sdkWindow, UID2 } from '../uid2Sdk'; import { loadConfig, removeConfig } from '../configManager'; import { ProductDetails } from '../product'; @@ -555,4 +555,28 @@ describe('Store config UID2', () => { expect(storageConfig).toBeNull(); }); }); + + describe('when no identity is sent in init', () => { + let handler: ReturnType; + beforeEach(() => { + handler = jest.fn(); + uid2.callbacks.push(handler); + }); + test('runs NoIdentityAvailable event', () => { + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 100000, + refresh_expires: Date.now() - 100000, + }); + uid2.init({ + identity: expiredIdentity, + }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, + }); + }); + }); }); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 2638e959..b385c58b 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -185,7 +185,14 @@ export abstract class SdkBase { } public isIdentityAvailable() { - return this.isIdentityValid() || this._apiClient?.hasActiveRequests(); + const identityAvailable = this.isIdentityValid() || this._apiClient?.hasActiveRequests(); + if (!identityAvailable) { + if (this._callbackManager) { + this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); + } + return false; + } + return true; } public hasOptedOut() { @@ -230,10 +237,14 @@ export abstract class SdkBase { this._initCallbackManager?.addInitCallback(opts.callback); } - const useNewIdentity = - opts.identity && - (!previousOpts.identity || - opts.identity.identity_expires > previousOpts.identity.identity_expires); + let useNewIdentity; + if (!opts.identity) useNewIdentity = true; + else { + useNewIdentity = + !previousOpts.identity || + opts.identity.identity_expires > previousOpts.identity.identity_expires; + } + if (useNewIdentity || opts.callback) { let identity = useNewIdentity ? opts.identity : previousOpts.identity ?? null; if (identity) { @@ -277,6 +288,7 @@ export abstract class SdkBase { this.setInitComplete(true); this._callbackManager?.runCallbacks(EventType.InitCompleted, {}); + this.isIdentityAvailable(); if (this.hasOptedOut()) this._callbackManager.runCallbacks(EventType.OptoutReceived, {}); } From 8460640fea5cb5fadb39f6b36f2a822fcd0323ac Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Thu, 13 Feb 2025 12:16:42 -0700 Subject: [PATCH 02/27] added more tests where identity could be unavailable --- src/integrationTests/options.test.ts | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 7369895c..ed3e4d6c 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -578,5 +578,35 @@ describe('Store config UID2', () => { identity: expiredIdentity, }); }); + test('runs NoIdentityAvailable event', () => { + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 100000, + refresh_expires: Date.now() - 100000, + }); + uid2.init({ + identity: expiredIdentity, + }); + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, + }); + }); + test('runs NoIdentityAvailable event', () => { + let expiredIdentity1 = makeIdentity({ + identity_expires: Date.now() - 5000, + refresh_expires: Date.now() - 5000, + }); + let expiredIdentity2 = makeIdentity({ + identity_expires: Date.now() - 100000, + refresh_expires: Date.now() - 100000, + }); + uid2.init({ + identity: expiredIdentity1, + }); + uid2.init({ identity: expiredIdentity2 }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity2, + }); + }); }); }); From bacfbf63fafca926053f23f3ec126d1f0f4e2256 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Thu, 13 Feb 2025 12:28:41 -0700 Subject: [PATCH 03/27] no identity available on set identity --- src/integrationTests/options.test.ts | 11 +++++++++++ src/sdkBase.ts | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index ed3e4d6c..faa2f370 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -608,5 +608,16 @@ describe('Store config UID2', () => { identity: expiredIdentity2, }); }); + test('runs NoIdentityAvailable event', () => { + uid2.init({}); + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 5000, + refresh_expires: Date.now() - 5000, + }); + uid2.setIdentity(expiredIdentity); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); }); }); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index b385c58b..3db0450d 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -158,6 +158,8 @@ export abstract class SdkBase { this.triggerRefreshOrSetTimer(validatedIdentity); } this._callbackManager.runCallbacks(EventType.IdentityUpdated, {}); + } else { + this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); } } From 59856db8cfea1b2bd82887ed30163d396e8c91ef Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Thu, 13 Feb 2025 12:29:29 -0700 Subject: [PATCH 04/27] more set identity examples --- src/integrationTests/options.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index faa2f370..a969ab35 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -619,5 +619,16 @@ describe('Store config UID2', () => { identity: null, }); }); + test('runs NoIdentityAvailable event', () => { + uid2.init({}); + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 5000, + refresh_expires: Date.now() - 5000, + }); + uid2.setIdentity(expiredIdentity); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); }); }); From f8b39ddb9dd896079d437ed87ac628eb91f7676b Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 10:15:06 -0700 Subject: [PATCH 05/27] no identity available new event --- src/callbackManager.ts | 8 +-- src/integrationTests/options.test.ts | 96 ++++++++++++++++++++-------- src/sdkBase.ts | 23 ++++--- 3 files changed, 87 insertions(+), 40 deletions(-) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index 970dd23b..a34f79ca 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -19,14 +19,14 @@ export type PayloadWithIdentity = { }; export class CallbackManager { - private _getIdentity: () => Identity | null | undefined; + private _getIdentity: (isForCallback: boolean) => Identity | null | undefined; private _logger: Logger; private _sdk: SdkBase; private _productName: string; constructor( sdk: SdkBase, productName: string, - getIdentity: () => Identity | null | undefined, + getIdentity: (isForCallback: boolean) => Identity | null | undefined, logger: Logger ) { this._productName = productName; @@ -44,7 +44,7 @@ export class CallbackManager { this.safeRunCallback(c, EventType.SdkLoaded, {}); if (this._sentInit) this.safeRunCallback(c, EventType.InitCompleted, { - identity: this._getIdentity() ?? null, + identity: this._getIdentity(true) ?? null, }); } return Array.prototype.push.apply(this._sdk.callbacks, args); @@ -57,7 +57,7 @@ export class CallbackManager { const enrichedPayload = { ...payload, - identity: this._getIdentity() ?? null, + identity: this._getIdentity(true) ?? null, }; for (const callback of this._sdk.callbacks) { this.safeRunCallback(callback, event, enrichedPayload); diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index a969ab35..de5a748d 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -556,15 +556,23 @@ describe('Store config UID2', () => { }); }); - describe('when no identity is sent in init', () => { + describe('calls the NoIdentityAvailable event', () => { let handler: ReturnType; beforeEach(() => { handler = jest.fn(); uid2.callbacks.push(handler); }); - test('runs NoIdentityAvailable event', () => { + + test('when init is called for the first time with no identity', () => { + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + }); + test('when init is already complete and called again with no identity', () => { + uid2.init({}); uid2.init({}); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + }); + test('when init is already complete and called again with an expired identity', () => { uid2.init({}); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); let expiredIdentity = makeIdentity({ @@ -578,7 +586,7 @@ describe('Store config UID2', () => { identity: expiredIdentity, }); }); - test('runs NoIdentityAvailable event', () => { + test('when init is already complete but the existing identity is expired', () => { let expiredIdentity = makeIdentity({ identity_expires: Date.now() - 100000, refresh_expires: Date.now() - 100000, @@ -586,47 +594,81 @@ describe('Store config UID2', () => { uid2.init({ identity: expiredIdentity, }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, + }); uid2.init({}); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: expiredIdentity, }); }); - test('runs NoIdentityAvailable event', () => { - let expiredIdentity1 = makeIdentity({ - identity_expires: Date.now() - 5000, - refresh_expires: Date.now() - 5000, - }); - let expiredIdentity2 = makeIdentity({ - identity_expires: Date.now() - 100000, - refresh_expires: Date.now() - 100000, + test('when identity is expired but refreshable', () => { + let expiredRefreshableIdentity = makeIdentity({ + identity_expires: Date.now() - 10000, + refresh_expires: Date.now() + 10000, }); - uid2.init({ - identity: expiredIdentity1, + uid2.setIdentity(expiredRefreshableIdentity); + + // in this case, identity is temporarily unavailable but still unavailable + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); - uid2.init({ identity: expiredIdentity2 }); + }); + test('when login is required', () => { + uid2.isLoginRequired(); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity2, + identity: null, }); }); - test('runs NoIdentityAvailable event', () => { - uid2.init({}); - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 5000, - refresh_expires: Date.now() - 5000, + test('when get identity returns null or get advertising token returns undefined', () => { + const nullIdentity = uid2.getIdentity(); + + expect(nullIdentity).toBeNull(); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); - uid2.setIdentity(expiredIdentity); + }); + test('when there is no advertising token', () => { + const token = uid2.getAdvertisingToken(); + + expect(token).toBeUndefined(); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null, }); }); - test('runs NoIdentityAvailable event', () => { + }); + + describe('does not call NoIdentityAvailable event', () => { + let handler: ReturnType; + beforeEach(() => { + handler = jest.fn(); + uid2.callbacks.push(handler); + }); + + test('when setIdentity is run with a valid identity, should not call NoIdentityAvailable on set or get', () => { uid2.init({}); - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 5000, - refresh_expires: Date.now() - 5000, + let validIdentity = makeIdentity(); + uid2.setIdentity(validIdentity); + expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); - uid2.setIdentity(expiredIdentity); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + + uid2.getIdentity(); + expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + + uid2.getAdvertisingToken(); + expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); + test('when identity is set with opted out identity', () => { + uid2.init({}); + let optedOutIdentity = makeIdentity({ status: 'optout' }); + uid2.setIdentity(optedOutIdentity); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null, }); }); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 3db0450d..7cafb8b4 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -84,7 +84,7 @@ export abstract class SdkBase { this._callbackManager = new CallbackManager( this, this._product.name, - () => this.getIdentity(), + () => this.getIdentity(true), this._logger ); } @@ -157,20 +157,25 @@ export abstract class SdkBase { } else { this.triggerRefreshOrSetTimer(validatedIdentity); } - this._callbackManager.runCallbacks(EventType.IdentityUpdated, {}); - } else { - this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); } + this.isIdentityAvailable(); } - public getIdentity(): Identity | null { + public getIdentity(isForCallback?: boolean): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); - return identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity) - ? identity - : null; + const isValid = + identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity); + if (!isValid) { + if (!isForCallback) { + this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); + } + return null; + } else { + return identity; + } } - // When the SDK has been initialized, this function should return the token + // When the SDK has been initialized, this vfunction should return the token // from the most recent refresh request, if there is a request, wait for the // new token. Otherwise, returns a promise which will be resolved after init. public getAdvertisingTokenAsync() { From d9b53b0f8dbbbef57466d70f625a6464c7d49255 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 10:53:33 -0700 Subject: [PATCH 06/27] callback changes no need to init --- .../react_client_side/views/index.html | 23 +++ src/callbackManager.ts | 1 - src/integrationTests/options.test.ts | 193 +++++++++--------- src/sdkBase.ts | 11 +- 4 files changed, 127 insertions(+), 101 deletions(-) create mode 100644 examples/google-secure-signals-integration/react_client_side/views/index.html diff --git a/examples/google-secure-signals-integration/react_client_side/views/index.html b/examples/google-secure-signals-integration/react_client_side/views/index.html new file mode 100644 index 00000000..91fe4413 --- /dev/null +++ b/examples/google-secure-signals-integration/react_client_side/views/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + UID2 Publisher Client-Side React Integration Example + + + +
+ + diff --git a/src/callbackManager.ts b/src/callbackManager.ts index a34f79ca..620dd370 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -53,7 +53,6 @@ export class CallbackManager { public runCallbacks(event: EventType, payload: CallbackPayload) { if (event === EventType.InitCompleted) this._sentInit = true; if (event === EventType.SdkLoaded) CallbackManager._sentSdkLoaded[this._productName] = true; - if (!this._sentInit && event !== EventType.SdkLoaded) return; const enrichedPayload = { ...payload, diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index de5a748d..64f8f8d9 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -555,122 +555,123 @@ describe('Store config UID2', () => { expect(storageConfig).toBeNull(); }); }); +}); - describe('calls the NoIdentityAvailable event', () => { - let handler: ReturnType; - beforeEach(() => { - handler = jest.fn(); - uid2.callbacks.push(handler); - }); +describe('calls the NoIdentityAvailable event', () => { + let handler: ReturnType; + beforeEach(() => { + handler = jest.fn(); + uid2.callbacks.push(handler); + }); - test('when init is called for the first time with no identity', () => { - uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + test('when init is called for the first time with no identity', () => { + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + }); + test('when init is already complete and called again with no identity', () => { + uid2.init({}); + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + }); + test('when init is already complete and called again with an expired identity', () => { + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 100000, + refresh_expires: Date.now() - 100000, }); - test('when init is already complete and called again with no identity', () => { - uid2.init({}); - uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + uid2.init({ + identity: expiredIdentity, }); - test('when init is already complete and called again with an expired identity', () => { - uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 100000, - refresh_expires: Date.now() - 100000, - }); - uid2.init({ - identity: expiredIdentity, - }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, }); - test('when init is already complete but the existing identity is expired', () => { - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 100000, - refresh_expires: Date.now() - 100000, - }); - uid2.init({ - identity: expiredIdentity, - }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); - uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); + }); + test('when init is already complete but the existing identity is expired', () => { + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 100000, + refresh_expires: Date.now() - 100000, }); - test('when identity is expired but refreshable', () => { - let expiredRefreshableIdentity = makeIdentity({ - identity_expires: Date.now() - 10000, - refresh_expires: Date.now() + 10000, - }); - uid2.setIdentity(expiredRefreshableIdentity); - - // in this case, identity is temporarily unavailable but still unavailable - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + uid2.init({ + identity: expiredIdentity, }); - test('when login is required', () => { - uid2.isLoginRequired(); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, + }); + }); + test('when identity is expired but refreshable', () => { + let expiredRefreshableIdentity = makeIdentity({ + identity_expires: Date.now() - 10000, + refresh_expires: Date.now() + 10000, + }); + uid2.init({ identity: expiredRefreshableIdentity }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + // in this case, identity is temporarily unavailable but still unavailable + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); - test('when get identity returns null or get advertising token returns undefined', () => { - const nullIdentity = uid2.getIdentity(); + }); + test('when login is required', () => { + uid2.isLoginRequired(); - expect(nullIdentity).toBeNull(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); - test('when there is no advertising token', () => { - const token = uid2.getAdvertisingToken(); + }); + test('when get identity returns null or get advertising token returns undefined', () => { + const nullIdentity = uid2.getIdentity(); - expect(token).toBeUndefined(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(nullIdentity).toBeNull(); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); }); + test('when there is no advertising token', () => { + const token = uid2.getAdvertisingToken(); - describe('does not call NoIdentityAvailable event', () => { - let handler: ReturnType; - beforeEach(() => { - handler = jest.fn(); - uid2.callbacks.push(handler); + expect(token).toBeUndefined(); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); + }); +}); - test('when setIdentity is run with a valid identity, should not call NoIdentityAvailable on set or get', () => { - uid2.init({}); - let validIdentity = makeIdentity(); - uid2.setIdentity(validIdentity); - expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); +describe('does not call NoIdentityAvailable event', () => { + let handler: ReturnType; + beforeEach(() => { + handler = jest.fn(); + uid2.callbacks.push(handler); + }); - uid2.getIdentity(); - expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + test('when setIdentity is run with a valid identity, should not call NoIdentityAvailable on set or get', () => { + uid2.init({}); + handler = jest.fn(); + let validIdentity = makeIdentity(); + uid2.setIdentity(validIdentity); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); - uid2.getAdvertisingToken(); - expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + uid2.getIdentity(); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); - test('when identity is set with opted out identity', () => { - uid2.init({}); - let optedOutIdentity = makeIdentity({ status: 'optout' }); - uid2.setIdentity(optedOutIdentity); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + + uid2.getAdvertisingToken(); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); + test('when identity is set with opted out identity', () => { + uid2.init({}); + let optedOutIdentity = makeIdentity({ status: 'optout' }); + uid2.setIdentity(optedOutIdentity); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, }); }); }); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 7cafb8b4..347850c7 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -175,7 +175,7 @@ export abstract class SdkBase { } } - // When the SDK has been initialized, this vfunction should return the token + // When the SDK has been initialized, this function should return the token // from the most recent refresh request, if there is a request, wait for the // new token. Otherwise, returns a promise which will be resolved after init. public getAdvertisingTokenAsync() { @@ -192,7 +192,11 @@ export abstract class SdkBase { } public isIdentityAvailable() { - const identityAvailable = this.isIdentityValid() || this._apiClient?.hasActiveRequests(); + const identity = this._identity ?? this.getIdentityNoInit(); + const identityAvailable = + (this.isIdentityValid(identity) && !this.temporarilyUnavailable(identity)) || + this._apiClient?.hasActiveRequests(); + if (!identityAvailable) { if (this._callbackManager) { this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); @@ -299,8 +303,7 @@ export abstract class SdkBase { if (this.hasOptedOut()) this._callbackManager.runCallbacks(EventType.OptoutReceived, {}); } - private isIdentityValid() { - const identity = this._identity ?? this.getIdentityNoInit(); + private isIdentityValid(identity: Identity | OptoutIdentity | null | undefined) { return identity && !hasExpired(identity.refresh_expires); } From d8cc05df9337be11e6f0887a5f356b6cc3c6e8fd Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 10:56:14 -0700 Subject: [PATCH 07/27] not needed from prev branch --- .../react_client_side/views/index.html | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 examples/google-secure-signals-integration/react_client_side/views/index.html diff --git a/examples/google-secure-signals-integration/react_client_side/views/index.html b/examples/google-secure-signals-integration/react_client_side/views/index.html deleted file mode 100644 index 91fe4413..00000000 --- a/examples/google-secure-signals-integration/react_client_side/views/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - UID2 Publisher Client-Side React Integration Example - - - -
- - From 75b495264f84059984166db263789566b3f6913e Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 11:00:00 -0700 Subject: [PATCH 08/27] wrote separate identity function for callback instead --- src/callbackManager.ts | 8 ++++---- src/sdkBase.ts | 15 ++++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index 620dd370..69b73d8f 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -19,14 +19,14 @@ export type PayloadWithIdentity = { }; export class CallbackManager { - private _getIdentity: (isForCallback: boolean) => Identity | null | undefined; + private _getIdentity: () => Identity | null | undefined; private _logger: Logger; private _sdk: SdkBase; private _productName: string; constructor( sdk: SdkBase, productName: string, - getIdentity: (isForCallback: boolean) => Identity | null | undefined, + getIdentity: () => Identity | null | undefined, logger: Logger ) { this._productName = productName; @@ -44,7 +44,7 @@ export class CallbackManager { this.safeRunCallback(c, EventType.SdkLoaded, {}); if (this._sentInit) this.safeRunCallback(c, EventType.InitCompleted, { - identity: this._getIdentity(true) ?? null, + identity: this._getIdentity() ?? null, }); } return Array.prototype.push.apply(this._sdk.callbacks, args); @@ -56,7 +56,7 @@ export class CallbackManager { const enrichedPayload = { ...payload, - identity: this._getIdentity(true) ?? null, + identity: this._getIdentity() ?? null, }; for (const callback of this._sdk.callbacks) { this.safeRunCallback(callback, event, enrichedPayload); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 347850c7..75841f2c 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -84,7 +84,7 @@ export abstract class SdkBase { this._callbackManager = new CallbackManager( this, this._product.name, - () => this.getIdentity(true), + () => this.getIdentityForCallback(), this._logger ); } @@ -161,20 +161,25 @@ export abstract class SdkBase { this.isIdentityAvailable(); } - public getIdentity(isForCallback?: boolean): Identity | null { + public getIdentity(): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); const isValid = identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity); if (!isValid) { - if (!isForCallback) { - this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); - } + this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); return null; } else { return identity; } } + private getIdentityForCallback(): Identity | null { + const identity = this._identity ?? this.getIdentityNoInit(); + return identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity) + ? identity + : null; + } + // When the SDK has been initialized, this function should return the token // from the most recent refresh request, if there is a request, wait for the // new token. Otherwise, returns a promise which will be resolved after init. From ea6f0e4b6167ee478ee46005085565a40b821f5f Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:14:20 -0700 Subject: [PATCH 09/27] added tests for cstg and refresh timer --- src/integrationTests/options.test.ts | 51 ++++++++++++++++++++++++++++ src/sdkBase.ts | 7 ++++ 2 files changed, 58 insertions(+) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 64f8f8d9..7217f1ff 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -638,6 +638,46 @@ describe('calls the NoIdentityAvailable event', () => { identity: null, }); }); + test('when cstg does not succeed', () => { + uid2.init({}); + expect(uid2.setIdentityFromEmail('a', mocks.makeUid2CstgOption())).rejects.toThrow( + 'Invalid email address' + ); + + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); + test('when an identity was valid but has since expired', () => { + uid2.init({}); + expect(uid2.setIdentityFromEmail('a', mocks.makeUid2CstgOption())).rejects.toThrow( + 'Invalid email address' + ); + + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); + test('when identity was valid on init but has since expired', () => { + const refreshFrom = Date.now() + 100; + const originalIdentity = makeIdentity({ + advertising_token: 'original_advertising_token', + identity_expires: refreshFrom, + //refresh_from: refreshFrom, + }); + + uid2.init({ identity: originalIdentity }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + + // set time to an expired date for this identity + jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); + + uid2.isIdentityAvailable(); + + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: originalIdentity, + }); + }); }); describe('does not call NoIdentityAvailable event', () => { @@ -674,4 +714,15 @@ describe('does not call NoIdentityAvailable event', () => { identity: null, }); }); + test('when cstg is successful', async () => { + uid2.init({}); + handler = jest.fn(); + expect(async () => { + await uid2.setIdentityFromEmail('test@test.com', mocks.makeUid2CstgOption()); + }).not.toThrow(); + + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); }); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 75841f2c..d39835bd 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -157,6 +157,7 @@ export abstract class SdkBase { } else { this.triggerRefreshOrSetTimer(validatedIdentity); } + this._callbackManager.runCallbacks(EventType.IdentityUpdated, {}); } this.isIdentityAvailable(); } @@ -193,6 +194,11 @@ export abstract class SdkBase { } public isLoginRequired() { + const identity = this._identity ?? this.getIdentityNoInit(); + // if identity temporarily unavailable, login is not required + if (this.temporarilyUnavailable(identity)) { + return false; + } return !this.isIdentityAvailable(); } @@ -526,6 +532,7 @@ export abstract class SdkBase { } else { const errorText = 'Unexpected status received from CSTG endpoint.'; this._logger.warn(errorText); + this.isIdentityAvailable(); throw new Error(errorText); } } From 1879ddce494ab9b1544e46b1a5ebd04eca1cf26d Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:17:51 -0700 Subject: [PATCH 10/27] added test for local storage --- src/integrationTests/options.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 7217f1ff..9e671efe 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -721,6 +721,15 @@ describe('does not call NoIdentityAvailable event', () => { await uid2.setIdentityFromEmail('test@test.com', mocks.makeUid2CstgOption()); }).not.toThrow(); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); + }); + test('when identity is set with local storage', () => { + let validIdentity = makeIdentity(); + mocks.setUid2LocalStorage(validIdentity); + uid2.init({}); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null, }); From f0d0bed21aab9f4ba21a649e6d3d1a6b7de9e6ed Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:21:05 -0700 Subject: [PATCH 11/27] added test without init --- src/integrationTests/options.test.ts | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 9e671efe..93e1ece2 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -559,6 +559,11 @@ describe('Store config UID2', () => { describe('calls the NoIdentityAvailable event', () => { let handler: ReturnType; + let expiredIdentity = makeIdentity({ + identity_expires: Date.now() - 100000, + refresh_expires: Date.now() - 100000, + }); + beforeEach(() => { handler = jest.fn(); uid2.callbacks.push(handler); @@ -576,10 +581,7 @@ describe('calls the NoIdentityAvailable event', () => { test('when init is already complete and called again with an expired identity', () => { uid2.init({}); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 100000, - refresh_expires: Date.now() - 100000, - }); + uid2.init({ identity: expiredIdentity, }); @@ -588,10 +590,6 @@ describe('calls the NoIdentityAvailable event', () => { }); }); test('when init is already complete but the existing identity is expired', () => { - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 100000, - refresh_expires: Date.now() - 100000, - }); uid2.init({ identity: expiredIdentity, }); @@ -681,6 +679,7 @@ describe('calls the NoIdentityAvailable event', () => { }); describe('does not call NoIdentityAvailable event', () => { + let validIdentity = makeIdentity(); let handler: ReturnType; beforeEach(() => { handler = jest.fn(); @@ -690,7 +689,6 @@ describe('does not call NoIdentityAvailable event', () => { test('when setIdentity is run with a valid identity, should not call NoIdentityAvailable on set or get', () => { uid2.init({}); handler = jest.fn(); - let validIdentity = makeIdentity(); uid2.setIdentity(validIdentity); expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null, @@ -725,10 +723,9 @@ describe('does not call NoIdentityAvailable event', () => { identity: null, }); }); - test('when identity is set with local storage', () => { - let validIdentity = makeIdentity(); + test('when identity is set with local storage and init has never been', () => { mocks.setUid2LocalStorage(validIdentity); - uid2.init({}); + uid2.isIdentityAvailable(); expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null, From b991a9834e80ea13f0fc154c2a24edd99e15e9f6 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:26:53 -0700 Subject: [PATCH 12/27] identity should always be null --- src/callbackManager.ts | 4 ++ src/integrationTests/options.test.ts | 64 +++++++--------------------- 2 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index 69b73d8f..fc824bbd 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -58,6 +58,10 @@ export class CallbackManager { ...payload, identity: this._getIdentity() ?? null, }; + if (event === EventType.NoIdentityAvailable && enrichedPayload.identity) { + enrichedPayload.identity = null; + } + for (const callback of this._sdk.callbacks) { this.safeRunCallback(callback, event, enrichedPayload); } diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 93e1ece2..3cbb5abe 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -585,21 +585,15 @@ describe('calls the NoIdentityAvailable event', () => { uid2.init({ identity: expiredIdentity, }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when init is already complete but the existing identity is expired', () => { uid2.init({ identity: expiredIdentity, }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is expired but refreshable', () => { let expiredRefreshableIdentity = makeIdentity({ @@ -609,32 +603,24 @@ describe('calls the NoIdentityAvailable event', () => { uid2.init({ identity: expiredRefreshableIdentity }); // in this case, identity is temporarily unavailable but still unavailable - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when login is required', () => { uid2.isLoginRequired(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when get identity returns null or get advertising token returns undefined', () => { const nullIdentity = uid2.getIdentity(); expect(nullIdentity).toBeNull(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when there is no advertising token', () => { const token = uid2.getAdvertisingToken(); expect(token).toBeUndefined(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when cstg does not succeed', () => { uid2.init({}); @@ -642,9 +628,7 @@ describe('calls the NoIdentityAvailable event', () => { 'Invalid email address' ); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when an identity was valid but has since expired', () => { uid2.init({}); @@ -652,9 +636,7 @@ describe('calls the NoIdentityAvailable event', () => { 'Invalid email address' ); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity was valid on init but has since expired', () => { const refreshFrom = Date.now() + 100; @@ -672,9 +654,7 @@ describe('calls the NoIdentityAvailable event', () => { uid2.isIdentityAvailable(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: originalIdentity, - }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); }); @@ -690,27 +670,19 @@ describe('does not call NoIdentityAvailable event', () => { uid2.init({}); handler = jest.fn(); uid2.setIdentity(validIdentity); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); uid2.getIdentity(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); uid2.getAdvertisingToken(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is set with opted out identity', () => { uid2.init({}); let optedOutIdentity = makeIdentity({ status: 'optout' }); uid2.setIdentity(optedOutIdentity); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when cstg is successful', async () => { uid2.init({}); @@ -719,16 +691,12 @@ describe('does not call NoIdentityAvailable event', () => { await uid2.setIdentityFromEmail('test@test.com', mocks.makeUid2CstgOption()); }).not.toThrow(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is set with local storage and init has never been', () => { mocks.setUid2LocalStorage(validIdentity); uid2.isIdentityAvailable(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); }); From 7aa9c23b11a19bf349cf40b3e2e390e4d6048ba7 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:31:20 -0700 Subject: [PATCH 13/27] organizing tests --- src/integrationTests/options.test.ts | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 3cbb5abe..87751a16 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -571,28 +571,29 @@ describe('calls the NoIdentityAvailable event', () => { test('when init is called for the first time with no identity', () => { uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when init is already complete and called again with no identity', () => { uid2.init({}); uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when init is already complete and called again with an expired identity', () => { uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - uid2.init({ identity: expiredIdentity, }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when init is already complete but the existing identity is expired', () => { uid2.init({ identity: expiredIdentity, }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); uid2.init({}); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is expired but refreshable', () => { @@ -611,9 +612,8 @@ describe('calls the NoIdentityAvailable event', () => { expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when get identity returns null or get advertising token returns undefined', () => { - const nullIdentity = uid2.getIdentity(); + uid2.getIdentity(); - expect(nullIdentity).toBeNull(); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when there is no advertising token', () => { @@ -624,29 +624,19 @@ describe('calls the NoIdentityAvailable event', () => { }); test('when cstg does not succeed', () => { uid2.init({}); - expect(uid2.setIdentityFromEmail('a', mocks.makeUid2CstgOption())).rejects.toThrow( - 'Invalid email address' - ); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when an identity was valid but has since expired', () => { - uid2.init({}); expect(uid2.setIdentityFromEmail('a', mocks.makeUid2CstgOption())).rejects.toThrow( 'Invalid email address' ); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity was valid on init but has since expired', () => { - const refreshFrom = Date.now() + 100; const originalIdentity = makeIdentity({ advertising_token: 'original_advertising_token', - identity_expires: refreshFrom, - //refresh_from: refreshFrom, + identity_expires: Date.now() + 100, }); - uid2.init({ identity: originalIdentity }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); // set time to an expired date for this identity @@ -669,6 +659,7 @@ describe('does not call NoIdentityAvailable event', () => { test('when setIdentity is run with a valid identity, should not call NoIdentityAvailable on set or get', () => { uid2.init({}); handler = jest.fn(); + uid2.setIdentity(validIdentity); expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); @@ -682,15 +673,16 @@ describe('does not call NoIdentityAvailable event', () => { uid2.init({}); let optedOutIdentity = makeIdentity({ status: 'optout' }); uid2.setIdentity(optedOutIdentity); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when cstg is successful', async () => { uid2.init({}); handler = jest.fn(); + expect(async () => { await uid2.setIdentityFromEmail('test@test.com', mocks.makeUid2CstgOption()); }).not.toThrow(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is set with local storage and init has never been', () => { From dc3802634a786b7d7070a292bae9d0f7662964bb Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:42:02 -0700 Subject: [PATCH 14/27] added cookie example also --- src/integrationTests/options.test.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 87751a16..1d897e56 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -611,15 +611,14 @@ describe('calls the NoIdentityAvailable event', () => { expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); - test('when get identity returns null or get advertising token returns undefined', () => { + test('when get identity returns null', () => { uid2.getIdentity(); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when there is no advertising token', () => { - const token = uid2.getAdvertisingToken(); + uid2.getAdvertisingToken(); - expect(token).toBeUndefined(); expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when cstg does not succeed', () => { @@ -670,9 +669,7 @@ describe('does not call NoIdentityAvailable event', () => { expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is set with opted out identity', () => { - uid2.init({}); - let optedOutIdentity = makeIdentity({ status: 'optout' }); - uid2.setIdentity(optedOutIdentity); + uid2.init({ identity: makeIdentity({ status: 'optout' }) }); expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); @@ -685,10 +682,16 @@ describe('does not call NoIdentityAvailable event', () => { }).not.toThrow(); expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); - test('when identity is set with local storage and init has never been', () => { + test('when identity is set with local storage and init has never been called', () => { mocks.setUid2LocalStorage(validIdentity); uid2.isIdentityAvailable(); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + }); + test('when identity is set with cookie and init has never been called', () => { + mocks.setUid2Cookie(validIdentity); + uid2.isIdentityAvailable(); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); }); From 2a7f821642666eecedb10d08cb374451361ef68b Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Fri, 14 Feb 2025 13:43:34 -0700 Subject: [PATCH 15/27] cleaned up valid identity test --- src/integrationTests/options.test.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 1d897e56..25e0ce0c 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -660,13 +660,10 @@ describe('does not call NoIdentityAvailable event', () => { handler = jest.fn(); uid2.setIdentity(validIdentity); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - uid2.getIdentity(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - uid2.getAdvertisingToken(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + + expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { identity: null }); }); test('when identity is set with opted out identity', () => { uid2.init({ identity: makeIdentity({ status: 'optout' }) }); From 50d0ceabfa8ce1fec865948c26e641e9f45e0e05 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 18 Feb 2025 12:34:31 -0700 Subject: [PATCH 16/27] added sdk loaded check in run callbacks --- src/callbackManager.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index fc824bbd..a9d5e427 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -53,6 +53,8 @@ export class CallbackManager { public runCallbacks(event: EventType, payload: CallbackPayload) { if (event === EventType.InitCompleted) this._sentInit = true; if (event === EventType.SdkLoaded) CallbackManager._sentSdkLoaded[this._productName] = true; + // if SDK has not been loaded yet, callbacks should not run + if (!CallbackManager._sentSdkLoaded[this._productName]) return; const enrichedPayload = { ...payload, From 3c0a13af1054a259999a4eaa0def91b3a7840bd9 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 18 Feb 2025 15:32:39 -0700 Subject: [PATCH 17/27] removed identity forced to be null --- src/callbackManager.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index a9d5e427..9a650399 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -60,10 +60,6 @@ export class CallbackManager { ...payload, identity: this._getIdentity() ?? null, }; - if (event === EventType.NoIdentityAvailable && enrichedPayload.identity) { - enrichedPayload.identity = null; - } - for (const callback of this._sdk.callbacks) { this.safeRunCallback(callback, event, enrichedPayload); } From ccd68ae5190523423e1006228ece75bab232812b Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 18 Feb 2025 16:17:12 -0700 Subject: [PATCH 18/27] fixed tests to expect expired identity sometimes --- src/integrationTests/options.test.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index 25e0ce0c..b84b55f7 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -586,7 +586,9 @@ describe('calls the NoIdentityAvailable event', () => { identity: expiredIdentity, }); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, + }); }); test('when init is already complete but the existing identity is expired', () => { uid2.init({ @@ -594,7 +596,9 @@ describe('calls the NoIdentityAvailable event', () => { }); uid2.init({}); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: expiredIdentity, + }); }); test('when identity is expired but refreshable', () => { let expiredRefreshableIdentity = makeIdentity({ @@ -636,14 +640,18 @@ describe('calls the NoIdentityAvailable event', () => { }); uid2.init({ identity: originalIdentity }); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: null, + }); // set time to an expired date for this identity jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); uid2.isIdentityAvailable(); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); + expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { + identity: originalIdentity, + }); }); }); From 6fcb0d3625490f93741d5066024bd0fb6a37261d Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 18 Feb 2025 16:30:34 -0700 Subject: [PATCH 19/27] cleaned up get identity to be more consistent with isvalididentity function --- src/sdkBase.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index d39835bd..544e58b8 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -1,5 +1,5 @@ import { version } from '../package.json'; -import { OptoutIdentity, Identity, isOptoutIdentity } from './Identity'; +import { OptoutIdentity, Identity, isOptoutIdentity, isValidIdentity } from './Identity'; import { IdentityStatus, InitCallbackManager } from './initCallbacks'; import { SdkOptions, isSDKOptionsOrThrow } from './sdkOptions'; import { Logger, MakeLogger } from './sdk/logger'; @@ -164,21 +164,16 @@ export abstract class SdkBase { public getIdentity(): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); - const isValid = - identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity); - if (!isValid) { + if (!isValidIdentity(identity) || this.temporarilyUnavailable(identity)) { this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); return null; - } else { - return identity; } + return identity; } private getIdentityForCallback(): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); - return identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity) - ? identity - : null; + return isValidIdentity(identity) && !this.temporarilyUnavailable(identity) ? identity : null; } // When the SDK has been initialized, this function should return the token From 6bea2a5a6a40e758a4abaae6434df5241a46542c Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 18 Feb 2025 16:33:12 -0700 Subject: [PATCH 20/27] the check iwll already happen in islogin required --- src/sdkBase.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 544e58b8..21bc2fef 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -189,11 +189,6 @@ export abstract class SdkBase { } public isLoginRequired() { - const identity = this._identity ?? this.getIdentityNoInit(); - // if identity temporarily unavailable, login is not required - if (this.temporarilyUnavailable(identity)) { - return false; - } return !this.isIdentityAvailable(); } From c16234bde326f5305e4e349055e9ffba67e31429 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Wed, 19 Feb 2025 10:36:24 -0700 Subject: [PATCH 21/27] unavailable check still needed --- src/sdkBase.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 21bc2fef..544e58b8 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -189,6 +189,11 @@ export abstract class SdkBase { } public isLoginRequired() { + const identity = this._identity ?? this.getIdentityNoInit(); + // if identity temporarily unavailable, login is not required + if (this.temporarilyUnavailable(identity)) { + return false; + } return !this.isIdentityAvailable(); } From f1d89c50c806d393bb983c8a6ee2d57655c2536c Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 25 Feb 2025 13:14:31 -0700 Subject: [PATCH 22/27] removed any no identity available event reference --- src/callbackManager.ts | 1 - src/integrationTests/options.test.ts | 144 --------------------------- src/sdkBase.ts | 20 +--- 3 files changed, 4 insertions(+), 161 deletions(-) diff --git a/src/callbackManager.ts b/src/callbackManager.ts index 9a650399..8648870e 100644 --- a/src/callbackManager.ts +++ b/src/callbackManager.ts @@ -7,7 +7,6 @@ export enum EventType { IdentityUpdated = 'IdentityUpdated', SdkLoaded = 'SdkLoaded', OptoutReceived = 'OptoutReceived', - NoIdentityAvailable = 'NoIdentityAvailable', } export type CallbackPayload = SdkLoadedPayload | PayloadWithIdentity; diff --git a/src/integrationTests/options.test.ts b/src/integrationTests/options.test.ts index b84b55f7..25df4b02 100644 --- a/src/integrationTests/options.test.ts +++ b/src/integrationTests/options.test.ts @@ -556,147 +556,3 @@ describe('Store config UID2', () => { }); }); }); - -describe('calls the NoIdentityAvailable event', () => { - let handler: ReturnType; - let expiredIdentity = makeIdentity({ - identity_expires: Date.now() - 100000, - refresh_expires: Date.now() - 100000, - }); - - beforeEach(() => { - handler = jest.fn(); - uid2.callbacks.push(handler); - }); - - test('when init is called for the first time with no identity', () => { - uid2.init({}); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when init is already complete and called again with no identity', () => { - uid2.init({}); - uid2.init({}); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when init is already complete and called again with an expired identity', () => { - uid2.init({}); - uid2.init({ - identity: expiredIdentity, - }); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); - }); - test('when init is already complete but the existing identity is expired', () => { - uid2.init({ - identity: expiredIdentity, - }); - uid2.init({}); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: expiredIdentity, - }); - }); - test('when identity is expired but refreshable', () => { - let expiredRefreshableIdentity = makeIdentity({ - identity_expires: Date.now() - 10000, - refresh_expires: Date.now() + 10000, - }); - uid2.init({ identity: expiredRefreshableIdentity }); - - // in this case, identity is temporarily unavailable but still unavailable - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when login is required', () => { - uid2.isLoginRequired(); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when get identity returns null', () => { - uid2.getIdentity(); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when there is no advertising token', () => { - uid2.getAdvertisingToken(); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when cstg does not succeed', () => { - uid2.init({}); - - expect(uid2.setIdentityFromEmail('a', mocks.makeUid2CstgOption())).rejects.toThrow( - 'Invalid email address' - ); - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when identity was valid on init but has since expired', () => { - const originalIdentity = makeIdentity({ - advertising_token: 'original_advertising_token', - identity_expires: Date.now() + 100, - }); - uid2.init({ identity: originalIdentity }); - - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: null, - }); - - // set time to an expired date for this identity - jest.setSystemTime(originalIdentity.refresh_expires * 1000 + 1); - - uid2.isIdentityAvailable(); - - expect(handler).toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { - identity: originalIdentity, - }); - }); -}); - -describe('does not call NoIdentityAvailable event', () => { - let validIdentity = makeIdentity(); - let handler: ReturnType; - beforeEach(() => { - handler = jest.fn(); - uid2.callbacks.push(handler); - }); - - test('when setIdentity is run with a valid identity, should not call NoIdentityAvailable on set or get', () => { - uid2.init({}); - handler = jest.fn(); - - uid2.setIdentity(validIdentity); - uid2.getIdentity(); - uid2.getAdvertisingToken(); - - expect(handler).not.toHaveBeenCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when identity is set with opted out identity', () => { - uid2.init({ identity: makeIdentity({ status: 'optout' }) }); - - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when cstg is successful', async () => { - uid2.init({}); - handler = jest.fn(); - - expect(async () => { - await uid2.setIdentityFromEmail('test@test.com', mocks.makeUid2CstgOption()); - }).not.toThrow(); - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when identity is set with local storage and init has never been called', () => { - mocks.setUid2LocalStorage(validIdentity); - uid2.isIdentityAvailable(); - - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); - test('when identity is set with cookie and init has never been called', () => { - mocks.setUid2Cookie(validIdentity); - uid2.isIdentityAvailable(); - - expect(handler).not.toHaveBeenLastCalledWith(EventType.NoIdentityAvailable, { identity: null }); - }); -}); diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 544e58b8..ec06df17 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -165,7 +165,6 @@ export abstract class SdkBase { public getIdentity(): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); if (!isValidIdentity(identity) || this.temporarilyUnavailable(identity)) { - this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); return null; } return identity; @@ -199,17 +198,10 @@ export abstract class SdkBase { public isIdentityAvailable() { const identity = this._identity ?? this.getIdentityNoInit(); - const identityAvailable = - (this.isIdentityValid(identity) && !this.temporarilyUnavailable(identity)) || - this._apiClient?.hasActiveRequests(); - - if (!identityAvailable) { - if (this._callbackManager) { - this._callbackManager.runCallbacks(EventType.NoIdentityAvailable, {}); - } - return false; - } - return true; + return ( + (identity && !hasExpired && !this.temporarilyUnavailable(identity)) || + this._apiClient?.hasActiveRequests() + ); } public hasOptedOut() { @@ -309,10 +301,6 @@ export abstract class SdkBase { if (this.hasOptedOut()) this._callbackManager.runCallbacks(EventType.OptoutReceived, {}); } - private isIdentityValid(identity: Identity | OptoutIdentity | null | undefined) { - return identity && !hasExpired(identity.refresh_expires); - } - private temporarilyUnavailable(identity: Identity | OptoutIdentity | null | undefined) { if (!identity && this._apiClient?.hasActiveRequests()) return true; // returns true if identity is expired but refreshable From 12ae483b9e23b2e344698832edbbf5226a164d71 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 25 Feb 2025 13:20:57 -0700 Subject: [PATCH 23/27] dont need separate get identity functions anymore --- src/sdkBase.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index ec06df17..6921385e 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -84,7 +84,7 @@ export abstract class SdkBase { this._callbackManager = new CallbackManager( this, this._product.name, - () => this.getIdentityForCallback(), + () => this.getIdentity(), this._logger ); } @@ -170,11 +170,6 @@ export abstract class SdkBase { return identity; } - private getIdentityForCallback(): Identity | null { - const identity = this._identity ?? this.getIdentityNoInit(); - return isValidIdentity(identity) && !this.temporarilyUnavailable(identity) ? identity : null; - } - // When the SDK has been initialized, this function should return the token // from the most recent refresh request, if there is a request, wait for the // new token. Otherwise, returns a promise which will be resolved after init. From 1c4167cf3638ea6066dd572eadf17d7b9414f654 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 25 Feb 2025 13:22:45 -0700 Subject: [PATCH 24/27] no need to call is identity available everywhere --- src/sdkBase.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 6921385e..73fd578a 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -159,7 +159,6 @@ export abstract class SdkBase { } this._callbackManager.runCallbacks(EventType.IdentityUpdated, {}); } - this.isIdentityAvailable(); } public getIdentity(): Identity | null { @@ -292,7 +291,6 @@ export abstract class SdkBase { this.setInitComplete(true); this._callbackManager?.runCallbacks(EventType.InitCompleted, {}); - this.isIdentityAvailable(); if (this.hasOptedOut()) this._callbackManager.runCallbacks(EventType.OptoutReceived, {}); } @@ -510,7 +508,6 @@ export abstract class SdkBase { } else { const errorText = 'Unexpected status received from CSTG endpoint.'; this._logger.warn(errorText); - this.isIdentityAvailable(); throw new Error(errorText); } } From 4053cb7c9be429edff84755bc5c0bc1bdb61bbd1 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 25 Feb 2025 13:25:56 -0700 Subject: [PATCH 25/27] clean up get identity --- src/sdkBase.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 73fd578a..a7967a50 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -163,10 +163,7 @@ export abstract class SdkBase { public getIdentity(): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); - if (!isValidIdentity(identity) || this.temporarilyUnavailable(identity)) { - return null; - } - return identity; + return isValidIdentity(identity) && !this.temporarilyUnavailable(identity) ? identity : null; } // When the SDK has been initialized, this function should return the token From c4061fec58f8bd47735bd30c2e222a2c4c73c671 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 25 Feb 2025 13:26:45 -0700 Subject: [PATCH 26/27] get identity return --- src/sdkBase.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index a7967a50..52e03fbf 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -163,6 +163,7 @@ export abstract class SdkBase { public getIdentity(): Identity | null { const identity = this._identity ?? this.getIdentityNoInit(); + // if identity is valid (includes not opted out) and available, return it return isValidIdentity(identity) && !this.temporarilyUnavailable(identity) ? identity : null; } From 86501e80ac87929e58e8ebf3e01cdbd942f90a93 Mon Sep 17 00:00:00 2001 From: Ashley Smith Date: Tue, 25 Feb 2025 13:38:15 -0700 Subject: [PATCH 27/27] fixed is identity available --- src/sdkBase.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sdkBase.ts b/src/sdkBase.ts index 52e03fbf..03b36f3b 100644 --- a/src/sdkBase.ts +++ b/src/sdkBase.ts @@ -190,8 +190,11 @@ export abstract class SdkBase { public isIdentityAvailable() { const identity = this._identity ?? this.getIdentityNoInit(); + // available if identity exists and has not expired or if there active requests return ( - (identity && !hasExpired && !this.temporarilyUnavailable(identity)) || + (identity && + !hasExpired(identity.refresh_expires) && + !this.temporarilyUnavailable(identity)) || this._apiClient?.hasActiveRequests() ); }