@enonic/nextjs-adapter 0.13.0 → 1.0.0-RC2

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.
package/UrlProcessor.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { commonChars, RENDER_MODE, SITE_KEY } from './utils';
2
+ import { useRouter } from 'next/router';
2
3
  export class UrlProcessor {
3
4
  static process(url, meta) {
4
5
  let result;
@@ -9,7 +10,17 @@ export class UrlProcessor {
9
10
  else {
10
11
  const apiUrl = this.getApiUrl(meta);
11
12
  const strippedUrl = this.stripApiUrl(url, apiUrl);
12
- result = ((meta === null || meta === void 0 ? void 0 : meta.baseUrl) || '') + strippedUrl;
13
+ let basePath;
14
+ // only add basePath in next
15
+ if (meta.renderMode === RENDER_MODE.NEXT) {
16
+ try {
17
+ basePath = useRouter().basePath;
18
+ }
19
+ catch (e) {
20
+ console.error('Error getting basePath from nextjs router', e);
21
+ }
22
+ }
23
+ result = (basePath && basePath !== '/' ? basePath : '') + ((meta === null || meta === void 0 ? void 0 : meta.baseUrl) || '') + strippedUrl;
13
24
  }
14
25
  return result;
15
26
  }
@@ -24,6 +35,20 @@ export class UrlProcessor {
24
35
  var _a;
25
36
  return ((_a = linkData.find(data => data.ref === ref)) === null || _a === void 0 ? void 0 : _a.image) !== null;
26
37
  }
38
+ static processSrcSet(srcset, meta) {
39
+ return srcset.split(/, */g).map(src => {
40
+ const srcParts = src.trim().split(' ');
41
+ switch (srcParts.length) {
42
+ case 1:
43
+ return this.process(src, meta);
44
+ case 2:
45
+ return this.process(srcParts[0], meta) + ' ' + srcParts[1];
46
+ default:
47
+ console.warn('Can not process image srcset: ' + src);
48
+ return src;
49
+ }
50
+ }).join(', ');
51
+ }
27
52
  static stripApiUrl(url, apiUrl) {
28
53
  // normalise localhost-127.0.0.1 if present in urls
29
54
  const normalUrl = url.replace(this.localhostPattern, '127.0.0.1');
@@ -1,20 +1,10 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import { MetaData, PageComponent } from './getMetaData';
4
- import { RENDER_MODE, XP_REQUEST_TYPE } from '../utils';
5
- import { ComponentRegistry } from '../ComponentRegistry';
6
4
  import { ParsedUrlQuery } from 'node:querystring';
7
5
  import { type GetServerSidePropsContext } from 'next';
8
6
  import { IncomingMessage } from 'http';
9
7
  import { type NextApiRequestCookies } from 'next/dist/server/api-utils';
10
- export type AdapterConstants = {
11
- APP_NAME: string;
12
- APP_NAME_DASHED: string;
13
- SITE_KEY: string;
14
- getXPRequestType: (context?: Context) => XP_REQUEST_TYPE;
15
- getRenderMode: (context?: Context) => RENDER_MODE;
16
- getSingleComponentPath: (context?: Context) => string | undefined;
17
- };
18
8
  type Result = {
19
9
  error?: {
20
10
  code: string;
@@ -30,9 +20,6 @@ export type FetchContentResult = Result & {
30
20
  meta: MetaData;
31
21
  page: PageComponent | null;
32
22
  };
33
- type FetcherConfig<T extends AdapterConstants> = T & {
34
- componentRegistry: typeof ComponentRegistry;
35
- };
36
23
  export interface ServerSideParams extends ParsedUrlQuery {
37
24
  contentPath?: string[];
38
25
  mode?: string;
@@ -63,14 +50,7 @@ export type ContentApiBaseBody = {
63
50
  /** Generic fetch */
64
51
  export declare const fetchFromApi: (apiUrl: string, body: ContentApiBaseBody, headers?: {}, method?: string) => Promise<any>;
65
52
  /** Guillotine-specialized fetch, using the generic fetch above */
66
- export declare const fetchGuillotine: (contentApiUrl: string, body: ContentApiBaseBody, xpContentPath: string, headers?: {}) => Promise<GuillotineResult>;
67
- /**
68
- * Configures, builds and returns a general fetchContent function.
69
- * @param adapterConstants Object containing attributes imported from enonic-connecion-config.js: constants and function concerned with connection to the XP backend. Easiest: caller imports enonic-connection-config and just passes that entire object here as adapterConstants.
70
- * @param componentRegistry ComponentRegistry object from ComponentRegistry.ts, holding user type mappings that are set in typesRegistration.ts file
71
- * @returns ContentFetcher
72
- */
73
- export declare const buildContentFetcher: <T extends AdapterConstants>(config: FetcherConfig<T>) => ContentFetcher;
53
+ export declare const fetchGuillotine: (contentApiUrl: string, body: ContentApiBaseBody, headers?: {}) => Promise<GuillotineResult>;
74
54
  /**
75
55
  * Default fetchContent function, built with params from imports.
76
56
  * It runs custom content-type-specific guillotine calls against an XP guillotine endpoint, returns content data, error and some meta data
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { getMetaQuery, pageFragmentQuery } from './getMetaData';
11
- import adapterConstants, { APP_NAME, APP_NAME_DASHED, FRAGMENT_CONTENTTYPE_NAME, FRAGMENT_DEFAULT_REGION_NAME, getContentApiUrl, getXpBaseUrl, IS_DEV_MODE, JSESSIONID_HEADER, PAGE_TEMPLATE_CONTENTTYPE_NAME, PAGE_TEMPLATE_FOLDER, RENDER_MODE, sanitizeGraphqlName, SITE_KEY, XP_COMPONENT_TYPE, XP_REQUEST_TYPE, } from '../utils';
11
+ import adapterConstants, { APP_NAME, APP_NAME_DASHED, FRAGMENT_CONTENTTYPE_NAME, FRAGMENT_DEFAULT_REGION_NAME, getContentApiUrl, getJsessionHeaders, getRenderMode, getXpBaseUrl, IS_DEV_MODE, PAGE_TEMPLATE_CONTENTTYPE_NAME, PAGE_TEMPLATE_FOLDER, RENDER_MODE, sanitizeGraphqlName, SITE_KEY, XP_COMPONENT_TYPE, XP_REQUEST_TYPE, } from '../utils';
12
12
  import { ComponentRegistry } from '../ComponentRegistry';
13
13
  const NO_PROPS_PROCESSOR = (props) => __awaiter(void 0, void 0, void 0, function* () { var _a; return (_a = yield props) !== null && _a !== void 0 ? _a : {}; });
14
14
  const ALIAS_PREFIX = 'request';
@@ -64,7 +64,8 @@ export const fetchFromApi = (apiUrl, body, headers, method = 'POST') => __awaite
64
64
  return json;
65
65
  });
66
66
  /** Guillotine-specialized fetch, using the generic fetch above */
67
- export const fetchGuillotine = (contentApiUrl, body, xpContentPath, headers) => __awaiter(void 0, void 0, void 0, function* () {
67
+ export const fetchGuillotine = (contentApiUrl, body, headers) => __awaiter(void 0, void 0, void 0, function* () {
68
+ var _b;
68
69
  if (typeof body.query !== 'string' || !body.query.trim()) {
69
70
  return {
70
71
  error: {
@@ -73,6 +74,8 @@ export const fetchGuillotine = (contentApiUrl, body, xpContentPath, headers) =>
73
74
  },
74
75
  };
75
76
  }
77
+ const path = (_b = body.variables) === null || _b === void 0 ? void 0 : _b.path;
78
+ const pathMessage = path ? `(path = ${JSON.stringify(path)})` : '';
76
79
  const result = yield fetchFromApi(contentApiUrl, body, headers)
77
80
  .then(json => {
78
81
  let errors = (json || {}).errors;
@@ -80,7 +83,7 @@ export const fetchGuillotine = (contentApiUrl, body, xpContentPath, headers) =>
80
83
  if (!Array.isArray(errors)) {
81
84
  errors = [errors];
82
85
  }
83
- console.warn(`${errors.length} error(s) when trying to fetch data (path = ${JSON.stringify(xpContentPath)}):`);
86
+ console.warn(`${errors.length} error(s) when trying to fetch data ${pathMessage}:`);
84
87
  errors.forEach(error => {
85
88
  console.error(error);
86
89
  });
@@ -96,7 +99,7 @@ export const fetchGuillotine = (contentApiUrl, body, xpContentPath, headers) =>
96
99
  return json.data;
97
100
  })
98
101
  .catch((err) => {
99
- console.warn(`Client-side error when trying to fetch data (path = ${JSON.stringify(xpContentPath)})`, err);
102
+ console.warn(`Client-side error when trying to fetch data ${pathMessage}`, err);
100
103
  try {
101
104
  return { error: JSON.parse(err.message) };
102
105
  }
@@ -108,20 +111,20 @@ export const fetchGuillotine = (contentApiUrl, body, xpContentPath, headers) =>
108
111
  });
109
112
  // /////////////////////////////////////////////////////////////////////////////// Specific fetch wrappers:
110
113
  const fetchMetaData = (contentApiUrl, xpContentPath, headers) => __awaiter(void 0, void 0, void 0, function* () {
111
- var _b;
114
+ var _c;
112
115
  const body = {
113
116
  query: getMetaQuery(pageFragmentQuery()),
114
117
  variables: {
115
118
  path: xpContentPath,
116
119
  },
117
120
  };
118
- const metaResult = yield fetchGuillotine(contentApiUrl, body, xpContentPath, headers);
121
+ const metaResult = yield fetchGuillotine(contentApiUrl, body, headers);
119
122
  if (metaResult.error) {
120
123
  return metaResult;
121
124
  }
122
125
  else {
123
126
  return {
124
- meta: (_b = metaResult === null || metaResult === void 0 ? void 0 : metaResult.guillotine) === null || _b === void 0 ? void 0 : _b.get,
127
+ meta: (_c = metaResult === null || metaResult === void 0 ? void 0 : metaResult.guillotine) === null || _c === void 0 ? void 0 : _c.get,
125
128
  };
126
129
  }
127
130
  });
@@ -130,7 +133,7 @@ const fetchContentData = (contentApiUrl, xpContentPath, query, variables, header
130
133
  if (variables && Object.keys(variables).length > 0) {
131
134
  body.variables = variables;
132
135
  }
133
- const contentResults = yield fetchGuillotine(contentApiUrl, body, xpContentPath, headers);
136
+ const contentResults = yield fetchGuillotine(contentApiUrl, body, headers);
134
137
  if (contentResults.error) {
135
138
  return contentResults;
136
139
  }
@@ -365,7 +368,7 @@ function getComponentConfig(cmp) {
365
368
  const cmpData = cmp && cmp[cmp.type];
366
369
  return cmpData && 'config' in cmpData ? cmpData.config : undefined;
367
370
  }
368
- function collectComponentDescriptors(components, componentRegistry, requestedComponentPath, xpContentPath, context) {
371
+ function collectComponentDescriptors(components, componentRegistry, xpContentPath, context) {
369
372
  const descriptors = [];
370
373
  for (const cmp of (components || [])) {
371
374
  processComponentConfig(APP_NAME, APP_NAME_DASHED, cmp);
@@ -388,7 +391,7 @@ function collectComponentDescriptors(components, componentRegistry, requestedCom
388
391
  }
389
392
  else {
390
393
  // look for parts inside fragments
391
- const fragPartDescs = collectComponentDescriptors(cmp.fragment.fragment.components, componentRegistry, requestedComponentPath, xpContentPath, context);
394
+ const fragPartDescs = collectComponentDescriptors(cmp.fragment.fragment.components, componentRegistry, xpContentPath, context);
392
395
  if (fragPartDescs.length) {
393
396
  descriptors.push(...fragPartDescs);
394
397
  }
@@ -453,11 +456,15 @@ function getQueryAndVariables(type, path, selectedQuery, context, config) {
453
456
  };
454
457
  }
455
458
  }
456
- function createPageData(contentType, components) {
459
+ function createPageData(contentType, components, componentPath) {
457
460
  let page;
458
- if (components) {
461
+ if (components && !componentPath) {
459
462
  page = buildPage(contentType, components);
460
463
  }
464
+ else {
465
+ // Don't build page for single component
466
+ page = null;
467
+ }
461
468
  return page;
462
469
  }
463
470
  function createMetaData(contentType, contentPath, requestType, renderMode, apiUrl, baseUrl, requestedComponentPath, pageCmp, components = []) {
@@ -483,10 +490,13 @@ function createMetaData(contentType, contentPath, requestType, renderMode, apiUr
483
490
  if ((typeDef === null || typeDef === void 0 ? void 0 : typeDef.view) && !typeDef.catchAll) {
484
491
  meta.canRender = true;
485
492
  }
493
+ else if (requestType === XP_REQUEST_TYPE.COMPONENT) {
494
+ // always render a single component (show missing if not implemented)
495
+ meta.canRender = true;
496
+ }
486
497
  else if (pageDesc) {
487
- // always render a page if there is a descriptor (show missing in case it's not implemented)
498
+ // always render a page if there is a descriptor (show missing if not implemented)
488
499
  meta.canRender = true;
489
- meta.catchAll = false; // catchAll only refers to content type catch-all
490
500
  }
491
501
  else if (typeDef === null || typeDef === void 0 ? void 0 : typeDef.view) {
492
502
  meta.canRender = true;
@@ -515,40 +525,76 @@ function errorResponse(code = '500', message = 'Unknown error', requestType, ren
515
525
  },
516
526
  };
517
527
  }
528
+ function restrictComponentsToPath(contentType, components, componentPath) {
529
+ if (!componentPath || !(components === null || components === void 0 ? void 0 : components.length)) {
530
+ return components || [];
531
+ }
532
+ // filter components to the requested one only
533
+ const component = components.find(cmp => {
534
+ return cmp.path === componentPath;
535
+ });
536
+ if (!component) {
537
+ return [];
538
+ }
539
+ let result = [component];
540
+ if (component.type !== XP_COMPONENT_TYPE.LAYOUT) {
541
+ // remember to include all parent layouts too !
542
+ const cmpPath = parseComponentPath(contentType, component.path);
543
+ for (let i = cmpPath.length - 2; i >= 0; i--) {
544
+ const parentPath = cmpPath[i];
545
+ const parentCmp = components.find(cmp => cmp.path === `/${parentPath.region}/${parentPath.index}`);
546
+ if (parentCmp) {
547
+ result.unshift(parentCmp);
548
+ }
549
+ }
550
+ }
551
+ else {
552
+ // It's a layout, include child components
553
+ const childCmps = components.filter(cmp => cmp.path !== component.path && cmp.path.startsWith(component.path));
554
+ if (childCmps.length) {
555
+ result = result.concat(childCmps);
556
+ }
557
+ }
558
+ return result;
559
+ }
560
+ const COMPONENT_PATH_KEY = /\/?_\/component/; // first slash is optional for root components
561
+ const getContentAndComponentPaths = (requestPath, context) => {
562
+ let contentPath, componentPath;
563
+ if (COMPONENT_PATH_KEY.test(requestPath)) {
564
+ [contentPath, componentPath] = requestPath.split(COMPONENT_PATH_KEY);
565
+ }
566
+ else {
567
+ contentPath = requestPath;
568
+ }
569
+ return [contentPath, componentPath];
570
+ };
518
571
  // ///////////////////////////// ENTRY 1 - THE BUILDER:
519
572
  /**
520
573
  * Configures, builds and returns a general fetchContent function.
521
- * @param adapterConstants Object containing attributes imported from enonic-connecion-config.js: constants and function concerned with connection to the XP backend. Easiest: caller imports enonic-connection-config and just passes that entire object here as adapterConstants.
522
- * @param componentRegistry ComponentRegistry object from ComponentRegistry.ts, holding user type mappings that are set in typesRegistration.ts file
574
+ * @param config object containing ComponentRegistry as well as constants imported from enonic-connecion-config.js
523
575
  * @returns ContentFetcher
524
576
  */
525
- export const buildContentFetcher = (config) => {
526
- const { APP_NAME, APP_NAME_DASHED, getXPRequestType, getRenderMode, getSingleComponentPath, componentRegistry, } = config;
577
+ const buildContentFetcher = (config) => {
578
+ const { APP_NAME, APP_NAME_DASHED, componentRegistry, } = config;
527
579
  return (contentPathOrArray, context) => __awaiter(void 0, void 0, void 0, function* () {
528
- var _a, _b, _c;
529
- let headers;
530
- const jsessionid = (_a = context === null || context === void 0 ? void 0 : context.req) === null || _a === void 0 ? void 0 : _a.headers[JSESSIONID_HEADER];
531
- if (jsessionid) {
532
- headers = {
533
- 'Cookie': `${JSESSIONID_HEADER}=${jsessionid}`,
534
- };
535
- }
580
+ var _a, _b;
581
+ const headers = getJsessionHeaders(context);
536
582
  const xpBaseUrl = getXpBaseUrl(context);
537
583
  const contentApiUrl = getContentApiUrl(context);
538
- const requestType = getXPRequestType(context);
539
584
  const renderMode = getRenderMode(context);
540
- let contentPath;
585
+ let requestType = XP_REQUEST_TYPE.TYPE;
541
586
  try {
542
- const siteRelativeContentPath = getCleanContentPathArrayOrThrow400(contentPathOrArray);
543
- let requestedComponentPath;
544
- if (requestType === XP_REQUEST_TYPE.COMPONENT) {
545
- requestedComponentPath = getSingleComponentPath(context);
587
+ const requestContentPath = getCleanContentPathArrayOrThrow400(contentPathOrArray);
588
+ const [siteRelativeContentPath, componentPath] = getContentAndComponentPaths(requestContentPath, context);
589
+ if (componentPath) {
590
+ // set component request type because url contains component path
591
+ requestType = XP_REQUEST_TYPE.COMPONENT;
546
592
  }
547
593
  // ///////////// FIRST GUILLOTINE CALL FOR METADATA /////////////////
548
594
  const metaResult = yield fetchMetaData(contentApiUrl, '${site}/' + siteRelativeContentPath, headers);
549
595
  // ///////////////////////////////////////////////////////////////////////
550
- const { type, components, _path } = metaResult.meta || {};
551
- contentPath = _path || '';
596
+ const { _path, type } = metaResult.meta || {};
597
+ const contentPath = _path || siteRelativeContentPath;
552
598
  if (metaResult.error) {
553
599
  console.error(metaResult.error);
554
600
  return errorResponse(metaResult.error.code, metaResult.error.message, requestType, renderMode, contentApiUrl, xpBaseUrl, contentPath);
@@ -565,6 +611,14 @@ export const buildContentFetcher = (config) => {
565
611
  type === PAGE_TEMPLATE_FOLDER)) {
566
612
  return errorResponse('404', `Content type [${type}] is not accessible in ${renderMode} mode`, requestType, renderMode, contentApiUrl, xpBaseUrl, contentPath);
567
613
  }
614
+ const components = restrictComponentsToPath(type, metaResult.meta.components, componentPath);
615
+ if (componentPath && !components.length) {
616
+ // component was not found
617
+ return errorResponse('404', `Component ${componentPath} was not found`, requestType, renderMode, contentApiUrl, xpBaseUrl, contentPath);
618
+ }
619
+ if (requestType !== XP_REQUEST_TYPE.COMPONENT && components.length > 0) {
620
+ requestType = XP_REQUEST_TYPE.PAGE;
621
+ }
568
622
  // ////////////////////////////////////////////////// Content type established. Proceed to data call:
569
623
  const allDescriptors = [];
570
624
  // Add the content type query at all cases
@@ -573,14 +627,14 @@ export const buildContentFetcher = (config) => {
573
627
  if (pageCmp) {
574
628
  processComponentConfig(APP_NAME, APP_NAME_DASHED, pageCmp);
575
629
  }
576
- const contentQueryAndVars = getQueryAndVariables(type, contentPath, contentTypeDef === null || contentTypeDef === void 0 ? void 0 : contentTypeDef.query, context, (_b = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _b === void 0 ? void 0 : _b.config);
630
+ const contentQueryAndVars = getQueryAndVariables(type, contentPath, contentTypeDef === null || contentTypeDef === void 0 ? void 0 : contentTypeDef.query, context, (_a = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _a === void 0 ? void 0 : _a.config);
577
631
  if (contentQueryAndVars) {
578
632
  allDescriptors.push({
579
633
  type: contentTypeDef,
580
634
  queryAndVariables: contentQueryAndVars,
581
635
  });
582
636
  }
583
- const commonQueryAndVars = getQueryAndVariables(type, contentPath, componentRegistry.getCommonQuery(), context, (_c = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _c === void 0 ? void 0 : _c.config);
637
+ const commonQueryAndVars = getQueryAndVariables(type, contentPath, componentRegistry.getCommonQuery(), context, (_b = pageCmp === null || pageCmp === void 0 ? void 0 : pageCmp.page) === null || _b === void 0 ? void 0 : _b.config);
584
638
  if (commonQueryAndVars) {
585
639
  allDescriptors.push({
586
640
  type: contentTypeDef,
@@ -592,7 +646,7 @@ export const buildContentFetcher = (config) => {
592
646
  processComponentConfig(APP_NAME, APP_NAME_DASHED, cmp);
593
647
  }
594
648
  // Collect component queries if defined
595
- const componentDescriptors = collectComponentDescriptors(components, componentRegistry, requestedComponentPath, contentPath, context);
649
+ const componentDescriptors = collectComponentDescriptors(components, componentRegistry, contentPath, context);
596
650
  if (componentDescriptors.length) {
597
651
  allDescriptors.push(...componentDescriptors);
598
652
  }
@@ -642,14 +696,13 @@ export const buildContentFetcher = (config) => {
642
696
  }
643
697
  }
644
698
  const page = createPageData(type, components);
645
- const meta = createMetaData(type, siteRelativeContentPath, requestType, renderMode, contentApiUrl, xpBaseUrl, requestedComponentPath, page, components);
699
+ const meta = createMetaData(type, siteRelativeContentPath, requestType, renderMode, contentApiUrl, xpBaseUrl, componentPath, page, components);
646
700
  return {
647
701
  data: contentData,
648
702
  common,
649
703
  meta,
650
- page: page || null,
704
+ page,
651
705
  };
652
- // /////////////////////////////////////////////////////////// Catch
653
706
  }
654
707
  catch (e) {
655
708
  console.error(e);
@@ -663,7 +716,7 @@ export const buildContentFetcher = (config) => {
663
716
  message: e.message,
664
717
  };
665
718
  }
666
- return errorResponse(error.code, error.message, requestType, renderMode, contentApiUrl, xpBaseUrl, contentPath);
719
+ return errorResponse(error.code, error.message, requestType, renderMode, contentApiUrl, xpBaseUrl, contentPathOrArray.toString());
667
720
  }
668
721
  });
669
722
  };
package/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  export * from './utils';
2
2
  export * from './guillotine/fetchContent';
3
+ export * from './guillotine/getMetaData';
4
+ export * from './ComponentRegistry';
5
+ export * from './UrlProcessor';
package/index.js CHANGED
@@ -1,2 +1,5 @@
1
1
  export * from './utils';
2
2
  export * from './guillotine/fetchContent';
3
+ export * from './guillotine/getMetaData';
4
+ export * from './ComponentRegistry';
5
+ export * from './UrlProcessor';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enonic/nextjs-adapter",
3
- "version": "0.13.0",
3
+ "version": "1.0.0-RC2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -8,26 +8,27 @@
8
8
  },
9
9
  "scripts": {
10
10
  "copy": "npx --yes cpy-cli package.json README.md dist",
11
- "build": "tsc",
12
- "lint": "eslint --quiet .",
13
- "lint:fix": "eslint --fix ."
11
+ "build": "tsc --build src/tsconfig.json && tsc --build server/tsconfig.json",
12
+ "lint": "eslint --quiet server && eslint --quiet src",
13
+ "lint:fix": "eslint --fix server && eslint --fix src"
14
14
  },
15
15
  "dependencies": {
16
- "html-react-parser": "^3.0.7",
17
- "next": "^13.1.2",
16
+ "html-react-parser": "^3.0.11",
17
+ "lru-cache": "^7.17.0",
18
+ "next": "^13.2.3",
18
19
  "react": "^18.2.0",
19
20
  "react-dom": "^18.2.0",
20
21
  "unescape": "^1.0.1"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@enonic/eslint-config": "^1.1.0",
24
- "@types/node": "^18.11.18",
25
- "@types/react": "^18.0.26",
26
- "@types/react-dom": "^18.0.10",
27
- "@typescript-eslint/eslint-plugin": "^5.48.1",
28
- "@typescript-eslint/parser": "^5.48.1",
29
- "eslint": "^8.32.0",
30
- "eslint-plugin-react": "^7.32.0",
31
- "typescript": "^4.9.4"
25
+ "@types/node": "^18.14.6",
26
+ "@types/react": "^18.0.28",
27
+ "@types/react-dom": "^18.0.11",
28
+ "@typescript-eslint/eslint-plugin": "^5.54.0",
29
+ "@typescript-eslint/parser": "^5.54.0",
30
+ "eslint": "^8.35.0",
31
+ "eslint-plugin-react": "^7.32.2",
32
+ "typescript": "^4.9.5"
32
33
  }
33
34
  }
@@ -0,0 +1,26 @@
1
+ import { CacheHandler, CacheHandlerContext, CacheHandlerValue } from 'next/dist/server/lib/incremental-cache';
2
+ import { CacheFs } from 'next/dist/shared/lib/utils';
3
+ type FileSystemCacheContext = Omit<CacheHandlerContext, 'fs' | 'serverDistDir'> & {
4
+ fs: CacheFs;
5
+ serverDistDir: string;
6
+ };
7
+ export default class ClearableFileCache implements CacheHandler {
8
+ private fs;
9
+ private flushToDisk?;
10
+ private serverDistDir;
11
+ private appDir;
12
+ constructor(ctx: FileSystemCacheContext);
13
+ clear(): void;
14
+ delete(path: string): boolean | undefined;
15
+ get(key: string, fetchCache?: boolean): Promise<CacheHandlerValue | null>;
16
+ set(key: string, data: CacheHandlerValue['value']): Promise<void>;
17
+ getFsPath({ pathname, appDir, fetchCache, }: {
18
+ pathname: string;
19
+ appDir?: boolean;
20
+ fetchCache?: boolean;
21
+ }): Promise<{
22
+ filePath: string;
23
+ isAppPath: boolean;
24
+ }>;
25
+ }
26
+ export {};