@adobe/alloy 2.29.0-beta.5 → 2.30.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/libEs5/components/ActivityCollector/utils/dom/findClickableElement.js +4 -0
- package/libEs5/components/Advertising/handlers/clickThroughHandler.js +2 -1
- package/libEs5/components/Advertising/handlers/onBeforeSendEventHandler.js +8 -3
- package/libEs5/components/Advertising/handlers/viewThroughHandler.js +2 -1
- package/libEs5/components/Advertising/identities/collectID5Id.js +1 -1
- package/libEs5/components/Advertising/identities/collectRampId.js +1 -1
- package/libEs5/components/Consent/createConsentRequestPayload.js +14 -3
- package/libEs5/components/Consent/types.js +18 -0
- package/libEs5/components/Personalization/dom-actions/action.js +7 -4
- package/libEs5/components/Personalization/dom-actions/initDomActionsModules.js +10 -10
- package/libEs5/components/PushNotifications/helpers/constants.js +19 -0
- package/libEs5/components/PushNotifications/helpers/getPushSubscriptionDetails.js +116 -0
- package/libEs5/components/PushNotifications/helpers/readFromIndexedDb.js +41 -0
- package/libEs5/components/PushNotifications/helpers/saveToIndexedDb.js +50 -0
- package/libEs5/components/PushNotifications/helpers/serviceWorkerNotificationClickListener.js +85 -0
- package/libEs5/components/PushNotifications/helpers/serviceWorkerPushListener.js +70 -0
- package/libEs5/components/PushNotifications/index.js +129 -0
- package/libEs5/components/PushNotifications/request/createSendPushSubscriptionPayload.js +62 -0
- package/libEs5/components/PushNotifications/request/createSendPushSubscriptionRequest.js +35 -0
- package/libEs5/components/PushNotifications/request/makeSendPushSubscriptionRequest.js +93 -0
- package/libEs5/components/PushNotifications/request/makeSendServiceWorkerTrackingData.js +146 -0
- package/libEs5/components/PushNotifications/serviceWorker.js +91 -0
- package/libEs5/components/PushNotifications/types.js +95 -0
- package/libEs5/constants/libraryVersion.js +1 -1
- package/libEs5/core/componentCreators.js +8 -1
- package/libEs5/core/consent/createConsent.js +10 -0
- package/libEs5/core/consent/createConsentStateMachine.js +36 -0
- package/libEs5/core/consent/types.js +24 -0
- package/libEs5/core/edgeNetwork/injectSendEdgeNetworkRequest.js +20 -0
- package/libEs5/core/edgeNetwork/types.js +10 -0
- package/libEs5/core/identity/createIdentity.js +36 -0
- package/libEs5/core/identity/types.js +15 -0
- package/libEs5/core/injectCreateResponse.js +9 -7
- package/libEs5/core/types.js +101 -11
- package/libEs5/utils/bytes.js +12 -1
- package/libEs5/utils/createLoggingCookieJar.js +14 -1
- package/libEs5/utils/createMerger.js +5 -4
- package/libEs5/utils/index.js +19 -0
- package/libEs5/utils/indexedDb.js +73 -0
- package/libEs5/utils/injectStorage.js +19 -0
- package/libEs5/utils/request/createDataCollectionRequestPayload.js +16 -8
- package/libEs5/utils/request/createRequest.js +28 -1
- package/libEs5/utils/request/createRequestPayload.js +15 -2
- package/libEs5/utils/request/types.js +52 -0
- package/libEs5/utils/types.js +39 -0
- package/libEs6/components/ActivityCollector/utils/dom/findClickableElement.js +4 -0
- package/libEs6/components/Advertising/handlers/clickThroughHandler.js +2 -1
- package/libEs6/components/Advertising/handlers/onBeforeSendEventHandler.js +8 -3
- package/libEs6/components/Advertising/handlers/viewThroughHandler.js +2 -1
- package/libEs6/components/Advertising/identities/collectID5Id.js +1 -1
- package/libEs6/components/Advertising/identities/collectRampId.js +1 -1
- package/libEs6/components/Consent/createConsentRequestPayload.js +16 -3
- package/libEs6/components/Consent/types.js +15 -0
- package/libEs6/components/Personalization/dom-actions/action.js +7 -4
- package/libEs6/components/Personalization/dom-actions/initDomActionsModules.js +10 -10
- package/libEs6/components/PushNotifications/helpers/constants.js +16 -0
- package/libEs6/components/PushNotifications/helpers/getPushSubscriptionDetails.js +114 -0
- package/libEs6/components/PushNotifications/helpers/readFromIndexedDb.js +40 -0
- package/libEs6/components/PushNotifications/helpers/saveToIndexedDb.js +48 -0
- package/libEs6/components/PushNotifications/helpers/serviceWorkerNotificationClickListener.js +82 -0
- package/libEs6/components/PushNotifications/helpers/serviceWorkerPushListener.js +69 -0
- package/libEs6/components/PushNotifications/index.js +126 -0
- package/libEs6/components/PushNotifications/request/createSendPushSubscriptionPayload.js +61 -0
- package/libEs6/components/PushNotifications/request/createSendPushSubscriptionRequest.js +34 -0
- package/libEs6/components/PushNotifications/request/makeSendPushSubscriptionRequest.js +89 -0
- package/libEs6/components/PushNotifications/request/makeSendServiceWorkerTrackingData.js +146 -0
- package/libEs6/components/PushNotifications/serviceWorker.js +90 -0
- package/libEs6/components/PushNotifications/types.js +92 -0
- package/libEs6/constants/libraryVersion.js +1 -1
- package/libEs6/core/componentCreators.js +2 -1
- package/libEs6/core/consent/createConsent.js +12 -0
- package/libEs6/core/consent/createConsentStateMachine.js +36 -0
- package/libEs6/core/consent/types.js +21 -0
- package/libEs6/core/edgeNetwork/injectSendEdgeNetworkRequest.js +20 -0
- package/libEs6/core/edgeNetwork/types.js +7 -0
- package/libEs6/core/identity/createIdentity.js +38 -0
- package/libEs6/core/identity/types.js +12 -0
- package/libEs6/core/injectCreateResponse.js +11 -7
- package/libEs6/core/types.js +101 -11
- package/libEs6/utils/bytes.js +12 -1
- package/libEs6/utils/createLoggingCookieJar.js +15 -1
- package/libEs6/utils/createMerger.js +5 -4
- package/libEs6/utils/index.js +1 -0
- package/libEs6/utils/indexedDb.js +67 -0
- package/libEs6/utils/injectStorage.js +20 -0
- package/libEs6/utils/request/createDataCollectionRequestPayload.js +19 -8
- package/libEs6/utils/request/createRequest.js +29 -1
- package/libEs6/utils/request/createRequestPayload.js +15 -2
- package/libEs6/utils/request/types.js +49 -0
- package/libEs6/utils/types.js +36 -0
- package/package.json +45 -52
- package/scripts/alloyBuilder.js +130 -4
- package/types/components/ActivityCollector/utils/dom/findClickableElement.d.ts.map +1 -1
- package/types/components/Advertising/handlers/onBeforeSendEventHandler.d.ts.map +1 -1
- package/types/components/Advertising/handlers/viewThroughHandler.d.ts.map +1 -1
- package/types/components/Consent/createConsentRequest.d.ts +1 -11
- package/types/components/Consent/createConsentRequest.d.ts.map +1 -1
- package/types/components/Consent/createConsentRequestPayload.d.ts +2 -9
- package/types/components/Consent/createConsentRequestPayload.d.ts.map +1 -1
- package/types/components/Consent/types.d.ts +28 -0
- package/types/components/Consent/types.d.ts.map +1 -0
- package/types/components/Identity/getIdentity/createIdentityRequest.d.ts +1 -11
- package/types/components/Identity/getIdentity/createIdentityRequest.d.ts.map +1 -1
- package/types/components/Identity/getIdentity/createIdentityRequestPayload.d.ts +1 -9
- package/types/components/Identity/getIdentity/createIdentityRequestPayload.d.ts.map +1 -1
- package/types/components/Personalization/dom-actions/action.d.ts +1 -1
- package/types/components/Personalization/dom-actions/action.d.ts.map +1 -1
- package/types/components/PushNotifications/helpers/constants.d.ts +5 -0
- package/types/components/PushNotifications/helpers/constants.d.ts.map +1 -0
- package/types/components/PushNotifications/helpers/getPushSubscriptionDetails.d.ts +30 -0
- package/types/components/PushNotifications/helpers/getPushSubscriptionDetails.d.ts.map +1 -0
- package/types/components/PushNotifications/helpers/readFromIndexedDb.d.ts +4 -0
- package/types/components/PushNotifications/helpers/readFromIndexedDb.d.ts.map +1 -0
- package/types/components/PushNotifications/helpers/saveToIndexedDb.d.ts +9 -0
- package/types/components/PushNotifications/helpers/saveToIndexedDb.d.ts.map +1 -0
- package/types/components/PushNotifications/helpers/serviceWorkerNotificationClickListener.d.ts +9 -0
- package/types/components/PushNotifications/helpers/serviceWorkerNotificationClickListener.d.ts.map +1 -0
- package/types/components/PushNotifications/helpers/serviceWorkerPushListener.d.ts +8 -0
- package/types/components/PushNotifications/helpers/serviceWorkerPushListener.d.ts.map +1 -0
- package/types/components/PushNotifications/index.d.ts +51 -0
- package/types/components/PushNotifications/index.d.ts.map +1 -0
- package/types/components/PushNotifications/request/createSendPushSubscriptionPayload.d.ts +10 -0
- package/types/components/PushNotifications/request/createSendPushSubscriptionPayload.d.ts.map +1 -0
- package/types/components/PushNotifications/request/createSendPushSubscriptionRequest.d.ts +7 -0
- package/types/components/PushNotifications/request/createSendPushSubscriptionRequest.d.ts.map +1 -0
- package/types/components/PushNotifications/request/makeSendPushSubscriptionRequest.d.ts +21 -0
- package/types/components/PushNotifications/request/makeSendPushSubscriptionRequest.d.ts.map +1 -0
- package/types/components/PushNotifications/request/makeSendServiceWorkerTrackingData.d.ts +11 -0
- package/types/components/PushNotifications/request/makeSendServiceWorkerTrackingData.d.ts.map +1 -0
- package/types/components/PushNotifications/serviceWorker.d.ts +2 -0
- package/types/components/PushNotifications/serviceWorker.d.ts.map +1 -0
- package/types/components/PushNotifications/types.d.ts +190 -0
- package/types/components/PushNotifications/types.d.ts.map +1 -0
- package/types/components/StreamingMedia/createMediaRequest.d.ts +1 -11
- package/types/components/StreamingMedia/createMediaRequest.d.ts.map +1 -1
- package/types/core/componentCreators.d.ts +1 -0
- package/types/core/consent/createConsent.d.ts +4 -10
- package/types/core/consent/createConsent.d.ts.map +1 -1
- package/types/core/consent/createConsentStateMachine.d.ts +4 -12
- package/types/core/consent/createConsentStateMachine.d.ts.map +1 -1
- package/types/core/consent/types.d.ts +42 -0
- package/types/core/consent/types.d.ts.map +1 -0
- package/types/core/edgeNetwork/injectSendEdgeNetworkRequest.d.ts +15 -13
- package/types/core/edgeNetwork/injectSendEdgeNetworkRequest.d.ts.map +1 -1
- package/types/core/edgeNetwork/types.d.ts +12 -0
- package/types/core/edgeNetwork/types.d.ts.map +1 -0
- package/types/core/identity/createIdentity.d.ts +9 -9
- package/types/core/identity/createIdentity.d.ts.map +1 -1
- package/types/core/identity/types.d.ts +23 -0
- package/types/core/identity/types.d.ts.map +1 -0
- package/types/core/injectCreateResponse.d.ts +3 -27
- package/types/core/injectCreateResponse.d.ts.map +1 -1
- package/types/core/types.d.ts +209 -22
- package/types/core/types.d.ts.map +1 -1
- package/types/utils/bytes.d.ts +3 -1
- package/types/utils/bytes.d.ts.map +1 -1
- package/types/utils/createLoggingCookieJar.d.ts +5 -3
- package/types/utils/createLoggingCookieJar.d.ts.map +1 -1
- package/types/utils/createMerger.d.ts +1 -1
- package/types/utils/createMerger.d.ts.map +1 -1
- package/types/utils/index.d.ts +1 -0
- package/types/utils/indexedDb.d.ts +4 -0
- package/types/utils/indexedDb.d.ts.map +1 -0
- package/types/utils/injectStorage.d.ts +2 -40
- package/types/utils/injectStorage.d.ts.map +1 -1
- package/types/utils/request/createDataCollectionRequest.d.ts +1 -11
- package/types/utils/request/createDataCollectionRequest.d.ts.map +1 -1
- package/types/utils/request/createDataCollectionRequestPayload.d.ts +2 -9
- package/types/utils/request/createDataCollectionRequestPayload.d.ts.map +1 -1
- package/types/utils/request/createRequest.d.ts +13 -11
- package/types/utils/request/createRequest.d.ts.map +1 -1
- package/types/utils/request/createRequestPayload.d.ts +7 -9
- package/types/utils/request/createRequestPayload.d.ts.map +1 -1
- package/types/utils/request/types.d.ts +91 -0
- package/types/utils/request/types.d.ts.map +1 -0
- package/types/utils/types.d.ts +91 -0
- package/types/utils/types.d.ts.map +1 -0
|
@@ -14,6 +14,8 @@ OF ANY KIND, either express or implied. See the License for the specific languag
|
|
|
14
14
|
governing permissions and limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
/** @import { RequestPayload, Identity } from './types.js' */
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* createMerger creates a function that does a deep merge. Example:
|
|
19
21
|
* ```js
|
|
@@ -64,8 +66,19 @@ const createMergeConfigOverride = (content, key) => updates => {
|
|
|
64
66
|
Object.assign(hostObjectForUpdates, updates);
|
|
65
67
|
};
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Creates a request payload object with methods for merging different types of data.
|
|
71
|
+
* This provides the base functionality that all types of request payloads share.
|
|
72
|
+
*
|
|
73
|
+
* @function
|
|
74
|
+
*
|
|
75
|
+
* @param {Object} options
|
|
76
|
+
* @param {Object} options.content
|
|
77
|
+
* @param {function(string, Identity): void} options.addIdentity
|
|
78
|
+
* @param {function(string): boolean} options.hasIdentity
|
|
79
|
+
*
|
|
80
|
+
* @returns {RequestPayload}
|
|
81
|
+
*/
|
|
69
82
|
var _default = options => {
|
|
70
83
|
const {
|
|
71
84
|
content,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.Types = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Request object with methods to access and modify request properties.
|
|
6
|
+
*
|
|
7
|
+
* @typedef {Object} Request
|
|
8
|
+
* @property {function(): string} getId
|
|
9
|
+
* @property {function(): RequestPayload} getPayload
|
|
10
|
+
* @property {function({isIdentityEstablished: boolean}): string} getAction
|
|
11
|
+
* @property {function(): string|undefined} getDatastreamIdOverride
|
|
12
|
+
* @property {Function} getUseSendBeacon
|
|
13
|
+
* @property {function(): string|undefined} getEdgeSubPath
|
|
14
|
+
* @property {Function} getUseIdThirdPartyDomain
|
|
15
|
+
* @property {Function} setUseIdThirdPartyDomain
|
|
16
|
+
* @property {Function} setIsIdentityEstablished
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Request payload object with methods for merging different types of data.
|
|
21
|
+
*
|
|
22
|
+
* @typedef {Object} RequestPayload
|
|
23
|
+
* @property {function(object): void} mergeMeta
|
|
24
|
+
* @property {function(object): void} mergeState
|
|
25
|
+
* @property {function(object): void} mergeQuery
|
|
26
|
+
* @property {function(object): void} mergeConfigOverride
|
|
27
|
+
* @property {function(string, Identity): void} options.addIdentity
|
|
28
|
+
* @property {function(string): boolean} options.hasIdentity
|
|
29
|
+
* @property {function(): object} toJSON
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Request payload object with methods for merging different types of data.
|
|
34
|
+
*
|
|
35
|
+
* @typedef {Object} DataCollectionRequestPayload
|
|
36
|
+
* @property {function(object): void} mergeMeta
|
|
37
|
+
* @property {function(object): void} mergeState
|
|
38
|
+
* @property {function(object): void} mergeQuery
|
|
39
|
+
* @property {function(object): void} mergeConfigOverride
|
|
40
|
+
* @property {function(string, Identity): void} options.addIdentity
|
|
41
|
+
* @property {function(string): boolean} options.hasIdentity
|
|
42
|
+
* @property {function(object): void} addEvent
|
|
43
|
+
* @property {function(): boolean} getDocumentMayUnload
|
|
44
|
+
* @property {function(): object} toJSON
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {Object} Identity
|
|
49
|
+
* @property {string} id
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
const Types = exports.Types = {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.Types = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} Storage
|
|
6
|
+
* @property {function(string): string|null} getItem
|
|
7
|
+
* @property {function(string, string): void} setItem
|
|
8
|
+
* @property {function(): void} clear
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} CookieAttributes
|
|
13
|
+
* @property {number|Date} [expires] - Cookie expiration (number of days or Date object)
|
|
14
|
+
* @property {string} [path] - Cookie path (default: "/")
|
|
15
|
+
* @property {string} [domain] - Cookie domain
|
|
16
|
+
* @property {boolean} [secure] - Requires HTTPS transmission
|
|
17
|
+
* @property {"strict"|"lax"|"none"} [sameSite] - SameSite attribute
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Object} CookieConverter
|
|
22
|
+
* @property {function(string, string): string} [read] - Custom decoder function
|
|
23
|
+
* @property {function(string, string): string} [write] - Custom encoder function
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {Object} CookieJar
|
|
28
|
+
* @property {function(string): string|undefined} get - Get cookie value by name, or get all cookies as object if no name provided
|
|
29
|
+
* @property {function(): Object<string, string>} get - Get all cookies as key-value object when called with no arguments
|
|
30
|
+
* @property {function(string, string, CookieAttributes=): string|undefined} set - Set cookie with optional attributes
|
|
31
|
+
* @property {function(string, CookieAttributes=): void} remove - Remove cookie with optional attributes (must match set attributes)
|
|
32
|
+
* @property {function(CookieConverter): CookieJar} withConverter - Create new instance with custom encoding/decoding
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {function(string): { session: Storage, persistent: Storage }} StorageCreator
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const Types = exports.Types = {};
|
|
@@ -17,6 +17,10 @@ import isButtonSubmitElement from "./isButtonSubmitElement.js";
|
|
|
17
17
|
export default element => {
|
|
18
18
|
let node = element;
|
|
19
19
|
while (node) {
|
|
20
|
+
// Stop looking when BODY is reached
|
|
21
|
+
if (node.nodeName && node.nodeName === "BODY") {
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
20
24
|
if (isSupportedAnchorElement(node) || elementHasClickHandler(node) || isInputSubmitElement(node) || isButtonSubmitElement(node)) {
|
|
21
25
|
return node;
|
|
22
26
|
}
|
|
@@ -62,7 +62,8 @@ export default async function handleClickThrough({
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
-
eventType: AD_CONVERSION_CLICK_EVENT_TYPE
|
|
65
|
+
eventType: AD_CONVERSION_CLICK_EVENT_TYPE,
|
|
66
|
+
timestamp: new Date().toISOString()
|
|
66
67
|
};
|
|
67
68
|
event.setUserXdm(xdm);
|
|
68
69
|
cookieManager.setValue(LAST_CONVERSION_TIME_KEY);
|
|
@@ -10,11 +10,12 @@ import { getRampId } from "../identities/collectRampId.js";
|
|
|
10
10
|
import { appendAdvertisingIdQueryToEvent, getUrlParams, isThrottled } from "../utils/helpers.js";
|
|
11
11
|
import { SURFER_ID, ID5_ID, RAMP_ID } from "../constants/index.js";
|
|
12
12
|
import { AUTO, WAIT } from "../../../constants/consentStatus.js";
|
|
13
|
+
import { CHROME } from "../../../constants/browser.js";
|
|
13
14
|
const isAdvertisingDisabled = advertising => {
|
|
14
|
-
return ![AUTO, WAIT].includes(advertising?.handleAdvertisingData);
|
|
15
|
+
return ![AUTO, WAIT].includes(advertising?.handleAdvertisingData?.toLowerCase());
|
|
15
16
|
};
|
|
16
17
|
const waitForAdvertisingId = advertising => {
|
|
17
|
-
return advertising?.handleAdvertisingData === WAIT;
|
|
18
|
+
return advertising?.handleAdvertisingData?.toLowerCase() === WAIT;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -44,7 +45,11 @@ export default async function handleOnBeforeSendEvent({
|
|
|
44
45
|
if (isAdvertisingDisabled(advertising) || isClickThru || isThrottled(SURFER_ID, cookieManager) && isThrottled(ID5_ID, cookieManager) && isThrottled(RAMP_ID, cookieManager)) return;
|
|
45
46
|
try {
|
|
46
47
|
const useShortTimeout = waitForAdvertisingId(advertising);
|
|
47
|
-
|
|
48
|
+
let rampIdPromise = null;
|
|
49
|
+
if (!getBrowser || getBrowser() !== CHROME) {
|
|
50
|
+
rampIdPromise = getRampId(logger, componentConfig.rampIdJSPath, cookieManager, useShortTimeout, useShortTimeout);
|
|
51
|
+
}
|
|
52
|
+
const [surferIdResult, id5IdResult, rampIdResult] = await Promise.allSettled([collectSurferId(cookieManager, getBrowser, useShortTimeout), getID5Id(logger, componentConfig.id5PartnerId, useShortTimeout, useShortTimeout), rampIdPromise]);
|
|
48
53
|
const availableIds = {};
|
|
49
54
|
if (surferIdResult.status === "fulfilled" && surferIdResult.value && !isThrottled(SURFER_ID, cookieManager)) {
|
|
50
55
|
availableIds.surferId = surferIdResult.value;
|
|
@@ -23,7 +23,8 @@ export default async function handleViewThrough({
|
|
|
23
23
|
try {
|
|
24
24
|
const event = appendAdvertisingIdQueryToEvent(resolvedIds, eventManager.createEvent(), cookieManager, componentConfig, true);
|
|
25
25
|
const xdm = {
|
|
26
|
-
eventType: AD_CONVERSION_VIEW_EVENT_TYPE
|
|
26
|
+
eventType: AD_CONVERSION_VIEW_EVENT_TYPE,
|
|
27
|
+
timestamp: new Date().toISOString()
|
|
27
28
|
};
|
|
28
29
|
event.setUserXdm(xdm);
|
|
29
30
|
const result = await adConversionHandler.trackAdConversion({
|
|
@@ -13,7 +13,7 @@ import { loadScript } from "../../../utils/dom/index.js";
|
|
|
13
13
|
import { ID5_SCRIPT_URL } from "../constants/index.js";
|
|
14
14
|
let id5Id = "";
|
|
15
15
|
let inProgressId5Promise = null;
|
|
16
|
-
const SHORT_TIMEOUT_MS =
|
|
16
|
+
const SHORT_TIMEOUT_MS = 2000;
|
|
17
17
|
const DEFAULT_TIMEOUT_MS = 30000;
|
|
18
18
|
const initiateID5Call = (partnerId, useShortTimeout, logger) => {
|
|
19
19
|
partnerId = Math.floor(Number(partnerId));
|
|
@@ -10,10 +10,18 @@ OF ANY KIND, either express or implied. See the License for the specific languag
|
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/** @import { ConsentRequestPayload } from './types.js' */
|
|
14
|
+
|
|
13
15
|
import { createRequestPayload } from "../../utils/request/index.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @function
|
|
19
|
+
*
|
|
20
|
+
* @returns {ConsentRequestPayload}
|
|
21
|
+
*/
|
|
14
22
|
export default () => {
|
|
15
23
|
const content = {};
|
|
16
|
-
const
|
|
24
|
+
const requestPayload = createRequestPayload({
|
|
17
25
|
content,
|
|
18
26
|
addIdentity: (namespaceCode, identity) => {
|
|
19
27
|
content.identityMap = content.identityMap || {};
|
|
@@ -24,8 +32,13 @@ export default () => {
|
|
|
24
32
|
return (content.identityMap && content.identityMap[namespaceCode]) !== undefined;
|
|
25
33
|
}
|
|
26
34
|
});
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
|
|
36
|
+
/** @type {ConsentRequestPayload} */
|
|
37
|
+
const payload = {
|
|
38
|
+
...requestPayload,
|
|
39
|
+
setConsent: consent => {
|
|
40
|
+
content.consent = consent;
|
|
41
|
+
}
|
|
29
42
|
};
|
|
30
43
|
return payload;
|
|
31
44
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request payload object with methods for merging different types of data.
|
|
3
|
+
*
|
|
4
|
+
* @typedef {Object} ConsentRequestPayload
|
|
5
|
+
* @property {Function} mergeMeta
|
|
6
|
+
* @property {Function} mergeState
|
|
7
|
+
* @property {Function} mergeQuery
|
|
8
|
+
* @property {Function} mergeConfigOverride
|
|
9
|
+
* @property {Function} addIdentity
|
|
10
|
+
* @property {Function} hasIdentity
|
|
11
|
+
* @property {Function} toJSON
|
|
12
|
+
* @property {Function} setConsent
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const Types = {};
|
|
@@ -40,9 +40,10 @@ const renderContent = ({
|
|
|
40
40
|
content,
|
|
41
41
|
decorateProposition,
|
|
42
42
|
renderFunc,
|
|
43
|
-
renderStatusHandler
|
|
43
|
+
renderStatusHandler,
|
|
44
|
+
alwaysRender
|
|
44
45
|
}) => {
|
|
45
|
-
const executions = containers.filter(renderStatusHandler.shouldRender).map(async container => {
|
|
46
|
+
const executions = containers.filter(element => alwaysRender || renderStatusHandler.shouldRender(element)).map(async container => {
|
|
46
47
|
await renderFunc(container, content, decorateProposition);
|
|
47
48
|
renderStatusHandler.markAsRendered(container);
|
|
48
49
|
});
|
|
@@ -53,8 +54,9 @@ const renderContent = ({
|
|
|
53
54
|
* Creates an action function that renders content into a container element.
|
|
54
55
|
*
|
|
55
56
|
* @param {Function} renderFunc - The function that performs the rendering.
|
|
57
|
+
* @param {boolean} alwaysRender - Whether to always render the content, even if it has already been rendered.
|
|
56
58
|
*/
|
|
57
|
-
export const createAction = renderFunc => {
|
|
59
|
+
export const createAction = (renderFunc, alwaysRender = false) => {
|
|
58
60
|
/**
|
|
59
61
|
* Renders content into a container element.
|
|
60
62
|
*
|
|
@@ -76,7 +78,8 @@ export const createAction = renderFunc => {
|
|
|
76
78
|
content,
|
|
77
79
|
decorateProposition,
|
|
78
80
|
renderFunc,
|
|
79
|
-
renderStatusHandler
|
|
81
|
+
renderStatusHandler,
|
|
82
|
+
alwaysRender
|
|
80
83
|
});
|
|
81
84
|
} finally {
|
|
82
85
|
showElements(prehidingSelector);
|
|
@@ -45,21 +45,21 @@ export const DOM_ACTION_CLICK = "click";
|
|
|
45
45
|
export const DOM_ACTION_COLLECT_INTERACTIONS = "collectInteractions";
|
|
46
46
|
export default () => {
|
|
47
47
|
return {
|
|
48
|
-
[DOM_ACTION_SET_HTML]: createAction(setHtml),
|
|
48
|
+
[DOM_ACTION_SET_HTML]: createAction(setHtml, true),
|
|
49
49
|
[DOM_ACTION_CUSTOM_CODE]: createAction(prependHtml),
|
|
50
|
-
[DOM_ACTION_SET_TEXT]: createAction(setText),
|
|
51
|
-
[DOM_ACTION_SET_ATTRIBUTE]: createAction(setAttributes),
|
|
52
|
-
[DOM_ACTION_SET_IMAGE_SOURCE]: createAction(swapImage),
|
|
53
|
-
[DOM_ACTION_SET_STYLE]: createAction(setStyles),
|
|
54
|
-
[DOM_ACTION_MOVE]: createAction(move),
|
|
55
|
-
[DOM_ACTION_RESIZE]: createAction(resize),
|
|
50
|
+
[DOM_ACTION_SET_TEXT]: createAction(setText, true),
|
|
51
|
+
[DOM_ACTION_SET_ATTRIBUTE]: createAction(setAttributes, true),
|
|
52
|
+
[DOM_ACTION_SET_IMAGE_SOURCE]: createAction(swapImage, true),
|
|
53
|
+
[DOM_ACTION_SET_STYLE]: createAction(setStyles, true),
|
|
54
|
+
[DOM_ACTION_MOVE]: createAction(move, true),
|
|
55
|
+
[DOM_ACTION_RESIZE]: createAction(resize, true),
|
|
56
56
|
[DOM_ACTION_REARRANGE]: createAction(rearrangeChildren),
|
|
57
|
-
[DOM_ACTION_REMOVE]: createAction(removeNode),
|
|
57
|
+
[DOM_ACTION_REMOVE]: createAction(removeNode, true),
|
|
58
58
|
[DOM_ACTION_INSERT_AFTER]: createAction(insertHtmlAfter),
|
|
59
59
|
[DOM_ACTION_INSERT_BEFORE]: createAction(insertHtmlBefore),
|
|
60
|
-
[DOM_ACTION_REPLACE_HTML]: createAction(replaceHtml),
|
|
60
|
+
[DOM_ACTION_REPLACE_HTML]: createAction(replaceHtml, true),
|
|
61
61
|
[DOM_ACTION_PREPEND_HTML]: createAction(prependHtml),
|
|
62
62
|
[DOM_ACTION_APPEND_HTML]: createAction(appendHtml),
|
|
63
|
-
[DOM_ACTION_COLLECT_INTERACTIONS]: createAction(collectInteractions)
|
|
63
|
+
[DOM_ACTION_COLLECT_INTERACTIONS]: createAction(collectInteractions, true)
|
|
64
64
|
};
|
|
65
65
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const DB_NAME = "alloyPushNotifications";
|
|
14
|
+
export const DB_VERSION = 1;
|
|
15
|
+
export const STORE_NAME = "config";
|
|
16
|
+
export const INDEX_KEY = "alloyConfig";
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** @import { PushSubscription } from '../types.js' */
|
|
14
|
+
|
|
15
|
+
import { base64ToBytes, bytesToBase64 } from "../../../utils/index.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Gets push subscription details for the current browser.
|
|
19
|
+
*
|
|
20
|
+
* @async
|
|
21
|
+
* @function
|
|
22
|
+
*
|
|
23
|
+
* @param {object} options
|
|
24
|
+
* @param {string} options.vapidPublicKey - The VAPID public key in base64 format used for push notification authentication.
|
|
25
|
+
* @param {Window} options.window
|
|
26
|
+
*
|
|
27
|
+
* @returns {Promise<PushSubscription>} A promise that resolves to an object containing the push subscription details.
|
|
28
|
+
|
|
29
|
+
* @throws {Error} Throws an error if service workers are not supported in the browser.
|
|
30
|
+
* @throws {Error} Throws an error if user didn't approve push notifications for the domain.
|
|
31
|
+
* @throws {Error} Throws an error if push notifications are not supported in the browser.
|
|
32
|
+
* @throws {Error} Throws an error if no VAPID public key was provided.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Get subscription details with VAPID key
|
|
36
|
+
* const vapidKey = "BEl62iUYgUivxIkv69yViEuiBIa40HI5hmjHbKPlXO...";
|
|
37
|
+
* const subscription = await getPushSubscriptionDetails(vapidKey);
|
|
38
|
+
* console.log(subscription.endpoint); // "https://fcm.googleapis.com/fcm/send/..."
|
|
39
|
+
*/
|
|
40
|
+
const getPushSubscriptionDetails = async ({
|
|
41
|
+
vapidPublicKey,
|
|
42
|
+
window
|
|
43
|
+
}) => {
|
|
44
|
+
if (!("serviceWorker" in window.navigator)) {
|
|
45
|
+
throw new Error("Service workers are not supported in this browser.");
|
|
46
|
+
}
|
|
47
|
+
if (!("PushManager" in window) || !("Notification" in window)) {
|
|
48
|
+
throw new Error("Push notifications are not supported in this browser.");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @type {object} */
|
|
52
|
+
const notification = window.Notification;
|
|
53
|
+
if (notification.permission !== "granted") {
|
|
54
|
+
throw new Error("The user has not given permission to send push notifications.");
|
|
55
|
+
}
|
|
56
|
+
const serviceWorkerRegistration =
|
|
57
|
+
// eslint-disable-next-line compat/compat
|
|
58
|
+
await window.navigator.serviceWorker.getRegistration();
|
|
59
|
+
if (!serviceWorkerRegistration) {
|
|
60
|
+
throw new Error("No service worker registration was found.");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Even `applicationServerKey` is not required in the spec, some browsers like Chrome are requiring it.
|
|
64
|
+
if (!vapidPublicKey) {
|
|
65
|
+
throw new Error("No VAPID public key was provided.");
|
|
66
|
+
}
|
|
67
|
+
const subscriptionOptions = {
|
|
68
|
+
userVisibleOnly: true,
|
|
69
|
+
applicationServerKey: base64ToBytes(vapidPublicKey)
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Push subscription handling strategy:
|
|
73
|
+
//
|
|
74
|
+
// 1. We always call subscribe() to either get the current subscription or create a new one.
|
|
75
|
+
// - If called with the same VAPID key as an existing subscription, it returns that subscription
|
|
76
|
+
// - If called with a different VAPID key when a subscription exists, it throws an error
|
|
77
|
+
//
|
|
78
|
+
// 2. Error handling approach:
|
|
79
|
+
// - Browser error messages vary and don't clearly indicate VAPID key conflicts
|
|
80
|
+
// - When subscribe() fails, we assume it's likely due to a VAPID key mismatch
|
|
81
|
+
// - We attempt recovery by unsubscribing the existing subscription and retrying
|
|
82
|
+
// - If the retry also fails, we re-throw the original error
|
|
83
|
+
//
|
|
84
|
+
// This strategy ensures we can handle both new subscriptions and VAPID key changes
|
|
85
|
+
// while gracefully falling back to error reporting when recovery isn't possible.
|
|
86
|
+
try {
|
|
87
|
+
const subscription = await serviceWorkerRegistration.pushManager.subscribe(subscriptionOptions);
|
|
88
|
+
return {
|
|
89
|
+
endpoint: subscription.endpoint,
|
|
90
|
+
keys: {
|
|
91
|
+
p256dh: bytesToBase64(new Uint8Array(subscription.getKey("p256dh")), {
|
|
92
|
+
urlSafe: true
|
|
93
|
+
}),
|
|
94
|
+
auth: bytesToBase64(new Uint8Array(subscription.getKey("auth")), {
|
|
95
|
+
urlSafe: true
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
} catch (e) {
|
|
100
|
+
const subscription = await serviceWorkerRegistration.pushManager.getSubscription();
|
|
101
|
+
if (!subscription) {
|
|
102
|
+
throw e;
|
|
103
|
+
}
|
|
104
|
+
const unsubscribeResult = await subscription.unsubscribe();
|
|
105
|
+
if (!unsubscribeResult) {
|
|
106
|
+
throw e;
|
|
107
|
+
}
|
|
108
|
+
return getPushSubscriptionDetails({
|
|
109
|
+
vapidPublicKey,
|
|
110
|
+
window
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
export default getPushSubscriptionDetails;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** @import { ServiceWorkerLogger } from '../types.js' */
|
|
14
|
+
|
|
15
|
+
import { getFromIndexedDbStore, openIndexedDb } from "../../../utils/indexedDb.js";
|
|
16
|
+
import { DB_NAME, DB_VERSION, STORE_NAME, INDEX_KEY } from "./constants.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {ServiceWorkerLogger} logger
|
|
20
|
+
* @returns {Promise<Object|undefined>}
|
|
21
|
+
* @throws {Error}
|
|
22
|
+
*/
|
|
23
|
+
export default async logger => {
|
|
24
|
+
try {
|
|
25
|
+
const db = await openIndexedDb(DB_NAME, DB_VERSION, (/** @type {IDBDatabase} */db) => {
|
|
26
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
27
|
+
db.createObjectStore(STORE_NAME, {
|
|
28
|
+
keyPath: "id"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const existingConfigData = await getFromIndexedDbStore(db, STORE_NAME, INDEX_KEY);
|
|
33
|
+
db.close();
|
|
34
|
+
return existingConfigData;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger.error("Failed to read data from IndexedDB", {
|
|
37
|
+
error
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** @import { Logger } from '../../../core/types.js' */
|
|
14
|
+
|
|
15
|
+
import { openIndexedDb, getFromIndexedDbStore, putToIndexedDbStore } from "../../../utils/index.js";
|
|
16
|
+
import { DB_NAME, DB_VERSION, STORE_NAME, INDEX_KEY } from "./constants.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {Object} data
|
|
20
|
+
* @param {Logger} logger
|
|
21
|
+
*
|
|
22
|
+
* @returns {Promise<void>}
|
|
23
|
+
*/
|
|
24
|
+
export default async function saveToIndexedDB(data, logger) {
|
|
25
|
+
try {
|
|
26
|
+
const db = await openIndexedDb(DB_NAME, DB_VERSION, (/** @type {IDBDatabase} */db) => {
|
|
27
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
28
|
+
db.createObjectStore(STORE_NAME, {
|
|
29
|
+
keyPath: "id"
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const existingConfigData = await getFromIndexedDbStore(db, STORE_NAME, INDEX_KEY);
|
|
34
|
+
const updatedConfigData = {
|
|
35
|
+
...(existingConfigData || {}),
|
|
36
|
+
...data,
|
|
37
|
+
id: INDEX_KEY,
|
|
38
|
+
timestamp: Date.now()
|
|
39
|
+
};
|
|
40
|
+
await putToIndexedDbStore(db, STORE_NAME, updatedConfigData);
|
|
41
|
+
db.close();
|
|
42
|
+
logger.info("Successfully saved web SDK config to IndexedDB", updatedConfigData);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
logger.error("Failed to save config to IndexedDB", {
|
|
45
|
+
error
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// @ts-check
|
|
14
|
+
/// <reference lib="webworker" />
|
|
15
|
+
|
|
16
|
+
/** @import { ServiceWorkerLogger } from '../types.js' */
|
|
17
|
+
|
|
18
|
+
import makeSendServiceWorkerTrackingData from "../request/makeSendServiceWorkerTrackingData.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} type
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
const canHandleUrl = type => ["DEEPLINK", "WEBURL"].includes(type);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @function
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} options
|
|
30
|
+
* @param {ServiceWorkerGlobalScope} options.sw
|
|
31
|
+
* @param {NotificationEvent} options.event
|
|
32
|
+
* @param {(url: string, options: object) => Promise<Response>} options.fetch
|
|
33
|
+
* @param {ServiceWorkerLogger} options.logger
|
|
34
|
+
*/
|
|
35
|
+
export default ({
|
|
36
|
+
event,
|
|
37
|
+
sw,
|
|
38
|
+
logger,
|
|
39
|
+
fetch
|
|
40
|
+
}) => {
|
|
41
|
+
event.notification.close();
|
|
42
|
+
const data = event.notification.data;
|
|
43
|
+
let targetUrl = null;
|
|
44
|
+
let actionLabel = null;
|
|
45
|
+
if (event.action) {
|
|
46
|
+
const actionIndex = parseInt(event.action.replace("action_", ""), 10);
|
|
47
|
+
if (data?.actions?.buttons[actionIndex]) {
|
|
48
|
+
const button = data.actions.buttons[actionIndex];
|
|
49
|
+
actionLabel = button.label;
|
|
50
|
+
if (canHandleUrl(button.type) && button.uri) {
|
|
51
|
+
targetUrl = button.uri;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} else if (canHandleUrl(data?.interaction?.type) && data?.interaction?.uri) {
|
|
55
|
+
targetUrl = data.interaction.uri;
|
|
56
|
+
}
|
|
57
|
+
makeSendServiceWorkerTrackingData({
|
|
58
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
59
|
+
xdm: data._xdm.mixins,
|
|
60
|
+
actionLabel,
|
|
61
|
+
applicationLaunches: 1
|
|
62
|
+
}, {
|
|
63
|
+
logger,
|
|
64
|
+
fetch
|
|
65
|
+
}).catch(error => {
|
|
66
|
+
logger.error("Failed to send tracking call:", error);
|
|
67
|
+
});
|
|
68
|
+
if (targetUrl) {
|
|
69
|
+
event.waitUntil(sw.clients.matchAll({
|
|
70
|
+
type: "window"
|
|
71
|
+
}).then(clientList => {
|
|
72
|
+
for (const client of clientList) {
|
|
73
|
+
if (client.url === targetUrl && "focus" in client) {
|
|
74
|
+
return client.focus();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (sw.clients.openWindow) {
|
|
78
|
+
return sw.clients.openWindow(targetUrl);
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
};
|