@enonic/nextjs-adapter 3.0.0-B1 → 3.0.0-B2

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 (239) hide show
  1. package/baseMappings.js +3 -2
  2. package/baseMappings.js.map +1 -0
  3. package/client.d.ts +1 -0
  4. package/client.js +3 -0
  5. package/client.js.map +1 -0
  6. package/common/ComponentRegistry.d.ts +34 -0
  7. package/{ComponentRegistry.js → common/ComponentRegistry.js} +26 -26
  8. package/common/ComponentRegistry.js.map +1 -0
  9. package/{UrlProcessor.d.ts → common/UrlProcessor.d.ts} +2 -2
  10. package/{UrlProcessor.js → common/UrlProcessor.js} +16 -8
  11. package/common/UrlProcessor.js.map +1 -0
  12. package/common/constants.d.ts +50 -0
  13. package/common/constants.js +79 -0
  14. package/common/constants.js.map +1 -0
  15. package/common/env.d.ts +11 -0
  16. package/common/env.js +28 -0
  17. package/common/env.js.map +1 -0
  18. package/guillotine/applyProcessors.d.ts +2 -0
  19. package/guillotine/applyProcessors.js +33 -0
  20. package/guillotine/applyProcessors.js.map +1 -0
  21. package/guillotine/buildComponentTree.d.ts +2 -0
  22. package/guillotine/buildComponentTree.js +45 -0
  23. package/guillotine/buildComponentTree.js.map +1 -0
  24. package/guillotine/buildErrorResponse.d.ts +3 -0
  25. package/guillotine/buildErrorResponse.js +26 -0
  26. package/guillotine/buildErrorResponse.js.map +1 -0
  27. package/guillotine/buildPage.d.ts +2 -0
  28. package/guillotine/buildPage.js +10 -0
  29. package/guillotine/buildPage.js.map +1 -0
  30. package/guillotine/collectComponentDescriptors.d.ts +6 -0
  31. package/guillotine/collectComponentDescriptors.js +43 -0
  32. package/guillotine/collectComponentDescriptors.js.map +1 -0
  33. package/guillotine/combineMultipleQueries.d.ts +2 -0
  34. package/guillotine/combineMultipleQueries.js +58 -0
  35. package/guillotine/combineMultipleQueries.js.map +1 -0
  36. package/guillotine/createMetaData.d.ts +17 -0
  37. package/guillotine/createMetaData.js +44 -0
  38. package/guillotine/createMetaData.js.map +1 -0
  39. package/guillotine/fetchContent.d.ts +1 -39
  40. package/guillotine/fetchContent.js +195 -808
  41. package/guillotine/fetchContent.js.map +1 -0
  42. package/guillotine/fetchContentData.d.ts +2 -0
  43. package/guillotine/fetchContentData.js +27 -0
  44. package/guillotine/fetchContentData.js.map +1 -0
  45. package/guillotine/fetchContentPathsForAllLocales.d.ts +2 -0
  46. package/guillotine/fetchContentPathsForAllLocales.js +21 -0
  47. package/guillotine/fetchContentPathsForAllLocales.js.map +1 -0
  48. package/guillotine/fetchContentPathsForLocale.d.ts +2 -0
  49. package/guillotine/fetchContentPathsForLocale.js +40 -0
  50. package/guillotine/fetchContentPathsForLocale.js.map +1 -0
  51. package/guillotine/fetchFromApi.d.ts +3 -0
  52. package/guillotine/fetchFromApi.js +65 -0
  53. package/guillotine/fetchFromApi.js.map +1 -0
  54. package/guillotine/fetchGuillotine.d.ts +3 -0
  55. package/guillotine/fetchGuillotine.js +55 -0
  56. package/guillotine/fetchGuillotine.js.map +1 -0
  57. package/guillotine/fetchMetaData.d.ts +2 -0
  58. package/guillotine/fetchMetaData.js +30 -0
  59. package/guillotine/fetchMetaData.js.map +1 -0
  60. package/guillotine/getCleanContentPathArrayOrThrow400.d.ts +2 -0
  61. package/guillotine/getCleanContentPathArrayOrThrow400.js +20 -0
  62. package/guillotine/getCleanContentPathArrayOrThrow400.js.map +1 -0
  63. package/guillotine/getComponentConfig.d.ts +2 -0
  64. package/guillotine/getComponentConfig.js +5 -0
  65. package/guillotine/getComponentConfig.js.map +1 -0
  66. package/guillotine/getContentAndComponentPaths.d.ts +1 -0
  67. package/guillotine/getContentAndComponentPaths.js +12 -0
  68. package/guillotine/getContentAndComponentPaths.js.map +1 -0
  69. package/guillotine/getMetaData.d.ts +0 -92
  70. package/guillotine/getMetaData.js +47 -109
  71. package/guillotine/getMetaData.js.map +1 -0
  72. package/guillotine/getParentRegion.d.ts +2 -0
  73. package/guillotine/getParentRegion.js +40 -0
  74. package/guillotine/getParentRegion.js.map +1 -0
  75. package/guillotine/getQueryAndVariables.d.ts +2 -0
  76. package/guillotine/getQueryAndVariables.js +32 -0
  77. package/guillotine/getQueryAndVariables.js.map +1 -0
  78. package/guillotine/metadata/configQuery.d.ts +2 -0
  79. package/guillotine/metadata/configQuery.js +36 -0
  80. package/guillotine/metadata/configQuery.js.map +1 -0
  81. package/guillotine/metadata/richTextQuery.d.ts +1 -0
  82. package/guillotine/metadata/richTextQuery.js +32 -0
  83. package/guillotine/metadata/richTextQuery.js.map +1 -0
  84. package/guillotine/parseComponentPath.d.ts +2 -0
  85. package/guillotine/parseComponentPath.js +22 -0
  86. package/guillotine/parseComponentPath.js.map +1 -0
  87. package/guillotine/prefixLayoutPath.d.ts +1 -0
  88. package/guillotine/prefixLayoutPath.js +13 -0
  89. package/guillotine/prefixLayoutPath.js.map +1 -0
  90. package/guillotine/processComponentConfig.d.ts +2 -0
  91. package/guillotine/processComponentConfig.js +30 -0
  92. package/guillotine/processComponentConfig.js.map +1 -0
  93. package/guillotine/restrictComponentsToPath.d.ts +2 -0
  94. package/guillotine/restrictComponentsToPath.js +35 -0
  95. package/guillotine/restrictComponentsToPath.js.map +1 -0
  96. package/guillotine/validateData.d.ts +2 -0
  97. package/guillotine/validateData.js +7 -0
  98. package/guillotine/validateData.js.map +1 -0
  99. package/guillotine/validateNotFound.d.ts +2 -0
  100. package/guillotine/validateNotFound.js +16 -0
  101. package/guillotine/validateNotFound.js.map +1 -0
  102. package/guillotine/validateShortcut.d.ts +2 -0
  103. package/guillotine/validateShortcut.js +29 -0
  104. package/guillotine/validateShortcut.js.map +1 -0
  105. package/i18n/LocaleContext.d.ts +2 -8
  106. package/i18n/LocaleContext.jsx +17 -13
  107. package/i18n/LocaleContext.jsx.map +1 -0
  108. package/i18n/i18n.d.ts +1 -3
  109. package/i18n/i18n.js +2 -1
  110. package/i18n/i18n.js.map +1 -0
  111. package/index.d.ts +18 -7
  112. package/index.js +18 -7
  113. package/index.js.map +1 -0
  114. package/package.json +63 -15
  115. package/query/Shortcut.js +1 -0
  116. package/query/Shortcut.js.map +1 -0
  117. package/types/component.d.ts +114 -0
  118. package/types/component.js +2 -0
  119. package/types/component.js.map +1 -0
  120. package/types/componentProps.d.ts +104 -0
  121. package/types/componentProps.js +2 -0
  122. package/types/componentProps.js.map +1 -0
  123. package/types/guillotine.d.ts +342 -0
  124. package/types/guillotine.js +2 -0
  125. package/types/guillotine.js.map +1 -0
  126. package/types/i18n.d.ts +7 -0
  127. package/types/i18n.js +2 -0
  128. package/types/i18n.js.map +1 -0
  129. package/types/index.d.ts +45 -0
  130. package/types/index.js +3 -0
  131. package/types/index.js.map +1 -0
  132. package/types/next.d.ts +6 -0
  133. package/types/next.js +2 -0
  134. package/types/next.js.map +1 -0
  135. package/types/util.d.ts +3 -0
  136. package/types/util.js +3 -0
  137. package/types/util.js.map +1 -0
  138. package/utils/addLineNumbers.d.ts +1 -0
  139. package/utils/addLineNumbers.js +4 -0
  140. package/utils/addLineNumbers.js.map +1 -0
  141. package/utils/buildGuillotineRequestHeaders.d.ts +7 -0
  142. package/utils/buildGuillotineRequestHeaders.js +16 -0
  143. package/utils/buildGuillotineRequestHeaders.js.map +1 -0
  144. package/utils/commonChars.d.ts +1 -0
  145. package/utils/commonChars.js +17 -0
  146. package/utils/commonChars.js.map +1 -0
  147. package/utils/fixDoubleSlashes.d.ts +1 -0
  148. package/utils/fixDoubleSlashes.js +4 -0
  149. package/utils/fixDoubleSlashes.js.map +1 -0
  150. package/utils/getContentApiUrl.d.ts +2 -0
  151. package/utils/getContentApiUrl.js +15 -0
  152. package/utils/getContentApiUrl.js.map +1 -0
  153. package/utils/getProjectLocaleConfig.d.ts +2 -0
  154. package/utils/getProjectLocaleConfig.js +19 -0
  155. package/utils/getProjectLocaleConfig.js.map +1 -0
  156. package/utils/getProjectLocaleConfigById.d.ts +2 -0
  157. package/utils/getProjectLocaleConfigById.js +16 -0
  158. package/utils/getProjectLocaleConfigById.js.map +1 -0
  159. package/utils/getProjectLocaleConfigByLocale.d.ts +2 -0
  160. package/utils/getProjectLocaleConfigByLocale.js +13 -0
  161. package/utils/getProjectLocaleConfigByLocale.js.map +1 -0
  162. package/utils/getProjectLocaleConfigs.d.ts +2 -0
  163. package/utils/getProjectLocaleConfigs.js +30 -0
  164. package/utils/getProjectLocaleConfigs.js.map +1 -0
  165. package/utils/getProjectLocales.d.ts +1 -0
  166. package/utils/getProjectLocales.js +5 -0
  167. package/utils/getProjectLocales.js.map +1 -0
  168. package/utils/getRenderMode.d.ts +3 -0
  169. package/utils/getRenderMode.js +8 -0
  170. package/utils/getRenderMode.js.map +1 -0
  171. package/utils/getRequestLocaleInfo.d.ts +6 -0
  172. package/utils/getRequestLocaleInfo.js +26 -0
  173. package/utils/getRequestLocaleInfo.js.map +1 -0
  174. package/utils/getXpBaseUrl.d.ts +2 -0
  175. package/utils/getXpBaseUrl.js +8 -0
  176. package/utils/getXpBaseUrl.js.map +1 -0
  177. package/utils/indent.d.ts +1 -0
  178. package/utils/indent.js +5 -0
  179. package/utils/indent.js.map +1 -0
  180. package/utils/sanitizeGraphqlName.d.ts +1 -0
  181. package/utils/sanitizeGraphqlName.js +12 -0
  182. package/utils/sanitizeGraphqlName.js.map +1 -0
  183. package/views/BaseComponent.d.ts +6 -11
  184. package/views/BaseComponent.jsx +18 -21
  185. package/views/BaseComponent.jsx.map +1 -0
  186. package/views/BaseContent.d.ts +3 -3
  187. package/views/BaseContent.jsx +2 -5
  188. package/views/BaseContent.jsx.map +1 -0
  189. package/views/BaseLayout.d.ts +3 -16
  190. package/views/BaseLayout.jsx +3 -3
  191. package/views/BaseLayout.jsx.map +1 -0
  192. package/views/BaseMacro.d.ts +3 -13
  193. package/views/BaseMacro.jsx +4 -3
  194. package/views/BaseMacro.jsx.map +1 -0
  195. package/views/BasePage.d.ts +3 -18
  196. package/views/BasePage.jsx +3 -3
  197. package/views/BasePage.jsx.map +1 -0
  198. package/views/BasePart.d.ts +3 -18
  199. package/views/BasePart.jsx +3 -3
  200. package/views/BasePart.jsx.map +1 -0
  201. package/views/Empty.d.ts +2 -2
  202. package/views/Empty.jsx +2 -1
  203. package/views/Empty.jsx.map +1 -0
  204. package/views/Fragment.d.ts +3 -9
  205. package/views/Fragment.jsx +2 -2
  206. package/views/Fragment.jsx.map +1 -0
  207. package/views/MainView.d.ts +3 -3
  208. package/views/MainView.jsx +2 -2
  209. package/views/MainView.jsx.map +1 -0
  210. package/views/PropsView.d.ts +3 -0
  211. package/views/PropsView.jsx +21 -0
  212. package/views/PropsView.jsx.map +1 -0
  213. package/views/Region.d.ts +4 -17
  214. package/views/Region.jsx +2 -2
  215. package/views/Region.jsx.map +1 -0
  216. package/views/RichTextView.d.ts +3 -13
  217. package/views/RichTextView.jsx +2 -2
  218. package/views/RichTextView.jsx.map +1 -0
  219. package/views/SingleComponent.d.ts +3 -3
  220. package/views/SingleComponent.jsx +1 -2
  221. package/views/SingleComponent.jsx.map +1 -0
  222. package/views/StaticContent.d.ts +2 -6
  223. package/views/StaticContent.jsx +1 -0
  224. package/views/StaticContent.jsx.map +1 -0
  225. package/views/Text.d.ts +5 -5
  226. package/views/Text.jsx +1 -1
  227. package/views/Text.jsx.map +1 -0
  228. package/views/getClientHydratedHtml.d.ts +2 -0
  229. package/views/getClientHydratedHtml.jsx +9 -0
  230. package/views/getClientHydratedHtml.jsx.map +1 -0
  231. package/views/macros/DefaultMacro.d.ts +1 -1
  232. package/views/macros/DefaultMacro.jsx +1 -0
  233. package/views/macros/DefaultMacro.jsx.map +1 -0
  234. package/views/macros/DisableMacro.d.ts +1 -1
  235. package/views/macros/DisableMacro.jsx +1 -0
  236. package/views/macros/DisableMacro.jsx.map +1 -0
  237. package/ComponentRegistry.d.ts +0 -64
  238. package/utils.d.ts +0 -111
  239. package/utils.js +0 -255
