nextjs-cms 0.0.1 → 0.5.1

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 (302) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +289 -0
  3. package/dist/api/axios/axiosInstance.d.ts +2 -0
  4. package/dist/api/axios/axiosInstance.d.ts.map +1 -0
  5. package/dist/api/axios/axiosInstance.js +8 -0
  6. package/dist/api/index.d.ts +856 -0
  7. package/dist/api/index.d.ts.map +1 -0
  8. package/dist/api/index.js +12 -0
  9. package/dist/api/lib/serverActions.d.ts +240 -0
  10. package/dist/api/lib/serverActions.d.ts.map +1 -0
  11. package/dist/api/lib/serverActions.js +834 -0
  12. package/dist/api/root.d.ts +829 -0
  13. package/dist/api/root.d.ts.map +1 -0
  14. package/dist/api/root.js +30 -0
  15. package/dist/api/routers/accountSettings.d.ts +61 -0
  16. package/dist/api/routers/accountSettings.d.ts.map +1 -0
  17. package/dist/api/routers/accountSettings.js +108 -0
  18. package/dist/api/routers/admins.d.ts +106 -0
  19. package/dist/api/routers/admins.d.ts.map +1 -0
  20. package/dist/api/routers/admins.js +219 -0
  21. package/dist/api/routers/auth.d.ts +48 -0
  22. package/dist/api/routers/auth.d.ts.map +1 -0
  23. package/dist/api/routers/auth.js +25 -0
  24. package/dist/api/routers/categorySection.d.ts +104 -0
  25. package/dist/api/routers/categorySection.d.ts.map +1 -0
  26. package/dist/api/routers/categorySection.js +38 -0
  27. package/dist/api/routers/cmsSettings.d.ts +49 -0
  28. package/dist/api/routers/cmsSettings.d.ts.map +1 -0
  29. package/dist/api/routers/cmsSettings.js +51 -0
  30. package/dist/api/routers/cpanel.d.ts +84 -0
  31. package/dist/api/routers/cpanel.d.ts.map +1 -0
  32. package/dist/api/routers/cpanel.js +216 -0
  33. package/dist/api/routers/files.d.ts +48 -0
  34. package/dist/api/routers/files.d.ts.map +1 -0
  35. package/dist/api/routers/files.js +23 -0
  36. package/dist/api/routers/gallery.d.ts +36 -0
  37. package/dist/api/routers/gallery.d.ts.map +1 -0
  38. package/dist/api/routers/gallery.js +62 -0
  39. package/dist/api/routers/googleAnalytics.d.ts +31 -0
  40. package/dist/api/routers/googleAnalytics.d.ts.map +1 -0
  41. package/dist/api/routers/googleAnalytics.js +7 -0
  42. package/dist/api/routers/hasItemsSection.d.ts +140 -0
  43. package/dist/api/routers/hasItemsSection.d.ts.map +1 -0
  44. package/dist/api/routers/hasItemsSection.js +34 -0
  45. package/dist/api/routers/navigation.d.ts +52 -0
  46. package/dist/api/routers/navigation.d.ts.map +1 -0
  47. package/dist/api/routers/navigation.js +11 -0
  48. package/dist/api/routers/simpleSection.d.ts +58 -0
  49. package/dist/api/routers/simpleSection.d.ts.map +1 -0
  50. package/dist/api/routers/simpleSection.js +12 -0
  51. package/dist/api/trpc.d.ts +107 -0
  52. package/dist/api/trpc.d.ts.map +1 -0
  53. package/dist/api/trpc.js +72 -0
  54. package/dist/auth/axios/axiosInstance.d.ts +2 -0
  55. package/dist/auth/axios/axiosInstance.d.ts.map +1 -0
  56. package/dist/auth/axios/axiosInstance.js +8 -0
  57. package/dist/auth/csrf.d.ts +30 -0
  58. package/dist/auth/csrf.d.ts.map +1 -0
  59. package/dist/auth/csrf.js +76 -0
  60. package/dist/auth/hooks/index.d.ts +4 -0
  61. package/dist/auth/hooks/index.d.ts.map +1 -0
  62. package/dist/auth/hooks/index.js +3 -0
  63. package/dist/auth/hooks/useAxiosPrivate.d.ts +5 -0
  64. package/dist/auth/hooks/useAxiosPrivate.d.ts.map +1 -0
  65. package/dist/auth/hooks/useAxiosPrivate.js +74 -0
  66. package/dist/auth/hooks/useRefreshToken.d.ts +7 -0
  67. package/dist/auth/hooks/useRefreshToken.d.ts.map +1 -0
  68. package/dist/auth/hooks/useRefreshToken.js +79 -0
  69. package/dist/auth/index.d.ts +23 -0
  70. package/dist/auth/index.d.ts.map +1 -0
  71. package/dist/auth/index.js +44 -0
  72. package/dist/auth/jwt.d.ts +6 -0
  73. package/dist/auth/jwt.d.ts.map +1 -0
  74. package/dist/auth/jwt.js +25 -0
  75. package/dist/auth/lib/actions.d.ts +33 -0
  76. package/dist/auth/lib/actions.d.ts.map +1 -0
  77. package/dist/auth/lib/actions.js +209 -0
  78. package/dist/auth/lib/client.d.ts +4 -0
  79. package/dist/auth/lib/client.d.ts.map +1 -0
  80. package/dist/auth/lib/client.js +46 -0
  81. package/dist/auth/lib/index.d.ts +3 -0
  82. package/dist/auth/lib/index.d.ts.map +1 -0
  83. package/dist/auth/lib/index.js +2 -0
  84. package/dist/auth/react.d.ts +106 -0
  85. package/dist/auth/react.d.ts.map +1 -0
  86. package/dist/auth/react.js +347 -0
  87. package/dist/auth/trpc.d.ts +6 -0
  88. package/dist/auth/trpc.d.ts.map +1 -0
  89. package/dist/auth/trpc.js +81 -0
  90. package/dist/core/config/config-loader.d.ts +92 -0
  91. package/dist/core/config/config-loader.d.ts.map +1 -0
  92. package/dist/core/config/config-loader.js +230 -0
  93. package/dist/core/config/index.d.ts +3 -0
  94. package/dist/core/config/index.d.ts.map +1 -0
  95. package/dist/core/config/index.js +1 -0
  96. package/dist/core/config/loader.d.ts +2 -0
  97. package/dist/core/config/loader.d.ts.map +1 -0
  98. package/dist/core/config/loader.js +42 -0
  99. package/dist/core/db/index.d.ts +2 -0
  100. package/dist/core/db/index.d.ts.map +1 -0
  101. package/dist/core/db/index.js +1 -0
  102. package/dist/core/db/table-checker/DbTable.d.ts +6 -0
  103. package/dist/core/db/table-checker/DbTable.d.ts.map +1 -0
  104. package/dist/core/db/table-checker/DbTable.js +5 -0
  105. package/dist/core/db/table-checker/MysqlTable.d.ts +34 -0
  106. package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -0
  107. package/dist/core/db/table-checker/MysqlTable.js +102 -0
  108. package/dist/core/db/table-checker/index.d.ts +2 -0
  109. package/dist/core/db/table-checker/index.d.ts.map +1 -0
  110. package/dist/core/db/table-checker/index.js +1 -0
  111. package/dist/core/factories/FieldFactory.d.ts +124 -0
  112. package/dist/core/factories/FieldFactory.d.ts.map +1 -0
  113. package/dist/core/factories/FieldFactory.js +411 -0
  114. package/dist/core/factories/SectionFactory.d.ts +110 -0
  115. package/dist/core/factories/SectionFactory.d.ts.map +1 -0
  116. package/dist/core/factories/SectionFactory.js +415 -0
  117. package/dist/core/factories/index.d.ts +3 -0
  118. package/dist/core/factories/index.d.ts.map +1 -0
  119. package/dist/core/factories/index.js +2 -0
  120. package/dist/core/fields/checkbox.d.ts +63 -0
  121. package/dist/core/fields/checkbox.d.ts.map +1 -0
  122. package/dist/core/fields/checkbox.js +62 -0
  123. package/dist/core/fields/color.d.ts +84 -0
  124. package/dist/core/fields/color.d.ts.map +1 -0
  125. package/dist/core/fields/color.js +91 -0
  126. package/dist/core/fields/date.d.ts +100 -0
  127. package/dist/core/fields/date.d.ts.map +1 -0
  128. package/dist/core/fields/date.js +108 -0
  129. package/dist/core/fields/document.d.ts +180 -0
  130. package/dist/core/fields/document.d.ts.map +1 -0
  131. package/dist/core/fields/document.js +277 -0
  132. package/dist/core/fields/field-group.d.ts +18 -0
  133. package/dist/core/fields/field-group.d.ts.map +1 -0
  134. package/dist/core/fields/field-group.js +6 -0
  135. package/dist/core/fields/field.d.ts +126 -0
  136. package/dist/core/fields/field.d.ts.map +1 -0
  137. package/dist/core/fields/field.js +148 -0
  138. package/dist/core/fields/fileField.d.ts +15 -0
  139. package/dist/core/fields/fileField.d.ts.map +1 -0
  140. package/dist/core/fields/fileField.js +5 -0
  141. package/dist/core/fields/index.d.ts +65 -0
  142. package/dist/core/fields/index.d.ts.map +1 -0
  143. package/dist/core/fields/index.js +18 -0
  144. package/dist/core/fields/map.d.ts +167 -0
  145. package/dist/core/fields/map.d.ts.map +1 -0
  146. package/dist/core/fields/map.js +152 -0
  147. package/dist/core/fields/number.d.ts +186 -0
  148. package/dist/core/fields/number.d.ts.map +1 -0
  149. package/dist/core/fields/number.js +241 -0
  150. package/dist/core/fields/password.d.ts +109 -0
  151. package/dist/core/fields/password.d.ts.map +1 -0
  152. package/dist/core/fields/password.js +133 -0
  153. package/dist/core/fields/photo.d.ts +289 -0
  154. package/dist/core/fields/photo.d.ts.map +1 -0
  155. package/dist/core/fields/photo.js +410 -0
  156. package/dist/core/fields/richText.d.ts +295 -0
  157. package/dist/core/fields/richText.d.ts.map +1 -0
  158. package/dist/core/fields/richText.js +338 -0
  159. package/dist/core/fields/select.d.ts +366 -0
  160. package/dist/core/fields/select.d.ts.map +1 -0
  161. package/dist/core/fields/select.js +499 -0
  162. package/dist/core/fields/selectMultiple.d.ts +236 -0
  163. package/dist/core/fields/selectMultiple.d.ts.map +1 -0
  164. package/dist/core/fields/selectMultiple.js +417 -0
  165. package/dist/core/fields/tags.d.ts +131 -0
  166. package/dist/core/fields/tags.d.ts.map +1 -0
  167. package/dist/core/fields/tags.js +105 -0
  168. package/dist/core/fields/text.d.ts +136 -0
  169. package/dist/core/fields/text.d.ts.map +1 -0
  170. package/dist/core/fields/text.js +157 -0
  171. package/dist/core/fields/textArea.d.ts +107 -0
  172. package/dist/core/fields/textArea.d.ts.map +1 -0
  173. package/dist/core/fields/textArea.js +126 -0
  174. package/dist/core/fields/video.d.ts +148 -0
  175. package/dist/core/fields/video.d.ts.map +1 -0
  176. package/dist/core/fields/video.js +248 -0
  177. package/dist/core/helpers/entity.d.ts +8 -0
  178. package/dist/core/helpers/entity.d.ts.map +1 -0
  179. package/dist/core/helpers/entity.js +27 -0
  180. package/dist/core/helpers/index.d.ts +5 -0
  181. package/dist/core/helpers/index.d.ts.map +1 -0
  182. package/dist/core/helpers/index.js +3 -0
  183. package/dist/core/index.d.ts +8 -0
  184. package/dist/core/index.d.ts.map +1 -0
  185. package/dist/core/index.js +7 -0
  186. package/dist/core/sections/category.d.ts +283 -0
  187. package/dist/core/sections/category.d.ts.map +1 -0
  188. package/dist/core/sections/category.js +147 -0
  189. package/dist/core/sections/hasItems.d.ts +632 -0
  190. package/dist/core/sections/hasItems.d.ts.map +1 -0
  191. package/dist/core/sections/hasItems.js +144 -0
  192. package/dist/core/sections/index.d.ts +5 -0
  193. package/dist/core/sections/index.d.ts.map +1 -0
  194. package/dist/core/sections/index.js +4 -0
  195. package/dist/core/sections/section.d.ts +226 -0
  196. package/dist/core/sections/section.d.ts.map +1 -0
  197. package/dist/core/sections/section.js +341 -0
  198. package/dist/core/sections/simple.d.ts +99 -0
  199. package/dist/core/sections/simple.d.ts.map +1 -0
  200. package/dist/core/sections/simple.js +95 -0
  201. package/dist/core/security/dom.d.ts +11 -0
  202. package/dist/core/security/dom.d.ts.map +1 -0
  203. package/dist/core/security/dom.js +92 -0
  204. package/dist/core/submit/ItemEditSubmit.d.ts +76 -0
  205. package/dist/core/submit/ItemEditSubmit.d.ts.map +1 -0
  206. package/dist/core/submit/ItemEditSubmit.js +186 -0
  207. package/dist/core/submit/NewItemSubmit.d.ts +14 -0
  208. package/dist/core/submit/NewItemSubmit.d.ts.map +1 -0
  209. package/dist/core/submit/NewItemSubmit.js +93 -0
  210. package/dist/core/submit/SimpleSectionSubmit.d.ts +13 -0
  211. package/dist/core/submit/SimpleSectionSubmit.d.ts.map +1 -0
  212. package/dist/core/submit/SimpleSectionSubmit.js +93 -0
  213. package/dist/core/submit/index.d.ts +5 -0
  214. package/dist/core/submit/index.d.ts.map +1 -0
  215. package/dist/core/submit/index.js +4 -0
  216. package/dist/core/submit/submit.d.ts +116 -0
  217. package/dist/core/submit/submit.d.ts.map +1 -0
  218. package/dist/core/submit/submit.js +479 -0
  219. package/dist/core/types/index.d.ts +280 -0
  220. package/dist/core/types/index.d.ts.map +1 -0
  221. package/dist/core/types/index.js +1 -0
  222. package/dist/db/client.d.ts +9 -0
  223. package/dist/db/client.d.ts.map +1 -0
  224. package/dist/db/client.js +19 -0
  225. package/dist/db/config.d.ts +6 -0
  226. package/dist/db/config.d.ts.map +1 -0
  227. package/dist/db/config.js +22 -0
  228. package/dist/db/drizzle.config.d.ts +6 -0
  229. package/dist/db/drizzle.config.d.ts.map +1 -0
  230. package/dist/db/drizzle.config.js +18 -0
  231. package/dist/db/index.d.ts +3 -0
  232. package/dist/db/index.d.ts.map +1 -0
  233. package/dist/db/index.js +3 -0
  234. package/dist/db/schema.d.ts +639 -0
  235. package/dist/db/schema.d.ts.map +1 -0
  236. package/dist/db/schema.js +73 -0
  237. package/dist/index.d.ts +7 -1
  238. package/dist/index.d.ts.map +1 -1
  239. package/dist/index.js +7 -1
  240. package/dist/translations/dictionaries/ar.json +279 -0
  241. package/dist/translations/dictionaries/en.json +279 -0
  242. package/dist/translations/index.d.ts +3 -0
  243. package/dist/translations/index.d.ts.map +1 -0
  244. package/dist/translations/index.js +15 -0
  245. package/dist/utils/CpanelApi.d.ts +25 -0
  246. package/dist/utils/CpanelApi.d.ts.map +1 -0
  247. package/dist/utils/CpanelApi.js +64 -0
  248. package/dist/utils/constants.d.ts +14 -0
  249. package/dist/utils/constants.d.ts.map +1 -0
  250. package/dist/utils/constants.js +61 -0
  251. package/dist/utils/index.d.ts +5 -0
  252. package/dist/utils/index.d.ts.map +1 -0
  253. package/dist/utils/index.js +4 -0
  254. package/dist/utils/utils.d.ts +60 -0
  255. package/dist/utils/utils.d.ts.map +1 -0
  256. package/dist/utils/utils.js +132 -0
  257. package/dist/validators/checkbox.d.ts +4 -0
  258. package/dist/validators/checkbox.d.ts.map +1 -0
  259. package/dist/validators/checkbox.js +12 -0
  260. package/dist/validators/color.d.ts +4 -0
  261. package/dist/validators/color.d.ts.map +1 -0
  262. package/dist/validators/color.js +7 -0
  263. package/dist/validators/date.d.ts +4 -0
  264. package/dist/validators/date.d.ts.map +1 -0
  265. package/dist/validators/date.js +5 -0
  266. package/dist/validators/document.d.ts +4 -0
  267. package/dist/validators/document.d.ts.map +1 -0
  268. package/dist/validators/document.js +57 -0
  269. package/dist/validators/index.d.ts +15 -0
  270. package/dist/validators/index.d.ts.map +1 -0
  271. package/dist/validators/index.js +14 -0
  272. package/dist/validators/map.d.ts +4 -0
  273. package/dist/validators/map.d.ts.map +1 -0
  274. package/dist/validators/map.js +5 -0
  275. package/dist/validators/number.d.ts +4 -0
  276. package/dist/validators/number.d.ts.map +1 -0
  277. package/dist/validators/number.js +20 -0
  278. package/dist/validators/password.d.ts +4 -0
  279. package/dist/validators/password.d.ts.map +1 -0
  280. package/dist/validators/password.js +11 -0
  281. package/dist/validators/photo.d.ts +4 -0
  282. package/dist/validators/photo.d.ts.map +1 -0
  283. package/dist/validators/photo.js +100 -0
  284. package/dist/validators/richText.d.ts +4 -0
  285. package/dist/validators/richText.d.ts.map +1 -0
  286. package/dist/validators/richText.js +8 -0
  287. package/dist/validators/select-multiple.d.ts +10 -0
  288. package/dist/validators/select-multiple.d.ts.map +1 -0
  289. package/dist/validators/select-multiple.js +20 -0
  290. package/dist/validators/select.d.ts +4 -0
  291. package/dist/validators/select.d.ts.map +1 -0
  292. package/dist/validators/select.js +5 -0
  293. package/dist/validators/text.d.ts +4 -0
  294. package/dist/validators/text.d.ts.map +1 -0
  295. package/dist/validators/text.js +7 -0
  296. package/dist/validators/textarea.d.ts +4 -0
  297. package/dist/validators/textarea.d.ts.map +1 -0
  298. package/dist/validators/textarea.js +7 -0
  299. package/dist/validators/video.d.ts +4 -0
  300. package/dist/validators/video.d.ts.map +1 -0
  301. package/dist/validators/video.js +57 -0
  302. package/package.json +150 -6
