@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,20 @@
1
+ /**
2
+ * Represents the Editing Layout variant.
3
+ * - shared - shared layout
4
+ * - final - final layout
5
+ */
6
+ export var LayoutKind;
7
+ (function (LayoutKind) {
8
+ LayoutKind["Final"] = "final";
9
+ LayoutKind["Shared"] = "shared";
10
+ })(LayoutKind || (LayoutKind = {}));
11
+ /**
12
+ * Represents the kind of metadata element.
13
+ * - open - starting chrome element
14
+ * - close - closing chrome element
15
+ */
16
+ export var MetadataKind;
17
+ (function (MetadataKind) {
18
+ MetadataKind["Open"] = "open";
19
+ MetadataKind["Close"] = "close";
20
+ })(MetadataKind || (MetadataKind = {}));
@@ -0,0 +1,72 @@
1
+ import { debug, NativeDataFetcher } from '..';
2
+ import { fetchData } from '../data-fetcher';
3
+ /**
4
+ * REST service that enables Component Library functioality
5
+ * Makes a request to /sitecore/api/layout/component in 'library' mode in Pages.
6
+ * Returns layoutData for one single rendered component
7
+ */
8
+ export class RestComponentLayoutService {
9
+ constructor(config) {
10
+ this.config = config;
11
+ this.getFetcher = (req, res) => {
12
+ return this.config.dataFetcherResolver
13
+ ? this.config.dataFetcherResolver(req, res)
14
+ : this.getDefaultFetcher(req);
15
+ };
16
+ /**
17
+ * Provides default @see NativeDataFetcher data fetcher
18
+ * @param {IncomingMessage} [req] Request instance
19
+ * @returns default fetcher
20
+ */
21
+ this.getDefaultFetcher = (req) => {
22
+ var _a;
23
+ const config = {
24
+ debugger: debug.editing,
25
+ };
26
+ const nativeFetcher = new NativeDataFetcher(config);
27
+ const headers = req && Object.assign(Object.assign({}, req.headers), (((_a = req.socket) === null || _a === void 0 ? void 0 : _a.remoteAddress) ? { 'X-Forwarded-For': req.socket.remoteAddress } : {}));
28
+ const fetcher = (url, data) => {
29
+ data = Object.assign(Object.assign({}, data), { headers: headers });
30
+ return nativeFetcher.fetch(url, data);
31
+ };
32
+ return fetcher;
33
+ };
34
+ }
35
+ fetchComponentData(params, req, res) {
36
+ params.siteName = params.siteName || this.config.siteName;
37
+ const querystringParams = this.getComponentFetchParams(params);
38
+ debug.layout('fetching component with uid %s for %s %s %s', params.componentUid, params.itemId, params.language, params.siteName);
39
+ const fetcher = this.getFetcher(req, res);
40
+ const fetchUrl = this.resolveLayoutServiceUrl('component');
41
+ return fetchData(fetchUrl, fetcher, querystringParams).catch((error) => {
42
+ var _a;
43
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
44
+ return error.response.data;
45
+ }
46
+ throw error;
47
+ });
48
+ }
49
+ /**
50
+ * Resolves layout service url
51
+ * @param {string} apiType which layout service API to call ('render' or 'placeholder')
52
+ * @returns the layout service url
53
+ */
54
+ resolveLayoutServiceUrl(apiType) {
55
+ const { apiHost = '', configurationName = 'jss' } = this.config;
56
+ return `${apiHost}/sitecore/api/layout/${apiType}/${configurationName}`;
57
+ }
58
+ getComponentFetchParams(params) {
59
+ // exclude undefined params with this one simple trick
60
+ return JSON.parse(JSON.stringify({
61
+ sc_apikey: this.config.apiKey,
62
+ item: params.itemId,
63
+ uid: params.componentUid,
64
+ dataSourceId: params.dataSourceId,
65
+ renderingItemId: params.renderingId,
66
+ version: params.version,
67
+ sc_site: params.siteName,
68
+ sc_lang: params.language || 'en',
69
+ sc_mode: params.editMode,
70
+ }));
71
+ }
72
+ }
@@ -0,0 +1,76 @@
1
+ import isServer from '../utils/is-server';
2
+ /**
3
+ * Default value of uid for root placeholder when uid is not present.
4
+ */
5
+ export const DEFAULT_PLACEHOLDER_UID = '00000000-0000-0000-0000-000000000000';
6
+ /**
7
+ * Query parameter for editing secret
8
+ */
9
+ export const QUERY_PARAM_EDITING_SECRET = 'secret';
10
+ /**
11
+ * ID to be used as a marker for a script rendered in XMC Pages
12
+ * Should identify app is in XM Cloud Pages editing mode
13
+ */
14
+ export const PAGES_EDITING_MARKER = 'jss-hrz-editing';
15
+ /**
16
+ * Default allowed origins for editing requests. This is used to enforce CORS, CSP headers.
17
+ */
18
+ export const EDITING_ALLOWED_ORIGINS = ['https://pages.sitecorecloud.io'];
19
+ /**
20
+ * Copy of chrome rediscovery contract from Horizon (chrome-rediscovery.contract.ts)
21
+ */
22
+ export const ChromeRediscoveryGlobalFunctionName = {
23
+ name: 'Sitecore.Horizon.ResetChromes',
24
+ };
25
+ /**
26
+ * Static utility class for Sitecore Pages Editor
27
+ */
28
+ export class PagesEditor {
29
+ /**
30
+ * Determines whether the current execution context is within a Pages Editor.
31
+ * Pages Editor environment can be identified only in the browser
32
+ * @returns true if executing within a Pages Editor
33
+ */
34
+ static isActive() {
35
+ if (isServer()) {
36
+ return false;
37
+ }
38
+ // Check for Chromes mode
39
+ const chromesCheck = window.location.search.indexOf('sc_headless_mode=edit') > -1;
40
+ // JSS will render a jss-exclusive script element in Metadata mode to indicate edit mode in Pages
41
+ return chromesCheck || !!window.document.getElementById(PAGES_EDITING_MARKER);
42
+ }
43
+ static resetChromes() {
44
+ if (isServer()) {
45
+ return;
46
+ }
47
+ // Reset chromes in Pages
48
+ window[ChromeRediscoveryGlobalFunctionName.name] &&
49
+ window[ChromeRediscoveryGlobalFunctionName.name]();
50
+ }
51
+ }
52
+ /**
53
+ * Determines whether the current execution context is within a Sitecore editor.
54
+ * Sitecore Editor environment can be identified only in the browser
55
+ * @returns true if executing within a Sitecore editor
56
+ */
57
+ export const isEditorActive = () => {
58
+ return PagesEditor.isActive();
59
+ };
60
+ /**
61
+ * Resets Sitecore editor "chromes"
62
+ */
63
+ export const resetEditorChromes = () => {
64
+ if (PagesEditor.isActive()) {
65
+ PagesEditor.resetChromes();
66
+ }
67
+ };
68
+ /**
69
+ * Gets extra JSS clientData scripts to render in XMC Pages in addition to clientData from Pages itself
70
+ * @returns {Record} collection of clientData
71
+ */
72
+ export const getJssPagesClientData = () => {
73
+ const clientData = {};
74
+ clientData[PAGES_EDITING_MARKER] = {};
75
+ return clientData;
76
+ };
@@ -0,0 +1,69 @@
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 { SitecoreTemplateId } from '../constants';
11
+ /** @private */
12
+ export const siteNameError = 'The site name must be a non-empty string';
13
+ /** @private */
14
+ export const languageError = 'The language must be a non-empty string';
15
+ /*
16
+ * GraphQL query that returns the ID of the root item of the specified site and language
17
+ */
18
+ const appRootQuery = /* GraphQL */ `
19
+ query AppRootQuery($jssAppTemplateId: String!, $siteName: String!, $language: String!) {
20
+ layout(site: $siteName, routePath: "/", language: $language) {
21
+ homePage: item {
22
+ rootItem: ancestors(includeTemplateIDs: [$jssAppTemplateId]) {
23
+ id
24
+ }
25
+ }
26
+ }
27
+ }
28
+ `;
29
+ /**
30
+ * Gets the ID of the JSS App root item for the specified site and language.
31
+ * @param {GraphQLClient} client that fetches data from a GraphQL endpoint.
32
+ * @param {string} siteName the name of the Sitecore site.
33
+ * @param {string} language the item language version.
34
+ * @param {string} [jssAppTemplateId] optional template ID of the app root item. If not
35
+ * specified, the ID of the "/sitecore/templates/Foundation/JavaScript Services/App"
36
+ * item is used.
37
+ * @returns the root item ID of the JSS App in Sitecore. Returns null if the app root item is not found.
38
+ * @throws {RangeError} if a valid site name value is not provided.
39
+ * @throws {RangeError} if a valid language value is not provided.
40
+ * @summary This function intentionally avoids throwing an error if a root item is not found,
41
+ * leaving that decision up to implementations.
42
+ */
43
+ export function getAppRootId(client, siteName, language, jssAppTemplateId) {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ var _a, _b, _c, _d, _e, _f;
46
+ if (!siteName) {
47
+ throw new RangeError(siteNameError);
48
+ }
49
+ if (!language) {
50
+ throw new RangeError(languageError);
51
+ }
52
+ let fetchResponse = yield client.request(appRootQuery, {
53
+ jssAppTemplateId: jssAppTemplateId || SitecoreTemplateId.JssApp,
54
+ siteName,
55
+ language,
56
+ });
57
+ if (!((_c = (_b = (_a = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.layout) === null || _a === void 0 ? void 0 : _a.homePage) === null || _b === void 0 ? void 0 : _b.rootItem) === null || _c === void 0 ? void 0 : _c.length) && language !== 'en') {
58
+ fetchResponse = yield client.request(appRootQuery, {
59
+ jssAppTemplateId: jssAppTemplateId || SitecoreTemplateId.JssApp,
60
+ siteName,
61
+ language: 'en',
62
+ });
63
+ }
64
+ if (!((_f = (_e = (_d = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.layout) === null || _d === void 0 ? void 0 : _d.homePage) === null || _e === void 0 ? void 0 : _e.rootItem) === null || _f === void 0 ? void 0 : _f.length)) {
65
+ return null;
66
+ }
67
+ return fetchResponse.layout.homePage.rootItem[0].id;
68
+ });
69
+ }
@@ -0,0 +1,16 @@
1
+ import { SITECORE_EDGE_URL_DEFAULT } from '../constants';
2
+ /**
3
+ * Generates a URL for accessing Sitecore Edge Platform Content using the provided endpoint and context ID.
4
+ * @param {string} sitecoreEdgeContextId - The unique context id.
5
+ * @param {string} [sitecoreEdgeUrl] - The base endpoint URL for the Edge Platform. Default is https://edge-platform.sitecorecloud.io
6
+ * @returns {string} The complete URL for accessing content through the Edge Platform.
7
+ */
8
+ export const getEdgeProxyContentUrl = (sitecoreEdgeContextId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) => `${sitecoreEdgeUrl}/v1/content/api/graphql/v1?sitecoreContextId=${sitecoreEdgeContextId}`;
9
+ /**
10
+ * Generates a URL for accessing Sitecore Edge Platform Forms using the provided form ID and context ID.
11
+ * @param {string} sitecoreEdgeContextId - The unique context id.
12
+ * @param {string} formId - The unique form id.
13
+ * @param {string} [sitecoreEdgeUrl] - The base endpoint URL for the Edge Platform. Default is https://edge-platform.sitecorecloud.io
14
+ * @returns {string} The complete URL for accessing forms through the Edge Platform.
15
+ */
16
+ export const getEdgeProxyFormsUrl = (sitecoreEdgeContextId, formId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) => `${sitecoreEdgeUrl}/v1/forms/publisher/${formId}?sitecoreContextId=${sitecoreEdgeContextId}`;
@@ -0,0 +1,4 @@
1
+ export { getAppRootId } from './app-root-query';
2
+ export { DefaultRetryStrategy, GraphQLRequestClient, } from '../graphql-request-client';
3
+ export { SearchQueryService, } from './search-service';
4
+ export { getEdgeProxyContentUrl, getEdgeProxyFormsUrl } from './graphql-edge-proxy';
@@ -0,0 +1,57 @@
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
+ /**
11
+ * @deprecated use GraphQLClient instead
12
+ * Provides functionality for performing GraphQL 'search' operations, including handling pagination.
13
+ * This class is meant to be extended or used as a mixin; it's not meant to be used directly.
14
+ * @template T The type of objects being requested.
15
+ * @mixin
16
+ */
17
+ export class SearchQueryService {
18
+ /**
19
+ * Creates an instance of search query service.
20
+ * @param {GraphQLClient} client that fetches data from a GraphQL endpoint.
21
+ */
22
+ constructor(client) {
23
+ this.client = client;
24
+ }
25
+ /**
26
+ * 1. Validates mandatory search query arguments
27
+ * 2. Executes search query with pagination
28
+ * 3. Aggregates pagination results into a single result-set.
29
+ * @template T The type of objects being requested.
30
+ * @param {string | DocumentNode} query the search query.
31
+ * @param {SearchQueryVariables} args search query arguments.
32
+ * @returns {T[]} array of result objects.
33
+ * @throws {RangeError} if a valid root item ID is not provided.
34
+ * @throws {RangeError} if the provided language(s) is(are) not valid.
35
+ */
36
+ fetch(query, args) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ var _a;
39
+ if (!args.rootItemId) {
40
+ throw new RangeError('"rootItemId" and "language" must be non-empty strings');
41
+ }
42
+ if (!args.language) {
43
+ throw new RangeError('"rootItemId" and "language" must be non-empty strings');
44
+ }
45
+ let results = [];
46
+ let hasNext = true;
47
+ let after = '';
48
+ while (hasNext) {
49
+ const fetchResponse = yield this.client.request(query, Object.assign(Object.assign({}, args), { after }));
50
+ results = results.concat((_a = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.search) === null || _a === void 0 ? void 0 : _a.results);
51
+ hasNext = fetchResponse.search.pageInfo.hasNext;
52
+ after = fetchResponse.search.pageInfo.endCursor;
53
+ }
54
+ return results;
55
+ });
56
+ }
57
+ }
@@ -0,0 +1,144 @@
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 { GraphQLClient as Client } from 'graphql-request';
11
+ import parse from 'url-parse';
12
+ import debuggers from './debug';
13
+ import TimeoutPromise from './utils/timeout-promise';
14
+ /**
15
+ * Represents a default retry strategy for handling retry attempts in case of specific HTTP status codes.
16
+ * This class implements the RetryStrategy interface and provides methods to determine whether a request
17
+ * should be retried and calculates the delay before the next retry attempt.
18
+ */
19
+ export class DefaultRetryStrategy {
20
+ /**
21
+ * @param {object} options Configurable options for retry mechanism.
22
+ * @param {number[]} [options.statusCodes] HTTP status codes to trigger retries on. Default is [429].
23
+ * @param {string[]} [options.errorCodes] Node error codes to trigger retries. Default is ['ECONNRESET', 'ETIMEDOUT', 'EPROTO'].
24
+ * @param {number} [options.factor] Factor by which the delay increases with each retry attempt. Default is 2.
25
+ */
26
+ constructor(options = {}) {
27
+ this.statusCodes = options.statusCodes || [429];
28
+ this.errorCodes = options.errorCodes || ['ECONNRESET', 'ETIMEDOUT', 'EPROTO'];
29
+ this.factor = options.factor || 2;
30
+ }
31
+ shouldRetry(error, attempt, retries) {
32
+ var _a;
33
+ const isStatusCodeError = ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) !== undefined && this.statusCodes.includes(error.response.status);
34
+ const isNodeErrorCode = error.code !== undefined && this.errorCodes.includes(error.code);
35
+ return retries > 0 && attempt <= retries && (isStatusCodeError || isNodeErrorCode);
36
+ }
37
+ getDelay(error, attempt) {
38
+ var _a;
39
+ const rawHeaders = (_a = error.response) === null || _a === void 0 ? void 0 : _a.headers;
40
+ const retryAfterHeader = rawHeaders === null || rawHeaders === void 0 ? void 0 : rawHeaders.get('Retry-After');
41
+ if (retryAfterHeader !== null &&
42
+ retryAfterHeader !== undefined &&
43
+ retryAfterHeader.trim() !== '') {
44
+ const delaySeconds = Number.parseFloat(retryAfterHeader);
45
+ return delaySeconds * 1000;
46
+ }
47
+ else {
48
+ return Math.pow(this.factor, attempt - 1) * 1000;
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * A GraphQL client for Sitecore APIs that uses the 'graphql-request' library.
54
+ * https://github.com/prisma-labs/graphql-request
55
+ */
56
+ export class GraphQLRequestClient {
57
+ /**
58
+ * Provides ability to execute graphql query using given `endpoint`
59
+ * @param {string} endpoint The Graphql endpoint
60
+ * @param {GraphQLRequestClientConfig} [clientConfig] GraphQL request client configuration.
61
+ */
62
+ constructor(endpoint, clientConfig = {}) {
63
+ var _a;
64
+ this.endpoint = endpoint;
65
+ this.headers = {};
66
+ if (clientConfig.apiKey) {
67
+ this.headers.sc_apikey = clientConfig.apiKey;
68
+ }
69
+ if (clientConfig.headers) {
70
+ this.headers = Object.assign(Object.assign({}, this.headers), clientConfig.headers);
71
+ }
72
+ if (!endpoint || !parse(endpoint).hostname) {
73
+ throw new Error(`Invalid GraphQL endpoint '${endpoint}'. Verify that 'layoutServiceHost' property in 'scjssconfig.json' file or appropriate environment variable is set`);
74
+ }
75
+ this.timeout = clientConfig.timeout;
76
+ this.retries = (_a = clientConfig.retries) !== null && _a !== void 0 ? _a : 3;
77
+ this.retryStrategy =
78
+ clientConfig.retryStrategy ||
79
+ new DefaultRetryStrategy({ statusCodes: [429, 502, 503, 504, 520, 521, 522, 523, 524] });
80
+ this.client = new Client(endpoint, {
81
+ headers: this.headers,
82
+ fetch: clientConfig.fetch,
83
+ });
84
+ this.debug = clientConfig.debugger || debuggers.http;
85
+ }
86
+ /**
87
+ * Factory method for creating a GraphQLRequestClientFactory.
88
+ * @param {object} config - client configuration options.
89
+ * @param {string} config.endpoint - endpoint
90
+ * @param {string} [config.apiKey] - apikey
91
+ */
92
+ static createClientFactory({ endpoint, apiKey, }) {
93
+ return (config = {}) => new GraphQLRequestClient(endpoint, Object.assign(Object.assign({}, config), { apiKey }));
94
+ }
95
+ /**
96
+ * Execute graphql request
97
+ * @param {string | DocumentNode} query graphql query
98
+ * @param {object} [variables] graphql variables
99
+ * @param {RequestOptions} [options] Options for configuring a GraphQL request.
100
+ */
101
+ request(query, variables, options) {
102
+ return __awaiter(this, void 0, void 0, function* () {
103
+ let attempt = 1;
104
+ const retryer = () => __awaiter(this, void 0, void 0, function* () {
105
+ // Note we don't have access to raw request/response with graphql-request
106
+ // but we should log whatever we have.
107
+ this.debug('request: %o', {
108
+ url: this.endpoint,
109
+ headers: Object.assign(Object.assign({}, this.headers), options === null || options === void 0 ? void 0 : options.headers),
110
+ query,
111
+ variables,
112
+ });
113
+ const startTimestamp = Date.now();
114
+ const fetchWithOptionalTimeout = [this.client.request(query, variables, options === null || options === void 0 ? void 0 : options.headers)];
115
+ if (this.timeout) {
116
+ this.abortTimeout = new TimeoutPromise(this.timeout);
117
+ fetchWithOptionalTimeout.push(this.abortTimeout.start);
118
+ }
119
+ return Promise.race(fetchWithOptionalTimeout).then((data) => {
120
+ var _a;
121
+ (_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear();
122
+ this.debug('response in %dms: %o', Date.now() - startTimestamp, data);
123
+ return Promise.resolve(data);
124
+ }, (error) => __awaiter(this, void 0, void 0, function* () {
125
+ var _a, _b;
126
+ (_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear();
127
+ this.debug('response error: %o', error.response || error.message || error);
128
+ const status = ((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) || error.code;
129
+ const shouldRetry = this.retryStrategy.shouldRetry(error, attempt, this.retries);
130
+ if (shouldRetry) {
131
+ const delayMs = this.retryStrategy.getDelay(error, attempt);
132
+ this.debug('Error: %s. Retrying in %dms (attempt %d).', status, delayMs, attempt);
133
+ attempt++;
134
+ return new Promise((resolve) => setTimeout(resolve, delayMs)).then(retryer);
135
+ }
136
+ else {
137
+ return Promise.reject(error);
138
+ }
139
+ }));
140
+ });
141
+ return retryer();
142
+ });
143
+ }
144
+ }
@@ -0,0 +1,41 @@
1
+ import { MemoryCacheClient } from '../cache-client';
2
+ /**
3
+ * Base implementation of @see DictionaryService that handles caching dictionary values
4
+ */
5
+ export class DictionaryServiceBase {
6
+ /**
7
+ * Initializes a new instance of @see DictionaryService using the provided @see CacheOptions
8
+ * @param {CacheOptions} options Configuration options
9
+ */
10
+ constructor(options) {
11
+ this.options = options;
12
+ this.cache = this.getCacheClient();
13
+ }
14
+ /**
15
+ * Caches a @see DictionaryPhrases value for the specified cache key.
16
+ * @param {string} key The cache key.
17
+ * @param {DictionaryPhrases} value The value to cache.
18
+ * @returns The value added to the cache.
19
+ * @mixes CacheClient<DictionaryPhrases>
20
+ */
21
+ setCacheValue(key, value) {
22
+ return this.cache.setCacheValue(key, value);
23
+ }
24
+ /**
25
+ * Retrieves a @see DictionaryPhrases value from the cache.
26
+ * @param {string} key The cache key.
27
+ * @returns The @see DictionaryPhrases value, or null if the specified key is not found in the cache.
28
+ */
29
+ getCacheValue(key) {
30
+ return this.cache.getCacheValue(key);
31
+ }
32
+ /**
33
+ * Gets a cache client that can cache data. Uses memory-cache as the default
34
+ * library for caching (@see MemoryCacheClient). Override this method if you
35
+ * want to use something else.
36
+ * @returns {CacheClient} implementation
37
+ */
38
+ getCacheClient() {
39
+ return new MemoryCacheClient(this.options);
40
+ }
41
+ }
@@ -0,0 +1,129 @@
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 { DictionaryServiceBase } from './dictionary-service';
11
+ import { siteNameError, languageError } from '../graphql/app-root-query';
12
+ import debug from '../debug';
13
+ /** @private */
14
+ export const queryError = 'Valid value for rootItemId not provided and failed to auto-resolve app root item.';
15
+ /** @default */
16
+ const siteQuery = /* GraphQL */ `
17
+ query DictionarySiteQuery(
18
+ $siteName: String!
19
+ $language: String!
20
+ $pageSize: Int = 500
21
+ $after: String
22
+ ) {
23
+ site {
24
+ siteInfo(site: $siteName) {
25
+ dictionary(language: $language, first: $pageSize, after: $after) {
26
+ pageInfo {
27
+ endCursor
28
+ hasNext
29
+ }
30
+ results {
31
+ key
32
+ value
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ `;
39
+ /**
40
+ * Service that fetch dictionary data using Sitecore's GraphQL API.
41
+ * @augments DictionaryServiceBase
42
+ * @mixes SearchQueryService<DictionaryQueryResult>
43
+ */
44
+ export class GraphQLDictionaryService extends DictionaryServiceBase {
45
+ /**
46
+ * Creates an instance of graphQL dictionary service with the provided options
47
+ * @param {GraphQLDictionaryService} options instance
48
+ */
49
+ constructor(options) {
50
+ super(options);
51
+ this.options = options;
52
+ this.graphQLClient = this.getGraphQLClient();
53
+ }
54
+ /**
55
+ * Fetches dictionary data for internalization. Uses search query by default
56
+ * @param {string} language the language to fetch
57
+ * @returns {Promise<DictionaryPhrases>} dictionary phrases
58
+ * @throws {Error} if the app root was not found for the specified site and language.
59
+ */
60
+ fetchDictionaryData(language) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ const cacheKey = this.options.siteName + language;
63
+ const cachedValue = this.getCacheValue(cacheKey);
64
+ if (cachedValue) {
65
+ debug.dictionary('using cached dictionary data for %s %s', language, this.options.siteName);
66
+ return cachedValue;
67
+ }
68
+ const phrases = yield this.fetchWithSiteQuery(language);
69
+ this.setCacheValue(cacheKey, phrases);
70
+ return phrases;
71
+ });
72
+ }
73
+ /**
74
+ * Fetches dictionary data with site query
75
+ * This is the default behavior for XMCloud deployments. Uses `siteQuery` to retrieve data.
76
+ * @param {string} language the language to fetch
77
+ * @returns {Promise<DictionaryPhrases>} dictionary phrases
78
+ */
79
+ fetchWithSiteQuery(language) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ var _a, _b;
82
+ const phrases = {};
83
+ debug.dictionary('fetching dictionary data for %s %s', language, this.options.siteName);
84
+ let results = [];
85
+ let hasNext = true;
86
+ let after = '';
87
+ if (!this.options.siteName) {
88
+ throw new RangeError(siteNameError);
89
+ }
90
+ if (!language) {
91
+ throw new RangeError(languageError);
92
+ }
93
+ while (hasNext) {
94
+ const fetchResponse = yield this.graphQLClient.request(siteQuery, {
95
+ siteName: this.options.siteName,
96
+ language,
97
+ pageSize: this.options.pageSize,
98
+ after,
99
+ });
100
+ if ((_b = (_a = fetchResponse === null || fetchResponse === void 0 ? void 0 : fetchResponse.site) === null || _a === void 0 ? void 0 : _a.siteInfo) === null || _b === void 0 ? void 0 : _b.dictionary) {
101
+ results = results.concat(fetchResponse.site.siteInfo.dictionary.results);
102
+ after = fetchResponse.site.siteInfo.dictionary.pageInfo.endCursor;
103
+ hasNext = fetchResponse.site.siteInfo.dictionary.pageInfo.hasNext;
104
+ }
105
+ else {
106
+ hasNext = false;
107
+ }
108
+ }
109
+ results.forEach((item) => (phrases[item.key] = item.value));
110
+ return phrases;
111
+ });
112
+ }
113
+ /**
114
+ * Gets a GraphQL client that can make requests to the API. Uses graphql-request as the default
115
+ * library for fetching graphql data (@see GraphQLRequestClient). Override this method if you
116
+ * want to use something else.
117
+ * @returns {GraphQLClient} implementation
118
+ */
119
+ getGraphQLClient() {
120
+ if (!this.options.clientFactory) {
121
+ throw new Error('clientFactory needs to be provided when initializing GraphQL client.');
122
+ }
123
+ return this.options.clientFactory({
124
+ debugger: debug.dictionary,
125
+ retries: this.options.retries,
126
+ retryStrategy: this.options.retryStrategy,
127
+ });
128
+ }
129
+ }
@@ -0,0 +1,2 @@
1
+ export { DictionaryServiceBase } from './dictionary-service';
2
+ export { GraphQLDictionaryService, } from './graphql-dictionary-service';
@@ -0,0 +1,9 @@
1
+ // NOTE: all imports are now named as to not make breaking changes
2
+ // and to keep react-native working with cjs modules.
3
+ import * as constants from './constants';
4
+ export { default as debug, enableDebug } from './debug';
5
+ export { DefaultRetryStrategy, GraphQLRequestClient, } from './graphql-request-client';
6
+ export { MemoryCacheClient } from './cache-client';
7
+ export { ClientError } from 'graphql-request';
8
+ export { NativeDataFetcher, } from './native-fetcher';
9
+ export { constants };