diff --git a/examples/google-secure-signals-integration/react_client_side/src/SecureSignalsApp.tsx b/examples/google-secure-signals-integration/react_client_side/src/SecureSignalsApp.tsx index b6f922a1..59340697 100644 --- a/examples/google-secure-signals-integration/react_client_side/src/SecureSignalsApp.tsx +++ b/examples/google-secure-signals-integration/react_client_side/src/SecureSignalsApp.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; - import './styles/app.css'; import './styles/ads.css'; 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..faa2f370 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,69 @@ 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, + }); + }); + 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, + }); + }); + 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 2638e959..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, {}); } } @@ -185,7 +187,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 +239,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 +290,7 @@ export abstract class SdkBase { this.setInitComplete(true); this._callbackManager?.runCallbacks(EventType.InitCompleted, {}); + this.isIdentityAvailable(); if (this.hasOptedOut()) this._callbackManager.runCallbacks(EventType.OptoutReceived, {}); }