@@ -0,0 +1,341 @@
1
+ import { entityKind } from '../helpers';
2
+ import { numberField } from '../fields';
3
+ import chalk from 'chalk';
4
+ import * as z from 'zod';
5
+ import { getCMSConfig } from '../config/config-loader';
6
+ const cmsConfig = getCMSConfig();
7
+ export const fieldConfigSchema = z.custom();
8
+ export const FieldGroupConfigSchema = z.custom();
9
+ const variantSchema = z.custom();
10
+ const hooksSchema = z.custom();
11
+ export const baseSectionOptionsSchema = z.strictObject({
12
+ name: z.string().describe('The name of the section'),
13
+ order: z.number(),
14
+ icon: z.string().optional(),
15
+ readonly: z.boolean().default(false).optional(),
16
+ gallery: z
17
+ .strictObject({
18
+ db: z.strictObject({
19
+ tableName: z.string(),
20
+ identifierField: z.string().optional(),
21
+ photoNameField: z.string().optional(),
22
+ metaField: z.string().optional(),
23
+ }),
24
+ watermark: z.boolean().optional(),
25
+ thumbnail: z
26
+ .strictObject({
27
+ width: z.number(),
28
+ height: z.number(),
29
+ crop: z.boolean(),
30
+ quality: z.number(),
31
+ })
32
+ .optional(),
33
+ })
34
+ .optional(),
35
+ db: z.strictObject({
36
+ table: z.string(),
37
+ identifier: fieldConfigSchema.optional(),
38
+ orderByField: fieldConfigSchema.optional(),
39
+ primaryKey: z.array(fieldConfigSchema).optional(),
40
+ foreignKeys: z
41
+ .array(z.strictObject({
42
+ columns: z.array(fieldConfigSchema),
43
+ foreignColumns: z.array(fieldConfigSchema),
44
+ name: z.string(),
45
+ }))
46
+ .optional(),
47
+ index: z
48
+ .array(z.strictObject({
49
+ columns: z.array(fieldConfigSchema),
50
+ name: z.string().optional(),
51
+ }))
52
+ .optional(),
53
+ unique: z
54
+ .array(z.strictObject({
55
+ columns: z.array(fieldConfigSchema),
56
+ name: z.string().optional(),
57
+ }))
58
+ .optional(),
59
+ fulltext: z
60
+ .array(z.strictObject({
61
+ columns: z.array(fieldConfigSchema),
62
+ name: z.string().optional(),
63
+ }))
64
+ .optional(),
65
+ }),
66
+ fields: z.array(fieldConfigSchema),
67
+ fieldGroups: z.array(FieldGroupConfigSchema).optional(),
68
+ variants: z.array(variantSchema).optional(),
69
+ hooks: hooksSchema.optional(),
70
+ });
71
+ /**
72
+ * This is the options schema for the helper functions that create section configs
73
+ * We omit the fields and fieldGroups properties from the baseSectionOptionsSchema
74
+ * and change the fields to be an array of field configs or field group configs
75
+ */
76
+ export const baseHelperFunctionOptionsSchema = z.strictObject({
77
+ ...baseSectionOptionsSchema.omit({ fields: true, fieldGroups: true }).shape,
78
+ fields: z
79
+ .array(fieldConfigSchema)
80
+ .min(1)
81
+ .describe('The fields of the section')
82
+ .or(z
83
+ .array(FieldGroupConfigSchema)
84
+ .min(1)
85
+ .describe('The field groups of the section')
86
+ .describe('The fields or field groups of the section')),
87
+ });
88
+ export function validateSectionConfig(config) {
89
+ const result = baseSectionOptionsSchema.safeParse(config);
90
+ if (!result.success) {
91
+ throw new Error(result.error.message);
92
+ }
93
+ }
94
+ export class Section {
95
+ static [entityKind] = 'Section';
96
+ name;
97
+ order;
98
+ icon;
99
+ readonly = false;
100
+ gallery;
101
+ _fields = undefined;
102
+ _fieldGroupConfigs = undefined;
103
+ _hasFieldGroups;
104
+ _fieldGroups = undefined;
105
+ _fieldConfigs;
106
+ /**
107
+ * A helper property to access the field configs.
108
+ * Sometimes it's handy to access the field configs without building the actual fields array.
109
+ */
110
+ get fieldConfigs() {
111
+ return this._fieldConfigs ?? [];
112
+ }
113
+ get fieldGroups() {
114
+ return this._fieldGroups ?? [];
115
+ }
116
+ get fields() {
117
+ if (this._fields === undefined) {
118
+ const errorMessage = `Fields are not yer built for section "${this.name}". Please run buildFields() before accessing the fields property.`;
119
+ const reportMessage = 'If this is a system bug, please open a bug report on GitHub.';
120
+ console.error('\n');
121
+ console.error(chalk.bold.red('[Section Error]', errorMessage));
122
+ console.error(chalk.bold.bgRed(reportMessage));
123
+ console.error('\n');
124
+ throw new Error(errorMessage);
125
+ }
126
+ return this._fields;
127
+ }
128
+ set fields(value) {
129
+ this._fields = value;
130
+ }
131
+ db;
132
+ variants;
133
+ hooks;
134
+ constructor(config) {
135
+ // this.id = config.id
136
+ this.name = config.name;
137
+ this.order = config.order;
138
+ this.icon = config.icon;
139
+ this.readonly = config.readonly ?? false;
140
+ /**
141
+ * Resolve gallery config
142
+ */
143
+ if (config.gallery) {
144
+ this.gallery = {
145
+ db: {
146
+ tableName: config.gallery.db.tableName,
147
+ referenceIdentifierField: config.gallery.db.identifierField ?? 'reference_id',
148
+ photoNameField: config.gallery.db.photoNameField ?? 'photo',
149
+ metaField: config.gallery.db.metaField ?? 'meta',
150
+ },
151
+ watermark: config.gallery.watermark ?? cmsConfig.files.images.watermark,
152
+ thumbnail: config.gallery.thumbnail ?? cmsConfig.files.images.thumbnail,
153
+ };
154
+ }
155
+ /**
156
+ * Check for db identifier field config
157
+ */
158
+ if (!config.db.identifier) {
159
+ // Create default id field config
160
+ const idFieldConfig = numberField({
161
+ name: 'id',
162
+ label: 'ID',
163
+ required: true,
164
+ hasAutoIncrement: true,
165
+ order: 0,
166
+ });
167
+ config.db.identifier = idFieldConfig;
168
+ config.fields.unshift(idFieldConfig);
169
+ }
170
+ else {
171
+ /**
172
+ * Make sure the identifier field config is a number or text field config
173
+ */
174
+ if (config.db.identifier.type !== 'number' && config.db.identifier.type !== 'text') {
175
+ const message = `[Section: ${this.name}]: DB identifier field config must be a number or text field. Got type: ${config.db.identifier.type}`;
176
+ console.error(chalk.red.bold(message));
177
+ console.error(chalk.yellow('Please make sure the identifier field config is a number or text field.'));
178
+ throw new Error(message);
179
+ }
180
+ }
181
+ /**
182
+ * Resolve db configuration fields
183
+ * If user doesn't specify primaryKey, default to identifier field
184
+ */
185
+ this.db = {
186
+ table: config.db.table,
187
+ identifier: config.db.identifier,
188
+ orderByField: config.db.orderByField,
189
+ primaryKey: config.db.primaryKey ?? [config.db.identifier],
190
+ foreignKeys: config.db.foreignKeys,
191
+ fulltext: config.db.fulltext,
192
+ index: config.db.index,
193
+ unique: config.db.unique ?? [],
194
+ };
195
+ /**
196
+ * Add the identifier field to the unique array if it's not already there
197
+ */
198
+ if (!this.db.unique.some((unique) => unique.columns.includes(this.db.identifier))) {
199
+ /**
200
+ * Add the identifier field as the first item in the unique array
201
+ */
202
+ this.db.unique.unshift({ columns: [this.db.identifier] });
203
+ }
204
+ this._fieldConfigs = config.fields;
205
+ this._fieldGroupConfigs = config.fieldGroups;
206
+ // Cache the hasFieldGroups check once during construction (immutable after this point)
207
+ this._hasFieldGroups = (this._fieldGroupConfigs?.length ?? 0) > 0;
208
+ this.variants = config.variants;
209
+ this.hooks = config.hooks;
210
+ }
211
+ /**
212
+ * Returns whether this section has field groups.
213
+ * Value is cached during construction for optimal performance.
214
+ */
215
+ get hasFieldGroups() {
216
+ return this._hasFieldGroups;
217
+ }
218
+ buildFieldGroups() {
219
+ const configs = this._fieldGroupConfigs;
220
+ if (!configs?.length)
221
+ return;
222
+ const fieldGroups = [];
223
+ const fields = [];
224
+ configs.forEach((groupConfig, index) => {
225
+ const fields = groupConfig.fields.map((fieldConfig) => this.resolveField(fieldConfig));
226
+ fieldGroups.push({
227
+ id: index + 1,
228
+ title: groupConfig.title,
229
+ order: groupConfig.order,
230
+ fields,
231
+ });
232
+ fields.push(...fields);
233
+ });
234
+ this._fieldGroups = fieldGroups;
235
+ this._fields = fields;
236
+ }
237
+ buildFields() {
238
+ if (this.hasFieldGroups) {
239
+ this.buildFieldGroups();
240
+ return;
241
+ }
242
+ if (this._fieldConfigs === undefined) {
243
+ throw new Error(`This section: (${this.name}) has no fields. Please set at least one field.`);
244
+ }
245
+ this._fields = this._fieldConfigs.map((input) => this.resolveField(input));
246
+ /**
247
+ * Create one group to hold all the fields
248
+ */
249
+ this._fieldGroups = [
250
+ {
251
+ id: 1,
252
+ title: '',
253
+ order: 1,
254
+ fields: this._fields,
255
+ },
256
+ ];
257
+ }
258
+ /**
259
+ * Helper function to resolve a field config to an instance
260
+ * by calling the build() method on the config
261
+ * @param config - The field config to resolve
262
+ * @returns The field instance
263
+ * @throws An error if the field config does not have a build() method
264
+ */
265
+ resolveField(config) {
266
+ // Config must have a build() method
267
+ if (typeof config.build === 'function') {
268
+ return config.build();
269
+ }
270
+ throw new Error(`[Section: ${this.name}]: Field "${config.name}" config must have a build() method. Use helper functions like textField(), numberField(), etc. to create field configs.`);
271
+ }
272
+ }
273
+ /**
274
+ * Helper function to ensure a section config has a db identifier field
275
+ * If db.identifier is missing, creates a default 'id' number field config
276
+ * and prepends it to fields and sets it as db.identifier
277
+ *
278
+ * @param section - Section config that may or may not have db.identifier
279
+ * @returns Section config with db.identifier guaranteed to exist
280
+ */
281
+ export function ensureSectionDbIdentifier(section) {
282
+ // If identifier already exists, return as-is
283
+ if (section.db.identifier) {
284
+ return section;
285
+ }
286
+ // Create default id field config
287
+ const idFieldConfig = numberField({
288
+ name: 'id',
289
+ label: 'ID',
290
+ required: true,
291
+ hasAutoIncrement: true,
292
+ order: 0,
293
+ });
294
+ // Return modified config with identifier
295
+ return {
296
+ ...section,
297
+ fields: [idFieldConfig, ...section.fields],
298
+ db: {
299
+ ...section.db,
300
+ identifier: idFieldConfig,
301
+ },
302
+ };
303
+ }
304
+ /**
305
+ * Helper function to normalize gallery config with default values
306
+ * Sets defaults for identifierField, photoNameField, and metaField if not provided
307
+ *
308
+ * @param section - Section config that may or may not have gallery config
309
+ * @returns Section config with normalized gallery config
310
+ */
311
+ export function ensureSectionGallery(section) {
312
+ // If no gallery config, return as-is
313
+ if (!section.gallery) {
314
+ return section;
315
+ }
316
+ // Return config with normalized gallery
317
+ return {
318
+ ...section,
319
+ gallery: {
320
+ ...section.gallery,
321
+ db: {
322
+ tableName: section.gallery.db.tableName,
323
+ identifierField: section.gallery.db.identifierField ?? 'reference_id',
324
+ photoNameField: section.gallery.db.photoNameField ?? 'photo',
325
+ metaField: section.gallery.db.metaField ?? 'meta',
326
+ },
327
+ },
328
+ };
329
+ }
330
+ export function resolveFieldsAndFieldGroups(config) {
331
+ if (config.fields.length) {
332
+ return {
333
+ fields: config.fields,
334
+ fieldGroups: [],
335
+ };
336
+ }
337
+ return {
338
+ fields: config.fieldGroups.flatMap((group) => group.fields),
339
+ fieldGroups: config.fieldGroups,
340
+ };
341
+ }
@@ -0,0 +1,99 @@
1
+ import { entityKind } from '../helpers';
2
+ import type { BaseSectionOptions } from './section';
3
+ import { Section } from './section';
4
+ import { FieldGroupConfig, type FieldConfig } from '../fields';
5
+ import * as z from 'zod';
6
+ declare const configSchema: z.ZodObject<{
7
+ title: z.ZodString;
8
+ db: z.ZodObject<{
9
+ table: z.ZodString;
10
+ }, z.core.$strict>;
11
+ }, z.core.$strict>;
12
+ type Config = z.infer<typeof configSchema>;
13
+ export declare class SimpleSection extends Section<Config> {
14
+ static readonly [entityKind] = "SimpleSection";
15
+ readonly type = "simple";
16
+ title: string;
17
+ constructor(config: BaseSectionOptions<Config>);
18
+ }
19
+ declare const optionsSchema: z.ZodObject<{
20
+ title: z.ZodString;
21
+ db: z.ZodObject<{
22
+ table: z.ZodString;
23
+ }, z.core.$strict>;
24
+ fields: z.ZodUnion<[z.ZodArray<z.ZodCustom<FieldConfig, FieldConfig>>, z.ZodArray<z.ZodCustom<FieldGroupConfig, FieldGroupConfig>>]>;
25
+ variants: z.ZodOptional<z.ZodArray<z.ZodCustom<import("../types").Variant, import("../types").Variant>>>;
26
+ name: z.ZodString;
27
+ order: z.ZodNumber;
28
+ readonly: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
29
+ icon: z.ZodOptional<z.ZodString>;
30
+ gallery: z.ZodOptional<z.ZodObject<{
31
+ db: z.ZodObject<{
32
+ tableName: z.ZodString;
33
+ identifierField: z.ZodOptional<z.ZodString>;
34
+ photoNameField: z.ZodOptional<z.ZodString>;
35
+ metaField: z.ZodOptional<z.ZodString>;
36
+ }, z.core.$strict>;
37
+ watermark: z.ZodOptional<z.ZodBoolean>;
38
+ thumbnail: z.ZodOptional<z.ZodObject<{
39
+ width: z.ZodNumber;
40
+ height: z.ZodNumber;
41
+ crop: z.ZodBoolean;
42
+ quality: z.ZodNumber;
43
+ }, z.core.$strict>>;
44
+ }, z.core.$strict>>;
45
+ hooks: z.ZodOptional<z.ZodCustom<import("./section").Hooks, import("./section").Hooks>>;
46
+ }, z.core.$strict>;
47
+ declare const simpleSectionConfigSchema: z.ZodObject<{
48
+ type: z.ZodLiteral<"simple">;
49
+ fields: z.ZodArray<z.ZodCustom<FieldConfig, FieldConfig>>;
50
+ build: z.ZodFunction<z.core.$ZodFunctionArgs, z.ZodCustom<SimpleSection, SimpleSection>>;
51
+ fieldGroups: z.ZodOptional<z.ZodArray<z.ZodCustom<FieldGroupConfig, FieldGroupConfig>>>;
52
+ title: z.ZodString;
53
+ db: z.ZodObject<{
54
+ table: z.ZodString;
55
+ }, z.core.$strict>;
56
+ variants: z.ZodOptional<z.ZodArray<z.ZodCustom<import("../types").Variant, import("../types").Variant>>>;
57
+ name: z.ZodString;
58
+ order: z.ZodNumber;
59
+ readonly: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
60
+ icon: z.ZodOptional<z.ZodString>;
61
+ gallery: z.ZodOptional<z.ZodObject<{
62
+ db: z.ZodObject<{
63
+ tableName: z.ZodString;
64
+ identifierField: z.ZodOptional<z.ZodString>;
65
+ photoNameField: z.ZodOptional<z.ZodString>;
66
+ metaField: z.ZodOptional<z.ZodString>;
67
+ }, z.core.$strict>;
68
+ watermark: z.ZodOptional<z.ZodBoolean>;
69
+ thumbnail: z.ZodOptional<z.ZodObject<{
70
+ width: z.ZodNumber;
71
+ height: z.ZodNumber;
72
+ crop: z.ZodBoolean;
73
+ quality: z.ZodNumber;
74
+ }, z.core.$strict>>;
75
+ }, z.core.$strict>>;
76
+ hooks: z.ZodOptional<z.ZodCustom<import("./section").Hooks, import("./section").Hooks>>;
77
+ }, z.core.$strict>;
78
+ export type SimpleSectionOptions = z.infer<typeof optionsSchema>;
79
+ /**
80
+ * Simple section configuration
81
+ * This is the output of the simpleSection() helper function, it that can be serialized and used anywhere
82
+ * The build() method allows creating a SimpleSection instance when needed
83
+ */
84
+ export type SimpleSectionConfig = z.infer<typeof simpleSectionConfigSchema>;
85
+ /**
86
+ * Helper function to create a simple section configuration
87
+ * Returns a config object with a build() method that can be serialized and used anywhere
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const sectionConfig = simpleSection({ name: 'settings', ... })
92
+ * const sectionInstance = sectionConfig.build()
93
+ * ```
94
+ *
95
+ * @param section
96
+ */
97
+ export declare function simpleSection(section: SimpleSectionOptions): SimpleSectionConfig;
98
+ export {};
99
+ //# sourceMappingURL=simple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple.d.ts","sourceRoot":"","sources":["../../../src/core/sections/simple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EAAmC,OAAO,EAAE,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAC9D,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,YAAY;;;;;kBAiBhB,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,aAAc,SAAQ,OAAO,CAAC,MAAM,CAAC;IAC9C,gBAAyB,CAAC,UAAU,CAAC,mBAAkB;IACvD,SAAkB,IAAI,YAAW;IACxB,KAAK,EAAE,MAAM,CAAA;gBAEV,MAAM,EAAE,kBAAkB,CAAC,MAAM,CAAC;CAIjD;AAED,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAGjB,CAAA;AAOF,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAK7B,CAAA;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEhE;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CA6ChF"}
@@ -0,0 +1,95 @@
1
+ import { entityKind } from '../helpers';
2
+ import { baseHelperFunctionOptionsSchema, Section } from './section';
3
+ import * as z from 'zod';
4
+ import { FieldGroupConfigSchema, fieldConfigSchema } from './section';
5
+ const configSchema = z.strictObject({
6
+ title: z.string('Section title is required').describe('The title of the section'),
7
+ db: z
8
+ .strictObject({
9
+ table: z
10
+ .string('Table name is required')
11
+ .describe('The name of the database table to use for this section'),
12
+ }, {
13
+ error: 'DB configuration is required',
14
+ })
15
+ .describe('In simple sections, the identifier field is a number field with the name `id`, and always has the value of 1 in the database table')
16
+ .describe('The database configuration for this section'),
17
+ });
18
+ export class SimpleSection extends Section {
19
+ static [entityKind] = 'SimpleSection';
20
+ type = 'simple';
21
+ title;
22
+ constructor(config) {
23
+ super(config);
24
+ this.title = config.title;
25
+ }
26
+ }
27
+ const optionsSchema = z.strictObject({
28
+ ...baseHelperFunctionOptionsSchema.shape,
29
+ ...configSchema.shape,
30
+ });
31
+ const compiledOptionsSchema = z.strictObject({
32
+ ...optionsSchema.shape,
33
+ fieldGroups: z.array(FieldGroupConfigSchema).optional().describe('The field groups of the section if provided'),
34
+ });
35
+ const simpleSectionConfigSchema = z.strictObject({
36
+ ...compiledOptionsSchema.shape,
37
+ type: z.literal('simple').describe('The type of the section'),
38
+ fields: z.array(fieldConfigSchema).describe('The fields of the section'),
39
+ build: z.function().output(z.instanceof(SimpleSection)).describe('Build a SimpleSection instance from this config'),
40
+ });
41
+ /**
42
+ * Helper function to create a simple section configuration
43
+ * Returns a config object with a build() method that can be serialized and used anywhere
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const sectionConfig = simpleSection({ name: 'settings', ... })
48
+ * const sectionInstance = sectionConfig.build()
49
+ * ```
50
+ *
51
+ * @param section
52
+ */
53
+ export function simpleSection(section) {
54
+ /**
55
+ * Validate the section config
56
+ */
57
+ const result = optionsSchema.safeParse(section);
58
+ if (!result.success) {
59
+ throw new Error(`[Section: ${section.name}]: ${z.prettifyError(result.error)}`);
60
+ }
61
+ /**
62
+ * Resolve fields and fieldGroups
63
+ */
64
+ let fields = [];
65
+ let fieldGroups = [];
66
+ if (section.fields && section.fields.length > 0) {
67
+ const firstInput = section.fields[0];
68
+ /**
69
+ * Check if the first item is a field group.
70
+ * We don't need to check every item,
71
+ * because zod already validated the fields array.
72
+ */
73
+ if (firstInput && 'fields' in firstInput) {
74
+ fieldGroups = section.fields;
75
+ fields = fieldGroups.flatMap((group) => group.fields);
76
+ }
77
+ else {
78
+ fields = section.fields;
79
+ }
80
+ }
81
+ const config = {
82
+ ...section,
83
+ fields,
84
+ fieldGroups: fieldGroups.length > 0 ? fieldGroups : undefined,
85
+ type: 'simple',
86
+ build() {
87
+ return new SimpleSection({
88
+ ...section,
89
+ fields,
90
+ fieldGroups: fieldGroups.length > 0 ? fieldGroups : undefined,
91
+ });
92
+ },
93
+ };
94
+ return config;
95
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Escape a string so it can be safely injected into an HTML text context.
3
+ * Returns `undefined` when the input is `undefined` or `null` to preserve caller intent.
4
+ */
5
+ export declare function escapeHTML(value: string | undefined | null): string | undefined;
6
+ /**
7
+ * Sanitize rich-text/HTML content using DOMPurify with a restrictive allow-list.
8
+ * Always returns a string (empty string when value is undefined or null).
9
+ */
10
+ export declare function sanitizeRichText(value: string | undefined | null): string;
11
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../src/core/security/dom.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAU/E;AA+DD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAMzE"}
@@ -0,0 +1,92 @@
1
+ import DOMPurify from 'isomorphic-dompurify';
2
+ const HTML_ESCAPE_LOOKUP = {
3
+ '&': '&amp;',
4
+ '<': '&lt;',
5
+ '>': '&gt;',
6
+ '"': '&quot;',
7
+ "'": '&#39;',
8
+ '/': '&#x2F;',
9
+ '`': '&#x60;',
10
+ '/\/': '&#x2F;',
11
+ };
12
+ const HTML_ESCAPE_REGEX = /[&<>"'\/`\/\/]/g;
13
+ /**
14
+ * Escape a string so it can be safely injected into an HTML text context.
15
+ * Returns `undefined` when the input is `undefined` or `null` to preserve caller intent.
16
+ */
17
+ export function escapeHTML(value) {
18
+ if (value === undefined || value === null) {
19
+ return value === null ? '' : undefined;
20
+ }
21
+ if (!HTML_ESCAPE_REGEX.test(value)) {
22
+ return value;
23
+ }
24
+ return value.replace(HTML_ESCAPE_REGEX, (char) => HTML_ESCAPE_LOOKUP[char]);
25
+ }
26
+ const RICH_TEXT_ALLOWED_TAGS = [
27
+ 'a',
28
+ 'abbr',
29
+ 'b',
30
+ 'blockquote',
31
+ 'br',
32
+ 'caption',
33
+ 'code',
34
+ 'div',
35
+ 'em',
36
+ 'strong',
37
+ 'i',
38
+ 'img',
39
+ 'figure',
40
+ 'figcaption',
41
+ 'hr',
42
+ 'li',
43
+ 'ol',
44
+ 'p',
45
+ 'pre',
46
+ 'span',
47
+ 'sub',
48
+ 'sup',
49
+ 'table',
50
+ 'tbody',
51
+ 'td',
52
+ 'tfoot',
53
+ 'th',
54
+ 'thead',
55
+ 'tr',
56
+ 'u',
57
+ 'ul',
58
+ ];
59
+ const RICH_TEXT_ALLOWED_ATTR = [
60
+ 'align',
61
+ 'alt',
62
+ 'class',
63
+ 'data*',
64
+ 'height',
65
+ 'href',
66
+ 'id',
67
+ 'name',
68
+ 'rel',
69
+ 'src',
70
+ 'style',
71
+ 'target',
72
+ 'title',
73
+ 'width',
74
+ ];
75
+ const RICH_TEXT_URI_REGEXP = /^(?:(?:https?|mailto|tel|ftp|file):|data:image\/[a-z0-9.+-]+;base64,)/i;
76
+ const RICH_TEXT_SANITIZE_CONFIG = {
77
+ ALLOWED_TAGS: [...RICH_TEXT_ALLOWED_TAGS],
78
+ ALLOWED_ATTR: [...RICH_TEXT_ALLOWED_ATTR],
79
+ ALLOW_DATA_ATTR: true,
80
+ ALLOWED_URI_REGEXP: RICH_TEXT_URI_REGEXP,
81
+ FORBID_TAGS: ['style', 'script'],
82
+ };
83
+ /**
84
+ * Sanitize rich-text/HTML content using DOMPurify with a restrictive allow-list.
85
+ * Always returns a string (empty string when value is undefined or null).
86
+ */
87
+ export function sanitizeRichText(value) {
88
+ if (value === undefined || value === null || value.trim().length === 0) {
89
+ return '';
90
+ }
91
+ return DOMPurify.sanitize(value, RICH_TEXT_SANITIZE_CONFIG);
92
+ }