nextjs-cms 0.9.30 → 0.9.32

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 (96) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +279 -279
  3. package/dist/api/actions/pages.d.ts +3 -3
  4. package/dist/api/client.d.ts +30 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +82 -0
  7. package/dist/api/index.d.ts +1 -974
  8. package/dist/api/index.d.ts.map +1 -1
  9. package/dist/api/index.js +0 -13
  10. package/dist/api/lib/serverActions.d.ts +13 -49
  11. package/dist/api/lib/serverActions.d.ts.map +1 -1
  12. package/dist/api/lib/serverActions.js +103 -31
  13. package/dist/api/root.d.ts +18 -1916
  14. package/dist/api/root.d.ts.map +1 -1
  15. package/dist/api/root.js +18 -83
  16. package/dist/api/routers/config.d.ts.map +1 -1
  17. package/dist/api/routers/gallery.d.ts +1 -0
  18. package/dist/api/routers/gallery.d.ts.map +1 -1
  19. package/dist/api/routers/gallery.js +36 -8
  20. package/dist/api/routers/hasItemsSection.d.ts +5 -30
  21. package/dist/api/routers/hasItemsSection.d.ts.map +1 -1
  22. package/dist/api/routers/navigation.d.ts +3 -3
  23. package/dist/api/routers/simpleSection.d.ts +3 -15
  24. package/dist/api/routers/simpleSection.d.ts.map +1 -1
  25. package/dist/api/server.d.ts +2748 -0
  26. package/dist/api/server.d.ts.map +1 -0
  27. package/dist/api/server.js +100 -0
  28. package/dist/api/trpc/error-logging.d.ts +14 -0
  29. package/dist/api/trpc/error-logging.d.ts.map +1 -0
  30. package/dist/api/trpc/error-logging.js +75 -0
  31. package/dist/api/trpc/root.d.ts +3 -3
  32. package/dist/api/trpc/root.d.ts.map +1 -1
  33. package/dist/api/trpc/routers/config.d.ts.map +1 -1
  34. package/dist/api/trpc/routers/hasItemsSection.d.ts.map +1 -1
  35. package/dist/api/trpc/routers/navigation.d.ts +3 -3
  36. package/dist/api/trpc/routers/simpleSection.d.ts.map +1 -1
  37. package/dist/api/trpc/server.d.ts +9 -9
  38. package/dist/api/trpc/server.d.ts.map +1 -1
  39. package/dist/api/utils/async-caller-proxy.d.ts +2 -0
  40. package/dist/api/utils/async-caller-proxy.d.ts.map +1 -0
  41. package/dist/api/utils/async-caller-proxy.js +36 -0
  42. package/dist/api/utils/lazy-caller-proxy.d.ts +2 -0
  43. package/dist/api/utils/lazy-caller-proxy.d.ts.map +1 -0
  44. package/dist/api/utils/lazy-caller-proxy.js +36 -0
  45. package/dist/api/utils/router-types.d.ts +7 -0
  46. package/dist/api/utils/router-types.d.ts.map +1 -0
  47. package/dist/api/utils/router-types.js +0 -0
  48. package/dist/auth/trpc.d.ts +1 -1
  49. package/dist/auth/trpc.d.ts.map +1 -1
  50. package/dist/auth/trpc.js +0 -1
  51. package/dist/cli/lib/db-config.js +10 -10
  52. package/dist/cli/lib/update-sections.d.ts.map +1 -1
  53. package/dist/cli/lib/update-sections.js +29 -24
  54. package/dist/core/config/config-loader.d.ts +2 -2
  55. package/dist/core/db/table-checker/MysqlTable.js +10 -10
  56. package/dist/core/factories/section-factory-with-esbuild.js +9 -9
  57. package/dist/core/factories/section-factory-with-jiti.js +9 -9
  58. package/dist/core/sections/category.d.ts +2 -2
  59. package/dist/core/sections/hasItems.d.ts +2 -2
  60. package/dist/core/sections/section.d.ts +2 -2
  61. package/dist/core/sections/simple.d.ts +2 -2
  62. package/dist/plugins/loader.d.ts +3 -1
  63. package/dist/plugins/loader.d.ts.map +1 -1
  64. package/dist/plugins/loader.js +28 -6
  65. package/dist/plugins/manifest.d.ts +28 -0
  66. package/dist/plugins/manifest.d.ts.map +1 -0
  67. package/dist/plugins/manifest.js +83 -0
  68. package/dist/plugins/registry.d.ts +22 -0
  69. package/dist/plugins/registry.d.ts.map +1 -0
  70. package/dist/plugins/registry.js +25 -0
  71. package/dist/translations/base/en.d.ts +6 -0
  72. package/dist/translations/base/en.d.ts.map +1 -1
  73. package/dist/translations/base/en.js +6 -0
  74. package/dist/translations/client.d.ts +76 -4
  75. package/dist/translations/client.d.ts.map +1 -1
  76. package/dist/translations/server.d.ts +76 -4
  77. package/dist/translations/server.d.ts.map +1 -1
  78. package/dist/utils/log.d.ts +18 -0
  79. package/dist/utils/log.d.ts.map +1 -0
  80. package/dist/utils/log.js +28 -0
  81. package/package.json +1 -1
  82. package/dist/core/fields/dateRange.d.ts +0 -115
  83. package/dist/core/fields/dateRange.d.ts.map +0 -1
  84. package/dist/core/fields/dateRange.js +0 -149
  85. package/dist/translations/locale-cookie.d.ts +0 -24
  86. package/dist/translations/locale-cookie.d.ts.map +0 -1
  87. package/dist/translations/locale-cookie.js +0 -44
  88. package/dist/translations/locale-utils.d.ts +0 -8
  89. package/dist/translations/locale-utils.d.ts.map +0 -1
  90. package/dist/translations/locale-utils.js +0 -11
  91. package/dist/translations/localization.d.ts +0 -40
  92. package/dist/translations/localization.d.ts.map +0 -1
  93. package/dist/translations/localization.js +0 -48
  94. package/dist/validators/dateRange.d.ts +0 -11
  95. package/dist/validators/dateRange.d.ts.map +0 -1
  96. package/dist/validators/dateRange.js +0 -16
