@adobe/alloy 2.34.2-beta.3 → 2.35.0-beta.4

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.
Files changed (38) hide show
  1. package/dist/alloy.js +286 -90
  2. package/dist/alloy.min.js +1 -1
  3. package/dist/alloyServiceWorker.js +85 -12
  4. package/dist/alloyServiceWorker.min.js +1 -1
  5. package/dist/types/browser/src/components/ActivityCollector/configValidators.d.ts +2 -2
  6. package/dist/types/browser/src/components/Advertising/configValidators.d.ts +1 -1
  7. package/dist/types/browser/src/components/Context/index.d.ts +1 -1
  8. package/dist/types/browser/src/components/Personalization/index.d.ts +1 -1
  9. package/dist/types/browser/src/components/PushNotifications/helpers/readFromIndexedDb.d.ts +2 -1
  10. package/dist/types/browser/src/components/PushNotifications/helpers/saveToIndexedDb.d.ts +3 -2
  11. package/dist/types/browser/src/components/PushNotifications/helpers/serviceWorkerPushListener.d.ts +3 -1
  12. package/dist/types/browser/src/components/PushNotifications/index.d.ts +1 -1
  13. package/dist/types/browser/src/components/PushNotifications/request/makeSendPushSubscriptionRequest.d.ts +5 -1
  14. package/dist/types/browser/src/components/PushNotifications/request/makeSendServiceWorkerTrackingData.d.ts +4 -2
  15. package/dist/types/browser/src/components/PushNotifications/types.d.ts +28 -0
  16. package/dist/types/core/src/components/BrandConcierge/configValidators.d.ts +1 -1
  17. package/dist/types/core/src/components/Consent/configValidators.d.ts +1 -1
  18. package/dist/types/core/src/components/Consent/validateSetConsentOptions.d.ts +1 -1
  19. package/dist/types/core/src/components/Identity/configValidators.d.ts +1 -1
  20. package/dist/types/core/src/components/RulesEngine/index.d.ts +1 -1
  21. package/dist/types/core/src/components/StreamingMedia/configValidators.d.ts +1 -1
  22. package/dist/types/core/src/core/config/createCoreConfigs.d.ts +1 -1
  23. package/dist/types/core/src/utils/bytes.d.ts +1 -1
  24. package/dist/types/core/src/utils/validateConfigOverride.d.ts +1 -1
  25. package/dist/types/core/src/utils/validateIdentityMap.d.ts +1 -1
  26. package/dist/types/core/src/utils/validation/index.d.ts +23 -11
  27. package/dist/types/core/src/utils/validation/types.d.ts +133 -0
  28. package/dist/types/core/src/utils/validation/utils.d.ts +4 -3
  29. package/package.json +2 -2
  30. package/src/components/PushNotifications/helpers/getPushSubscriptionDetails.js +10 -8
  31. package/src/components/PushNotifications/helpers/readFromIndexedDb.js +3 -2
  32. package/src/components/PushNotifications/helpers/saveToIndexedDb.js +2 -1
  33. package/src/components/PushNotifications/helpers/serviceWorkerPushListener.js +58 -2
  34. package/src/components/PushNotifications/index.js +7 -6
  35. package/src/components/PushNotifications/request/makeSendPushSubscriptionRequest.js +2 -1
  36. package/src/components/PushNotifications/request/makeSendServiceWorkerTrackingData.js +14 -6
  37. package/src/components/PushNotifications/types.js +15 -0
  38. package/src/createEventListeners.js +1 -0
@@ -10,6 +10,20 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
+ /*
14
+ Copyright 2019 Adobe. All rights reserved.
15
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
16
+ you may not use this file except in compliance with the License. You may obtain a copy
17
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
18
+
19
+ Unless required by applicable law or agreed to in writing, software distributed under
20
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
21
+ OF ANY KIND, either express or implied. See the License for the specific language
22
+ governing permissions and limitations under the License.
23
+ */
24
+
25
+ var ecidNamespace = "ECID";
26
+
13
27
  /*
14
28
  Copyright 2025 Adobe. All rights reserved.
15
29
  This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -22,11 +36,50 @@ OF ANY KIND, either express or implied. See the License for the specific languag
22
36
  governing permissions and limitations under the License.
23
37
  */
24
38
 
25
- // @ts-check
26
- /// <reference lib="webworker" />
27
39
 
28
- /** @import { PushNotificationData } from '../types.js' */
29
- /** @import { ServiceWorkerLogger } from '../types.js' */
40
+ /**
41
+ * Determines whether a notification targeted at a specific identity should be
42
+ * shown on this browser. When the payload contains an `identity` with the ECID
43
+ * namespace, the notification is only shown if the ECID in the payload matches
44
+ * the ECID stored in IndexedDB for this browser. When there is no identity, or
45
+ * the namespace is not ECID, the notification is always shown.
46
+ *
47
+ * @param {Object} options
48
+ * @param {PushNotificationData["web"]} options.webData
49
+ * @param {(logger: ServiceWorkerLogger) => Promise<PushServiceWorkerConfig|undefined>} options.readFromIndexedDb
50
+ * @param {ServiceWorkerLogger} options.logger
51
+ * @returns {Promise<boolean>}
52
+ */
53
+ const shouldShowNotification = async ({
54
+ webData,
55
+ readFromIndexedDb,
56
+ logger,
57
+ }) => {
58
+ const { identity } = webData;
59
+
60
+ if (!identity || identity.namespace?.toUpperCase() !== ecidNamespace) {
61
+ return true;
62
+ }
63
+
64
+ let storedConfig;
65
+ try {
66
+ storedConfig = await readFromIndexedDb(logger);
67
+ } catch (error) {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ logger.error(`Unable to read the stored ECID for this browser. ${message}`);
70
+ return true;
71
+ }
72
+ const storedEcid = storedConfig?.ecid;
73
+
74
+ if (identity.id !== storedEcid) {
75
+ logger.info(
76
+ "Suppressing push notification: payload ECID does not match the ECID stored for this browser.",
77
+ );
78
+ return false;
79
+ }
80
+
81
+ return true;
82
+ };
30
83
 
