@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,40 @@
|
|
|
1
|
+
import { PERSONALIZE_PLUGIN_NAME } from './const';
|
|
2
|
+
import { CLIENT_ID_COOKIE_NAME, COOKIE_NAME_PREFIX, } from '@sitecore-content-sdk/analytics-core/internal';
|
|
3
|
+
import { getPersonalizePlugin } from './shared';
|
|
4
|
+
import { ANALYTICS_PLUGIN_NAME, getAnalyticsPlugin, } from '@sitecore-content-sdk/analytics-core/internal';
|
|
5
|
+
/**
|
|
6
|
+
* Initializes the personalize plugin with the provided options.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
async function init() {
|
|
10
|
+
const personalizePlugin = getPersonalizePlugin();
|
|
11
|
+
const personalizeOptions = personalizePlugin.options;
|
|
12
|
+
const analyticsPlugin = getAnalyticsPlugin();
|
|
13
|
+
if (analyticsPlugin.options.cookies.enabled && personalizeOptions.cookies.enabled)
|
|
14
|
+
await personalizePlugin.adapter.setProfileId();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a personalize server plugin with the provided options.
|
|
18
|
+
* @param {PersonalizeServerPluginParams} params - The parameters for the personalize plugin.
|
|
19
|
+
* @returns {PersonalizeServerPlugin} The personalize plugin instance.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export function personalizeServerPlugin(params) {
|
|
23
|
+
var _a;
|
|
24
|
+
const { adapter, options } = params;
|
|
25
|
+
const cookies = {
|
|
26
|
+
enabled: (_a = options === null || options === void 0 ? void 0 : options.enablePersonalizeCookie) !== null && _a !== void 0 ? _a : false,
|
|
27
|
+
name: `${COOKIE_NAME_PREFIX}${CLIENT_ID_COOKIE_NAME}_personalize`,
|
|
28
|
+
};
|
|
29
|
+
const dependencies = [ANALYTICS_PLUGIN_NAME];
|
|
30
|
+
const resolvedOptions = {
|
|
31
|
+
cookies,
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
name: PERSONALIZE_PLUGIN_NAME,
|
|
35
|
+
init,
|
|
36
|
+
dependencies,
|
|
37
|
+
options: resolvedOptions,
|
|
38
|
+
adapter,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createCookieString, getCookieServerSide, } 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 server-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
|
+
* The adapter also provides access user agent from the request headers.
|
|
11
|
+
* @template Request - The HTTP request type extending `IncomingMessage`.
|
|
12
|
+
* @template Response - The HTTP response type extending `OutgoingMessage`.
|
|
13
|
+
* @param {Request} request - The HTTP request object.
|
|
14
|
+
* @param {Response} response - The HTTP response object.
|
|
15
|
+
* @returns {PersonalizeServerAdapter} An PersonalizeServerAdapter instance.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export function personalizeServerAdapter(request, response) {
|
|
19
|
+
return {
|
|
20
|
+
type: 'server',
|
|
21
|
+
getUserAgent: () => request.headers['user-agent'],
|
|
22
|
+
getProfileId: () => getProfileId(request),
|
|
23
|
+
setProfileId: async () => {
|
|
24
|
+
var _a;
|
|
25
|
+
const coreConfig = getCoreContext().config;
|
|
26
|
+
const cookieOptions = getAnalyticsPlugin().options.cookies;
|
|
27
|
+
const clientIdName = cookieOptions.name;
|
|
28
|
+
const personalizePlugin = getPersonalizePlugin();
|
|
29
|
+
const profileIdName = personalizePlugin.options.cookies.name;
|
|
30
|
+
const legacyProfileIdCookieName = `${COOKIE_NAME_PREFIX}${coreConfig.contextId}_personalize`;
|
|
31
|
+
const cookieAttributes = getDefaultCookieAttributes(cookieOptions.expiryDays, cookieOptions.domain);
|
|
32
|
+
const legacyProfileIdCookie = getCookieServerSide(request.headers.cookie, legacyProfileIdCookieName);
|
|
33
|
+
if (legacyProfileIdCookie) {
|
|
34
|
+
request.headers.cookie = (_a = request.headers.cookie) === null || _a === void 0 ? void 0 : _a.replace(legacyProfileIdCookie.name, profileIdName);
|
|
35
|
+
response.setHeader('Set-Cookie', [
|
|
36
|
+
createCookieString(profileIdName, legacyProfileIdCookie.value, cookieAttributes),
|
|
37
|
+
createCookieString(legacyProfileIdCookieName, '', Object.assign(Object.assign({}, cookieAttributes), { maxAge: 0 })),
|
|
38
|
+
]);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const cookiesValuesFromEdgeServer = getAnalyticsPlugin().options.visitorIds;
|
|
42
|
+
const profileIdCookie = getCookieServerSide(request.headers.cookie, profileIdName);
|
|
43
|
+
const clientIdCookie = getCookieServerSide(request.headers.cookie, clientIdName);
|
|
44
|
+
let profileIdCookieString;
|
|
45
|
+
if (profileIdCookie)
|
|
46
|
+
profileIdCookieString = createCookieString(profileIdName, profileIdCookie.value, cookieAttributes);
|
|
47
|
+
else if (cookiesValuesFromEdgeServer === null || cookiesValuesFromEdgeServer === void 0 ? void 0 : cookiesValuesFromEdgeServer.profileId)
|
|
48
|
+
profileIdCookieString = createCookieString(profileIdName, cookiesValuesFromEdgeServer.profileId, cookieAttributes);
|
|
49
|
+
else if (clientIdCookie) {
|
|
50
|
+
const profileIdCookieValueFromEdgeProxy = await fetchProfileIdFromEdgeProxy(clientIdCookie.value, coreConfig.contextId, coreConfig.edgeUrl);
|
|
51
|
+
profileIdCookieString = createCookieString(profileIdName, profileIdCookieValueFromEdgeProxy, cookieAttributes);
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
return;
|
|
55
|
+
if (!profileIdCookie)
|
|
56
|
+
request.headers.cookie = request.headers.cookie
|
|
57
|
+
? request.headers.cookie + '; ' + profileIdCookieString
|
|
58
|
+
: profileIdCookieString;
|
|
59
|
+
let cookieHeader;
|
|
60
|
+
const currentSetCookieHeader = response.getHeader('Set-Cookie');
|
|
61
|
+
if (currentSetCookieHeader) {
|
|
62
|
+
if (Array.isArray(currentSetCookieHeader)) {
|
|
63
|
+
cookieHeader = [...currentSetCookieHeader, profileIdCookieString];
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
cookieHeader = `${currentSetCookieHeader}; ${profileIdCookieString}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
cookieHeader = profileIdCookieString;
|
|
71
|
+
}
|
|
72
|
+
response.setHeader('Set-Cookie', cookieHeader);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Retrieves the profile ID from the request cookies.
|
|
78
|
+
* @template Request - The HTTP request type extending `IncomingMessage`.
|
|
79
|
+
* @param {Request} request
|
|
80
|
+
* @returns {string | null} The profile ID or null if not found.
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
function getProfileId(request) {
|
|
84
|
+
var _a, _b;
|
|
85
|
+
return ((_b = (_a = getCookieServerSide(request.headers.cookie, getPersonalizePlugin().options.cookies.name)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null);
|
|
86
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getCoreContext, constants } from '@sitecore-content-sdk/core';
|
|
2
|
+
import { PERSONALIZE_PLUGIN_NAME } from './const';
|
|
3
|
+
const { ERROR_MESSAGES } = constants;
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves the personalize plugin instance from the core context.
|
|
6
|
+
* @returns {PersonalizePlugin} The personalize plugin instance.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export function getPersonalizePlugin() {
|
|
10
|
+
const plugin = getCoreContext().plugins.get(PERSONALIZE_PLUGIN_NAME);
|
|
11
|
+
if (!plugin)
|
|
12
|
+
throw new Error(ERROR_MESSAGES.IE_004(PERSONALIZE_PLUGIN_NAME));
|
|
13
|
+
return plugin;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getAnalyticsPlugin } from '@sitecore-content-sdk/analytics-core/internal';
|
|
2
|
+
import { Personalizer } from './personalizer';
|
|
3
|
+
import { getCoreContext } from '@sitecore-content-sdk/core';
|
|
4
|
+
import { getPersonalizePlugin } from '../initialization/shared';
|
|
5
|
+
/**
|
|
6
|
+
* A function that executes an interactive/web experiment over any web-based/mobile application.
|
|
7
|
+
* @param {PersonalizeData} personalizeData - The required/optional attributes for a flow execution.
|
|
8
|
+
* @param {PersonalizeOpts} opts - An object containing additional options.
|
|
9
|
+
* @returns {Promise<unknown | null | FailedCalledFlowsResponse>} A flow execution response.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export async function personalize(personalizeData, opts) {
|
|
13
|
+
var _a;
|
|
14
|
+
const { config, readyPromise } = getCoreContext();
|
|
15
|
+
await readyPromise;
|
|
16
|
+
const { adapter: personalizeAdapter } = getPersonalizePlugin();
|
|
17
|
+
const { adapter: analyticsAdapter } = getAnalyticsPlugin();
|
|
18
|
+
const clientId = analyticsAdapter.getClientId() || '';
|
|
19
|
+
const profileId = personalizeAdapter.getProfileId() || '';
|
|
20
|
+
const searchParams = analyticsAdapter.location.getSearchParams();
|
|
21
|
+
const userAgent = (_a = personalizeAdapter.getUserAgent) === null || _a === void 0 ? void 0 : _a.call(personalizeAdapter);
|
|
22
|
+
return new Personalizer(clientId, profileId).getInteractiveExperienceData(personalizeData, config, searchParams, {
|
|
23
|
+
userAgent,
|
|
24
|
+
timeout: opts === null || opts === void 0 ? void 0 : opts.timeout,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { language } from '@sitecore-content-sdk/analytics-core/internal';
|
|
2
|
+
import { UTM_PREFIX } from '../consts';
|
|
3
|
+
import { sendCallFlowsRequest } from './send-call-flows-request';
|
|
4
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
5
|
+
const { ERROR_MESSAGES } = constants;
|
|
6
|
+
/**
|
|
7
|
+
* The Personalizer Class runs a flow of interactive experiments.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export class Personalizer {
|
|
11
|
+
/**
|
|
12
|
+
* The Personalizer Class runs a flow of interactive experiments.
|
|
13
|
+
* @param {string} clientId - The client id of the user
|
|
14
|
+
* @param {string} [profileId] - The profile id of the user
|
|
15
|
+
*/
|
|
16
|
+
constructor(clientId, profileId) {
|
|
17
|
+
this.clientId = clientId;
|
|
18
|
+
this.profileId = profileId;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A function to make a request to the Sitecore Edge Proxy `/callFlows` API endpoint
|
|
22
|
+
* @param {PersonalizeData} personalizeData - The personalize input from the developer
|
|
23
|
+
* @param {CoreContext['config']} config - The configuration that was set during initialization
|
|
24
|
+
* @param {string} searchParams - The URL search parameters
|
|
25
|
+
* @param {GetInteractiveExperienceDataOpts} opts - Optional object that contains options for timeout and User Agent
|
|
26
|
+
* @returns {Promise<unknown | null | FailedCalledFlowsResponse>} A promise that resolves with either the Sitecore Edge Proxy response object or null
|
|
27
|
+
*/
|
|
28
|
+
async getInteractiveExperienceData(personalizeData, config, searchParams, opts) {
|
|
29
|
+
var _a;
|
|
30
|
+
this.validate(personalizeData);
|
|
31
|
+
const sanitizedInput = this.sanitizeInput(personalizeData);
|
|
32
|
+
if (searchParams.includes(UTM_PREFIX) && !((_a = sanitizedInput.params) === null || _a === void 0 ? void 0 : _a.utm)) {
|
|
33
|
+
sanitizedInput.params = sanitizedInput.params || {};
|
|
34
|
+
sanitizedInput.params.utm = this.extractUrlParamsWithPrefix(searchParams, UTM_PREFIX);
|
|
35
|
+
}
|
|
36
|
+
const mappedData = this.mapPersonalizeInputToEPData(sanitizedInput);
|
|
37
|
+
if (!mappedData.email && !mappedData.identifiers)
|
|
38
|
+
mappedData.browserId = this.clientId;
|
|
39
|
+
return await sendCallFlowsRequest(mappedData, config, opts);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A function that sanitizes the personalize input data
|
|
43
|
+
* @param {PersonalizeData} personalizeData - The personalize input data to sanitize
|
|
44
|
+
* @returns {PersonalizeData} The sanitized object
|
|
45
|
+
*/
|
|
46
|
+
sanitizeInput(personalizeData) {
|
|
47
|
+
var _a;
|
|
48
|
+
const sanitizedData = {
|
|
49
|
+
channel: personalizeData.channel,
|
|
50
|
+
currency: personalizeData.currency,
|
|
51
|
+
friendlyId: personalizeData.friendlyId,
|
|
52
|
+
language: personalizeData.language,
|
|
53
|
+
};
|
|
54
|
+
if (personalizeData.identifier &&
|
|
55
|
+
personalizeData.identifier.id &&
|
|
56
|
+
personalizeData.identifier.id.trim().length > 0)
|
|
57
|
+
sanitizedData.identifier = personalizeData.identifier;
|
|
58
|
+
if (personalizeData.email && personalizeData.email.trim().length > 0)
|
|
59
|
+
sanitizedData.email = personalizeData.email;
|
|
60
|
+
if (personalizeData.params && Object.keys(personalizeData.params).length > 0)
|
|
61
|
+
sanitizedData.params = personalizeData.params;
|
|
62
|
+
if (personalizeData.geo && Object.keys(personalizeData.geo).length > 0)
|
|
63
|
+
sanitizedData.params = Object.assign(Object.assign({}, personalizeData.params), { geo: Object.assign({}, personalizeData.geo) });
|
|
64
|
+
if ((_a = personalizeData.pageVariantIds) === null || _a === void 0 ? void 0 : _a.length)
|
|
65
|
+
sanitizedData.pageVariantIds = personalizeData.pageVariantIds;
|
|
66
|
+
return sanitizedData;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A function that maps the personalize input data with the Edge Proxy
|
|
70
|
+
* @param {PersonalizeData} input - The personalize input data to map
|
|
71
|
+
* @returns {EPCallFlowsBody} The Edge Proxy object
|
|
72
|
+
*/
|
|
73
|
+
mapPersonalizeInputToEPData(input) {
|
|
74
|
+
var _a;
|
|
75
|
+
const mappedData = {
|
|
76
|
+
channel: input.channel,
|
|
77
|
+
clientKey: '',
|
|
78
|
+
currencyCode: input.currency,
|
|
79
|
+
email: input.email,
|
|
80
|
+
friendlyId: input.friendlyId,
|
|
81
|
+
guestRef: this.profileId,
|
|
82
|
+
identifiers: input.identifier,
|
|
83
|
+
language: (_a = input.language) !== null && _a !== void 0 ? _a : language(),
|
|
84
|
+
params: input.params,
|
|
85
|
+
pointOfSale: '',
|
|
86
|
+
variants: input.pageVariantIds,
|
|
87
|
+
};
|
|
88
|
+
return mappedData;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* A validation method to throw error for the mandatory property for runtime users
|
|
92
|
+
* @param {PersonalizeData} params - The personalize data object
|
|
93
|
+
*/
|
|
94
|
+
validate(params) {
|
|
95
|
+
if (!params.friendlyId || params.friendlyId.trim().length === 0)
|
|
96
|
+
throw new Error(ERROR_MESSAGES.MV_004);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Retrieves UTM parameters from the url query string e.g. `utm_test1=123&utm_test2=456`
|
|
100
|
+
* @param {string} urlParams - The url params passed
|
|
101
|
+
* @param {string} prefix - The prefix we want to extract from the params
|
|
102
|
+
* @returns {{ [key: string]: string }} An object containing the UTM parameters (if they exist) in the form: `utm: {test1: 123, test2: 456}`
|
|
103
|
+
*/
|
|
104
|
+
extractUrlParamsWithPrefix(urlParams, prefix) {
|
|
105
|
+
const urlSearchParams = new URLSearchParams(decodeURI(urlParams));
|
|
106
|
+
const extractedParams = {};
|
|
107
|
+
urlSearchParams.forEach((value, key) => {
|
|
108
|
+
const paramKey = key.toLowerCase();
|
|
109
|
+
if (paramKey.indexOf(prefix) === 0) {
|
|
110
|
+
const paramName = paramKey.substring(prefix.length);
|
|
111
|
+
extractedParams[paramName] = value;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return extractedParams;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { generateCorrelationId } from '@sitecore-content-sdk/analytics-core/internal';
|
|
2
|
+
import { PACKAGE_VERSION } from '../consts';
|
|
3
|
+
import { NativeDataFetcher, constants } from '@sitecore-content-sdk/core';
|
|
4
|
+
import { debug } from '../debug';
|
|
5
|
+
const { ERROR_MESSAGES } = constants;
|
|
6
|
+
/**
|
|
7
|
+
* A function that sends a CallFlow request to Sitecore Edge Proxy
|
|
8
|
+
* @param {EPCallFlowsBody} epCallFlowsBody - Properties to be sent to Sitecore Edge Proxy
|
|
9
|
+
* @param {CoreContext['config']} config - Configuration for the url params
|
|
10
|
+
* @param {GetInteractiveExperienceDataOpts} opts - Optional configuration object
|
|
11
|
+
* @returns {Promise<unknown | null | FailedCalledFlowsResponse>} A promise that resolves with either the Sitecore Edge Proxy response object or unknown
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export async function sendCallFlowsRequest(epCallFlowsBody, config, opts) {
|
|
15
|
+
// eslint-disable-next-line max-len
|
|
16
|
+
const requestUrl = `${config.edgeUrl}/v1/personalize?siteId=${config.siteName}`;
|
|
17
|
+
const fetchOptions = {
|
|
18
|
+
body: JSON.stringify(epCallFlowsBody),
|
|
19
|
+
headers: {
|
|
20
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
'X-Library-Version': PACKAGE_VERSION,
|
|
23
|
+
'x-sc-correlation-id': generateCorrelationId(),
|
|
24
|
+
'x-sitecore-contextid': config.contextId,
|
|
25
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
26
|
+
},
|
|
27
|
+
method: 'POST',
|
|
28
|
+
};
|
|
29
|
+
if (opts === null || opts === void 0 ? void 0 : opts.userAgent)
|
|
30
|
+
fetchOptions.headers['User-Agent'] = opts.userAgent;
|
|
31
|
+
const fetcher = new NativeDataFetcher({ timeout: opts === null || opts === void 0 ? void 0 : opts.timeout, debugger: debug.personalize });
|
|
32
|
+
return fetcher
|
|
33
|
+
.fetch(requestUrl, fetchOptions)
|
|
34
|
+
.then((response) => {
|
|
35
|
+
if (!response)
|
|
36
|
+
return null;
|
|
37
|
+
return response.data;
|
|
38
|
+
})
|
|
39
|
+
.catch((error) => {
|
|
40
|
+
if (error.message.includes(ERROR_MESSAGES.IV_002) || error.message.includes(ERROR_MESSAGES.IE_003))
|
|
41
|
+
throw new Error(error.message);
|
|
42
|
+
return null;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { API_VERSION } from '@sitecore-content-sdk/analytics-core/internal';
|
|
2
|
+
import { PACKAGE_VERSION } from '../consts';
|
|
3
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
4
|
+
const { ERROR_MESSAGES } = constants;
|
|
5
|
+
/**
|
|
6
|
+
* Gets the profile id from Edge Proxy.
|
|
7
|
+
* @param {string} clientId - The client ID of the client.
|
|
8
|
+
* @param {string} contextId - The Sitecore Edge context ID.
|
|
9
|
+
* @param {string} edgeUrl - The Sitecore Edge base URL.
|
|
10
|
+
* @returns {Promise<string>} A promise that resolves with the profile id.
|
|
11
|
+
* @throws Will throw an error if the client key or client ID is invalid.
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export async function fetchProfileIdFromEdgeProxy(clientId, contextId, edgeUrl) {
|
|
15
|
+
// eslint-disable-next-line max-len
|
|
16
|
+
const url = `${edgeUrl}/v1/events/${API_VERSION}/browser/${clientId}/show.json?client_key=&api_token=`;
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
18
|
+
const response = await fetch(url, {
|
|
19
|
+
headers: {
|
|
20
|
+
'X-Library-Version': PACKAGE_VERSION,
|
|
21
|
+
'x-sitecore-contextid': contextId,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const { error_msg: errorMsg, moreInfo } = data;
|
|
27
|
+
throw new Error(`${errorMsg}, for more info: ${moreInfo}`);
|
|
28
|
+
}
|
|
29
|
+
if (!data.customer.ref)
|
|
30
|
+
throw new Error(ERROR_MESSAGES.IE_006);
|
|
31
|
+
return data.customer.ref;
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieves the CDN URL for web personalization
|
|
3
|
+
* @param {string} contextId - The Sitecore Edge context ID
|
|
4
|
+
* @param {string} edgeUrl - The Sitecore Edge URL
|
|
5
|
+
* @returns {Promise<string | null>} The CDN URL or null if unavailable
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export async function getCdnUrl(contextId, edgeUrl) {
|
|
9
|
+
const requestUrl = `${edgeUrl}/v1/personalize/cdn-url?client_key=`;
|
|
10
|
+
try {
|
|
11
|
+
const response = await fetch(requestUrl, {
|
|
12
|
+
headers: {
|
|
13
|
+
'x-sitecore-contextid': contextId,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok)
|
|
17
|
+
return null;
|
|
18
|
+
return await response.text();
|
|
19
|
+
// eslint-disable-next-line no-unused-vars
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/internal.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types/src/internal';
|
package/package.json
ADDED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/consts.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAsB,CAAC;AACnD,eAAO,MAAM,YAAY,QAAmB,CAAC;AAC7C,eAAO,MAAM,UAAU,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/debug.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,KAAK;;CAEjB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type { PersonalizeData, PersonalizeGeolocation, PersonalizeIdentifierInput, PersonalizeInputParams, } from './personalization/personalizer';
|
|
2
|
+
export type { FailedCalledFlowsResponse } from './personalization/send-call-flows-request';
|
|
3
|
+
export { personalize, type PersonalizeOpts } from './personalization/personalize';
|
|
4
|
+
export type { PersonalizeServerPluginParams } from './initialization/plugin-server';
|
|
5
|
+
export { personalizeServerPlugin } from './initialization/plugin-server';
|
|
6
|
+
export type { PersonalizeServerAdapter } from './initialization/server-adapter';
|
|
7
|
+
export type { PersonalizeServerPlugin } from './initialization/types';
|
|
8
|
+
export { personalizeServerAdapter } from './initialization/server-adapter';
|
|
9
|
+
export type { PersonalizeBrowserPluginParams } from './initialization/plugin-browser';
|
|
10
|
+
export { personalizeBrowserPlugin } from './initialization/plugin-browser';
|
|
11
|
+
export type { PersonalizeBrowserAdapter } from './initialization/browser-adapter';
|
|
12
|
+
export type { PersonalizeBrowserPlugin } from './initialization/types';
|
|
13
|
+
export { personalizeBrowserAdapter } from './initialization/browser-adapter';
|
|
14
|
+
export type { WebPersonalizationOptions, PersonalizePluginOptions, PersonalizeServerPluginOptions, } from './initialization/types';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAElF,YAAY,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,YAAY,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAChF,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,YAAY,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,YAAY,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAClF,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PersonalizeAdapter } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Defines the PersonalizeBrowserAdapter.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface PersonalizeBrowserAdapter extends PersonalizeAdapter {
|
|
7
|
+
/**
|
|
8
|
+
* The type of the adapter.
|
|
9
|
+
*/
|
|
10
|
+
type: 'browser';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a browser-based personalize adapter that reads and writes the profile ID
|
|
14
|
+
* using cookies and can resolve a new profile ID from the Edge proxy when needed.
|
|
15
|
+
* @returns {PersonalizeBrowserAdapter} An PersonalizeBrowserAdapter instance.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export declare function personalizeBrowserAdapter(): PersonalizeBrowserAdapter;
|
|
19
|
+
//# sourceMappingURL=browser-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-adapter.d.ts","sourceRoot":"","sources":["../../../src/initialization/browser-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAU7C;;;GAGG;AACH,MAAM,WAAW,yBAA0B,SAAQ,kBAAkB;IACnE;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,yBAAyB,CA6DrE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../../src/initialization/const.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,uBAAuB,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the profile ID.
|
|
3
|
+
* @returns {Promise<string>} A promise that resolves with the profile ID.
|
|
4
|
+
* @throws If the Sitecore Edge context ID is incorrect.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare function getProfileId(): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=get-profile-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-profile-id.d.ts","sourceRoot":"","sources":["../../../src/initialization/get-profile-id.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAMpD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PersonalizeBrowserPlugin, PersonalizeAdapter, PersonalizePluginOptions, WebPersonalizationOptions } from './types';
|
|
2
|
+
import { getProfileId } from './get-profile-id';
|
|
3
|
+
import { personalize } from '../personalization/personalize';
|
|
4
|
+
/**
|
|
5
|
+
* Parameters for creating a personalize browser plugin.
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export interface PersonalizeBrowserPluginParams {
|
|
9
|
+
/**
|
|
10
|
+
* The adapter to be used for the personalize browser plugin.
|
|
11
|
+
*/
|
|
12
|
+
adapter: PersonalizeAdapter;
|
|
13
|
+
/**
|
|
14
|
+
* Optional configuration options for the personalize browser plugin.
|
|
15
|
+
*/
|
|
16
|
+
options?: PersonalizePluginOptions;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a personalize browser plugin with the provided adapter and options.
|
|
20
|
+
* @param {PersonalizeBrowserPluginParams} params - The personalize plugin parameters including adapter and options.
|
|
21
|
+
* @returns {PersonalizeBrowserPlugin} The configured personalize browser plugin.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export declare function personalizeBrowserPlugin(params: PersonalizeBrowserPluginParams): PersonalizeBrowserPlugin;
|
|
25
|
+
declare global {
|
|
26
|
+
interface AnalyticsCore {
|
|
27
|
+
getProfileId: typeof getProfileId;
|
|
28
|
+
}
|
|
29
|
+
interface ScContentSDK {
|
|
30
|
+
personalize: {
|
|
31
|
+
personalize: typeof personalize;
|
|
32
|
+
options?: Partial<WebPersonalizationOptions>;
|
|
33
|
+
version: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=plugin-browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-browser.d.ts","sourceRoot":"","sources":["../../../src/initialization/plugin-browser.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EAE1B,MAAM,SAAS,CAAC;AAUjB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AA+C7D;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAAC;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACpC;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,8BAA8B,GACrC,wBAAwB,CAkC1B;AAED,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,aAAa;QACrB,YAAY,EAAE,OAAO,YAAY,CAAC;KACnC;IAED,UAAU,YAAY;QACpB,WAAW,EAAE;YACX,WAAW,EAAE,OAAO,WAAW,CAAC;YAChC,OAAO,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;YAC7C,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;KACH;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PersonalizeAdapter, PersonalizeServerPlugin, PersonalizeServerPluginOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Parameters for creating a personalize server plugin.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface PersonalizeServerPluginParams {
|
|
7
|
+
/**
|
|
8
|
+
* The adapter to be used for the personalize server plugin.
|
|
9
|
+
*/
|
|
10
|
+
adapter: PersonalizeAdapter;
|
|
11
|
+
/**
|
|
12
|
+
* Optional configuration options for the personalize server plugin.
|
|
13
|
+
*/
|
|
14
|
+
options?: PersonalizeServerPluginOptions;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a personalize server plugin with the provided options.
|
|
18
|
+
* @param {PersonalizeServerPluginParams} params - The parameters for the personalize plugin.
|
|
19
|
+
* @returns {PersonalizeServerPlugin} The personalize plugin instance.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export declare function personalizeServerPlugin(params: PersonalizeServerPluginParams): PersonalizeServerPlugin;
|
|
23
|
+
//# sourceMappingURL=plugin-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-server.d.ts","sourceRoot":"","sources":["../../../src/initialization/plugin-server.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,8BAA8B,EAE/B,MAAM,SAAS,CAAC;AAoBjB;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAAC;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,8BAA8B,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,6BAA6B,GACpC,uBAAuB,CAoBzB"}
|