@sitecore-content-sdk/core 0.1.0-beta.1

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 (160) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +11 -0
  3. package/dist/cjs/cache-client.js +54 -0
  4. package/dist/cjs/constants.js +13 -0
  5. package/dist/cjs/data-fetcher.js +33 -0
  6. package/dist/cjs/debug.js +43 -0
  7. package/dist/cjs/editing/component-library.js +104 -0
  8. package/dist/cjs/editing/graphql-editing-service.js +186 -0
  9. package/dist/cjs/editing/index.js +23 -0
  10. package/dist/cjs/editing/models.js +23 -0
  11. package/dist/cjs/editing/rest-component-layout-service.js +76 -0
  12. package/dist/cjs/editing/utils.js +86 -0
  13. package/dist/cjs/graphql/app-root-query.js +73 -0
  14. package/dist/cjs/graphql/graphql-edge-proxy.js +21 -0
  15. package/dist/cjs/graphql/index.js +13 -0
  16. package/dist/cjs/graphql/search-service.js +61 -0
  17. package/dist/cjs/graphql-request-client.js +152 -0
  18. package/dist/cjs/i18n/dictionary-service.js +45 -0
  19. package/dist/cjs/i18n/graphql-dictionary-service.js +136 -0
  20. package/dist/cjs/i18n/index.js +7 -0
  21. package/dist/cjs/index.js +55 -0
  22. package/dist/cjs/layout/content-styles.js +70 -0
  23. package/dist/cjs/layout/graphql-layout-service.js +86 -0
  24. package/dist/cjs/layout/index.js +24 -0
  25. package/dist/cjs/layout/layout-service.js +9 -0
  26. package/dist/cjs/layout/models.js +35 -0
  27. package/dist/cjs/layout/themes.js +74 -0
  28. package/dist/cjs/layout/utils.js +110 -0
  29. package/dist/cjs/media/index.js +38 -0
  30. package/dist/cjs/media/media-api.js +96 -0
  31. package/dist/cjs/models.js +2 -0
  32. package/dist/cjs/native-fetcher.js +200 -0
  33. package/dist/cjs/personalize/graphql-personalize-service.js +114 -0
  34. package/dist/cjs/personalize/index.js +14 -0
  35. package/dist/cjs/personalize/layout-personalizer.js +97 -0
  36. package/dist/cjs/personalize/utils.js +136 -0
  37. package/dist/cjs/site/graphql-error-pages-service.js +89 -0
  38. package/dist/cjs/site/graphql-redirects-service.js +105 -0
  39. package/dist/cjs/site/graphql-robots-service.js +83 -0
  40. package/dist/cjs/site/graphql-siteinfo-service.js +107 -0
  41. package/dist/cjs/site/graphql-sitemap-service.js +93 -0
  42. package/dist/cjs/site/index.js +22 -0
  43. package/dist/cjs/site/site-resolver.js +79 -0
  44. package/dist/cjs/site/utils.js +43 -0
  45. package/dist/cjs/utils/env.js +26 -0
  46. package/dist/cjs/utils/index.js +20 -0
  47. package/dist/cjs/utils/is-server.js +10 -0
  48. package/dist/cjs/utils/timeout-promise.js +31 -0
  49. package/dist/cjs/utils/utils.js +222 -0
  50. package/dist/esm/cache-client.js +50 -0
  51. package/dist/esm/constants.js +10 -0
  52. package/dist/esm/data-fetcher.js +28 -0
  53. package/dist/esm/debug.js +36 -0
  54. package/dist/esm/editing/component-library.js +98 -0
  55. package/dist/esm/editing/graphql-editing-service.js +179 -0
  56. package/dist/esm/editing/index.js +5 -0
  57. package/dist/esm/editing/models.js +20 -0
  58. package/dist/esm/editing/rest-component-layout-service.js +72 -0
  59. package/dist/esm/editing/utils.js +76 -0
  60. package/dist/esm/graphql/app-root-query.js +69 -0
  61. package/dist/esm/graphql/graphql-edge-proxy.js +16 -0
  62. package/dist/esm/graphql/index.js +4 -0
  63. package/dist/esm/graphql/search-service.js +57 -0
  64. package/dist/esm/graphql-request-client.js +144 -0
  65. package/dist/esm/i18n/dictionary-service.js +41 -0
  66. package/dist/esm/i18n/graphql-dictionary-service.js +129 -0
  67. package/dist/esm/i18n/index.js +2 -0
  68. package/dist/esm/index.js +9 -0
  69. package/dist/esm/layout/content-styles.js +62 -0
  70. package/dist/esm/layout/graphql-layout-service.js +79 -0
  71. package/dist/esm/layout/index.js +6 -0
  72. package/dist/esm/layout/layout-service.js +5 -0
  73. package/dist/esm/layout/models.js +32 -0
  74. package/dist/esm/layout/themes.js +69 -0
  75. package/dist/esm/layout/utils.js +102 -0
  76. package/dist/esm/media/index.js +2 -0
  77. package/dist/esm/media/media-api.js +86 -0
  78. package/dist/esm/models.js +1 -0
  79. package/dist/esm/native-fetcher.js +193 -0
  80. package/dist/esm/personalize/graphql-personalize-service.js +107 -0
  81. package/dist/esm/personalize/index.js +3 -0
  82. package/dist/esm/personalize/layout-personalizer.js +92 -0
  83. package/dist/esm/personalize/utils.js +128 -0
  84. package/dist/esm/site/graphql-error-pages-service.js +82 -0
  85. package/dist/esm/site/graphql-redirects-service.js +98 -0
  86. package/dist/esm/site/graphql-robots-service.js +76 -0
  87. package/dist/esm/site/graphql-siteinfo-service.js +100 -0
  88. package/dist/esm/site/graphql-sitemap-service.js +86 -0
  89. package/dist/esm/site/index.js +7 -0
  90. package/dist/esm/site/site-resolver.js +75 -0
  91. package/dist/esm/site/utils.js +37 -0
  92. package/dist/esm/utils/env.js +22 -0
  93. package/dist/esm/utils/index.js +3 -0
  94. package/dist/esm/utils/is-server.js +8 -0
  95. package/dist/esm/utils/timeout-promise.js +28 -0
  96. package/dist/esm/utils/utils.js +207 -0
  97. package/editing.d.ts +1 -0
  98. package/editing.js +1 -0
  99. package/graphql.d.ts +1 -0
  100. package/graphql.js +1 -0
  101. package/i18n.d.ts +1 -0
  102. package/i18n.js +1 -0
  103. package/layout.d.ts +1 -0
  104. package/layout.js +1 -0
  105. package/media.d.ts +1 -0
  106. package/media.js +1 -0
  107. package/package.json +76 -0
  108. package/personalize.d.ts +1 -0
  109. package/personalize.js +1 -0
  110. package/site.d.ts +1 -0
  111. package/site.js +1 -0
  112. package/types/cache-client.d.ts +64 -0
  113. package/types/constants.d.ts +7 -0
  114. package/types/data-fetcher.d.ts +34 -0
  115. package/types/debug.d.ts +26 -0
  116. package/types/editing/component-library.d.ts +48 -0
  117. package/types/editing/graphql-editing-service.d.ts +90 -0
  118. package/types/editing/index.d.ts +6 -0
  119. package/types/editing/models.d.ts +52 -0
  120. package/types/editing/rest-component-layout-service.d.ts +100 -0
  121. package/types/editing/utils.d.ts +70 -0
  122. package/types/graphql/app-root-query.d.ts +32 -0
  123. package/types/graphql/graphql-edge-proxy.d.ts +15 -0
  124. package/types/graphql/index.d.ts +4 -0
  125. package/types/graphql/search-service.d.ts +95 -0
  126. package/types/graphql-request-client.d.ts +159 -0
  127. package/types/i18n/dictionary-service.d.ts +56 -0
  128. package/types/i18n/graphql-dictionary-service.d.ts +94 -0
  129. package/types/i18n/index.d.ts +2 -0
  130. package/types/index.d.ts +8 -0
  131. package/types/layout/content-styles.d.ts +18 -0
  132. package/types/layout/graphql-layout-service.d.ts +58 -0
  133. package/types/layout/index.d.ts +6 -0
  134. package/types/layout/layout-service.d.ts +19 -0
  135. package/types/layout/models.d.ts +145 -0
  136. package/types/layout/themes.d.ts +11 -0
  137. package/types/layout/utils.d.ts +40 -0
  138. package/types/media/index.d.ts +2 -0
  139. package/types/media/media-api.d.ts +55 -0
  140. package/types/models.d.ts +6 -0
  141. package/types/native-fetcher.d.ts +121 -0
  142. package/types/personalize/graphql-personalize-service.d.ts +80 -0
  143. package/types/personalize/index.d.ts +3 -0
  144. package/types/personalize/layout-personalizer.d.ts +27 -0
  145. package/types/personalize/utils.d.ts +69 -0
  146. package/types/site/graphql-error-pages-service.d.ts +57 -0
  147. package/types/site/graphql-redirects-service.d.ts +68 -0
  148. package/types/site/graphql-robots-service.d.ts +49 -0
  149. package/types/site/graphql-siteinfo-service.d.ts +70 -0
  150. package/types/site/graphql-sitemap-service.d.ts +55 -0
  151. package/types/site/index.d.ts +7 -0
  152. package/types/site/site-resolver.d.ts +27 -0
  153. package/types/site/utils.d.ts +24 -0
  154. package/types/utils/env.d.ts +7 -0
  155. package/types/utils/index.d.ts +3 -0
  156. package/types/utils/is-server.d.ts +6 -0
  157. package/types/utils/timeout-promise.d.ts +17 -0
  158. package/types/utils/utils.d.ts +71 -0
  159. package/utils.d.ts +1 -0
  160. package/utils.js +1 -0
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Determines whether the current execution context is server-side
5
+ * @returns true if executing server-side
6
+ */
7
+ function isServer() {
8
+ return !(typeof window !== 'undefined' && window.document);
9
+ }
10
+ exports.default = isServer;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * A helper to assign timeouts to fetch or other promises
5
+ * Useful in nextjs middleware until fetch.signal is fully supported by Vercel edge functions
6
+ */
7
+ class TimeoutPromise {
8
+ constructor(timeout) {
9
+ this.timeout = timeout;
10
+ this.timeoutId = undefined;
11
+ }
12
+ /**
13
+ * Creates a timeout promise
14
+ */
15
+ get start() {
16
+ return new Promise((_, reject) => {
17
+ this.timeoutId = setTimeout(() => {
18
+ const abortError = new Error(`Request timed out, timeout of ${this.timeout}ms is exceeded`);
19
+ abortError.name = 'AbortError';
20
+ reject(abortError);
21
+ }, this.timeout);
22
+ });
23
+ }
24
+ /**
25
+ * Clears the timeout from timeout promise
26
+ */
27
+ clear() {
28
+ this.timeoutId && clearTimeout(this.timeoutId);
29
+ }
30
+ }
31
+ exports.default = TimeoutPromise;
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.mergeURLSearchParams = exports.escapeNonSpecialQuestionMarks = exports.areURLSearchParamsEqual = exports.isRegexOrUrl = exports.enforceCors = exports.getAllowedOriginsFromEnv = exports.isTimeoutError = exports.isAbsoluteUrl = void 0;
7
+ exports.resolveUrl = resolveUrl;
8
+ const is_server_1 = __importDefault(require("./is-server"));
9
+ /**
10
+ * note: encodeURIComponent is available via browser (window) or natively in node.js
11
+ * if you use another js engine for server-side rendering you may not have native encodeURIComponent
12
+ * and would then need to install a package for that functionality
13
+ * @param {ParsedUrlQueryInput} params query string parameters
14
+ * @returns {string} query string
15
+ */
16
+ function getQueryString(params) {
17
+ return Object.keys(params)
18
+ .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(String(params[k]))}`)
19
+ .join('&');
20
+ }
21
+ /**
22
+ * Resolves a base URL that may contain query string parameters and an additional set of query
23
+ * string parameters into a unified string representation.
24
+ * @param {string} urlBase the base URL that may contain query string parameters
25
+ * @param {ParsedUrlQueryInput} params query string parameters
26
+ * @returns a URL string
27
+ * @throws {RangeError} if the provided url is an empty string
28
+ */
29
+ function resolveUrl(urlBase, params = {}) {
30
+ if (!urlBase) {
31
+ throw new RangeError('url must be a non-empty string');
32
+ }
33
+ // This is a better way to work with URLs since it handles different user input
34
+ // edge cases. This works in Node and all browser except IE11.
35
+ // https://developer.mozilla.org/en-US/docs/Web/API/URL
36
+ // TODO: Verify our browser support requirements.
37
+ if ((0, is_server_1.default)()) {
38
+ const url = new URL(urlBase);
39
+ for (const key in params) {
40
+ if ({}.hasOwnProperty.call(params, key)) {
41
+ url.searchParams.append(key, String(params[key]));
42
+ }
43
+ }
44
+ const result = url.toString();
45
+ return result;
46
+ }
47
+ const qs = getQueryString(params);
48
+ const result = urlBase.indexOf('?') !== -1 ? `${urlBase}&${qs}` : `${urlBase}?${qs}`;
49
+ return result;
50
+ }
51
+ const isAbsoluteUrl = (url) => {
52
+ if (!url) {
53
+ return false;
54
+ }
55
+ if (typeof url !== 'string') {
56
+ throw new TypeError('Expected a string');
57
+ }
58
+ return /^[a-z][a-z0-9+.-]*:/.test(url);
59
+ };
60
+ exports.isAbsoluteUrl = isAbsoluteUrl;
61
+ /**
62
+ * Indicates whether the error is a timeout error
63
+ * @param {unknown} error error
64
+ * @returns {boolean} is timeout error
65
+ */
66
+ const isTimeoutError = (error) => {
67
+ var _a;
68
+ return ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 408 || error.name === 'AbortError';
69
+ };
70
+ exports.isTimeoutError = isTimeoutError;
71
+ /**
72
+ * Converts a string value in a regex pattern allowing wildcard matching
73
+ * @param {string} pattern input with wildcards i.e. site.*.com
74
+ * @returns {string} modified string that can be used as regexp input
75
+ */
76
+ const convertToWildcardRegex = (pattern) => {
77
+ return ('^' +
78
+ pattern
79
+ .replace(/\//g, '\\/')
80
+ .replace(/\./g, '\\.')
81
+ .replace(/\*/g, '.*') +
82
+ '$');
83
+ };
84
+ /**
85
+ * Gets allowed origins from JSS_ALLOWED_ORIGINS env variable
86
+ * @returns {string[]} list of allowed origins from JSS_ALLOWED_ORIGINS env variable
87
+ */
88
+ const getAllowedOriginsFromEnv = () => process.env.JSS_ALLOWED_ORIGINS
89
+ ? process.env.JSS_ALLOWED_ORIGINS.replace(' ', '').split(',')
90
+ : [];
91
+ exports.getAllowedOriginsFromEnv = getAllowedOriginsFromEnv;
92
+ /**
93
+ * Tests origin from incoming request against allowed origins list that can be
94
+ * set in JSS's JSS_ALLOWED_ORIGINS env variable, passed via allowedOrigins param and/or
95
+ * be already set in Access-Control-Allow-Origin by other logic.
96
+ * Applies Access-Control-Allow-Origin and Access-Control-Allow-Methods on match
97
+ * Also applies Access-Control-Allow-Headers for preflight requests
98
+ * @param {IncomingMessage} req incoming request
99
+ * @param {OutgoingMessage} res response to set CORS headers for
100
+ * @param {string[]} [allowedOrigins] additional list of origins to test against
101
+ * @returns true if incoming origin matches the allowed lists, false when it does not
102
+ */
103
+ const enforceCors = (req, res, allowedOrigins) => {
104
+ // origin in not present for non-CORS requests (e.g. server-side) - so we skip the checks
105
+ if (!req.headers.origin) {
106
+ return true;
107
+ }
108
+ // 3 sources of allowed origins are considered:
109
+ // the env value
110
+ const defaultAllowedOrigins = (0, exports.getAllowedOriginsFromEnv)();
111
+ // the allowedOrigins prop
112
+ allowedOrigins = defaultAllowedOrigins.concat(allowedOrigins || []);
113
+ // and the existing CORS header, if present (i.e. set by nextjs config)
114
+ const presetCors = res.getHeader('Access-Control-Allow-Origin');
115
+ if (presetCors) {
116
+ allowedOrigins.push(presetCors);
117
+ }
118
+ const origin = req.headers.origin;
119
+ if (origin &&
120
+ allowedOrigins.some((allowedOrigin) => origin === allowedOrigin || new RegExp(convertToWildcardRegex(allowedOrigin)).test(origin))) {
121
+ res.setHeader('Access-Control-Allow-Origin', origin);
122
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE, PUT, PATCH');
123
+ // set the allowed headers for preflight requests
124
+ if (req.method === 'OPTIONS') {
125
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
126
+ }
127
+ return true;
128
+ }
129
+ return false;
130
+ };
131
+ exports.enforceCors = enforceCors;
132
+ /**
133
+ * Determines whether the given input is a regular expression or resembles a URL.
134
+ * @param {string} input - The input string to evaluate.
135
+ * @returns {'regex' | 'url'} - Returns 'url' if the input looks like a URL, otherwise 'regex'.
136
+ */
137
+ const isRegexOrUrl = (input) => {
138
+ // Remove the trailing slash.
139
+ input = input.slice(0, -1);
140
+ // Check if the string resembles a URL.
141
+ const isUrlLike = /^\/[a-zA-Z0-9\-\/]+(\?([a-zA-Z0-9\-_]+=[a-zA-Z0-9\-_]+)(&[a-zA-Z0-9\-_]+=[a-zA-Z0-9\-_]+)*)?$/.test(input);
142
+ if (isUrlLike) {
143
+ return 'url';
144
+ }
145
+ // If it doesn't resemble a URL, it's likely a regular expression.
146
+ return 'regex';
147
+ };
148
+ exports.isRegexOrUrl = isRegexOrUrl;
149
+ /**
150
+ * Compares two URLSearchParams objects to determine if they are equal.
151
+ * @param {URLSearchParams} params1 - The first set of URL search parameters.
152
+ * @param {URLSearchParams} params2 - The second set of URL search parameters.
153
+ * @returns {boolean} - Returns true if the parameters are equal, otherwise false.
154
+ */
155
+ const areURLSearchParamsEqual = (params1, params2) => {
156
+ // Generates a sorted string representation of URL search parameters.
157
+ const getSortedParamsString = (params) => {
158
+ return [...params.entries()]
159
+ .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
160
+ .map(([key, value]) => `${key}=${value}`)
161
+ .join('&');
162
+ };
163
+ // Compare the sorted strings of both parameter sets.
164
+ return getSortedParamsString(params1) === getSortedParamsString(params2);
165
+ };
166
+ exports.areURLSearchParamsEqual = areURLSearchParamsEqual;
167
+ /**
168
+ * Escapes non-special "?" characters in a string or regex.
169
+ * - For regular strings, it escapes all unescaped "?" characters by adding a backslash (`\`).
170
+ * - For regex patterns (strings enclosed in `/.../`), it analyzes each "?" to determine if it has special meaning
171
+ * (e.g., `?` in `(abc)?`, `.*?`, `(?!...)`) or is just a literal character. Only literal "?" characters are escaped.
172
+ * @param {string} input - The input string or regex pattern.
173
+ * @returns {string} - The modified string or regex with non-special "?" characters escaped.
174
+ */
175
+ const escapeNonSpecialQuestionMarks = (input) => {
176
+ const regexPattern = /(?<!\\)\?/g; // Match unescaped "?" characters
177
+ const negativeLookaheadPattern = /\(\?!$/; // Detect the start of a Negative Lookahead pattern
178
+ const specialRegexSymbols = /[.*+)\[\]|\(]$/; // Check for special regex symbols before "?"
179
+ let result = '';
180
+ let lastIndex = 0;
181
+ let match;
182
+ while ((match = regexPattern.exec(input)) !== null) {
183
+ const index = match.index; // Position of the "?" in the string
184
+ const before = input.slice(lastIndex, index); // Context before the "?"
185
+ // Check if "?" is part of a Negative Lookahead
186
+ const isNegativeLookahead = negativeLookaheadPattern.test(before.slice(-3));
187
+ // Check if "?" follows a special regex symbol
188
+ const isSpecialRegexSymbol = specialRegexSymbols.test(before.slice(-1));
189
+ if (isNegativeLookahead || isSpecialRegexSymbol) {
190
+ // If it's a special case, keep the "?" as is
191
+ result += input.slice(lastIndex, index + 1);
192
+ }
193
+ else {
194
+ // Otherwise, escape the "?"
195
+ result += input.slice(lastIndex, index) + '\\?';
196
+ }
197
+ lastIndex = index + 1; // Move to the next part of the string
198
+ }
199
+ // Append the remaining part of the string
200
+ result += input.slice(lastIndex);
201
+ return result;
202
+ };
203
+ exports.escapeNonSpecialQuestionMarks = escapeNonSpecialQuestionMarks;
204
+ /**
205
+ * Merges two URLSearchParams objects. If both objects contain the same key, the value from the second object overrides the first.
206
+ * @param {URLSearchParams} params1 - The first set of URL search parameters.
207
+ * @param {URLSearchParams} params2 - The second set of URL search parameters.
208
+ * @returns {string} - A string representation of the merged URL search parameters.
209
+ */
210
+ const mergeURLSearchParams = (params1, params2) => {
211
+ const merged = new URLSearchParams();
212
+ // Add all keys and values from the first object.
213
+ for (const [key, value] of params1.entries()) {
214
+ merged.set(key, value);
215
+ }
216
+ // Add all keys and values from the second object, replacing existing ones.
217
+ for (const [key, value] of params2.entries()) {
218
+ merged.set(key, value);
219
+ }
220
+ return merged.toString();
221
+ };
222
+ exports.mergeURLSearchParams = mergeURLSearchParams;
@@ -0,0 +1,50 @@
1
+ import { Cache } from 'memory-cache';
2
+ /**
3
+ * Default cache configuration
4
+ */
5
+ const DEFAULTS = Object.freeze({
6
+ cacheTimeout: 60,
7
+ cacheEnabled: true,
8
+ });
9
+ /**
10
+ * A cache client that uses the 'memory-cache' library (https://github.com/ptarjan/node-cache).
11
+ * This class is meant to be extended or used as a mixin; it's not meant to be used directly.
12
+ * @template T The type of data being cached.
13
+ * @mixin
14
+ */
15
+ export class MemoryCacheClient {
16
+ /**
17
+ * Initializes a new instance of @see MemoryCacheClient using the provided @see CacheOptions
18
+ * @param {CacheOptions} options Configuration options
19
+ */
20
+ constructor(options) {
21
+ var _a;
22
+ this.options = options;
23
+ this.cache = new Cache();
24
+ this.options.cacheTimeout = ((_a = this.options.cacheTimeout) !== null && _a !== void 0 ? _a : DEFAULTS.cacheTimeout) * 1000;
25
+ if (this.options.cacheEnabled === undefined) {
26
+ this.options.cacheEnabled = DEFAULTS.cacheEnabled;
27
+ }
28
+ }
29
+ /**
30
+ * Retrieves a value from the cache.
31
+ * @template T The type of data being cached.
32
+ * @param {string} key The cache key.
33
+ * @returns The cache value as {T}, or null if the specified key is not found in the cache.
34
+ */
35
+ getCacheValue(key) {
36
+ return this.options.cacheEnabled ? this.cache.get(key) : null;
37
+ }
38
+ /**
39
+ * Adds a value to the cache for the specified cache key.
40
+ * @template T The type of data being cached.
41
+ * @param {string} key The cache key.
42
+ * @param {T} value The value to cache.
43
+ * @returns The value added to the cache.
44
+ */
45
+ setCacheValue(key, value) {
46
+ return this.options.cacheEnabled
47
+ ? this.cache.put(key, value, this.options.cacheTimeout)
48
+ : value;
49
+ }
50
+ }
@@ -0,0 +1,10 @@
1
+ export var SitecoreTemplateId;
2
+ (function (SitecoreTemplateId) {
3
+ // /sitecore/templates/Foundation/JavaScript Services/App
4
+ SitecoreTemplateId["JssApp"] = "061cba1554744b918a0617903b102b82";
5
+ // /sitecore/templates/System/Dictionary/Dictionary entry
6
+ SitecoreTemplateId["DictionaryEntry"] = "6d1cd89719364a3aa511289a94c2a7b1";
7
+ })(SitecoreTemplateId || (SitecoreTemplateId = {}));
8
+ export const siteNameError = 'The siteName cannot be empty';
9
+ export const SITECORE_EDGE_URL_DEFAULT = 'https://edge-platform.sitecorecloud.io';
10
+ export const HIDDEN_RENDERING_NAME = 'Hidden Rendering';
@@ -0,0 +1,28 @@
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 { resolveUrl } from './utils/utils';
11
+ export class ResponseError extends Error {
12
+ constructor(message, response) {
13
+ super(message);
14
+ Object.setPrototypeOf(this, ResponseError.prototype);
15
+ this.response = response;
16
+ }
17
+ }
18
+ /**
19
+ * @param {string} url the URL to request; may include query string
20
+ * @param {HttpDataFetcher<T> | NativeDataFetcherFunction<T>} fetcher the fetcher to use to perform the request
21
+ * @param {ParsedUrlQueryInput} params the query string parameters to send with the request
22
+ */
23
+ export function fetchData(url_1, fetcher_1) {
24
+ return __awaiter(this, arguments, void 0, function* (url, fetcher, params = {}) {
25
+ const response = yield fetcher(resolveUrl(url, params));
26
+ return response.data;
27
+ });
28
+ }
@@ -0,0 +1,36 @@
1
+ var _a;
2
+ import debug from 'debug';
3
+ import isServer from './utils/is-server';
4
+ const rootNamespace = 'core';
5
+ // On server/node side, allow switching from the built-in
6
+ // `%o` (pretty-print single line) and `%O` (pretty-print multiple line)
7
+ // with a `DEBUG_MULTILINE` environment variable.
8
+ if (isServer() &&
9
+ ((_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.DEBUG_MULTILINE) === 'true' &&
10
+ debug.formatters.o &&
11
+ debug.formatters.O) {
12
+ debug.formatters.o = debug.formatters.O;
13
+ }
14
+ /**
15
+ * Enable debug logging dynamically
16
+ * @param {string} namespaces space-separated list of namespaces to enable
17
+ */
18
+ export const enableDebug = (namespaces) => debug.enable(namespaces);
19
+ /**
20
+ * Default Sitecore JSS 'debug' module debuggers. Uses namespace prefix 'core:'.
21
+ * See {@link https://www.npmjs.com/package/debug} for details.
22
+ */
23
+ export default {
24
+ common: debug(`${rootNamespace}:common`),
25
+ http: debug(`${rootNamespace}:http`),
26
+ layout: debug(`${rootNamespace}:layout`),
27
+ dictionary: debug(`${rootNamespace}:dictionary`),
28
+ editing: debug(`${rootNamespace}:editing`),
29
+ sitemap: debug(`${rootNamespace}:sitemap`),
30
+ multisite: debug(`${rootNamespace}:multisite`),
31
+ robots: debug(`${rootNamespace}:robots`),
32
+ redirects: debug(`${rootNamespace}:redirects`),
33
+ personalize: debug(`${rootNamespace}:personalize`),
34
+ errorpages: debug(`${rootNamespace}:errorpages`),
35
+ proxy: debug(`${rootNamespace}:proxy`),
36
+ };
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Event to be sent when report status to component library
3
+ */
4
+ export const COMPONENT_LIBRARY_STATUS_EVENT_NAME = 'component:status';
5
+ /**
6
+ * Enumeration of statuses for the component library.
7
+ */
8
+ export var ComponentLibraryStatus;
9
+ (function (ComponentLibraryStatus) {
10
+ ComponentLibraryStatus["READY"] = "ready";
11
+ ComponentLibraryStatus["RENDERED"] = "rendered";
12
+ })(ComponentLibraryStatus || (ComponentLibraryStatus = {}));
13
+ /**
14
+ * Adds the browser-side event handler for 'component:update' message used in Component Library
15
+ * The event should update a component on page by uid, with fields and params from event args
16
+ * @param {ComponentRendering} rootComponent root component displayed for Component Library page
17
+ * @param {Function} successCallback callback to be called after successful component update
18
+ */
19
+ export const addComponentUpdateHandler = (rootComponent, successCallback) => {
20
+ if (!window)
21
+ return;
22
+ const handler = (e) => updateComponentHandler(e, rootComponent, successCallback);
23
+ window.addEventListener('message', handler);
24
+ // the power to remove handler outside of this function, if needed
25
+ const unsubscribe = () => {
26
+ window.removeEventListener('message', handler);
27
+ };
28
+ return unsubscribe;
29
+ };
30
+ const validateOrigin = (event) => {
31
+ // TODO: use `EDITING_ALLOWED_ORIGINS.concat(getAllowedOriginsFromEnv())` later
32
+ // nextjs's JSS_ALLOWED_ORIGINS is not available on the client, need to use NEXT_PUBLIC_ variable, but it's a breaking change for Deploy
33
+ const allowedOrigins = ['*'];
34
+ return allowedOrigins.some((origin) => origin === event.origin ||
35
+ new RegExp('^' + origin.replace('.', '\\.').replace(/\*/g, '.*') + '$').test(event.origin));
36
+ };
37
+ export const updateComponentHandler = (e, rootComponent, successCallback) => {
38
+ var _a;
39
+ const eventArgs = e.data;
40
+ if (!e.origin || !eventArgs || eventArgs.name !== 'component:update') {
41
+ // avoid extra noise in logs
42
+ if (!validateOrigin(e)) {
43
+ console.debug('Component Library: event skipped: message %s from origin %s', eventArgs.name, e.origin);
44
+ }
45
+ return;
46
+ }
47
+ if (!((_a = eventArgs.details) === null || _a === void 0 ? void 0 : _a.uid)) {
48
+ console.debug('Received component:update event without uid, aborting event handler...');
49
+ return;
50
+ }
51
+ const findComponent = (root) => {
52
+ var _a, _b;
53
+ if (((_a = root.uid) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === ((_b = eventArgs.details) === null || _b === void 0 ? void 0 : _b.uid.toLowerCase()))
54
+ return root;
55
+ if (root.placeholders) {
56
+ for (const plhName of Object.keys(root.placeholders)) {
57
+ for (const rendering of root.placeholders[plhName]) {
58
+ const result = findComponent(rendering);
59
+ if (result)
60
+ return result;
61
+ }
62
+ }
63
+ }
64
+ return null;
65
+ };
66
+ const updateComponent = findComponent(rootComponent);
67
+ if (updateComponent) {
68
+ console.debug('Found component with uid %s to update. Update fields: %o. Update params: %o.', eventArgs.details.uid, eventArgs.details.fields, eventArgs.details.params);
69
+ if (eventArgs.details.fields) {
70
+ updateComponent.fields = Object.assign(Object.assign({}, updateComponent.fields), eventArgs.details.fields);
71
+ }
72
+ if (eventArgs.details.params) {
73
+ updateComponent.params = Object.assign(Object.assign({}, updateComponent.params), eventArgs.details.params);
74
+ }
75
+ if (successCallback)
76
+ successCallback(rootComponent);
77
+ }
78
+ else {
79
+ console.debug('Rendering with uid %s not found', eventArgs.details.uid);
80
+ }
81
+ // strictly for testing
82
+ return rootComponent;
83
+ };
84
+ /**
85
+ * Generates a ComponentLibraryStatusEvent with the given status and uid.
86
+ * @param {ComponentLibraryStatus} status - The status of rendering.
87
+ * @param {string} uid - The unique identifier for the event.
88
+ * @returns An object representing the ComponentLibraryStatusEvent.
89
+ */
90
+ export function getComponentLibraryStatusEvent(status, uid) {
91
+ return {
92
+ name: COMPONENT_LIBRARY_STATUS_EVENT_NAME,
93
+ message: {
94
+ status,
95
+ uid,
96
+ },
97
+ };
98
+ }
@@ -0,0 +1,179 @@
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 { LayoutKind } from './models';
12
+ /**
13
+ * The dictionary query default page size.
14
+ */
15
+ const PAGE_SIZE = 1000;
16
+ /**
17
+ * GraphQL query for fetching editing data.
18
+ */
19
+ export const query = /* GraphQL */ `
20
+ query EditingQuery(
21
+ $siteName: String!
22
+ $itemId: String!
23
+ $language: String!
24
+ $version: String
25
+ $after: String
26
+ $pageSize: Int = ${PAGE_SIZE}
27
+ ) {
28
+ item(path: $itemId, language: $language, version: $version) {
29
+ rendered
30
+ }
31
+ site {
32
+ siteInfo(site: $siteName) {
33
+ dictionary(language: $language, first: $pageSize, after: $after) {
34
+ results {
35
+ key
36
+ value
37
+ }
38
+ pageInfo {
39
+ endCursor
40
+ hasNext
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ `;
47
+ /**
48
+ * GraphQL query for fetching dictionary data.
49
+ * This query is used when the dictionary data is paginated.
50
+ */
51
+ export const dictionaryQuery = /* GraphQL */ `
52
+ query EditingDictionaryQuery(
53
+ $siteName: String!
54
+ $language: String!
55
+ $after: String
56
+ $pageSize: Int = ${PAGE_SIZE}
57
+ ) {
58
+ site {
59
+ siteInfo(site: $siteName) {
60
+ dictionary(language: $language, first: $pageSize, after: $after) {
61
+ results {
62
+ key
63
+ value
64
+ }
65
+ pageInfo {
66
+ endCursor
67
+ hasNext
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ `;
74
+ /**
75
+ * Service for fetching editing data from Sitecore using the Sitecore's GraphQL API.
76
+ * Expected to be used in XMCloud Pages preview (editing) Metadata Edit Mode.
77
+ */
78
+ export class GraphQLEditingService {
79
+ /**
80
+ * Fetch layout data using the Sitecore GraphQL endpoint.
81
+ * @param {GraphQLLayoutServiceConfig} serviceConfig configuration
82
+ */
83
+ constructor(serviceConfig) {
84
+ this.serviceConfig = serviceConfig;
85
+ this.graphQLClient = this.getGraphQLClient();
86
+ }
87
+ /**
88
+ * Fetches editing data. Provides the layout data and dictionary phrases
89
+ * @param {object} variables - The parameters for fetching editing data.
90
+ * @param {string} variables.siteName - The site name.
91
+ * @param {string} variables.itemId - The item id (path) to fetch layout data for.
92
+ * @param {string} variables.language - The language to fetch layout data for.
93
+ * @param {string} [variables.version] - The version of the item (optional).
94
+ * @param {LayoutKind} [variables.layoutKind] - The final or shared layout variant.
95
+ * @returns {Promise} The layout data and dictionary phrases.
96
+ */
97
+ fetchEditingData(_a) {
98
+ return __awaiter(this, arguments, void 0, function* ({ siteName, itemId, language, version, layoutKind = LayoutKind.Final, }) {
99
+ var _b, _c, _d;
100
+ debug.editing('fetching editing data for %s %s %s %s', siteName, itemId, language, version, layoutKind);
101
+ if (!siteName) {
102
+ throw new RangeError('The site name must be a non-empty string');
103
+ }
104
+ if (!language) {
105
+ throw new RangeError('The language must be a non-empty string');
106
+ }
107
+ let dictionaryResults = [];
108
+ let hasNext = true;
109
+ let after = '';
110
+ const editingData = yield this.graphQLClient.request(query, {
111
+ siteName,
112
+ itemId,
113
+ version,
114
+ language,
115
+ }, {
116
+ headers: {
117
+ sc_layoutKind: layoutKind,
118
+ },
119
+ });
120
+ if ((_c = (_b = editingData === null || editingData === void 0 ? void 0 : editingData.site) === null || _b === void 0 ? void 0 : _b.siteInfo) === null || _c === void 0 ? void 0 : _c.dictionary) {
121
+ dictionaryResults = editingData.site.siteInfo.dictionary.results;
122
+ hasNext = editingData.site.siteInfo.dictionary.pageInfo.hasNext;
123
+ after = editingData.site.siteInfo.dictionary.pageInfo.endCursor;
124
+ }
125
+ else {
126
+ hasNext = false;
127
+ }
128
+ const dictionary = yield this.fetchDictionaryData({ siteName, language }, dictionaryResults, hasNext, after);
129
+ return {
130
+ layoutData: ((_d = editingData === null || editingData === void 0 ? void 0 : editingData.item) === null || _d === void 0 ? void 0 : _d.rendered) || {
131
+ sitecore: {
132
+ context: { pageEditing: true, language },
133
+ route: null,
134
+ },
135
+ },
136
+ dictionary,
137
+ };
138
+ });
139
+ }
140
+ fetchDictionaryData(_a) {
141
+ return __awaiter(this, arguments, void 0, function* ({ siteName, language, }, initDictionary = [], hasNext = true, after) {
142
+ var _b, _c;
143
+ let dictionaryResults = initDictionary;
144
+ const dictionary = {};
145
+ while (hasNext) {
146
+ const data = yield this.graphQLClient.request(dictionaryQuery, {
147
+ siteName,
148
+ language,
149
+ after,
150
+ });
151
+ if ((_c = (_b = data === null || data === void 0 ? void 0 : data.site) === null || _b === void 0 ? void 0 : _b.siteInfo) === null || _c === void 0 ? void 0 : _c.dictionary) {
152
+ dictionaryResults = dictionaryResults.concat(data.site.siteInfo.dictionary.results);
153
+ hasNext = data.site.siteInfo.dictionary.pageInfo.hasNext;
154
+ after = data.site.siteInfo.dictionary.pageInfo.endCursor;
155
+ }
156
+ else {
157
+ hasNext = false;
158
+ }
159
+ }
160
+ dictionaryResults.forEach((item) => (dictionary[item.key] = item.value));
161
+ return dictionary;
162
+ });
163
+ }
164
+ /**
165
+ * Gets a GraphQL client that can make requests to the API.
166
+ * @returns {GraphQLClient} implementation
167
+ */
168
+ getGraphQLClient() {
169
+ if (!this.serviceConfig.clientFactory) {
170
+ throw new Error('clientFactory needs to be provided when initializing GraphQL client.');
171
+ }
172
+ return this.serviceConfig.clientFactory({
173
+ debugger: debug.editing,
174
+ headers: {
175
+ sc_editMode: 'true',
176
+ },
177
+ });
178
+ }
179
+ }
@@ -0,0 +1,5 @@
1
+ export { GraphQLEditingService } from './graphql-editing-service';
2
+ export { DEFAULT_PLACEHOLDER_UID, PagesEditor, isEditorActive, resetEditorChromes, getJssPagesClientData, EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET, PAGES_EDITING_MARKER, } from './utils';
3
+ export { RestComponentLayoutService, } from './rest-component-layout-service';
4
+ export { LayoutKind, MetadataKind } from './models';
5
+ export { addComponentUpdateHandler, ComponentLibraryStatus, getComponentLibraryStatusEvent, } from './component-library';