@enonic/nextjs-adapter 2.0.1 → 2.0.3
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/ComponentRegistry.d.ts +64 -0
- package/ComponentRegistry.js +121 -0
- package/UrlProcessor.d.ts +25 -0
- package/UrlProcessor.js +127 -0
- package/baseMappings.d.ts +1 -0
- package/{src/baseMappings.ts → baseMappings.js} +3 -13
- package/guillotine/fetchContent.d.ts +49 -0
- package/{src/guillotine/fetchContent.ts → guillotine/fetchContent.js} +244 -493
- package/guillotine/getMetaData.d.ts +94 -0
- package/guillotine/getMetaData.js +128 -0
- package/{src/index.ts → index.d.ts} +1 -1
- package/index.js +5 -0
- package/package.json +2 -2
- package/query/Shortcut.d.ts +1 -0
- package/server/ClearableFileCache.d.ts +31 -0
- package/server/ClearableFileCache.js +472 -0
- package/server/cache.d.ts +2 -0
- package/server/cache.js +129 -0
- package/server/index.d.ts +5 -0
- package/server/index.js +132 -0
- package/utils.d.ts +114 -0
- package/{src/utils.ts → utils.js} +81 -154
- package/views/BaseComponent.d.ts +25 -0
- package/{src/views/BaseComponent.tsx → views/BaseComponent.jsx} +39 -73
- package/views/BaseContent.d.ts +4 -0
- package/{src/views/BaseContent.tsx → views/BaseContent.jsx} +17 -24
- package/views/BaseLayout.d.ts +17 -0
- package/views/BaseLayout.jsx +24 -0
- package/views/BaseMacro.d.ts +16 -0
- package/{src/views/BaseMacro.tsx → views/BaseMacro.jsx} +29 -45
- package/views/BasePage.d.ts +19 -0
- package/views/BasePage.jsx +34 -0
- package/views/BasePart.d.ts +19 -0
- package/views/BasePart.jsx +24 -0
- package/views/Empty.d.ts +3 -0
- package/{src/views/Empty.tsx → views/Empty.jsx} +0 -2
- package/views/Fragment.d.ts +10 -0
- package/views/Fragment.jsx +30 -0
- package/views/MainView.d.ts +4 -0
- package/views/MainView.jsx +14 -0
- package/views/Region.d.ts +20 -0
- package/views/Region.jsx +52 -0
- package/views/RichTextView.d.ts +16 -0
- package/{src/views/RichTextView.tsx → views/RichTextView.jsx} +10 -31
- package/views/SingleComponent.d.ts +5 -0
- package/{src/views/SingleComponent.tsx → views/SingleComponent.jsx} +2 -8
- package/views/StaticContent.d.ts +15 -0
- package/views/StaticContent.jsx +36 -0
- package/views/Text.d.ts +9 -0
- package/views/Text.jsx +4 -0
- package/views/macros/DefaultMacro.d.ts +4 -0
- package/views/macros/DefaultMacro.jsx +3 -0
- package/views/macros/DisableMacro.d.ts +3 -0
- package/views/macros/DisableMacro.jsx +2 -0
- package/.eslint-childrc.js +0 -17
- package/.eslintrc.js +0 -15
- package/.github/dependabot.yml +0 -20
- package/.github/pull-merger.yml +0 -1
- package/.github/workflows/release.yml +0 -39
- package/LICENSE +0 -201
- package/RELEASE.md +0 -75
- package/server/.eslintrc.js +0 -11
- package/server/ClearableFileCache.ts +0 -410
- package/server/cache.ts +0 -50
- package/server/index.ts +0 -74
- package/server/tsconfig.json +0 -23
- package/src/.eslintrc.js +0 -11
- package/src/ComponentRegistry.ts +0 -189
- package/src/UrlProcessor.ts +0 -115
- package/src/guillotine/getMetaData.ts +0 -246
- package/src/tsconfig.json +0 -20
- package/src/views/BaseLayout.tsx +0 -45
- package/src/views/BasePage.tsx +0 -56
- package/src/views/BasePart.tsx +0 -50
- package/src/views/Fragment.tsx +0 -45
- package/src/views/MainView.tsx +0 -21
- package/src/views/Region.tsx +0 -89
- package/src/views/StaticContent.tsx +0 -40
- package/src/views/Text.tsx +0 -15
- package/src/views/macros/DefaultMacro.tsx +0 -9
- package/src/views/macros/DisableMacro.tsx +0 -8
- /package/{src/query/Shortcut.ts → query/Shortcut.js} +0 -0
package/server/.eslintrc.js
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import {LRUCache} from 'lru-cache';
|
|
3
|
-
import {CacheHandler, CacheHandlerContext, CacheHandlerValue} from 'next/dist/server/lib/incremental-cache';
|
|
4
|
-
import {CacheFs} from 'next/dist/shared/lib/utils';
|
|
5
|
-
import {CachedFetchValue, IncrementalCacheValue} from 'next/dist/server/response-cache';
|
|
6
|
-
import type {OutgoingHttpHeaders} from 'http';
|
|
7
|
-
import {getDerivedTags} from 'next/dist/server/lib/incremental-cache/utils';
|
|
8
|
-
|
|
9
|
-
type FileSystemCacheContext = Omit<
|
|
10
|
-
CacheHandlerContext,
|
|
11
|
-
'fs' | 'serverDistDir'
|
|
12
|
-
> & {
|
|
13
|
-
fs: CacheFs
|
|
14
|
-
serverDistDir: string
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type TagsManifest = {
|
|
18
|
-
version: 1
|
|
19
|
-
items: { [tag: string]: { keys: string[]; revalidatedAt: number } }
|
|
20
|
-
};
|
|
21
|
-
let memoryCache: LRUCache<string, CacheHandlerValue> | undefined;
|
|
22
|
-
let tagsManifest: TagsManifest | undefined;
|
|
23
|
-
|
|
24
|
-
export default class FileSystemCache implements CacheHandler {
|
|
25
|
-
private fs: FileSystemCacheContext['fs'];
|
|
26
|
-
private flushToDisk?: FileSystemCacheContext['flushToDisk'];
|
|
27
|
-
private serverDistDir: FileSystemCacheContext['serverDistDir'];
|
|
28
|
-
private appDir: boolean;
|
|
29
|
-
private tagsManifestPath?: string;
|
|
30
|
-
private revalidatedTags: string[];
|
|
31
|
-
|
|
32
|
-
constructor(ctx: FileSystemCacheContext) {
|
|
33
|
-
this.fs = ctx.fs;
|
|
34
|
-
this.flushToDisk = ctx.flushToDisk;
|
|
35
|
-
this.serverDistDir = ctx.serverDistDir;
|
|
36
|
-
this.appDir = !!ctx._appDir;
|
|
37
|
-
this.revalidatedTags = ctx.revalidatedTags;
|
|
38
|
-
|
|
39
|
-
if (ctx.maxMemoryCacheSize && !memoryCache) {
|
|
40
|
-
memoryCache = new LRUCache({
|
|
41
|
-
max: ctx.maxMemoryCacheSize,
|
|
42
|
-
maxSize: 10 * ctx.maxMemoryCacheSize, // had to be used sizeCalculation function
|
|
43
|
-
sizeCalculation({value}: { value: IncrementalCacheValue | null }) {
|
|
44
|
-
if (!value) {
|
|
45
|
-
return 25;
|
|
46
|
-
} else if (value.kind === 'REDIRECT') {
|
|
47
|
-
return JSON.stringify(value.props).length;
|
|
48
|
-
} else if (value.kind === 'IMAGE') {
|
|
49
|
-
throw new Error('invariant image should not be incremental-cache');
|
|
50
|
-
} else if (value.kind === 'FETCH') {
|
|
51
|
-
return JSON.stringify(value.data || '').length;
|
|
52
|
-
} else if (value.kind === 'ROUTE') {
|
|
53
|
-
return value.body.length;
|
|
54
|
-
}
|
|
55
|
-
// rough estimate of size of cache value
|
|
56
|
-
return (
|
|
57
|
-
value.html.length + (JSON.stringify(value.pageData)?.length || 0)
|
|
58
|
-
);
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
if (this.serverDistDir && this.fs) {
|
|
63
|
-
this.tagsManifestPath = path.join(
|
|
64
|
-
this.serverDistDir,
|
|
65
|
-
'..',
|
|
66
|
-
'cache',
|
|
67
|
-
'fetch-cache',
|
|
68
|
-
'tags-manifest.json',
|
|
69
|
-
);
|
|
70
|
-
this.loadTagsManifest();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
public clear() {
|
|
75
|
-
memoryCache?.clear();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public delete(path: string) {
|
|
79
|
-
return memoryCache?.delete(path);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
private loadTagsManifest() {
|
|
83
|
-
if (!this.tagsManifestPath || !this.fs || tagsManifest) return;
|
|
84
|
-
try {
|
|
85
|
-
tagsManifest = JSON.parse(
|
|
86
|
-
this.fs.readFileSync(this.tagsManifestPath).toString('utf8'),
|
|
87
|
-
);
|
|
88
|
-
} catch (err: any) {
|
|
89
|
-
tagsManifest = {version: 1, items: {}};
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async setTags(key: string, tags: string[]) {
|
|
94
|
-
this.loadTagsManifest();
|
|
95
|
-
if (!tagsManifest || !this.tagsManifestPath) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
for (const tag of tags) {
|
|
100
|
-
const data = tagsManifest.items[tag] || {keys: []};
|
|
101
|
-
if (!data.keys.includes(key)) {
|
|
102
|
-
data.keys.push(key);
|
|
103
|
-
}
|
|
104
|
-
tagsManifest.items[tag] = data;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
await this.fs.mkdir(path.dirname(this.tagsManifestPath));
|
|
109
|
-
await this.fs.writeFile(
|
|
110
|
-
this.tagsManifestPath,
|
|
111
|
-
JSON.stringify(tagsManifest || {}),
|
|
112
|
-
);
|
|
113
|
-
} catch (err: any) {
|
|
114
|
-
console.warn('Failed to update tags manifest.', err);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
public async revalidateTag(tag: string) {
|
|
119
|
-
// we need to ensure the tagsManifest is refreshed
|
|
120
|
-
// since separate workers can be updating it at the same
|
|
121
|
-
// time and we can't flush out of sync data
|
|
122
|
-
this.loadTagsManifest();
|
|
123
|
-
if (!tagsManifest || !this.tagsManifestPath) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const data = tagsManifest.items[tag] || {keys: []};
|
|
128
|
-
data.revalidatedAt = Date.now();
|
|
129
|
-
tagsManifest.items[tag] = data;
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
await this.fs.mkdir(path.dirname(this.tagsManifestPath));
|
|
133
|
-
await this.fs.writeFile(
|
|
134
|
-
this.tagsManifestPath,
|
|
135
|
-
JSON.stringify(tagsManifest || {}),
|
|
136
|
-
);
|
|
137
|
-
} catch (err: any) {
|
|
138
|
-
console.warn('Failed to update tags manifest.', err);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
public async get(key: string, fetchCache?: boolean) {
|
|
143
|
-
let data = memoryCache?.get(key);
|
|
144
|
-
|
|
145
|
-
// let's check the disk for seed data
|
|
146
|
-
if (!data && process.env.NEXT_RUNTIME !== 'edge') {
|
|
147
|
-
try {
|
|
148
|
-
const {filePath} = await this.getFsPath({
|
|
149
|
-
pathname: `${key}.body`,
|
|
150
|
-
appDir: true,
|
|
151
|
-
});
|
|
152
|
-
const fileData = await this.fs.readFile(filePath);
|
|
153
|
-
const {mtime} = await this.fs.stat(filePath);
|
|
154
|
-
|
|
155
|
-
const meta = JSON.parse(
|
|
156
|
-
(
|
|
157
|
-
await this.fs.readFile(filePath.replace(/\.body$/, '.meta'))
|
|
158
|
-
).toString('utf8'),
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
const cacheEntry: CacheHandlerValue = {
|
|
162
|
-
lastModified: mtime.getTime(),
|
|
163
|
-
value: {
|
|
164
|
-
kind: 'ROUTE',
|
|
165
|
-
body: fileData,
|
|
166
|
-
headers: meta.headers,
|
|
167
|
-
status: meta.status,
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
return cacheEntry;
|
|
171
|
-
} catch (_) {
|
|
172
|
-
// no .meta data for the related key
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
const {filePath, isAppPath} = await this.getFsPath({
|
|
177
|
-
pathname: fetchCache ? key : `${key}.html`,
|
|
178
|
-
fetchCache,
|
|
179
|
-
});
|
|
180
|
-
const fileData = (await this.fs.readFile(filePath)).toString('utf-8');
|
|
181
|
-
const {mtime} = await this.fs.stat(filePath);
|
|
182
|
-
|
|
183
|
-
if (fetchCache) {
|
|
184
|
-
const lastModified = mtime.getTime();
|
|
185
|
-
const parsedData: CachedFetchValue = JSON.parse(fileData);
|
|
186
|
-
data = {
|
|
187
|
-
lastModified,
|
|
188
|
-
value: parsedData,
|
|
189
|
-
};
|
|
190
|
-
} else {
|
|
191
|
-
const pageData = isAppPath
|
|
192
|
-
? (
|
|
193
|
-
await this.fs.readFile(
|
|
194
|
-
(
|
|
195
|
-
await this.getFsPath({
|
|
196
|
-
pathname: `${key}.rsc`,
|
|
197
|
-
appDir: true,
|
|
198
|
-
})
|
|
199
|
-
).filePath,
|
|
200
|
-
)
|
|
201
|
-
).toString('utf8')
|
|
202
|
-
: JSON.parse(
|
|
203
|
-
(
|
|
204
|
-
await this.fs.readFile(
|
|
205
|
-
(
|
|
206
|
-
await this.getFsPath({
|
|
207
|
-
pathname: `${key}.json`,
|
|
208
|
-
appDir: false,
|
|
209
|
-
})
|
|
210
|
-
).filePath,
|
|
211
|
-
)
|
|
212
|
-
).toString('utf8'),
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
let meta: { status?: number; headers?: OutgoingHttpHeaders } = {};
|
|
216
|
-
|
|
217
|
-
if (isAppPath) {
|
|
218
|
-
try {
|
|
219
|
-
meta = JSON.parse(
|
|
220
|
-
(
|
|
221
|
-
await this.fs.readFile(filePath.replace(/\.html$/, '.meta'))
|
|
222
|
-
).toString('utf-8'),
|
|
223
|
-
);
|
|
224
|
-
} catch (_) { /* empty */
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
data = {
|
|
229
|
-
lastModified: mtime.getTime(),
|
|
230
|
-
value: {
|
|
231
|
-
kind: 'PAGE',
|
|
232
|
-
html: fileData,
|
|
233
|
-
pageData,
|
|
234
|
-
headers: meta.headers,
|
|
235
|
-
status: meta.status,
|
|
236
|
-
},
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (data) {
|
|
241
|
-
memoryCache?.set(key, data);
|
|
242
|
-
}
|
|
243
|
-
} catch (_) {
|
|
244
|
-
// unable to get data from disk
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
let cacheTags: undefined | string[];
|
|
248
|
-
|
|
249
|
-
if (data?.value?.kind === 'PAGE') {
|
|
250
|
-
const tagsHeader = data.value.headers?.['x-next-cache-tags'];
|
|
251
|
-
|
|
252
|
-
if (typeof tagsHeader === 'string') {
|
|
253
|
-
cacheTags = tagsHeader.split(',');
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (data?.value?.kind === 'PAGE' && cacheTags?.length) {
|
|
258
|
-
this.loadTagsManifest();
|
|
259
|
-
const derivedTags = getDerivedTags(cacheTags || []);
|
|
260
|
-
|
|
261
|
-
const isStale = derivedTags.some((tag) => {
|
|
262
|
-
return (
|
|
263
|
-
tagsManifest?.items[tag]?.revalidatedAt &&
|
|
264
|
-
tagsManifest?.items[tag].revalidatedAt >=
|
|
265
|
-
(data?.lastModified || Date.now())
|
|
266
|
-
);
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// we trigger a blocking validation if an ISR page
|
|
270
|
-
// had a tag revalidated, if we want to be a background
|
|
271
|
-
// revalidation instead we return data.lastModified = -1
|
|
272
|
-
if (isStale) {
|
|
273
|
-
data = undefined;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (data && data?.value?.kind === 'FETCH') {
|
|
278
|
-
this.loadTagsManifest();
|
|
279
|
-
const innerData = data.value.data;
|
|
280
|
-
const derivedTags = getDerivedTags(innerData.tags || []);
|
|
281
|
-
|
|
282
|
-
const wasRevalidated = derivedTags.some((tag) => {
|
|
283
|
-
if (this.revalidatedTags.includes(tag)) {
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return (
|
|
288
|
-
tagsManifest?.items[tag]?.revalidatedAt &&
|
|
289
|
-
tagsManifest?.items[tag].revalidatedAt >=
|
|
290
|
-
(data?.lastModified || Date.now())
|
|
291
|
-
);
|
|
292
|
-
});
|
|
293
|
-
// When revalidate tag is called we don't return
|
|
294
|
-
// stale data so it's updated right away
|
|
295
|
-
if (wasRevalidated) {
|
|
296
|
-
data = undefined;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return data || null;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
public async set(key: string, data: CacheHandlerValue['value']) {
|
|
304
|
-
memoryCache?.set(key, {
|
|
305
|
-
value: data,
|
|
306
|
-
lastModified: Date.now(),
|
|
307
|
-
});
|
|
308
|
-
if (!this.flushToDisk) return;
|
|
309
|
-
|
|
310
|
-
if (data?.kind === 'ROUTE') {
|
|
311
|
-
const {filePath} = await this.getFsPath({
|
|
312
|
-
pathname: `${key}.body`,
|
|
313
|
-
appDir: true,
|
|
314
|
-
});
|
|
315
|
-
await this.fs.mkdir(path.dirname(filePath));
|
|
316
|
-
await this.fs.writeFile(filePath, data.body);
|
|
317
|
-
await this.fs.writeFile(
|
|
318
|
-
filePath.replace(/\.body$/, '.meta'),
|
|
319
|
-
JSON.stringify({headers: data.headers, status: data.status}),
|
|
320
|
-
);
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (data?.kind === 'PAGE') {
|
|
325
|
-
const isAppPath = typeof data.pageData === 'string';
|
|
326
|
-
const {filePath: htmlPath} = await this.getFsPath({
|
|
327
|
-
pathname: `${key}.html`,
|
|
328
|
-
appDir: isAppPath,
|
|
329
|
-
});
|
|
330
|
-
await this.fs.mkdir(path.dirname(htmlPath));
|
|
331
|
-
await this.fs.writeFile(htmlPath, data.html);
|
|
332
|
-
|
|
333
|
-
await this.fs.writeFile(
|
|
334
|
-
(
|
|
335
|
-
await this.getFsPath({
|
|
336
|
-
pathname: `${key}.${isAppPath ? 'rsc' : 'json'}`,
|
|
337
|
-
appDir: isAppPath,
|
|
338
|
-
})
|
|
339
|
-
).filePath,
|
|
340
|
-
isAppPath ? data.pageData : JSON.stringify(data.pageData),
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
if (data.headers || data.status) {
|
|
344
|
-
await this.fs.writeFile(
|
|
345
|
-
htmlPath.replace(/\.html$/, '.meta'),
|
|
346
|
-
JSON.stringify({
|
|
347
|
-
headers: data.headers,
|
|
348
|
-
status: data.status,
|
|
349
|
-
}),
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
} else if (data?.kind === 'FETCH') {
|
|
353
|
-
const {filePath} = await this.getFsPath({
|
|
354
|
-
pathname: key,
|
|
355
|
-
fetchCache: true,
|
|
356
|
-
});
|
|
357
|
-
await this.fs.mkdir(path.dirname(filePath));
|
|
358
|
-
await this.fs.writeFile(filePath, JSON.stringify(data));
|
|
359
|
-
await this.setTags(key, data.data.tags || []);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
public async getFsPath({
|
|
364
|
-
pathname,
|
|
365
|
-
appDir,
|
|
366
|
-
fetchCache,
|
|
367
|
-
}: {
|
|
368
|
-
pathname: string
|
|
369
|
-
appDir?: boolean
|
|
370
|
-
fetchCache?: boolean
|
|
371
|
-
}): Promise<{
|
|
372
|
-
filePath: string
|
|
373
|
-
isAppPath: boolean
|
|
374
|
-
}> {
|
|
375
|
-
if (fetchCache) {
|
|
376
|
-
// we store in .next/cache/fetch-cache so it can be persisted
|
|
377
|
-
// across deploys
|
|
378
|
-
return {
|
|
379
|
-
filePath: path.join(
|
|
380
|
-
this.serverDistDir,
|
|
381
|
-
'..',
|
|
382
|
-
'cache',
|
|
383
|
-
'fetch-cache',
|
|
384
|
-
pathname,
|
|
385
|
-
),
|
|
386
|
-
isAppPath: false,
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
const isAppPath = false;
|
|
390
|
-
const filePath = path.join(this.serverDistDir, 'pages', pathname);
|
|
391
|
-
|
|
392
|
-
if (!this.appDir || appDir === false)
|
|
393
|
-
return {
|
|
394
|
-
filePath,
|
|
395
|
-
isAppPath,
|
|
396
|
-
};
|
|
397
|
-
try {
|
|
398
|
-
await this.fs.readFile(filePath);
|
|
399
|
-
return {
|
|
400
|
-
filePath,
|
|
401
|
-
isAppPath,
|
|
402
|
-
};
|
|
403
|
-
} catch (err) {
|
|
404
|
-
return {
|
|
405
|
-
filePath: path.join(this.serverDistDir, 'app', pathname),
|
|
406
|
-
isAppPath: true,
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
package/server/cache.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import {IncrementalCache} from 'next/dist/server/lib/incremental-cache';
|
|
3
|
-
import ClearableFileCache from './ClearableFileCache';
|
|
4
|
-
|
|
5
|
-
const getCacheHandler = (cache: IncrementalCache): ClearableFileCache => {
|
|
6
|
-
return cache.cacheHandler as ClearableFileCache;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const purgeCache = async (cache: IncrementalCache, pathname?: string) => {
|
|
10
|
-
if (pathname) {
|
|
11
|
-
return purgePath(cache, pathname);
|
|
12
|
-
} else {
|
|
13
|
-
return purgeAll(cache);
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const purgePath = async (cache: IncrementalCache, pathname: string) => {
|
|
18
|
-
const handler = getCacheHandler(cache);
|
|
19
|
-
const fsPathObj = await handler.getFsPath({pathname});
|
|
20
|
-
try {
|
|
21
|
-
/* Delete entry in cache */
|
|
22
|
-
handler.delete(pathname);
|
|
23
|
-
|
|
24
|
-
/* Delete files from disc */
|
|
25
|
-
fs.unlinkSync(`${fsPathObj.filePath}.html`);
|
|
26
|
-
fs.unlinkSync(`${fsPathObj.filePath}.json`);
|
|
27
|
-
|
|
28
|
-
console.info(`\nCache deleted for '${fsPathObj.filePath}'\n`);
|
|
29
|
-
} catch (err) {
|
|
30
|
-
console.error(`Could not delete cache of '${fsPathObj.filePath}':`, err);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const purgeAll = async (cache: IncrementalCache) => {
|
|
35
|
-
const handler = getCacheHandler(cache);
|
|
36
|
-
try {
|
|
37
|
-
/* Purge cache */
|
|
38
|
-
handler.clear();
|
|
39
|
-
|
|
40
|
-
const {filePath: pagesRoot} = await handler.getFsPath({pathname: ''});
|
|
41
|
-
|
|
42
|
-
if (fs.existsSync(pagesRoot)) {
|
|
43
|
-
fs.rmSync(pagesRoot, {recursive: true});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
console.info('\nCache was successfully purged\n');
|
|
47
|
-
} catch (err) {
|
|
48
|
-
console.error('Could not purge cache:', err);
|
|
49
|
-
}
|
|
50
|
-
};
|
package/server/index.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import {createServer} from 'http';
|
|
2
|
-
import {purgeCache} from './cache';
|
|
3
|
-
import {NextServer} from 'next/dist/server/next';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import {NextConfig} from 'next/dist/server/config-shared';
|
|
6
|
-
|
|
7
|
-
const hostname = process.env.HOST || '127.0.0.1';
|
|
8
|
-
const dev = process.env.NODE_ENV !== 'production';
|
|
9
|
-
const port = process.env.PORT && parseInt(process.env.PORT, 10) || (dev ? 3000 : 4242);
|
|
10
|
-
|
|
11
|
-
export const PURGE_CACHE_URL = '/_/enonic/cache/purge';
|
|
12
|
-
|
|
13
|
-
export const withEnonicCache = function (config: any) {
|
|
14
|
-
const exp = config.experimental || {};
|
|
15
|
-
exp.isrMemoryCacheSize = exp.isrMemoryCacheSize || 1000000;
|
|
16
|
-
exp.incrementalCacheHandlerPath = path.resolve(__dirname, 'ClearableFileCache.js');
|
|
17
|
-
config.experimental = exp;
|
|
18
|
-
return config;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Not typed to prevent collision of local types with end-user ones
|
|
22
|
-
export default async (next: (options: any) => any) => {
|
|
23
|
-
const nextServer = next({dev, hostname, port}) as NextServer;
|
|
24
|
-
const nextHandler = nextServer.getRequestHandler();
|
|
25
|
-
return await nextServer.prepare().then(async () => {
|
|
26
|
-
const nextNodeServer = await nextServer['getServer']?.();
|
|
27
|
-
if (!nextNodeServer) {
|
|
28
|
-
console.error('Unable to access incremental cache, cache purge endpoint will be disabled');
|
|
29
|
-
return nextServer;
|
|
30
|
-
}
|
|
31
|
-
const opts: NextConfig = nextNodeServer['serverOptions'].conf;
|
|
32
|
-
const purgeUrl = (opts?.basePath || '') + PURGE_CACHE_URL;
|
|
33
|
-
|
|
34
|
-
console.info(`Staring cache purge endpoint at ${purgeUrl}...`);
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
36
|
-
const server = createServer(async (req, res) => {
|
|
37
|
-
const parsedUrl = new URL(`http://${hostname}:${port}${req.url || ''}`);
|
|
38
|
-
if (parsedUrl.pathname !== purgeUrl) {
|
|
39
|
-
await nextHandler(req, res);
|
|
40
|
-
} else if (dev) {
|
|
41
|
-
console.warn('\nCache clearing is not available in DEV mode.\n');
|
|
42
|
-
|
|
43
|
-
res.setHeader('Content-Type', 'application/json');
|
|
44
|
-
res.end(JSON.stringify({purged: false}));
|
|
45
|
-
} else {
|
|
46
|
-
const tokenParam = parsedUrl.searchParams.get('token');
|
|
47
|
-
if (tokenParam !== process.env.ENONIC_API_TOKEN) {
|
|
48
|
-
// XP hijacks 401 to show login page, so send 407 instead
|
|
49
|
-
res.statusCode = 407;
|
|
50
|
-
res.end(JSON.stringify({message: 'Invalid token'}));
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const cache = nextNodeServer.getIncrementalCache({
|
|
55
|
-
requestHeaders: Object.assign({}, req.headers),
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const pathParam = parsedUrl.searchParams.get('path') || undefined;
|
|
59
|
-
await purgeCache(cache, pathParam);
|
|
60
|
-
|
|
61
|
-
res.setHeader('Content-Type', 'application/json');
|
|
62
|
-
res.end(JSON.stringify({purged: true}));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
}).listen(port, hostname, () => {
|
|
66
|
-
console.info(`Server ready on ${hostname}:${port}`);
|
|
67
|
-
}).on('error', (e) => {
|
|
68
|
-
console.error('Server error:', e);
|
|
69
|
-
server.close();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
return nextServer;
|
|
73
|
-
});
|
|
74
|
-
};
|
package/server/tsconfig.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es5",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"skipLibCheck": true,
|
|
6
|
-
"moduleResolution": "Node",
|
|
7
|
-
"lib": [
|
|
8
|
-
"es6"
|
|
9
|
-
],
|
|
10
|
-
"strict": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"allowJs": true,
|
|
13
|
-
"noImplicitAny": true,
|
|
14
|
-
"outDir": "../dist/server",
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"declaration": true
|
|
17
|
-
},
|
|
18
|
-
"include": [
|
|
19
|
-
"../next-env.d.ts",
|
|
20
|
-
"**/*.ts"
|
|
21
|
-
],
|
|
22
|
-
"exclude": []
|
|
23
|
-
}
|
package/src/.eslintrc.js
DELETED