sitero 0.6.0 → 0.7.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 (368) hide show
  1. package/dist/export/cms/client/components/index.js +6 -2
  2. package/dist/export/cms/client/index.js +2 -0
  3. package/dist/export/cms/client/pages/index.js +1 -3
  4. package/dist/export/cms/server/index.js +1 -0
  5. package/dist/export/core/server/index.js +2 -0
  6. package/dist/export/index.js +1 -0
  7. package/dist/export/web/server/index.js +1 -0
  8. package/dist/prisma/generated/internal/class.js +4 -4
  9. package/dist/src/cms/client/applications/create-applications.js +5 -0
  10. package/dist/src/cms/client/applications/resources/page/form-data.js +56 -0
  11. package/dist/src/cms/client/applications/resources/page/use-page-update-form-data.js +30 -0
  12. package/dist/src/cms/client/applications/resources/post/use-create-form-data.js +5 -5
  13. package/dist/src/cms/client/applications/resources/post/use-update-form-data.js +1 -1
  14. package/dist/src/cms/client/applications/resources/seo-metadata/build-seo-metadata-translations.js +35 -0
  15. package/dist/src/cms/client/applications/resources/seo-metadata/use-upsert-form-data.js +15 -31
  16. package/dist/src/cms/client/applications/ui/use-nav-items.js +28 -39
  17. package/dist/src/cms/client/infrastructure/i18n/messages/en-US/resources/file.js +5 -4
  18. package/dist/src/cms/client/infrastructure/i18n/messages/en-US/resources/index.js +7 -0
  19. package/dist/src/cms/client/infrastructure/i18n/messages/en-US/resources/post.js +32 -1
  20. package/dist/src/cms/client/infrastructure/i18n/messages/en-US/ui/index.js +8 -1
  21. package/dist/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/file.js +6 -5
  22. package/dist/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/index.js +7 -0
  23. package/dist/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/post.js +18 -1
  24. package/dist/src/cms/client/infrastructure/i18n/messages/zh-TW/ui/index.js +7 -2
  25. package/dist/src/cms/client/infrastructure/operation-result/presentation/message.js +15 -0
  26. package/dist/src/cms/client/interfaces/components/create-components.js +4 -8
  27. package/dist/src/cms/client/interfaces/components/create-page-contents.js +28 -0
  28. package/dist/src/cms/client/interfaces/components/resources/page/content/field-groups.js +16 -0
  29. package/dist/src/cms/client/interfaces/components/resources/page/content/page-edit-content.js +216 -0
  30. package/dist/src/cms/client/interfaces/components/resources/page/content/page-show-content.js +114 -0
  31. package/dist/src/cms/client/interfaces/components/resources/page/content/types.js +12 -0
  32. package/dist/src/cms/client/interfaces/components/resources/post/category/category-card.js +5 -3
  33. package/dist/src/cms/client/interfaces/components/resources/post/category/category-table.js +6 -4
  34. package/dist/src/cms/client/interfaces/components/resources/post/content/post-create-content.js +13 -8
  35. package/dist/src/cms/client/interfaces/components/resources/post/content/post-edit-content.js +11 -7
  36. package/dist/src/cms/client/interfaces/components/resources/post/content/post-show-content.js +7 -2
  37. package/dist/src/cms/client/interfaces/components/resources/post/post-card.js +5 -3
  38. package/dist/src/cms/client/interfaces/components/resources/post/post-list.js +45 -10
  39. package/dist/src/cms/client/interfaces/components/resources/post/post-state-icons.js +17 -1
  40. package/dist/src/cms/client/interfaces/components/resources/post/post-table.js +8 -4
  41. package/dist/src/cms/client/interfaces/components/resources/post/search/control-fields-filters.js +5 -1
  42. package/dist/src/cms/client/interfaces/components/resources/seo-metadata/seo-form/seo-form.js +90 -67
  43. package/dist/src/cms/client/interfaces/components/resources/seo-metadata/seo-metadata-dialog.js +11 -1
  44. package/dist/src/cms/client/interfaces/components/ui/blocks/list-container/list-container.js +1 -1
  45. package/dist/src/cms/client/interfaces/components/ui/blocks/list-container/pagination.js +9 -9
  46. package/dist/src/cms/client/interfaces/components/ui/features/accordion/accordion-header.js +15 -3
  47. package/dist/src/cms/client/interfaces/components/ui/features/accordion/accordion.js +5 -7
  48. package/dist/src/cms/client/interfaces/components/ui/form/control-fields/control-fields-display.js +1 -1
  49. package/dist/src/cms/client/interfaces/components/ui/form/control-fields/control-fields-input.js +1 -1
  50. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/category/_id_/edit/page.js +11 -11
  51. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/category/_id_/page.js +12 -16
  52. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/category/_id_/relations/page.js +6 -2
  53. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/category/create/page.js +15 -16
  54. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/page.js +18 -41
  55. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/post/_id_/edit/page.js +10 -11
  56. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/post/_id_/page.js +11 -16
  57. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/post/_id_/relations/page.js +1 -0
  58. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/post/create/page.js +14 -16
  59. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/subcategory/_id_/edit/page.js +11 -11
  60. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/subcategory/_id_/page.js +12 -16
  61. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/subcategory/_id_/relations/page.js +1 -0
  62. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/_topicSlug_/subcategory/create/page.js +15 -16
  63. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/page.js +18 -32
  64. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/_id_/edit/page.js +2 -2
  65. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/_id_/page.js +9 -9
  66. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/_id_/relations/page.js +6 -2
  67. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/create/page.js +2 -2
  68. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/trash/page.js +204 -0
  69. package/dist/src/cms/client/interfaces/pages/dashboard/system/access/admin/_id_/admin-refresh-token/page.js +1 -0
  70. package/dist/src/cms/client/interfaces/pages/dashboard/system/access/admin/_id_/page.js +1 -0
  71. package/dist/src/cms/client/interfaces/pages/dashboard/system/access/admin/_id_/relations/page.js +8 -3
  72. package/dist/src/cms/client/interfaces/pages/dashboard/system/storage/file/_id_/page.js +3 -2
  73. package/dist/src/cms/client/interfaces/pages/dashboard/system/storage/file/_id_/relations/page.js +41 -30
  74. package/dist/src/cms/client/interfaces/pages/dashboard/system/storage/file/delete-many/page.js +3 -3
  75. package/dist/src/cms/client/interfaces/pages/dashboard/system/storage/file/page.js +1 -1
  76. package/dist/src/cms/client/interfaces/pages/dashboard/system/storage/trash/page.js +3 -2
  77. package/dist/src/cms/client/interfaces/pages/dashboard/website/website-page/_slug_/edit/page.js +19 -11
  78. package/dist/src/cms/client/interfaces/pages/dashboard/website/website-page/_slug_/page.js +23 -10
  79. package/dist/src/cms/client/interfaces/pages/dashboard/website/website-page/page.js +7 -7
  80. package/dist/src/cms/server/create-cms-server.js +2 -0
  81. package/dist/src/cms/server/resources/page/actions.js +31 -0
  82. package/dist/src/cms/server/resources/post/actions.js +27 -6
  83. package/dist/src/cms/server/resources/seo-metadata/actions.js +7 -16
  84. package/dist/src/config/content-ui.js +24 -0
  85. package/dist/src/config/topics.js +1 -1
  86. package/dist/src/constants/paths/cms-paths.js +2 -2
  87. package/dist/src/core/infrastructure/prisma/file/include.js +44 -0
  88. package/dist/src/core/infrastructure/prisma/file/mappers.js +51 -3
  89. package/dist/src/core/infrastructure/prisma/helpers/active-file-references.js +2 -1
  90. package/dist/src/core/infrastructure/prisma/page/include.js +20 -0
  91. package/dist/src/core/infrastructure/prisma/page/mappers.js +44 -0
  92. package/dist/src/core/infrastructure/prisma/page/page-prisma-ports.js +91 -0
  93. package/dist/src/core/infrastructure/prisma/post/include.js +2 -5
  94. package/dist/src/core/infrastructure/prisma/post/lifecycle.js +108 -0
  95. package/dist/src/core/infrastructure/prisma/post/mappers.js +0 -2
  96. package/dist/src/core/infrastructure/prisma/post/post-prisma-ports.js +76 -24
  97. package/dist/src/core/infrastructure/prisma/post/read-scope.js +45 -0
  98. package/dist/src/core/infrastructure/prisma/seo-metadata/mappers.js +6 -1
  99. package/dist/src/core/infrastructure/prisma/seo-metadata/seo-metadata-prisma-ports.js +32 -11
  100. package/dist/src/core/seeders/page/seeder.js +9 -29
  101. package/dist/src/core/seeders/seed.js +0 -3
  102. package/dist/src/core/sitero-server/create-sitero-server.js +10 -0
  103. package/dist/src/web/server/create-web-server.js +5 -1
  104. package/dist/src/web/server/resources/page/actions.js +20 -0
  105. package/dist/src/web/server/resources/post/actions.js +3 -13
  106. package/dist/src/web/server/seo/sitemap/get-page-items.js +7 -6
  107. package/dist/src/web/server/seo/sitemap/get-post-items.js +2 -2
  108. package/dist/src/web/server/seo/sitemap/get-subcategory-items.js +1 -1
  109. package/dist/types/export/cms/client/components/index.d.ts +3 -0
  110. package/dist/types/export/cms/client/components/index.d.ts.map +1 -1
  111. package/dist/types/export/cms/client/index.d.ts +2 -0
  112. package/dist/types/export/cms/client/index.d.ts.map +1 -1
  113. package/dist/types/export/cms/client/pages/index.d.ts +2 -1
  114. package/dist/types/export/cms/client/pages/index.d.ts.map +1 -1
  115. package/dist/types/export/cms/server/index.d.ts +2 -1
  116. package/dist/types/export/cms/server/index.d.ts.map +1 -1
  117. package/dist/types/export/index.d.ts +1 -1
  118. package/dist/types/export/index.d.ts.map +1 -1
  119. package/dist/types/export/web/server/index.d.ts +2 -1
  120. package/dist/types/export/web/server/index.d.ts.map +1 -1
  121. package/dist/types/src/cms/client/applications/create-applications.d.ts.map +1 -1
  122. package/dist/types/src/cms/client/applications/index.d.ts +1 -0
  123. package/dist/types/src/cms/client/applications/index.d.ts.map +1 -1
  124. package/dist/types/src/cms/client/applications/resources/index.d.ts +1 -0
  125. package/dist/types/src/cms/client/applications/resources/index.d.ts.map +1 -1
  126. package/dist/types/src/cms/client/applications/resources/page/form-data.d.ts +21 -0
  127. package/dist/types/src/cms/client/applications/resources/page/form-data.d.ts.map +1 -0
  128. package/dist/types/src/cms/client/applications/resources/page/index.d.ts +3 -0
  129. package/dist/types/src/cms/client/applications/resources/page/index.d.ts.map +1 -0
  130. package/dist/types/src/cms/client/applications/resources/page/use-page-update-form-data.d.ts +12 -0
  131. package/dist/types/src/cms/client/applications/resources/page/use-page-update-form-data.d.ts.map +1 -0
  132. package/dist/types/src/cms/client/applications/resources/post/use-create-form-data.d.ts +3 -5
  133. package/dist/types/src/cms/client/applications/resources/post/use-create-form-data.d.ts.map +1 -1
  134. package/dist/types/src/cms/client/applications/resources/post/use-update-form-data.d.ts.map +1 -1
  135. package/dist/types/src/cms/client/applications/resources/seo-metadata/build-seo-metadata-translations.d.ts +6 -0
  136. package/dist/types/src/cms/client/applications/resources/seo-metadata/build-seo-metadata-translations.d.ts.map +1 -0
  137. package/dist/types/src/cms/client/applications/resources/seo-metadata/use-upsert-form-data.d.ts +5 -4
  138. package/dist/types/src/cms/client/applications/resources/seo-metadata/use-upsert-form-data.d.ts.map +1 -1
  139. package/dist/types/src/cms/client/applications/types.d.ts +2 -1
  140. package/dist/types/src/cms/client/applications/types.d.ts.map +1 -1
  141. package/dist/types/src/cms/client/applications/ui/use-nav-items.d.ts +3 -4
  142. package/dist/types/src/cms/client/applications/ui/use-nav-items.d.ts.map +1 -1
  143. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/index.d.ts +86 -0
  144. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/index.d.ts.map +1 -1
  145. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/resources/file.d.ts +3 -0
  146. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/resources/file.d.ts.map +1 -1
  147. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/resources/index.d.ts +71 -0
  148. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/resources/index.d.ts.map +1 -1
  149. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/resources/post.d.ts +51 -0
  150. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/resources/post.d.ts.map +1 -1
  151. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/ui/index.d.ts +15 -0
  152. package/dist/types/src/cms/client/infrastructure/i18n/messages/en-US/ui/index.d.ts.map +1 -1
  153. package/dist/types/src/cms/client/infrastructure/i18n/messages/index.d.ts +172 -0
  154. package/dist/types/src/cms/client/infrastructure/i18n/messages/index.d.ts.map +1 -1
  155. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/index.d.ts +86 -0
  156. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/index.d.ts.map +1 -1
  157. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/file.d.ts +3 -0
  158. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/file.d.ts.map +1 -1
  159. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/index.d.ts +71 -0
  160. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/index.d.ts.map +1 -1
  161. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/post.d.ts +51 -0
  162. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/resources/post.d.ts.map +1 -1
  163. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/ui/index.d.ts +15 -0
  164. package/dist/types/src/cms/client/infrastructure/i18n/messages/zh-TW/ui/index.d.ts.map +1 -1
  165. package/dist/types/src/cms/client/infrastructure/operation-result/presentation/message.d.ts.map +1 -1
  166. package/dist/types/src/cms/client/interfaces/components/create-components.d.ts +6 -3
  167. package/dist/types/src/cms/client/interfaces/components/create-components.d.ts.map +1 -1
  168. package/dist/types/src/cms/client/interfaces/components/create-page-contents.d.ts +30 -0
  169. package/dist/types/src/cms/client/interfaces/components/create-page-contents.d.ts.map +1 -0
  170. package/dist/types/src/cms/client/interfaces/components/resources/index.d.ts +1 -1
  171. package/dist/types/src/cms/client/interfaces/components/resources/index.d.ts.map +1 -1
  172. package/dist/types/src/cms/client/interfaces/components/resources/page/content/field-groups.d.ts +3 -0
  173. package/dist/types/src/cms/client/interfaces/components/resources/page/content/field-groups.d.ts.map +1 -0
  174. package/dist/types/src/cms/client/interfaces/components/resources/page/content/page-edit-content.d.ts +14 -0
  175. package/dist/types/src/cms/client/interfaces/components/resources/page/content/page-edit-content.d.ts.map +1 -0
  176. package/dist/types/src/cms/client/interfaces/components/resources/page/content/page-show-content.d.ts +7 -0
  177. package/dist/types/src/cms/client/interfaces/components/resources/page/content/page-show-content.d.ts.map +1 -0
  178. package/dist/types/src/cms/client/interfaces/components/resources/page/content/types.d.ts +27 -0
  179. package/dist/types/src/cms/client/interfaces/components/resources/page/content/types.d.ts.map +1 -0
  180. package/dist/types/src/cms/client/interfaces/components/resources/page/index.d.ts +4 -0
  181. package/dist/types/src/cms/client/interfaces/components/resources/page/index.d.ts.map +1 -0
  182. package/dist/types/src/cms/client/interfaces/components/resources/post/category/category-card.d.ts +3 -1
  183. package/dist/types/src/cms/client/interfaces/components/resources/post/category/category-card.d.ts.map +1 -1
  184. package/dist/types/src/cms/client/interfaces/components/resources/post/category/category-table.d.ts +1 -1
  185. package/dist/types/src/cms/client/interfaces/components/resources/post/category/category-table.d.ts.map +1 -1
  186. package/dist/types/src/cms/client/interfaces/components/resources/post/content/post-create-content.d.ts +3 -5
  187. package/dist/types/src/cms/client/interfaces/components/resources/post/content/post-create-content.d.ts.map +1 -1
  188. package/dist/types/src/cms/client/interfaces/components/resources/post/content/post-edit-content.d.ts.map +1 -1
  189. package/dist/types/src/cms/client/interfaces/components/resources/post/content/post-show-content.d.ts.map +1 -1
  190. package/dist/types/src/cms/client/interfaces/components/resources/post/post-card.d.ts +3 -1
  191. package/dist/types/src/cms/client/interfaces/components/resources/post/post-card.d.ts.map +1 -1
  192. package/dist/types/src/cms/client/interfaces/components/resources/post/post-list.d.ts +6 -3
  193. package/dist/types/src/cms/client/interfaces/components/resources/post/post-list.d.ts.map +1 -1
  194. package/dist/types/src/cms/client/interfaces/components/resources/post/post-state-icons.d.ts.map +1 -1
  195. package/dist/types/src/cms/client/interfaces/components/resources/post/post-table.d.ts +3 -1
  196. package/dist/types/src/cms/client/interfaces/components/resources/post/post-table.d.ts.map +1 -1
  197. package/dist/types/src/cms/client/interfaces/components/resources/post/search/control-fields-filters.d.ts.map +1 -1
  198. package/dist/types/src/cms/client/interfaces/components/resources/seo-metadata/seo-form/seo-form.d.ts +5 -2
  199. package/dist/types/src/cms/client/interfaces/components/resources/seo-metadata/seo-form/seo-form.d.ts.map +1 -1
  200. package/dist/types/src/cms/client/interfaces/components/resources/seo-metadata/seo-metadata-dialog.d.ts +2 -1
  201. package/dist/types/src/cms/client/interfaces/components/resources/seo-metadata/seo-metadata-dialog.d.ts.map +1 -1
  202. package/dist/types/src/cms/client/interfaces/components/ui/blocks/list-container/list-container.d.ts.map +1 -1
  203. package/dist/types/src/cms/client/interfaces/components/ui/features/accordion/accordion-header.d.ts +3 -1
  204. package/dist/types/src/cms/client/interfaces/components/ui/features/accordion/accordion-header.d.ts.map +1 -1
  205. package/dist/types/src/cms/client/interfaces/components/ui/features/accordion/accordion.d.ts +2 -1
  206. package/dist/types/src/cms/client/interfaces/components/ui/features/accordion/accordion.d.ts.map +1 -1
  207. package/dist/types/src/cms/client/interfaces/components/ui/form/control-fields/control-fields-display.d.ts.map +1 -1
  208. package/dist/types/src/cms/client/interfaces/components/ui/form/control-fields/control-fields-input.d.ts.map +1 -1
  209. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/[id]/edit/page.d.ts +1 -1
  210. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/[id]/edit/page.d.ts.map +1 -1
  211. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/[id]/page.d.ts +3 -1
  212. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/[id]/page.d.ts.map +1 -1
  213. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/[id]/relations/page.d.ts +3 -1
  214. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/[id]/relations/page.d.ts.map +1 -1
  215. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/create/page.d.ts +4 -7
  216. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/category/create/page.d.ts.map +1 -1
  217. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/page.d.ts +1 -4
  218. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/page.d.ts.map +1 -1
  219. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/post/[id]/edit/page.d.ts.map +1 -1
  220. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/post/[id]/page.d.ts.map +1 -1
  221. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/post/[id]/relations/page.d.ts.map +1 -1
  222. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/post/create/page.d.ts +4 -7
  223. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/post/create/page.d.ts.map +1 -1
  224. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/[id]/edit/page.d.ts +1 -1
  225. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/[id]/edit/page.d.ts.map +1 -1
  226. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/[id]/page.d.ts +3 -1
  227. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/[id]/page.d.ts.map +1 -1
  228. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/[id]/relations/page.d.ts.map +1 -1
  229. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/create/page.d.ts +4 -7
  230. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/[topicSlug]/subcategory/create/page.d.ts.map +1 -1
  231. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/page.d.ts +1 -3
  232. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/page.d.ts.map +1 -1
  233. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/[id]/page.d.ts.map +1 -1
  234. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/[id]/relations/page.d.ts +3 -1
  235. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/tag/[id]/relations/page.d.ts.map +1 -1
  236. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/trash/index.d.ts +2 -0
  237. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/trash/index.d.ts.map +1 -0
  238. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/trash/page.d.ts +18 -0
  239. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/trash/page.d.ts.map +1 -0
  240. package/dist/types/src/cms/client/interfaces/pages/dashboard/system/access/admin/[id]/relations/page.d.ts +3 -1
  241. package/dist/types/src/cms/client/interfaces/pages/dashboard/system/access/admin/[id]/relations/page.d.ts.map +1 -1
  242. package/dist/types/src/cms/client/interfaces/pages/dashboard/system/storage/file/[id]/relations/page.d.ts +5 -6
  243. package/dist/types/src/cms/client/interfaces/pages/dashboard/system/storage/file/[id]/relations/page.d.ts.map +1 -1
  244. package/dist/types/src/cms/client/interfaces/pages/dashboard/system/storage/trash/page.d.ts.map +1 -1
  245. package/dist/types/src/cms/client/interfaces/pages/dashboard/website/website-page/[slug]/edit/page.d.ts +7 -9
  246. package/dist/types/src/cms/client/interfaces/pages/dashboard/website/website-page/[slug]/edit/page.d.ts.map +1 -1
  247. package/dist/types/src/cms/client/interfaces/pages/dashboard/website/website-page/[slug]/page.d.ts +7 -9
  248. package/dist/types/src/cms/client/interfaces/pages/dashboard/website/website-page/[slug]/page.d.ts.map +1 -1
  249. package/dist/types/src/cms/client/interfaces/pages/dashboard/website/website-page/page.d.ts +3 -3
  250. package/dist/types/src/cms/client/interfaces/pages/dashboard/website/website-page/page.d.ts.map +1 -1
  251. package/dist/types/src/cms/client/interfaces/pages/index.d.ts +1 -1
  252. package/dist/types/src/cms/client/interfaces/pages/index.d.ts.map +1 -1
  253. package/dist/types/src/cms/contracts/resources/page/actions.d.ts +7 -0
  254. package/dist/types/src/cms/contracts/resources/page/actions.d.ts.map +1 -0
  255. package/dist/types/src/cms/contracts/resources/post/actions.d.ts +2 -0
  256. package/dist/types/src/cms/contracts/resources/post/actions.d.ts.map +1 -1
  257. package/dist/types/src/cms/contracts/resources/post/form-data.d.ts +1 -1
  258. package/dist/types/src/cms/contracts/resources/post/form-data.d.ts.map +1 -1
  259. package/dist/types/src/cms/contracts/resources/seo-metadata/form-data.d.ts +2 -2
  260. package/dist/types/src/cms/contracts/resources/seo-metadata/form-data.d.ts.map +1 -1
  261. package/dist/types/src/cms/server/create-cms-server.d.ts +7 -0
  262. package/dist/types/src/cms/server/create-cms-server.d.ts.map +1 -1
  263. package/dist/types/src/cms/server/index.d.ts +1 -1
  264. package/dist/types/src/cms/server/index.d.ts.map +1 -1
  265. package/dist/types/src/cms/server/resources/index.d.ts +1 -0
  266. package/dist/types/src/cms/server/resources/index.d.ts.map +1 -1
  267. package/dist/types/src/cms/server/resources/page/actions.d.ts +8 -0
  268. package/dist/types/src/cms/server/resources/page/actions.d.ts.map +1 -0
  269. package/dist/types/src/cms/server/resources/post/actions.d.ts +2 -0
  270. package/dist/types/src/cms/server/resources/post/actions.d.ts.map +1 -1
  271. package/dist/types/src/cms/server/resources/seo-metadata/actions.d.ts.map +1 -1
  272. package/dist/types/src/config/content-ui.d.ts +14 -0
  273. package/dist/types/src/config/content-ui.d.ts.map +1 -0
  274. package/dist/types/src/config/index.d.ts +2 -0
  275. package/dist/types/src/config/index.d.ts.map +1 -1
  276. package/dist/types/src/config/page.d.ts +4 -0
  277. package/dist/types/src/config/page.d.ts.map +1 -0
  278. package/dist/types/src/config/topics.d.ts +2 -2
  279. package/dist/types/src/config/topics.d.ts.map +1 -1
  280. package/dist/types/src/constants/paths/cms-paths.d.ts +3 -3
  281. package/dist/types/src/core/infrastructure/index.d.ts +1 -0
  282. package/dist/types/src/core/infrastructure/index.d.ts.map +1 -1
  283. package/dist/types/src/core/infrastructure/prisma/file/include.d.ts +121 -0
  284. package/dist/types/src/core/infrastructure/prisma/file/include.d.ts.map +1 -1
  285. package/dist/types/src/core/infrastructure/prisma/file/mappers.d.ts.map +1 -1
  286. package/dist/types/src/core/infrastructure/prisma/helpers/active-file-references.d.ts +1 -1
  287. package/dist/types/src/core/infrastructure/prisma/helpers/active-file-references.d.ts.map +1 -1
  288. package/dist/types/src/core/infrastructure/prisma/index.d.ts +1 -0
  289. package/dist/types/src/core/infrastructure/prisma/index.d.ts.map +1 -1
  290. package/dist/types/src/core/infrastructure/prisma/page/include.d.ts +63 -0
  291. package/dist/types/src/core/infrastructure/prisma/page/include.d.ts.map +1 -0
  292. package/dist/types/src/core/infrastructure/prisma/page/index.d.ts +4 -0
  293. package/dist/types/src/core/infrastructure/prisma/page/index.d.ts.map +1 -0
  294. package/dist/types/src/core/infrastructure/prisma/page/mappers.d.ts +9 -0
  295. package/dist/types/src/core/infrastructure/prisma/page/mappers.d.ts.map +1 -0
  296. package/dist/types/src/core/infrastructure/prisma/page/page-prisma-ports.d.ts +7 -0
  297. package/dist/types/src/core/infrastructure/prisma/page/page-prisma-ports.d.ts.map +1 -0
  298. package/dist/types/src/core/infrastructure/prisma/page/types.d.ts +10 -0
  299. package/dist/types/src/core/infrastructure/prisma/page/types.d.ts.map +1 -0
  300. package/dist/types/src/core/infrastructure/prisma/post/include.d.ts +0 -29
  301. package/dist/types/src/core/infrastructure/prisma/post/include.d.ts.map +1 -1
  302. package/dist/types/src/core/infrastructure/prisma/post/lifecycle.d.ts +66 -0
  303. package/dist/types/src/core/infrastructure/prisma/post/lifecycle.d.ts.map +1 -0
  304. package/dist/types/src/core/infrastructure/prisma/post/mappers.d.ts.map +1 -1
  305. package/dist/types/src/core/infrastructure/prisma/post/post-prisma-ports.d.ts.map +1 -1
  306. package/dist/types/src/core/infrastructure/prisma/post/read-scope.d.ts +271 -0
  307. package/dist/types/src/core/infrastructure/prisma/post/read-scope.d.ts.map +1 -0
  308. package/dist/types/src/core/infrastructure/prisma/seo-metadata/mappers.d.ts +1 -1
  309. package/dist/types/src/core/infrastructure/prisma/seo-metadata/mappers.d.ts.map +1 -1
  310. package/dist/types/src/core/infrastructure/prisma/seo-metadata/seo-metadata-prisma-ports.d.ts +2 -2
  311. package/dist/types/src/core/infrastructure/prisma/seo-metadata/seo-metadata-prisma-ports.d.ts.map +1 -1
  312. package/dist/types/src/core/seeders/page/seeder.d.ts +3 -3
  313. package/dist/types/src/core/seeders/page/seeder.d.ts.map +1 -1
  314. package/dist/types/src/core/seeders/seed.d.ts +2 -3
  315. package/dist/types/src/core/seeders/seed.d.ts.map +1 -1
  316. package/dist/types/src/core/sitero-server/create-sitero-server.d.ts.map +1 -1
  317. package/dist/types/src/core/sitero-server/types.d.ts +2 -0
  318. package/dist/types/src/core/sitero-server/types.d.ts.map +1 -1
  319. package/dist/types/src/shared/list-item.d.ts +1 -0
  320. package/dist/types/src/shared/list-item.d.ts.map +1 -1
  321. package/dist/types/src/web/contracts/index.d.ts +1 -0
  322. package/dist/types/src/web/contracts/index.d.ts.map +1 -1
  323. package/dist/types/src/web/contracts/resources/page/actions.d.ts +5 -0
  324. package/dist/types/src/web/contracts/resources/page/actions.d.ts.map +1 -0
  325. package/dist/types/src/web/contracts/resources/post/actions.d.ts +1 -1
  326. package/dist/types/src/web/contracts/resources/post/actions.d.ts.map +1 -1
  327. package/dist/types/src/web/server/create-web-server.d.ts.map +1 -1
  328. package/dist/types/src/web/server/index.d.ts +1 -1
  329. package/dist/types/src/web/server/index.d.ts.map +1 -1
  330. package/dist/types/src/web/server/resources/index.d.ts +1 -0
  331. package/dist/types/src/web/server/resources/index.d.ts.map +1 -1
  332. package/dist/types/src/web/server/resources/page/actions.d.ts +17 -0
  333. package/dist/types/src/web/server/resources/page/actions.d.ts.map +1 -0
  334. package/dist/types/src/web/server/resources/post/actions.d.ts +1 -6
  335. package/dist/types/src/web/server/resources/post/actions.d.ts.map +1 -1
  336. package/dist/types/src/web/server/seo/metadata/build-metadata.d.ts +5 -2
  337. package/dist/types/src/web/server/seo/metadata/build-metadata.d.ts.map +1 -1
  338. package/dist/types/src/web/server/seo/sitemap/build-entries.d.ts +2 -2
  339. package/dist/types/src/web/server/seo/sitemap/build-entries.d.ts.map +1 -1
  340. package/dist/types/src/web/server/seo/sitemap/get-page-items.d.ts +6 -2
  341. package/dist/types/src/web/server/seo/sitemap/get-page-items.d.ts.map +1 -1
  342. package/dist/types/src/web/server/seo/sitemap/get-post-items.d.ts.map +1 -1
  343. package/dist/types/src/web/server/seo/sitemap/get-subcategory-items.d.ts.map +1 -1
  344. package/dist/types/src/web/server/types.d.ts +6 -2
  345. package/dist/types/src/web/server/types.d.ts.map +1 -1
  346. package/package.json +3 -3
  347. package/dist/src/cms/client/interfaces/components/resources/post/topic/topic-card.js +0 -81
  348. package/dist/src/cms/client/interfaces/components/resources/post/topic/topic-table.js +0 -120
  349. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/_id_/edit/page.js +0 -110
  350. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/_id_/page.js +0 -161
  351. package/dist/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/page.js +0 -103
  352. package/dist/src/core/seeders/topic/seeder.js +0 -47
  353. package/dist/types/src/cms/client/interfaces/components/resources/post/topic/index.d.ts +0 -3
  354. package/dist/types/src/cms/client/interfaces/components/resources/post/topic/index.d.ts.map +0 -1
  355. package/dist/types/src/cms/client/interfaces/components/resources/post/topic/topic-card.d.ts +0 -5
  356. package/dist/types/src/cms/client/interfaces/components/resources/post/topic/topic-card.d.ts.map +0 -1
  357. package/dist/types/src/cms/client/interfaces/components/resources/post/topic/topic-table.d.ts +0 -3
  358. package/dist/types/src/cms/client/interfaces/components/resources/post/topic/topic-table.d.ts.map +0 -1
  359. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/[id]/edit/page.d.ts +0 -20
  360. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/[id]/edit/page.d.ts.map +0 -1
  361. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/[id]/page.d.ts +0 -20
  362. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/[id]/page.d.ts.map +0 -1
  363. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/index.d.ts +0 -4
  364. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/index.d.ts.map +0 -1
  365. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/page.d.ts +0 -14
  366. package/dist/types/src/cms/client/interfaces/pages/dashboard/content/content-management/topic/page.d.ts.map +0 -1
  367. package/dist/types/src/core/seeders/topic/seeder.d.ts +0 -10
  368. package/dist/types/src/core/seeders/topic/seeder.d.ts.map +0 -1
