nextjs-cms 0.5.56 → 0.5.58
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/dist/api/index.d.ts +82 -45
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/lib/serverActions.d.ts +68 -5
- package/dist/api/lib/serverActions.d.ts.map +1 -1
- package/dist/api/lib/serverActions.js +33 -8
- package/dist/api/root.d.ts +953 -44
- package/dist/api/root.d.ts.map +1 -1
- package/dist/api/root.js +2 -1
- package/dist/api/routers/accountSettings.d.ts +1 -3
- package/dist/api/routers/accountSettings.d.ts.map +1 -1
- package/dist/api/routers/admins.d.ts +1 -3
- package/dist/api/routers/admins.d.ts.map +1 -1
- package/dist/api/routers/admins.js +1 -1
- package/dist/api/routers/auth.d.ts +1 -3
- package/dist/api/routers/auth.d.ts.map +1 -1
- package/dist/api/routers/categorySection.d.ts +1 -3
- package/dist/api/routers/categorySection.d.ts.map +1 -1
- package/dist/api/routers/cmsSettings.d.ts +1 -3
- package/dist/api/routers/cmsSettings.d.ts.map +1 -1
- package/dist/api/routers/cpanel.d.ts +1 -3
- package/dist/api/routers/cpanel.d.ts.map +1 -1
- package/dist/api/routers/files.d.ts +1 -3
- package/dist/api/routers/files.d.ts.map +1 -1
- package/dist/api/routers/gallery.d.ts +1 -3
- package/dist/api/routers/gallery.d.ts.map +1 -1
- package/dist/api/routers/gallery.js +7 -6
- package/dist/api/routers/googleAnalytics.d.ts +1 -3
- package/dist/api/routers/googleAnalytics.d.ts.map +1 -1
- package/dist/api/routers/hasItemsSection.d.ts +49 -5
- package/dist/api/routers/hasItemsSection.d.ts.map +1 -1
- package/dist/api/routers/navigation.d.ts +1 -3
- package/dist/api/routers/navigation.d.ts.map +1 -1
- package/dist/api/routers/simpleSection.d.ts +21 -4
- package/dist/api/routers/simpleSection.d.ts.map +1 -1
- package/dist/api/trpc/query-client.d.ts +3 -0
- package/dist/api/trpc/query-client.d.ts.map +1 -0
- package/dist/api/trpc/query-client.js +23 -0
- package/dist/api/trpc/server.d.ts +8 -0
- package/dist/api/trpc/server.d.ts.map +1 -0
- package/dist/api/trpc/server.js +23 -0
- package/dist/api/trpc.d.ts +6 -17
- package/dist/api/trpc.d.ts.map +1 -1
- package/dist/api/trpc.js +6 -9
- package/dist/auth/react.js +1 -1
- package/dist/core/config/config-loader.d.ts +1 -1
- package/dist/core/config/config-loader.d.ts.map +1 -1
- package/dist/core/config/config-loader.js +9 -6
- package/dist/core/config/index.d.ts +1 -0
- package/dist/core/config/index.d.ts.map +1 -1
- package/dist/core/config/index.js +1 -0
- package/dist/core/config/loader-with-esbuild.d.ts +7 -0
- package/dist/core/config/loader-with-esbuild.d.ts.map +1 -0
- package/dist/core/config/loader-with-esbuild.js +98 -0
- package/dist/core/config/loader-with-jiti.d.ts +13 -0
- package/dist/core/config/loader-with-jiti.d.ts.map +1 -0
- package/dist/core/config/loader-with-jiti.js +162 -0
- package/dist/core/config/loader.d.ts +1 -1
- package/dist/core/config/loader.d.ts.map +1 -1
- package/dist/core/config/loader.js +1 -75
- package/dist/core/factories/SectionFactory.d.ts +1 -109
- package/dist/core/factories/SectionFactory.d.ts.map +1 -1
- package/dist/core/factories/SectionFactory.js +1 -452
- package/dist/core/factories/section-factory-with-esbuild.d.ts +110 -0
- package/dist/core/factories/section-factory-with-esbuild.d.ts.map +1 -0
- package/dist/core/factories/section-factory-with-esbuild.js +509 -0
- package/dist/core/factories/section-factory-with-jiti.d.ts +113 -0
- package/dist/core/factories/section-factory-with-jiti.d.ts.map +1 -0
- package/dist/core/factories/section-factory-with-jiti.js +556 -0
- package/dist/core/fields/document.d.ts +0 -1
- package/dist/core/fields/document.d.ts.map +1 -1
- package/dist/core/fields/document.js +5 -4
- package/dist/core/fields/photo.d.ts +10 -7
- package/dist/core/fields/photo.d.ts.map +1 -1
- package/dist/core/fields/photo.js +44 -17
- package/dist/core/fields/richText.d.ts +0 -1
- package/dist/core/fields/richText.d.ts.map +1 -1
- package/dist/core/fields/richText.js +5 -4
- package/dist/core/fields/video.d.ts +0 -1
- package/dist/core/fields/video.d.ts.map +1 -1
- package/dist/core/fields/video.js +5 -4
- package/dist/core/sections/section.d.ts +17 -15
- package/dist/core/sections/section.d.ts.map +1 -1
- package/dist/core/sections/section.js +28 -5
- package/dist/core/submit/submit.d.ts.map +1 -1
- package/dist/core/submit/submit.js +13 -12
- package/dist/translations/dictionaries/ar.json +1 -0
- package/dist/translations/dictionaries/en.json +1 -0
- package/dist/translations/index.d.ts.map +1 -1
- package/dist/translations/index.js +1 -3
- package/package.json +18 -9
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import { cloneDeep } from 'lodash-es';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { eq } from 'drizzle-orm';
|
|
6
|
+
import chokidar from 'chokidar';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import { createRequire } from 'module';
|
|
9
|
+
import { db } from '../../db/client.js';
|
|
10
|
+
import { AdminPrivilegesTable } from '../../db/schema.js';
|
|
11
|
+
import { getCMSConfig, getConfigImportVersion } from '../config/index.js';
|
|
12
|
+
const hotMarkerFile = resolve(process.cwd(), 'components/form/helpers/_section-hot-reload.js');
|
|
13
|
+
// Create a require function that works in ES modules
|
|
14
|
+
const safeRequire = createRequire(import.meta.url);
|
|
15
|
+
/**
|
|
16
|
+
* Load jiti via Node require so Next can externalize it and avoid <dynamic> bundler errors.
|
|
17
|
+
*/
|
|
18
|
+
const loadJiti = () => {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
20
|
+
const jitiModule = safeRequire('jiti');
|
|
21
|
+
return jitiModule.createJiti;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Global jiti instance for loading section modules.
|
|
25
|
+
* We keep it global so we can clear its cache when files change.
|
|
26
|
+
*/
|
|
27
|
+
let jitiInstance = null;
|
|
28
|
+
let cachedCmsConfig = null;
|
|
29
|
+
let cachedCmsConfigVersion = -1;
|
|
30
|
+
const getCmsConfigCached = async (currentVersion = getConfigImportVersion()) => {
|
|
31
|
+
if (!cachedCmsConfig || cachedCmsConfigVersion !== currentVersion) {
|
|
32
|
+
cachedCmsConfig = await getCMSConfig();
|
|
33
|
+
cachedCmsConfigVersion = currentVersion;
|
|
34
|
+
}
|
|
35
|
+
return cachedCmsConfig;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Log a message to the console if debug mode is enabled
|
|
39
|
+
* @param args - The arguments to log
|
|
40
|
+
* @returns void
|
|
41
|
+
*/
|
|
42
|
+
const log = (...args) => {
|
|
43
|
+
if (!cachedCmsConfig?.debug)
|
|
44
|
+
return;
|
|
45
|
+
console.log(chalk.black.bgGreen(`[${new Date().toISOString()}][next-cms-debug]`, ...args));
|
|
46
|
+
};
|
|
47
|
+
const getJitiInstance = () => {
|
|
48
|
+
if (!jitiInstance) {
|
|
49
|
+
const createJiti = loadJiti();
|
|
50
|
+
jitiInstance = createJiti(import.meta.url, {
|
|
51
|
+
// Keep your previous behavior:
|
|
52
|
+
// - return default export compatibly
|
|
53
|
+
interopDefault: true,
|
|
54
|
+
// Caching (new API uses fsCache/moduleCache)
|
|
55
|
+
// Keep them enabled for better performance.
|
|
56
|
+
fsCache: true,
|
|
57
|
+
moduleCache: true,
|
|
58
|
+
rebuildFsCache: true,
|
|
59
|
+
// Optional: nicer debugging in stack traces (off by default in jiti)
|
|
60
|
+
// sourceMaps: true,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return jitiInstance;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Clear jiti's cache for a specific file path.
|
|
67
|
+
* This ensures that when a file changes, jiti will reload it on the next require.
|
|
68
|
+
*/
|
|
69
|
+
const clearJitiCache = (absPath) => {
|
|
70
|
+
const jiti = getJitiInstance();
|
|
71
|
+
try {
|
|
72
|
+
// Try to resolve the path using jiti's resolve (which handles TS files)
|
|
73
|
+
let resolvedPath;
|
|
74
|
+
try {
|
|
75
|
+
// jiti extends NodeRequire, so it has resolve
|
|
76
|
+
resolvedPath = jiti.resolve(absPath);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Last resort: use the absPath as-is
|
|
80
|
+
resolvedPath = absPath;
|
|
81
|
+
}
|
|
82
|
+
// Clear from jiti's cache (jiti extends NodeRequire, so it has cache)
|
|
83
|
+
if (resolvedPath && jiti.cache[resolvedPath]) {
|
|
84
|
+
delete jiti.cache[resolvedPath];
|
|
85
|
+
log('Cleared jiti cache for', resolvedPath);
|
|
86
|
+
}
|
|
87
|
+
// Also clear from Node's global require cache (for safety)
|
|
88
|
+
if (resolvedPath && safeRequire.cache[resolvedPath]) {
|
|
89
|
+
delete safeRequire.cache[resolvedPath];
|
|
90
|
+
log('Cleared Node require cache for', resolvedPath);
|
|
91
|
+
}
|
|
92
|
+
// Try clearing with .ts extension if different
|
|
93
|
+
const tsPath = absPath.endsWith('.ts') ? absPath : `${absPath}.ts`;
|
|
94
|
+
if (tsPath !== resolvedPath && jiti.cache[tsPath]) {
|
|
95
|
+
delete jiti.cache[tsPath];
|
|
96
|
+
log('Cleared jiti cache for', tsPath);
|
|
97
|
+
}
|
|
98
|
+
if (tsPath !== resolvedPath && safeRequire.cache[tsPath]) {
|
|
99
|
+
delete safeRequire.cache[tsPath];
|
|
100
|
+
log('Cleared Node require cache for', tsPath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
// If resolution fails, try clearing by matching keys in cache
|
|
105
|
+
log('Could not resolve path for cache clearing, trying pattern match:', absPath);
|
|
106
|
+
const absPathNormalized = absPath.replace(/\\/g, '/');
|
|
107
|
+
// Clear any cache entries that match this path
|
|
108
|
+
for (const key in jiti.cache) {
|
|
109
|
+
if (key.replace(/\\/g, '/').includes(absPathNormalized)) {
|
|
110
|
+
delete jiti.cache[key];
|
|
111
|
+
log('Cleared jiti cache entry:', key);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const key in safeRequire.cache) {
|
|
115
|
+
if (key.replace(/\\/g, '/').includes(absPathNormalized)) {
|
|
116
|
+
delete safeRequire.cache[key];
|
|
117
|
+
log('Cleared Node require cache entry:', key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const loadSectionModuleRuntime = async (absPath) => {
|
|
123
|
+
const jiti = getJitiInstance();
|
|
124
|
+
/**
|
|
125
|
+
* We're using the deprecated synchronous API because
|
|
126
|
+
* it works with Turbopack, the new jiti.import() does not.
|
|
127
|
+
*/
|
|
128
|
+
const mod = jiti(absPath);
|
|
129
|
+
return mod?.default ?? mod;
|
|
130
|
+
};
|
|
131
|
+
export class SectionFactory {
|
|
132
|
+
/**
|
|
133
|
+
* These are the fixed sections that can not be present in the sections folder.
|
|
134
|
+
*/
|
|
135
|
+
static fixedSections = ['admins', 'analytics', 'emails', 'dashboard'];
|
|
136
|
+
static isDev = process.env.NODE_ENV !== 'production';
|
|
137
|
+
static isProd = !this.isDev;
|
|
138
|
+
static sectionProcessingErrors = {};
|
|
139
|
+
static sectionFetchingErrors = {};
|
|
140
|
+
static errorCount = 0;
|
|
141
|
+
/**
|
|
142
|
+
* Global in-process cache for all section configs.
|
|
143
|
+
* Populated once per Node process via loadAllSections(),
|
|
144
|
+
* reused by all get*() calls until the process is restarted,
|
|
145
|
+
* so all subsequent calls reuse this array.
|
|
146
|
+
*/
|
|
147
|
+
static allSectionsPromise = null;
|
|
148
|
+
static allSectionsLoaded = false;
|
|
149
|
+
static watcherStarted = false;
|
|
150
|
+
static configVersion = -1;
|
|
151
|
+
static sectionWatcher = null;
|
|
152
|
+
static async ensureConfigFresh() {
|
|
153
|
+
const currentVersion = getConfigImportVersion();
|
|
154
|
+
const cmsConfig = await getCmsConfigCached(currentVersion);
|
|
155
|
+
if (this.configVersion !== currentVersion) {
|
|
156
|
+
this.configVersion = currentVersion;
|
|
157
|
+
this.sectionProcessingErrors = {};
|
|
158
|
+
this.sectionFetchingErrors = {};
|
|
159
|
+
this.errorCount = 0;
|
|
160
|
+
this.allSectionsPromise = null;
|
|
161
|
+
this.allSectionsLoaded = false;
|
|
162
|
+
if (this.sectionWatcher) {
|
|
163
|
+
await this.sectionWatcher.close();
|
|
164
|
+
this.sectionWatcher = null;
|
|
165
|
+
this.watcherStarted = false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return cmsConfig;
|
|
169
|
+
}
|
|
170
|
+
static bumpHotMarker() {
|
|
171
|
+
if (!SectionFactory.isDev)
|
|
172
|
+
return;
|
|
173
|
+
const content = `/**\n` +
|
|
174
|
+
` * AUTO-GENERATED. DO NOT EDIT.\n` +
|
|
175
|
+
` * This file is used to track the last time the sections/config schema was updated.\n` +
|
|
176
|
+
` * It is used to trigger a hot reload of the section/config in development mode.\n` +
|
|
177
|
+
` */\n` +
|
|
178
|
+
`\n` +
|
|
179
|
+
`export const revalidate = 0\n` +
|
|
180
|
+
`\n` +
|
|
181
|
+
`// @refresh reset\n` +
|
|
182
|
+
`\n` +
|
|
183
|
+
`export const configLastUpdated = ${Date.now()}\n`;
|
|
184
|
+
try {
|
|
185
|
+
fs.writeFileSync(hotMarkerFile, content, 'utf8');
|
|
186
|
+
log('Bumped _section-hot-reload.js to trigger Next Fast Refresh');
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
console.error('Failed to bump _section-hot-reload.js:', err);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// ---------- PUBLIC API ----------
|
|
193
|
+
/**
|
|
194
|
+
* Get all sections
|
|
195
|
+
* @param type - The type of sections to get
|
|
196
|
+
* @returns The sections
|
|
197
|
+
*/
|
|
198
|
+
static async getSections(type) {
|
|
199
|
+
return await this.get({ type });
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get all accessible sections for an admin
|
|
203
|
+
* @param type - The type of section to get
|
|
204
|
+
* @param admin - The admin to get the sections for
|
|
205
|
+
* @returns The sections for the admin
|
|
206
|
+
*/
|
|
207
|
+
static async getSectionsForAdmin({ type, admin, }) {
|
|
208
|
+
const sections = await this.get({ type, admin });
|
|
209
|
+
const privileges = await db
|
|
210
|
+
.select({
|
|
211
|
+
sectionName: AdminPrivilegesTable.sectionName,
|
|
212
|
+
operations: AdminPrivilegesTable.operations,
|
|
213
|
+
})
|
|
214
|
+
.from(AdminPrivilegesTable)
|
|
215
|
+
.where(eq(AdminPrivilegesTable.adminId, admin.id));
|
|
216
|
+
const fixedSections = privileges
|
|
217
|
+
.filter((privilege) => this.fixedSections.includes(privilege.sectionName))
|
|
218
|
+
.map((privilege) => privilege.sectionName);
|
|
219
|
+
const simpleSections = sections.filter((section) => section.type === 'simple');
|
|
220
|
+
const hasItemsSections = sections.filter((section) => section.type === 'has_items');
|
|
221
|
+
const categorySections = sections.filter((section) => section.type === 'category');
|
|
222
|
+
return {
|
|
223
|
+
simple: simpleSections,
|
|
224
|
+
has_items: hasItemsSections,
|
|
225
|
+
category: categorySections,
|
|
226
|
+
fixed: fixedSections,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get a section
|
|
231
|
+
* @param name - The name of the section to get
|
|
232
|
+
* @param type - The type of section to get
|
|
233
|
+
* @returns The section
|
|
234
|
+
*/
|
|
235
|
+
static async getSection({ name, type, }) {
|
|
236
|
+
const section = await this.get({ name, type });
|
|
237
|
+
return section[0] ? section[0] : null;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get an accessible section for an admin
|
|
241
|
+
* @param name - The name of the section to get
|
|
242
|
+
* @param type - The type of section to get
|
|
243
|
+
* @param admin - The admin to get the section for
|
|
244
|
+
* @returns The section for the admin
|
|
245
|
+
*/
|
|
246
|
+
static async getSectionForAdmin({ name, type, admin, }) {
|
|
247
|
+
const section = await this.get({ type, admin, name });
|
|
248
|
+
return section[0] ? section[0] : null;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Create a Section instance from a section config
|
|
252
|
+
* The config must have a build() method (created via helper functions like simpleSection(), hasItemsSection(), etc.)
|
|
253
|
+
*
|
|
254
|
+
* Note: This factory only accepts configs. If you already have a Section instance,
|
|
255
|
+
* use it directly - don't pass it to this factory.
|
|
256
|
+
*
|
|
257
|
+
* @param config - A section config object with a build() method
|
|
258
|
+
* @returns A Section instance
|
|
259
|
+
* @throws Error if config doesn't have a build() method
|
|
260
|
+
*/
|
|
261
|
+
static create(config) {
|
|
262
|
+
if (typeof config.build === 'function') {
|
|
263
|
+
return config.build();
|
|
264
|
+
}
|
|
265
|
+
throw new Error('Section config must have a build() method. Use helper functions like simpleSection(), hasItemsSection(), categorySection() to create configs.');
|
|
266
|
+
}
|
|
267
|
+
// ---------- INTERNAL CORE ----------
|
|
268
|
+
/**
|
|
269
|
+
* Return a clone of the section(s) info to get a fresh copy of the section(s).
|
|
270
|
+
* Not cloning will cause the original section(s) (in *.section.ts file) to be modified!
|
|
271
|
+
* Each *.section.ts file must have exactly one default export (arrays are not allowed).
|
|
272
|
+
*
|
|
273
|
+
* @param name - The name of the section to get
|
|
274
|
+
* @param type - The type of section to get
|
|
275
|
+
* @param admin - The admin to get the section for
|
|
276
|
+
* @returns The section(s)
|
|
277
|
+
*/
|
|
278
|
+
static async get({ name, type, admin, }) {
|
|
279
|
+
try {
|
|
280
|
+
const allSections = await this.loadAllSections();
|
|
281
|
+
/**
|
|
282
|
+
* Always show errors if there are any.
|
|
283
|
+
* This is to make sure the errors are shown on every request (technically, every time the section is requested).
|
|
284
|
+
* This way devs can notice the errors and fix them.
|
|
285
|
+
*/
|
|
286
|
+
if (this.errorCount > 0) {
|
|
287
|
+
console.log(`\n${chalk.bgRed.bold(` Errors while fetching sections `)}${chalk.red.bold('-------')}\n`);
|
|
288
|
+
if (Object.keys(this.sectionProcessingErrors).length > 0) {
|
|
289
|
+
console.log(`${chalk.bold.redBright(`Processing errors:`)}`);
|
|
290
|
+
for (const [file, errors] of Object.entries(this.sectionProcessingErrors)) {
|
|
291
|
+
console.log('');
|
|
292
|
+
console.log(chalk.bold(`[${file}]:`));
|
|
293
|
+
for (const error of errors) {
|
|
294
|
+
console.error(error);
|
|
295
|
+
}
|
|
296
|
+
console.log('');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (Object.keys(this.sectionFetchingErrors).length > 0) {
|
|
300
|
+
console.log(`\n${chalk.bold.redBright(`Importing errors:`)}`);
|
|
301
|
+
for (const [file, errors] of Object.entries(this.sectionFetchingErrors)) {
|
|
302
|
+
console.log('');
|
|
303
|
+
console.log(chalk.bold(`[${file}]:`));
|
|
304
|
+
for (const error of errors) {
|
|
305
|
+
console.error(error);
|
|
306
|
+
}
|
|
307
|
+
console.log('');
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
console.log(`${chalk.red.bold('-------')}`);
|
|
311
|
+
}
|
|
312
|
+
const types = type
|
|
313
|
+
? Array.isArray(type)
|
|
314
|
+
? type
|
|
315
|
+
: [type]
|
|
316
|
+
: ['has_items', 'simple', 'category'];
|
|
317
|
+
// Filter by type first
|
|
318
|
+
let filtered = allSections.filter((section) => types.includes(section.type));
|
|
319
|
+
// If admin is provided, restrict to privileged sections
|
|
320
|
+
if (admin && admin.id) {
|
|
321
|
+
const privileges = await db
|
|
322
|
+
.select({
|
|
323
|
+
sectionName: AdminPrivilegesTable.sectionName,
|
|
324
|
+
operations: AdminPrivilegesTable.operations,
|
|
325
|
+
})
|
|
326
|
+
.from(AdminPrivilegesTable)
|
|
327
|
+
.where(eq(AdminPrivilegesTable.adminId, admin.id));
|
|
328
|
+
const privilegedSections = [];
|
|
329
|
+
privileges.forEach((privilege) => {
|
|
330
|
+
if (admin.requiredRole) {
|
|
331
|
+
if (privilege.operations.includes(admin.requiredRole)) {
|
|
332
|
+
privilegedSections.push(privilege.sectionName);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
privilegedSections.push(privilege.sectionName);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
filtered = filtered.filter((section) => privilegedSections.includes(section.name));
|
|
340
|
+
}
|
|
341
|
+
if (name) {
|
|
342
|
+
const found = filtered.find((section) => section.name === name);
|
|
343
|
+
return found ? [cloneDeep(found)] : [];
|
|
344
|
+
}
|
|
345
|
+
return filtered.map((section) => cloneDeep(section));
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
console.error('Error loading section configs:', err);
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Load all *.section.ts files once, import their default exports,
|
|
354
|
+
* and cache the resulting configs for the lifetime of the process
|
|
355
|
+
* (until invalidated in dev by file changes).
|
|
356
|
+
*/
|
|
357
|
+
static async loadAllSections() {
|
|
358
|
+
const cmsConfig = await this.ensureConfigFresh();
|
|
359
|
+
if (this.allSectionsPromise)
|
|
360
|
+
return this.allSectionsPromise;
|
|
361
|
+
if (this.isDev) {
|
|
362
|
+
// In dev, watch for changes and reload on demand
|
|
363
|
+
// This will lazy load on first get() as well
|
|
364
|
+
this.startWatcher(cmsConfig);
|
|
365
|
+
}
|
|
366
|
+
this.allSectionsPromise = (async () => {
|
|
367
|
+
if (!this.allSectionsLoaded) {
|
|
368
|
+
log('Loading all sections from disk...', this.isDev ? '(dev mode)' : '(production mode)');
|
|
369
|
+
}
|
|
370
|
+
const sections = [];
|
|
371
|
+
try {
|
|
372
|
+
const sectionFiles = await glob('**/*.section.ts', {
|
|
373
|
+
cwd: cmsConfig.sections.path,
|
|
374
|
+
});
|
|
375
|
+
for (const file of sectionFiles) {
|
|
376
|
+
try {
|
|
377
|
+
const absPath = resolve(cmsConfig.sections.path, file);
|
|
378
|
+
const defaultExport = await loadSectionModuleRuntime(absPath);
|
|
379
|
+
if (!defaultExport) {
|
|
380
|
+
if (!this.sectionFetchingErrors[file]) {
|
|
381
|
+
this.sectionFetchingErrors[file] = [];
|
|
382
|
+
}
|
|
383
|
+
this.sectionFetchingErrors[file].push(chalk.rgb(255, 100, 0)('Section file must have a default export. Skipping.'));
|
|
384
|
+
this.errorCount++;
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (Array.isArray(defaultExport)) {
|
|
388
|
+
if (!this.sectionFetchingErrors[file]) {
|
|
389
|
+
this.sectionFetchingErrors[file] = [];
|
|
390
|
+
}
|
|
391
|
+
this.sectionFetchingErrors[file].push(chalk.rgb(255, 100, 0)('Section file exports an array. Each file must export exactly one section. Skipping.'));
|
|
392
|
+
this.errorCount++;
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (!defaultExport.type || !defaultExport.name) {
|
|
396
|
+
if (!this.sectionFetchingErrors[file]) {
|
|
397
|
+
this.sectionFetchingErrors[file] = [];
|
|
398
|
+
}
|
|
399
|
+
this.sectionFetchingErrors[file].push(chalk.rgb(255, 100, 0)('Section file default export must have "type" and "name". Skipping.'));
|
|
400
|
+
this.errorCount++;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
sections.push(defaultExport);
|
|
404
|
+
}
|
|
405
|
+
catch (importErr) {
|
|
406
|
+
/**
|
|
407
|
+
* Guardrail: extensioned imports inside section files
|
|
408
|
+
* This usually means the developer wrote:
|
|
409
|
+
* import x from './other.section.ts'
|
|
410
|
+
* or './other.section.js'
|
|
411
|
+
* which breaks once sections are bundled.
|
|
412
|
+
*/
|
|
413
|
+
if (importErr instanceof Error &&
|
|
414
|
+
importErr.message.includes('Cannot find module') &&
|
|
415
|
+
importErr.message.includes('.section')) {
|
|
416
|
+
this.sectionProcessingErrors[file] ??= [];
|
|
417
|
+
this.sectionProcessingErrors[file].push(`❌ Invalid section import detected.
|
|
418
|
+
|
|
419
|
+
Sections MUST use extensionless relative imports:
|
|
420
|
+
|
|
421
|
+
✅ import exampleSection from './example.section'
|
|
422
|
+
❌ import exampleSection from './example.section.ts'
|
|
423
|
+
❌ import exampleSection from './example.section.js'
|
|
424
|
+
|
|
425
|
+
This file is bundled with esbuild, so Node never resolves the import directly.
|
|
426
|
+
If you added an extension manually, remove it.`);
|
|
427
|
+
this.errorCount++;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Normal error handling
|
|
432
|
+
* Only display the error message, not the stack trace.
|
|
433
|
+
*/
|
|
434
|
+
if (importErr instanceof Error) {
|
|
435
|
+
/**
|
|
436
|
+
* Only display the error message, not the stack trace.
|
|
437
|
+
*/
|
|
438
|
+
if (!this.sectionProcessingErrors[file]) {
|
|
439
|
+
this.sectionProcessingErrors[file] = [];
|
|
440
|
+
}
|
|
441
|
+
this.sectionProcessingErrors[file].push(importErr.message);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
if (!this.sectionFetchingErrors[file]) {
|
|
445
|
+
this.sectionFetchingErrors[file] = [];
|
|
446
|
+
}
|
|
447
|
+
this.sectionFetchingErrors[file].push(chalk.rgb(255, 100, 0)(`Unknown error type: ${typeof importErr}`));
|
|
448
|
+
throw new Error(`${chalk.bgRed(` Error importing ${file}: `)}, ${importErr}`);
|
|
449
|
+
}
|
|
450
|
+
this.errorCount++;
|
|
451
|
+
/**
|
|
452
|
+
* Tests-only:
|
|
453
|
+
* remove from require cache so it will be reloaded next time.
|
|
454
|
+
* In dev/runtime, cache busting is handled via versioned ESM imports.
|
|
455
|
+
*/
|
|
456
|
+
if (process.env.NODE_ENV === 'test') {
|
|
457
|
+
try {
|
|
458
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
459
|
+
delete safeRequire.cache?.[resolve(cmsConfig.sections.path, file)];
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
// ignore
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
catch (err) {
|
|
469
|
+
console.error('Error finding section files:', err);
|
|
470
|
+
}
|
|
471
|
+
this.allSectionsLoaded = true;
|
|
472
|
+
/**
|
|
473
|
+
* If `strict` mode is enabled,
|
|
474
|
+
* don't return sections if there are errors.
|
|
475
|
+
*/
|
|
476
|
+
if (cmsConfig.sections.strict && this.errorCount > 0) {
|
|
477
|
+
return [];
|
|
478
|
+
}
|
|
479
|
+
log(`Loaded ${sections.length} section(s)`);
|
|
480
|
+
return sections;
|
|
481
|
+
})();
|
|
482
|
+
return this.allSectionsPromise;
|
|
483
|
+
}
|
|
484
|
+
// ---------- DEV WATCHER & CACHE INVALIDATION ----------
|
|
485
|
+
static startWatcher(cmsConfig) {
|
|
486
|
+
if (!this.isDev || this.watcherStarted)
|
|
487
|
+
return;
|
|
488
|
+
this.watcherStarted = true;
|
|
489
|
+
const watcher = chokidar.watch('**/*.section.ts', {
|
|
490
|
+
cwd: cmsConfig.sections.path,
|
|
491
|
+
ignoreInitial: true,
|
|
492
|
+
});
|
|
493
|
+
this.sectionWatcher = watcher;
|
|
494
|
+
log('Starting section watcher in dev mode...');
|
|
495
|
+
/**
|
|
496
|
+
* Invalidate section cache + bust runtime import cache.
|
|
497
|
+
* When a section file changes, we need to:
|
|
498
|
+
* 1. Clear jiti's module cache for that file
|
|
499
|
+
* 2. Reset our in-process caches
|
|
500
|
+
* 3. Reset the promise so sections reload on next access
|
|
501
|
+
* 4. Bump the hot marker to trigger Next.js Fast Refresh
|
|
502
|
+
*/
|
|
503
|
+
const invalidateForRelPath = (relPath) => {
|
|
504
|
+
const absPath = resolve(cmsConfig.sections.path, relPath);
|
|
505
|
+
// Clear jiti's cache for the changed file
|
|
506
|
+
clearJitiCache(absPath);
|
|
507
|
+
// Also clear the require cache for the hot marker file (if it exists)
|
|
508
|
+
try {
|
|
509
|
+
const jiti = getJitiInstance();
|
|
510
|
+
if (jiti.cache[hotMarkerFile]) {
|
|
511
|
+
delete jiti.cache[hotMarkerFile];
|
|
512
|
+
}
|
|
513
|
+
if (safeRequire.cache[hotMarkerFile]) {
|
|
514
|
+
delete safeRequire.cache[hotMarkerFile];
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
catch {
|
|
518
|
+
// ignore if not resolvable
|
|
519
|
+
}
|
|
520
|
+
// Reset our in-process caches
|
|
521
|
+
this.sectionProcessingErrors = {};
|
|
522
|
+
this.sectionFetchingErrors = {};
|
|
523
|
+
this.errorCount = 0;
|
|
524
|
+
this.allSectionsPromise = null;
|
|
525
|
+
this.allSectionsLoaded = false;
|
|
526
|
+
log('Invalidated section cache due to change in', relPath);
|
|
527
|
+
// Bump the hot marker to trigger Next.js Fast Refresh
|
|
528
|
+
this.bumpHotMarker();
|
|
529
|
+
};
|
|
530
|
+
watcher
|
|
531
|
+
.on('add', (path) => {
|
|
532
|
+
log('Section file added:', path);
|
|
533
|
+
invalidateForRelPath(path);
|
|
534
|
+
})
|
|
535
|
+
.on('change', (path) => {
|
|
536
|
+
log('Section file changed:', path);
|
|
537
|
+
invalidateForRelPath(path);
|
|
538
|
+
})
|
|
539
|
+
.on('unlink', (path) => {
|
|
540
|
+
log('Section file removed:', path);
|
|
541
|
+
invalidateForRelPath(path);
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
static init() {
|
|
545
|
+
if (this.isProd) {
|
|
546
|
+
// Preload all sections at startup in production
|
|
547
|
+
void this.loadAllSections();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Run initialization once when the module is loaded
|
|
552
|
+
*/
|
|
553
|
+
static {
|
|
554
|
+
this.init();
|
|
555
|
+
}
|
|
556
|
+
}
|
|
@@ -54,7 +54,6 @@ export declare class DocumentField extends FileField<'document', Config> {
|
|
|
54
54
|
private _buffer;
|
|
55
55
|
private _folder;
|
|
56
56
|
private _allowedExtensions;
|
|
57
|
-
readonly uploadsFolder: string;
|
|
58
57
|
constructor(config: BaseFieldConfig<Config>, file?: File);
|
|
59
58
|
exportForClient(): {
|
|
60
59
|
maxFileSize: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/core/fields/document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAIxB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAQ1C,QAAA,MAAM,YAAY;IACd;;;;;;;OAOG;;;;;;;;IAEH;;;;;OAKG;;;;;;;;;;;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,aAAc,SAAQ,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5D,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAkB;IAC/D,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IAE7B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAqE;IAE1G;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,kBAAkB,CAAU;
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/core/fields/document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAIxB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAQ1C,QAAA,MAAM,YAAY;IACd;;;;;;;OAOG;;;;;;;;IAEH;;;;;OAKG;;;;;;;;;;;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,aAAc,SAAQ,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5D,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAkB;IAC/D,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IAE7B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAqE;IAE1G;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,kBAAkB,CAAU;gBAExB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI;IAqDxC,eAAe;;kBApED,MAAM;kBAAQ,IAAI,GAAG,IAAI;;;;;;;;;;;;;IA6EjD,iBAAiB,CAAC,EACpB,WAAW,EACX,MAAM,EACN,aAAiB,GACpB,EAAE;QACC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;QACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAClC,GAAG,OAAO,CAAC,UAAU,CAAC;IAevB;;OAEG;IACG,WAAW;IA+BK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBzD;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIX,WAAW,CAAC,KAAK,EAAE,MAAM;IAIvB,QAAQ,CAAC,KAAK,EAAE,GAAG;IAQnB,OAAO,CAAC,IAAI,EAAE,IAAI;IAK3B,aAAa;IAab;;OAEG;IACG,oBAAoB;CAoD7B;AAED,MAAM,MAAM,yBAAyB,GAAG,UAAU,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAEpF,QAAA,MAAM,aAAa;IAlRf;;;;;;;OAOG;;;;;;;;IAEH;;;;;OAKG;;;;;;;;;;;;;;;;;;;kBAuQL,CAAA;AAEF,QAAA,MAAM,yBAAyB;;;IAvR3B;;;;;;;OAOG;;;;;;;;IAEH;;;;;OAKG;;;;;;;;;;;;;;;;;;;kBA6QL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,mBAAmB,CAmBvF"}
|
|
@@ -42,7 +42,6 @@ export class DocumentField extends FileField {
|
|
|
42
42
|
_buffer;
|
|
43
43
|
_folder;
|
|
44
44
|
_allowedExtensions;
|
|
45
|
-
uploadsFolder = getCMSConfig().media.upload.path;
|
|
46
45
|
constructor(config, file) {
|
|
47
46
|
super(config, 'document');
|
|
48
47
|
if (file) {
|
|
@@ -127,14 +126,15 @@ export class DocumentField extends FileField {
|
|
|
127
126
|
/**
|
|
128
127
|
* If .documents, and 'sectionName' folders don't exist, create them
|
|
129
128
|
*/
|
|
130
|
-
const
|
|
129
|
+
const uploadsFolder = (await getCMSConfig()).media.upload.path;
|
|
130
|
+
const documentsFolder = path.join(uploadsFolder, '.documents', this._folder);
|
|
131
131
|
if (!fs.existsSync(documentsFolder)) {
|
|
132
132
|
fs.mkdirSync(documentsFolder, { recursive: true });
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
135
|
* Write the file to disk
|
|
136
136
|
*/
|
|
137
|
-
await fs.promises.writeFile(path.join(
|
|
137
|
+
await fs.promises.writeFile(path.join(uploadsFolder, '.documents', this._folder, this.value), this._buffer);
|
|
138
138
|
}
|
|
139
139
|
catch (error) {
|
|
140
140
|
throw new Error(`${this.label}: Error writing file to disk ${error.message}`);
|
|
@@ -153,7 +153,8 @@ export class DocumentField extends FileField {
|
|
|
153
153
|
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder before writing the file to disk`);
|
|
154
154
|
}
|
|
155
155
|
try {
|
|
156
|
-
const
|
|
156
|
+
const uploadsFolder = (await getCMSConfig()).media.upload.path;
|
|
157
|
+
const pathToFile = path.join(uploadsFolder, '.documents', this._folder, this.value);
|
|
157
158
|
await fs.promises.unlink(pathToFile);
|
|
158
159
|
}
|
|
159
160
|
catch (error) {
|
|
@@ -81,14 +81,10 @@ export declare class PhotoField extends FileField<'photo', Config> {
|
|
|
81
81
|
};
|
|
82
82
|
readonly mimeType: string[];
|
|
83
83
|
readonly extensions: string[];
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
crop: boolean;
|
|
88
|
-
quality?: number;
|
|
89
|
-
};
|
|
84
|
+
private _thumbnail;
|
|
85
|
+
/** Thumbnail config passed via field options (may be undefined if using CMS defaults) */
|
|
86
|
+
private _thumbnailConfig;
|
|
90
87
|
readonly removeExtension: boolean;
|
|
91
|
-
readonly uploadsFolder: string;
|
|
92
88
|
/**
|
|
93
89
|
* _file is the file object if it's present
|
|
94
90
|
* Whereas the value is the path to the file
|
|
@@ -98,6 +94,13 @@ export declare class PhotoField extends FileField<'photo', Config> {
|
|
|
98
94
|
private _folder;
|
|
99
95
|
private _allowedExtensions;
|
|
100
96
|
constructor(config: BaseFieldConfig<Config>, file?: File);
|
|
97
|
+
/**
|
|
98
|
+
* Get the thumbnail configuration.
|
|
99
|
+
* Uses user-provided config if available, otherwise fetches from CMS config.
|
|
100
|
+
* Note: getCMSConfig() handles caching with version checking internally.
|
|
101
|
+
*/
|
|
102
|
+
private getThumbnail;
|
|
103
|
+
build(): Promise<void>;
|
|
101
104
|
exportForClient(): {
|
|
102
105
|
thumbnail: {
|
|
103
106
|
width: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"photo.d.ts","sourceRoot":"","sources":["../../../src/core/fields/photo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAKxB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"photo.d.ts","sourceRoot":"","sources":["../../../src/core/fields/photo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAKxB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAmC1C,QAAA,MAAM,YAAY;IACd,yCAAyC;;;;;;QA7BzC;;;;;;;;;;;;WAYG;;;;;;;;;IAsBH;;;;;;;OAOG;;;;;;;;IAEH;;;;;;;OAOG;;;;;;;IAEH;;;OAGG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,UAAW,SAAQ,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IACtD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAe;IAC5D,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;IAC9C,QAAQ,CAAC,eAAe,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;IACpD,QAAQ,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAA;IAC3E,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IAC7B,OAAO,CAAC,UAAU,CAA4F;IAC9G,yFAAyF;IACzF,OAAO,CAAC,gBAAgB,CAA4F;IACpH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;IAEjC;;;OAGG;IACH,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,kBAAkB,CAAU;gBAExB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI;IAoCxD;;;;OAIG;YACW,YAAY;IAaX,KAAK;IAOJ,eAAe;;mBA3EF,MAAM;oBAAU,MAAM;kBAAQ,OAAO;sBAAY,MAAM;;;mBAJ5D,MAAM;oBAAU,MAAM;kBAAQ,OAAO;;;kBAC/B,MAAM;kBAAQ,IAAI,GAAG,IAAI;;;;;;;;;;;;;IA8FvD;;OAEG;IACG,WAAW;IA+DK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBzD;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIX,WAAW,CAAC,KAAK,EAAE,MAAM;IAIvB,QAAQ,CAAC,KAAK,EAAE,GAAG;IAQ5B,OAAO,CAAC,IAAI,EAAE,IAAI;IAKlB,aAAa;IAab;;OAEG;IACG,oBAAoB;CAqJ7B;AAED,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE9E,QAAA,MAAM,aAAa;IA5Zf,yCAAyC;;;;;;QA7BzC;;;;;;;;;;;;WAYG;;;;;;;;;IAsBH;;;;;;;OAOG;;;;;;;;IAEH;;;;;;;OAOG;;;;;;;IAEH;;;OAGG;;;;;;;;;kBAqYL,CAAA;AAEF,QAAA,MAAM,sBAAsB;;;IAjaxB,yCAAyC;;;;;;QA7BzC;;;;;;;;;;;;WAYG;;;;;;;;;IAsBH;;;;;;;OAOG;;;;;;;;IAEH;;;;;;;OAOG;;;;;;;IAEH;;;OAGG;;;;;;;;;kBA2YL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,gBAAgB,CAmBjF"}
|