@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.
- package/LICENSE.MD +202 -0
- package/README.md +114 -0
- package/dist/cjs/package.json +75 -0
- package/dist/cjs/src/consts.js +14 -0
- package/dist/cjs/src/debug.js +12 -0
- package/dist/cjs/src/index.js +13 -0
- package/dist/cjs/src/initialization/browser-adapter.js +48 -0
- package/dist/cjs/src/initialization/const.js +8 -0
- package/dist/cjs/src/initialization/get-profile-id.js +17 -0
- package/dist/cjs/src/initialization/plugin-browser.js +82 -0
- package/dist/cjs/src/initialization/plugin-server.js +43 -0
- package/dist/cjs/src/initialization/server-adapter.js +89 -0
- package/dist/cjs/src/initialization/shared.js +17 -0
- package/dist/cjs/src/initialization/types.js +2 -0
- package/dist/cjs/src/internal.js +11 -0
- package/dist/cjs/src/personalization/personalize.js +29 -0
- package/dist/cjs/src/personalization/personalizer.js +120 -0
- package/dist/cjs/src/personalization/send-call-flows-request.js +47 -0
- package/dist/cjs/src/profile-id/fetch-profile-id-from-edge-proxy.js +35 -0
- package/dist/cjs/src/web-personalization/get-cdn-url.js +27 -0
- package/dist/esm/package.json +75 -0
- package/dist/esm/src/consts.js +8 -0
- package/dist/esm/src/debug.js +9 -0
- package/dist/esm/src/index.js +5 -0
- package/dist/esm/src/initialization/browser-adapter.js +45 -0
- package/dist/esm/src/initialization/const.js +5 -0
- package/dist/esm/src/initialization/get-profile-id.js +14 -0
- package/dist/esm/src/initialization/plugin-browser.js +79 -0
- package/dist/esm/src/initialization/plugin-server.js +40 -0
- package/dist/esm/src/initialization/server-adapter.js +86 -0
- package/dist/esm/src/initialization/shared.js +14 -0
- package/dist/esm/src/initialization/types.js +1 -0
- package/dist/esm/src/internal.js +4 -0
- package/dist/esm/src/personalization/personalize.js +26 -0
- package/dist/esm/src/personalization/personalizer.js +116 -0
- package/dist/esm/src/personalization/send-call-flows-request.js +44 -0
- package/dist/esm/src/profile-id/fetch-profile-id-from-edge-proxy.js +32 -0
- package/dist/esm/src/web-personalization/get-cdn-url.js +24 -0
- package/internal.d.ts +1 -0
- package/package.json +75 -0
- package/types/src/consts.d.ts +8 -0
- package/types/src/consts.d.ts.map +1 -0
- package/types/src/debug.d.ts +9 -0
- package/types/src/debug.d.ts.map +1 -0
- package/types/src/index.d.ts +15 -0
- package/types/src/index.d.ts.map +1 -0
- package/types/src/initialization/browser-adapter.d.ts +19 -0
- package/types/src/initialization/browser-adapter.d.ts.map +1 -0
- package/types/src/initialization/const.d.ts +6 -0
- package/types/src/initialization/const.d.ts.map +1 -0
- package/types/src/initialization/get-profile-id.d.ts +8 -0
- package/types/src/initialization/get-profile-id.d.ts.map +1 -0
- package/types/src/initialization/plugin-browser.d.ts +37 -0
- package/types/src/initialization/plugin-browser.d.ts.map +1 -0
- package/types/src/initialization/plugin-server.d.ts +23 -0
- package/types/src/initialization/plugin-server.d.ts.map +1 -0
- package/types/src/initialization/server-adapter.d.ts +29 -0
- package/types/src/initialization/server-adapter.d.ts.map +1 -0
- package/types/src/initialization/shared.d.ts +8 -0
- package/types/src/initialization/shared.d.ts.map +1 -0
- package/types/src/initialization/types.d.ts +168 -0
- package/types/src/initialization/types.d.ts.map +1 -0
- package/types/src/internal.d.ts +8 -0
- package/types/src/internal.d.ts.map +1 -0
- package/types/src/personalization/personalize.d.ts +21 -0
- package/types/src/personalization/personalize.d.ts.map +1 -0
- package/types/src/personalization/personalizer.d.ts +177 -0
- package/types/src/personalization/personalizer.d.ts.map +1 -0
- package/types/src/personalization/send-call-flows-request.d.ts +78 -0
- package/types/src/personalization/send-call-flows-request.d.ts.map +1 -0
- package/types/src/profile-id/fetch-profile-id-from-edge-proxy.d.ts +39 -0
- package/types/src/profile-id/fetch-profile-id-from-edge-proxy.d.ts.map +1 -0
- package/types/src/web-personalization/get-cdn-url.d.ts +9 -0
- 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,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,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,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
|
+
}
|