@sitecore-jss/sitecore-jss 0.1.0-beta.2

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 (143) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +7 -0
  3. package/dist/cjs/cache-client.js +54 -0
  4. package/dist/cjs/constants.js +12 -0
  5. package/dist/cjs/debug.js +43 -0
  6. package/dist/cjs/graphql/app-root-query.js +73 -0
  7. package/dist/cjs/graphql/graphql-edge-proxy.js +12 -0
  8. package/dist/cjs/graphql/index.js +11 -0
  9. package/dist/cjs/graphql/search-service.js +60 -0
  10. package/dist/cjs/graphql-request-client.js +106 -0
  11. package/dist/cjs/i18n/dictionary-service.js +45 -0
  12. package/dist/cjs/i18n/graphql-dictionary-service.js +125 -0
  13. package/dist/cjs/i18n/index.js +7 -0
  14. package/dist/cjs/index.js +36 -0
  15. package/dist/cjs/layout/content-styles.js +73 -0
  16. package/dist/cjs/layout/graphql-layout-service.js +84 -0
  17. package/dist/cjs/layout/index.js +18 -0
  18. package/dist/cjs/layout/layout-service.js +9 -0
  19. package/dist/cjs/layout/models.js +27 -0
  20. package/dist/cjs/layout/themes.js +79 -0
  21. package/dist/cjs/layout/utils.js +44 -0
  22. package/dist/cjs/media/index.js +24 -0
  23. package/dist/cjs/media/media-api.js +128 -0
  24. package/dist/cjs/models.js +2 -0
  25. package/dist/cjs/native-fetcher.js +183 -0
  26. package/dist/cjs/personalize/graphql-personalize-service.js +114 -0
  27. package/dist/cjs/personalize/index.js +12 -0
  28. package/dist/cjs/personalize/layout-personalizer.js +75 -0
  29. package/dist/cjs/personalize/utils.js +92 -0
  30. package/dist/cjs/site/graphql-error-pages-service.js +86 -0
  31. package/dist/cjs/site/graphql-redirects-service.js +103 -0
  32. package/dist/cjs/site/graphql-robots-service.js +81 -0
  33. package/dist/cjs/site/graphql-siteinfo-service.js +128 -0
  34. package/dist/cjs/site/graphql-sitemap-service.js +91 -0
  35. package/dist/cjs/site/index.js +22 -0
  36. package/dist/cjs/site/site-resolver.js +79 -0
  37. package/dist/cjs/site/utils.js +43 -0
  38. package/dist/cjs/utils/edit-frame.js +138 -0
  39. package/dist/cjs/utils/editing.js +122 -0
  40. package/dist/cjs/utils/env.js +26 -0
  41. package/dist/cjs/utils/index.js +25 -0
  42. package/dist/cjs/utils/is-server.js +10 -0
  43. package/dist/cjs/utils/timeout-promise.js +31 -0
  44. package/dist/cjs/utils/utils.js +70 -0
  45. package/dist/esm/cache-client.js +50 -0
  46. package/dist/esm/constants.js +9 -0
  47. package/dist/esm/debug.js +36 -0
  48. package/dist/esm/graphql/app-root-query.js +69 -0
  49. package/dist/esm/graphql/graphql-edge-proxy.js +8 -0
  50. package/dist/esm/graphql/index.js +4 -0
  51. package/dist/esm/graphql/search-service.js +56 -0
  52. package/dist/esm/graphql-request-client.js +99 -0
  53. package/dist/esm/i18n/dictionary-service.js +41 -0
  54. package/dist/esm/i18n/graphql-dictionary-service.js +118 -0
  55. package/dist/esm/i18n/index.js +2 -0
  56. package/dist/esm/index.js +7 -0
  57. package/dist/esm/layout/content-styles.js +65 -0
  58. package/dist/esm/layout/graphql-layout-service.js +77 -0
  59. package/dist/esm/layout/index.js +6 -0
  60. package/dist/esm/layout/layout-service.js +5 -0
  61. package/dist/esm/layout/models.js +24 -0
  62. package/dist/esm/layout/themes.js +74 -0
  63. package/dist/esm/layout/utils.js +39 -0
  64. package/dist/esm/media/index.js +2 -0
  65. package/dist/esm/media/media-api.js +117 -0
  66. package/dist/esm/models.js +1 -0
  67. package/dist/esm/native-fetcher.js +176 -0
  68. package/dist/esm/personalize/graphql-personalize-service.js +107 -0
  69. package/dist/esm/personalize/index.js +3 -0
  70. package/dist/esm/personalize/layout-personalizer.js +69 -0
  71. package/dist/esm/personalize/utils.js +85 -0
  72. package/dist/esm/site/graphql-error-pages-service.js +79 -0
  73. package/dist/esm/site/graphql-redirects-service.js +96 -0
  74. package/dist/esm/site/graphql-robots-service.js +74 -0
  75. package/dist/esm/site/graphql-siteinfo-service.js +121 -0
  76. package/dist/esm/site/graphql-sitemap-service.js +84 -0
  77. package/dist/esm/site/index.js +7 -0
  78. package/dist/esm/site/site-resolver.js +75 -0
  79. package/dist/esm/site/utils.js +37 -0
  80. package/dist/esm/utils/edit-frame.js +133 -0
  81. package/dist/esm/utils/editing.js +111 -0
  82. package/dist/esm/utils/env.js +22 -0
  83. package/dist/esm/utils/index.js +5 -0
  84. package/dist/esm/utils/is-server.js +8 -0
  85. package/dist/esm/utils/timeout-promise.js +28 -0
  86. package/dist/esm/utils/utils.js +61 -0
  87. package/graphql.d.ts +1 -0
  88. package/graphql.js +1 -0
  89. package/i18n.d.ts +1 -0
  90. package/i18n.js +1 -0
  91. package/layout.d.ts +1 -0
  92. package/layout.js +1 -0
  93. package/media.d.ts +1 -0
  94. package/media.js +1 -0
  95. package/package.json +71 -0
  96. package/personalize.d.ts +1 -0
  97. package/personalize.js +1 -0
  98. package/site.d.ts +1 -0
  99. package/site.js +1 -0
  100. package/types/cache-client.d.ts +64 -0
  101. package/types/constants.d.ts +6 -0
  102. package/types/debug.d.ts +26 -0
  103. package/types/graphql/app-root-query.d.ts +32 -0
  104. package/types/graphql/graphql-edge-proxy.d.ts +7 -0
  105. package/types/graphql/index.d.ts +4 -0
  106. package/types/graphql/search-service.d.ts +92 -0
  107. package/types/graphql-request-client.d.ts +88 -0
  108. package/types/i18n/dictionary-service.d.ts +56 -0
  109. package/types/i18n/graphql-dictionary-service.d.ts +65 -0
  110. package/types/i18n/index.d.ts +2 -0
  111. package/types/index.d.ts +6 -0
  112. package/types/layout/content-styles.d.ts +18 -0
  113. package/types/layout/graphql-layout-service.d.ts +59 -0
  114. package/types/layout/index.d.ts +6 -0
  115. package/types/layout/layout-service.d.ts +20 -0
  116. package/types/layout/models.d.ts +140 -0
  117. package/types/layout/themes.d.ts +11 -0
  118. package/types/layout/utils.d.ts +17 -0
  119. package/types/media/index.d.ts +2 -0
  120. package/types/media/media-api.d.ts +69 -0
  121. package/types/models.d.ts +6 -0
  122. package/types/native-fetcher.d.ts +92 -0
  123. package/types/personalize/graphql-personalize-service.d.ts +77 -0
  124. package/types/personalize/index.d.ts +3 -0
  125. package/types/personalize/layout-personalizer.d.ts +25 -0
  126. package/types/personalize/utils.d.ts +53 -0
  127. package/types/site/graphql-error-pages-service.d.ts +55 -0
  128. package/types/site/graphql-redirects-service.d.ts +66 -0
  129. package/types/site/graphql-robots-service.d.ts +47 -0
  130. package/types/site/graphql-siteinfo-service.d.ts +69 -0
  131. package/types/site/graphql-sitemap-service.d.ts +53 -0
  132. package/types/site/index.d.ts +7 -0
  133. package/types/site/site-resolver.d.ts +27 -0
  134. package/types/site/utils.d.ts +24 -0
  135. package/types/utils/edit-frame.d.ts +76 -0
  136. package/types/utils/editing.d.ts +58 -0
  137. package/types/utils/env.d.ts +7 -0
  138. package/types/utils/index.d.ts +5 -0
  139. package/types/utils/is-server.d.ts +6 -0
  140. package/types/utils/timeout-promise.d.ts +18 -0
  141. package/types/utils/utils.d.ts +18 -0
  142. package/utils.d.ts +1 -0
  143. package/utils.js +1 -0
