@sitecore-content-sdk/nextjs 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 (112) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +10 -0
  3. package/dist/cjs/ComponentBuilder.js +63 -0
  4. package/dist/cjs/components/BYOCWrapper.js +41 -0
  5. package/dist/cjs/components/ComponentPropsContext.js +57 -0
  6. package/dist/cjs/components/FEaaSWrapper.js +43 -0
  7. package/dist/cjs/components/Link.js +87 -0
  8. package/dist/cjs/components/NextImage.js +82 -0
  9. package/dist/cjs/components/Placeholder.js +49 -0
  10. package/dist/cjs/components/RichText.js +95 -0
  11. package/dist/cjs/editing/constants.js +10 -0
  12. package/dist/cjs/editing/editing-config-middleware.js +62 -0
  13. package/dist/cjs/editing/editing-render-middleware.js +182 -0
  14. package/dist/cjs/editing/feaas-render-middleware.js +101 -0
  15. package/dist/cjs/editing/index.js +16 -0
  16. package/dist/cjs/editing/render-middleware.js +43 -0
  17. package/dist/cjs/graphql/index.js +7 -0
  18. package/dist/cjs/index.js +119 -0
  19. package/dist/cjs/middleware/index.js +13 -0
  20. package/dist/cjs/middleware/middleware.js +97 -0
  21. package/dist/cjs/middleware/multisite-middleware.js +93 -0
  22. package/dist/cjs/middleware/personalize-middleware.js +231 -0
  23. package/dist/cjs/middleware/redirects-middleware.js +264 -0
  24. package/dist/cjs/monitoring/healthcheck-middleware.js +30 -0
  25. package/dist/cjs/monitoring/index.js +5 -0
  26. package/dist/cjs/services/base-graphql-sitemap-service.js +206 -0
  27. package/dist/cjs/services/component-props-service.js +167 -0
  28. package/dist/cjs/services/graphql-sitemap-service.js +64 -0
  29. package/dist/cjs/services/mutisite-graphql-sitemap-service.js +81 -0
  30. package/dist/cjs/sharedTypes/component-props.js +2 -0
  31. package/dist/cjs/sharedTypes/module-factory.js +2 -0
  32. package/dist/cjs/site/index.js +5 -0
  33. package/dist/cjs/utils/index.js +11 -0
  34. package/dist/cjs/utils/utils.js +42 -0
  35. package/dist/esm/ComponentBuilder.js +59 -0
  36. package/dist/esm/components/BYOCWrapper.js +36 -0
  37. package/dist/esm/components/ComponentPropsContext.js +19 -0
  38. package/dist/esm/components/FEaaSWrapper.js +38 -0
  39. package/dist/esm/components/Link.js +48 -0
  40. package/dist/esm/components/NextImage.js +76 -0
  41. package/dist/esm/components/Placeholder.js +12 -0
  42. package/dist/esm/components/RichText.js +55 -0
  43. package/dist/esm/editing/constants.js +7 -0
  44. package/dist/esm/editing/editing-config-middleware.js +58 -0
  45. package/dist/esm/editing/editing-render-middleware.js +177 -0
  46. package/dist/esm/editing/feaas-render-middleware.js +97 -0
  47. package/dist/esm/editing/index.js +5 -0
  48. package/dist/esm/editing/render-middleware.js +39 -0
  49. package/dist/esm/graphql/index.js +1 -0
  50. package/dist/esm/index.js +23 -0
  51. package/dist/esm/middleware/index.js +5 -0
  52. package/dist/esm/middleware/middleware.js +93 -0
  53. package/dist/esm/middleware/multisite-middleware.js +89 -0
  54. package/dist/esm/middleware/personalize-middleware.js +227 -0
  55. package/dist/esm/middleware/redirects-middleware.js +257 -0
  56. package/dist/esm/monitoring/healthcheck-middleware.js +26 -0
  57. package/dist/esm/monitoring/index.js +1 -0
  58. package/dist/esm/services/base-graphql-sitemap-service.js +201 -0
  59. package/dist/esm/services/component-props-service.js +160 -0
  60. package/dist/esm/services/graphql-sitemap-service.js +59 -0
  61. package/dist/esm/services/mutisite-graphql-sitemap-service.js +77 -0
  62. package/dist/esm/sharedTypes/component-props.js +1 -0
  63. package/dist/esm/sharedTypes/module-factory.js +1 -0
  64. package/dist/esm/site/index.js +1 -0
  65. package/dist/esm/utils/index.js +3 -0
  66. package/dist/esm/utils/utils.js +37 -0
  67. package/editing.d.ts +1 -0
  68. package/editing.js +1 -0
  69. package/global.d.ts +21 -0
  70. package/graphql.d.ts +1 -0
  71. package/graphql.js +1 -0
  72. package/middleware.d.ts +1 -0
  73. package/middleware.js +1 -0
  74. package/monitoring.d.ts +1 -0
  75. package/monitoring.js +1 -0
  76. package/package.json +92 -0
  77. package/site.d.ts +1 -0
  78. package/site.js +1 -0
  79. package/types/ComponentBuilder.d.ts +59 -0
  80. package/types/components/BYOCWrapper.d.ts +20 -0
  81. package/types/components/ComponentPropsContext.d.ts +18 -0
  82. package/types/components/FEaaSWrapper.d.ts +22 -0
  83. package/types/components/Link.d.ts +10 -0
  84. package/types/components/NextImage.d.ts +6 -0
  85. package/types/components/Placeholder.d.ts +8 -0
  86. package/types/components/RichText.d.ts +32 -0
  87. package/types/editing/constants.d.ts +7 -0
  88. package/types/editing/editing-config-middleware.d.ts +29 -0
  89. package/types/editing/editing-render-middleware.d.ts +79 -0
  90. package/types/editing/feaas-render-middleware.d.ts +32 -0
  91. package/types/editing/index.d.ts +5 -0
  92. package/types/editing/render-middleware.d.ts +24 -0
  93. package/types/graphql/index.d.ts +1 -0
  94. package/types/index.d.ts +24 -0
  95. package/types/middleware/index.d.ts +5 -0
  96. package/types/middleware/middleware.d.ts +82 -0
  97. package/types/middleware/multisite-middleware.d.ts +39 -0
  98. package/types/middleware/personalize-middleware.d.ts +102 -0
  99. package/types/middleware/redirects-middleware.d.ts +57 -0
  100. package/types/monitoring/healthcheck-middleware.d.ts +12 -0
  101. package/types/monitoring/index.d.ts +1 -0
  102. package/types/services/base-graphql-sitemap-service.d.ts +148 -0
  103. package/types/services/component-props-service.d.ts +81 -0
  104. package/types/services/graphql-sitemap-service.d.ts +51 -0
  105. package/types/services/mutisite-graphql-sitemap-service.d.ts +42 -0
  106. package/types/sharedTypes/component-props.d.ts +26 -0
  107. package/types/sharedTypes/module-factory.d.ts +32 -0
  108. package/types/site/index.d.ts +1 -0
  109. package/types/utils/index.d.ts +3 -0
  110. package/types/utils/utils.d.ts +8 -0
  111. package/utils.d.ts +1 -0
  112. package/utils.js +1 -0
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.GraphQLSitemapService = exports.siteError = exports.languageError = void 0;
13
+ exports.getSiteEmptyError = getSiteEmptyError;
14
+ const base_graphql_sitemap_service_1 = require("./base-graphql-sitemap-service");
15
+ /** @private */
16
+ exports.languageError = 'The list of languages cannot be empty';
17
+ exports.siteError = 'The service needs a site name';
18
+ /**
19
+ * @param {string} siteName to inject into error text
20
+ * @private
21
+ */
22
+ function getSiteEmptyError(siteName) {
23
+ return `Site "${siteName}" does not exist or site item tree is missing`;
24
+ }
25
+ /**
26
+ * Service that fetches the list of site pages using Sitecore's GraphQL API.
27
+ * Used to handle a single site
28
+ * This list is used for SSG and Export functionality.
29
+ * @mixes SearchQueryService<PageListQueryResult>
30
+ */
31
+ class GraphQLSitemapService extends base_graphql_sitemap_service_1.BaseGraphQLSitemapService {
32
+ /**
33
+ * Creates an instance of graphQL sitemap service with the provided options
34
+ * @param {GraphQLSitemapServiceConfig} options instance
35
+ */
36
+ constructor(options) {
37
+ super(options);
38
+ this.options = options;
39
+ }
40
+ /**
41
+ * Fetch a flat list of all pages that belong to the specificed site and have a
42
+ * version in the specified language(s).
43
+ * @param {string[]} languages Fetch pages that have versions in this language(s).
44
+ * @param {Function} formatStaticPath Function for transforming the raw search results into (@see StaticPath) types.
45
+ * @returns list of pages
46
+ * @throws {RangeError} if the list of languages is empty.
47
+ * @throws {RangeError} if the any of the languages is an empty string.
48
+ */
49
+ fetchSitemap(languages, formatStaticPath) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ const paths = new Array();
52
+ if (!languages.length) {
53
+ throw new RangeError(exports.languageError);
54
+ }
55
+ const siteName = this.options.siteName;
56
+ if (!siteName) {
57
+ throw new RangeError(exports.siteError);
58
+ }
59
+ paths.push(...(yield this.getTranformedPaths(siteName, languages, formatStaticPath)));
60
+ return [].concat(...paths);
61
+ });
62
+ }
63
+ }
64
+ exports.GraphQLSitemapService = GraphQLSitemapService;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.MultisiteGraphQLSitemapService = exports.sitesError = void 0;
13
+ const site_1 = require("@sitecore-content-sdk/core/site");
14
+ const base_graphql_sitemap_service_1 = require("./base-graphql-sitemap-service");
15
+ exports.sitesError = 'The list of sites cannot be empty';
16
+ /**
17
+ * Service that fetches the list of site pages using Sitecore's GraphQL API.
18
+ * Used to handle multiple sites
19
+ * This list is used for SSG and Export functionality.
20
+ * @mixes SearchQueryService<PageListQueryResult>
21
+ */
22
+ class MultisiteGraphQLSitemapService extends base_graphql_sitemap_service_1.BaseGraphQLSitemapService {
23
+ /**
24
+ * Creates an instance of graphQL sitemap service with the provided options
25
+ * @param {MultisiteGraphQLSitemapServiceConfig} options instance
26
+ */
27
+ constructor(options) {
28
+ super(options);
29
+ this.options = options;
30
+ }
31
+ /**
32
+ * Fetch a flat list of all pages that belong to all the requested sites and have a
33
+ * version in the specified language(s).
34
+ * @param {string[]} languages Fetch pages that have versions in this language(s).
35
+ * @param {Function} formatStaticPath Function for transforming the raw search results into (@see StaticPath) types.
36
+ * @returns list of pages
37
+ * @throws {RangeError} if the list of languages is empty.
38
+ * @throws {RangeError} if the any of the languages is an empty string.
39
+ */
40
+ fetchSitemap(languages, formatStaticPath) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ const paths = new Array();
43
+ if (!languages.length) {
44
+ throw new RangeError(base_graphql_sitemap_service_1.languageError);
45
+ }
46
+ // Get all sites
47
+ const sites = this.options.sites;
48
+ if (!sites || !sites.length) {
49
+ throw new RangeError(exports.sitesError);
50
+ }
51
+ // Fetch paths for each site
52
+ for (let i = 0; i < sites.length; i++) {
53
+ const siteName = sites[i];
54
+ // Fetch paths using all locales
55
+ paths.push(...(yield this.getTranformedPaths(siteName, languages, formatStaticPath)));
56
+ }
57
+ return [].concat(...paths);
58
+ });
59
+ }
60
+ /**
61
+ * Fetch and return site paths for multisite implementation, with prefixes included
62
+ * @param {string} language path language
63
+ * @param {string} siteName site name
64
+ * @returns modified paths
65
+ */
66
+ fetchLanguageSitePaths(language, siteName) {
67
+ const _super = Object.create(null, {
68
+ fetchLanguageSitePaths: { get: () => super.fetchLanguageSitePaths }
69
+ });
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ const results = yield _super.fetchLanguageSitePaths.call(this, language, siteName);
72
+ results.forEach((item) => {
73
+ if (item) {
74
+ item.path = (0, site_1.getSiteRewrite)(item.path, { siteName: siteName });
75
+ }
76
+ });
77
+ return results;
78
+ });
79
+ }
80
+ }
81
+ exports.MultisiteGraphQLSitemapService = MultisiteGraphQLSitemapService;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SiteResolver = void 0;
4
+ var site_1 = require("@sitecore-content-sdk/core/site");
5
+ Object.defineProperty(exports, "SiteResolver", { enumerable: true, get: function () { return site_1.SiteResolver; } });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resetEditorChromes = exports.isEditorActive = exports.resolveUrl = exports.tryParseEnvValue = exports.handleEditorFastRefresh = void 0;
4
+ var utils_1 = require("./utils");
5
+ Object.defineProperty(exports, "handleEditorFastRefresh", { enumerable: true, get: function () { return utils_1.handleEditorFastRefresh; } });
6
+ var utils_2 = require("@sitecore-content-sdk/core/utils");
7
+ Object.defineProperty(exports, "tryParseEnvValue", { enumerable: true, get: function () { return utils_2.tryParseEnvValue; } });
8
+ Object.defineProperty(exports, "resolveUrl", { enumerable: true, get: function () { return utils_2.resolveUrl; } });
9
+ var editing_1 = require("@sitecore-content-sdk/core/editing");
10
+ Object.defineProperty(exports, "isEditorActive", { enumerable: true, get: function () { return editing_1.isEditorActive; } });
11
+ Object.defineProperty(exports, "resetEditorChromes", { enumerable: true, get: function () { return editing_1.resetEditorChromes; } });
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getJssEditingSecret = exports.handleEditorFastRefresh = void 0;
4
+ const editing_1 = require("@sitecore-content-sdk/core/editing");
5
+ /**
6
+ * Since Sitecore editors do not support Fast Refresh:
7
+ * 1. Subscribe on events provided by webpack.
8
+ * 2. Reset editor chromes when build is finished
9
+ * @param {boolean} [forceReload] force page reload instead of reset chromes
10
+ */
11
+ const handleEditorFastRefresh = (forceReload = false) => {
12
+ if (process.env.NODE_ENV !== 'development' || !(0, editing_1.isEditorActive)()) {
13
+ // Only run if development mode and editor is active
14
+ return;
15
+ }
16
+ const eventSource = new window.EventSource('/_next/webpack-hmr');
17
+ window.addEventListener('beforeunload', () => eventSource.close());
18
+ eventSource.onopen = () => console.log('[Sitecore Editor Fast Refresh Listener] Online');
19
+ eventSource.onmessage = (event) => {
20
+ if (event.data.indexOf('{') === -1)
21
+ return; // heartbeat
22
+ const payload = JSON.parse(event.data);
23
+ console.debug(`[Sitecore Editor Fast Refresh Listener] Saw event: ${JSON.stringify(payload)}`);
24
+ if (payload.action !== 'built')
25
+ return;
26
+ if (forceReload)
27
+ return window.location.reload();
28
+ setTimeout(() => {
29
+ console.log('[Sitecore Editor HMR Listener] Sitecore editor does not support Fast Refresh, reloading chromes...');
30
+ (0, editing_1.resetEditorChromes)();
31
+ }, 500);
32
+ };
33
+ };
34
+ exports.handleEditorFastRefresh = handleEditorFastRefresh;
35
+ const getJssEditingSecret = () => {
36
+ const secret = process.env.JSS_EDITING_SECRET;
37
+ if (!secret || secret.length === 0) {
38
+ throw new Error('The JSS_EDITING_SECRET environment variable is missing or invalid.');
39
+ }
40
+ return secret;
41
+ };
42
+ exports.getJssEditingSecret = getJssEditingSecret;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Nextjs implementation of component builder class for building components based on the configuration.
3
+ */
4
+ export class ComponentBuilder {
5
+ constructor(config) {
6
+ this.config = config;
7
+ /**
8
+ * SXA uses custom default export name
9
+ */
10
+ this.DEFAULT_EXPORT_NAME = 'Default';
11
+ this.components = new Map([...config.components]);
12
+ }
13
+ /**
14
+ * Creates a new instance of module factory
15
+ * Module factory provides a module (file) including all exports.
16
+ * Module can be imported dynamically or statically.
17
+ * @returns {ModuleFactory} Module factory implementation
18
+ */
19
+ getModuleFactory() {
20
+ return (componentName) => {
21
+ const component = this.components.get(componentName);
22
+ if (!component)
23
+ return null;
24
+ // check if module should be imported dynamically
25
+ if (component.module) {
26
+ return component.module();
27
+ }
28
+ return component;
29
+ };
30
+ }
31
+ /**
32
+ * Creates a new instance of component factory
33
+ * Component can be imported dynamically or statically.
34
+ * @param {object} [config] Component factory configuration
35
+ * @param {boolean} [config.isEditing] Indicates if component factory is used in editing mode
36
+ * @returns {ComponentFactory} Component factory implementation
37
+ */
38
+ getComponentFactory({ isEditing } = {}) {
39
+ return (componentName, exportName) => {
40
+ const component = this.components.get(componentName);
41
+ if (!component)
42
+ return null;
43
+ // check if component should be imported dynamically
44
+ if (component.element) {
45
+ // Editing mode doesn't work well with dynamic components in nextjs: dynamic components are not displayed without refresh after a rendering is added.
46
+ // This happens beacuse Sitecore editors simply insert updated HTML generated on server side. This conflicts with nextjs dynamic logic as no HTML gets rendered for dynamic component
47
+ // So we use require() to obtain dynamic components in editing mode while preserving dynamic logic for non-editing scenarios
48
+ // As we need to be able to seamlessly work with dynamic components in both editing and normal modes, different componentFactory functions will be passed to app
49
+ return component.element(isEditing);
50
+ }
51
+ if (exportName && exportName !== this.DEFAULT_EXPORT_NAME) {
52
+ return component[exportName];
53
+ }
54
+ return (component.Default ||
55
+ component.default ||
56
+ component);
57
+ };
58
+ }
59
+ }
@@ -0,0 +1,36 @@
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 { BYOCWrapper, fetchBYOCComponentServerProps, } from '@sitecore-content-sdk/react';
11
+ /**
12
+ * TODO: remove when framework agnostic forms implemented
13
+ * This is a repackaged version of the React BYOCWrapper component with support for
14
+ * server rendering in Next.js (using component-level data-fetching feature of JSS).
15
+ */
16
+ /**
17
+ * Will be called during SSG
18
+ * @param {ComponentRendering} rendering
19
+ * @returns {GetStaticPropsContext} context
20
+ */
21
+ export const getStaticProps = (rendering) => __awaiter(void 0, void 0, void 0, function* () {
22
+ const params = rendering.params || {};
23
+ const result = yield fetchBYOCComponentServerProps(params);
24
+ return result;
25
+ });
26
+ /**
27
+ * Will be called during SSR
28
+ * @param {ComponentRendering} rendering
29
+ * @returns {GetStaticPropsContext} context
30
+ */
31
+ export const getServerSideProps = (rendering) => __awaiter(void 0, void 0, void 0, function* () {
32
+ const params = rendering.params || {};
33
+ const result = yield fetchBYOCComponentServerProps(params);
34
+ return result;
35
+ });
36
+ export default BYOCWrapper;
@@ -0,0 +1,19 @@
1
+ import React, { createContext, useContext } from 'react';
2
+ /**
3
+ * Component props context which we are using in order to store data fetched on components level (getStaticProps/getServerSideProps)
4
+ */
5
+ export const ComponentPropsReactContext = createContext({});
6
+ /**
7
+ * Hook in order to get access to props related to specific component. Data comes from ComponentPropsContext.
8
+ * @see ComponentPropsContext
9
+ * @param {string | undefined} componentUid component uId
10
+ * @returns {ComponentData | undefined} component props
11
+ */
12
+ export function useComponentProps(componentUid) {
13
+ if (!componentUid) {
14
+ return undefined;
15
+ }
16
+ const data = useContext(ComponentPropsReactContext);
17
+ return data[componentUid];
18
+ }
19
+ export const ComponentPropsContext = ({ children, value, }) => (React.createElement(ComponentPropsReactContext.Provider, { value: value }, children));
@@ -0,0 +1,38 @@
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 { FEaaSWrapper, fetchFEaaSComponentServerProps, } from '@sitecore-content-sdk/react';
11
+ /**
12
+ * TODO: remove when framework agnostic forms implemented
13
+ * This is a repackaged version of the React FEaaSWrapper component with support for
14
+ * server rendering in Next.js (using component-level data-fetching feature of JSS).
15
+ */
16
+ /**
17
+ * Will be called during SSG
18
+ * @param {ComponentRendering} rendering
19
+ * @param {LayoutServiceData} layoutData
20
+ * @returns {GetStaticPropsContext} context
21
+ */
22
+ export const getStaticProps = (rendering, layoutData) => __awaiter(void 0, void 0, void 0, function* () {
23
+ const params = rendering.params || {};
24
+ const result = yield fetchFEaaSComponentServerProps(params, layoutData.sitecore.context.pageState);
25
+ return result;
26
+ });
27
+ /**
28
+ * Will be called during SSR
29
+ * @param {ComponentRendering} rendering
30
+ * @param {LayoutServiceData} layoutData
31
+ * @returns {GetStaticPropsContext} context
32
+ */
33
+ export const getServerSideProps = (rendering, layoutData) => __awaiter(void 0, void 0, void 0, function* () {
34
+ const params = rendering.params || {};
35
+ const result = yield fetchFEaaSComponentServerProps(params, layoutData.sitecore.context.pageState);
36
+ return result;
37
+ });
38
+ export default FEaaSWrapper;
@@ -0,0 +1,48 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React, { forwardRef } from 'react';
13
+ import PropTypes from 'prop-types';
14
+ import NextLink from 'next/link';
15
+ import { Link as ReactLink, LinkPropTypes, } from '@sitecore-content-sdk/react';
16
+ /**
17
+ * Matches relative URLs that end with a file extension.
18
+ */
19
+ const FILE_EXTENSION_MATCHER = /^\/.*\.\w+$/;
20
+ export const Link = forwardRef((props, ref) => {
21
+ const { field, editable = true, children, internalLinkMatcher = /^\//g, showLinkTextWithChildrenPresent } = props, htmlLinkProps = __rest(props, ["field", "editable", "children", "internalLinkMatcher", "showLinkTextWithChildrenPresent"]);
22
+ if (!field || (!field.value && !field.href && !field.metadata)) {
23
+ return null;
24
+ }
25
+ const value = (field.href
26
+ ? field
27
+ : field.value);
28
+ // fallback to {} if value is undefined; could happen if field is LinkFieldValue, href is empty in metadata mode
29
+ const { href, querystring, anchor } = value || {};
30
+ const isEditing = editable && field.metadata;
31
+ if (href && !isEditing) {
32
+ const text = showLinkTextWithChildrenPresent || !children ? value.text || value.href : null;
33
+ const isMatching = internalLinkMatcher.test(href);
34
+ const isFileUrl = FILE_EXTENSION_MATCHER.test(href);
35
+ // determine if a link is a route or not. File extensions are not routes and should not be pre-fetched.
36
+ if (isMatching && !isFileUrl) {
37
+ return (React.createElement(NextLink, Object.assign({ href: { pathname: href, query: querystring, hash: anchor }, key: "link", locale: false, title: value.title, target: value.target, className: value.class }, htmlLinkProps, { ref: ref }, (process.env.TEST ? { 'data-nextjs-link': true } : {})),
38
+ text,
39
+ children));
40
+ }
41
+ }
42
+ // prevent passing internalLinkMatcher as it is an invalid DOM element prop
43
+ const reactLinkProps = Object.assign({}, props);
44
+ delete reactLinkProps.internalLinkMatcher;
45
+ return (React.createElement(ReactLink, Object.assign({}, reactLinkProps, { ref: ref }, (process.env.TEST ? { 'data-react-link': true } : {}))));
46
+ });
47
+ Link.displayName = 'NextLink';
48
+ Link.propTypes = Object.assign({ internalLinkMatcher: PropTypes.instanceOf(RegExp) }, LinkPropTypes);
@@ -0,0 +1,76 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { mediaApi } from '@sitecore-content-sdk/core/media';
13
+ import PropTypes from 'prop-types';
14
+ import React from 'react';
15
+ import { withFieldMetadata, SitecoreContextReactContext, } from '@sitecore-content-sdk/react';
16
+ import Image from 'next/image';
17
+ import { withEmptyFieldEditingComponent } from '@sitecore-content-sdk/react';
18
+ import { DefaultEmptyFieldEditingComponentImage } from '@sitecore-content-sdk/react';
19
+ import { isFieldValueEmpty, LayoutServicePageState } from '@sitecore-content-sdk/core/layout';
20
+ export const NextImage = withFieldMetadata(withEmptyFieldEditingComponent((_a) => {
21
+ var _b;
22
+ var { editable = true, imageParams, field, mediaUrlPrefix, fill, priority } = _a, otherProps = __rest(_a, ["editable", "imageParams", "field", "mediaUrlPrefix", "fill", "priority"]);
23
+ const sitecoreContext = React.useContext(SitecoreContextReactContext);
24
+ // next handles src and we use a custom loader,
25
+ // throw error if these are present
26
+ if (otherProps.src) {
27
+ throw new Error('Detected src prop. If you wish to use src, use next/image directly.');
28
+ }
29
+ const dynamicMedia = field;
30
+ if (isFieldValueEmpty(dynamicMedia)) {
31
+ return null;
32
+ }
33
+ // some wise-guy/gal is passing in a 'raw' image object value
34
+ const img = dynamicMedia.src
35
+ ? field
36
+ : dynamicMedia.value;
37
+ if (!img) {
38
+ return null;
39
+ }
40
+ // disable image optimization for Edit and Preview, but preserve original value if true
41
+ const unoptimized = otherProps.unoptimized ||
42
+ ((_b = sitecoreContext.context) === null || _b === void 0 ? void 0 : _b.pageState) !== LayoutServicePageState.Normal;
43
+ const attrs = Object.assign(Object.assign(Object.assign({}, img), otherProps), { fill,
44
+ priority, src: mediaApi.updateImageUrl(img.src, imageParams, mediaUrlPrefix), unoptimized });
45
+ const imageProps = Object.assign(Object.assign({}, attrs), {
46
+ // force replace /media with /jssmedia in src since we _know_ we will be adding a 'mw' query string parameter
47
+ // this is required for Sitecore media API resizing to work properly
48
+ src: mediaApi.replaceMediaUrlPrefix(attrs.src, mediaUrlPrefix) });
49
+ // Exclude `width`, `height` in case image is responsive, `fill` is used
50
+ if (imageProps.fill) {
51
+ delete imageProps.width;
52
+ delete imageProps.height;
53
+ }
54
+ if (attrs) {
55
+ return (React.createElement(Image, Object.assign({ alt: "" }, imageProps, (process.env.TEST ? { 'data-unoptimized': unoptimized } : {}))));
56
+ }
57
+ return null; // we can't handle the truth
58
+ }, { defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentImage }));
59
+ NextImage.propTypes = {
60
+ field: PropTypes.oneOfType([
61
+ PropTypes.shape({
62
+ src: PropTypes.string.isRequired,
63
+ }),
64
+ PropTypes.shape({
65
+ value: PropTypes.object,
66
+ }),
67
+ ]),
68
+ editable: PropTypes.bool,
69
+ mediaUrlPrefix: PropTypes.instanceOf(RegExp),
70
+ imageParams: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.number.isRequired, PropTypes.string.isRequired]).isRequired),
71
+ emptyFieldEditingComponent: PropTypes.oneOfType([
72
+ PropTypes.object,
73
+ PropTypes.func,
74
+ ]),
75
+ };
76
+ NextImage.displayName = 'NextImage';
@@ -0,0 +1,12 @@
1
+ import React, { useContext } from 'react';
2
+ import { Placeholder as ReactPlaceholder, } from '@sitecore-content-sdk/react';
3
+ import { ComponentPropsReactContext } from './ComponentPropsContext';
4
+ export const Placeholder = (props) => {
5
+ const componentPropsContext = useContext(ComponentPropsReactContext);
6
+ return (React.createElement(ReactPlaceholder, Object.assign({}, props, { modifyComponentProps: (initialProps) => {
7
+ if (!initialProps.rendering.uid)
8
+ return initialProps;
9
+ const data = componentPropsContext[initialProps.rendering.uid];
10
+ return Object.assign(Object.assign({}, initialProps), data);
11
+ } })));
12
+ };
@@ -0,0 +1,55 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React, { useEffect, useRef } from 'react';
13
+ import PropTypes from 'prop-types';
14
+ import { useRouter } from 'next/router';
15
+ import { RichText as ReactRichText, RichTextPropTypes, } from '@sitecore-content-sdk/react';
16
+ const prefetched = {};
17
+ export const RichText = (props) => {
18
+ const { internalLinksSelector = 'a[href^="/"]', prefetchLinks = true, editable = true } = props, rest = __rest(props, ["internalLinksSelector", "prefetchLinks", "editable"]);
19
+ const hasText = props.field && props.field.value;
20
+ const isEditing = editable && props.field && props.field.metadata;
21
+ const router = useRouter();
22
+ const richTextRef = useRef(null);
23
+ useEffect(() => {
24
+ // NOT IN EDIT MODE
25
+ if (hasText && !isEditing) {
26
+ initializeLinks();
27
+ }
28
+ }, [hasText]);
29
+ const routeHandler = (ev) => {
30
+ if (!ev.currentTarget)
31
+ return;
32
+ ev.preventDefault();
33
+ const pathname = ev.currentTarget.href;
34
+ router.push(pathname, pathname, { locale: false });
35
+ };
36
+ const initializeLinks = () => {
37
+ const node = richTextRef.current;
38
+ // selects all links that start with '/'
39
+ const internalLinks = node && node.querySelectorAll(internalLinksSelector);
40
+ if (!internalLinks || !internalLinks.length)
41
+ return;
42
+ internalLinks.forEach((link) => {
43
+ if (link.target === '_blank')
44
+ return;
45
+ if (prefetchLinks && !prefetched[link.pathname]) {
46
+ router.prefetch(link.pathname, undefined, { locale: false });
47
+ prefetched[link.pathname] = true;
48
+ }
49
+ link.addEventListener('click', routeHandler, false);
50
+ });
51
+ };
52
+ return React.createElement(ReactRichText, Object.assign({ ref: richTextRef, editable: editable }, rest));
53
+ };
54
+ RichText.propTypes = Object.assign({ internalLinksSelector: PropTypes.string }, RichTextPropTypes);
55
+ RichText.displayName = 'NextRichText';
@@ -0,0 +1,7 @@
1
+ export const QUERY_PARAM_VERCEL_PROTECTION_BYPASS = 'x-vercel-protection-bypass';
2
+ export const QUERY_PARAM_VERCEL_SET_BYPASS_COOKIE = 'x-vercel-set-bypass-cookie';
3
+ /**
4
+ * Headers that should be passed along to (Editing Chromes handler) SSR request.
5
+ * Note these are in lowercase format to match expected `IncomingHttpHeaders`.
6
+ */
7
+ export const EDITING_PASS_THROUGH_HEADERS = ['authorization', 'cookie'];
@@ -0,0 +1,58 @@
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 { EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET, } from '@sitecore-content-sdk/core/editing';
11
+ import { debug } from '@sitecore-content-sdk/core';
12
+ import { enforceCors } from '@sitecore-content-sdk/core/utils';
13
+ import { EditMode } from '@sitecore-content-sdk/core/layout';
14
+ import { getJssEditingSecret } from '../utils/utils';
15
+ /**
16
+ * Middleware / handler used in the editing config API route in xmcloud add on (e.g. '/api/editing/config')
17
+ * provides configuration information to determine feature compatibility on Pages side.
18
+ */
19
+ export class EditingConfigMiddleware {
20
+ /**
21
+ * @param {EditingConfigMiddlewareConfig} [config] Editing configuration middleware config
22
+ */
23
+ constructor(config) {
24
+ this.config = config;
25
+ this.handler = (_req, res) => __awaiter(this, void 0, void 0, function* () {
26
+ const secret = _req.query[QUERY_PARAM_EDITING_SECRET];
27
+ if (!enforceCors(_req, res, EDITING_ALLOWED_ORIGINS)) {
28
+ debug.editing('invalid origin host - set allowed origins in JSS_ALLOWED_ORIGINS environment variable');
29
+ return res.status(401).json({ message: 'Invalid origin' });
30
+ }
31
+ if (secret !== getJssEditingSecret()) {
32
+ debug.editing('invalid editing secret - sent "%s" expected "%s"', secret, getJssEditingSecret());
33
+ return res.status(401).json({ message: 'Missing or invalid editing secret' });
34
+ }
35
+ // Handle preflight request
36
+ if (_req.method === 'OPTIONS') {
37
+ debug.editing('preflight request');
38
+ // CORS headers are set by enforceCors
39
+ return res.status(204).send(null);
40
+ }
41
+ const components = Array.isArray(this.config.components)
42
+ ? this.config.components
43
+ : Array.from(this.config.components.keys());
44
+ return res.status(200).json({
45
+ components,
46
+ packages: this.config.metadata.packages,
47
+ editMode: EditMode.Metadata,
48
+ });
49
+ });
50
+ }
51
+ /**
52
+ * Gets the Next.js API route handler
53
+ * @returns middleware handler
54
+ */
55
+ getHandler() {
56
+ return this.handler;
57
+ }
58
+ }