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,295 @@
1
+ import type { BaseFieldConfig } from './field';
2
+ import { Field } from './field';
3
+ import { entityKind } from '../helpers';
4
+ import * as z from 'zod';
5
+ declare const allowImageUploadsSchema: z.ZodObject<{
6
+ /**
7
+ * The public URL prefix for inline photos.
8
+ * This url should be handled by the website app, not the NextJS-CMS app
9
+ * This is the URL that will be used to access the photos publicly on the website
10
+ * The name of the photo will be appended to this URL
11
+ */
12
+ publicURLPrefix: z.ZodURL;
13
+ size: z.ZodOptional<z.ZodObject<{
14
+ width: z.ZodNumber;
15
+ height: z.ZodNumber;
16
+ crop: z.ZodDefault<z.ZodBoolean>;
17
+ }, z.core.$strict>>;
18
+ maxFileSize: z.ZodOptional<z.ZodObject<{
19
+ size: z.ZodNumber;
20
+ unit: z.ZodEnum<{
21
+ kb: "kb";
22
+ mb: "mb";
23
+ }>;
24
+ }, z.core.$strict>>;
25
+ handleMethod: z.ZodOptional<z.ZodEnum<{
26
+ base64: "base64";
27
+ tempSave: "tempSave";
28
+ }>>;
29
+ /**
30
+ * Omit the extension of the image when saving it to disk
31
+ */
32
+ omitExtension: z.ZodOptional<z.ZodBoolean>;
33
+ format: z.ZodOptional<z.ZodEnum<{
34
+ webp: "webp";
35
+ jpg: "jpg";
36
+ jpeg: "jpeg";
37
+ png: "png";
38
+ }>>;
39
+ }, z.core.$strict>;
40
+ declare const configSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
41
+ placeholder: z.ZodOptional<z.ZodString>;
42
+ minLength: z.ZodOptional<z.ZodNumber>;
43
+ maxLength: z.ZodOptional<z.ZodNumber>;
44
+ sanitize: z.ZodOptional<z.ZodBoolean>;
45
+ allowMedia: z.ZodLiteral<true>;
46
+ allowImageUploads: z.ZodOptional<z.ZodObject<{
47
+ /**
48
+ * The public URL prefix for inline photos.
49
+ * This url should be handled by the website app, not the NextJS-CMS app
50
+ * This is the URL that will be used to access the photos publicly on the website
51
+ * The name of the photo will be appended to this URL
52
+ */
53
+ publicURLPrefix: z.ZodURL;
54
+ size: z.ZodOptional<z.ZodObject<{
55
+ width: z.ZodNumber;
56
+ height: z.ZodNumber;
57
+ crop: z.ZodDefault<z.ZodBoolean>;
58
+ }, z.core.$strict>>;
59
+ maxFileSize: z.ZodOptional<z.ZodObject<{
60
+ size: z.ZodNumber;
61
+ unit: z.ZodEnum<{
62
+ kb: "kb";
63
+ mb: "mb";
64
+ }>;
65
+ }, z.core.$strict>>;
66
+ handleMethod: z.ZodOptional<z.ZodEnum<{
67
+ base64: "base64";
68
+ tempSave: "tempSave";
69
+ }>>;
70
+ /**
71
+ * Omit the extension of the image when saving it to disk
72
+ */
73
+ omitExtension: z.ZodOptional<z.ZodBoolean>;
74
+ format: z.ZodOptional<z.ZodEnum<{
75
+ webp: "webp";
76
+ jpg: "jpg";
77
+ jpeg: "jpeg";
78
+ png: "png";
79
+ }>>;
80
+ }, z.core.$strict>>;
81
+ }, z.core.$strict>, z.ZodObject<{
82
+ placeholder: z.ZodOptional<z.ZodString>;
83
+ minLength: z.ZodOptional<z.ZodNumber>;
84
+ maxLength: z.ZodOptional<z.ZodNumber>;
85
+ sanitize: z.ZodOptional<z.ZodBoolean>;
86
+ allowMedia: z.ZodOptional<z.ZodLiteral<false>>;
87
+ }, z.core.$strict>], "allowMedia">;
88
+ type Config = z.infer<typeof configSchema>;
89
+ export declare class RichTextField extends Field<'rich_text', Config> {
90
+ static readonly [entityKind]: string;
91
+ readonly maxLength: number | undefined;
92
+ readonly minLength: number | undefined;
93
+ readonly placeholder: string | undefined;
94
+ readonly allowMedia: boolean | undefined;
95
+ readonly allowImageUploads: z.infer<typeof allowImageUploadsSchema> | false;
96
+ readonly sanitize: boolean;
97
+ private _inlinePhotos;
98
+ readonly uploadsFolder: string;
99
+ constructor(config: BaseFieldConfig<Config>);
100
+ /**
101
+ * Get the value of the field
102
+ */
103
+ getValue(): string;
104
+ exportForClient(): {
105
+ maxLength: number | undefined;
106
+ minLength: number | undefined;
107
+ placeholder: string | undefined;
108
+ allowMedia: boolean | undefined;
109
+ allowImageUploads: false | {
110
+ publicURLPrefix: string;
111
+ size?: {
112
+ width: number;
113
+ height: number;
114
+ crop: boolean;
115
+ } | undefined;
116
+ maxFileSize?: {
117
+ size: number;
118
+ unit: "kb" | "mb";
119
+ } | undefined;
120
+ handleMethod?: "base64" | "tempSave" | undefined;
121
+ omitExtension?: boolean | undefined;
122
+ format?: "webp" | "jpg" | "jpeg" | "png" | undefined;
123
+ };
124
+ sanitize: boolean;
125
+ type: "rich_text";
126
+ name: string;
127
+ label: string;
128
+ required: boolean;
129
+ conditionalFields: import("../types").ConditionalField[];
130
+ readonly: boolean;
131
+ defaultValue: any;
132
+ value: any;
133
+ };
134
+ /**
135
+ * Sanitize the value
136
+ */
137
+ private sanitizeValue;
138
+ checkRequired(): void;
139
+ /**
140
+ * Extract inline images from the value
141
+ */
142
+ extractInlineImages(): void;
143
+ writeInlineImages(sectionName: string, itemId: string): Promise<void>;
144
+ /**
145
+ * Prepare the field for submission
146
+ */
147
+ prepareForSubmission(): Promise<void>;
148
+ postSubmit({ sectionName, itemId }: {
149
+ sectionName: string;
150
+ itemId: string;
151
+ }): Promise<void>;
152
+ private checkPreviousInlineImages;
153
+ }
154
+ export type RichTextFieldClientConfig = ReturnType<RichTextField['exportForClient']>;
155
+ declare const optionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
156
+ placeholder: z.ZodOptional<z.ZodString>;
157
+ minLength: z.ZodOptional<z.ZodNumber>;
158
+ maxLength: z.ZodOptional<z.ZodNumber>;
159
+ sanitize: z.ZodOptional<z.ZodBoolean>;
160
+ allowMedia: z.ZodLiteral<true>;
161
+ allowImageUploads: z.ZodOptional<z.ZodObject<{
162
+ /**
163
+ * The public URL prefix for inline photos.
164
+ * This url should be handled by the website app, not the NextJS-CMS app
165
+ * This is the URL that will be used to access the photos publicly on the website
166
+ * The name of the photo will be appended to this URL
167
+ */
168
+ publicURLPrefix: z.ZodURL;
169
+ size: z.ZodOptional<z.ZodObject<{
170
+ width: z.ZodNumber;
171
+ height: z.ZodNumber;
172
+ crop: z.ZodDefault<z.ZodBoolean>;
173
+ }, z.core.$strict>>;
174
+ maxFileSize: z.ZodOptional<z.ZodObject<{
175
+ size: z.ZodNumber;
176
+ unit: z.ZodEnum<{
177
+ kb: "kb";
178
+ mb: "mb";
179
+ }>;
180
+ }, z.core.$strict>>;
181
+ handleMethod: z.ZodOptional<z.ZodEnum<{
182
+ base64: "base64";
183
+ tempSave: "tempSave";
184
+ }>>;
185
+ /**
186
+ * Omit the extension of the image when saving it to disk
187
+ */
188
+ omitExtension: z.ZodOptional<z.ZodBoolean>;
189
+ format: z.ZodOptional<z.ZodEnum<{
190
+ webp: "webp";
191
+ jpg: "jpg";
192
+ jpeg: "jpeg";
193
+ png: "png";
194
+ }>>;
195
+ }, z.core.$strict>>;
196
+ name: z.ZodString;
197
+ label: z.ZodOptional<z.ZodString>;
198
+ required: z.ZodOptional<z.ZodBoolean>;
199
+ defaultValue: z.ZodOptional<z.ZodAny>;
200
+ order: z.ZodOptional<z.ZodNumber>;
201
+ conditionalRules: z.ZodOptional<z.ZodArray<z.ZodCustom<import("../types").ConditionalRule, import("../types").ConditionalRule>>>;
202
+ adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
203
+ }, z.core.$strict>, z.ZodObject<{
204
+ placeholder: z.ZodOptional<z.ZodString>;
205
+ minLength: z.ZodOptional<z.ZodNumber>;
206
+ maxLength: z.ZodOptional<z.ZodNumber>;
207
+ sanitize: z.ZodOptional<z.ZodBoolean>;
208
+ allowMedia: z.ZodOptional<z.ZodLiteral<false>>;
209
+ name: z.ZodString;
210
+ label: z.ZodOptional<z.ZodString>;
211
+ required: z.ZodOptional<z.ZodBoolean>;
212
+ defaultValue: z.ZodOptional<z.ZodAny>;
213
+ order: z.ZodOptional<z.ZodNumber>;
214
+ conditionalRules: z.ZodOptional<z.ZodArray<z.ZodCustom<import("../types").ConditionalRule, import("../types").ConditionalRule>>>;
215
+ adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
216
+ }, z.core.$strict>], "allowMedia">;
217
+ declare const richTextFieldConfigSchema: z.ZodIntersection<z.ZodDiscriminatedUnion<[z.ZodObject<{
218
+ placeholder: z.ZodOptional<z.ZodString>;
219
+ minLength: z.ZodOptional<z.ZodNumber>;
220
+ maxLength: z.ZodOptional<z.ZodNumber>;
221
+ sanitize: z.ZodOptional<z.ZodBoolean>;
222
+ allowMedia: z.ZodLiteral<true>;
223
+ allowImageUploads: z.ZodOptional<z.ZodObject<{
224
+ /**
225
+ * The public URL prefix for inline photos.
226
+ * This url should be handled by the website app, not the NextJS-CMS app
227
+ * This is the URL that will be used to access the photos publicly on the website
228
+ * The name of the photo will be appended to this URL
229
+ */
230
+ publicURLPrefix: z.ZodURL;
231
+ size: z.ZodOptional<z.ZodObject<{
232
+ width: z.ZodNumber;
233
+ height: z.ZodNumber;
234
+ crop: z.ZodDefault<z.ZodBoolean>;
235
+ }, z.core.$strict>>;
236
+ maxFileSize: z.ZodOptional<z.ZodObject<{
237
+ size: z.ZodNumber;
238
+ unit: z.ZodEnum<{
239
+ kb: "kb";
240
+ mb: "mb";
241
+ }>;
242
+ }, z.core.$strict>>;
243
+ handleMethod: z.ZodOptional<z.ZodEnum<{
244
+ base64: "base64";
245
+ tempSave: "tempSave";
246
+ }>>;
247
+ /**
248
+ * Omit the extension of the image when saving it to disk
249
+ */
250
+ omitExtension: z.ZodOptional<z.ZodBoolean>;
251
+ format: z.ZodOptional<z.ZodEnum<{
252
+ webp: "webp";
253
+ jpg: "jpg";
254
+ jpeg: "jpeg";
255
+ png: "png";
256
+ }>>;
257
+ }, z.core.$strict>>;
258
+ name: z.ZodString;
259
+ label: z.ZodOptional<z.ZodString>;
260
+ required: z.ZodOptional<z.ZodBoolean>;
261
+ defaultValue: z.ZodOptional<z.ZodAny>;
262
+ order: z.ZodOptional<z.ZodNumber>;
263
+ conditionalRules: z.ZodOptional<z.ZodArray<z.ZodCustom<import("../types").ConditionalRule, import("../types").ConditionalRule>>>;
264
+ adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
265
+ }, z.core.$strict>, z.ZodObject<{
266
+ placeholder: z.ZodOptional<z.ZodString>;
267
+ minLength: z.ZodOptional<z.ZodNumber>;
268
+ maxLength: z.ZodOptional<z.ZodNumber>;
269
+ sanitize: z.ZodOptional<z.ZodBoolean>;
270
+ allowMedia: z.ZodOptional<z.ZodLiteral<false>>;
271
+ name: z.ZodString;
272
+ label: z.ZodOptional<z.ZodString>;
273
+ required: z.ZodOptional<z.ZodBoolean>;
274
+ defaultValue: z.ZodOptional<z.ZodAny>;
275
+ order: z.ZodOptional<z.ZodNumber>;
276
+ conditionalRules: z.ZodOptional<z.ZodArray<z.ZodCustom<import("../types").ConditionalRule, import("../types").ConditionalRule>>>;
277
+ adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
278
+ }, z.core.$strict>], "allowMedia">, z.ZodObject<{
279
+ type: z.ZodLiteral<"rich_text">;
280
+ build: z.ZodFunction<z.core.$ZodFunctionArgs, z.ZodCustom<RichTextField, RichTextField>>;
281
+ }, z.core.$strict>>;
282
+ /**
283
+ * RichText field configuration type
284
+ * This is a plain object that can be serialized and used anywhere
285
+ * The build() method allows creating a RichTextField instance when needed
286
+ */
287
+ export type RichTextFieldConfig = z.infer<typeof richTextFieldConfigSchema>;
288
+ /**
289
+ * Helper function to create a rich text field configuration
290
+ * Returns a config object with a build() method that can be serialized and used anywhere
291
+ * @param field
292
+ */
293
+ export declare function richTextField(field: z.infer<typeof optionsSchema>): RichTextFieldConfig;
294
+ export {};
295
+ //# sourceMappingURL=richText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"richText.d.ts","sourceRoot":"","sources":["../../../src/core/fields/richText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,KAAK,EAAyB,MAAM,SAAS,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAexB,QAAA,MAAM,uBAAuB;IACzB;;;;;OAKG;;;;;;;;;;;;;;;;;;IAgBH;;OAEG;;;;;;;;kBAGL,CAAA;AAkCF,QAAA,MAAM,YAAY;;;;;;;QA5Dd;;;;;WAKG;;;;;;;;;;;;;;;;;;QAgBH;;WAEG;;;;;;;;;;;;;;;kCAwCL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,aAAc,SAAQ,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC;IACzD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAkB;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,GAAG,KAAK,CAAA;IAC3E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAE1B,OAAO,CAAC,aAAa,CAIb;IAER,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAyC;gBAE3D,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAsB3C;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIF,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAY/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB,aAAa;IAWb;;OAEG;IACH,mBAAmB;IAuBb,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IA2C3D;;OAEG;IACG,oBAAoB;IA0BJ,UAAU,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAYnG,yBAAyB;CA2D1C;AAED,MAAM,MAAM,yBAAyB,GAAG,UAAU,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAWpF,QAAA,MAAM,aAAa;;;;;;;QA7Uf;;;;;WAKG;;;;;;;;;;;;;;;;;;QAgBH;;WAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAyTL,CAAA;AAEF,QAAA,MAAM,yBAAyB;;;;;;;QAlV3B;;;;;WAKG;;;;;;;;;;;;;;;;;;QAgBH;;WAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAoUN,CAAA;AAED;;;;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"}
@@ -0,0 +1,338 @@
1
+ import { Field, baseFieldConfigSchema } from './field';
2
+ import { entityKind } from '../helpers';
3
+ import * as z from 'zod';
4
+ import { customAlphabet } from 'nanoid';
5
+ import sharp from 'sharp';
6
+ import path from 'path';
7
+ import { db } from '../../db/client';
8
+ import { EditorPhotosTable } from '../../db/schema';
9
+ import fs from 'fs';
10
+ import { and, eq } from 'drizzle-orm';
11
+ import { getCMSConfig } from '../config';
12
+ import { sanitizeRichText } from '../security/dom';
13
+ const positiveInt = z.number().int().positive();
14
+ const nonNegativeInt = z.number().int().nonnegative();
15
+ const allowImageUploadsSchema = z.strictObject({
16
+ /**
17
+ * The public URL prefix for inline photos.
18
+ * This url should be handled by the website app, not the NextJS-CMS app
19
+ * This is the URL that will be used to access the photos publicly on the website
20
+ * The name of the photo will be appended to this URL
21
+ */
22
+ publicURLPrefix: z.url().describe('The public URL prefix for inline photos'),
23
+ size: z
24
+ .strictObject({
25
+ width: positiveInt,
26
+ height: positiveInt,
27
+ crop: z.boolean().default(false),
28
+ })
29
+ .optional(),
30
+ maxFileSize: z
31
+ .strictObject({
32
+ size: positiveInt,
33
+ unit: z.enum(['kb', 'mb']),
34
+ })
35
+ .optional(),
36
+ handleMethod: z.enum(['base64', 'tempSave']).optional(),
37
+ /**
38
+ * Omit the extension of the image when saving it to disk
39
+ */
40
+ omitExtension: z.boolean().optional(),
41
+ format: z.enum(['webp', 'jpg', 'jpeg', 'png']).optional(),
42
+ });
43
+ const baseRichTextExtraConfigSchema = z
44
+ .strictObject({
45
+ placeholder: z.string().optional(),
46
+ minLength: nonNegativeInt.optional(),
47
+ maxLength: positiveInt.optional(),
48
+ /**
49
+ * Whether to sanitize the value before saving it to the database.
50
+ * If true, the value will be sanitized using DOMPurify (removes scripts, keeps HTML).
51
+ * If false, the value will be saved as is (raw input).
52
+ * @default true
53
+ */
54
+ sanitize: z.boolean().optional().describe('Sanitize the value before saving'),
55
+ })
56
+ .superRefine((value, ctx) => {
57
+ if (value.minLength !== undefined && value.maxLength !== undefined && value.minLength > value.maxLength) {
58
+ ctx.addIssue({
59
+ code: 'custom',
60
+ path: ['maxLength'],
61
+ message: 'maxLength must be greater than or equal to minLength',
62
+ });
63
+ }
64
+ });
65
+ const richTextFieldWithMediaConfigSchema = baseRichTextExtraConfigSchema.safeExtend({
66
+ allowMedia: z.literal(true),
67
+ allowImageUploads: allowImageUploadsSchema.optional(),
68
+ });
69
+ const richTextFieldWithoutMediaConfigSchema = baseRichTextExtraConfigSchema.safeExtend({
70
+ allowMedia: z.literal(false).optional(),
71
+ });
72
+ const configSchema = z.discriminatedUnion('allowMedia', [
73
+ richTextFieldWithMediaConfigSchema,
74
+ richTextFieldWithoutMediaConfigSchema,
75
+ ]);
76
+ export class RichTextField extends Field {
77
+ static [entityKind] = 'RichTextField';
78
+ maxLength;
79
+ minLength;
80
+ placeholder;
81
+ allowMedia;
82
+ allowImageUploads;
83
+ sanitize;
84
+ _inlinePhotos = [];
85
+ uploadsFolder = getCMSConfig().files.upload.uploadPath;
86
+ constructor(config) {
87
+ super(config, 'rich_text');
88
+ this.maxLength = config.maxLength;
89
+ this.minLength = config.minLength;
90
+ this.placeholder = config.placeholder;
91
+ this.sanitize = config.sanitize ?? true;
92
+ if (config.allowMedia && config.allowImageUploads?.publicURLPrefix) {
93
+ this.allowMedia = true;
94
+ this.allowImageUploads = {
95
+ publicURLPrefix: config.allowImageUploads.publicURLPrefix,
96
+ size: config.allowImageUploads.size ?? { width: 400, height: 400, crop: false },
97
+ maxFileSize: config.allowImageUploads.maxFileSize ?? { size: 1, unit: 'mb' },
98
+ handleMethod: config.allowImageUploads.handleMethod ?? 'base64',
99
+ omitExtension: config.allowImageUploads.omitExtension ?? true,
100
+ format: config.allowImageUploads.format ?? 'webp',
101
+ };
102
+ }
103
+ else {
104
+ this.allowMedia = false;
105
+ this.allowImageUploads = false;
106
+ }
107
+ }
108
+ /**
109
+ * Get the value of the field
110
+ */
111
+ getValue() {
112
+ return this.value;
113
+ }
114
+ exportForClient() {
115
+ return {
116
+ ...super.exportForClient(),
117
+ maxLength: this.maxLength,
118
+ minLength: this.minLength,
119
+ placeholder: this.placeholder,
120
+ allowMedia: this.allowMedia,
121
+ allowImageUploads: this.allowImageUploads,
122
+ sanitize: this.sanitize,
123
+ };
124
+ }
125
+ /**
126
+ * Sanitize the value
127
+ */
128
+ sanitizeValue() {
129
+ /**
130
+ * Check if the value is not undefined
131
+ */
132
+ if (this.value !== undefined && this.sanitize) {
133
+ /**
134
+ * Sanitize the value
135
+ */
136
+ this.value = sanitizeRichText(this.value);
137
+ }
138
+ }
139
+ checkRequired() {
140
+ /**
141
+ * Check if the field is required
142
+ */
143
+ if (this.required) {
144
+ if (!this.value || this.value.trim().length === 0) {
145
+ throw new Error(`Field ${this.label} is required`);
146
+ }
147
+ }
148
+ }
149
+ /**
150
+ * Extract inline images from the value
151
+ */
152
+ extractInlineImages() {
153
+ if (!this.value)
154
+ return;
155
+ if (!this.allowImageUploads)
156
+ return;
157
+ const regex = /<img.*?src="(data:image\/.*?;base64,.*?)".*?>/g;
158
+ const matches = this.value.matchAll(regex);
159
+ for (const match of matches) {
160
+ const base64String = match[1];
161
+ const extension = base64String.split(';')[0].split('/')[1];
162
+ const randomString = customAlphabet('1234567890abcdef', 21)();
163
+ const name = `${randomString}${this.allowImageUploads.omitExtension ? '' : `.${extension}`}`;
164
+ this._inlinePhotos.push({
165
+ base64String,
166
+ extension,
167
+ name: name,
168
+ });
169
+ /**
170
+ * Replace the inline image src with the name of the image
171
+ */
172
+ this.value = this.value.replace(base64String, `${this.allowImageUploads?.publicURLPrefix}/${name}`);
173
+ }
174
+ }
175
+ async writeInlineImages(sectionName, itemId) {
176
+ if (!this.allowImageUploads)
177
+ return;
178
+ /**
179
+ * If .photos, and 'sectionName' folders don't exist, create them
180
+ */
181
+ const photosFolder = path.join(this.uploadsFolder, '.photos', sectionName);
182
+ if (!fs.existsSync(photosFolder)) {
183
+ fs.mkdirSync(photosFolder, { recursive: true });
184
+ }
185
+ for (const photo of this._inlinePhotos) {
186
+ const str = photo.base64String.split(',')[1];
187
+ if (!str)
188
+ continue;
189
+ /**
190
+ * Use sharp to write the image to disk
191
+ */
192
+ const buffer = Buffer.from(str, 'base64');
193
+ sharp.cache({ files: 0 });
194
+ sharp.cache(false);
195
+ const image = sharp(buffer);
196
+ await image
197
+ .toFormat(this.allowImageUploads.format ?? 'webp')
198
+ .toFile(path.join(this.uploadsFolder, '.photos', sectionName, photo.name));
199
+ /**
200
+ * Insert the image into the database
201
+ */
202
+ await db.insert(EditorPhotosTable).values({
203
+ name: photo.name,
204
+ itemId: itemId,
205
+ section: sectionName,
206
+ field: this.name,
207
+ linked: true,
208
+ });
209
+ /**
210
+ * Destroy the image to free up memory
211
+ */
212
+ image.destroy();
213
+ }
214
+ }
215
+ /**
216
+ * Prepare the field for submission
217
+ */
218
+ async prepareForSubmission() {
219
+ /**
220
+ * Sanitize the value
221
+ */
222
+ this.sanitizeValue();
223
+ /**
224
+ * Check minimum length
225
+ */
226
+ if (this.minLength) {
227
+ if (this.minLength > this.value.length) {
228
+ throw new Error(`Field ${this.label} must be at least ${this.minLength} characters long`);
229
+ }
230
+ }
231
+ /**
232
+ * Check maximum length
233
+ */
234
+ if (this.maxLength) {
235
+ if (this.maxLength < this.value.length) {
236
+ throw new Error(`Field ${this.label} must be at most ${this.maxLength} characters long`);
237
+ }
238
+ }
239
+ this.extractInlineImages();
240
+ }
241
+ async postSubmit({ sectionName, itemId }) {
242
+ if (!this._inlinePhotos)
243
+ return;
244
+ /**
245
+ * First, check if there are any inline images saved in the `editor_photos` table (edit operation)
246
+ * If there are, check if they are still present in the rich text value
247
+ * If they are not present (admin deleted them), delete them from the database and disk
248
+ */
249
+ await this.checkPreviousInlineImages(sectionName, itemId);
250
+ await this.writeInlineImages(sectionName, itemId);
251
+ }
252
+ async checkPreviousInlineImages(sectionName, itemId) {
253
+ if (!this.allowImageUploads)
254
+ return;
255
+ /**
256
+ * Get all the photos saved in the database for this field
257
+ */
258
+ const tablePhotos = await db
259
+ .select()
260
+ .from(EditorPhotosTable)
261
+ .where(and(eq(EditorPhotosTable.section, sectionName), eq(EditorPhotosTable.itemId, itemId), eq(EditorPhotosTable.field, this.name)));
262
+ if (tablePhotos.length === 0)
263
+ return;
264
+ /**
265
+ * Extract the photos from the value (only photos that has the publicURLPrefix)
266
+ */
267
+ const regex = new RegExp(`${this.allowImageUploads.publicURLPrefix}/(.*?)`, 'g');
268
+ const matches = this.value.matchAll(regex);
269
+ const photosInValue = [];
270
+ for (const match of matches) {
271
+ photosInValue.push(match[1]);
272
+ }
273
+ /**
274
+ * Check if the photos in the database are still present in the value
275
+ */
276
+ for (const tablePhoto of tablePhotos) {
277
+ if (!photosInValue.includes(tablePhoto.name)) {
278
+ /**
279
+ * Delete the photo from the database
280
+ */
281
+ await db
282
+ .delete(EditorPhotosTable)
283
+ .where(and(eq(EditorPhotosTable.section, sectionName), eq(EditorPhotosTable.itemId, itemId), eq(EditorPhotosTable.field, this.name), eq(EditorPhotosTable.name, tablePhoto.name)));
284
+ /**
285
+ * Delete the photo from disk
286
+ */
287
+ try {
288
+ await fs.promises.unlink(path.join(this.uploadsFolder, '.photos', sectionName, tablePhoto.name));
289
+ }
290
+ catch (error) {
291
+ console.log(`${this.label}: Error deleting file from disk`);
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ const richTextFieldWithMediaOptionsSchema = z.strictObject({
298
+ ...baseFieldConfigSchema.shape,
299
+ ...richTextFieldWithMediaConfigSchema.shape,
300
+ });
301
+ const richTextFieldWithoutMediaOptionsSchema = z.strictObject({
302
+ ...baseFieldConfigSchema.shape,
303
+ ...richTextFieldWithoutMediaConfigSchema.shape,
304
+ });
305
+ const optionsSchema = z.discriminatedUnion('allowMedia', [
306
+ richTextFieldWithMediaOptionsSchema,
307
+ richTextFieldWithoutMediaOptionsSchema,
308
+ ]);
309
+ const richTextFieldConfigSchema = z.intersection(optionsSchema, z.strictObject({
310
+ type: z.literal('rich_text').describe('The type of the field'),
311
+ build: z
312
+ .function()
313
+ .output(z.instanceof(RichTextField))
314
+ .describe('Build a RichTextField instance from this config'),
315
+ }));
316
+ /**
317
+ * Helper function to create a rich text field configuration
318
+ * Returns a config object with a build() method that can be serialized and used anywhere
319
+ * @param field
320
+ */
321
+ export function richTextField(field) {
322
+ /**
323
+ * Validate the field config
324
+ */
325
+ const result = optionsSchema.safeParse(field);
326
+ if (!result.success) {
327
+ throw new Error(`[Field: ${field.name}]: ${z.prettifyError(result.error)}`);
328
+ }
329
+ const config = {
330
+ ...field,
331
+ type: 'rich_text',
332
+ build() {
333
+ // Use the original field config directly (it doesn't have build() method)
334
+ return new RichTextField(field);
335
+ },
336
+ };
337
+ return config;
338
+ }