@sitecore-content-sdk/personalize 2.0.0-canary.12

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 (74) hide show
  1. package/LICENSE.MD +202 -0
  2. package/README.md +114 -0
  3. package/dist/cjs/package.json +75 -0
  4. package/dist/cjs/src/consts.js +14 -0
  5. package/dist/cjs/src/debug.js +12 -0
  6. package/dist/cjs/src/index.js +13 -0
  7. package/dist/cjs/src/initialization/browser-adapter.js +48 -0
  8. package/dist/cjs/src/initialization/const.js +8 -0
  9. package/dist/cjs/src/initialization/get-profile-id.js +17 -0
  10. package/dist/cjs/src/initialization/plugin-browser.js +82 -0
  11. package/dist/cjs/src/initialization/plugin-server.js +43 -0
  12. package/dist/cjs/src/initialization/server-adapter.js +89 -0
  13. package/dist/cjs/src/initialization/shared.js +17 -0
  14. package/dist/cjs/src/initialization/types.js +2 -0
  15. package/dist/cjs/src/internal.js +11 -0
  16. package/dist/cjs/src/personalization/personalize.js +29 -0
  17. package/dist/cjs/src/personalization/personalizer.js +120 -0
  18. package/dist/cjs/src/personalization/send-call-flows-request.js +47 -0
  19. package/dist/cjs/src/profile-id/fetch-profile-id-from-edge-proxy.js +35 -0
  20. package/dist/cjs/src/web-personalization/get-cdn-url.js +27 -0
  21. package/dist/esm/package.json +75 -0
  22. package/dist/esm/src/consts.js +8 -0
  23. package/dist/esm/src/debug.js +9 -0
  24. package/dist/esm/src/index.js +5 -0
  25. package/dist/esm/src/initialization/browser-adapter.js +45 -0
  26. package/dist/esm/src/initialization/const.js +5 -0
  27. package/dist/esm/src/initialization/get-profile-id.js +14 -0
  28. package/dist/esm/src/initialization/plugin-browser.js +79 -0
  29. package/dist/esm/src/initialization/plugin-server.js +40 -0
  30. package/dist/esm/src/initialization/server-adapter.js +86 -0
  31. package/dist/esm/src/initialization/shared.js +14 -0
  32. package/dist/esm/src/initialization/types.js +1 -0
  33. package/dist/esm/src/internal.js +4 -0
  34. package/dist/esm/src/personalization/personalize.js +26 -0
  35. package/dist/esm/src/personalization/personalizer.js +116 -0
  36. package/dist/esm/src/personalization/send-call-flows-request.js +44 -0
  37. package/dist/esm/src/profile-id/fetch-profile-id-from-edge-proxy.js +32 -0
  38. package/dist/esm/src/web-personalization/get-cdn-url.js +24 -0
  39. package/internal.d.ts +1 -0
  40. package/package.json +75 -0
  41. package/types/src/consts.d.ts +8 -0
  42. package/types/src/consts.d.ts.map +1 -0
  43. package/types/src/debug.d.ts +9 -0
  44. package/types/src/debug.d.ts.map +1 -0
  45. package/types/src/index.d.ts +15 -0
  46. package/types/src/index.d.ts.map +1 -0
  47. package/types/src/initialization/browser-adapter.d.ts +19 -0
  48. package/types/src/initialization/browser-adapter.d.ts.map +1 -0
  49. package/types/src/initialization/const.d.ts +6 -0
  50. package/types/src/initialization/const.d.ts.map +1 -0
  51. package/types/src/initialization/get-profile-id.d.ts +8 -0
  52. package/types/src/initialization/get-profile-id.d.ts.map +1 -0
  53. package/types/src/initialization/plugin-browser.d.ts +37 -0
  54. package/types/src/initialization/plugin-browser.d.ts.map +1 -0
  55. package/types/src/initialization/plugin-server.d.ts +23 -0
  56. package/types/src/initialization/plugin-server.d.ts.map +1 -0
  57. package/types/src/initialization/server-adapter.d.ts +29 -0
  58. package/types/src/initialization/server-adapter.d.ts.map +1 -0
  59. package/types/src/initialization/shared.d.ts +8 -0
  60. package/types/src/initialization/shared.d.ts.map +1 -0
  61. package/types/src/initialization/types.d.ts +168 -0
  62. package/types/src/initialization/types.d.ts.map +1 -0
  63. package/types/src/internal.d.ts +8 -0
  64. package/types/src/internal.d.ts.map +1 -0
  65. package/types/src/personalization/personalize.d.ts +21 -0
  66. package/types/src/personalization/personalize.d.ts.map +1 -0
  67. package/types/src/personalization/personalizer.d.ts +177 -0
  68. package/types/src/personalization/personalizer.d.ts.map +1 -0
  69. package/types/src/personalization/send-call-flows-request.d.ts +78 -0
  70. package/types/src/personalization/send-call-flows-request.d.ts.map +1 -0
  71. package/types/src/profile-id/fetch-profile-id-from-edge-proxy.d.ts +39 -0
  72. package/types/src/profile-id/fetch-profile-id-from-edge-proxy.d.ts.map +1 -0
  73. package/types/src/web-personalization/get-cdn-url.d.ts +9 -0
  74. package/types/src/web-personalization/get-cdn-url.d.ts.map +1 -0
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.personalizeServerAdapter = personalizeServerAdapter;
4
+ const utils_1 = require("@sitecore-content-sdk/analytics-core/utils");
5
+ const core_1 = require("@sitecore-content-sdk/core");
6
+ const shared_1 = require("./shared");
7
+ const internal_1 = require("@sitecore-content-sdk/analytics-core/internal");
8
+ const internal_2 = require("@sitecore-content-sdk/analytics-core/internal");
9
+ const fetch_profile_id_from_edge_proxy_1 = require("../profile-id/fetch-profile-id-from-edge-proxy");
10
+ /**
11
+ * Creates a server-based personalize adapter that reads and writes the profile ID
12
+ * using cookies and can resolve a new profile ID from the Edge proxy when needed.
13
+ * The adapter also provides access user agent from the request headers.
14
+ * @template Request - The HTTP request type extending `IncomingMessage`.
15
+ * @template Response - The HTTP response type extending `OutgoingMessage`.
16
+ * @param {Request} request - The HTTP request object.
17
+ * @param {Response} response - The HTTP response object.
18
+ * @returns {PersonalizeServerAdapter} An PersonalizeServerAdapter instance.
19
+ * @public
20
+ */
21
+ function personalizeServerAdapter(request, response) {
22
+ return {
23
+ type: 'server',
24
+ getUserAgent: () => request.headers['user-agent'],
25
+ getProfileId: () => getProfileId(request),
26
+ setProfileId: async () => {
27
+ var _a;
28
+ const coreConfig = (0, core_1.getCoreContext)().config;
29
+ const cookieOptions = (0, internal_2.getAnalyticsPlugin)().options.cookies;
30
+ const clientIdName = cookieOptions.name;
31
+ const personalizePlugin = (0, shared_1.getPersonalizePlugin)();
32
+ const profileIdName = personalizePlugin.options.cookies.name;
33
+ const legacyProfileIdCookieName = `${internal_1.COOKIE_NAME_PREFIX}${coreConfig.contextId}_personalize`;
34
+ const cookieAttributes = (0, internal_1.getDefaultCookieAttributes)(cookieOptions.expiryDays, cookieOptions.domain);
35
+ const legacyProfileIdCookie = (0, utils_1.getCookieServerSide)(request.headers.cookie, legacyProfileIdCookieName);
36
+ if (legacyProfileIdCookie) {
37
+ request.headers.cookie = (_a = request.headers.cookie) === null || _a === void 0 ? void 0 : _a.replace(legacyProfileIdCookie.name, profileIdName);
38
+ response.setHeader('Set-Cookie', [
39
+ (0, utils_1.createCookieString)(profileIdName, legacyProfileIdCookie.value, cookieAttributes),
40
+ (0, utils_1.createCookieString)(legacyProfileIdCookieName, '', Object.assign(Object.assign({}, cookieAttributes), { maxAge: 0 })),
41
+ ]);
42
+ return;
43
+ }
44
+ const cookiesValuesFromEdgeServer = (0, internal_2.getAnalyticsPlugin)().options.visitorIds;
45
+ const profileIdCookie = (0, utils_1.getCookieServerSide)(request.headers.cookie, profileIdName);
46
+ const clientIdCookie = (0, utils_1.getCookieServerSide)(request.headers.cookie, clientIdName);
47
+ let profileIdCookieString;
48
+ if (profileIdCookie)
49
+ profileIdCookieString = (0, utils_1.createCookieString)(profileIdName, profileIdCookie.value, cookieAttributes);
50
+ else if (cookiesValuesFromEdgeServer === null || cookiesValuesFromEdgeServer === void 0 ? void 0 : cookiesValuesFromEdgeServer.profileId)
51
+ profileIdCookieString = (0, utils_1.createCookieString)(profileIdName, cookiesValuesFromEdgeServer.profileId, cookieAttributes);
52
+ else if (clientIdCookie) {
53
+ const profileIdCookieValueFromEdgeProxy = await (0, fetch_profile_id_from_edge_proxy_1.fetchProfileIdFromEdgeProxy)(clientIdCookie.value, coreConfig.contextId, coreConfig.edgeUrl);
54
+ profileIdCookieString = (0, utils_1.createCookieString)(profileIdName, profileIdCookieValueFromEdgeProxy, cookieAttributes);
55
+ }
56
+ else
57
+ return;
58
+ if (!profileIdCookie)
59
+ request.headers.cookie = request.headers.cookie
60
+ ? request.headers.cookie + '; ' + profileIdCookieString
61
+ : profileIdCookieString;
62
+ let cookieHeader;
63
+ const currentSetCookieHeader = response.getHeader('Set-Cookie');
64
+ if (currentSetCookieHeader) {
65
+ if (Array.isArray(currentSetCookieHeader)) {
66
+ cookieHeader = [...currentSetCookieHeader, profileIdCookieString];
67
+ }
68
+ else {
69
+ cookieHeader = `${currentSetCookieHeader}; ${profileIdCookieString}`;
70
+ }
71
+ }
72
+ else {
73
+ cookieHeader = profileIdCookieString;
74
+ }
75
+ response.setHeader('Set-Cookie', cookieHeader);
76
+ },
77
+ };
78
+ }
79
+ /**
80
+ * Retrieves the profile ID from the request cookies.
81
+ * @template Request - The HTTP request type extending `IncomingMessage`.
82
+ * @param {Request} request
83
+ * @returns {string | null} The profile ID or null if not found.
84
+ * @internal
85
+ */
86
+ function getProfileId(request) {
87
+ var _a, _b;
88
+ return ((_b = (_a = (0, utils_1.getCookieServerSide)(request.headers.cookie, (0, shared_1.getPersonalizePlugin)().options.cookies.name)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null);
89
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPersonalizePlugin = getPersonalizePlugin;
4
+ const core_1 = require("@sitecore-content-sdk/core");
5
+ const const_1 = require("./const");
6
+ const { ERROR_MESSAGES } = core_1.constants;
7
+ /**
8
+ * Retrieves the personalize plugin instance from the core context.
9
+ * @returns {PersonalizePlugin} The personalize plugin instance.
10
+ * @internal
11
+ */
12
+ function getPersonalizePlugin() {
13
+ const plugin = (0, core_1.getCoreContext)().plugins.get(const_1.PERSONALIZE_PLUGIN_NAME);
14
+ if (!plugin)
15
+ throw new Error(ERROR_MESSAGES.IE_004(const_1.PERSONALIZE_PLUGIN_NAME));
16
+ return plugin;
17
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PACKAGE_VERSION = exports.fetchProfileIdFromEdgeProxy = exports.PERSONALIZE_PLUGIN_NAME = exports.getPersonalizePlugin = void 0;
4
+ var shared_1 = require("./initialization/shared");
5
+ Object.defineProperty(exports, "getPersonalizePlugin", { enumerable: true, get: function () { return shared_1.getPersonalizePlugin; } });
6
+ var const_1 = require("./initialization/const");
7
+ Object.defineProperty(exports, "PERSONALIZE_PLUGIN_NAME", { enumerable: true, get: function () { return const_1.PERSONALIZE_PLUGIN_NAME; } });
8
+ var fetch_profile_id_from_edge_proxy_1 = require("./profile-id/fetch-profile-id-from-edge-proxy");
9
+ Object.defineProperty(exports, "fetchProfileIdFromEdgeProxy", { enumerable: true, get: function () { return fetch_profile_id_from_edge_proxy_1.fetchProfileIdFromEdgeProxy; } });
10
+ var consts_1 = require("./consts");
11
+ Object.defineProperty(exports, "PACKAGE_VERSION", { enumerable: true, get: function () { return consts_1.PACKAGE_VERSION; } });
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.personalize = personalize;
4
+ const internal_1 = require("@sitecore-content-sdk/analytics-core/internal");
5
+ const personalizer_1 = require("./personalizer");
6
+ const core_1 = require("@sitecore-content-sdk/core");
7
+ const shared_1 = require("../initialization/shared");
8
+ /**
9
+ * A function that executes an interactive/web experiment over any web-based/mobile application.
10
+ * @param {PersonalizeData} personalizeData - The required/optional attributes for a flow execution.
11
+ * @param {PersonalizeOpts} opts - An object containing additional options.
12
+ * @returns {Promise<unknown | null | FailedCalledFlowsResponse>} A flow execution response.
13
+ * @public
14
+ */
15
+ async function personalize(personalizeData, opts) {
16
+ var _a;
17
+ const { config, readyPromise } = (0, core_1.getCoreContext)();
18
+ await readyPromise;
19
+ const { adapter: personalizeAdapter } = (0, shared_1.getPersonalizePlugin)();
20
+ const { adapter: analyticsAdapter } = (0, internal_1.getAnalyticsPlugin)();
21
+ const clientId = analyticsAdapter.getClientId() || '';
22
+ const profileId = personalizeAdapter.getProfileId() || '';
23
+ const searchParams = analyticsAdapter.location.getSearchParams();
24
+ const userAgent = (_a = personalizeAdapter.getUserAgent) === null || _a === void 0 ? void 0 : _a.call(personalizeAdapter);
25
+ return new personalizer_1.Personalizer(clientId, profileId).getInteractiveExperienceData(personalizeData, config, searchParams, {
26
+ userAgent,
27
+ timeout: opts === null || opts === void 0 ? void 0 : opts.timeout,
28
+ });
29
+ }
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Personalizer = void 0;
4
+ const internal_1 = require("@sitecore-content-sdk/analytics-core/internal");
5
+ const consts_1 = require("../consts");
6
+ const send_call_flows_request_1 = require("./send-call-flows-request");
7
+ const core_1 = require("@sitecore-content-sdk/core");
8
+ const { ERROR_MESSAGES } = core_1.constants;
9
+ /**
10
+ * The Personalizer Class runs a flow of interactive experiments.
11
+ * @internal
12
+ */
13
+ class Personalizer {
14
+ /**
15
+ * The Personalizer Class runs a flow of interactive experiments.
16
+ * @param {string} clientId - The client id of the user
17
+ * @param {string} [profileId] - The profile id of the user
18
+ */
19
+ constructor(clientId, profileId) {
20
+ this.clientId = clientId;
21
+ this.profileId = profileId;
22
+ }
23
+ /**
24
+ * A function to make a request to the Sitecore Edge Proxy `/callFlows` API endpoint
25
+ * @param {PersonalizeData} personalizeData - The personalize input from the developer
26
+ * @param {CoreContext['config']} config - The configuration that was set during initialization
27
+ * @param {string} searchParams - The URL search parameters
28
+ * @param {GetInteractiveExperienceDataOpts} opts - Optional object that contains options for timeout and User Agent
29
+ * @returns {Promise<unknown | null | FailedCalledFlowsResponse>} A promise that resolves with either the Sitecore Edge Proxy response object or null
30
+ */
31
+ async getInteractiveExperienceData(personalizeData, config, searchParams, opts) {
32
+ var _a;
33
+ this.validate(personalizeData);
34
+ const sanitizedInput = this.sanitizeInput(personalizeData);
35
+ if (searchParams.includes(consts_1.UTM_PREFIX) && !((_a = sanitizedInput.params) === null || _a === void 0 ? void 0 : _a.utm)) {
36
+ sanitizedInput.params = sanitizedInput.params || {};
37
+ sanitizedInput.params.utm = this.extractUrlParamsWithPrefix(searchParams, consts_1.UTM_PREFIX);
38
+ }
39
+ const mappedData = this.mapPersonalizeInputToEPData(sanitizedInput);
40
+ if (!mappedData.email && !mappedData.identifiers)
41
+ mappedData.browserId = this.clientId;
42
+ return await (0, send_call_flows_request_1.sendCallFlowsRequest)(mappedData, config, opts);
43
+ }
44
+ /**
45
+ * A function that sanitizes the personalize input data
46
+ * @param {PersonalizeData} personalizeData - The personalize input data to sanitize
47
+ * @returns {PersonalizeData} The sanitized object
48
+ */
49
+ sanitizeInput(personalizeData) {
50
+ var _a;
51
+ const sanitizedData = {
52
+ channel: personalizeData.channel,
53
+ currency: personalizeData.currency,
54
+ friendlyId: personalizeData.friendlyId,
55
+ language: personalizeData.language,
56
+ };
57
+ if (personalizeData.identifier &&
58
+ personalizeData.identifier.id &&
59
+ personalizeData.identifier.id.trim().length > 0)
60
+ sanitizedData.identifier = personalizeData.identifier;
61
+ if (personalizeData.email && personalizeData.email.trim().length > 0)
62
+ sanitizedData.email = personalizeData.email;
63
+ if (personalizeData.params && Object.keys(personalizeData.params).length > 0)
64
+ sanitizedData.params = personalizeData.params;
65
+ if (personalizeData.geo && Object.keys(personalizeData.geo).length > 0)
66
+ sanitizedData.params = Object.assign(Object.assign({}, personalizeData.params), { geo: Object.assign({}, personalizeData.geo) });
67
+ if ((_a = personalizeData.pageVariantIds) === null || _a === void 0 ? void 0 : _a.length)
68
+ sanitizedData.pageVariantIds = personalizeData.pageVariantIds;
69
+ return sanitizedData;
70
+ }
71
+ /**
72
+ * A function that maps the personalize input data with the Edge Proxy
73
+ * @param {PersonalizeData} input - The personalize input data to map
74
+ * @returns {EPCallFlowsBody} The Edge Proxy object
75
+ */
76
+ mapPersonalizeInputToEPData(input) {
77
+ var _a;
78
+ const mappedData = {
79
+ channel: input.channel,
80
+ clientKey: '',
81
+ currencyCode: input.currency,
82
+ email: input.email,
83
+ friendlyId: input.friendlyId,
84
+ guestRef: this.profileId,
85
+ identifiers: input.identifier,
86
+ language: (_a = input.language) !== null && _a !== void 0 ? _a : (0, internal_1.language)(),
87
+ params: input.params,
88
+ pointOfSale: '',
89
+ variants: input.pageVariantIds,
90
+ };
91
+ return mappedData;
92
+ }
93
+ /**
94
+ * A validation method to throw error for the mandatory property for runtime users
95
+ * @param {PersonalizeData} params - The personalize data object
96
+ */
97
+ validate(params) {
98
+ if (!params.friendlyId || params.friendlyId.trim().length === 0)
99
+ throw new Error(ERROR_MESSAGES.MV_004);
100
+ }
101
+ /**
102
+ * Retrieves UTM parameters from the url query string e.g. `utm_test1=123&utm_test2=456`
103
+ * @param {string} urlParams - The url params passed
104
+ * @param {string} prefix - The prefix we want to extract from the params
105
+ * @returns {{ [key: string]: string }} An object containing the UTM parameters (if they exist) in the form: `utm: {test1: 123, test2: 456}`
106
+ */
107
+ extractUrlParamsWithPrefix(urlParams, prefix) {
108
+ const urlSearchParams = new URLSearchParams(decodeURI(urlParams));
109
+ const extractedParams = {};
110
+ urlSearchParams.forEach((value, key) => {
111
+ const paramKey = key.toLowerCase();
112
+ if (paramKey.indexOf(prefix) === 0) {
113
+ const paramName = paramKey.substring(prefix.length);
114
+ extractedParams[paramName] = value;
115
+ }
116
+ });
117
+ return extractedParams;
118
+ }
119
+ }
120
+ exports.Personalizer = Personalizer;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendCallFlowsRequest = sendCallFlowsRequest;
4
+ const internal_1 = require("@sitecore-content-sdk/analytics-core/internal");
5
+ const consts_1 = require("../consts");
6
+ const core_1 = require("@sitecore-content-sdk/core");
7
+ const debug_1 = require("../debug");
8
+ const { ERROR_MESSAGES } = core_1.constants;
9
+ /**
10
+ * A function that sends a CallFlow request to Sitecore Edge Proxy
11
+ * @param {EPCallFlowsBody} epCallFlowsBody - Properties to be sent to Sitecore Edge Proxy
12
+ * @param {CoreContext['config']} config - Configuration for the url params
13
+ * @param {GetInteractiveExperienceDataOpts} opts - Optional configuration object
14
+ * @returns {Promise<unknown | null | FailedCalledFlowsResponse>} A promise that resolves with either the Sitecore Edge Proxy response object or unknown
15
+ * @internal
16
+ */
17
+ async function sendCallFlowsRequest(epCallFlowsBody, config, opts) {
18
+ // eslint-disable-next-line max-len
19
+ const requestUrl = `${config.edgeUrl}/v1/personalize?siteId=${config.siteName}`;
20
+ const fetchOptions = {
21
+ body: JSON.stringify(epCallFlowsBody),
22
+ headers: {
23
+ /* eslint-disable @typescript-eslint/naming-convention */
24
+ 'Content-Type': 'application/json',
25
+ 'X-Library-Version': consts_1.PACKAGE_VERSION,
26
+ 'x-sc-correlation-id': (0, internal_1.generateCorrelationId)(),
27
+ 'x-sitecore-contextid': config.contextId,
28
+ /* eslint-enable @typescript-eslint/naming-convention */
29
+ },
30
+ method: 'POST',
31
+ };
32
+ if (opts === null || opts === void 0 ? void 0 : opts.userAgent)
33
+ fetchOptions.headers['User-Agent'] = opts.userAgent;
34
+ const fetcher = new core_1.NativeDataFetcher({ timeout: opts === null || opts === void 0 ? void 0 : opts.timeout, debugger: debug_1.debug.personalize });
35
+ return fetcher
36
+ .fetch(requestUrl, fetchOptions)
37
+ .then((response) => {
38
+ if (!response)
39
+ return null;
40
+ return response.data;
41
+ })
42
+ .catch((error) => {
43
+ if (error.message.includes(ERROR_MESSAGES.IV_002) || error.message.includes(ERROR_MESSAGES.IE_003))
44
+ throw new Error(error.message);
45
+ return null;
46
+ });
47
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchProfileIdFromEdgeProxy = fetchProfileIdFromEdgeProxy;
4
+ const internal_1 = require("@sitecore-content-sdk/analytics-core/internal");
5
+ const consts_1 = require("../consts");
6
+ const core_1 = require("@sitecore-content-sdk/core");
7
+ const { ERROR_MESSAGES } = core_1.constants;
8
+ /**
9
+ * Gets the profile id from Edge Proxy.
10
+ * @param {string} clientId - The client ID of the client.
11
+ * @param {string} contextId - The Sitecore Edge context ID.
12
+ * @param {string} edgeUrl - The Sitecore Edge base URL.
13
+ * @returns {Promise<string>} A promise that resolves with the profile id.
14
+ * @throws Will throw an error if the client key or client ID is invalid.
15
+ * @internal
16
+ */
17
+ async function fetchProfileIdFromEdgeProxy(clientId, contextId, edgeUrl) {
18
+ // eslint-disable-next-line max-len
19
+ const url = `${edgeUrl}/v1/events/${internal_1.API_VERSION}/browser/${clientId}/show.json?client_key=&api_token=`;
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ const response = await fetch(url, {
22
+ headers: {
23
+ 'X-Library-Version': consts_1.PACKAGE_VERSION,
24
+ 'x-sitecore-contextid': contextId,
25
+ },
26
+ });
27
+ const data = await response.json();
28
+ if (!response.ok) {
29
+ const { error_msg: errorMsg, moreInfo } = data;
30
+ throw new Error(`${errorMsg}, for more info: ${moreInfo}`);
31
+ }
32
+ if (!data.customer.ref)
33
+ throw new Error(ERROR_MESSAGES.IE_006);
34
+ return data.customer.ref;
35
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCdnUrl = getCdnUrl;
4
+ /**
5
+ * Retrieves the CDN URL for web personalization
6
+ * @param {string} contextId - The Sitecore Edge context ID
7
+ * @param {string} edgeUrl - The Sitecore Edge URL
8
+ * @returns {Promise<string | null>} The CDN URL or null if unavailable
9
+ * @internal
10
+ */
11
+ async function getCdnUrl(contextId, edgeUrl) {
12
+ const requestUrl = `${edgeUrl}/v1/personalize/cdn-url?client_key=`;
13
+ try {
14
+ const response = await fetch(requestUrl, {
15
+ headers: {
16
+ 'x-sitecore-contextid': contextId,
17
+ },
18
+ });
19
+ if (!response.ok)
20
+ return null;
21
+ return await response.text();
22
+ // eslint-disable-next-line no-unused-vars
23
+ }
24
+ catch (error) {
25
+ return null;
26
+ }
27
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "author": {
3
+ "name": "Sitecore Corporation",
4
+ "url": "https://doc.sitecore.com/xmc/en/developers/content-sdk/index.html"
5
+ },
6
+ "bugs": {
7
+ "url": "https://github.com/sitecore/content-sdk/issues"
8
+ },
9
+ "dependencies": {
10
+ "@sitecore-content-sdk/analytics-core": "2.0.0-canary.12",
11
+ "@sitecore-content-sdk/core": "2.0.0-canary.12",
12
+ "@sitecore-content-sdk/events": "2.0.0-canary.12",
13
+ "debug": "^4.4.3"
14
+ },
15
+ "description": "Provides personalization capabilities to build tailored experiences for site visitors.",
16
+ "devDependencies": {
17
+ "@jest/types": "^29.6.3",
18
+ "@stylistic/eslint-plugin": "^5.2.2",
19
+ "@types/debug": "^4.1.12",
20
+ "@types/jest": "^29.5.12",
21
+ "@typescript-eslint/eslint-plugin": "8.39.0",
22
+ "@typescript-eslint/parser": "8.39.0",
23
+ "del-cli": "^6.0.0",
24
+ "eslint": "^9.32.0",
25
+ "eslint-config-prettier": "^10.1.8",
26
+ "eslint-plugin-import": "2.32.0",
27
+ "eslint-plugin-jsdoc": "52.0.3",
28
+ "eslint-plugin-prettier": "^4.0.0",
29
+ "jest": "^29.7.0",
30
+ "jest-environment-jsdom": "^29.7.0",
31
+ "jest-environment-node": "^29.7.0",
32
+ "ts-jest": "^29.1.0",
33
+ "ts-node": "^10.9.2"
34
+ },
35
+ "main": "dist/cjs/src/index.js",
36
+ "module": "dist/esm/src/index.js",
37
+ "types": "types/src/index.d.ts",
38
+ "exports": {
39
+ ".": {
40
+ "import": "./dist/esm/src/index.js",
41
+ "require": "./dist/cjs/src/index.js",
42
+ "types": "./types/src/index.d.ts"
43
+ },
44
+ "./internal": {
45
+ "import": "./dist/esm/src/internal.js",
46
+ "require": "./dist/cjs/src/internal.js",
47
+ "types": "./types/src/internal.d.ts"
48
+ }
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "types",
53
+ "/*.d.ts"
54
+ ],
55
+ "homepage": "https://doc.sitecore.com/xmc/en/developers/content-sdk/index.html",
56
+ "license": "Apache-2.0",
57
+ "name": "@sitecore-content-sdk/personalize",
58
+ "publishConfig": {
59
+ "access": "public",
60
+ "registry": "https://registry.npmjs.org/"
61
+ },
62
+ "scripts": {
63
+ "build": "npm run clean && tsc -p tsconfig.json && tsc -p tsconfig-esm.json",
64
+ "clean": "del-cli dist types",
65
+ "coverage": "jest --config jest.config.ts --coverage",
66
+ "generate-docs": "npx typedoc --plugin typedoc-plugin-markdown --outputFileStrategy Members --parametersFormat table --readme none --out ../../ref-docs/personalize --entryPoints src/internal.ts --entryPoints src/index.ts --githubPages false",
67
+ "lint": "eslint \"./src/**/*.ts\"",
68
+ "prepublishOnly": "npm run build",
69
+ "test": "jest --config jest.config.ts",
70
+ "api-extractor": "npm run build && api-extractor run --local --verbose",
71
+ "api-extractor:verify": "api-extractor run"
72
+ },
73
+ "version": "2.0.0-canary.12",
74
+ "gitHead": "4a26005860f4931f25d8c63d765a030e04a5b1f4"
75
+ }
@@ -0,0 +1,8 @@
1
+ import packageJson from '../package.json';
2
+ /**
3
+ * The package version.
4
+ * @internal
5
+ */
6
+ export const PACKAGE_VERSION = packageJson.version;
7
+ export const PACKAGE_NAME = packageJson.name;
8
+ export const UTM_PREFIX = 'utm_';
@@ -0,0 +1,9 @@
1
+ import { debugNamespace, debugModule } from '@sitecore-content-sdk/core';
2
+ export const PERSONALIZE_NAMESPACE = 'personalize';
3
+ /**
4
+ * Debug module for personalize package
5
+ * @public
6
+ */
7
+ export const debug = {
8
+ personalize: debugModule(`${debugNamespace}:${PERSONALIZE_NAMESPACE}`),
9
+ };
@@ -0,0 +1,5 @@
1
+ export { personalize } from './personalization/personalize';
2
+ export { personalizeServerPlugin } from './initialization/plugin-server';
3
+ export { personalizeServerAdapter } from './initialization/server-adapter';
4
+ export { personalizeBrowserPlugin } from './initialization/plugin-browser';
5
+ export { personalizeBrowserAdapter } from './initialization/browser-adapter';
@@ -0,0 +1,45 @@
1
+ import { createCookieString, getCookieValueClientSide, } from '@sitecore-content-sdk/analytics-core/utils';
2
+ import { getCoreContext } from '@sitecore-content-sdk/core';
3
+ import { getPersonalizePlugin } from './shared';
4
+ import { COOKIE_NAME_PREFIX, getDefaultCookieAttributes, } from '@sitecore-content-sdk/analytics-core/internal';
5
+ import { getAnalyticsPlugin } from '@sitecore-content-sdk/analytics-core/internal';
6
+ import { fetchProfileIdFromEdgeProxy } from '../profile-id/fetch-profile-id-from-edge-proxy';
7
+ /**
8
+ * Creates a browser-based personalize adapter that reads and writes the profile ID
9
+ * using cookies and can resolve a new profile ID from the Edge proxy when needed.
10
+ * @returns {PersonalizeBrowserAdapter} An PersonalizeBrowserAdapter instance.
11
+ * @public
12
+ */
13
+ export function personalizeBrowserAdapter() {
14
+ return {
15
+ type: 'browser',
16
+ getProfileId: () => {
17
+ return getCookieValueClientSide(getPersonalizePlugin().options.cookies.name);
18
+ },
19
+ setProfileId: async () => {
20
+ const coreConfig = getCoreContext().config;
21
+ const analyticsOptions = getAnalyticsPlugin().options;
22
+ const personalizePlugin = getPersonalizePlugin();
23
+ const profileIdCookieName = personalizePlugin.options.cookies.name;
24
+ const legacyProfileIdCookieName = `${COOKIE_NAME_PREFIX}${coreConfig.contextId}_personalize`;
25
+ const cookieAttributes = getDefaultCookieAttributes(analyticsOptions.cookies.expiryDays, analyticsOptions.cookies.domain);
26
+ const legacyProfileIdCookie = getCookieValueClientSide(legacyProfileIdCookieName);
27
+ if (legacyProfileIdCookie) {
28
+ document.cookie = createCookieString(profileIdCookieName, legacyProfileIdCookie, cookieAttributes);
29
+ document.cookie = createCookieString(legacyProfileIdCookieName, '', Object.assign(Object.assign({}, cookieAttributes), { maxAge: 0 }));
30
+ return;
31
+ }
32
+ const cookiesValuesFromEdgeBrowser = getAnalyticsPlugin().options.visitorIds;
33
+ const profileIdCookieValue = getCookieValueClientSide(profileIdCookieName);
34
+ const clientIdCookieValue = getCookieValueClientSide(analyticsOptions.cookies.name);
35
+ if (profileIdCookieValue)
36
+ return;
37
+ else if (cookiesValuesFromEdgeBrowser === null || cookiesValuesFromEdgeBrowser === void 0 ? void 0 : cookiesValuesFromEdgeBrowser.profileId)
38
+ document.cookie = createCookieString(profileIdCookieName, cookiesValuesFromEdgeBrowser.profileId, cookieAttributes);
39
+ else if (clientIdCookieValue) {
40
+ const profileIdCookieValue = await fetchProfileIdFromEdgeProxy(clientIdCookieValue, coreConfig.contextId, coreConfig.edgeUrl);
41
+ document.cookie = createCookieString(profileIdCookieName, profileIdCookieValue, cookieAttributes);
42
+ }
43
+ },
44
+ };
45
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The name of the Personalize plugin.
3
+ * @public
4
+ */
5
+ export const PERSONALIZE_PLUGIN_NAME = 'PersonalizePlugin';
@@ -0,0 +1,14 @@
1
+ import { getAnalyticsPlugin } from '@sitecore-content-sdk/analytics-core/internal';
2
+ import { fetchProfileIdFromEdgeProxy } from '../profile-id/fetch-profile-id-from-edge-proxy';
3
+ import { getCoreContext } from '@sitecore-content-sdk/core';
4
+ /**
5
+ * Returns the profile ID.
6
+ * @returns {Promise<string>} A promise that resolves with the profile ID.
7
+ * @throws If the Sitecore Edge context ID is incorrect.
8
+ * @internal
9
+ */
10
+ export async function getProfileId() {
11
+ const { config } = getCoreContext();
12
+ const clientId = getAnalyticsPlugin().adapter.getClientId() || '';
13
+ return fetchProfileIdFromEdgeProxy(clientId, config.contextId, config.edgeUrl);
14
+ }
@@ -0,0 +1,79 @@
1
+ import { PERSONALIZE_PLUGIN_NAME } from './const';
2
+ import { PACKAGE_VERSION } from '../consts';
3
+ import { CLIENT_ID_COOKIE_NAME, COOKIE_NAME_PREFIX, } from '@sitecore-content-sdk/analytics-core/internal';
4
+ import { EVENTS_PLUGIN_NAME } from '@sitecore-content-sdk/events/internal';
5
+ import { getCoreContext } from '@sitecore-content-sdk/core';
6
+ import { getCdnUrl } from '../web-personalization/get-cdn-url';
7
+ import { appendScriptWithAttributes } from '@sitecore-content-sdk/analytics-core/utils';
8
+ import { getPersonalizePlugin } from './shared';
9
+ import { ANALYTICS_PLUGIN_NAME, getAnalyticsPlugin, } from '@sitecore-content-sdk/analytics-core/internal';
10
+ import { getProfileId } from './get-profile-id';
11
+ import { personalize } from '../personalization/personalize';
12
+ /**
13
+ * Initializes the personalize plugin with the provided options.
14
+ * @internal
15
+ */
16
+ async function init() {
17
+ var _a;
18
+ const coreConfig = getCoreContext().config;
19
+ const personalizePlugin = getPersonalizePlugin();
20
+ const personalizeOptions = personalizePlugin.options;
21
+ const analyticsPlugin = getAnalyticsPlugin();
22
+ if (analyticsPlugin.options.cookies.enabled &&
23
+ personalizeOptions.cookies.enabled &&
24
+ (!personalizePlugin.adapter.getProfileId() || personalizePlugin.adapter.type !== 'browser'))
25
+ await personalizePlugin.adapter.setProfileId();
26
+ if (typeof window === 'undefined')
27
+ return;
28
+ window.scContentSDK = Object.assign(Object.assign({}, window.scContentSDK), { personalize: {
29
+ personalize,
30
+ version: PACKAGE_VERSION,
31
+ options: personalizeOptions.webPersonalization ? personalizeOptions.webPersonalization : {},
32
+ }, analytics_core: Object.assign(Object.assign({}, (_a = window.scContentSDK) === null || _a === void 0 ? void 0 : _a.analytics_core), { getProfileId }) });
33
+ if (!personalizeOptions.webPersonalization)
34
+ return;
35
+ window.scContentSDK.personalize.options = personalizeOptions.webPersonalization;
36
+ const cdnUrl = await getCdnUrl(coreConfig.contextId, coreConfig.edgeUrl);
37
+ if (!cdnUrl)
38
+ return;
39
+ appendScriptWithAttributes({
40
+ async: personalizeOptions.webPersonalization.async,
41
+ src: cdnUrl,
42
+ });
43
+ }
44
+ /**
45
+ * Creates a personalize browser plugin with the provided adapter and options.
46
+ * @param {PersonalizeBrowserPluginParams} params - The personalize plugin parameters including adapter and options.
47
+ * @returns {PersonalizeBrowserPlugin} The configured personalize browser plugin.
48
+ * @public
49
+ */
50
+ export function personalizeBrowserPlugin(params) {
51
+ var _a, _b, _c, _d;
52
+ const { adapter, options } = params;
53
+ const cookies = {
54
+ enabled: (_a = options === null || options === void 0 ? void 0 : options.enablePersonalizeCookie) !== null && _a !== void 0 ? _a : false,
55
+ name: `${COOKIE_NAME_PREFIX}${CLIENT_ID_COOKIE_NAME}_personalize`,
56
+ };
57
+ const dependencies = [ANALYTICS_PLUGIN_NAME];
58
+ let webPersonalization;
59
+ if (options === null || options === void 0 ? void 0 : options.webPersonalization) {
60
+ dependencies.push(EVENTS_PLUGIN_NAME);
61
+ webPersonalization = {
62
+ async: (_b = options.webPersonalization.async) !== null && _b !== void 0 ? _b : true,
63
+ defer: (_c = options.webPersonalization.defer) !== null && _c !== void 0 ? _c : false,
64
+ language: (_d = options.webPersonalization.language) !== null && _d !== void 0 ? _d : undefined,
65
+ };
66
+ }
67
+ webPersonalization !== null && webPersonalization !== void 0 ? webPersonalization : (webPersonalization = false);
68
+ const resolvedOptions = {
69
+ webPersonalization,
70
+ cookies,
71
+ };
72
+ return {
73
+ name: PERSONALIZE_PLUGIN_NAME,
74
+ init,
75
+ dependencies,
76
+ options: resolvedOptions,
77
+ adapter,
78
+ };
79
+ }