@adobe/alloy 2.34.2-beta.1 → 2.34.2-beta.3

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.
@@ -1,5 +1,5 @@
1
1
  export function is(element: any, tagName: any): boolean;
2
2
  export function getInlineScripts(fragment: any): any[];
3
- export function getRemoteScriptsUrls(fragment: any): any[];
3
+ export function getRemoteScripts(fragment: any): any[];
4
4
  export function executeInlineScripts(parent: any, scripts: any): void;
5
- export function executeRemoteScripts(urls: any): Promise<any[]>;
5
+ export function executeRemoteScripts(scripts: any): Promise<any[]>;
@@ -2,7 +2,7 @@
2
2
  * @param {Object} data
3
3
  * @param {Logger} logger
4
4
  *
5
- * @returns {Promise<void>}
5
+ * @returns {Promise<boolean>} Whether the data was successfully saved.
6
6
  */
7
- export default function saveToIndexedDB(data: Object, logger: Logger): Promise<void>;
7
+ export default function saveToIndexedDB(data: Object, logger: Logger): Promise<boolean>;
8
8
  import type { Logger } from '@adobe/alloy-core/core/types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/alloy",
3
- "version": "2.34.2-beta.1",
3
+ "version": "2.34.2-beta.3",
4
4
  "description": "Adobe Experience Platform Web SDK",
5
5
  "type": "module",
