@adobe/alloy 2.36.0-beta.1 → 2.36.1-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.
@@ -1,4 +1,8 @@
1
- declare function _default({ fetch }: {
2
- fetch: any;
3
- }): (url: any, body: any, headers: any) => any;
1
+ declare function _default({ fetch, logger }: {
2
+ fetch: typeof window.fetch;
3
+ logger: {
4
+ info: (...args: any[]) => void;
5
+ };
6
+ }): NetworkService["sendFetchRequest"];
4
7
  export default _default;
8
+ import type { NetworkService } from "@adobe/alloy-core/services";
@@ -4,11 +4,12 @@ declare function _default({ logger, sendFetchRequest, sendBeaconRequest, isReque
4
4
  sendBeaconRequest: any;
5
5
  isRequestRetryable: any;
6
6
  getRequestRetryDelay: any;
7
- }): ({ requestId, url, payload, useSendBeacon, headers }: {
7
+ }): ({ requestId, url, payload, useSendBeacon, useKeepalive, headers, }: {
8
8
  requestId: any;
9
9
  url: any;
10
10
  payload: any;
11
11
  useSendBeacon: any;
12
+ useKeepalive: any;
12
13
  headers: any;
13
14
  }) => any;
14
15
  export default _default;
@@ -2,8 +2,24 @@ export type NetworkResponse = {
2
2
  statusCode: number;
3
3
  body: string;
4
4
  getHeader: (name: string) => (string | null);
5
+ /**
6
+ * `true` when the request was handed to `navigator.sendBeacon`. The browser
7
+ * gives no response for these, so `statusCode`, `body`, and `getHeader` are
8
+ * placeholders rather than values from the server.
9
+ */
10
+ sentWithBeacon?: boolean | undefined;
11
+ };
12
+ export type SendFetchRequestOptions = {
13
+ /**
14
+ * Send the request with `keepalive` so the
15
+ * browser finishes it even if the page unloads. Implementations fall back to
16
+ * a regular request if the browser refuses (for example, when in-flight
17
+ * keepalive data on the page would exceed 64 KiB). Ignored where there is no
18
+ * page to unload (Node).
19
+ */
20
+ keepalive?: boolean | undefined;
5
21
  };
6
- export type SendFetchRequest = (url: string, body: string) => Promise<NetworkResponse>;
22
+ export type SendFetchRequest = (url: string, body: string, headers?: Record<string, string>, options?: SendFetchRequestOptions) => Promise<NetworkResponse>;
7
23
  export type SendBeaconRequest = (url: string, body: string) => Promise<NetworkResponse>;