@@ -1 +1 @@
1
- {"version":3,"file":"serverActions.d.ts","sourceRoot":"","sources":["../../../src/api/lib/serverActions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serverActions.d.ts","sourceRoot":"","sources":["../../../src/api/lib/serverActions.ts"],"names":[],"mappings":"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"}
@@ -1,26 +1,25 @@
1
1
  // import 'server-only'
2
- import { db } from '../../db/client.js';
3
- import { AdminPrivilegesTable, AdminsTable, EditorPhotosTable } from '../../db/schema.js';
4
- import { and, eq, sql } from 'drizzle-orm';
5
- import { TRPCError } from '@trpc/server';
6
- import { FieldFactory, SectionFactory } from '../../core/factories/index.js';
7
- import { SelectField } from '../../core/fields/index.js';
8
- import { MysqlTableChecker } from '../../core/db/index.js';
9
2
  import fs from 'fs';
10
- import { Readable } from 'stream';
11
3
  import path from 'path';
12
- import { sanitizeFileName, sanitizeFolderOrFileName } from '../../utils/index.js';
13
- import sharp from 'sharp';
14
- import { readChunk } from 'read-chunk';
4
+ import { Readable } from 'stream';
5
+ import { TRPCError } from '@trpc/server';
6
+ import { and, eq, sql } from 'drizzle-orm';
15
7
  import { fileTypeFromBuffer } from 'file-type';
8
+ import { readChunk } from 'read-chunk';
9
+ import sharp from 'sharp';
10
+ import through2 from 'through2';
16
11
  import { getCMSConfig } from '../../core/config/index.js';
12
+ import { MysqlTableChecker } from '../../core/db/index.js';
13
+ import { FieldFactory, SectionFactory } from '../../core/factories/index.js';
14
+ import { SelectField } from '../../core/fields/index.js';
17
15
  import { resolveLocale } from '../../core/localization/index.js';
18
- import { getPluginRoutes } from '../../plugins/loader.js';
19
- import through2 from 'through2';
16
+ import { db } from '../../db/client.js';
17
+ import { AdminPrivilegesTable, AdminsTable, EditorPhotosTable } from '../../db/schema.js';
20
18
  import { recordLog } from '../../logging/index.js';
19
+ import { getPluginRoutes } from '../../plugins/loader.js';
21
20
  import getString from '../../translations/index.js';
22
- import { resolveMultilingualString } from '../../translations/language-utils.js';
23
- import { resolveLanguage } from '../../translations/language-utils.js';
21
+ import { resolveLanguage, resolveMultilingualString } from '../../translations/language-utils.js';
22
+ import { sanitizeFileName, sanitizeFolderOrFileName } from '../../utils/index.js';
24
23
  export const isAccessAllowed = async ({ sectionName, role, userId, }) => {
25
24
  /**
26
25
  * Check admin privileges
@@ -39,6 +38,35 @@ export const isAccessAllowed = async ({ sectionName, role, userId, }) => {
39
38
  }
40
39
  return true;
41
40
  };
41
+ async function deleteGalleryFiles({ uploadsFolder, sectionName, photos, }) {
42
+ for (const photo of photos) {
43
+ try {
44
+ await fs.promises.unlink(path.join(uploadsFolder, '.photos', sectionName, photo));
45
+ await fs.promises.unlink(path.join(uploadsFolder, '.thumbs', sectionName, photo));
46
+ }
47
+ catch (error) {
48
+ console.error('Error deleting gallery photo', error);
49
+ }
50
+ }
51
+ }
52
+ async function deleteLocalizedGalleryRows({ section, gallery, sectionItemId, locale, uploadsFolder, }) {
53
+ if (!gallery.localized)
54
+ return;
55
+ const { tableName, referenceIdentifierField, photoNameField } = gallery.db;
56
+ const columns = await MysqlTableChecker.getColumns(tableName);
57
+ if (!columns.includes(referenceIdentifierField) ||
58
+ !columns.includes(photoNameField) ||
59
+ !columns.includes('locale')) {
60
+ return;
61
+ }
62
+ const [rows] = await db.execute(sql `SELECT \`${sql.raw(photoNameField)}\` AS photo FROM \`${sql.raw(tableName)}\` WHERE \`${sql.raw(referenceIdentifierField)}\` = ${sectionItemId} AND \`locale\` = ${locale}`);
63
+ const photos = (rows ?? []).map((row) => row.photo).filter(Boolean);
64
+ await deleteGalleryFiles({ uploadsFolder, sectionName: section.name, photos });
65
+ await db.execute(sql `DELETE FROM \`${sql.raw(tableName)}\` WHERE \`${sql.raw(referenceIdentifierField)}\` = ${sectionItemId} AND \`locale\` = ${locale}`);
66
+ }
67
+ function sectionHasLocalizedContent(section) {
68
+ return section.hasLocalizedContent ?? section.hasLocalizedFields ?? false;
69
+ }
42
70
  export const getDocument = async (session, input) => {
43
71
  const { name, sectionName, fieldName } = input;
44
72
  // Sanitize the inputs
@@ -273,11 +301,11 @@ export const getAllPrivileges = async (session) => {
273
301
  // Now, let's add the rest of the privileges to the list
274
302
  sections.forEach((section, index) => {
275
303
  let title;
276
- if (typeof section.title === 'string') {
277
- title = resolveMultilingualString(section.title, language, cmsConfig.i18n.fallbackLanguage);
304
+ if (section.type === 'has_items' || section.type === 'category') {
305
+ title = resolveMultilingualString(section.title.section, language, cmsConfig.i18n.fallbackLanguage);
278
306
  }
279
307
  else {
280
- title = resolveMultilingualString(section.title.section, language, cmsConfig.i18n.fallbackLanguage);
308
+ title = resolveMultilingualString(section.title, language, cmsConfig.i18n.fallbackLanguage);
281
309
  }
282
310
  privilegesList.push({
283
311
  title,
@@ -380,7 +408,8 @@ export const createSimpleSectionPage = async (session, sectionName, locale) => {
380
408
  let localizationData = null;
381
409
  if (localeResult.localizationEnabled) {
382
410
  let existingTranslations = [];
383
- if (sectionInfo.hasLocalizedFields) {
411
+ const hasLocalizedContent = sectionHasLocalizedContent(sectionInfo);
412
+ if (hasLocalizedContent) {
384
413
  const localesTableName = sectionInfo.localesTableName;
385
414
  const localeColumns = await MysqlTableChecker.getColumns(localesTableName);
386
415
  const localeTableExists = localeColumns.length > 0;
@@ -428,6 +457,9 @@ export const createSimpleSectionPage = async (session, sectionName, locale) => {
428
457
  : [];
429
458
  field.setValue(tags.join(','));
430
459
  }
460
+ else if (field.type === 'date_range' && typeof f.setRangeValues === 'function') {
461
+ f.setRangeValues(localeRow ? (localeRow[f.startName] ?? null) : null, localeRow ? (localeRow[f.endName] ?? null) : null);
462
+ }
431
463
  else {
432
464
  // Simple field: override from locale row
433
465
  field.setValue(localeRow ? (localeRow[field.name] ?? null) : null);
@@ -436,11 +468,22 @@ export const createSimpleSectionPage = async (session, sectionName, locale) => {
436
468
  }
437
469
  }
438
470
  }
471
+ // Show the locale switcher when multiple locales are configured AND either:
472
+ // - the section has localized fields (production case), or
473
+ // - the app is in development mode (so devs can preview the switcher
474
+ // while wiring up localization on a section).
475
+ // The developer note is rendered in dev-mode only, when the switcher is
476
+ // visible but the section itself has no localized content yet.
477
+ const localeSwitcherEnabled = localeResult.availableLocales.length > 1 &&
478
+ (hasLocalizedContent === true || process.env.NODE_ENV === 'development');
479
+ const developerNoteEnabled = localeSwitcherEnabled && hasLocalizedContent === false;
439
480
  localizationData = {
440
481
  defaultLocale: localeResult.defaultLocale,
441
482
  currentLocale: localeResult.resolvedLocale ?? localeResult.defaultLocale,
442
483
  existingTranslations,
443
484
  locales: localeResult.availableLocales,
485
+ localeSwitcherEnabled,
486
+ developerNoteEnabled,
444
487
  };
445
488
  }
446
489
  return {
@@ -520,7 +563,7 @@ export const deleteSectionItem = async (session, sectionName, sectionItemId, rec
520
563
  * Use deleteLocaleTranslation per locale to ensure localized files are cleaned up from disk.
521
564
  */
522
565
  const cmsConfig = await getCMSConfig();
523
- if (cmsConfig.localization?.enabled && section.hasLocalizedFields) {
566
+ if (cmsConfig.localization?.enabled && sectionHasLocalizedContent(section)) {
524
567
  const localesTableName = section.localesTableName;
525
568
  const localeColumns = await MysqlTableChecker.getColumns(localesTableName);
526
569
  if (localeColumns.length > 0) {
@@ -723,7 +766,7 @@ export const deleteLocaleTranslation = async (session, sectionName, sectionItemI
723
766
  };
724
767
  }
725
768
  const cmsConfig = await getCMSConfig();
726
- if (!cmsConfig.localization?.enabled || !section.hasLocalizedFields) {
769
+ if (!cmsConfig.localization?.enabled || !sectionHasLocalizedContent(section)) {
727
770
  return {
728
771
  error: {
729
772
  message: getString('localizationNotEnabledForSection', session.user.language),
@@ -794,11 +837,21 @@ export const deleteLocaleTranslation = async (session, sectionName, sectionItemI
794
837
  }
795
838
  }
796
839
  }
797
- // Delete locale-scoped editor photos for localized rich_text fields
798
- const editorPhotos = await db
799
- .select()
800
- .from(EditorPhotosTable)
801
- .where(and(eq(EditorPhotosTable.section, sectionName), eq(EditorPhotosTable.itemId, sectionItemId.toString()), eq(EditorPhotosTable.locale, locale)));
840
+ const gallery = await section.getGallery();
841
+ if (gallery?.localized) {
842
+ await deleteLocalizedGalleryRows({
843
+ section,
844
+ gallery,
845
+ sectionItemId,
846
+ locale,
847
+ uploadsFolder: cmsConfig.media.upload.path,
848
+ });
849
+ }
850
+ // Delete locale-scoped editor photos for localized rich_text fields.
851
+ // Uses raw SQL because the `locale` column only exists on the DB table when
852
+ // localization is enabled; the Drizzle schema no longer declares it.
853
+ const [editorPhotoRows] = await db.execute(sql `SELECT \`photo\` as \`name\` FROM \`editor_photos\` WHERE \`section\` = ${sectionName} AND \`item_id\` = ${sectionItemId.toString()} AND \`locale\` = ${locale}`);
854
+ const editorPhotos = editorPhotoRows ?? [];
802
855
  if (editorPhotos.length > 0) {
803
856
  const uploadsFolder = cmsConfig.media.upload.path;
804
857
  for (const photo of editorPhotos) {
@@ -809,9 +862,7 @@ export const deleteLocaleTranslation = async (session, sectionName, sectionItemI
809
862
  console.error('Error deleting editor photo', error);
810
863
  }
811
864
  }
812
- await db
813
- .delete(EditorPhotosTable)
814
- .where(and(eq(EditorPhotosTable.section, sectionName), eq(EditorPhotosTable.itemId, sectionItemId.toString()), eq(EditorPhotosTable.locale, locale)));
865
+ await db.execute(sql `DELETE FROM \`editor_photos\` WHERE \`section\` = ${sectionName} AND \`item_id\` = ${sectionItemId.toString()} AND \`locale\` = ${locale}`);
815
866
  }
816
867
  // Delete locale-scoped junction table rows for localized select/tags fields
817
868
  const localizedJunctionFields = section.fieldConfigs.filter((f) => f.localized === true &&
@@ -942,13 +993,19 @@ export const createEditPage = async (session, sectionName, sectionItemId, locale
942
993
  if (columns.includes(photoNameField) &&
943
994
  columns.includes(referenceIdentifierField) &&
944
995
  columns.includes(metaField)) {
945
- const [items, fields] = await db.execute(sql `select * from \`${sql.raw(tableName)}\` where \`${sql.raw(referenceIdentifierField)}\` = ${sectionItemId}`);
996
+ const galleryIsLocalized = gallery.localized === true && localeResult.localizationEnabled;
997
+ const currentLocale = localeResult.resolvedLocale?.code;
998
+ const localeFilter = galleryIsLocalized && currentLocale && columns.includes('locale')
999
+ ? sql ` AND \`locale\` = ${currentLocale}`
1000
+ : sql ``;
1001
+ const [items] = await db.execute(sql `select * from \`${sql.raw(tableName)}\` where \`${sql.raw(referenceIdentifierField)}\` = ${sectionItemId}${localeFilter}`);
946
1002
  const galleryPhotos = items;
947
1003
  galleryPhotos?.map((item) => {
948
1004
  galleryItems.push({
949
1005
  referenceId: item[referenceIdentifierField],
950
1006
  photo: item[photoNameField],
951
1007
  meta: item[metaField],
1008
+ locale: item.locale,
952
1009
  });
953
1010
  });
954
1011
  }
@@ -967,7 +1024,8 @@ export const createEditPage = async (session, sectionName, sectionItemId, locale
967
1024
  let localizationData = null;
968
1025
  if (localeResult.localizationEnabled) {
969
1026
  let existingTranslations = [];
970
- if (sectionInfo.hasLocalizedFields) {
1027
+ const hasLocalizedContent = sectionHasLocalizedContent(sectionInfo);
1028
+ if (hasLocalizedContent) {
971
1029
  const localesTableName = sectionInfo.localesTableName;
972
1030
  const localeColumns = await MysqlTableChecker.getColumns(localesTableName);
973
1031
  const localeTableExists = localeColumns.length > 0;
@@ -1013,6 +1071,9 @@ export const createEditPage = async (session, sectionName, sectionItemId, locale
1013
1071
  : [];
1014
1072
  field.setValue(tags.join(','));
1015
1073
  }
1074
+ else if (field.type === 'date_range' && typeof f.setRangeValues === 'function') {
1075
+ f.setRangeValues(localeRow ? (localeRow[f.startName] ?? null) : null, localeRow ? (localeRow[f.endName] ?? null) : null);
1076
+ }
1016
1077
  else {
1017
1078
  // Simple field: override from locale row
1018
1079
  field.setValue(localeRow ? (localeRow[field.name] ?? null) : null);
@@ -1021,11 +1082,22 @@ export const createEditPage = async (session, sectionName, sectionItemId, locale
1021
1082
  }
1022
1083
  }
1023
1084
  }
1085
+ // Show the locale switcher when multiple locales are configured AND either:
1086
+ // - the section has localized fields (production case), or
1087
+ // - the app is in development mode (so devs can preview the switcher
1088
+ // while wiring up localization on a section).
1089
+ // The developer note is rendered in dev-mode only, when the switcher is
1090
+ // visible but the section itself has no localized content yet.
1091
+ const localeSwitcherEnabled = localeResult.availableLocales.length > 1 &&
1092
+ (hasLocalizedContent === true || process.env.NODE_ENV === 'development');
1093
+ const developerNoteEnabled = localeSwitcherEnabled && hasLocalizedContent === false;
1024
1094
  localizationData = {
1025
1095
  defaultLocale: localeResult.defaultLocale,
1026
1096
  currentLocale: localeResult.resolvedLocale ?? localeResult.defaultLocale,
1027
1097
  existingTranslations,
1028
1098
  locales: localeResult.availableLocales,
1099
+ localeSwitcherEnabled,
1100
+ developerNoteEnabled,
1029
1101
  };
1030
1102
  }
1031
1103
  return {