6
6
  "repository": {
@@ -18,7 +18,7 @@ import {
18
18
  executeInlineScripts,
19
19
  executeRemoteScripts,
20
20
  getInlineScripts,
21
- getRemoteScriptsUrls,
21
+ getRemoteScripts,
22
22
  } from "./scripts.js";
23
23
 
24
24
  export default (container, html, decorateProposition) => {
@@ -26,7 +26,7 @@ export default (container, html, decorateProposition) => {
26
26
  addNonceToInlineStyleElements(fragment);
27
27
  const elements = getChildNodes(fragment);
28
28
  const scripts = getInlineScripts(fragment);
29
- const scriptsUrls = getRemoteScriptsUrls(fragment);
29
+ const remoteScripts = getRemoteScripts(fragment);
30
30
 
31
31
  loadImages(fragment);
32
32
 
@@ -38,5 +38,5 @@ export default (container, html, decorateProposition) => {
38
38
 
39
39
  executeInlineScripts(container, scripts);
40
40
 
41
- return executeRemoteScripts(scriptsUrls);
41
+ return executeRemoteScripts(remoteScripts);
42
42
  };
@@ -15,7 +15,7 @@ import { loadImages } from "./images.js";
15
15
  import addNonceToInlineStyleElements from "./addNonceToInlineStyleElements.js";
16
16
  import {
17
17
  getInlineScripts,
18
- getRemoteScriptsUrls,
18
+ getRemoteScripts,
19
19
  executeInlineScripts,
20
20
  executeRemoteScripts,
21
21
  } from "./scripts.js";
@@ -25,7 +25,7 @@ export default (container, html, decorateProposition) => {
25
25
  addNonceToInlineStyleElements(fragment);
26
26
  const elements = getChildNodes(fragment);
27
27
  const scripts = getInlineScripts(fragment);
28
- const scriptsUrls = getRemoteScriptsUrls(fragment);
28
+ const remoteScripts = getRemoteScripts(fragment);
29
29
 
30
30
  loadImages(fragment);
31
31
 
@@ -39,5 +39,5 @@ export default (container, html, decorateProposition) => {
39
39
 
40
40
  executeInlineScripts(container, scripts);
41
41
 
42
- return executeRemoteScripts(scriptsUrls);
42
+ return executeRemoteScripts(remoteScripts);
43
43
  };
@@ -17,7 +17,7 @@ import {
17
17
  executeInlineScripts,
18
18
  executeRemoteScripts,
19
19
  getInlineScripts,
20
- getRemoteScriptsUrls,
20
+ getRemoteScripts,
21
21
  } from "./scripts.js";
22
22
 
23
23
  export default (container, html, decorateProposition) => {
@@ -25,7 +25,7 @@ export default (container, html, decorateProposition) => {
25
25
  addNonceToInlineStyleElements(fragment);
26
26
  const elements = getChildNodes(fragment);
27
27
  const scripts = getInlineScripts(fragment);
28
- const scriptsUrls = getRemoteScriptsUrls(fragment);
28
+ const remoteScripts = getRemoteScripts(fragment);
29
29
 
30
30
  loadImages(fragment);
31
31
 
@@ -36,5 +36,5 @@ export default (container, html, decorateProposition) => {
36
36
 
37
37
  executeInlineScripts(container, scripts);
38
38
 
39
- return executeRemoteScripts(scriptsUrls);
39
+ return executeRemoteScripts(remoteScripts);
40
40
  };
@@ -23,7 +23,7 @@ import {
23
23
  executeInlineScripts,
24
24
  executeRemoteScripts,
25
25
  getInlineScripts,
26
- getRemoteScriptsUrls,
26
+ getRemoteScripts,
27
27
  } from "./scripts.js";
28
28
 
29
29
  export default (container, html, decorateProposition) => {
@@ -31,7 +31,7 @@ export default (container, html, decorateProposition) => {
31
31
  addNonceToInlineStyleElements(fragment);
32
32
  const elements = getChildNodes(fragment);
33
33
  const scripts = getInlineScripts(fragment);
34
- const scriptsUrls = getRemoteScriptsUrls(fragment);
34
+ const remoteScripts = getRemoteScripts(fragment);
35
35
  const { length } = elements;
36
36
  let i = length - 1;
37
37
 
@@ -56,5 +56,5 @@ export default (container, html, decorateProposition) => {
56
56
 
57
57
  executeInlineScripts(container, scripts);
58
58
 
59
- return executeRemoteScripts(scriptsUrls);
59
+ return executeRemoteScripts(remoteScripts);
60
60
  };
@@ -24,10 +24,24 @@ const getPromise = (url, script) => {
24
24
  };
25
25
  });
26
26
  };
27
- const loadScript = (url) => {
27
+ const loadScript = (source) => {
28
+ const url = getAttribute(source, SRC);
28
29
  const script = document.createElement("script");
29
- script.src = url;
30
+ // Preserve all author-supplied attributes (class, type, data-*, etc.) so
31
+ // consumers relying on them keep working.
32
+ const { attributes } = source;
33
+ for (let i = 0; i < attributes.length; i += 1) {
34
+ const { name, value } = attributes[i];
35
+ script.setAttribute(name, value);
36
+ }
37
+ // Override invariants last so they can't be clobbered by the source element.
38
+ const nonce = getNonce();
39
+ if (nonce) {
40
+ script.setAttribute("nonce", nonce);
41
+ }
30
42
  script.async = true;
43
+ // Assign load handlers after copying attributes so a copied inline
44
+ // onload/onerror attribute can't break load-completion tracking.
31
45
  const promise = getPromise(url, script);
32
46
  document.head.appendChild(script);
33
47
  return promise;
@@ -70,7 +84,7 @@ export const getInlineScripts = (fragment) => {
70
84
  return result;
71
85
  };
72
86
 
73
- export const getRemoteScriptsUrls = (fragment) => {
87
+ export const getRemoteScripts = (fragment) => {
74
88
  const scripts = selectNodes(SCRIPT, fragment);
75
89
  const result = [];
76
90
  const { length } = scripts;
@@ -78,17 +92,12 @@ export const getRemoteScriptsUrls = (fragment) => {
78
92
  for (let i = 0; i < length; i += 1) {
79
93
  const element = scripts[i];
80
94
 
95
+ // isRemoteScript already requires a non-empty src attribute.
81
96
  if (!isRemoteScript(element)) {
82
97
  continue;
83
98
  }
84
99
 
85
- const url = getAttribute(element, SRC);
86
-
87
- if (!url) {
88
- continue;
89
- }
90
-
91
- result.push(url);
100
+ result.push(element);
92
101
  }
93
102
 
94
103
  return result;
@@ -101,6 +110,6 @@ export const executeInlineScripts = (parent, scripts) => {
101
110
  });
102
111
  };
103
112
 
104
- export const executeRemoteScripts = (urls) => {
105
- return Promise.all(urls.map(loadScript));
113
+ export const executeRemoteScripts = (scripts) => {
114
+ return Promise.all(scripts.map(loadScript));
106
115
  };
@@ -24,7 +24,7 @@ import { DB_NAME, DB_VERSION, STORE_NAME, INDEX_KEY } from "./constants.js";
24
24
  * @param {Object} data
25
25
  * @param {Logger} logger
26
26
  *
27
- * @returns {Promise<void>}
27
+ * @returns {Promise<boolean>} Whether the data was successfully saved.
28
28
  */
29
29
  export default async function saveToIndexedDB(data, logger) {
30
30
  try {
@@ -58,7 +58,11 @@ export default async function saveToIndexedDB(data, logger) {
58
58
  "Successfully saved web SDK config to IndexedDB",
59
59
  updatedConfigData,
60
60
  );
61
+
62
+ return true;
61
63
  } catch (error) {
62
64
  logger.error("Failed to save config to IndexedDB", { error });
65
+
66
+ return false;
63
67
  }
64
68
  }
@@ -59,6 +59,14 @@ export default async ({
59
59
  await identity.awaitIdentity();
60
60
  const ecid = identity.getEcidFromCookie();
61
61
 
62
+ if (!ecid) {
63
+ logger.info(
64
+ "No ECID is available. Not sending push subscription details to the server.",
65
+ );
66
+
67
+ return;
68
+ }
69
+
62
70
  const pushSubscriptionDetails = await getPushSubscriptionDetails({
63
71
  vapidPublicKey,
64
72
  window,
@@ -71,7 +79,7 @@ export default async ({
71
79
  const cacheValue = `${ecid}${serializedPushSubscriptionDetails}`;
72
80
  const storedValue = await storage.getItem(SUBSCRIPTION_DETAILS);
73
81
 
74
- if (cacheValue === storedValue) {
82
+ if (storedValue && cacheValue === storedValue) {
75
83
  logger.info(
76
84
  "Subscription details have not changed. Not sending to the server.",
77
85
  );
@@ -79,8 +87,6 @@ export default async ({
79
87
  return;
80
88
  }
81
89
 
82
- storage.setItem(SUBSCRIPTION_DETAILS, cacheValue);
83
-
84
90
  const payload = await createSendPushSubscriptionPayload({
85
91
  eventManager,
86
92
  ecid,
@@ -95,5 +101,13 @@ export default async ({
95
101
  await consent.awaitConsent();
96
102
  await sendEdgeNetworkRequest({ request });
97
103
 
98
- await saveToIndexedDb({ ecid }, logger);
104
+ const savedToIndexedDb = await saveToIndexedDb({ ecid }, logger);
105
+
106
+ // Only cache the subscription details once the ECID has been persisted, so
107
+ // that a failed send or a failed IndexedDB write does not short-circuit the
108
+ // dedupe check on the next call. This lets a subsequent sendPushSubscription
109
+ // self-heal instead of getting stuck with a cached subscription but no ECID.
110
+ if (savedToIndexedDb) {
111
+ storage.setItem(SUBSCRIPTION_DETAILS, cacheValue);
112
+ }
99
113
  };