8
24
  export type NetworkService = {
9
25
  /**
@@ -6,6 +6,7 @@ declare function _default(options: {
6
6
  getUseSendBeacon: (arg0: {
7
7
  isIdentityEstablished: boolean;
8
8
  }) => boolean;
9
+ getUseKeepalive?: (() => boolean) | undefined;
9
10
  datastreamIdOverride?: string | undefined;
10
11
  edgeSubPath?: string | undefined;
11
12
  }): Request;
@@ -7,6 +7,7 @@
7
7
  * @property {function({isIdentityEstablished: boolean}): string} getAction
8
8
  * @property {function(): string|undefined} getDatastreamIdOverride
9
9
  * @property {Function} getUseSendBeacon
10
+ * @property {function(): boolean} getUseKeepalive
10
11
  * @property {function(): string|undefined} getEdgeSubPath
11
12
  * @property {Function} getUseIdThirdPartyDomain
12
13
  * @property {Function} setUseIdThirdPartyDomain
@@ -55,6 +56,7 @@ export type Request = {
55
56
  }) => string;
56
57
  getDatastreamIdOverride: () => string | undefined;
57
58
  getUseSendBeacon: Function;
59
+ getUseKeepalive: () => boolean;
58
60
  getEdgeSubPath: () => string | undefined;
59
61
  getUseIdThirdPartyDomain: Function;
60
62
  setUseIdThirdPartyDomain: Function;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/alloy",
3
- "version": "2.36.0-beta.1",
3
+ "version": "2.36.1-beta.0",
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.3.0-beta.1"
72
+ "@adobe/alloy-core": "^1.3.1-beta.0"
73
73
  },
74
74
  "devDependencies": {
75
75
  "glob": "^13.0.6",
@@ -86,7 +86,9 @@
86
86
  "release": "node scripts/release.mjs",
87
87
  "build:types": "tsc -p jsconfig.json --declaration --emitDeclarationOnly --outDir dist/types --checkJs false --noEmit false",
88
88
  "build": "pnpm run clean && rollup -c --environment BASE_CODE_MIN,STANDALONE,STANDALONE_MIN,SERVICE_WORKER,SERVICE_WORKER_MIN,UTILITY_EXPORTS,BUNDLESIZE && pnpm run build:types",
89
- "build:watch": "pnpm run clean && rollup -c --watch --environment BASE_CODE_MIN,STANDALONE,UTILITY_EXPORTS",
89
+ "build:watch": "rollup -c --watch --environment BASE_CODE_MIN,STANDALONE,SERVICE_WORKER,UTILITY_EXPORTS",
90
+ "dev:prepare": "rollup -c --environment BASE_CODE_MIN,STANDALONE,SERVICE_WORKER,UTILITY_EXPORTS",
91
+ "dev": "pnpm run build:watch",
90
92
  "build:custom": "node scripts/alloyBuilder.js",
91
93
  "test:functional": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" testcafe playwright:chromium",
92
94
  "test:functional:custom": "node ./scripts/runFunctionalTests.js",
@@ -21,7 +21,7 @@ import injectSendBeaconRequest from "./injectSendBeaconRequest.js";
21
21
  */
22
22
  const createBrowserNetworkService = ({ logger }) => {
23
23
  const { fetch, navigator } = window;
24
- const sendFetchRequest = injectSendFetchRequest({ fetch });
24
+ const sendFetchRequest = injectSendFetchRequest({ fetch, logger });
25
25
  const sendBeaconRequest =
26
26
  typeof navigator.sendBeacon === "function"
27
27
  ? injectSendBeaconRequest({
@@ -20,13 +20,15 @@ export default ({ sendBeacon, sendFetchRequest, logger }) => {
20
20
 
21
21
  // Using sendBeacon, we technically don't get a response back from
22
22
  // the server, but we'll resolve the promise with an object to maintain
23
- // consistency with other network strategies.
23
+ // consistency with other network strategies. `sentWithBeacon` marks the
24
+ // response as synthetic so it isn't logged as a real server response.
24
25
  return Promise.resolve({
25
26
  statusCode: 204,
26
27
  getHeader() {
27
28
  return null;
28
29
  },
29
30
  body: "",
31
+ sentWithBeacon: true,
30
32
  });
31
33
  };
32
34
  };
@@ -10,9 +10,23 @@ 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
- export default ({ fetch }) => {
14
- return (url, body, headers) => {
15
- return fetch(url, {
13
+ /** @import { NetworkService } from "@adobe/alloy-core/services" */
14
+
15
+ /**
16
+ * @param {Object} params
17
+ * @param {typeof window.fetch} params.fetch
18
+ * @param {{ info: (...args: any[]) => void }} params.logger
19
+ * @returns {NetworkService["sendFetchRequest"]}
20
+ */
21
+ export default ({ fetch, logger }) => {
22
+ /**
23
+ * @param {string} url
24
+ * @param {string} body
25
+ * @param {Record<string, string> | undefined} headers
26
+ * @param {boolean} keepalive
27
+ */
28
+ const startFetch = (url, body, headers, keepalive) =>
29
+ fetch(url, {
16
30
  method: "POST",
17
31
  cache: "no-cache",
18
32
  credentials: "include", // To set the cookie header in the request.
@@ -22,7 +36,30 @@ export default ({ fetch }) => {
22
36
  },
23
37
  referrerPolicy: "no-referrer-when-downgrade",
24
38
  body,
25
- }).then((response) => {
39
+ ...(keepalive ? { keepalive: true } : {}),
40
+ });
41
+
42
+ return (url, body, headers, { keepalive = false } = {}) => {
43
+ let responsePromise = startFetch(url, body, headers, keepalive);
44
+
45
+ if (keepalive) {
46
+ // Browsers reject keepalive requests whose body, together with every
47
+ // other in-flight keepalive request and sendBeacon on the page, exceeds
48
+ // 64 KiB. The rejection is a TypeError that looks the same as any other
49
+ // network error ("Failed to fetch", "NetworkError when attempting to
50
+ // fetch resource.", "Load failed") and arrives before anything is sent,
51
+ // so retry once without keepalive. Only fetch() itself is covered here;
52
+ // a failure while reading the response is not retried because the
53
+ // server already received the request.
54
+ responsePromise = responsePromise.catch(() => {
55
+ logger.info(
56
+ "Unable to send the request with `keepalive`; falling back to a regular `fetch`.",
57
+ );
58
+ return startFetch(url, body, headers, false);
59
+ });
60
+ }
61
+
62
+ return responsePromise.then((response) => {
26
63
  return response.text().then((responseBody) => ({
27
64
  statusCode: response.status,
28
65
  // We expose headers through a function instead of creating an object