includio-cms 0.1.3 → 0.5.0

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 (313) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/ROADMAP.md +23 -13
  3. package/dist/admin/api/accept-invite.js +1 -5
  4. package/dist/admin/api/invite.js +7 -16
  5. package/dist/admin/client/account/account-page.svelte +20 -50
  6. package/dist/admin/client/account/lang.d.ts +15 -23
  7. package/dist/admin/client/account/lang.js +51 -67
  8. package/dist/admin/client/account/preferences-section.svelte +26 -84
  9. package/dist/admin/client/account/profile-section.svelte +60 -40
  10. package/dist/admin/client/account/schema.d.ts +11 -3
  11. package/dist/admin/client/account/schema.js +25 -16
  12. package/dist/admin/client/account/security-section.svelte +139 -105
  13. package/dist/admin/client/account/sessions-section.svelte +35 -34
  14. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
  15. package/dist/admin/client/admin/admin-layout.svelte +3 -2
  16. package/dist/admin/client/admin/admin-preloader.svelte +36 -0
  17. package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
  18. package/dist/admin/client/admin/dashboard-page.svelte +55 -41
  19. package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
  20. package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
  21. package/dist/admin/client/collection/bulk-actions-bar.svelte +83 -0
  22. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +9 -0
  23. package/dist/admin/client/collection/collection-entries.svelte +255 -256
  24. package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
  25. package/dist/admin/client/collection/collection-view.svelte.js +9 -5
  26. package/dist/admin/client/collection/collection.svelte +22 -12
  27. package/dist/admin/client/collection/data-table.svelte +50 -39
  28. package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
  29. package/dist/admin/client/collection/date-cell.svelte +7 -5
  30. package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
  31. package/dist/admin/client/collection/empty-state.svelte +28 -0
  32. package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
  33. package/dist/admin/client/collection/entry-link.svelte +10 -4
  34. package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
  35. package/dist/admin/client/collection/grid-view.svelte +21 -23
  36. package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
  37. package/dist/admin/client/collection/row-actions.svelte +60 -0
  38. package/dist/admin/client/collection/row-actions.svelte.d.ts +9 -0
  39. package/dist/admin/client/collection/status-badge.svelte +7 -8
  40. package/dist/admin/client/collection/table-pagination.svelte +122 -79
  41. package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
  42. package/dist/admin/client/collection/table-toolbar.svelte +108 -88
  43. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
  44. package/dist/admin/client/entry/entry-form.svelte +109 -1
  45. package/dist/admin/client/entry/entry-header.svelte +96 -37
  46. package/dist/admin/client/entry/entry-header.svelte.d.ts +5 -0
  47. package/dist/admin/client/entry/entry.svelte +171 -60
  48. package/dist/admin/client/entry/header/a11y-validator.d.ts +46 -0
  49. package/dist/admin/client/entry/header/a11y-validator.js +311 -0
  50. package/dist/admin/client/entry/header/publish-panel.svelte +373 -131
  51. package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
  52. package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
  53. package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
  54. package/dist/admin/client/entry/header/status-badge.svelte +25 -118
  55. package/dist/admin/client/entry/header/version-history-sheet.svelte +314 -98
  56. package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
  57. package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
  58. package/dist/admin/client/form/form-submissions.svelte +421 -139
  59. package/dist/admin/client/form/submission-link.svelte +8 -2
  60. package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
  61. package/dist/admin/client/form/submission-status-badge.svelte +18 -4
  62. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
  63. package/dist/admin/client/login/lang.d.ts +32 -0
  64. package/dist/admin/client/login/lang.js +66 -2
  65. package/dist/admin/client/login/login-form.svelte +237 -95
  66. package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
  67. package/dist/admin/client/login/login-page.svelte +34 -98
  68. package/dist/admin/client/login/reset-password-page.svelte +235 -0
  69. package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
  70. package/dist/admin/client/login/schema.d.ts +15 -0
  71. package/dist/admin/client/login/schema.js +21 -0
  72. package/dist/admin/client/users/accept-invite-page.svelte +166 -37
  73. package/dist/admin/client/users/create-user-dialog.svelte +15 -7
  74. package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
  75. package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
  76. package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
  77. package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
  78. package/dist/admin/client/users/lang.d.ts +27 -0
  79. package/dist/admin/client/users/lang.js +64 -10
  80. package/dist/admin/client/users/pending-invitations.svelte +59 -23
  81. package/dist/admin/client/users/users-page.svelte +471 -72
  82. package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
  83. package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
  84. package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
  85. package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
  86. package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
  87. package/dist/admin/components/dashboard/index.d.ts +4 -2
  88. package/dist/admin/components/dashboard/index.js +4 -2
  89. package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
  90. package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
  91. package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
  92. package/dist/admin/components/dashboard/stat-card.svelte +2 -2
  93. package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
  94. package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
  95. package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
  96. package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
  97. package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
  98. package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
  99. package/dist/admin/components/fields/content-field.svelte +27 -0
  100. package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
  101. package/dist/admin/components/fields/field-renderer.svelte +9 -7
  102. package/dist/admin/components/fields/image-field.svelte +2 -2
  103. package/dist/admin/components/fields/media-field.svelte +2 -2
  104. package/dist/admin/components/fields/seo-field.svelte +205 -25
  105. package/dist/admin/components/fields/simple-array-field.svelte +289 -0
  106. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
  107. package/dist/admin/components/fields/slug-field.svelte +3 -2
  108. package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
  109. package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
  110. package/dist/admin/components/fields/text-field-wrapper.svelte +13 -1
  111. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  112. package/dist/admin/components/fields/url-field.svelte +5 -4
  113. package/dist/admin/components/layout/app-sidebar.svelte +27 -24
  114. package/dist/admin/components/layout/lang.d.ts +6 -0
  115. package/dist/admin/components/layout/lang.js +13 -1
  116. package/dist/admin/components/layout/layout-renderer.svelte +352 -0
  117. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
  118. package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
  119. package/dist/admin/components/layout/nav-collections.svelte +65 -36
  120. package/dist/admin/components/layout/nav-footer.svelte +31 -0
  121. package/dist/admin/components/layout/nav-footer.svelte.d.ts +18 -0
  122. package/dist/admin/components/layout/nav-forms.svelte +55 -30
  123. package/dist/admin/components/layout/nav-main.svelte +14 -52
  124. package/dist/admin/components/layout/nav-search.svelte +4 -3
  125. package/dist/admin/components/layout/nav-singletons.svelte +59 -17
  126. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
  127. package/dist/admin/components/layout/site-header.svelte +74 -13
  128. package/dist/admin/components/media/alt-input.svelte +32 -22
  129. package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
  130. package/dist/admin/components/media/file/file-details.svelte +299 -217
  131. package/dist/admin/components/media/file/file-miniature.svelte +54 -41
  132. package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
  133. package/dist/admin/components/media/file/file-preview.svelte +1 -1
  134. package/dist/admin/components/media/file-upload.svelte +24 -26
  135. package/dist/admin/components/media/files-list.svelte +112 -40
  136. package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
  137. package/dist/admin/components/media/focal-point-input.svelte +122 -26
  138. package/dist/admin/components/media/media-library.svelte +127 -70
  139. package/dist/admin/components/media/media-search.svelte +6 -6
  140. package/dist/admin/components/media/media-sort.svelte +3 -1
  141. package/dist/admin/components/media/multi-file-summary.svelte +88 -68
  142. package/dist/admin/components/media/tag-combobox.svelte +141 -66
  143. package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
  144. package/dist/admin/components/media/tag-sidebar.svelte +139 -121
  145. package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
  146. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
  147. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
  148. package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
  149. package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
  150. package/dist/admin/components/tiptap/content-editor.svelte +280 -0
  151. package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
  152. package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
  153. package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
  154. package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
  155. package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
  156. package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
  157. package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
  158. package/dist/admin/components/tiptap/inline-block-node.js +98 -0
  159. package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
  160. package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
  161. package/dist/admin/components/tiptap/slash-command.js +181 -0
  162. package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
  163. package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
  164. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
  165. package/dist/admin/email/invite-template.d.ts +8 -0
  166. package/dist/admin/email/invite-template.js +99 -0
  167. package/dist/admin/email/reset-password-template.d.ts +7 -0
  168. package/dist/admin/email/reset-password-template.js +96 -0
  169. package/dist/admin/remote/ai.remote.d.ts +1 -0
  170. package/dist/admin/remote/ai.remote.js +4 -1
  171. package/dist/admin/remote/entry.remote.d.ts +8 -0
  172. package/dist/admin/remote/entry.remote.js +53 -4
  173. package/dist/admin/remote/preview.remote.js +2 -1
  174. package/dist/admin/shared/password-schema.d.ts +5 -0
  175. package/dist/admin/shared/password-schema.js +10 -0
  176. package/dist/admin/styles/admin.css +1530 -151
  177. package/dist/admin/utils/formatDate.d.ts +1 -0
  178. package/dist/admin/utils/formatDate.js +8 -0
  179. package/dist/admin/utils/roleLabel.d.ts +2 -0
  180. package/dist/admin/utils/roleLabel.js +13 -0
  181. package/dist/ai-claude/index.d.ts +2 -0
  182. package/dist/ai-claude/index.js +56 -0
  183. package/dist/cms/runtime/api.d.ts +6 -1
  184. package/dist/cms/runtime/api.js +3 -0
  185. package/dist/cms/runtime/schemas.d.ts +9 -1
  186. package/dist/cms/runtime/schemas.js +8 -0
  187. package/dist/cms/runtime/types.d.ts +82 -10
  188. package/dist/cms/runtime/types.js +4 -0
  189. package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
  190. package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
  191. package/dist/components/ui/alert/alert.stories.svelte +53 -0
  192. package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
  193. package/dist/components/ui/alert/alert.svelte +5 -0
  194. package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
  195. package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
  196. package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
  197. package/dist/components/ui/badge/badge.stories.svelte +33 -0
  198. package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
  200. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
  201. package/dist/components/ui/button/button.stories.svelte +43 -0
  202. package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
  203. package/dist/components/ui/button/button.svelte +1 -2
  204. package/dist/components/ui/button/button.svelte.d.ts +0 -3
  205. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  206. package/dist/components/ui/card/card.stories.svelte +42 -0
  207. package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
  208. package/dist/components/ui/command/command.stories.svelte +51 -0
  209. package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
  210. package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
  211. package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
  212. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  213. package/dist/components/ui/field/field.stories.svelte +21 -0
  214. package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
  215. package/dist/components/ui/input/input.stories.svelte +40 -0
  216. package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
  217. package/dist/components/ui/input/input.svelte +2 -4
  218. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  219. package/dist/components/ui/label/label.stories.svelte +20 -0
  220. package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
  221. package/dist/components/ui/popover/popover.stories.svelte +29 -0
  222. package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
  223. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  224. package/dist/components/ui/select/select.stories.svelte +23 -0
  225. package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
  226. package/dist/components/ui/separator/separator.stories.svelte +24 -0
  227. package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
  228. package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
  229. package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
  230. package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
  231. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
  232. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
  233. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
  234. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  235. package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
  236. package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
  237. package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
  238. package/dist/components/ui/sonner/sonner.svelte +8 -2
  239. package/dist/components/ui/sonner/toast-demo.svelte +29 -0
  240. package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
  241. package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
  242. package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/textarea/textarea.svelte +0 -2
  244. package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
  245. package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
  246. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
  247. package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
  248. package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
  249. package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
  250. package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
  251. package/dist/core/fields/fieldSchemaToTs.js +133 -1
  252. package/dist/core/fields/layoutUtils.d.ts +17 -0
  253. package/dist/core/fields/layoutUtils.js +149 -0
  254. package/dist/core/fields/structuredToHtml.d.ts +9 -0
  255. package/dist/core/fields/structuredToHtml.js +161 -0
  256. package/dist/core/server/entries/operations/create.js +2 -1
  257. package/dist/core/server/entries/operations/get.js +8 -6
  258. package/dist/core/server/entries/operations/update.d.ts +3 -0
  259. package/dist/core/server/entries/operations/update.js +30 -2
  260. package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
  261. package/dist/core/server/fields/queryStructuredContent.js +65 -0
  262. package/dist/core/server/fields/resolveImageFields.js +51 -2
  263. package/dist/core/server/fields/resolveRelationFields.js +2 -2
  264. package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
  265. package/dist/core/server/fields/resolveUrlFields.js +57 -6
  266. package/dist/core/server/fields/slugResolver.d.ts +10 -0
  267. package/dist/core/server/fields/slugResolver.js +34 -0
  268. package/dist/core/server/generator/fields.js +15 -4
  269. package/dist/core/server/generator/generator.js +3 -2
  270. package/dist/files-local/index.js +126 -64
  271. package/dist/paraglide/.prettierignore +3 -0
  272. package/dist/paraglide/messages/_index.d.ts +36 -0
  273. package/dist/paraglide/messages/_index.js +72 -0
  274. package/dist/paraglide/messages/en.d.ts +5 -0
  275. package/dist/paraglide/messages/en.js +14 -0
  276. package/dist/paraglide/messages/pl.d.ts +5 -0
  277. package/dist/paraglide/messages/pl.js +14 -0
  278. package/dist/paraglide/messages.d.ts +2 -0
  279. package/dist/paraglide/messages.js +4 -0
  280. package/dist/paraglide/registry.d.ts +21 -0
  281. package/dist/paraglide/registry.js +31 -0
  282. package/dist/paraglide/runtime.d.ts +583 -0
  283. package/dist/paraglide/runtime.js +1402 -0
  284. package/dist/paraglide/server.d.ts +67 -0
  285. package/dist/paraglide/server.js +175 -0
  286. package/dist/server/auth.d.ts +5 -0
  287. package/dist/server/auth.js +12 -1
  288. package/dist/sveltekit/components/structured-content.svelte +204 -0
  289. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  290. package/dist/sveltekit/config.d.ts +13 -3
  291. package/dist/sveltekit/index.d.ts +3 -0
  292. package/dist/sveltekit/index.js +3 -0
  293. package/dist/sveltekit/server/handle.js +1 -0
  294. package/dist/types/config.d.ts +3 -0
  295. package/dist/types/fields.d.ts +19 -2
  296. package/dist/types/index.d.ts +2 -0
  297. package/dist/types/index.js +2 -0
  298. package/dist/types/layout.d.ts +54 -0
  299. package/dist/types/layout.js +6 -0
  300. package/dist/types/structured-content.d.ts +63 -0
  301. package/dist/types/structured-content.js +1 -0
  302. package/dist/updates/0.1.4/index.d.ts +2 -0
  303. package/dist/updates/0.1.4/index.js +11 -0
  304. package/dist/updates/0.1.5/index.d.ts +2 -0
  305. package/dist/updates/0.1.5/index.js +18 -0
  306. package/dist/updates/0.2.0/index.d.ts +2 -0
  307. package/dist/updates/0.2.0/index.js +11 -0
  308. package/dist/updates/0.2.2/index.d.ts +2 -0
  309. package/dist/updates/0.2.2/index.js +13 -0
  310. package/dist/updates/0.5.0/index.d.ts +2 -0
  311. package/dist/updates/0.5.0/index.js +14 -0
  312. package/dist/updates/index.js +6 -1
  313. package/package.json +17 -10