@@ -0,0 +1,108 @@
1
+ import { POST_ERROR_CODES, OperationError } from 'sitero-server';
2
+
3
+ async function lockPostWrites(tx) {
4
+ await tx.$queryRaw`SELECT pg_advisory_xact_lock(1936286821, 1)::text`;
5
+ }
6
+ function fail(code, ids = []) {
7
+ throw new OperationError({ code, details: { postIds: ids } });
8
+ }
9
+ async function requirePost(tx, id, deleted = false) {
10
+ const post = await tx.post.findUnique({ where: { id } });
11
+ if (!post) fail(POST_ERROR_CODES.NOT_FOUND);
12
+ if (!!post.deletedAt !== deleted) fail(POST_ERROR_CODES.INVALID_STATE);
13
+ return post;
14
+ }
15
+ async function assertNoPostReferences(tx, id) {
16
+ const references = await tx.post.findMany({
17
+ where: {
18
+ id: { not: id },
19
+ OR: [
20
+ { parents: { some: { id } } },
21
+ { tags: { some: { id } } },
22
+ { relatedPosts: { some: { id } } }
23
+ ]
24
+ },
25
+ select: { id: true }
26
+ });
27
+ if (references.length)
28
+ fail(
29
+ POST_ERROR_CODES.IN_USE,
30
+ references.map(({ id: id2 }) => id2)
31
+ );
32
+ }
33
+ async function assertPublishedAncestors(tx, ids) {
34
+ const visited = /* @__PURE__ */ new Set();
35
+ let pending = ids;
36
+ while (pending.length) {
37
+ const batch = [...new Set(pending)].filter((id) => !visited.has(id));
38
+ if (!batch.length) break;
39
+ batch.forEach((id) => visited.add(id));
40
+ const parents = await tx.post.findMany({
41
+ where: { id: { in: batch } },
42
+ include: { parents: { select: { id: true } } }
43
+ });
44
+ const unavailable = batch.filter(
45
+ (id) => !parents.some((p) => p.id === id && p.isActive && !p.deletedAt)
46
+ );
47
+ if (unavailable.length)
48
+ fail(POST_ERROR_CODES.PARENT_UNPUBLISHED, unavailable);
49
+ pending = parents.flatMap((p) => p.parents.map(({ id }) => id));
50
+ }
51
+ }
52
+ async function assertNoPublishedDescendants(tx, id) {
53
+ const visited = /* @__PURE__ */ new Set([id]);
54
+ let pending = [id];
55
+ while (pending.length) {
56
+ const children = await tx.post.findMany({
57
+ where: { parents: { some: { id: { in: pending } } } },
58
+ select: { id: true, isActive: true, deletedAt: true }
59
+ });
60
+ const published = children.filter(
61
+ (child) => child.isActive && !child.deletedAt
62
+ );
63
+ if (published.length)
64
+ fail(
65
+ POST_ERROR_CODES.HAS_PUBLISHED_CHILDREN,
66
+ published.map(({ id: id2 }) => id2)
67
+ );
68
+ pending = children.map(({ id: id2 }) => id2).filter((id2) => !visited.has(id2));
69
+ pending.forEach((id2) => visited.add(id2));
70
+ }
71
+ }
72
+ async function assertPostWrite(tx, input, id, previous) {
73
+ const type = previous?.type ?? input.type;
74
+ const topicKey = previous ? previous.topicKey : input.topicKey;
75
+ const slug = input.slug?.trim() || id;
76
+ const conflict = await tx.post.findFirst({
77
+ where: { type, topicKey, slug, id: { not: id } },
78
+ select: { id: true }
79
+ });
80
+ if (conflict) fail(POST_ERROR_CODES.SLUG_CONFLICT, [conflict.id]);
81
+ const ids = [
82
+ ...new Set(
83
+ [...input.parents, ...input.tags, ...input.relatedPosts].map(
84
+ ({ id: id2 }) => id2
85
+ )
86
+ )
87
+ ];
88
+ if (ids.length) {
89
+ const records = await tx.post.findMany({
90
+ where: { id: { in: ids }, deletedAt: null },
91
+ select: { id: true }
92
+ });
93
+ const unavailable = ids.filter(
94
+ (id2) => !records.some((record) => record.id === id2)
95
+ );
96
+ if (unavailable.length)
97
+ fail(POST_ERROR_CODES.REFERENCE_UNAVAILABLE, unavailable);
98
+ }
99
+ if (input.isActive)
100
+ await assertPublishedAncestors(
101
+ tx,
102
+ input.parents.map(({ id: id2 }) => id2)
103
+ );
104
+ if (!input.isActive && (type === "CATEGORY" || type === "SUBCATEGORY"))
105
+ await assertNoPublishedDescendants(tx, id);
106
+ }
107
+
108
+ export { assertNoPostReferences, assertPostWrite, lockPostWrites, requirePost };
@@ -27,7 +27,6 @@ function postReferenceWithCoverToDomain(post) {
27
27
  function postListCardToDomain(post) {
28
28
  return {
29
29
  ...postReferenceWithCoverToDomain(post),
30
- topic: post.topic ? postReferenceToDomain(post.topic) : null,
31
30
  parents: post.parents.map(postReferenceWithCoverToDomain)
32
31
  };
33
32
  }
@@ -36,7 +35,6 @@ function postDetailToDomain(post) {
36
35
  return {
37
36
  ...postListCardToDomain(post),
38
37
  author,
39
- postsInTopic: post.postsInTopic.map(postReferenceToDomain),
40
38
  children: post.children.map(postReferenceToDomain),
41
39
  tags: post.tags.map(postReferenceToDomain),
42
40
  taggedPosts: post.taggedPosts.map(postReferenceToDomain),
@@ -1,10 +1,13 @@
1
+ import { OperationError, POST_ERROR_CODES } from 'sitero-server';
1
2
  import { ulid } from 'ulid';
2
3
  import { withActiveFileReferences } from '../helpers/active-file-references.js';
3
4
  import { connectOrDisconnectOne, setMany, connectOne, connectMany } from '../helpers/relation-writes.js';
4
5
  import { createSearchWhere } from '../helpers/search-where.js';
5
6
  import { postToDomain } from './base-mappers.js';
6
- import { POST_RELATIONS_INCLUDE, POST_DETAIL_INCLUDE, POST_LIST_CARD_INCLUDE, POST_REFERENCE_INCLUDE } from './include.js';
7
+ import { POST_RELATIONS_INCLUDE, POST_REFERENCE_INCLUDE } from './include.js';
8
+ import { lockPostWrites, requirePost, assertNoPostReferences, assertPostWrite } from './lifecycle.js';
7
9
  import { postRelationsToDomain, postListCardToDomain, postDetailToDomain, postReferenceToDomain } from './mappers.js';
10
+ import { postReadWhere, postDetailInclude, postListInclude } from './read-scope.js';
8
11
 
9
12
  const SEARCH_TEXT_FIELDS = [
10
13
  "text1",
@@ -55,6 +58,7 @@ function createPostPrismaPorts(prisma) {
55
58
  // ------------------------------------------------------------
56
59
  postCommandPort: {
57
60
  async create(input) {
61
+ const id = ulid();
58
62
  return withActiveFileReferences(
59
63
  prisma,
60
64
  [
@@ -68,10 +72,8 @@ function createPostPrismaPorts(prisma) {
68
72
  input.file4
69
73
  ],
70
74
  async (transaction) => {
71
- const id = ulid();
72
75
  const {
73
76
  author,
74
- topic,
75
77
  parents,
76
78
  tags,
77
79
  relatedPosts,
@@ -88,7 +90,6 @@ function createPostPrismaPorts(prisma) {
88
90
  ...scalars
89
91
  } = input;
90
92
  const authorWrite = connectOne(author);
91
- const topicWrite = connectOne(topic);
92
93
  const coverImageWrite = connectOne(coverImage);
93
94
  const file1Write = connectOne(file1);
94
95
  const file2Write = connectOne(file2);
@@ -100,7 +101,6 @@ function createPostPrismaPorts(prisma) {
100
101
  id,
101
102
  slug: slug?.trim() || id,
102
103
  ...authorWrite ? { author: authorWrite } : {},
103
- ...topicWrite ? { topic: topicWrite } : {},
104
104
  parents: connectMany(parents),
105
105
  tags: connectMany(tags),
106
106
  relatedPosts: connectMany(relatedPosts),
@@ -116,6 +116,10 @@ function createPostPrismaPorts(prisma) {
116
116
  }
117
117
  });
118
118
  return postToDomain(post);
119
+ },
120
+ async (tx) => {
121
+ await lockPostWrites(tx);
122
+ await assertPostWrite(tx, input, id);
119
123
  }
120
124
  );
121
125
  },
@@ -136,7 +140,6 @@ function createPostPrismaPorts(prisma) {
136
140
  const {
137
141
  id,
138
142
  author,
139
- topic,
140
143
  parents,
141
144
  tags,
142
145
  relatedPosts,
@@ -153,12 +156,11 @@ function createPostPrismaPorts(prisma) {
153
156
  ...scalars
154
157
  } = input;
155
158
  const post = await transaction.post.update({
156
- where: { id },
159
+ where: { id, deletedAt: null },
157
160
  data: {
158
161
  ...scalars,
159
162
  slug: slug?.trim() || id,
160
163
  author: connectOrDisconnectOne(author),
161
- topic: connectOrDisconnectOne(topic),
162
164
  parents: setMany(parents),
163
165
  tags: setMany(tags),
164
166
  relatedPosts: setMany(relatedPosts),
@@ -182,13 +184,54 @@ function createPostPrismaPorts(prisma) {
182
184
  }
183
185
  });
184
186
  return postToDomain(post);
187
+ },
188
+ async (tx) => {
189
+ await lockPostWrites(tx);
190
+ const previous = await requirePost(tx, input.id);
191
+ await assertPostWrite(tx, input, input.id, previous);
185
192
  }
186
193
  );
187
194
  },
188
195
  async delete({ id }) {
189
- return postToDomain(
190
- await prisma.post.delete({ where: { id, isLocked: false } })
191
- );
196
+ return prisma.$transaction(async (tx) => {
197
+ await lockPostWrites(tx);
198
+ const post = await requirePost(tx, id);
199
+ if (post.isLocked)
200
+ throw new OperationError({ code: POST_ERROR_CODES.DELETE_LOCKED });
201
+ await assertNoPostReferences(tx, id);
202
+ return postToDomain(
203
+ await tx.post.update({
204
+ where: { id, deletedAt: null, isLocked: false },
205
+ data: { deletedAt: /* @__PURE__ */ new Date(), isActive: false }
206
+ })
207
+ );
208
+ });
209
+ },
210
+ async restore({ id }) {
211
+ return prisma.$transaction(async (tx) => {
212
+ await lockPostWrites(tx);
213
+ await requirePost(tx, id, true);
214
+ return postToDomain(
215
+ await tx.post.update({
216
+ where: { id, deletedAt: { not: null } },
217
+ data: { deletedAt: null, isActive: false }
218
+ })
219
+ );
220
+ });
221
+ },
222
+ async purge({ id }) {
223
+ return prisma.$transaction(async (tx) => {
224
+ await lockPostWrites(tx);
225
+ const post = await requirePost(tx, id, true);
226
+ if (post.isLocked)
227
+ throw new OperationError({ code: POST_ERROR_CODES.DELETE_LOCKED });
228
+ await assertNoPostReferences(tx, id);
229
+ return postToDomain(
230
+ await tx.post.delete({
231
+ where: { id, deletedAt: { not: null }, isLocked: false }
232
+ })
233
+ );
234
+ });
192
235
  }
193
236
  },
194
237
  // ------------------------------------------------------------
@@ -198,8 +241,9 @@ function createPostPrismaPorts(prisma) {
198
241
  async findMany(input) {
199
242
  const posts = await prisma.post.findMany({
200
243
  where: {
244
+ ...postReadWhere(input),
201
245
  ...input?.type ? { type: input.type } : {},
202
- ...input?.topicId === void 0 ? {} : { topicId: input.topicId },
246
+ ...input?.topicKey === void 0 ? {} : { topicKey: input.topicKey },
203
247
  ...input?.postIds ? { id: { in: input.postIds } } : {}
204
248
  },
205
249
  orderBy,
@@ -227,10 +271,8 @@ function createPostPrismaPorts(prisma) {
227
271
  const where = {
228
272
  ...customStateFilters,
229
273
  ...input.type ? { type: input.type } : {},
230
- ...input.topicId === void 0 ? {} : { topicId: input.topicId },
231
- ...input.topicSlug ? { topic: { slug: input.topicSlug } } : {},
232
- ...input.parentId ? { parents: { some: { id: input.parentId } } } : {},
233
- ...input.parentSlug ? { parents: { some: { slug: input.parentSlug } } } : {},
274
+ ...input.topicKey === void 0 ? {} : { topicKey: input.topicKey },
275
+ ...input.topicSlug ? { AND: [{ topicKey: input.topicSlug }] } : {},
234
276
  ...input.authorId ? { authorId: input.authorId } : {},
235
277
  ...input.postIds || input.excludeIds ? {
236
278
  id: {
@@ -253,16 +295,24 @@ function createPostPrismaPorts(prisma) {
253
295
  })
254
296
  };
255
297
  const pagination = input.page && input.pageSize ? { skip: (input.page - 1) * input.pageSize, take: input.pageSize } : {};
298
+ const scopedWhere = {
299
+ AND: [
300
+ where,
301
+ postReadWhere(input),
302
+ ...input.parentId ? [{ parents: { some: { id: input.parentId } } }] : [],
303
+ ...input.parentSlug ? [{ parents: { some: { slug: input.parentSlug } } }] : []
304
+ ]
305
+ };
256
306
  const findManyInput = {
257
- where,
307
+ where: scopedWhere,
258
308
  orderBy,
259
- include: POST_LIST_CARD_INCLUDE,
309
+ include: postListInclude(input),
260
310
  ...pagination
261
311
  };
262
312
  const result = await prisma.$transaction(async (transaction) => {
263
313
  const [items, total] = await Promise.all([
264
314
  transaction.post.findMany(findManyInput),
265
- transaction.post.count({ where })
315
+ transaction.post.count({ where: scopedWhere })
266
316
  ]);
267
317
  return { items, total };
268
318
  });
@@ -274,17 +324,19 @@ function createPostPrismaPorts(prisma) {
274
324
  async findDetail(input) {
275
325
  const lookup = "id" in input ? { id: input.id } : { type: input.type, slug: input.slug };
276
326
  const scope = {
327
+ AND: [postReadWhere(input)],
277
328
  ...input.isActive === void 0 ? {} : { isActive: input.isActive },
278
- ...input.topicSlug ? { topic: { slug: input.topicSlug } } : {}
329
+ ...input.topicSlug ? { topicKey: input.topicSlug } : {}
279
330
  };
280
331
  const post = await prisma.post.findFirst({
281
332
  where: { ...scope, ...lookup },
282
- include: POST_DETAIL_INCLUDE
333
+ include: postDetailInclude(input)
283
334
  });
284
335
  if (!post) return { post: null, previous: null, next: null };
285
336
  const adjacentWhere = {
286
337
  ...scope,
287
- ..."id" in input ? {} : { type: input.type }
338
+ type: post.type,
339
+ topicKey: post.topicKey
288
340
  };
289
341
  const [previous, next] = await Promise.all([
290
342
  prisma.post.findFirst({
@@ -292,14 +344,14 @@ function createPostPrismaPorts(prisma) {
292
344
  orderBy: orderBy.map(reverseOrderBy),
293
345
  cursor: { id: post.id },
294
346
  skip: 1,
295
- include: POST_LIST_CARD_INCLUDE
347
+ include: postListInclude(input)
296
348
  }),
297
349
  prisma.post.findFirst({
298
350
  where: adjacentWhere,
299
351
  orderBy,
300
352
  cursor: { id: post.id },
301
353
  skip: 1,
302
- include: POST_LIST_CARD_INCLUDE
354
+ include: postListInclude(input)
303
355
  })
304
356
  ]);
305
357
  return {
@@ -0,0 +1,45 @@
1
+ import { POST_DETAIL_INCLUDE, POST_REFERENCE_INCLUDE, POST_LIST_CARD_INCLUDE, POST_REFERENCE_WITH_COVER_INCLUDE } from './include.js';
2
+
3
+ const active = { isActive: true, deletedAt: null };
4
+ const publishedParent = {
5
+ ...active,
6
+ parents: { every: active }
7
+ };
8
+ const PUBLIC_POST_WHERE = {
9
+ ...active,
10
+ parents: { every: publishedParent }
11
+ };
12
+ function postReadWhere(scope) {
13
+ const deletion = scope?.deletion === "all" ? {} : {
14
+ deletedAt: scope?.deletion === "deleted" ? { not: null } : null
15
+ };
16
+ return scope?.visibility === "public" ? { AND: [PUBLIC_POST_WHERE, deletion] } : deletion;
17
+ }
18
+ function postListInclude(scope) {
19
+ if (scope?.visibility !== "public") return POST_LIST_CARD_INCLUDE;
20
+ return {
21
+ ...POST_LIST_CARD_INCLUDE,
22
+ parents: {
23
+ where: PUBLIC_POST_WHERE,
24
+ include: POST_REFERENCE_WITH_COVER_INCLUDE
25
+ }
26
+ };
27
+ }
28
+ function postDetailInclude(scope) {
29
+ if (scope?.visibility !== "public") return POST_DETAIL_INCLUDE;
30
+ const reference = {
31
+ where: PUBLIC_POST_WHERE,
32
+ include: POST_REFERENCE_INCLUDE
33
+ };
34
+ return {
35
+ ...POST_DETAIL_INCLUDE,
36
+ ...postListInclude(scope),
37
+ children: reference,
38
+ tags: reference,
39
+ taggedPosts: reference,
40
+ relatedPosts: { where: PUBLIC_POST_WHERE, include: postListInclude(scope) },
41
+ referencingPosts: reference
42
+ };
43
+ }
44
+
45
+ export { PUBLIC_POST_WHERE, postDetailInclude, postListInclude, postReadWhere };
@@ -6,8 +6,13 @@ function seoMetadataToWrite(data) {
6
6
  };
7
7
  }
8
8
  function seoMetadataToDomain(seoMetadata) {
9
+ const { postId, pageId, ...data } = seoMetadata;
10
+ if (postId != null === (pageId != null))
11
+ throw new Error("Invalid SEO metadata owner");
12
+ const owner = postId != null ? { postId, pageId: null } : { pageId, postId: null };
9
13
  return {
10
- ...seoMetadata,
14
+ ...data,
15
+ ...owner,
11
16
  alternate: seoMetadata.alternate,
12
17
  jsonLd: seoMetadata.jsonLd
13
18
  };
@@ -1,3 +1,4 @@
1
+ import { lockPostWrites, requirePost } from '../post/lifecycle.js';
1
2
  import { seoMetadataToWrite, seoMetadataToDomain } from './mappers.js';
2
3
 
3
4
  function createSeoMetadataPrismaPorts(prisma) {
@@ -6,17 +7,37 @@ function createSeoMetadataPrismaPorts(prisma) {
6
7
  // Command
7
8
  // ------------------------------------------------------------
8
9
  seoMetadataCommandPort: {
9
- async upsert({ postId, translations }) {
10
- const seoMetadatas = await prisma.$transaction(
11
- translations.map((translation) => {
12
- const data = seoMetadataToWrite(translation);
13
- return prisma.seoMetadata.upsert({
14
- where: { postId_locale: { postId, locale: translation.locale } },
15
- update: data,
16
- create: { postId, ...data }
17
- });
18
- })
19
- );
10
+ async upsert(input) {
11
+ const { translations } = input;
12
+ const seoMetadatas = await prisma.$transaction(async (tx) => {
13
+ if (input.postId !== void 0) {
14
+ await lockPostWrites(tx);
15
+ await requirePost(tx, input.postId);
16
+ }
17
+ return Promise.all(
18
+ translations.map((translation) => {
19
+ const data = seoMetadataToWrite(translation);
20
+ return tx.seoMetadata.upsert({
21
+ where: input.postId !== void 0 ? {
22
+ postId_locale: {
23
+ postId: input.postId,
24
+ locale: translation.locale
25
+ }
26
+ } : {
27
+ pageId_locale: {
28
+ pageId: input.pageId,
29
+ locale: translation.locale
30
+ }
31
+ },
32
+ update: data,
33
+ create: {
34
+ ...data,
35
+ ...input.postId !== void 0 ? { postId: input.postId, pageId: null } : { pageId: input.pageId, postId: null }
36
+ }
37
+ });
38
+ })
39
+ );
40
+ });
20
41
  return seoMetadatas.map(seoMetadataToDomain);
21
42
  }
22
43
  }
@@ -1,39 +1,19 @@
1
- import { POST_TYPES } from 'sitero-domain';
2
-
3
1
  function pageSeeder({
4
2
  prisma,
5
- pages: staticPages,
3
+ pages,
6
4
  locales
7
5
  }) {
8
- async function checkExistence(slug) {
9
- const page = await prisma.post.findFirst({
10
- where: { type: POST_TYPES.PAGE, slug },
11
- select: { id: true }
12
- });
13
- return page ? true : false;
14
- }
15
6
  async function seed() {
16
- const pages = Object.entries(staticPages).map(([slug, data]) => ({
17
- slug,
18
- ...data
19
- }));
20
- for (const [i, item] of pages.entries()) {
21
- const exists = await checkExistence(item.slug);
22
- if (exists) continue;
23
- await prisma.post.create({
24
- data: {
25
- type: POST_TYPES.PAGE,
26
- // states
27
- isActive: true,
28
- isSlugActive: true,
29
- slug: item.slug,
30
- isIndexActive: true,
31
- index: i + 1,
32
- // translation
7
+ for (const [key, page] of Object.entries(pages)) {
8
+ await prisma.page.upsert({
9
+ where: { key },
10
+ update: {},
11
+ create: {
12
+ key,
33
13
  translations: {
34
- create: locales.map((locale) => ({
14
+ create: [...new Set(locales)].map((locale) => ({
35
15
  locale,
36
- title: item.title[locale]
16
+ title: page.title[locale] ?? null
37
17
  }))
38
18
  }
39
19
  }
@@ -1,20 +1,17 @@
1
1
  import { adminSeeder } from './admin/seeder.js';
2
2
  import { configSeeder } from './config/seeder.js';
3
3
  import { pageSeeder } from './page/seeder.js';
4
- import { topicSeeder } from './topic/seeder.js';
5
4
 
6
5
  async function seed({
7
6
  prisma,
8
7
  webLocales: locales,
9
8
  admins,
10
9
  pages,
11
- topics,
12
10
  configs
13
11
  }) {
14
12
  const siteroPrisma = prisma;
15
13
  await adminSeeder({ prisma: siteroPrisma, locales, admins }).seed();
16
14
  await pageSeeder({ prisma: siteroPrisma, locales, pages }).seed();
17
- await topicSeeder({ prisma: siteroPrisma, locales, topics }).seed();
18
15
  await configSeeder({ prisma: siteroPrisma, locales, configs }).seed();
19
16
  }
20
17
 
@@ -10,6 +10,8 @@ import { createFilePrismaPorts } from '../infrastructure/prisma/file/file-prisma
10
10
  import { createInquiryPrismaPorts } from '../infrastructure/prisma/inquiry/inquiry-prisma-ports.js';
11
11
  import { createPostPrismaPorts } from '../infrastructure/prisma/post/post-prisma-ports.js';
12
12
  import { createSeoMetadataPrismaPorts } from '../infrastructure/prisma/seo-metadata/seo-metadata-prisma-ports.js';
13
+ import { createPagePrismaPorts } from '../infrastructure/prisma/page/page-prisma-ports.js';
14
+ import '../infrastructure/prisma/page/include.js';
13
15
  import { createRedisRateLimiterPort } from '../infrastructure/rate-limiter/create-redis-rate-limiter-port.js';
14
16
  import { getRedisClient } from '../infrastructure/redis/create-redis-client.js';
15
17
  import { createEmailComposition } from './email.js';
@@ -51,12 +53,19 @@ function createSiteroServer(input) {
51
53
  const prisma = input.prisma;
52
54
  const adminPrismaPorts = createAdminPrismaPorts(prisma);
53
55
  const adminRefreshTokenPrismaPorts = createAdminRefreshTokenPrismaPorts(prisma);
56
+ const pagePrismaPorts = createPagePrismaPorts(prisma);
54
57
  const configPrismaPorts = createConfigPrismaPorts(prisma);
55
58
  const filePrismaPorts = createFilePrismaPorts(prisma);
56
59
  const inquiryPrismaPorts = createInquiryPrismaPorts(prisma);
57
60
  const postPrismaPorts = createPostPrismaPorts(prisma);
58
61
  const seoMetadataPrismaPorts = createSeoMetadataPrismaPorts(prisma);
59
62
  return createSiteroServer$1({
63
+ topics: Object.fromEntries(
64
+ Object.entries(input.topics).map(([key, { roles }]) => [
65
+ key,
66
+ { roles: [...roles] }
67
+ ])
68
+ ),
60
69
  authentication: {
61
70
  admin: {
62
71
  refreshTokenTtlSeconds: input.authentication?.refreshTokenTtlSeconds
@@ -79,6 +88,7 @@ function createSiteroServer(input) {
79
88
  }
80
89
  },
81
90
  resources: {
91
+ page: pagePrismaPorts,
82
92
  admin: {
83
93
  adminCommandPort: adminPrismaPorts.adminCommandPort,
84
94
  adminInquiryNotificationRecipientQueryPort: adminPrismaPorts.adminInquiryNotificationRecipientQueryPort,
@@ -5,11 +5,13 @@ import 'zod';
5
5
  import { createWebInquiryActions } from './features/inquiry/actions.js';
6
6
  import { createWebConfigActions } from './resources/config/actions.js';
7
7
  import { createWebPostActions } from './resources/post/actions.js';
8
+ import { createWebPageActions } from './resources/page/actions.js';
8
9
 
9
10
  function createWebServer({
10
11
  siteroServer,
11
12
  staticTopics
12
13
  }) {
14
+ const page = createWebPageActions({ siteroServer });
13
15
  const config = createWebConfigActions({ siteroServer });
14
16
  const inquiry = createWebInquiryActions({
15
17
  siteroServer,
@@ -22,13 +24,15 @@ function createWebServer({
22
24
  inquiry
23
25
  },
24
26
  resources: {
27
+ page: page.actions,
25
28
  config: config.actions,
26
29
  post: post.actions
27
30
  }
28
31
  },
29
32
  loaders: {
30
33
  ...config.loaders,
31
- ...post.loaders
34
+ ...post.loaders,
35
+ ...page.loaders
32
36
  }
33
37
  };
34
38
  }
@@ -0,0 +1,20 @@
1
+ import { operationResult, PageUnavailableError } from 'sitero-server';
2
+
3
+ function createWebPageActions({
4
+ siteroServer
5
+ }) {
6
+ const findDetail = async (input) => {
7
+ const page = siteroServer.resources.page;
8
+ if (!page) return operationResult.failure(new PageUnavailableError());
9
+ return siteroServer.executor.execute(page.findDetail, input, {});
10
+ };
11
+ const loadPage = async ({ pageSlug }) => {
12
+ const result = await findDetail({ key: pageSlug });
13
+ if (result.success) return { page: result.data.page };
14
+ if (result.error.code === "PAGE_NOT_FOUND") return { page: void 0 };
15
+ throw new Error(`[page.loadPage] ${result.error.code}`);
16
+ };
17
+ return { actions: { findDetail }, loaders: { loadPage } };
18
+ }
19
+
20
+ export { createWebPageActions };
@@ -14,7 +14,7 @@ function getSlug(post) {
14
14
  return "slug" in post && typeof post.slug === "string" ? post.slug : "";
15
15
  }
16
16
  function topicHasRole(staticTopics, topicSlug, role) {
17
- const topic = staticTopics[topicSlug];
17
+ const topic = Object.hasOwn(staticTopics, topicSlug) ? staticTopics[topicSlug] : void 0;
18
18
  return !!topic && topic.roles.includes(role);
19
19
  }
20
20
  function createWebPostActions({
@@ -24,7 +24,7 @@ function createWebPostActions({
24
24
  const postFindDetailAction = async (input) => {
25
25
  const result = await siteroServer.executor.execute(
26
26
  siteroServer.resources.post.findDetail,
27
- { ...input, isActive: true },
27
+ { ...input, isActive: true, deletion: "active", visibility: "public" },
28
28
  {}
29
29
  );
30
30
  if (!result.success) return result;
@@ -37,7 +37,7 @@ function createWebPostActions({
37
37
  const postFindListCardsAction = async (input) => {
38
38
  const result = await siteroServer.executor.execute(
39
39
  siteroServer.resources.post.findListCards,
40
- { ...input, isActive: true },
40
+ { ...input, isActive: true, deletion: "active", visibility: "public" },
41
41
  {}
42
42
  );
43
43
  if (!result.success) return result;
@@ -46,15 +46,6 @@ function createWebPostActions({
46
46
  items: result.data.items.map(toWebPostListCard)
47
47
  });
48
48
  };
49
- const loadPage = async ({ pageSlug }) => {
50
- const response = await postFindDetailAction({
51
- type: POST_TYPES.PAGE,
52
- slug: pageSlug
53
- });
54
- return {
55
- page: response.success ? response.data?.post : void 0
56
- };
57
- };
58
49
  const loadCategories = async ({
59
50
  locale,
60
51
  topicSlug,
@@ -230,7 +221,6 @@ function createWebPostActions({
230
221
  findListCards: postFindListCardsAction
231
222
  },
232
223
  loaders: {
233
- loadPage,
234
224
  loadCategories,
235
225
  loadCategory,
236
226
  loadSubcategories,