@@ -0,0 +1,176 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
21
+ import debuggers from './debug';
22
+ import TimeoutPromise from './utils/timeout-promise';
23
+ export class NativeDataFetcher {
24
+ constructor(config = {}) {
25
+ this.config = config;
26
+ }
27
+ /**
28
+ * Implements a data fetcher.
29
+ * @param {string} url The URL to request (may include query string)
30
+ * @param {RequestInit} [options] Optional fetch options
31
+ * @returns {Promise<NativeDataFetcherResponse<T>>} response
32
+ */
33
+ fetch(url, options = {}) {
34
+ var _a;
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const _b = this.config, { debugger: debugOverride, fetch: fetchOverride } = _b, init = __rest(_b, ["debugger", "fetch"]);
37
+ const startTimestamp = Date.now();
38
+ const fetchImpl = fetchOverride || fetch;
39
+ const debug = debugOverride || debuggers.http;
40
+ // merge options from fetcher config and fetch call
41
+ const requestInit = this.getRequestInit(Object.assign(Object.assign({}, init), options));
42
+ const fetchWithOptionalTimeout = [fetchImpl(url, requestInit)];
43
+ if (init.timeout) {
44
+ this.abortTimeout = new TimeoutPromise(init.timeout);
45
+ fetchWithOptionalTimeout.push(this.abortTimeout.start);
46
+ }
47
+ // Note a goal here is to provide consistent debug logging and error handling
48
+ // as we do in GraphQLRequestClient
49
+ const { headers: reqHeaders } = requestInit, rest = __rest(requestInit, ["headers"]);
50
+ debug('request: %o', Object.assign({ url, headers: this.extractDebugHeaders(reqHeaders) }, rest));
51
+ const response = yield Promise.race(fetchWithOptionalTimeout)
52
+ .then((res) => {
53
+ var _a;
54
+ (_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear();
55
+ return res;
56
+ })
57
+ .catch((error) => {
58
+ var _a;
59
+ (_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear();
60
+ debug('request error: %o', error);
61
+ throw error;
62
+ });
63
+ // Note even an error status may send useful json data in response (which we want for logging)
64
+ let respData = undefined;
65
+ const isJson = (_a = response.headers.get('Content-Type')) === null || _a === void 0 ? void 0 : _a.includes('application/json');
66
+ if (isJson) {
67
+ respData = yield response.json().catch((error) => {
68
+ debug('response.json() error: %o', error);
69
+ });
70
+ }
71
+ else {
72
+ // if not JSON, just read the response as text
73
+ respData = yield response.text().catch((error) => {
74
+ debug('response.text() error: %o', error);
75
+ });
76
+ }
77
+ const debugResponse = {
78
+ status: response.status,
79
+ statusText: response.statusText,
80
+ headers: this.extractDebugHeaders(response.headers),
81
+ url: response.url,
82
+ redirected: response.redirected,
83
+ data: respData,
84
+ };
85
+ if (!response.ok) {
86
+ debug('response error: %o', debugResponse);
87
+ throw new Error(`HTTP ${response.status} ${response.statusText}`);
88
+ }
89
+ debug('response in %dms: %o', Date.now() - startTimestamp, debugResponse);
90
+ return Object.assign(Object.assign({}, response), { data: respData });
91
+ });
92
+ }
93
+ /**
94
+ * Perform a GET request
95
+ * @param {string} url The URL to request (may include query string)
96
+ * @param {RequestInit} [options] Fetch options
97
+ * @returns {Promise<NativeDataFetcherResponse<T>>} response
98
+ */
99
+ get(url, options = {}) {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ return this.fetch(url, Object.assign({ method: 'GET' }, options));
102
+ });
103
+ }
104
+ /**
105
+ * Perform a POST request
106
+ * @param {string} url The URL to request (may include query string)
107
+ * @param {unknown} body The data to send with the request
108
+ * @param {RequestInit} [options] Fetch options
109
+ * @returns {Promise<NativeDataFetcherResponse<T>>} response
110
+ */
111
+ post(url, body, options = {}) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ return this.fetch(url, Object.assign({ method: 'POST', body: JSON.stringify(body) }, options));
114
+ });
115
+ }
116
+ /**
117
+ * Perform a DELETE request
118
+ * @param {string} url The URL to request (may include query string)
119
+ * @param {RequestInit} [options] Fetch options
120
+ * @returns {Promise<NativeDataFetcherResponse<T>>} response
121
+ */
122
+ delete(url, options = {}) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ return this.fetch(url, Object.assign({ method: 'DELETE' }, options));
125
+ });
126
+ }
127
+ /**
128
+ * Perform a PUT request
129
+ * @param {string} url The URL to request (may include query string)
130
+ * @param {unknown} body The data to send with the request
131
+ * @param {RequestInit} [options] Fetch options
132
+ * @returns {Promise<NativeDataFetcherResponse<T>>} response
133
+ */
134
+ put(url, body, options = {}) {
135
+ return __awaiter(this, void 0, void 0, function* () {
136
+ return this.fetch(url, Object.assign({ method: 'PUT', body: JSON.stringify(body) }, options));
137
+ });
138
+ }
139
+ /**
140
+ * Perform a HEAD request
141
+ * @param {string} url The URL to request (may include query string)
142
+ * @param {RequestInit} [options] Fetch options
143
+ * @returns {Promise<NativeDataFetcherResponse<T>>} response
144
+ */
145
+ head(url, options = {}) {
146
+ return this.fetch(url, Object.assign({ method: 'HEAD' }, options));
147
+ }
148
+ /**
149
+ * Determines settings for the request
150
+ * @param {RequestInit} init Custom settings for request
151
+ * @returns {RequestInit} The final request settings
152
+ */
153
+ getRequestInit(init = {}) {
154
+ const headers = new Headers(init.headers);
155
+ if (!init.method) {
156
+ init.method = init.body ? 'POST' : 'GET';
157
+ }
158
+ headers.set('Content-Type', 'application/json');
159
+ init.headers = headers;
160
+ return init;
161
+ }
162
+ /**
163
+ * Safely extract all headers for debug logging
164
+ * @param {HeadersInit} incomingHeaders Incoming headers
165
+ * @returns Object with headers as key/value pairs
166
+ */
167
+ extractDebugHeaders(incomingHeaders = {}) {
168
+ const headers = {};
169
+ if (typeof (incomingHeaders === null || incomingHeaders === void 0 ? void 0 : incomingHeaders.forEach) !== 'string' && incomingHeaders.forEach) {
170
+ incomingHeaders === null || incomingHeaders === void 0 ? void 0 : incomingHeaders.forEach((value, key) => {
171
+ headers[key] = value;
172
+ });
173
+ }
174
+ return headers;
175
+ }
176
+ }
@@ -0,0 +1,107 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import debug from '../debug';
11
+ import { isTimeoutError } from '../utils';
12
+ import { CdpHelper } from './utils';
13
+ import { MemoryCacheClient } from '../cache-client';
14
+ export class GraphQLPersonalizeService {
15
+ /**
16
+ * Fetch personalize data using the Sitecore GraphQL endpoint.
17
+ * @param {GraphQLPersonalizeServiceConfig} config
18
+ */
19
+ constructor(config) {
20
+ this.config = config;
21
+ this.config.timeout = config.timeout || 400;
22
+ this.graphQLClient = this.getGraphQLClient();
23
+ this.cache = this.getCacheClient();
24
+ }
25
+ get query() {
26
+ return /* GraphQL */ `
27
+ query($siteName: String!, $language: String!, $itemPath: String!) {
28
+ layout(site: $siteName, routePath: $itemPath, language: $language) {
29
+ item {
30
+ id
31
+ version
32
+ personalization {
33
+ variantIds
34
+ }
35
+ }
36
+ }
37
+ }
38
+ `;
39
+ }
40
+ /**
41
+ * Get personalize information for a route
42
+ * @param {string} itemPath page route
43
+ * @param {string} language language
44
+ * @param {string} siteName site name
45
+ * @returns {Promise<PersonalizeInfo | undefined>} the personalize information or undefined (if itemPath / language not found)
46
+ */
47
+ getPersonalizeInfo(itemPath, language, siteName) {
48
+ var _a;
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ debug.personalize('fetching personalize info for %s %s %s', siteName, itemPath, language);
51
+ const cacheKey = this.getCacheKey(itemPath, language, siteName);
52
+ let data = this.cache.getCacheValue(cacheKey);
53
+ if (!data) {
54
+ try {
55
+ data = yield this.graphQLClient.request(this.query, {
56
+ siteName,
57
+ itemPath,
58
+ language,
59
+ });
60
+ this.cache.setCacheValue(cacheKey, data);
61
+ }
62
+ catch (error) {
63
+ if (isTimeoutError(error)) {
64
+ return undefined;
65
+ }
66
+ throw error;
67
+ }
68
+ }
69
+ return ((_a = data === null || data === void 0 ? void 0 : data.layout) === null || _a === void 0 ? void 0 : _a.item)
70
+ ? {
71
+ // CDP expects content id format `embedded_[<scope>_]<id>_<lang>` (lowercase)
72
+ contentId: CdpHelper.getContentId(data.layout.item.id, language, this.config.scope),
73
+ variantIds: data.layout.item.personalization.variantIds,
74
+ }
75
+ : undefined;
76
+ });
77
+ }
78
+ /**
79
+ * Gets cache client implementation
80
+ * Override this method if custom cache needs to be used
81
+ * @returns CacheClient instance
82
+ */
83
+ getCacheClient() {
84
+ var _a, _b;
85
+ return new MemoryCacheClient({
86
+ cacheEnabled: (_a = this.config.cacheEnabled) !== null && _a !== void 0 ? _a : true,
87
+ cacheTimeout: (_b = this.config.cacheTimeout) !== null && _b !== void 0 ? _b : 10,
88
+ });
89
+ }
90
+ getCacheKey(itemPath, language, siteName) {
91
+ return `${siteName}-${itemPath}-${language}`;
92
+ }
93
+ /**
94
+ * Gets a GraphQL client that can make requests to the API.
95
+ * @returns {GraphQLClient} implementation
96
+ */
97
+ getGraphQLClient() {
98
+ if (!this.config.clientFactory) {
99
+ throw new Error('You should provide a clientFactory.');
100
+ }
101
+ return this.config.clientFactory({
102
+ debugger: debug.personalize,
103
+ fetch: this.config.fetch,
104
+ timeout: this.config.timeout,
105
+ });
106
+ }
107
+ }
@@ -0,0 +1,3 @@
1
+ export { personalizeLayout } from './layout-personalizer';
2
+ export { GraphQLPersonalizeService, } from './graphql-personalize-service';
3
+ export { getPersonalizedRewrite, getPersonalizedRewriteData, normalizePersonalizedRewrite, CdpHelper, } from './utils';
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Apply personalization to layout data. This will recursively go through all placeholders/components, check experiences nodes and replace default with object from specific experience.
3
+ * @param {LayoutServiceData} layout Layout data
4
+ * @param {string} variantId variant id
5
+ */
6
+ export function personalizeLayout(layout, variantId) {
7
+ var _a;
8
+ // Add variantId to Sitecore context so that it is accessible here
9
+ layout.sitecore.context.variantId = variantId;
10
+ const placeholders = (_a = layout.sitecore.route) === null || _a === void 0 ? void 0 : _a.placeholders;
11
+ if (Object.keys(placeholders !== null && placeholders !== void 0 ? placeholders : {}).length === 0) {
12
+ return;
13
+ }
14
+ if (placeholders) {
15
+ Object.keys(placeholders).forEach((placeholder) => {
16
+ placeholders[placeholder] = personalizePlaceholder(placeholders[placeholder], variantId);
17
+ });
18
+ }
19
+ }
20
+ /**
21
+
22
+ * @param {Array} components components within placeholder
23
+ * @param {string} variantId variant id
24
+ * @returns {Array<ComponentRendering | HtmlElementRendering>} components with personalization applied
25
+ */
26
+ export function personalizePlaceholder(components, variantId) {
27
+ return components
28
+ .map((component) => {
29
+ const rendering = component;
30
+ if (rendering.experiences !== undefined) {
31
+ return personalizeComponent(rendering, variantId);
32
+ }
33
+ else if (rendering.placeholders) {
34
+ const placeholders = rendering.placeholders;
35
+ Object.keys(placeholders).forEach((placeholder) => {
36
+ placeholders[placeholder] = personalizePlaceholder(placeholders[placeholder], variantId);
37
+ });
38
+ }
39
+ return component;
40
+ })
41
+ .filter(Boolean);
42
+ }
43
+ /**
44
+ * @param {ComponentRenderingWithExperiences} component component with experiences
45
+ * @param {string} variantId variant id
46
+ * @returns {ComponentRendering | null} component with personalization applied or null if hidden
47
+ */
48
+ export function personalizeComponent(component, variantId) {
49
+ const variant = component.experiences[variantId];
50
+ if (variant === undefined && component.componentName === undefined) {
51
+ // DEFAULT IS HIDDEN
52
+ return null;
53
+ }
54
+ else if (variant && variant.componentName === null && variant.dataSource === null) {
55
+ // HIDDEN
56
+ return null;
57
+ }
58
+ else if (variant) {
59
+ component = variant;
60
+ }
61
+ if (!component.placeholders)
62
+ return component;
63
+ Object.keys(component === null || component === void 0 ? void 0 : component.placeholders).forEach((placeholder) => {
64
+ if (component.placeholders) {
65
+ component.placeholders[placeholder] = personalizePlaceholder(component.placeholders[placeholder], variantId);
66
+ }
67
+ });
68
+ return component;
69
+ }
@@ -0,0 +1,85 @@
1
+ export const DEFAULT_VARIANT = '_default';
2
+ export const VARIANT_PREFIX = '_variantId_';
3
+ /**
4
+ * Get a personalized rewrite path for given pathname
5
+ * @param {string} pathname the pathname
6
+ * @param {PersonalizedRewriteData} data the personalize data to include in the rewrite
7
+ * @returns {string} the rewrite path
8
+ */
9
+ export function getPersonalizedRewrite(pathname, data) {
10
+ const path = pathname.startsWith('/') ? pathname : '/' + pathname;
11
+ return `/${VARIANT_PREFIX}${data.variantId}${path}`;
12
+ }
13
+ /**
14
+ * Get personalize data from the rewrite path
15
+ * @param {string} pathname the pathname
16
+ * @returns {PersonalizedRewriteData} the personalize data from the rewrite
17
+ */
18
+ export function getPersonalizedRewriteData(pathname) {
19
+ const data = {
20
+ variantId: DEFAULT_VARIANT,
21
+ };
22
+ const path = pathname.endsWith('/') ? pathname : pathname + '/';
23
+ const result = path.match(`${VARIANT_PREFIX}(.*?)\\/`);
24
+ if (result) {
25
+ data.variantId = result[1];
26
+ }
27
+ return data;
28
+ }
29
+ /**
30
+ * Normalize a personalized rewrite path (remove personalize data)
31
+ * @param {string} pathname the pathname
32
+ * @returns {string} the pathname with personalize data removed
33
+ */
34
+ export function normalizePersonalizedRewrite(pathname) {
35
+ if (!pathname.includes(VARIANT_PREFIX)) {
36
+ return pathname;
37
+ }
38
+ const result = pathname.match(`${VARIANT_PREFIX}.*?(?:\\/|$)`);
39
+ return result === null ? pathname : pathname.replace(result[0], '');
40
+ }
41
+ /**
42
+ * Static utility class for Sitecore CDP
43
+ */
44
+ export class CdpHelper {
45
+ /**
46
+ * Gets the page variant id for CDP in the required format
47
+ * @param {string} pageId the page id
48
+ * @param {string} language the language
49
+ * @param {string} variantId the variant id
50
+ * @param {string} [scope] the scope value
51
+ * @returns {string} the formatted page variant id
52
+ */
53
+ static getPageVariantId(pageId, language, variantId, scope) {
54
+ const formattedPageId = pageId.replace(/[{}-]/g, '');
55
+ const formattedLanguage = language.replace('-', '_');
56
+ const scopeId = scope ? `${this.normalizeScope(scope)}_` : '';
57
+ let formattedVariantId = variantId;
58
+ if (!variantId || variantId === DEFAULT_VARIANT) {
59
+ formattedVariantId = 'default';
60
+ }
61
+ return `${scopeId}${formattedPageId}_${formattedLanguage}_${formattedVariantId}`.toLowerCase();
62
+ }
63
+ /**
64
+ * Gets the content id for CDP in the required format `embedded_[<scope>_]<id>_<lang>`
65
+ * @param {string} pageId the page id
66
+ * @param {string} language the language
67
+ * @param {string} [scope] the scope value
68
+ * @returns {string} the content id
69
+ */
70
+ static getContentId(pageId, language, scope) {
71
+ const formattedPageId = pageId.replace(/[{}-]/g, '');
72
+ const formattedLanguage = language.replace('-', '_');
73
+ const scopeId = scope ? `${this.normalizeScope(scope)}_` : '';
74
+ return `embedded_${scopeId}${formattedPageId}_${formattedLanguage}`.toLowerCase();
75
+ }
76
+ /**
77
+ * Normalizes the scope from the given string value
78
+ * Removes all non-alphanumeric characters
79
+ * @param {string} [scope] the scope value
80
+ * @returns {string} normalized scope value
81
+ */
82
+ static normalizeScope(scope) {
83
+ return (scope === null || scope === void 0 ? void 0 : scope.replace(/[^a-zA-Z0-9]+/g, '')) || '';
84
+ }
85
+ }
@@ -0,0 +1,79 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { siteNameError } from '../constants';
11
+ import debug from '../debug';
12
+ // The default query for request error handling
13
+ const defaultQuery = /* GraphQL */ `
14
+ query ErrorPagesQuery($siteName: String!, $language: String!) {
15
+ site {
16
+ siteInfo(site: $siteName) {
17
+ errorHandling(language: $language) {
18
+ notFoundPage {
19
+ rendered
20
+ }
21
+ notFoundPagePath
22
+ serverErrorPage {
23
+ rendered
24
+ }
25
+ serverErrorPagePath
26
+ }
27
+ }
28
+ }
29
+ }
30
+ `;
31
+ /**
32
+ * Service that fetch the error pages data using Sitecore's GraphQL API.
33
+ */
34
+ export class GraphQLErrorPagesService {
35
+ /**
36
+ * Creates an instance of graphQL error pages service with the provided options
37
+ * @param {GraphQLErrorPagesServiceConfig} options instance
38
+ */
39
+ constructor(options) {
40
+ this.options = options;
41
+ this.graphQLClient = this.getGraphQLClient();
42
+ }
43
+ get query() {
44
+ return defaultQuery;
45
+ }
46
+ /**
47
+ * Fetch list of error pages for the site
48
+ * @returns {ErrorPages} list of url's error pages
49
+ * @throws {Error} if the siteName is empty.
50
+ */
51
+ fetchErrorPages() {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ const siteName = this.options.siteName;
54
+ const language = this.options.language;
55
+ if (!siteName) {
56
+ throw new Error(siteNameError);
57
+ }
58
+ return this.graphQLClient.request(this.query, {
59
+ siteName,
60
+ language,
61
+ })
62
+ .then((result) => result.site.siteInfo ? result.site.siteInfo.errorHandling : null)
63
+ .catch((e) => Promise.reject(e));
64
+ });
65
+ }
66
+ /**
67
+ * Gets a GraphQL client that can make requests to the API.
68
+ * @returns {GraphQLClient} implementation
69
+ */
70
+ getGraphQLClient() {
71
+ if (!this.options.clientFactory) {
72
+ throw new Error('You should provide a clientFactory.');
73
+ }
74
+ return this.options.clientFactory({
75
+ debugger: debug.errorpages,
76
+ retries: this.options.retries,
77
+ });
78
+ }
79
+ }
@@ -0,0 +1,96 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { siteNameError } from '../constants';
11
+ import debug from '../debug';
12
+ import { MemoryCacheClient } from '../cache-client';
13
+ export const REDIRECT_TYPE_301 = 'REDIRECT_301';
14
+ export const REDIRECT_TYPE_302 = 'REDIRECT_302';
15
+ export const REDIRECT_TYPE_SERVER_TRANSFER = 'SERVER_TRANSFER';
16
+ // The default query for request redirects of site
17
+ const defaultQuery = /* GraphQL */ `
18
+ query RedirectsQuery($siteName: String!) {
19
+ site {
20
+ siteInfo(site: $siteName) {
21
+ redirects {
22
+ pattern
23
+ target
24
+ redirectType
25
+ isQueryStringPreserved
26
+ locale
27
+ }
28
+ }
29
+ }
30
+ }
31
+ `;
32
+ /**
33
+ * The GraphQLRedirectsService class is used to query the JSS redirects using Graphql endpoint
34
+ */
35
+ export class GraphQLRedirectsService {
36
+ /**
37
+ * Creates an instance of graphQL redirects service with the provided options
38
+ * @param {GraphQLRedirectsServiceConfig} options instance
39
+ */
40
+ constructor(options) {
41
+ this.options = options;
42
+ this.graphQLClient = this.getGraphQLClient();
43
+ this.cache = this.getCacheClient();
44
+ }
45
+ get query() {
46
+ return defaultQuery;
47
+ }
48
+ /**
49
+ * Fetch an array of redirects from API
50
+ * @param {string} siteName site name
51
+ * @returns Promise<RedirectInfo[]>
52
+ * @throws {Error} if the siteName is empty.
53
+ */
54
+ fetchRedirects(siteName) {
55
+ var _a, _b;
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ if (!siteName) {
58
+ throw new Error(siteNameError);
59
+ }
60
+ const cacheKey = `redirects-${siteName}`;
61
+ let data = this.cache.getCacheValue(cacheKey);
62
+ if (!data) {
63
+ data = yield this.graphQLClient.request(this.query, {
64
+ siteName,
65
+ });
66
+ this.cache.setCacheValue(cacheKey, data);
67
+ }
68
+ return ((_b = (_a = data === null || data === void 0 ? void 0 : data.site) === null || _a === void 0 ? void 0 : _a.siteInfo) === null || _b === void 0 ? void 0 : _b.redirects) || [];
69
+ });
70
+ }
71
+ /**
72
+ * Gets a GraphQL client that can make requests to the API.
73
+ * @returns {GraphQLClient} implementation
74
+ */
75
+ getGraphQLClient() {
76
+ if (!this.options.clientFactory) {
77
+ throw new Error('You should provide a clientFactory.');
78
+ }
79
+ return this.options.clientFactory({
80
+ debugger: debug.redirects,
81
+ fetch: this.options.fetch,
82
+ });
83
+ }
84
+ /**
85
+ * Gets cache client implementation
86
+ * Override this method if custom cache needs to be used
87
+ * @returns CacheClient instance
88
+ */
89
+ getCacheClient() {
90
+ var _a, _b;
91
+ return new MemoryCacheClient({
92
+ cacheEnabled: (_a = this.options.cacheEnabled) !== null && _a !== void 0 ? _a : true,
93
+ cacheTimeout: (_b = this.options.cacheTimeout) !== null && _b !== void 0 ? _b : 10,
94
+ });
95
+ }
96
+ }