@@ -1,7 +1,9 @@
1
1
  import { getCMS } from '../../../cms.js';
2
2
  import { generateZodSchemaFromFields } from '../../../fields/fieldSchemaToTs.js';
3
+ import { getFieldsFromConfig } from '../../../fields/layoutUtils.js';
3
4
  import z from 'zod';
4
- import { getDbEntryOrThrow, getDbEntryVersionOrThrow } from './get.js';
5
+ import { getDbEntryOrThrow, getDbEntryVersionOrThrow, getDbEntryVersions } from './get.js';
6
+ import { createEntryVersion } from './create.js';
5
7
  export const updateEntrySchema = z.object({
6
8
  availableLocales: z.array(z.string()).optional(),
7
9
  archivedAt: z.date().nullable().optional(),
@@ -57,7 +59,7 @@ export const updateEntryVersion = async (id, data) => {
57
59
  const entry = await getDbEntryOrThrow({ id: version.entryId });
58
60
  const config = getCMS().getBySlug(entry.slug);
59
61
  const languages = getCMS().languages;
60
- const schema = generateZodSchemaFromFields(config.fields, languages);
62
+ const schema = generateZodSchemaFromFields(getFieldsFromConfig(config), languages);
61
63
  const parsedData = schema.safeParse(filteredData.data);
62
64
  if (!parsedData.success) {
63
65
  throw Error('Invalid data: ' + parsedData.error.flatten());
@@ -102,6 +104,32 @@ export const pruneOldDraftVersions = async (entryId) => {
102
104
  await Promise.all(toDelete.map((v) => getCMS().databaseAdapter.deleteEntryVersion({ id: v.id })));
103
105
  }
104
106
  };
107
+ export const upsertDraftVersion = async (entryId, data, options) => {
108
+ const entry = await getDbEntryOrThrow({ id: entryId });
109
+ const versions = await getDbEntryVersions({ entryIds: [entryId] });
110
+ // Sort desc by versionNumber, find latest non-published draft
111
+ const sorted = versions.sort((a, b) => b.versionNumber - a.versionNumber);
112
+ const latestDraft = sorted.find((v) => v.id !== entry.publishedVersionId);
113
+ if (latestDraft) {
114
+ // Compare data — if identical, skip
115
+ const existingData = JSON.stringify(latestDraft.data);
116
+ const newData = JSON.stringify(data);
117
+ if (existingData === newData) {
118
+ return latestDraft;
119
+ }
120
+ // Different data — update in place
121
+ const updated = await getCMS().databaseAdapter.updateEntryVersion({
122
+ id: latestDraft.id,
123
+ data: {
124
+ data: data,
125
+ createdAt: new Date()
126
+ }
127
+ });
128
+ return updated;
129
+ }
130
+ // No draft exists — create new version
131
+ return createEntryVersion({ entryId, data }, options);
132
+ };
105
133
  export const unpublishEntry = async (entryId) => {
106
134
  await updateEntry(entryId, {
107
135
  publishedVersionId: null,
@@ -0,0 +1,15 @@
1
+ import type { SCNode, StructuredContentDoc, SCInlineBlockAttrs } from '../../../types/structured-content.js';
2
+ export interface MediaRef {
3
+ type: 'image' | 'video';
4
+ src: string;
5
+ alt?: string;
6
+ mediaId?: string;
7
+ }
8
+ /** Extract block-level nodes, optionally filtered by type. */
9
+ export declare function extractBlocks(doc: StructuredContentDoc, type?: string): SCNode[];
10
+ /** Extract inline block nodes, optionally filtered by blockType. */
11
+ export declare function extractInlineBlocks(doc: StructuredContentDoc, blockType?: string): SCInlineBlockAttrs[];
12
+ /** Extract all plain text from doc (useful for excerpts, search indexing). */
13
+ export declare function extractText(doc: StructuredContentDoc): string;
14
+ /** Extract media references from figure/video/image nodes. */
15
+ export declare function extractMediaRefs(doc: StructuredContentDoc): MediaRef[];
@@ -0,0 +1,65 @@
1
+ import { walkNodes } from '../../../admin/components/tiptap/structured-content-utils.js';
2
+ /** Extract block-level nodes, optionally filtered by type. */
3
+ export function extractBlocks(doc, type) {
4
+ const result = [];
5
+ walkNodes(doc.content, (node) => {
6
+ if (type ? node.type === type : !['doc', 'text'].includes(node.type)) {
7
+ result.push(node);
8
+ }
9
+ });
10
+ return result;
11
+ }
12
+ /** Extract inline block nodes, optionally filtered by blockType. */
13
+ export function extractInlineBlocks(doc, blockType) {
14
+ const result = [];
15
+ walkNodes(doc.content, (node) => {
16
+ if (node.type !== 'inlineBlock' || !node.attrs)
17
+ return;
18
+ const attrs = node.attrs;
19
+ if (blockType ? attrs.blockType === blockType : true) {
20
+ result.push(attrs);
21
+ }
22
+ });
23
+ return result;
24
+ }
25
+ /** Extract all plain text from doc (useful for excerpts, search indexing). */
26
+ export function extractText(doc) {
27
+ const parts = [];
28
+ walkNodes(doc.content, (node) => {
29
+ if (node.type === 'text' && node.text) {
30
+ parts.push(node.text);
31
+ }
32
+ else if (node.type === 'hardBreak') {
33
+ parts.push('\n');
34
+ }
35
+ });
36
+ return parts.join('');
37
+ }
38
+ /** Extract media references from figure/video/image nodes. */
39
+ export function extractMediaRefs(doc) {
40
+ const refs = [];
41
+ walkNodes(doc.content, (node) => {
42
+ if (node.type === 'figure' || node.type === 'image') {
43
+ const attrs = node.attrs;
44
+ if (attrs?.src) {
45
+ refs.push({
46
+ type: 'image',
47
+ src: attrs.src,
48
+ alt: attrs.alt ?? undefined,
49
+ mediaId: attrs['data-media-id'] ?? undefined
50
+ });
51
+ }
52
+ }
53
+ else if (node.type === 'video') {
54
+ const attrs = node.attrs;
55
+ if (attrs?.src) {
56
+ refs.push({
57
+ type: 'video',
58
+ src: attrs.src,
59
+ mediaId: attrs['data-media-id'] ?? undefined
60
+ });
61
+ }
62
+ }
63
+ });
64
+ return refs;
65
+ }
@@ -3,6 +3,7 @@ const PUBLIC_URL = env.PUBLIC_URL ?? '';
3
3
  import { getCMS } from '../../cms.js';
4
4
  import z from 'zod';
5
5
  import { getImageStyles } from './utils/imageStyles.js';
6
+ import { extractMediaIds as extractMediaIdsFromDoc, walkMediaNodes, cloneDoc } from '../../../admin/components/tiptap/structured-content-utils.js';
6
7
  export async function resolveMediaFields(data, fields) {
7
8
  const mediaIds = [];
8
9
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -39,7 +40,7 @@ export async function resolveMediaFields(data, fields) {
39
40
  case 'object':
40
41
  collectIds(val.data, field.fields);
41
42
  break;
42
- case 'array':
43
+ case 'blocks':
43
44
  if (Array.isArray(val)) {
44
45
  val.forEach((item) => {
45
46
  // Find the object definition for this item based on its slug
@@ -50,6 +51,17 @@ export async function resolveMediaFields(data, fields) {
50
51
  });
51
52
  }
52
53
  break;
54
+ case 'content': {
55
+ // Content field is localized: { lang: StructuredContentDoc }
56
+ if (typeof val === 'object' && val !== null) {
57
+ for (const doc of Object.values(val)) {
58
+ if (doc && typeof doc === 'object' && doc.type === 'doc') {
59
+ mediaIds.push(...extractMediaIdsFromDoc(doc));
60
+ }
61
+ }
62
+ }
63
+ break;
64
+ }
53
65
  }
54
66
  }
55
67
  };
@@ -178,7 +190,7 @@ export async function resolveMediaFields(data, fields) {
178
190
  data: await resolveValues(val.data, field.fields)
179
191
  };
180
192
  break;
181
- case 'array':
193
+ case 'blocks':
182
194
  result[field.slug] = await Promise.all(
183
195
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
184
196
  val.map(async (item) => {
@@ -194,6 +206,43 @@ export async function resolveMediaFields(data, fields) {
194
206
  return item;
195
207
  }));
196
208
  break;
209
+ case 'content': {
210
+ // Content field is localized: { lang: StructuredContentDoc }
211
+ if (typeof val === 'object' && val !== null) {
212
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
213
+ const resolved = {};
214
+ for (const [lang, doc] of Object.entries(val)) {
215
+ if (doc && typeof doc === 'object' && doc.type === 'doc') {
216
+ const cloned = cloneDoc(doc);
217
+ walkMediaNodes(cloned, (node) => {
218
+ const mediaId = node.attrs?.['data-media-id'];
219
+ if (!mediaId)
220
+ return;
221
+ const mediaFile = mediaMap[mediaId];
222
+ if (!mediaFile)
223
+ return;
224
+ node.attrs.src = mediaFile.url;
225
+ if (mediaFile.width)
226
+ node.attrs.width = mediaFile.width;
227
+ if (mediaFile.height)
228
+ node.attrs.height = mediaFile.height;
229
+ if (mediaFile.alt && !node.attrs.alt)
230
+ node.attrs.alt = mediaFile.alt;
231
+ node.attrs._media = {
232
+ data: mediaFile,
233
+ ...(mediaFile.type === 'image' ? { blurDataUrl: mediaFile.blurDataUrl } : {})
234
+ };
235
+ });
236
+ resolved[lang] = cloned;
237
+ }
238
+ else {
239
+ resolved[lang] = doc;
240
+ }
241
+ }
242
+ result[field.slug] = resolved;
243
+ }
244
+ break;
245
+ }
197
246
  default:
198
247
  result[field.slug] = val;
199
248
  }
@@ -26,7 +26,7 @@ export async function resolveRelationFields(data, fields, language) {
26
26
  case 'object':
27
27
  collectIds(val.data, field.fields);
28
28
  break;
29
- case 'array':
29
+ case 'blocks':
30
30
  if (Array.isArray(val)) {
31
31
  val.forEach((item) => {
32
32
  // Find the object definition for this item based on its slug
@@ -78,7 +78,7 @@ export async function resolveRelationFields(data, fields, language) {
78
78
  data: resolveValues(val.data, field.fields)
79
79
  };
80
80
  break;
81
- case 'array':
81
+ case 'blocks':
82
82
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
83
  result[field.slug] = val.map((item) => {
84
84
  // Find the object definition for this item based on its slug
@@ -1,4 +1,6 @@
1
1
  import { getCMS } from '../../cms.js';
2
+ import { extractEntryIds as extractEntryIdsFromDoc, extractMediaIds as extractMediaIdsFromDoc, cloneDoc, walkLinkMarks, walkInlineBlockNodes } from '../../../admin/components/tiptap/structured-content-utils.js';
3
+ import { getEntrySlugPath, getSlugFromEntryData } from './slugResolver.js';
2
4
  const ENTRY_ID_RE = /data-entry-id="([0-9a-f-]{36})"/g;
3
5
  function extractEntryIds(html) {
4
6
  const ids = [];
@@ -7,15 +9,47 @@ function extractEntryIds(html) {
7
9
  }
8
10
  return ids;
9
11
  }
10
- function resolveHtml(html, entriesMap) {
12
+ function resolveHtml(html, slugMap) {
11
13
  return html.replace(/<a\s([^>]*data-entry-id="([0-9a-f-]{36})"[^>]*)>/g, (match, _attrs, id) => {
12
- const entryData = entriesMap[id]?.data;
13
- const slug = entryData?.seo?.slug;
14
+ const slug = slugMap[id];
14
15
  if (!slug)
15
16
  return match;
16
17
  return match.replace(/href="[^"]*"/, `href="${slug}"`);
17
18
  });
18
19
  }
20
+ /** Extract entry IDs from inlineBlock blockData relation fields. */
21
+ function extractEntryIdsFromInlineBlocks(doc) {
22
+ const ids = [];
23
+ walkInlineBlockNodes(doc, (node) => {
24
+ const data = node.attrs?.blockData;
25
+ if (!data || typeof data !== 'object')
26
+ return;
27
+ for (const val of Object.values(data)) {
28
+ if (typeof val === 'string' && val.length === 36)
29
+ ids.push(val);
30
+ if (Array.isArray(val)) {
31
+ for (const item of val) {
32
+ if (typeof item === 'string' && item.length === 36)
33
+ ids.push(item);
34
+ }
35
+ }
36
+ }
37
+ });
38
+ return ids;
39
+ }
40
+ function resolveContentDoc(doc, slugMap) {
41
+ const cloned = cloneDoc(doc);
42
+ walkLinkMarks(cloned, (mark) => {
43
+ const entryId = mark.attrs?.['data-entry-id'];
44
+ if (!entryId)
45
+ return;
46
+ const slug = slugMap[entryId];
47
+ if (slug && mark.attrs) {
48
+ mark.attrs.href = slug;
49
+ }
50
+ });
51
+ return cloned;
52
+ }
19
53
  export async function resolveRichtextLinks(data, fields, language) {
20
54
  const entriesIds = [];
21
55
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -39,10 +73,22 @@ export async function resolveRichtextLinks(data, fields, language) {
39
73
  }
40
74
  break;
41
75
  }
76
+ case 'content': {
77
+ // Content field is localized: { lang: StructuredContentDoc, ... }
78
+ if (typeof val === 'object' && val !== null) {
79
+ for (const doc of Object.values(val)) {
80
+ if (doc && typeof doc === 'object' && doc.type === 'doc') {
81
+ entriesIds.push(...extractEntryIdsFromDoc(doc));
82
+ entriesIds.push(...extractEntryIdsFromInlineBlocks(doc));
83
+ }
84
+ }
85
+ }
86
+ break;
87
+ }
42
88
  case 'object':
43
89
  collectIds(val.data, field.fields);
44
90
  break;
45
- case 'array':
91
+ case 'blocks':
46
92
  if (Array.isArray(val)) {
47
93
  val.forEach((item) => {
48
94
  const objectDef = field.of.find((objDef) => objDef.slug === item.slug);
@@ -71,15 +117,20 @@ export async function resolveRichtextLinks(data, fields, language) {
71
117
  const versions = await db.getEntryVersions({
72
118
  ids: publishedVersionIds
73
119
  });
74
- // Build map: entryId → { data: { seo: { slug } } } using raw version data
75
- const entriesMap = {};
120
+ // Build map: entryId → collectionSlug for config lookup
121
+ const entryConfigSlugMap = {};
122
+ for (const entry of entries) {
123
+ entryConfigSlugMap[entry.id] = entry.slug;
124
+ }
125
+ // Build map: entryId → resolved slug string
126
+ const slugMap = {};
76
127
  for (const version of versions) {
77
128
  const rawData = version.data;
78
- const seoRaw = rawData?.seo;
79
- const slugField = seoRaw?.slug;
80
- const slug = slugField?.[language];
129
+ const configSlug = entryConfigSlugMap[version.entryId];
130
+ const slugPath = configSlug ? getEntrySlugPath(configSlug) : 'seo.slug';
131
+ const slug = getSlugFromEntryData(rawData, slugPath, language);
81
132
  if (slug) {
82
- entriesMap[version.entryId] = { data: { seo: { slug } } };
133
+ slugMap[version.entryId] = slug;
83
134
  }
84
135
  }
85
136
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -99,12 +150,28 @@ export async function resolveRichtextLinks(data, fields, language) {
99
150
  const resolved = {};
100
151
  for (const [lang, html] of Object.entries(val)) {
101
152
  resolved[lang] =
102
- typeof html === 'string' ? resolveHtml(html, entriesMap) : html;
153
+ typeof html === 'string' ? resolveHtml(html, slugMap) : html;
103
154
  }
104
155
  result[field.slug] = resolved;
105
156
  }
106
157
  else if (typeof val === 'string') {
107
- result[field.slug] = resolveHtml(val, entriesMap);
158
+ result[field.slug] = resolveHtml(val, slugMap);
159
+ }
160
+ break;
161
+ }
162
+ case 'content': {
163
+ if (typeof val === 'object' && val !== null) {
164
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
165
+ const resolved = {};
166
+ for (const [lang, doc] of Object.entries(val)) {
167
+ if (doc && typeof doc === 'object' && doc.type === 'doc') {
168
+ resolved[lang] = resolveContentDoc(doc, slugMap);
169
+ }
170
+ else {
171
+ resolved[lang] = doc;
172
+ }
173
+ }
174
+ result[field.slug] = resolved;
108
175
  }
109
176
  break;
110
177
  }
@@ -114,7 +181,7 @@ export async function resolveRichtextLinks(data, fields, language) {
114
181
  data: resolveValues(val.data, field.fields)
115
182
  };
116
183
  break;
117
- case 'array':
184
+ case 'blocks':
118
185
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
186
  result[field.slug] = val.map((item) => {
120
187
  const objectDef = field.of.find((objDef) => objDef.slug === item.slug);
@@ -1,5 +1,6 @@
1
1
  import { urlFieldDataSchema, urlFieldDataWithRelationSchema } from '../../../schemas/field/url.js';
2
2
  import { getEntries } from '../entries/operations/get.js';
3
+ import { getEntrySlugPath, getSlugFromEntryData } from './slugResolver.js';
3
4
  export async function resolveUrlFields(data, fields, language) {
4
5
  const entriesIds = [];
5
6
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -26,7 +27,7 @@ export async function resolveUrlFields(data, fields, language) {
26
27
  case 'object':
27
28
  collectIds(val.data, field.fields);
28
29
  break;
29
- case 'array':
30
+ case 'blocks':
30
31
  if (Array.isArray(val)) {
31
32
  val.forEach((item) => {
32
33
  // Find the object definition for this item based on its slug
@@ -37,14 +38,29 @@ export async function resolveUrlFields(data, fields, language) {
37
38
  });
38
39
  }
39
40
  break;
41
+ case 'array':
42
+ if (field.of === 'url' && Array.isArray(val)) {
43
+ for (const item of val) {
44
+ const parsedVal = urlFieldDataWithRelationSchema.safeParse(item);
45
+ if (parsedVal.success) {
46
+ entriesIds.push(parsedVal.data.id);
47
+ }
48
+ }
49
+ }
50
+ break;
40
51
  }
41
52
  }
42
53
  };
43
54
  collectIds(data, fields);
44
- let entriesMap = {};
55
+ const slugMap = {};
45
56
  if (entriesIds.length > 0) {
46
57
  const entries = await getEntries({ ids: entriesIds, language });
47
- entriesMap = Object.fromEntries(entries.map((m) => [m.id, m]));
58
+ for (const entry of entries) {
59
+ const slugPath = getEntrySlugPath(entry.slug);
60
+ const slug = getSlugFromEntryData(entry.data, slugPath);
61
+ if (slug)
62
+ slugMap[entry.id] = slug;
63
+ }
48
64
  }
49
65
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
66
  const resolveValues = (value, fields) => {
@@ -83,8 +99,7 @@ export async function resolveUrlFields(data, fields, language) {
83
99
  extras.newTab = parsed.newTab;
84
100
  }
85
101
  if (parsedValWithRelation.success) {
86
- const entryData = entriesMap[parsedValWithRelation.data.id]?.data;
87
- const slug = entryData?.seo?.slug;
102
+ const slug = slugMap[parsedValWithRelation.data.id];
88
103
  if (slug) {
89
104
  result[field.slug] = { url: slug, ...extras };
90
105
  break;
@@ -102,7 +117,7 @@ export async function resolveUrlFields(data, fields, language) {
102
117
  data: resolveValues(val.data, field.fields)
103
118
  };
104
119
  break;
105
- case 'array':
120
+ case 'blocks':
106
121
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
107
122
  result[field.slug] = val.map((item) => {
108
123
  // Find the object definition for this item based on its slug
@@ -117,6 +132,42 @@ export async function resolveUrlFields(data, fields, language) {
117
132
  return item;
118
133
  });
119
134
  break;
135
+ case 'array':
136
+ if (field.of === 'url' && Array.isArray(val)) {
137
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
138
+ result[field.slug] = val.map((item) => {
139
+ const parsedValWithRelation = urlFieldDataWithRelationSchema.safeParse(item);
140
+ const parsedVal = urlFieldDataSchema.safeParse(item);
141
+ const parsed = parsedValWithRelation.success
142
+ ? parsedValWithRelation.data
143
+ : parsedVal.success
144
+ ? parsedVal.data
145
+ : null;
146
+ if (!parsed)
147
+ return item;
148
+ const extras = {};
149
+ if (parsed.text) {
150
+ extras.text = language ? parsed.text[language] : parsed.text;
151
+ }
152
+ if (parsed.newTab !== undefined) {
153
+ extras.newTab = parsed.newTab;
154
+ }
155
+ if (parsedValWithRelation.success) {
156
+ const slug = slugMap[parsedValWithRelation.data.id];
157
+ if (slug) {
158
+ return { url: slug, ...extras };
159
+ }
160
+ }
161
+ const resolvedUrl = language
162
+ ? parsed.url[language]
163
+ : parsed.url;
164
+ return { url: resolvedUrl, ...extras };
165
+ });
166
+ }
167
+ else {
168
+ result[field.slug] = val;
169
+ }
170
+ break;
120
171
  default:
121
172
  result[field.slug] = val;
122
173
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Get the dot-path to the slug field for a given collection/single slug.
3
+ * Falls back to 'seo.slug' if no slugField is configured.
4
+ */
5
+ export declare function getEntrySlugPath(configSlug: string): string;
6
+ /**
7
+ * Traverse a dot-path in entry data and return the slug value.
8
+ * Handles both plain strings and localized objects { lang: string }.
9
+ */
10
+ export declare function getSlugFromEntryData(data: Record<string, unknown>, slugPath: string, language?: string): string | undefined;
@@ -0,0 +1,34 @@
1
+ import { getCMS } from '../../cms.js';
2
+ const DEFAULT_SLUG_PATH = 'seo.slug';
3
+ /**
4
+ * Get the dot-path to the slug field for a given collection/single slug.
5
+ * Falls back to 'seo.slug' if no slugField is configured.
6
+ */
7
+ export function getEntrySlugPath(configSlug) {
8
+ try {
9
+ const config = getCMS().getBySlug(configSlug);
10
+ return config.slugField || DEFAULT_SLUG_PATH;
11
+ }
12
+ catch {
13
+ return DEFAULT_SLUG_PATH;
14
+ }
15
+ }
16
+ /**
17
+ * Traverse a dot-path in entry data and return the slug value.
18
+ * Handles both plain strings and localized objects { lang: string }.
19
+ */
20
+ export function getSlugFromEntryData(data, slugPath, language) {
21
+ const parts = slugPath.split('.');
22
+ let current = data;
23
+ for (const part of parts) {
24
+ if (current == null || typeof current !== 'object')
25
+ return undefined;
26
+ current = current[part];
27
+ }
28
+ if (typeof current === 'string')
29
+ return current;
30
+ if (language && current != null && typeof current === 'object') {
31
+ return current[language];
32
+ }
33
+ return undefined;
34
+ }
@@ -6,6 +6,8 @@ function getFieldTypeAsString(field) {
6
6
  case 'date':
7
7
  case 'datetime':
8
8
  return 'string';
9
+ case 'content':
10
+ return 'StructuredContentDoc';
9
11
  case 'radio':
10
12
  return field.options.map((opt) => `'${opt.value.trim()}'`).join(' | ');
11
13
  case 'image': {
@@ -39,11 +41,11 @@ function getFieldTypeAsString(field) {
39
41
  slug: '${field.slug}';
40
42
  data: {${field.fields.map((f) => ` ${f.slug}${f.required ? '' : '?'}: ${getFieldTypeAsString(f)}`).join(';\n')}};
41
43
  }`;
42
- case 'array':
44
+ case 'blocks':
43
45
  return `
44
46
  (
45
47
  ${field.of
46
- .map((f) => `
48
+ .map((f) => `
47
49
  {
48
50
  slug: '${f.slug}';
49
51
  data: {${f.fields.map((f) => ` ${f.slug}${f.required ? '' : '?'}: ${getFieldTypeAsString(f)}`).join(';\n')}};
@@ -51,13 +53,22 @@ function getFieldTypeAsString(field) {
51
53
  `)
52
54
  .join(' | ')}
53
55
  )[]`;
56
+ case 'array':
57
+ switch (field.of) {
58
+ case 'text':
59
+ return field.localized ? 'Record<string, string>[]' : 'string[]';
60
+ case 'number':
61
+ return 'number[]';
62
+ case 'url':
63
+ return 'UrlFieldData[]';
64
+ }
54
65
  case 'slug':
55
66
  return 'string';
56
67
  case 'seo':
57
68
  return `{
58
- slug?: string;
69
+ slug: string;
59
70
  canonicalUrl?: string;
60
- title?: string;
71
+ title: string;
61
72
  description?: string;
62
73
  ogImage?: string;
63
74
  keywords?: string;
@@ -4,6 +4,7 @@ import { generateTsTypeFromFields } from './fields.js';
4
4
  import { generateTsTypeFromFormFields } from './formFields.js';
5
5
  import { generateZodSchemaStringFromFormFieldsAsString } from './formFieldSchemaToString.js';
6
6
  import { toPascalCase } from './utils.js';
7
+ import { getFieldsFromConfig } from '../../fields/layoutUtils.js';
7
8
  function createCmsRuntimeDir() {
8
9
  const cmsDir = join(process.cwd(), 'src/lib/cms/runtime');
9
10
  mkdirSync(cmsDir, { recursive: true });
@@ -19,7 +20,7 @@ function generateTypesStringForRecords(type, records) {
19
20
  export interface ${toPascalCase(single.slug)} {
20
21
  id: string;
21
22
  slug: string;
22
- data: ${generateTsTypeFromFields(single.fields)}
23
+ data: ${generateTsTypeFromFields(getFieldsFromConfig(single))}
23
24
  publishedAt: Date | null;
24
25
  };
25
26
  `;
@@ -68,7 +69,7 @@ function generateTypes(config) {
68
69
  const cmsDir = join(process.cwd(), 'src/lib/cms/runtime');
69
70
  const filePath = join(cmsDir, 'types.ts');
70
71
  let code = `// This file is auto-generated. Do not edit directly.\n\n`;
71
- code += `import type { MediaFile, ImageFieldData, VideoFieldData } from 'includio-cms/types';\n\n`;
72
+ code += `import type { MediaFile, ImageFieldData, VideoFieldData, StructuredContentDoc } from 'includio-cms/types';\n\n`;
72
73
  if (config.singles && config.singles.length > 0) {
73
74
  code += generateTypesStringForRecords('single', Object.values(config.singles));
74
75
  }