31
84
  /**
32
85
  * @async
@@ -36,9 +89,10 @@ governing permissions and limitations under the License.
36
89
  * @param {ServiceWorkerGlobalScope} options.sw
37
90
  * @param {PushEvent} options.event
38
91
  * @param {ServiceWorkerLogger} options.logger
92
+ * @param {(logger: ServiceWorkerLogger) => Promise<PushServiceWorkerConfig|undefined>} options.readFromIndexedDb
39
93
  * @returns {Promise<void>}
40
94
  */
41
- var serviceWorkerPushListener = async ({ sw, event, logger }) => {
95
+ var serviceWorkerPushListener = async ({ sw, event, logger, readFromIndexedDb }) => {
42
96
  if (!event.data) {
43
97
  return;
44
98
  }
@@ -57,6 +111,15 @@ var serviceWorkerPushListener = async ({ sw, event, logger }) => {
57
111
  return;
58
112
  }
59
113
 
114
+ const showNotification = await shouldShowNotification({
115
+ webData,
116
+ readFromIndexedDb,
117
+ logger,
118
+ });
119
+ if (!showNotification) {
120
+ return;
121
+ }
122
+
60
123
  /** @type {Record<string, unknown>} */
61
124
  const notificationOptions = {
62
125
  data: webData,
@@ -251,7 +314,7 @@ governing permissions and limitations under the License.
251
314
 
252
315
  /**
253
316
  * @param {ServiceWorkerLogger} logger
254
- * @returns {Promise<Object|undefined>}
317
+ * @returns {Promise<PushServiceWorkerConfig|undefined>}
255
318
  * @throws {Error}
256
319
  */
257
320
  var readFromIndexedDb = async (logger) => {
@@ -277,6 +340,7 @@ var readFromIndexedDb = async (logger) => {
277
340
  return existingConfigData;
278
341
  } catch (error) {
279
342
  logger.error("Failed to read data from IndexedDB", { error });
343
+ throw error;
280
344
  }
281
345
  };
282
346
 
@@ -294,14 +358,16 @@ governing permissions and limitations under the License.
294
358
 
295
359
  /** @import { ServiceWorkerLogger } from '../types.js' */
296
360
  /** @import { TrackingDataPayload } from '../types.js' */
361
+ /** @import { PushServiceWorkerConfig } from '../types.js' */
362
+ /** @import { XdmTrackingContext } from '../types.js' */
297
363
 
298
364
  /**
299
365
  * @param {Object} dependencies
300
- * @param {(logger: ServiceWorkerLogger) => Promise<Object>} dependencies.readFromIndexedDb
366
+ * @param {(logger: ServiceWorkerLogger) => Promise<PushServiceWorkerConfig>} dependencies.readFromIndexedDb
301
367
  * @param {() => string} dependencies.uuidv4
302
368
  * @param {ServiceWorkerLogger} dependencies.logger
303
369
  * @param {(url: string, options: object) => Promise<Response>} dependencies.fetch
304
- * @returns {(options: { xdm: Object, actionLabel?: string, applicationLaunches?: number }) => Promise<boolean>}
370
+ * @returns {(options: { xdm: XdmTrackingContext, actionLabel?: string, applicationLaunches?: number }) => Promise<boolean>}
305
371
  */
306
372
  const createMakeSendServiceWorkerTrackingData = ({
307
373
  readFromIndexedDb,
@@ -313,7 +379,7 @@ const createMakeSendServiceWorkerTrackingData = ({
313
379
  * @async
314
380
  * @function
315
381
  * @param {Object} options
316
- * @param {Object} options.xdm
382
+ * @param {XdmTrackingContext} options.xdm
317
383
  * @param {string} [options.actionLabel]
318
384
  * @param {number} [options.applicationLaunches=0]
319
385
  *
@@ -332,6 +398,7 @@ const createMakeSendServiceWorkerTrackingData = ({
332
398
  };
333
399
  }
334
400
 
401
+ /** @type {{ name: keyof PushServiceWorkerConfig, errorField: string }[]} */
335
402
  const requiredFields = [
336
403
  { name: "browser", errorField: "Browser" },
337
404
  { name: "ecid", errorField: "ECID" },
@@ -364,19 +431,24 @@ const createMakeSendServiceWorkerTrackingData = ({
364
431
 
365
432
  const url = `https://${edgeDomain}/${edgeBasePath}/v1/interact?configId=${datastreamId}&requestId=${uuidv4()}`;
366
433
 
434
+ // The requiredFields loop above guarantees these are defined strings.
435
+ const validEcid = /** @type {string} */ (ecid);
436
+ const validBrowser = /** @type {string} */ (browser);
437
+ const validDatasetId = /** @type {string} */ (datasetId);
438
+
367
439
  /** @type {TrackingDataPayload} */
368
440
  const payload = {
369
441
  events: [
370
442
  {
371
443
  xdm: {
372
444
  identityMap: {
373
- ECID: [{ id: ecid }],
445
+ ECID: [{ id: validEcid }],
374
446
  },
375
447
  timestamp: new Date().toISOString(),
376
448
  pushNotificationTracking: {
377
449
  ...customActionData,
378
450
  pushProviderMessageID: uuidv4(),
379
- pushProvider: browser.toLowerCase(),
451
+ pushProvider: validBrowser.toLowerCase(),
380
452
  },
381
453
  application: {
382
454
  launches: {
@@ -403,7 +475,7 @@ const createMakeSendServiceWorkerTrackingData = ({
403
475
  },
404
476
  meta: {
405
477
  collect: {
406
- datasetId,
478
+ datasetId: validDatasetId,
407
479
  },
408
480
  },
409
481
  },
@@ -541,6 +613,7 @@ const createEventListeners = ({ platform, sw }) => {
541
613
  event,
542
614
  sw,
543
615
  logger: platform.logger,
616
+ readFromIndexedDb,
544
617
  });
545
618
  },
546
619
  /**
@@ -10,4 +10,4 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- const e=e=>["DEEPLINK","WEBURL"].includes(e);const t="config";var n=async e=>{try{const e=await(n="alloyPushNotifications",o=1,r=e=>{e.objectStoreNames.contains(t)||e.createObjectStore(t,{keyPath:"id"})},new Promise((e,t)=>{const a=indexedDB.open(n,o);a.onerror=()=>t(a.error),a.onsuccess=()=>e(a.result),a.onupgradeneeded=e=>{const t=e.target.result;r&&r(t)}})),a=await((e,t,n)=>new Promise((o,r)=>{const a=e.transaction([t],"readonly").objectStore(t).get(n);a.onerror=()=>r(a.error),a.onsuccess=()=>o(a.result)}))(e,t,"alloyConfig");return e.close(),a}catch(t){e.error("Failed to read data from IndexedDB",{error:t})}var n,o,r};const o=[];for(let e=0;e<256;++e)o.push((e+256).toString(16).slice(1));const r=new Uint8Array(16);function a(e,t,n){return t||e||!crypto.randomUUID?function(e,t,n){e=e||{};const a=e.random??e.rng?.()??crypto.getRandomValues(r);if(a.length<16)throw new Error("Random bytes length must be >= 16");if(a[6]=15&a[6]|64,a[8]=63&a[8]|128,t){if((n=n||0)<0||n+16>t.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`);for(let e=0;e<16;++e)t[n+e]=a[e];return t}return function(e,t=0){return(o[e[t+0]]+o[e[t+1]]+o[e[t+2]]+o[e[t+3]]+"-"+o[e[t+4]]+o[e[t+5]]+"-"+o[e[t+6]]+o[e[t+7]]+"-"+o[e[t+8]]+o[e[t+9]]+"-"+o[e[t+10]]+o[e[t+11]]+o[e[t+12]]+o[e[t+13]]+o[e[t+14]]+o[e[t+15]]).toLowerCase()}(a)}(e,t,n):crypto.randomUUID()}const i=self,s={namespace:"[alloy][pushNotificationWorker]",info:(...e)=>console.log(s.namespace,...e),error:(...e)=>console.error(s.namespace,...e)},c=(({platform:t,sw:o})=>{const r=(({readFromIndexedDb:e,uuidv4:t,logger:n,fetch:o})=>async({xdm:r,actionLabel:a,applicationLaunches:i=0})=>{const s=await e(n),{browser:c,ecid:l,edgeDomain:d,edgeBasePath:u,datastreamId:g,datasetId:m}=s||{};let f={};a&&(f={customAction:{actionID:a}});const p=[{name:"browser",errorField:"Browser"},{name:"ecid",errorField:"ECID"},{name:"edgeDomain",errorField:"Edge domain"},{name:"edgeBasePath",errorField:"Edge base path"},{name:"datastreamId",errorField:"Datastream ID"},{name:"datasetId",errorField:"Dataset ID"}];try{for(const e of p)if(!s[e.name])throw new Error(`Cannot send tracking call. ${e.errorField} is missing.`);const e=`https://${d}/${u}/v1/interact?configId=${g}&requestId=${t()}`,h={events:[{xdm:{identityMap:{ECID:[{id:l}]},timestamp:(new Date).toISOString(),pushNotificationTracking:{...f,pushProviderMessageID:t(),pushProvider:c.toLowerCase()},application:{launches:{value:i}},eventType:a?"pushTracking.customAction":"pushTracking.applicationOpened",_experience:{...r._experience,customerJourneyManagement:{...r._experience.customerJourneyManagement,pushChannelContext:{platform:"web"},messageProfile:{channel:{_id:"https://ns.adobe.com/xdm/channels/push"}}}}},meta:{collect:{datasetId:m}}}]},w=await o(e,{method:"POST",headers:{"content-type":"text/plain; charset=UTF-8"},body:JSON.stringify(h)});return!!w.ok||(n.error("Tracking call failed: ",w.status,w.statusText),!1)}catch(e){return n.error("Error sending tracking call:",e),!1}})({readFromIndexedDb:n,uuidv4:a,logger:t.logger,fetch:t.fetch}),i=(({makeSendServiceWorkerTrackingData:t,sw:n,logger:o})=>({event:r})=>{r.notification.close();const a=r.notification.data;let i=null,s=null;if(r.action){const t=parseInt(r.action.replace("action_",""),10);if(a?.actions?.buttons[t]){const n=a.actions.buttons[t];s=n.label,e(n.type)&&n.uri&&(i=n.uri)}}else e(a?.interaction?.type)&&a?.interaction?.uri&&(i=a.interaction.uri);t({xdm:a._xdm.mixins,actionLabel:s,applicationLaunches:1}).catch(e=>{o.error("Failed to send tracking call:",e)}),i&&r.waitUntil(n.clients.matchAll({type:"window"}).then(e=>{for(const t of e)if(t.url===i&&"focus"in t)return t.focus();if(n.clients.openWindow)return n.clients.openWindow(i)}))})({makeSendServiceWorkerTrackingData:r,sw:o,logger:t.logger});return{pushNotifications:{onPush:e=>(async({sw:e,event:t,logger:n})=>{if(!t.data)return;let o;try{o=t.data.json()}catch(e){return void n.error("Error decoding notification JSON data:",e)}const r=o.web;if(!r?.title)return;const a={data:r,actions:r.actions?.buttons?.map((e,t)=>({action:`action_${t}`,title:e.label}))??[]};return null!=r.body&&(a.body=r.body),null!=r.media&&(a.icon=r.media,a.image=r.media),e.registration.showNotification(r.title,a)})({event:e,sw:o,logger:t.logger}),onNotificationClick(e){i({event:e})},async onNotificationClose(e){const n=e.notification.data;try{await r({xdm:n._xdm.mixins,actionLabel:"Dismiss"})}catch(e){t.logger.error("Failed to send tracking call:",e)}}}}})({sw:i,platform:{logger:s,fetch:fetch}});i.addEventListener("install",()=>{i.skipWaiting()}),i.addEventListener("activate",e=>{e.waitUntil(i.clients.claim())}),i.addEventListener("push",e=>c.pushNotifications.onPush(e)),i.addEventListener("notificationclick",e=>c.pushNotifications.onNotificationClick(e)),i.addEventListener("notificationclose",e=>{c.pushNotifications.onNotificationClose(e)});
13
+ var e=async({sw:e,event:t,logger:n,readFromIndexedDb:o})=>{if(!t.data)return;let r;try{r=t.data.json()}catch(e){return void n.error("Error decoding notification JSON data:",e)}const a=r.web;if(!a?.title)return;const i=await(async({webData:e,readFromIndexedDb:t,logger:n})=>{const{identity:o}=e;if(!o||"ECID"!==o.namespace?.toUpperCase())return!0;let r;try{r=await t(n)}catch(e){const t=e instanceof Error?e.message:String(e);return n.error(`Unable to read the stored ECID for this browser. ${t}`),!0}const a=r?.ecid;return o.id===a||(n.info("Suppressing push notification: payload ECID does not match the ECID stored for this browser."),!1)})({webData:a,readFromIndexedDb:o,logger:n});if(!i)return;const s={data:a,actions:a.actions?.buttons?.map((e,t)=>({action:`action_${t}`,title:e.label}))??[]};return null!=a.body&&(s.body=a.body),null!=a.media&&(s.icon=a.media,s.image=a.media),e.registration.showNotification(a.title,s)};const t=e=>["DEEPLINK","WEBURL"].includes(e);const n="config";var o=async e=>{try{const e=await(t="alloyPushNotifications",o=1,r=e=>{e.objectStoreNames.contains(n)||e.createObjectStore(n,{keyPath:"id"})},new Promise((e,n)=>{const a=indexedDB.open(t,o);a.onerror=()=>n(a.error),a.onsuccess=()=>e(a.result),a.onupgradeneeded=e=>{const t=e.target.result;r&&r(t)}})),a=await((e,t,n)=>new Promise((o,r)=>{const a=e.transaction([t],"readonly").objectStore(t).get(n);a.onerror=()=>r(a.error),a.onsuccess=()=>o(a.result)}))(e,n,"alloyConfig");return e.close(),a}catch(t){throw e.error("Failed to read data from IndexedDB",{error:t}),t}var t,o,r};const r=[];for(let e=0;e<256;++e)r.push((e+256).toString(16).slice(1));const a=new Uint8Array(16);function i(e,t,n){return t||e||!crypto.randomUUID?function(e,t,n){e=e||{};const o=e.random??e.rng?.()??crypto.getRandomValues(a);if(o.length<16)throw new Error("Random bytes length must be >= 16");if(o[6]=15&o[6]|64,o[8]=63&o[8]|128,t){if((n=n||0)<0||n+16>t.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`);for(let e=0;e<16;++e)t[n+e]=o[e];return t}return function(e,t=0){return(r[e[t+0]]+r[e[t+1]]+r[e[t+2]]+r[e[t+3]]+"-"+r[e[t+4]]+r[e[t+5]]+"-"+r[e[t+6]]+r[e[t+7]]+"-"+r[e[t+8]]+r[e[t+9]]+"-"+r[e[t+10]]+r[e[t+11]]+r[e[t+12]]+r[e[t+13]]+r[e[t+14]]+r[e[t+15]]).toLowerCase()}(o)}(e,t,n):crypto.randomUUID()}const s=self,c={namespace:"[alloy][pushNotificationWorker]",info:(...e)=>console.log(c.namespace,...e),error:(...e)=>console.error(c.namespace,...e)},d=(({platform:n,sw:r})=>{const a=(({readFromIndexedDb:e,uuidv4:t,logger:n,fetch:o})=>async({xdm:r,actionLabel:a,applicationLaunches:i=0})=>{const s=await e(n),{browser:c,ecid:d,edgeDomain:l,edgeBasePath:u,datastreamId:g,datasetId:m}=s||{};let f={};a&&(f={customAction:{actionID:a}});const p=[{name:"browser",errorField:"Browser"},{name:"ecid",errorField:"ECID"},{name:"edgeDomain",errorField:"Edge domain"},{name:"edgeBasePath",errorField:"Edge base path"},{name:"datastreamId",errorField:"Datastream ID"},{name:"datasetId",errorField:"Dataset ID"}];try{for(const e of p)if(!s[e.name])throw new Error(`Cannot send tracking call. ${e.errorField} is missing.`);const e=`https://${l}/${u}/v1/interact?configId=${g}&requestId=${t()}`,h=c,w=m,b={events:[{xdm:{identityMap:{ECID:[{id:d}]},timestamp:(new Date).toISOString(),pushNotificationTracking:{...f,pushProviderMessageID:t(),pushProvider:h.toLowerCase()},application:{launches:{value:i}},eventType:a?"pushTracking.customAction":"pushTracking.applicationOpened",_experience:{...r._experience,customerJourneyManagement:{...r._experience.customerJourneyManagement,pushChannelContext:{platform:"web"},messageProfile:{channel:{_id:"https://ns.adobe.com/xdm/channels/push"}}}}},meta:{collect:{datasetId:w}}}]},y=await o(e,{method:"POST",headers:{"content-type":"text/plain; charset=UTF-8"},body:JSON.stringify(b)});return!!y.ok||(n.error("Tracking call failed: ",y.status,y.statusText),!1)}catch(e){return n.error("Error sending tracking call:",e),!1}})({readFromIndexedDb:o,uuidv4:i,logger:n.logger,fetch:n.fetch}),s=(({makeSendServiceWorkerTrackingData:e,sw:n,logger:o})=>({event:r})=>{r.notification.close();const a=r.notification.data;let i=null,s=null;if(r.action){const e=parseInt(r.action.replace("action_",""),10);if(a?.actions?.buttons[e]){const n=a.actions.buttons[e];s=n.label,t(n.type)&&n.uri&&(i=n.uri)}}else t(a?.interaction?.type)&&a?.interaction?.uri&&(i=a.interaction.uri);e({xdm:a._xdm.mixins,actionLabel:s,applicationLaunches:1}).catch(e=>{o.error("Failed to send tracking call:",e)}),i&&r.waitUntil(n.clients.matchAll({type:"window"}).then(e=>{for(const t of e)if(t.url===i&&"focus"in t)return t.focus();if(n.clients.openWindow)return n.clients.openWindow(i)}))})({makeSendServiceWorkerTrackingData:a,sw:r,logger:n.logger});return{pushNotifications:{onPush:t=>e({event:t,sw:r,logger:n.logger,readFromIndexedDb:o}),onNotificationClick(e){s({event:e})},async onNotificationClose(e){const t=e.notification.data;try{await a({xdm:t._xdm.mixins,actionLabel:"Dismiss"})}catch(e){n.logger.error("Failed to send tracking call:",e)}}}}})({sw:s,platform:{logger:c,fetch:fetch}});s.addEventListener("install",()=>{s.skipWaiting()}),s.addEventListener("activate",e=>{e.waitUntil(s.clients.claim())}),s.addEventListener("push",e=>d.pushNotifications.onPush(e)),s.addEventListener("notificationclick",e=>d.pushNotifications.onNotificationClick(e)),s.addEventListener("notificationclose",e=>{d.pushNotifications.onNotificationClose(e)});
@@ -1,4 +1,4 @@
1
- export const downloadLinkQualifier: any;
1
+ export const downloadLinkQualifier: import("@adobe/alloy-core/utils/validation/types").AnyValidator;
2
2
  export default validators;
3
3
  export const DEFAULT_DOWNLOAD_QUALIFIER: "\\.(exe|zip|wav|mp3|mov|mpg|avi|wmv|pdf|doc|docx|xls|xlsx|ppt|pptx)$";
4
- declare const validators: Function;
4
+ declare const validators: import("@adobe/alloy-core/utils/validation/types").ObjectValidator;
@@ -1,2 +1,2 @@
1
- declare const _default: Function;
1
+ declare const _default: import("@adobe/alloy-core/utils/validation/types").ObjectValidator;
2
2
  export default _default;
@@ -12,5 +12,5 @@ declare function createContext({ config, logger }: {
12
12
  };
13
13
  declare namespace createContext {
14
14
  let namespace: string;
15
- let configValidators: Function;
15
+ let configValidators: import("@adobe/alloy-core/utils/validation/types.js").ObjectValidator;
16
16
  }
@@ -33,5 +33,5 @@ declare function createPersonalization({ config, logger, eventManager, consent }
33
33
  };
34
34
  declare namespace createPersonalization {
35
35
  let namespace: string;
36
- let configValidators: Function;
36
+ let configValidators: import("@adobe/alloy-core/utils/validation/types.js").ObjectValidator;
37
37
  }
@@ -1,3 +1,4 @@
1
- declare function _default(logger: ServiceWorkerLogger): Promise<Object | undefined>;
1
+ declare function _default(logger: ServiceWorkerLogger): Promise<PushServiceWorkerConfig | undefined>;
2
2
  export default _default;
3
3
  import type { ServiceWorkerLogger } from '../types.js';
4
+ import type { PushServiceWorkerConfig } from '../types.js';
@@ -1,8 +1,9 @@
1
1
  /**
2
- * @param {Object} data
2
+ * @param {Partial<PushServiceWorkerConfig>} data
3
3
  * @param {Logger} logger
4
4
  *
5
5
  * @returns {Promise<boolean>} Whether the data was successfully saved.
6
6
  */
7
- export default function saveToIndexedDB(data: Object, logger: Logger): Promise<boolean>;
7
+ export default function saveToIndexedDB(data: Partial<PushServiceWorkerConfig>, logger: Logger): Promise<boolean>;
8
+ import type { PushServiceWorkerConfig } from '../types.js';
8
9
  import type { Logger } from '@adobe/alloy-core/core/types.js';
@@ -1,7 +1,9 @@
1
- declare function _default({ sw, event, logger }: {
1
+ declare function _default({ sw, event, logger, readFromIndexedDb }: {
2
2
  sw: ServiceWorkerGlobalScope;
3
3
  event: PushEvent;
4
4
  logger: ServiceWorkerLogger;
5
+ readFromIndexedDb: (logger: ServiceWorkerLogger) => Promise<PushServiceWorkerConfig | undefined>;
5
6
  }): Promise<void>;
6
7
  export default _default;
7
8
  import type { ServiceWorkerLogger } from '../types.js';
9
+ import type { PushServiceWorkerConfig } from '../types.js';
@@ -40,7 +40,7 @@ declare function createPushNotifications({ eventManager, config, logger, consent
40
40
  };
41
41
  declare namespace createPushNotifications {
42
42
  let namespace: string;
43
- let configValidators: Function;
43
+ let configValidators: import("@adobe/alloy-core/utils/validation/types.js").ObjectValidator;
44
44
  }
45
45
  import type { EventManager } from '@adobe/alloy-core/core/types.js';
46
46
  import type { Logger } from '@adobe/alloy-core/core/types.js';
@@ -10,9 +10,13 @@ declare function _default({ config: { vapidPublicKey, appId }, storage, logger,
10
10
  sendEdgeNetworkRequest: EdgeRequestExecutor;
11
11
  consent: ConsentManager;
12
12
  window: Window;
13
+ getPushSubscriptionDetails?: (({ vapidPublicKey, window }: {
14
+ vapidPublicKey: string;
15
+ window: Window;
16
+ }) => Promise<import("../types.js").PushSubscription>) | undefined;
13
17
  }): Promise<void>;
14
18
  export default _default;
15
- import type { Storage } from '@adobe/alloy-core/utils/types.js';
19
+ import type { Storage } from '@adobe/alloy-core/services';
16
20
  import type { Logger } from '@adobe/alloy-core/core/types.js';
17
21
  import type { EventManager } from '@adobe/alloy-core/core/types.js';
18
22
  import type { IdentityManager } from '@adobe/alloy-core/core/identity/types.js';
@@ -1,11 +1,13 @@
1
1
  export function createMakeSendServiceWorkerTrackingData({ readFromIndexedDb, uuidv4, logger, fetch, }: {
2
- readFromIndexedDb: (logger: ServiceWorkerLogger) => Promise<Object>;
2
+ readFromIndexedDb: (logger: ServiceWorkerLogger) => Promise<PushServiceWorkerConfig>;
3
3
  uuidv4: () => string;
4
4
  logger: ServiceWorkerLogger;
5
5
  fetch: (url: string, options: object) => Promise<Response>;
6
6
  }): (options: {
7
- xdm: Object;
7
+ xdm: XdmTrackingContext;
8
8
  actionLabel?: string;
9
9
  applicationLaunches?: number;
10
10
  }) => Promise<boolean>;
11
11
  import type { ServiceWorkerLogger } from '../types.js';
12
+ import type { PushServiceWorkerConfig } from '../types.js';
13
+ import type { XdmTrackingContext } from '../types.js';
@@ -39,6 +39,9 @@
39
39
  * @property {string} web.title
40
40
  * @property {string} web.body
41
41
  * @property {string|null} web.media
42
+ * @property {Object} [web.identity]
43
+ * @property {string} [web.identity.id]
44
+ * @property {string} [web.identity.namespace]
42
45
  * @property {Object} web.interaction
43
46
  * @property {string} web.interaction.type
44
47
  * @property {string|null} web.interaction.uri
@@ -81,6 +84,17 @@
81
84
  * @property {(...args: any[]) => void} info
82
85
  * @property {(...args: any[]) => void} error
83
86
  */
87
+ /**
88
+ * @typedef {Object} PushServiceWorkerConfig
89
+ * @property {string} [ecid]
90
+ * @property {string} [browser]
91
+ * @property {string} [edgeDomain]
92
+ * @property {string} [edgeBasePath]
93
+ * @property {string} [datastreamId]
94
+ * @property {string} [datasetId]
95
+ * @property {string} [id]
96
+ * @property {number} [timestamp]
97
+ */
84
98
  export const Types: {};
85
99
  export type PushSubscription = {
86
100
  /**
@@ -131,6 +145,10 @@ export type PushNotificationData = {
131
145
  title: string;
132
146
  body: string;
133
147
  media: string | null;
148
+ identity?: {
149
+ id?: string | undefined;
150
+ namespace?: string | undefined;
151
+ } | undefined;
134
152
  interaction: {
135
153
  type: string;
136
154
  uri: string | null;
@@ -187,3 +205,13 @@ export type ServiceWorkerLogger = {
187
205
  info: (...args: any[]) => void;
188
206
  error: (...args: any[]) => void;
189
207
  };
208
+ export type PushServiceWorkerConfig = {
209
+ ecid?: string | undefined;
210
+ browser?: string | undefined;
211
+ edgeDomain?: string | undefined;
212
+ edgeBasePath?: string | undefined;
213
+ datastreamId?: string | undefined;
214
+ datasetId?: string | undefined;
215
+ id?: string | undefined;
216
+ timestamp?: number | undefined;
217
+ };
@@ -1,2 +1,2 @@
1
- declare const _default: Function;
1
+ declare const _default: import("../../utils/validation/types.js").ObjectValidator;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: Function;
1
+ declare const _default: import("../../utils/validation/types.js").ObjectValidator;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: any;
1
+ declare const _default: import("../../utils/validation/types.js").AnyValidator;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
1
  export default configValidators;
2
- declare const configValidators: Function;
2
+ declare const configValidators: import("../../utils/validation/types.js").ObjectValidator;
@@ -44,5 +44,5 @@ declare function createRulesEngine({ config, eventManager, consent, getBrowser,
44
44
  };
45
45
  declare namespace createRulesEngine {
46
46
  let namespace: string;
47
- let configValidators: Function;
47
+ let configValidators: import("../../utils/validation/types.js").ObjectValidator;
48
48
  }
@@ -1,2 +1,2 @@
1
- declare const _default: Function;
1
+ declare const _default: import("../../utils/validation/types.js").ObjectValidator;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare function _default(): any;
1
+ declare function _default(): import("../../utils/validation/types.js").ObjectValidator;
2
2
  export default _default;
@@ -1,4 +1,4 @@
1
- export function base64ToBytes(base64String: string): Uint8Array;
1
+ export function base64ToBytes(base64String: string): Uint8Array<ArrayBuffer>;
2
2
  export function bytesToBase64(bytes: Uint8Array, options?: {
3
3
  urlSafe?: boolean | undefined;
4
4
  }): string;
@@ -1,2 +1,2 @@
1
- declare const _default: Function;
1
+ declare const _default: import("./validation/types.js").ObjectValidator;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: Function;
1
+ declare const _default: import("./validation/types.js").MapOfValuesValidator;
2
2
  export default _default;
@@ -1,12 +1,24 @@
1
- declare function boundAnyOf(validators: any, message: any): Function;
2
- declare function boundAnything(): any;
3
- declare function boundArrayOf(elementValidator: any): Function;
4
- declare function boundBoolean(): Function;
5
- declare function boundCallback(): Function;
6
- declare function boundLiteral(literalValue: any): Function;
7
- declare function boundNumber(): Function;
8
- declare function boundMapOfValues(valuesValidator: any): Function;
9
- declare function boundObjectOf(schema: any): Function;
10
- declare function boundString(): Function;
11
- declare function boundEnumOf(...values: any[]): Function;
1
+ declare const boundAnyOf: (validators: ValidatorFn[], message?: string | undefined) => AnyValidator;
2
+ declare const boundAnything: () => AnyValidator;
3
+ declare const boundArrayOf: (elementValidator: ValidatorFn) => ArrayValidator;
4
+ declare const boundBoolean: () => AnyValidator;
5
+ declare const boundCallback: () => AnyValidator;
6
+ declare const boundLiteral: (literalValue: any) => AnyValidator;
7
+ declare const boundNumber: () => NumberValidator;
8
+ declare const boundMapOfValues: (valuesValidator: ValidatorFn) => MapOfValuesValidator;
9
+ declare const boundObjectOf: (schema: ObjectValidatorSchema) => ObjectValidator;
10
+ declare const boundString: () => StringValidator;
11
+ /**
12
+ * @param {...any} values
13
+ * @returns {AnyValidator}
14
+ */
15
+ declare function boundEnumOf(...values: any[]): AnyValidator;
16
+ import type { ValidatorFn } from './types.js';
17
+ import type { AnyValidator } from './types.js';
18
+ import type { ArrayValidator } from './types.js';
19
+ import type { NumberValidator } from './types.js';
20
+ import type { MapOfValuesValidator } from './types.js';
21
+ import type { ObjectValidatorSchema } from './types.js';
22
+ import type { ObjectValidator } from './types.js';
23
+ import type { StringValidator } from './types.js';
12
24
  export { boundAnyOf as anyOf, boundAnything as anything, boundArrayOf as arrayOf, boundBoolean as boolean, boundCallback as callback, boundLiteral as literal, boundNumber as number, boundMapOfValues as mapOfValues, boundObjectOf as objectOf, boundString as string, boundEnumOf as enumOf };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * A validator is a function of a value and an optional path that returns the
3
+ * computed value if valid, or throws if invalid.
4
+ * @typedef {(value: any, path?: string) => any} ValidatorFn
5
+ */
6
+ /**
7
+ * The methods available on every validator, regardless of data type.
8
+ * @typedef {ValidatorFn & {
9
+ * required: () => AnyValidator,
10
+ * default: (defaultValue: any) => AnyValidator,
11
+ * deprecated: (message: string) => AnyValidator,
12
+ * }} AnyValidator
13
+ */
14
+ /**
15
+ * @typedef {AnyValidator & {
16
+ * nonEmpty: () => ArrayValidator,
17
+ * uniqueItems: () => ArrayValidator,
18
+ * required: () => ArrayValidator,
19
+ * default: (defaultValue: any[]) => ArrayValidator,
20
+ * deprecated: (message: string) => ArrayValidator,
21
+ * }} ArrayValidator
22
+ */
23
+ /**
24
+ * @typedef {AnyValidator & {
25
+ * minimum: (minValue: number) => NumberValidator,
26
+ * maximum: (maxValue: number) => NumberValidator,
27
+ * integer: () => NumberValidator,
28
+ * unique: () => NumberValidator,
29
+ * required: () => NumberValidator,
30
+ * default: (defaultValue: number) => NumberValidator,
31
+ * deprecated: (message: string) => NumberValidator,
32
+ * }} NumberValidator
33
+ */
34
+ /**
35
+ * @typedef {AnyValidator & {
36
+ * nonEmpty: () => MapOfValuesValidator,
37
+ * required: () => MapOfValuesValidator,
38
+ * default: (defaultValue: object) => MapOfValuesValidator,
39
+ * deprecated: (message: string) => MapOfValuesValidator,
40
+ * }} MapOfValuesValidator
41
+ */
42
+ /**
43
+ * objectOf's schema is normally a plain map of field name to validator, but
44
+ * it is also idiomatically called with a bare validator (e.g. `objectOf(anything())`)
45
+ * to mean "an object, with no per-field validation."
46
+ * @typedef {Record<string, ValidatorFn> | ValidatorFn} ObjectValidatorSchema
47
+ */
48
+ /**
49
+ * @typedef {AnyValidator & {
50
+ * noUnknownFields: () => ObjectValidator,
51
+ * nonEmpty: () => ObjectValidator,
52
+ * concat: (otherObjectOfValidator: ObjectValidator) => ObjectValidator,
53
+ * renamed: (oldField: string, oldSchema: ValidatorFn, newField: string) => ObjectValidator,
54
+ * schema: ObjectValidatorSchema,
55
+ * required: () => ObjectValidator,
56
+ * default: (defaultValue: object) => ObjectValidator,
57
+ * deprecated: (message: string) => ObjectValidator,
58
+ * }} ObjectValidator
59
+ */
60
+ /**
61
+ * @typedef {AnyValidator & {
62
+ * regexp: () => StringValidator,
63
+ * domain: () => StringValidator,
64
+ * nonEmpty: () => StringValidator,
65
+ * unique: () => StringValidator,
66
+ * matches: (pattern: RegExp) => StringValidator,
67
+ * required: () => StringValidator,
68
+ * default: (defaultValue: string) => StringValidator,
69
+ * deprecated: (message: string) => StringValidator,
70
+ * }} StringValidator
71
+ */
72
+ export const Types: {};
73
+ /**
74
+ * A validator is a function of a value and an optional path that returns the
75
+ * computed value if valid, or throws if invalid.
76
+ */
77
+ export type ValidatorFn = (value: any, path?: string) => any;
78
+ /**
79
+ * The methods available on every validator, regardless of data type.
80
+ */
81
+ export type AnyValidator = ValidatorFn & {
82
+ required: () => AnyValidator;
83
+ default: (defaultValue: any) => AnyValidator;
84
+ deprecated: (message: string) => AnyValidator;
85
+ };
86
+ export type ArrayValidator = AnyValidator & {
87
+ nonEmpty: () => ArrayValidator;
88
+ uniqueItems: () => ArrayValidator;
89
+ required: () => ArrayValidator;
90
+ default: (defaultValue: any[]) => ArrayValidator;
91
+ deprecated: (message: string) => ArrayValidator;
92
+ };
93
+ export type NumberValidator = AnyValidator & {
94
+ minimum: (minValue: number) => NumberValidator;
95
+ maximum: (maxValue: number) => NumberValidator;
96
+ integer: () => NumberValidator;
97
+ unique: () => NumberValidator;
98
+ required: () => NumberValidator;
99
+ default: (defaultValue: number) => NumberValidator;
100
+ deprecated: (message: string) => NumberValidator;
101
+ };
102
+ export type MapOfValuesValidator = AnyValidator & {
103
+ nonEmpty: () => MapOfValuesValidator;
104
+ required: () => MapOfValuesValidator;
105
+ default: (defaultValue: object) => MapOfValuesValidator;
106
+ deprecated: (message: string) => MapOfValuesValidator;
107
+ };
108
+ /**
109
+ * objectOf's schema is normally a plain map of field name to validator, but
110
+ * it is also idiomatically called with a bare validator (e.g. `objectOf(anything())`)
111
+ * to mean "an object, with no per-field validation."
112
+ */
113
+ export type ObjectValidatorSchema = Record<string, ValidatorFn> | ValidatorFn;
114
+ export type ObjectValidator = AnyValidator & {
115
+ noUnknownFields: () => ObjectValidator;
116
+ nonEmpty: () => ObjectValidator;
117
+ concat: (otherObjectOfValidator: ObjectValidator) => ObjectValidator;
118
+ renamed: (oldField: string, oldSchema: ValidatorFn, newField: string) => ObjectValidator;
119
+ schema: ObjectValidatorSchema;
120
+ required: () => ObjectValidator;
121
+ default: (defaultValue: object) => ObjectValidator;
122
+ deprecated: (message: string) => ObjectValidator;
123
+ };
124
+ export type StringValidator = AnyValidator & {
125
+ regexp: () => StringValidator;
126
+ domain: () => StringValidator;
127
+ nonEmpty: () => StringValidator;
128
+ unique: () => StringValidator;
129
+ matches: (pattern: RegExp) => StringValidator;
130
+ required: () => StringValidator;
131
+ default: (defaultValue: string) => StringValidator;
132
+ deprecated: (message: string) => StringValidator;
133
+ };
@@ -1,4 +1,5 @@
1
- export function chain(baseValidator: Function, newValidator: Function, additionalMethods: object): Function;
2
- export function nullSafeChain(baseValidator: Function, newValidator: Function, additionalMethods: object): Function;
3
- export function reverseNullSafeChainJoinErrors(baseValidator: Function, newValidator: Function, additionalMethods: Function): Function;
1
+ export function chain(baseValidator: ValidatorFn, newValidator: ValidatorFn, additionalMethods?: object): ValidatorFn;
2
+ export function nullSafeChain(baseValidator: ValidatorFn, newValidator: ValidatorFn, additionalMethods?: object): ValidatorFn;
3
+ export function reverseNullSafeChainJoinErrors(baseValidator: ValidatorFn, newValidator: ValidatorFn, additionalMethods?: object): ValidatorFn;
4
4
  export function assertValid(isValid: boolean, value: any, path: string, message: string): void;
5
+ import type { ValidatorFn } from './types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/alloy",
3
- "version": "2.34.2-beta.3",
3
+ "version": "2.35.0-beta.4",
4
4
  "description": "Adobe Experience Platform Web SDK",
5
5
  "type": "module",
6
6
  "repository": {
@@ -69,7 +69,7 @@
69
69
  "commander": "^14.0.2",
70
70
  "rollup": "^4.60.3",
71
71
  "rollup-plugin-license": "^3.7.1",
72
- "@adobe/alloy-core": "^1.2.2-beta.0"
72
+ "@adobe/alloy-core": "^1.2.2-beta.1"
73
73
  },
74
74
  "devDependencies": {
75
75
  "glob": "^13.0.6",