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.
Files changed (90) hide show
  1. package/dist/api/index.d.ts +82 -45
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/lib/serverActions.d.ts +68 -5
  4. package/dist/api/lib/serverActions.d.ts.map +1 -1
  5. package/dist/api/lib/serverActions.js +33 -8
  6. package/dist/api/root.d.ts +953 -44
  7. package/dist/api/root.d.ts.map +1 -1
  8. package/dist/api/root.js +2 -1
  9. package/dist/api/routers/accountSettings.d.ts +1 -3
  10. package/dist/api/routers/accountSettings.d.ts.map +1 -1
  11. package/dist/api/routers/admins.d.ts +1 -3
  12. package/dist/api/routers/admins.d.ts.map +1 -1
  13. package/dist/api/routers/admins.js +1 -1
  14. package/dist/api/routers/auth.d.ts +1 -3
  15. package/dist/api/routers/auth.d.ts.map +1 -1
  16. package/dist/api/routers/categorySection.d.ts +1 -3
  17. package/dist/api/routers/categorySection.d.ts.map +1 -1
  18. package/dist/api/routers/cmsSettings.d.ts +1 -3
  19. package/dist/api/routers/cmsSettings.d.ts.map +1 -1
  20. package/dist/api/routers/cpanel.d.ts +1 -3
  21. package/dist/api/routers/cpanel.d.ts.map +1 -1
  22. package/dist/api/routers/files.d.ts +1 -3
  23. package/dist/api/routers/files.d.ts.map +1 -1
  24. package/dist/api/routers/gallery.d.ts +1 -3
  25. package/dist/api/routers/gallery.d.ts.map +1 -1
  26. package/dist/api/routers/gallery.js +7 -6
  27. package/dist/api/routers/googleAnalytics.d.ts +1 -3
  28. package/dist/api/routers/googleAnalytics.d.ts.map +1 -1
  29. package/dist/api/routers/hasItemsSection.d.ts +49 -5
  30. package/dist/api/routers/hasItemsSection.d.ts.map +1 -1
  31. package/dist/api/routers/navigation.d.ts +1 -3
  32. package/dist/api/routers/navigation.d.ts.map +1 -1
  33. package/dist/api/routers/simpleSection.d.ts +21 -4
  34. package/dist/api/routers/simpleSection.d.ts.map +1 -1
  35. package/dist/api/trpc/query-client.d.ts +3 -0
  36. package/dist/api/trpc/query-client.d.ts.map +1 -0
  37. package/dist/api/trpc/query-client.js +23 -0
  38. package/dist/api/trpc/server.d.ts +8 -0
  39. package/dist/api/trpc/server.d.ts.map +1 -0
  40. package/dist/api/trpc/server.js +23 -0
  41. package/dist/api/trpc.d.ts +6 -17
  42. package/dist/api/trpc.d.ts.map +1 -1
  43. package/dist/api/trpc.js +6 -9
  44. package/dist/auth/react.js +1 -1
  45. package/dist/core/config/config-loader.d.ts +1 -1
  46. package/dist/core/config/config-loader.d.ts.map +1 -1
  47. package/dist/core/config/config-loader.js +9 -6
  48. package/dist/core/config/index.d.ts +1 -0
  49. package/dist/core/config/index.d.ts.map +1 -1
  50. package/dist/core/config/index.js +1 -0
  51. package/dist/core/config/loader-with-esbuild.d.ts +7 -0
  52. package/dist/core/config/loader-with-esbuild.d.ts.map +1 -0
  53. package/dist/core/config/loader-with-esbuild.js +98 -0
  54. package/dist/core/config/loader-with-jiti.d.ts +13 -0
  55. package/dist/core/config/loader-with-jiti.d.ts.map +1 -0
  56. package/dist/core/config/loader-with-jiti.js +162 -0
  57. package/dist/core/config/loader.d.ts +1 -1
  58. package/dist/core/config/loader.d.ts.map +1 -1
  59. package/dist/core/config/loader.js +1 -75
  60. package/dist/core/factories/SectionFactory.d.ts +1 -109
  61. package/dist/core/factories/SectionFactory.d.ts.map +1 -1
  62. package/dist/core/factories/SectionFactory.js +1 -452
  63. package/dist/core/factories/section-factory-with-esbuild.d.ts +110 -0
  64. package/dist/core/factories/section-factory-with-esbuild.d.ts.map +1 -0
  65. package/dist/core/factories/section-factory-with-esbuild.js +509 -0
  66. package/dist/core/factories/section-factory-with-jiti.d.ts +113 -0
  67. package/dist/core/factories/section-factory-with-jiti.d.ts.map +1 -0
  68. package/dist/core/factories/section-factory-with-jiti.js +556 -0
  69. package/dist/core/fields/document.d.ts +0 -1
  70. package/dist/core/fields/document.d.ts.map +1 -1
  71. package/dist/core/fields/document.js +5 -4
  72. package/dist/core/fields/photo.d.ts +10 -7
  73. package/dist/core/fields/photo.d.ts.map +1 -1
  74. package/dist/core/fields/photo.js +44 -17
  75. package/dist/core/fields/richText.d.ts +0 -1
  76. package/dist/core/fields/richText.d.ts.map +1 -1
  77. package/dist/core/fields/richText.js +5 -4
  78. package/dist/core/fields/video.d.ts +0 -1
  79. package/dist/core/fields/video.d.ts.map +1 -1
  80. package/dist/core/fields/video.js +5 -4
  81. package/dist/core/sections/section.d.ts +17 -15
  82. package/dist/core/sections/section.d.ts.map +1 -1
  83. package/dist/core/sections/section.js +28 -5
  84. package/dist/core/submit/submit.d.ts.map +1 -1
  85. package/dist/core/submit/submit.js +13 -12
  86. package/dist/translations/dictionaries/ar.json +1 -0
  87. package/dist/translations/dictionaries/en.json +1 -0
  88. package/dist/translations/index.d.ts.map +1 -1
  89. package/dist/translations/index.js +1 -3
  90. 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;IAEpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAmC;gBAErD,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI;IAqDxC,eAAe;;kBAtED,MAAM;kBAAQ,IAAI,GAAG,IAAI;;;;;;;;;;;;;IA+EjD,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;IAiCK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAezD;;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;IArRf;;;;;;;OAOG;;;;;;;;IAEH;;;;;OAKG;;;;;;;;;;;;;;;;;;;kBA0QL,CAAA;AAEF,QAAA,MAAM,yBAAyB;;;IA1R3B;;;;;;;OAOG;;;;;;;;IAEH;;;;;OAKG;;;;;;;;;;;;;;;;;;;kBAgRL,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"}
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 documentsFolder = path.join(this.uploadsFolder, '.documents', this._folder);
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(this.uploadsFolder, '.documents', this._folder, this.value), this._buffer);
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 pathToFile = path.join(this.uploadsFolder, '.documents', this._folder, this.value);
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
- readonly thumbnail: {
85
- width: number;
86
- height: number;
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":"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"}
1
+ {"version":3,"file":"photo.d.ts","sourceRoot":"","sources":["../../../src/core/fields/photo.ts"],"names":[],"mappings":"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"}