@@ -7,829 +7,216 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { getMetaQuery, pageFragmentQuery } from './getMetaData';
11
- import adapterConstants, { addJsessionHeaders, addLocaleHeaders, APP_NAME, APP_NAME_DASHED, FRAGMENT_CONTENTTYPE_NAME, FRAGMENT_DEFAULT_REGION_NAME, GET_STATIC_PATHS_QUERY, getContentApiUrl, getProjectLocaleConfig, getProjectLocaleConfigs, getRenderMode, getRequestLocaleInfo, getXpBaseUrl, IS_DEV_MODE, PAGE_TEMPLATE_CONTENTTYPE_NAME, PAGE_TEMPLATE_FOLDER, RENDER_MODE, sanitizeGraphqlName, XP_COMPONENT_TYPE, XP_REQUEST_TYPE, } from '../utils';
12
- import { ComponentRegistry } from '../ComponentRegistry';
13
- import { UrlProcessor } from '../UrlProcessor';
14
- import { notFound, redirect, RedirectType } from 'next/navigation';
15
10
  import { headers } from 'next/headers';
16
- const NO_PROPS_PROCESSOR = (props) => __awaiter(void 0, void 0, void 0, function* () { var _a; return (_a = yield props) !== null && _a !== void 0 ? _a : {}; });
17
- const ALIAS_PREFIX = 'request';
18
- const GUILLOTINE_QUERY_REGEXP = /^\s*query\s*(?:\((.*)*\))?\s*{\s*guillotine\s*{((?:.|\s)+)}\s*}\s*$/;
19
- const GRAPHQL_FRAGMENTS_REGEXP = /fragment\s+.+\s+on\s+.+\s*{[\s\w{}().,:"'`]+}/;
20
- /** Generic fetch */
21
- export const fetchFromApi = (apiUrl, body, projectConfig, headers, method = 'POST') => __awaiter(void 0, void 0, void 0, function* () {
22
- const options = {
23
- method,
24
- headers: {
25
- 'Accept': 'application/json',
26
- 'Content-Type': 'application/json',
27
- 'X-Guillotine-SiteKey': projectConfig.site,
28
- },
29
- body: JSON.stringify(body),
30
- };
31
- if (headers) {
32
- Object.assign(options.headers, headers);
33
- }
34
- let res;
35
- try {
36
- res = yield fetch(apiUrl, options);
37
- }
38
- catch (e) {
39
- console.warn(apiUrl, e);
40
- throw new Error(JSON.stringify({
41
- code: 'API',
42
- message: e.message,
43
- }));
44
- }
45
- if (!res.ok) {
46
- throw new Error(JSON.stringify({
47
- code: res.status,
48
- message: `Data fetching failed (message: '${yield res.text()}')`,
49
- }));
11
+ import { ComponentRegistry } from '../common/ComponentRegistry';
12
+ import { UrlProcessor } from '../common/UrlProcessor';
13
+ import { FRAGMENT_CONTENTTYPE_NAME, PAGE_TEMPLATE_CONTENTTYPE_NAME, PAGE_TEMPLATE_FOLDER, RENDER_MODE, XP_COMPONENT_TYPE, XP_REQUEST_TYPE, } from '../common/constants';
14
+ import { APP_NAME, APP_NAME_DASHED, IS_DEV_MODE } from '../common/env';
15
+ import { getContentApiUrl } from '../utils/getContentApiUrl';
16
+ import { getProjectLocaleConfig } from '../utils/getProjectLocaleConfig';
17
+ import { getRenderMode } from '../utils/getRenderMode';
18
+ import { getXpBaseUrl } from '../utils/getXpBaseUrl';
19
+ import { getRequestLocaleInfo } from '../utils/getRequestLocaleInfo';
20
+ import { buildGuillotineRequestHeaders } from '../utils/buildGuillotineRequestHeaders';
21
+ import { buildPage } from './buildPage';
22
+ import { fetchMetaData } from './fetchMetaData';
23
+ import { getCleanContentPathArrayOrThrow400 } from './getCleanContentPathArrayOrThrow400';
24
+ import { buildErrorResponse } from './buildErrorResponse';
25
+ import { getContentAndComponentPaths } from './getContentAndComponentPaths';
26
+ import { restrictComponentsToPath } from './restrictComponentsToPath';
27
+ import { processComponentConfig } from './processComponentConfig';
28
+ import { getQueryAndVariables } from './getQueryAndVariables';
29
+ import { collectComponentDescriptors } from './collectComponentDescriptors';
30
+ import { combineMultipleQueries } from './combineMultipleQueries';
31
+ import { fetchContentData } from './fetchContentData';
32
+ import { applyProcessors } from './applyProcessors';
33
+ import { createMetaData } from './createMetaData';
34
+ /**
35
+ * Default fetchContent function, built with params from imports.
36
+ * It runs custom content-type-specific guillotine calls against an XP guillotine endpoint, returns content data, error and some meta data
37
+ * Sends one query to the guillotine API and asks for content type, then uses the type to select a second query and variables, which is sent to the API and fetches content data.
38
+ * @param context object from Next, contains .query info
39
+ * @returns FetchContentResult object: {data?: T, error?: {code, message}}
40
+ */
41
+ export const fetchContent = (context) => __awaiter(void 0, void 0, void 0, function* () {
42
+ var _a, _b;
43
+ const { locale, locales, defaultLocale } = getRequestLocaleInfo(context);
44
+ // ideally we only want to set headers in draft mode,
45
+ // but draft mode token is not passed in non-static mode
46
+ // so try to add them whenever they are absent
47
+ if (!context.headers) {
48
+ // TODO does this break routing or dynamic server-side rendering?
49
+ // I guess hydration will fix it anyway?
50
+ const allHeaders = headers();
51
+ context.headers = new Headers();
52
+ allHeaders.forEach((value, key) => {
53
+ context.headers.set(key, value);
54
+ });
50
55
  }
51
- let json;
56
+ const outHeaders = buildGuillotineRequestHeaders({
57
+ context,
58
+ defaultLocale,
59
+ locale,
60
+ locales,
61
+ });
62
+ const xpBaseUrl = getXpBaseUrl(context);
63
+ const contentApiUrl = getContentApiUrl(context);
64
+ const projectConfig = getProjectLocaleConfig(context);
65
+ const renderMode = getRenderMode(context);
66
+ let requestType = XP_REQUEST_TYPE.TYPE;
67
+ const requestContentPath = getCleanContentPathArrayOrThrow400(context.contentPath);
68
+ const errorResponse = buildErrorResponse(requestType, renderMode, contentApiUrl, xpBaseUrl, locale, defaultLocale, requestContentPath);
69
+ UrlProcessor.setSiteKey(projectConfig.site);
52
70
  try {
53
- json = yield res.json();
54
- }
55
- catch (e) {
56
- throw new Error(JSON.stringify({
57
- code: 500,
58
- message: `API call completed but with non-JSON data: ${JSON.stringify(yield res.text())}`,
59
- }));
60
- }
61
- if (!json) {
62
- throw new Error(JSON.stringify({
63
- code: 500,
64
- message: `API call completed but with unexpectedly empty data: ${JSON.stringify(yield res.text())}`,
65
- }));
66
- }
67
- return json;
68
- });
69
- /** Guillotine-specialized fetch, using the generic fetch above */
70
- export const fetchGuillotine = (contentApiUrl, body, projectConfig, headers) => __awaiter(void 0, void 0, void 0, function* () {
71
- var _b;
72
- if (typeof body.query !== 'string' || !body.query.trim()) {
73
- return {
74
- error: {
75
- code: '400',
76
- message: `Invalid or missing query. JSON.stringify(query) = ${JSON.stringify(body.query)}`,
77
- },
78
- };
79
- }
80
- const path = (_b = body.variables) === null || _b === void 0 ? void 0 : _b.path;
81
- const pathMessage = path ? JSON.stringify(path) : '';
82
- const result = yield fetchFromApi(contentApiUrl, body, projectConfig, headers)
83
- .then(json => {
84
- let errors = (json || {}).errors;
85
- if (errors) {
86
- if (!Array.isArray(errors)) {
87
- errors = [errors];
88
- }
89
- console.error(`${errors.length} error(s) when fetching data from: ${contentApiUrl}`);
90
- console.error(`headers: ${JSON.stringify(headers, null, 2)} \nvariables: ${JSON.stringify(body.variables, null, 2)}`);
91
- errors.forEach(error => {
92
- console.error(error);
71
+ const [siteRelativeContentPath, componentPath] = getContentAndComponentPaths(requestContentPath);
72
+ if (componentPath) {
73
+ // set component request type because url contains component path
74
+ requestType = XP_REQUEST_TYPE.COMPONENT;
75
+ }
76
+ // ///////////// FIRST GUILLOTINE CALL FOR METADATA /////////////////
77
+ const metaResult = yield fetchMetaData(contentApiUrl, '${site}/' + siteRelativeContentPath, projectConfig, outHeaders);
78
+ // ///////////////////////////////////////////////////////////////////////
79
+ const { _path, type } = metaResult.meta || {};
80
+ const contentPath = _path || siteRelativeContentPath;
81
+ if (metaResult.error) {
82
+ console.error(metaResult.error);
83
+ return errorResponse(metaResult.error.code, metaResult.error.message);
84
+ }
85
+ if (!metaResult.meta) {
86
+ return errorResponse('404', 'No meta data found for content, most likely content does not exist');
87
+ }
88
+ else if (!type) {
89
+ return errorResponse('500', "Server responded with incomplete meta data: missing content 'type' attribute.");
90
+ }
91
+ else if (renderMode === RENDER_MODE.NEXT
92
+ && !IS_DEV_MODE
93
+ && (type === FRAGMENT_CONTENTTYPE_NAME ||
94
+ type === PAGE_TEMPLATE_CONTENTTYPE_NAME ||
95
+ type === PAGE_TEMPLATE_FOLDER)) {
96
+ return errorResponse('404', `Content type [${type}] is not accessible in ${renderMode} mode`);
97
+ }
98
+ const components = restrictComponentsToPath(type, metaResult.meta.components, componentPath);
99
+ if (componentPath && !components.length) {
100
+ // component was not found
101
+ return errorResponse('404', `Component ${componentPath} was not found`);
102
+ }
103
+ if (requestType !== XP_REQUEST_TYPE.COMPONENT && components.length > 0) {
104
+ requestType = XP_REQUEST_TYPE.PAGE;
105
+ }
106
+ // ////////////////////////////////////////////////// Content type established. Proceed to data call:
107
+ const allDescriptors = [];
108
+ // Add the content type query at all cases
109
+ const contentTypeDef = ComponentRegistry.getContentType(type);
110
+ const pageCmp = (components || []).find(cmp => cmp.type === XP_COMPONENT_TYPE.PAGE);
111
+ if (pageCmp) {
112
+ processComponentConfig(APP_NAME, APP_NAME_DASHED, pageCmp);
113
+ }
114
+ const contentQueryAndVars = getQueryAndVariables(type, contentPath, context, contentTypeDef === null || contentTypeDef === void 0 ? void 0 : contentTypeDef.query, (_a = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _a === void 0 ? void 0 : _a.config);
115
+ if (contentQueryAndVars) {
116
+ allDescriptors.push({
117
+ type: contentTypeDef,
118
+ queryAndVariables: contentQueryAndVars,
93
119
  });
94
- return {
95
- error: {
96
- code: '500',
97
- message: `Server responded with ${errors.length} error(s), probably from guillotine - see log.`,
98
- },
99
- };
100
120
  }
101
- return json.data;
102
- })
103
- .catch((err) => {
104
- console.warn(`Client-side error when trying to fetch data ${pathMessage}`, err);
105
- try {
106
- return { error: JSON.parse(err.message) };
107
- }
108
- catch (e2) {
109
- return { error: { code: 'Client-side error', message: err.message } };
110
- }
111
- });
112
- return result;
113
- });
114
- // /////////////////////////////////////////////////////////////////////////////// Specific fetch wrappers:
115
- const fetchMetaData = (contentApiUrl, xpContentPath, projectConfig, headers) => __awaiter(void 0, void 0, void 0, function* () {
116
- var _c;
117
- const body = {
118
- query: getMetaQuery(pageFragmentQuery()),
119
- variables: {
120
- path: xpContentPath,
121
- },
122
- };
123
- const metaResult = yield fetchGuillotine(contentApiUrl, body, projectConfig, headers);
124
- if (metaResult.error) {
125
- return metaResult;
126
- }
127
- else {
128
- return {
129
- meta: (_c = metaResult === null || metaResult === void 0 ? void 0 : metaResult.guillotine) === null || _c === void 0 ? void 0 : _c.get,
130
- };
131
- }
132
- });
133
- const fetchContentData = (contentApiUrl, xpContentPath, projectConfig, query, variables, headers) => __awaiter(void 0, void 0, void 0, function* () {
134
- const body = { query };
135
- if (variables && Object.keys(variables).length > 0) {
136
- body.variables = variables;
137
- }
138
- const contentResults = yield fetchGuillotine(contentApiUrl, body, projectConfig, headers);
139
- if (contentResults.error) {
140
- return contentResults;
141
- }
142
- else {
143
- return {
144
- // omit the aliases and return values
145
- contents: Object.values(contentResults),
146
- };
147
- }
148
- });
149
- // /////////////////////////////////////////////////////////////////////////////// Error checking:
150
- /** Checks a site-relative contentPath as a slash-delimited string or a string array, and returns a pure site-relative path string (no double slashes, starts with a slash, does not end with one). */
151
- const getCleanContentPathArrayOrThrow400 = (contentPath) => {
152
- if (contentPath === undefined) {
153
- return '';
154
- }
155
- const isArray = Array.isArray(contentPath);
156
- if (!isArray) {
157
- if (typeof contentPath !== 'string') {
158
- throw Error(JSON.stringify({
159
- code: 400,
160
- message: `Unexpected target content _path: contentPath must be a string or pure string array (contentPath=${JSON.stringify(contentPath)})`,
161
- }));
162
- }
163
- return contentPath;
164
- }
165
- else {
166
- return (contentPath).join('/');
167
- }
168
- };
169
- function parseComponentPath(contentType, path) {
170
- const matches = [];
171
- let match;
172
- const myRegexp = /(?:(\w+)\/(\d+))+/g;
173
- while ((match = myRegexp.exec(path)) !== null) {
174
- matches.push({
175
- region: match[1],
176
- index: +match[2],
177
- });
178
- }
179
- if (contentType === FRAGMENT_CONTENTTYPE_NAME) {
180
- // there is no main region in fragment content and the root component has '/' path
181
- // prepend FRAGMENT_DEFAULT_REGION_NAME to path to conform to page structure
182
- matches.unshift({
183
- region: FRAGMENT_DEFAULT_REGION_NAME,
184
- index: 0,
185
- });
186
- }
187
- return matches;
188
- }
189
- function getParentRegion(source, contentType, cmpPath, components = [], createMissing) {
190
- let currentTree = source;
191
- let currentRegion;
192
- let parentPath = '';
193
- for (let i = 0; i < cmpPath.length; i++) {
194
- const pathFragment = cmpPath[i];
195
- const regionName = pathFragment.region;
196
- parentPath += `/${pathFragment.region}/${pathFragment.index}`;
197
- currentRegion = currentTree[regionName];
198
- if (!currentRegion) {
199
- if (createMissing) {
200
- currentRegion = {
201
- name: regionName,
202
- components: [],
203
- };
204
- currentTree[regionName] = currentRegion;
205
- }
206
- else {
207
- throw `Region [${regionName}] was not found`;
208
- }
209
- }
210
- if (i < cmpPath.length - 1) {
211
- // look for layouts inside if this is not the last path fragment
212
- const layout = components.find((cmp) => {
213
- return cmp.type === XP_COMPONENT_TYPE.LAYOUT && prefixLayoutPath(contentType, cmp.path) === parentPath;
121
+ const commonQueryAndVars = getQueryAndVariables(type, contentPath, context, ComponentRegistry.getCommonQuery(), (_b = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _b === void 0 ? void 0 : _b.config);
122
+ if (commonQueryAndVars) {
123
+ allDescriptors.push({
124
+ type: contentTypeDef,
125
+ queryAndVariables: commonQueryAndVars,
214
126
  });
215
- if (!layout) {
216
- throw `Layout [${parentPath}] not found among components, but needed for component [${JSON.stringify(cmpPath, null, 2)}]`;
217
- }
218
- if (!layout.regions) {
219
- layout.regions = {};
220
- }
221
- currentTree = layout.regions;
222
127
  }
223
- }
224
- return currentRegion;
225
- }
226
- function prefixLayoutPath(contentType, path) {
227
- if (contentType !== FRAGMENT_CONTENTTYPE_NAME) {
228
- return path;
229
- }
230
- else {
231
- // prepend FRAGMENT_DEFAULT_REGION_NAME to path to conform to page structure
232
- // so that component with path '/' becomes /FRAGMENT_DEFAULT_REGION_NAME/0
233
- // path /left/1 becomes /FRAGMENT_DEFAULT_REGION_NAME/0/left/1
234
- return `/${FRAGMENT_DEFAULT_REGION_NAME}/0${path === '/' ? '' : path}`;
235
- }
236
- }
237
- function buildPage(contentType, comps = []) {
238
- const page = {
239
- type: XP_COMPONENT_TYPE.PAGE,
240
- path: '/',
241
- };
242
- return buildComponentTree(comps, page, contentType);
243
- }
244
- function buildComponentTree(comps, rootComp, contentType) {
245
- const rootTree = {};
246
- const isFragmentType = contentType === FRAGMENT_CONTENTTYPE_NAME;
247
- if (isFragmentType) {
248
- rootComp.regions = rootTree;
249
- }
250
- (comps || []).forEach(cmp => {
251
- var _a, _b, _c;
252
- const cmpPath = parseComponentPath(contentType, cmp.path);
253
- if (cmp.path === '/') {
254
- if (cmp.type === XP_COMPONENT_TYPE.PAGE && rootComp.type === XP_COMPONENT_TYPE.PAGE) {
255
- // add page values to page object
256
- rootComp = Object.assign(rootComp, cmp);
257
- rootComp.page.regions = rootTree;
258
- return;
259
- }
260
- else if (cmp.type === XP_COMPONENT_TYPE.LAYOUT && rootComp.type === XP_COMPONENT_TYPE.FRAGMENT) {
261
- // when rendering fragment as part of the page with layout at root path
262
- // remove other children from list as they will be included in layout
263
- rootComp.fragment.fragment.components = [cmp];
264
- cmp.regions = rootTree;
128
+ if ((components === null || components === void 0 ? void 0 : components.length) && ComponentRegistry) {
129
+ for (const cmp of (components || [])) {
130
+ processComponentConfig(APP_NAME, APP_NAME_DASHED, cmp);
265
131
  }
266
- }
267
- if (cmp.type === XP_COMPONENT_TYPE.FRAGMENT) {
268
- // build component subtree for fragment
269
- cmp = buildComponentTree((_b = (_a = cmp.fragment) === null || _a === void 0 ? void 0 : _a.fragment) === null || _b === void 0 ? void 0 : _b.components, cmp, contentType);
270
- }
271
- const region = getParentRegion(rootTree, contentType, cmpPath, comps, true);
272
- if (region) {
273
- // getting the index of component from string like '/main/0/left/11'
274
- const cmpIndex = (_c = cmpPath[cmpPath.length - 1]) === null || _c === void 0 ? void 0 : _c.index;
275
- if (cmpIndex >= 0) {
276
- region.components.splice(cmpIndex, 0, cmp);
132
+ // Collect component queries if defined
133
+ const componentDescriptors = collectComponentDescriptors({
134
+ components,
135
+ xpContentPath: contentPath,
136
+ context,
137
+ });
138
+ if (componentDescriptors.length) {
139
+ allDescriptors.push(...componentDescriptors);
140
+ }
141
+ }
142
+ const { query, variables } = combineMultipleQueries(allDescriptors);
143
+ if (!query.trim()) {
144
+ return errorResponse('400', `Missing or empty query override for content type ${type}`);
145
+ }
146
+ // /////////////// SECOND GUILLOTINE CALL FOR DATA //////////////////////
147
+ const contentResults = yield fetchContentData(contentApiUrl, contentPath, projectConfig, query, variables, outHeaders);
148
+ // ///////////////////////////////////////////////////////////////////////////
149
+ if (contentResults.error) {
150
+ console.error(contentResults.error);
151
+ return errorResponse(contentResults.error.code, contentResults.error.message);
152
+ }
153
+ // Apply processors to every component
154
+ const datas = yield applyProcessors(allDescriptors, contentResults, context);
155
+ // Unwind the data back to components
156
+ let contentData = null, common = null;
157
+ let startFrom = 0;
158
+ if (contentQueryAndVars) {
159
+ const item = datas[startFrom];
160
+ contentData = item.status === 'fulfilled' ? item.value : item.reason;
161
+ startFrom++;
162
+ }
163
+ if (commonQueryAndVars) {
164
+ const item = datas[startFrom];
165
+ common = item.status === 'fulfilled' ? item.value : item.reason;
166
+ startFrom++;
167
+ }
168
+ for (let i = startFrom; i < datas.length; i++) {
169
+ // component descriptors hold references to components
170
+ // that will later be used for creating page regions
171
+ const datum = datas[i];
172
+ if (datum.status === 'rejected') {
173
+ let reason = datum.reason;
174
+ if (reason instanceof Error) {
175
+ reason = reason.message;
176
+ }
177
+ else if (typeof reason !== 'string') {
178
+ reason = String(reason);
179
+ }
180
+ allDescriptors[i].component.error = reason;
277
181
  }
278
182
  else {
279
- throw Error(`Could not find [${cmp.type}] component index at ${JSON.stringify(cmpPath, null, 2)}, rendering not possible.`);
280
- }
281
- }
282
- });
283
- return rootComp;
284
- }
285
- function combineMultipleQueries(queriesWithVars) {
286
- const queries = [];
287
- const fragments = [];
288
- const superVars = {};
289
- const superParams = [];
290
- queriesWithVars.forEach((componentDescriptor, index) => {
291
- const queryAndVars = componentDescriptor.queryAndVariables;
292
- if (!queryAndVars) {
293
- return;
294
- }
295
- // Extract fragments first if exist
296
- let q = queryAndVars.query;
297
- let match = q.match(GRAPHQL_FRAGMENTS_REGEXP);
298
- if ((match === null || match === void 0 ? void 0 : match.length) === 1) {
299
- // extract a fragment to put it at root level
300
- fragments.push(match[0]);
301
- // remove it from query because queries are going to get wrapped
302
- q = q.replace(match[0], '');
303
- }
304
- // Extract graphql query and its params and add prefixes to exclude collisions with other queries
305
- match = q.match(GUILLOTINE_QUERY_REGEXP);
306
- let query = '';
307
- if (match && match.length === 2) {
308
- // no params, just query
309
- query = match[1];
310
- }
311
- else if (match && match.length === 3) {
312
- // both query and params are present
313
- query = match[2];
314
- // process args
315
- const args = match[1];
316
- if (args) {
317
- args.split(',').forEach(originalParamString => {
318
- const [originalKey, originalVal] = originalParamString.trim().split(':');
319
- const [prefixedKey, prefixedVal] = [`$${ALIAS_PREFIX}${index}_${originalKey.substr(1)}`, originalVal];
320
- superParams.push(`${prefixedKey}:${prefixedVal}`);
321
- // also update param references in query itself !
322
- // query = query.replaceAll(originalKey, prefixedKey);
323
- // replaceAll is not supported in older nodejs versions
324
- const origKeyPattern = new RegExp(originalKey.replace(/\$/g, '\\$'), 'g');
325
- query = query.replace(origKeyPattern, prefixedKey);
326
- });
327
- }
328
- }
329
- if (query.length) {
330
- queries.push(`${ALIAS_PREFIX}${index}:guillotine {${query}}`);
331
- }
332
- // Update variables with the same prefixes
333
- Object.entries(queryAndVars.variables || {}).forEach(entry => {
334
- superVars[`${ALIAS_PREFIX}${index}_${entry[0]}`] = entry[1];
183
+ allDescriptors[i].component.data = datum.value;
184
+ }
185
+ }
186
+ const page = buildPage(type, components);
187
+ const meta = createMetaData({
188
+ apiUrl: contentApiUrl,
189
+ baseUrl: xpBaseUrl,
190
+ components,
191
+ contentPath: siteRelativeContentPath,
192
+ contentType: type,
193
+ defaultLocale,
194
+ locale,
195
+ pageCmp: page,
196
+ renderMode,
197
+ requestedComponentPath: componentPath,
198
+ requestType,
335
199
  });
336
- });
337
- // Compose the super query
338
- const superQuery = `query ${superParams.length ? `(${superParams.join(', ')})` : ''} {
339
- ${queries.join('\n')}
340
- }
341
- ${fragments.join('\n')}
342
- `;
343
- return {
344
- query: superQuery,
345
- variables: superVars,
346
- };
347
- }
348
- function applyProcessors(componentDescriptors, contentResults, context) {
349
- return __awaiter(this, void 0, void 0, function* () {
350
- let dataCounter = 0;
351
- const processorPromises = componentDescriptors.map((desc) => __awaiter(this, void 0, void 0, function* () {
352
- var _a;
353
- // we're iterating component descriptors here
354
- // some of them might not have provided graphql requests
355
- // but we still need to run props processor for them
356
- // in case they want to fetch their data from elsewhere
357
- const propsProcessor = ((_a = desc.type) === null || _a === void 0 ? void 0 : _a.processor) || NO_PROPS_PROCESSOR;
358
- let data;
359
- if (desc.queryAndVariables) {
360
- // if there is a query then there must be a result for it
361
- data = contentResults.contents[dataCounter++];
362
- }
363
- const config = getComponentConfig(desc.component);
364
- return yield propsProcessor(data, context, config);
365
- }));
366
- return Promise.allSettled(processorPromises);
367
- });
368
- }
369
- function getComponentConfig(cmp) {
370
- const cmpData = cmp && cmp[cmp.type];
371
- return cmpData && 'config' in cmpData ? cmpData.config : undefined;
372
- }
373
- function collectComponentDescriptors(components, componentRegistry, xpContentPath, context) {
374
- var _a, _b;
375
- const descriptors = [];
376
- for (const cmp of (components || [])) {
377
- processComponentConfig(APP_NAME, APP_NAME_DASHED, cmp);
378
- // only look for parts
379
- // look for single part if it is a single component request
380
- if (XP_COMPONENT_TYPE.FRAGMENT !== cmp.type) {
381
- const cmpDef = ComponentRegistry.getByComponent(cmp);
382
- if (cmpDef) {
383
- // const partPath = `${xpContentPath}/_component${cmp.path}`;
384
- const config = getComponentConfig(cmp);
385
- const queryAndVariables = getQueryAndVariables(cmp.type, xpContentPath, context, cmpDef.query, config);
386
- if (queryAndVariables) {
387
- descriptors.push({
388
- component: cmp,
389
- type: cmpDef,
390
- queryAndVariables: queryAndVariables,
391
- });
392
- }
393
- }
394
- }
395
- else {
396
- // look for parts inside fragments
397
- const fragPartDescs = collectComponentDescriptors((_b = (_a = cmp.fragment) === null || _a === void 0 ? void 0 : _a.fragment) === null || _b === void 0 ? void 0 : _b.components, componentRegistry, xpContentPath, context);
398
- if (fragPartDescs.length) {
399
- descriptors.push(...fragPartDescs);
400
- }
401
- }
402
- }
403
- return descriptors;
404
- }
405
- function processComponentConfig(myAppName, myAppNameDashed, cmp) {
406
- const cmpData = cmp[cmp.type];
407
- if (cmpData && 'descriptor' in cmpData && cmpData.descriptor) {
408
- const [appName, cmpName] = cmpData.descriptor.split(':');
409
- if (appName !== myAppName) {
410
- return;
411
- }
412
- let config;
413
- const configArray = [];
414
- if ('configAsJson' in cmpData && cmpData.configAsJson && cmpData.configAsJson[myAppNameDashed]) {
415
- config = cmpData.configAsJson[myAppNameDashed][cmpName];
416
- if (config) {
417
- configArray.push(config);
418
- delete cmpData.configAsJson;
419
- }
420
- }
421
- const sanitizedAppName = sanitizeGraphqlName(appName);
422
- if ('config' in cmpData && cmpData.config && cmpData.config[sanitizedAppName]) {
423
- config = cmpData.config[sanitizedAppName][sanitizeGraphqlName(cmpName)];
424
- if (config) {
425
- configArray.push(config);
426
- }
427
- }
428
- if (configArray.length) {
429
- cmpData.config = Object.assign({}, ...configArray);
430
- }
431
- }
432
- }
433
- function getQueryAndVariables(type, path, context, selectedQuery, config) {
434
- let query, getVariables;
435
- if (typeof selectedQuery === 'string' || typeof selectedQuery === 'function') {
436
- query = selectedQuery;
437
- }
438
- else if (Array.isArray(selectedQuery)) {
439
- query = selectedQuery[0];
440
- getVariables = selectedQuery[1];
441
- }
442
- else if (typeof selectedQuery === 'object') {
443
- query = selectedQuery.query;
444
- getVariables = selectedQuery.variables;
445
- }
446
- if (getVariables && typeof getVariables !== 'function') {
447
- throw Error(`getVariables for content type ${type} should be a function, not: ${typeof getVariables}`);
448
- }
449
- if (query && typeof query !== 'string' && typeof query !== 'function') {
450
- throw Error(`Query for content type ${type} should be a string or function, not: ${typeof query}`);
451
- }
452
- if (typeof query === 'function') {
453
- query = query(path, context, config);
454
- }
455
- if (query) {
456
- return {
457
- query,
458
- variables: getVariables ? getVariables(path, context, config) : { path },
459
- };
460
- }
461
- }
462
- function createPageData(contentType, components, componentPath) {
463
- let page;
464
- if (components && !componentPath) {
465
- page = buildPage(contentType, components);
466
- }
467
- else {
468
- // Don't build page for single component
469
- page = null;
470
- }
471
- return page;
472
- }
473
- function createMetaData(contentType, contentPath, requestType, renderMode, apiUrl, baseUrl, locale, defaultLocale, requestedComponentPath, pageCmp, components = []) {
474
- var _a;
475
- // .meta will be visible in final rendered inline props.
476
- // Only adding some .meta attributes here on certain conditions
477
- // (instead of always adding them and letting them be visible as false/undefined etc)
478
- const meta = {
479
- type: contentType,
480
- path: contentPath,
481
- requestType: requestType,
482
- renderMode: renderMode,
483
- canRender: false,
484
- catchAll: false,
485
- apiUrl,
486
- baseUrl,
487
- locale,
488
- defaultLocale,
489
- };
490
- if (requestedComponentPath) {
491
- meta.requestedComponent = components.find(cmp => cmp.path === requestedComponentPath);
492
- }
493
- const pageDesc = (_a = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _a === void 0 ? void 0 : _a.descriptor;
494
- const typeDef = ComponentRegistry.getContentType(contentType);
495
- if ((typeDef === null || typeDef === void 0 ? void 0 : typeDef.view) && !typeDef.catchAll) {
496
- meta.canRender = true;
497
- }
498
- else if (requestType === XP_REQUEST_TYPE.COMPONENT) {
499
- // always render a single component (show missing if not implemented)
500
- meta.canRender = true;
501
- }
502
- else if (pageDesc) {
503
- // always render a page if there is a descriptor (show missing if not implemented)
504
- meta.canRender = true;
505
- }
506
- else if (typeDef === null || typeDef === void 0 ? void 0 : typeDef.view) {
507
- meta.canRender = true;
508
- meta.catchAll = true;
509
- }
510
- return meta;
511
- }
512
- function buildErrorResponse(requestType, renderMode, apiUrl, baseUrl, locale, defaultLocale, contentPath) {
513
- return function (code = '500', message = 'Unknown error') {
514
200
  return {
515
- error: {
516
- code,
517
- message,
518
- },
519
- page: null,
520
- common: null,
521
- data: null,
522
- meta: {
523
- type: '',
524
- requestType: requestType,
525
- renderMode: renderMode,
526
- path: contentPath || '',
527
- canRender: false,
528
- catchAll: false,
529
- apiUrl,
530
- baseUrl,
531
- locale,
532
- defaultLocale,
533
- },
201
+ data: contentData,
202
+ common,
203
+ meta,
204
+ page,
534
205
  };
535
- };
536
- }
537
- function restrictComponentsToPath(contentType, components, componentPath) {
538
- if (!componentPath || !(components === null || components === void 0 ? void 0 : components.length)) {
539
- return components || [];
540
- }
541
- // filter components to the requested one only
542
- const component = components.find(cmp => {
543
- return cmp.path === componentPath;
544
- });
545
- if (!component) {
546
- return [];
547
- }
548
- let result = [component];
549
- if (component.type !== XP_COMPONENT_TYPE.LAYOUT) {
550
- // remember to include all parent layouts too !
551
- const cmpPath = parseComponentPath(contentType, component.path);
552
- for (let i = cmpPath.length - 2; i >= 0; i--) {
553
- const parentPath = cmpPath[i];
554
- const parentCmp = components.find(cmp => cmp.path === `/${parentPath.region}/${parentPath.index}`);
555
- if (parentCmp) {
556
- result.unshift(parentCmp);
557
- }
558
- }
559
- }
560
- else {
561
- // It's a layout, include child components
562
- const childCmps = components.filter(cmp => cmp.path !== component.path && cmp.path.startsWith(component.path));
563
- if (childCmps.length) {
564
- result = result.concat(childCmps);
565
- }
566
- }
567
- return result;
568
- }
569
- const COMPONENT_PATH_KEY = /\/?_\/component/; // first slash is optional for root components
570
- const getContentAndComponentPaths = (requestPath) => {
571
- let contentPath, componentPath;
572
- if (COMPONENT_PATH_KEY.test(requestPath)) {
573
- [contentPath, componentPath] = requestPath.split(COMPONENT_PATH_KEY);
574
- }
575
- else {
576
- contentPath = requestPath;
577
206
  }
578
- return [contentPath, componentPath];
579
- };
580
- // ///////////////////////////// ENTRY 1 - THE BUILDER:
581
- /**
582
- * Configures, builds and returns a general fetchContent function.
583
- * @param config object containing ComponentRegistry as well as constants imported from enonic-connecion-config.js
584
- * @returns ContentFetcher
585
- */
586
- const buildContentFetcher = (config) => {
587
- const { APP_NAME, APP_NAME_DASHED, componentRegistry, } = config;
588
- return (context) => __awaiter(void 0, void 0, void 0, function* () {
589
- var _a, _b;
590
- const { locale, locales, defaultLocale } = getRequestLocaleInfo(context);
591
- // ideally we only want to set headers in draft mode,
592
- // but draft mode token is not passed in non-static mode
593
- // so try to add them whenever they are absent
594
- if (!context.headers) {
595
- const allHeaders = headers();
596
- context.headers = new Headers();
597
- allHeaders.forEach((value, key) => {
598
- context.headers.set(key, value);
599
- });
600
- }
601
- const outHeaders = {};
602
- addJsessionHeaders(outHeaders, context);
603
- addLocaleHeaders(outHeaders, locale, locales, defaultLocale);
604
- const xpBaseUrl = getXpBaseUrl(context);
605
- const contentApiUrl = getContentApiUrl(context);
606
- const projectConfig = getProjectLocaleConfig(context);
607
- const renderMode = getRenderMode(context);
608
- let requestType = XP_REQUEST_TYPE.TYPE;
609
- const requestContentPath = getCleanContentPathArrayOrThrow400(context.contentPath);
610
- const errorResponse = buildErrorResponse(requestType, renderMode, contentApiUrl, xpBaseUrl, locale, defaultLocale, requestContentPath);
611
- UrlProcessor.setSiteKey(projectConfig.site);
207
+ catch (e) {
208
+ console.error(e);
209
+ let error;
612
210
  try {
613
- const [siteRelativeContentPath, componentPath] = getContentAndComponentPaths(requestContentPath);
614
- if (componentPath) {
615
- // set component request type because url contains component path
616
- requestType = XP_REQUEST_TYPE.COMPONENT;
617
- }
618
- // ///////////// FIRST GUILLOTINE CALL FOR METADATA /////////////////
619
- const metaResult = yield fetchMetaData(contentApiUrl, '${site}/' + siteRelativeContentPath, projectConfig, outHeaders);
620
- // ///////////////////////////////////////////////////////////////////////
621
- const { _path, type } = metaResult.meta || {};
622
- const contentPath = _path || siteRelativeContentPath;
623
- if (metaResult.error) {
624
- console.error(metaResult.error);
625
- return errorResponse(metaResult.error.code, metaResult.error.message);
626
- }
627
- if (!metaResult.meta) {
628
- return errorResponse('404', 'No meta data found for content, most likely content does not exist');
629
- }
630
- else if (!type) {
631
- return errorResponse('500', "Server responded with incomplete meta data: missing content 'type' attribute.");
632
- }
633
- else if (renderMode === RENDER_MODE.NEXT && !IS_DEV_MODE &&
634
- (type === FRAGMENT_CONTENTTYPE_NAME ||
635
- type === PAGE_TEMPLATE_CONTENTTYPE_NAME ||
636
- type === PAGE_TEMPLATE_FOLDER)) {
637
- return errorResponse('404', `Content type [${type}] is not accessible in ${renderMode} mode`);
638
- }
639
- const components = restrictComponentsToPath(type, metaResult.meta.components, componentPath);
640
- if (componentPath && !components.length) {
641
- // component was not found
642
- return errorResponse('404', `Component ${componentPath} was not found`);
643
- }
644
- if (requestType !== XP_REQUEST_TYPE.COMPONENT && components.length > 0) {
645
- requestType = XP_REQUEST_TYPE.PAGE;
646
- }
647
- // ////////////////////////////////////////////////// Content type established. Proceed to data call:
648
- const allDescriptors = [];
649
- // Add the content type query at all cases
650
- const contentTypeDef = componentRegistry === null || componentRegistry === void 0 ? void 0 : componentRegistry.getContentType(type);
651
- const pageCmp = (components || []).find(cmp => cmp.type === XP_COMPONENT_TYPE.PAGE);
652
- if (pageCmp) {
653
- processComponentConfig(APP_NAME, APP_NAME_DASHED, pageCmp);
654
- }
655
- const contentQueryAndVars = getQueryAndVariables(type, contentPath, context, contentTypeDef === null || contentTypeDef === void 0 ? void 0 : contentTypeDef.query, (_a = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _a === void 0 ? void 0 : _a.config);
656
- if (contentQueryAndVars) {
657
- allDescriptors.push({
658
- type: contentTypeDef,
659
- queryAndVariables: contentQueryAndVars,
660
- });
661
- }
662
- const commonQueryAndVars = getQueryAndVariables(type, contentPath, context, componentRegistry.getCommonQuery(), (_b = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _b === void 0 ? void 0 : _b.config);
663
- if (commonQueryAndVars) {
664
- allDescriptors.push({
665
- type: contentTypeDef,
666
- queryAndVariables: commonQueryAndVars,
667
- });
668
- }
669
- if ((components === null || components === void 0 ? void 0 : components.length) && componentRegistry) {
670
- for (const cmp of (components || [])) {
671
- processComponentConfig(APP_NAME, APP_NAME_DASHED, cmp);
672
- }
673
- // Collect component queries if defined
674
- const componentDescriptors = collectComponentDescriptors(components, componentRegistry, contentPath, context);
675
- if (componentDescriptors.length) {
676
- allDescriptors.push(...componentDescriptors);
677
- }
678
- }
679
- const { query, variables } = combineMultipleQueries(allDescriptors);
680
- if (!query.trim()) {
681
- return errorResponse('400', `Missing or empty query override for content type ${type}`);
682
- }
683
- // /////////////// SECOND GUILLOTINE CALL FOR DATA //////////////////////
684
- const contentResults = yield fetchContentData(contentApiUrl, contentPath, projectConfig, query, variables, outHeaders);
685
- // ///////////////////////////////////////////////////////////////////////////
686
- if (contentResults.error) {
687
- console.error(contentResults.error);
688
- return errorResponse(contentResults.error.code, contentResults.error.message);
689
- }
690
- // Apply processors to every component
691
- const datas = yield applyProcessors(allDescriptors, contentResults, context);
692
- // Unwind the data back to components
693
- let contentData = null, common = null;
694
- let startFrom = 0;
695
- if (contentQueryAndVars) {
696
- const item = datas[startFrom];
697
- contentData = item.status === 'fulfilled' ? item.value : item.reason;
698
- startFrom++;
699
- }
700
- if (commonQueryAndVars) {
701
- const item = datas[startFrom];
702
- common = item.status === 'fulfilled' ? item.value : item.reason;
703
- startFrom++;
704
- }
705
- for (let i = startFrom; i < datas.length; i++) {
706
- // component descriptors hold references to components
707
- // that will later be used for creating page regions
708
- const datum = datas[i];
709
- if (datum.status === 'rejected') {
710
- let reason = datum.reason;
711
- if (reason instanceof Error) {
712
- reason = reason.message;
713
- }
714
- else if (typeof reason !== 'string') {
715
- reason = String(reason);
716
- }
717
- allDescriptors[i].component.error = reason;
718
- }
719
- else {
720
- allDescriptors[i].component.data = datum.value;
721
- }
722
- }
723
- const page = createPageData(type, components);
724
- const meta = createMetaData(type, siteRelativeContentPath, requestType, renderMode, contentApiUrl, xpBaseUrl, locale, defaultLocale, componentPath, page, components);
725
- return {
726
- data: contentData,
727
- common,
728
- meta,
729
- page,
730
- };
731
- }
732
- catch (e) {
733
- console.error(e);
734
- let error;
735
- try {
736
- error = JSON.parse(e.message);
737
- }
738
- catch (e2) {
739
- error = {
740
- code: 'Local',
741
- message: e.message,
742
- };
743
- }
744
- return errorResponse(error.code, error.message);
211
+ error = JSON.parse(e.message);
745
212
  }
746
- });
747
- };
748
- // //////////////////////////// ENTRY 2: ready-to-use fetchContent function
749
- /**
750
- * Default fetchContent function, built with params from imports.
751
- * It runs custom content-type-specific guillotine calls against an XP guillotine endpoint, returns content data, error and some meta data
752
- * Sends one query to the guillotine API and asks for content type, then uses the type to select a second query and variables, which is sent to the API and fetches content data.
753
- * @param contentPath string or string array: local (site-relative) path to a content available on the API (by XP _path - obtainable by running contentPath through getXpPath). Pre-split into string array, or already a slash-delimited string.
754
- * @param context object from Next, contains .query info
755
- * @returns FetchContentResult object: {data?: T, error?: {code, message}}
756
- */
757
- export const fetchContent = buildContentFetcher(Object.assign(Object.assign({}, adapterConstants), { componentRegistry: ComponentRegistry }));
758
- export function validateData(props) {
759
- validateNotFound(props);
760
- validateShortcut(props);
761
- }
762
- function validateNotFound(props) {
763
- const { error } = props;
764
- if (error) {
765
- switch (error.code) {
766
- case '404':
767
- console.warn(error.code, error.message);
768
- notFound();
769
- break;
770
- default:
771
- console.error(error.code, error.message);
772
- throw new Error(error.message);
773
- }
774
- }
775
- }
776
- function validateShortcut(props) {
777
- var _a, _b, _c;
778
- const { data, meta, error } = props;
779
- const pageUrl = (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.get) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.target) === null || _c === void 0 ? void 0 : _c.pageUrl;
780
- if (meta.type === 'base:shortcut' && pageUrl) {
781
- if (meta.renderMode !== RENDER_MODE.NEXT) {
782
- // console.debug(`Returning 404 for shortcut in ${RENDER_MODE.NEXT} mode`);
783
- // do not show shortcut targets in preview/edit mode
784
- console.warn(404, `Shortcuts are not available in ${RENDER_MODE.NEXT} render mode`);
785
- notFound();
213
+ catch (e2) {
214
+ error = {
215
+ code: 'Local',
216
+ message: e.message,
217
+ };
786
218
  }
787
- const destination = UrlProcessor.process(pageUrl, meta, true);
788
- console.debug(`Redirecting shortcut content [${meta.path}] to`, destination);
789
- redirect(destination, RedirectType.replace);
790
- }
791
- // we can not set 418 for static paths,
792
- // but we can show 404 instead to be handled in CS
793
- const canNotRender = meta && !meta.canRender && meta.renderMode !== RENDER_MODE.EDIT;
794
- const catchAllInNextProdMode = (meta === null || meta === void 0 ? void 0 : meta.renderMode) === RENDER_MODE.NEXT && !IS_DEV_MODE && (meta === null || meta === void 0 ? void 0 : meta.catchAll);
795
- const isNotFound = (error && error.code === '404') || canNotRender || catchAllInNextProdMode;
796
- if (isNotFound) {
797
- console.warn(404, `Can not render content at [${meta.path}]`);
798
- notFound();
219
+ return errorResponse(error.code, error.message);
799
220
  }
800
- }
801
- export function fetchContentPathsForAllLocales(path, query = GET_STATIC_PATHS_QUERY, countPerLocale = 999) {
802
- return __awaiter(this, void 0, void 0, function* () {
803
- const promises = Object.values(getProjectLocaleConfigs()).map(config => fetchContentPathsForLocale(path, config, query, countPerLocale));
804
- return Promise.all(promises).then(results => {
805
- return results.reduce((all, localePaths) => all.concat(localePaths), []);
806
- });
807
- });
808
- }
809
- export function fetchContentPathsForLocale(path, config, query = GET_STATIC_PATHS_QUERY, count = 999) {
810
- return __awaiter(this, void 0, void 0, function* () {
811
- const contentApiUrl = getContentApiUrl({
812
- contentPath: path,
813
- locale: config.locale,
814
- });
815
- const body = {
816
- query,
817
- variables: {
818
- path,
819
- count,
820
- },
821
- };
822
- return fetchGuillotine(contentApiUrl, body, config).then((results) => {
823
- return results.guillotine.queryDsl.reduce((prev, child) => {
824
- var _a;
825
- const regexp = new RegExp(`/${(_a = child.site) === null || _a === void 0 ? void 0 : _a._name}/?`);
826
- const contentPath = child._path.replace(regexp, '');
827
- prev.push({
828
- contentPath: contentPath.split('/'),
829
- locale: config.locale,
830
- });
831
- return prev;
832
- }, []);
833
- });
834
- });
835
- }
221
+ });
222
+ //# sourceMappingURL=fetchContent.js.map