@cosmicdrift/kumiko-samples 0.377.0 → 0.379.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 (526) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +18 -17
  3. package/packages/bundled-features/src/account-security/feature.ts +2 -2
  4. package/packages/bundled-features/src/account-security/index.ts +8 -8
  5. package/packages/bundled-features/src/account-security/{constants.ts → web/constants.ts} +0 -2
  6. package/packages/bundled-features/src/account-security/{i18n.ts → web/i18n.ts} +0 -1
  7. package/packages/bundled-features/src/admin-shell/feature.ts +10 -9
  8. package/packages/bundled-features/src/admin-shell/index.ts +8 -8
  9. package/packages/bundled-features/src/admin-shell/web/client-plugin.tsx +2 -3
  10. package/packages/bundled-features/src/admin-shell/{constants.ts → web/constants.ts} +0 -1
  11. package/packages/bundled-features/src/admin-shell/web/default-translations.ts +10 -0
  12. package/packages/bundled-features/src/admin-shell/web/i18n.ts +51 -9
  13. package/packages/bundled-features/src/admin-shell/web/index.ts +0 -1
  14. package/packages/bundled-features/src/audit/changes.json +7 -0
  15. package/packages/bundled-features/src/audit/feature.ts +72 -64
  16. package/packages/bundled-features/src/audit/handlers/audit-events.ts +153 -0
  17. package/packages/bundled-features/src/audit/handlers/audit-system-db.ts +13 -0
  18. package/packages/bundled-features/src/audit/handlers/details-all-tenants.query.ts +26 -0
  19. package/packages/bundled-features/src/audit/handlers/details.query.ts +11 -39
  20. package/packages/bundled-features/src/audit/handlers/list-all-tenants.query.ts +47 -0
  21. package/packages/bundled-features/src/audit/handlers/list.query.ts +16 -123
  22. package/packages/bundled-features/src/audit/handlers/resolve-audit-tenant.ts +21 -7
  23. package/packages/bundled-features/src/audit/index.ts +1 -1
  24. package/packages/bundled-features/src/audit/run-escape-hatch-retention.ts +4 -4
  25. package/packages/bundled-features/src/audit/screens.ts +82 -0
  26. package/packages/bundled-features/src/audit/web/client-plugin.tsx +2 -3
  27. package/packages/bundled-features/src/audit/{constants.ts → web/constants.ts} +11 -1
  28. package/packages/bundled-features/src/audit/web/default-translations.ts +7 -0
  29. package/packages/bundled-features/src/audit/web/i18n.ts +33 -7
  30. package/packages/bundled-features/src/audit/web/index.ts +0 -2
  31. package/packages/bundled-features/src/auth-email-password/bootstrap.ts +6 -6
  32. package/packages/bundled-features/src/auth-email-password/changes.json +6 -0
  33. package/packages/bundled-features/src/auth-email-password/errors.ts +1 -1
  34. package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
  35. package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.write.ts +1 -1
  36. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +4 -4
  37. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +3 -3
  38. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  39. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +38 -4
  40. package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -1
  41. package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -1
  42. package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -1
  43. package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +1 -1
  44. package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +1 -1
  45. package/packages/bundled-features/src/auth-email-password/index.ts +6 -1
  46. package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +1 -1
  47. package/packages/bundled-features/src/auth-email-password/signup-activation.ts +1 -1
  48. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +0 -1
  49. package/packages/bundled-features/src/auth-email-password/web/auth-form-logic.ts +0 -1
  50. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +0 -1
  51. package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +0 -1
  52. package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +0 -1
  53. package/packages/bundled-features/src/auth-email-password/web/client-actions.ts +0 -1
  54. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +1 -2
  55. package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +0 -1
  56. package/packages/bundled-features/src/auth-email-password/{constants.ts → web/constants.ts} +3 -6
  57. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +0 -1
  58. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +0 -1
  59. package/packages/bundled-features/src/auth-email-password/{i18n.ts → web/i18n.ts} +3 -4
  60. package/packages/bundled-features/src/auth-email-password/web/index.ts +1 -2
  61. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +2 -3
  62. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +0 -1
  63. package/packages/bundled-features/src/auth-email-password/{mail-i18n.ts → web/mail-i18n.ts} +0 -1
  64. package/packages/bundled-features/src/auth-email-password/web/request-account-unlock-screen.tsx +0 -1
  65. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +0 -1
  66. package/packages/bundled-features/src/auth-email-password/web/session-bootstrap-error.tsx +0 -1
  67. package/packages/bundled-features/src/auth-email-password/web/session.tsx +0 -1
  68. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +2 -3
  69. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +0 -1
  70. package/packages/bundled-features/src/auth-email-password/web/tenant-menu-items.tsx +0 -1
  71. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +0 -1
  72. package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +0 -1
  73. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +0 -1
  74. package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +0 -1
  75. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  76. package/packages/bundled-features/src/auth-mfa/errors.ts +2 -2
  77. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +1 -1
  78. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  79. package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +1 -1
  80. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  81. package/packages/bundled-features/src/auth-mfa/index.ts +8 -8
  82. package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +4 -4
  83. package/packages/bundled-features/src/auth-mfa/screens.ts +1 -1
  84. package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +0 -1
  85. package/packages/bundled-features/src/auth-mfa/{constants.ts → web/constants.ts} +0 -1
  86. package/packages/bundled-features/src/auth-mfa/web/i18n.ts +0 -1
  87. package/packages/bundled-features/src/auth-mfa/web/index.ts +0 -1
  88. package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +0 -1
  89. package/packages/bundled-features/src/auth-mfa/web/mfa-disable-dialog.tsx +1 -2
  90. package/packages/bundled-features/src/auth-mfa/web/mfa-recovery-codes-reveal.tsx +0 -1
  91. package/packages/bundled-features/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +1 -2
  92. package/packages/bundled-features/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +21 -23
  93. package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +0 -1
  94. package/packages/bundled-features/src/billing-foundation/changes.json +18 -0
  95. package/packages/bundled-features/src/billing-foundation/checkout-core.ts +3 -3
  96. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-text.ts +2 -2
  97. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +11 -3
  98. package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +11 -1
  99. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +1 -1
  100. package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +12 -1
  101. package/packages/bundled-features/src/billing-foundation/consumer-protection/stored-user-email.ts +12 -0
  102. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-mail.ts +6 -1
  103. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-notify.ts +1 -1
  104. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-pages.ts +167 -28
  105. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +102 -3
  106. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +43 -12
  107. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +202 -0
  108. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +70 -0
  109. package/packages/bundled-features/src/billing-foundation/events.ts +20 -2
  110. package/packages/bundled-features/src/billing-foundation/feature.ts +5 -5
  111. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +82 -9
  112. package/packages/bundled-features/src/billing-foundation/handlers/switch-plan.write.ts +1 -1
  113. package/packages/bundled-features/src/billing-foundation/handlers/sync-subscription.write.ts +1 -1
  114. package/packages/bundled-features/src/billing-foundation/index.ts +27 -27
  115. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +7 -7
  116. package/packages/bundled-features/src/billing-foundation/screens.ts +1 -1
  117. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +1 -1
  118. package/packages/bundled-features/src/billing-foundation/types.ts +17 -3
  119. package/packages/bundled-features/src/billing-foundation/validate-options.ts +3 -3
  120. package/packages/bundled-features/src/billing-foundation/web/billing-contact-plan.tsx +1 -3
  121. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +5 -7
  122. package/packages/bundled-features/src/billing-foundation/web/cancel-contract-dialog.tsx +1 -3
  123. package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +1 -3
  124. package/packages/bundled-features/src/billing-foundation/web/client-plugin.tsx +1 -2
  125. package/packages/bundled-features/src/billing-foundation/{constants.ts → web/constants.ts} +37 -31
  126. package/packages/bundled-features/src/billing-foundation/{consumer-protection → web/consumer-protection}/consent-locale.ts +0 -1
  127. package/packages/bundled-features/src/billing-foundation/{contact-card.ts → web/contact-card.ts} +0 -2
  128. package/packages/bundled-features/src/billing-foundation/web/index.ts +14 -15
  129. package/packages/bundled-features/src/billing-foundation/web/localized-params.ts +0 -2
  130. package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +5 -2
  131. package/packages/bundled-features/src/cap-counter/changes.json +12 -0
  132. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -0
  133. package/packages/bundled-features/src/cap-overview/feature.ts +1 -1
  134. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
  135. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +2 -2
  136. package/packages/bundled-features/src/cap-overview/index.ts +9 -9
  137. package/packages/bundled-features/src/cap-overview/screens.ts +2 -2
  138. package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +1 -2
  139. package/packages/bundled-features/src/cap-overview/web/cap-usage-bar.tsx +1 -2
  140. package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +0 -2
  141. package/packages/bundled-features/src/cap-overview/web/client-plugin.tsx +3 -4
  142. package/packages/bundled-features/src/cap-overview/{constants.ts → web/constants.ts} +0 -1
  143. package/packages/bundled-features/src/cap-overview/web/index.ts +0 -1
  144. package/packages/bundled-features/src/cap-overview/{usage-math.ts → web/usage-math.ts} +1 -2
  145. package/packages/bundled-features/src/compliance-profiles/feature.ts +5 -5
  146. package/packages/bundled-features/src/compliance-profiles/index.ts +6 -6
  147. package/packages/bundled-features/src/compliance-profiles/web/client-plugin.tsx +2 -3
  148. package/packages/bundled-features/src/compliance-profiles/web/compliance-profile-catalog.tsx +1 -2
  149. package/packages/bundled-features/src/compliance-profiles/{constants.ts → web/constants.ts} +0 -1
  150. package/packages/bundled-features/src/compliance-profiles/web/i18n.ts +0 -1
  151. package/packages/bundled-features/src/compliance-profiles/web/index.ts +0 -1
  152. package/packages/bundled-features/src/config/index.ts +6 -6
  153. package/packages/bundled-features/src/config/web/client-plugin.ts +1 -2
  154. package/packages/bundled-features/src/config/{constants.ts → web/constants.ts} +0 -1
  155. package/packages/bundled-features/src/config/web/i18n.ts +1 -1
  156. package/packages/bundled-features/src/config/web/index.ts +1 -3
  157. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  158. package/packages/bundled-features/src/custom-fields/feature.ts +8 -8
  159. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
  160. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +1 -1
  161. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
  162. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +4 -4
  163. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
  164. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +1 -1
  165. package/packages/bundled-features/src/custom-fields/index.ts +8 -8
  166. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +1 -1
  167. package/packages/bundled-features/src/custom-fields/schemas.ts +1 -1
  168. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +1 -2
  169. package/packages/bundled-features/src/custom-fields/{constants.ts → web/constants.ts} +18 -19
  170. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +1 -2
  171. package/packages/bundled-features/src/custom-fields/web/i18n.ts +0 -1
  172. package/packages/bundled-features/src/custom-fields/web/index.ts +2 -3
  173. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +1 -2
  174. package/packages/bundled-features/src/delivery/address-opt-out.ts +1 -1
  175. package/packages/bundled-features/src/delivery/attempt-log-retention.ts +24 -8
  176. package/packages/bundled-features/src/delivery/changes.json +6 -0
  177. package/packages/bundled-features/src/delivery/constants.ts +2 -2
  178. package/packages/bundled-features/src/delivery/i18n.ts +1 -1
  179. package/packages/bundled-features/src/delivery/unsubscribe-page.ts +1 -1
  180. package/packages/bundled-features/src/delivery/web/client-plugin.tsx +6 -7
  181. package/packages/bundled-features/src/delivery/web/delivery-channel-cell.tsx +0 -1
  182. package/packages/bundled-features/src/delivery/web/delivery-error-cell.tsx +0 -1
  183. package/packages/bundled-features/src/delivery/web/delivery-status-cell.tsx +1 -2
  184. package/packages/bundled-features/src/delivery/web/delivery-time-cell.tsx +0 -1
  185. package/packages/bundled-features/src/delivery/web/delivery-type-cell.tsx +0 -1
  186. package/packages/bundled-features/src/delivery/web/index.ts +0 -1
  187. package/packages/bundled-features/src/delivery/{public-names.ts → web/public-names.ts} +0 -1
  188. package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
  189. package/packages/bundled-features/src/document-ingest-foundation/events.ts +4 -0
  190. package/packages/bundled-features/src/document-ingest-foundation/executor.ts +2 -1
  191. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +18 -4
  192. package/packages/bundled-features/src/document-ingest-foundation/index.ts +1 -0
  193. package/packages/bundled-features/src/feature-toggles/feature.ts +7 -7
  194. package/packages/bundled-features/src/feature-toggles/handlers/list.query.ts +1 -1
  195. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
  196. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +3 -3
  197. package/packages/bundled-features/src/feature-toggles/index.ts +6 -6
  198. package/packages/bundled-features/src/feature-toggles/web/client-plugin.tsx +1 -2
  199. package/packages/bundled-features/src/feature-toggles/{constants.ts → web/constants.ts} +0 -1
  200. package/packages/bundled-features/src/feature-toggles/web/i18n.ts +0 -1
  201. package/packages/bundled-features/src/feature-toggles/web/index.ts +0 -1
  202. package/packages/bundled-features/src/files/changes.json +7 -0
  203. package/packages/bundled-features/src/folders/feature.ts +1 -1
  204. package/packages/bundled-features/src/folders/handlers/clear-folder.write.ts +1 -1
  205. package/packages/bundled-features/src/folders/handlers/delete-folder.write.ts +1 -1
  206. package/packages/bundled-features/src/folders/handlers/set-folder.write.ts +1 -1
  207. package/packages/bundled-features/src/folders/index.ts +8 -8
  208. package/packages/bundled-features/src/folders/web/client-plugin.tsx +1 -3
  209. package/packages/bundled-features/src/folders/{constants.ts → web/constants.ts} +0 -1
  210. package/packages/bundled-features/src/folders/web/folder-manager.tsx +1 -2
  211. package/packages/bundled-features/src/folders/web/folder-section.tsx +1 -2
  212. package/packages/bundled-features/src/folders/web/i18n.ts +0 -1
  213. package/packages/bundled-features/src/folders/web/index.ts +1 -2
  214. package/packages/bundled-features/src/folders/web/tree.ts +0 -1
  215. package/packages/bundled-features/src/form-draft/changes.json +7 -0
  216. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +25 -11
  217. package/packages/bundled-features/src/form-draft/decrypt-draft.ts +24 -0
  218. package/packages/bundled-features/src/form-draft/entity.ts +6 -9
  219. package/packages/bundled-features/src/form-draft/feature.ts +1 -1
  220. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +26 -5
  221. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  222. package/packages/bundled-features/src/form-draft/handlers/get.query.ts +6 -7
  223. package/packages/bundled-features/src/form-draft/handlers/list.query.ts +13 -7
  224. package/packages/bundled-features/src/form-draft/handlers/save.write.ts +5 -5
  225. package/packages/bundled-features/src/form-draft/index.ts +8 -8
  226. package/packages/bundled-features/src/form-draft/lookup.ts +10 -4
  227. package/packages/bundled-features/src/form-draft/schemas.ts +1 -1
  228. package/packages/bundled-features/src/form-draft/{constants.ts → web/constants.ts} +0 -1
  229. package/packages/bundled-features/src/form-draft-user-data/hooks.ts +2 -2
  230. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +6 -0
  231. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +11 -4
  232. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +10 -10
  233. package/packages/bundled-features/src/jobs/feature.ts +7 -7
  234. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  235. package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +1 -1
  236. package/packages/bundled-features/src/jobs/index.ts +1 -1
  237. package/packages/bundled-features/src/jobs/web/client-plugin.tsx +2 -3
  238. package/packages/bundled-features/src/jobs/{constants.ts → web/constants.ts} +0 -1
  239. package/packages/bundled-features/src/jobs/web/default-translations.ts +7 -0
  240. package/packages/bundled-features/src/jobs/web/i18n.ts +53 -7
  241. package/packages/bundled-features/src/jobs/web/index.ts +0 -1
  242. package/packages/bundled-features/src/ledger/changes.json +7 -0
  243. package/packages/bundled-features/src/ledger/entity.ts +1 -1
  244. package/packages/bundled-features/src/ledger/feature.ts +1 -1
  245. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +2 -10
  246. package/packages/bundled-features/src/ledger/handlers/create-transaction.write.ts +1 -1
  247. package/packages/bundled-features/src/ledger/handlers/reports.query.ts +1 -1
  248. package/packages/bundled-features/src/ledger/handlers/reverse-transaction.write.ts +1 -1
  249. package/packages/bundled-features/src/ledger/index.ts +13 -13
  250. package/packages/bundled-features/src/ledger/recurring.ts +1 -1
  251. package/packages/bundled-features/src/ledger/reports.ts +1 -1
  252. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  253. package/packages/bundled-features/src/ledger/{constants.ts → web/constants.ts} +0 -1
  254. package/packages/bundled-features/src/ledger/web/index.ts +11 -12
  255. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  256. package/packages/bundled-features/src/legal-pages/feature.ts +5 -5
  257. package/packages/bundled-features/src/legal-pages/index.ts +11 -11
  258. package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +1 -1
  259. package/packages/bundled-features/src/legal-pages/lib/validate-routes.ts +1 -1
  260. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +1 -2
  261. package/packages/bundled-features/src/legal-pages/{constants.ts → web/constants.ts} +6 -8
  262. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -1
  263. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  264. package/packages/bundled-features/src/mail-foundation/i18n.ts +3 -2
  265. package/packages/bundled-features/src/mail-transport-smtp/i18n.ts +1 -1
  266. package/packages/bundled-features/src/managed-pages/feature.ts +1 -1
  267. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +1 -2
  268. package/packages/bundled-features/src/managed-pages/web/default-translations.ts +17 -0
  269. package/packages/bundled-features/src/managed-pages/web/i18n.ts +59 -16
  270. package/packages/bundled-features/src/managed-pages/web/index.ts +1 -2
  271. package/packages/bundled-features/src/metrics/compute.ts +1 -1
  272. package/packages/bundled-features/src/metrics/feature.ts +6 -6
  273. package/packages/bundled-features/src/metrics/index.ts +8 -8
  274. package/packages/bundled-features/src/metrics/types.ts +1 -1
  275. package/packages/bundled-features/src/metrics/validate.ts +1 -1
  276. package/packages/bundled-features/src/metrics/{constants.ts → web/constants.ts} +0 -1
  277. package/packages/bundled-features/src/metrics/window.ts +1 -1
  278. package/packages/bundled-features/src/notes-history/feature.ts +1 -1
  279. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  280. package/packages/bundled-features/src/notes-history/index.ts +8 -8
  281. package/packages/bundled-features/src/notes-history/web/client-plugin.tsx +1 -3
  282. package/packages/bundled-features/src/notes-history/{constants.ts → web/constants.ts} +0 -1
  283. package/packages/bundled-features/src/notes-history/web/i18n.ts +0 -1
  284. package/packages/bundled-features/src/notes-history/web/index.ts +2 -3
  285. package/packages/bundled-features/src/notes-history/web/notes-section.tsx +2 -3
  286. package/packages/bundled-features/src/personal-access-tokens/feature.ts +12 -10
  287. package/packages/bundled-features/src/personal-access-tokens/handlers/available-scopes.query.ts +1 -1
  288. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +1 -1
  289. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  290. package/packages/bundled-features/src/personal-access-tokens/hash.ts +1 -1
  291. package/packages/bundled-features/src/personal-access-tokens/i18n.ts +2 -2
  292. package/packages/bundled-features/src/personal-access-tokens/index.ts +5 -5
  293. package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -1
  294. package/packages/bundled-features/src/personal-access-tokens/schema/api-token.ts +1 -1
  295. package/packages/bundled-features/src/personal-access-tokens/screens.ts +2 -2
  296. package/packages/bundled-features/src/personal-access-tokens/{constants.ts → web/constants.ts} +0 -1
  297. package/packages/bundled-features/src/personal-access-tokens/{scopes.ts → web/scopes.ts} +0 -1
  298. package/packages/bundled-features/src/presets/changes.json +7 -0
  299. package/packages/bundled-features/src/presets/index.ts +0 -1
  300. package/packages/bundled-features/src/presets/security-baseline.ts +1 -1
  301. package/packages/bundled-features/src/renderer-foundation/types.ts +1 -1
  302. package/packages/bundled-features/src/secrets/feature.ts +1 -1
  303. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +1 -1
  304. package/packages/bundled-features/src/secrets/handlers/list.query.ts +1 -1
  305. package/packages/bundled-features/src/secrets/handlers/set.write.ts +1 -1
  306. package/packages/bundled-features/src/secrets/i18n.ts +1 -1
  307. package/packages/bundled-features/src/secrets/index.ts +8 -8
  308. package/packages/bundled-features/src/secrets/{constants.ts → web/constants.ts} +0 -1
  309. package/packages/bundled-features/src/secrets/write-gate.ts +1 -1
  310. package/packages/bundled-features/src/sessions/feature.ts +7 -4
  311. package/packages/bundled-features/src/sessions/{i18n.ts → web/i18n.ts} +0 -1
  312. package/packages/bundled-features/src/shared/index.ts +6 -1
  313. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +10 -2
  314. package/packages/bundled-features/src/shared/web/translate-or-raw.ts +0 -1
  315. package/packages/bundled-features/src/subscription-stripe/feature.ts +2 -0
  316. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +19 -0
  317. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +1 -0
  318. package/packages/bundled-features/src/tags/changes.json +6 -0
  319. package/packages/bundled-features/src/tags/feature.ts +1 -1
  320. package/packages/bundled-features/src/tags/handlers/assign-tag.write.ts +11 -7
  321. package/packages/bundled-features/src/tags/handlers/create-tag.write.ts +1 -1
  322. package/packages/bundled-features/src/tags/handlers/delete-tag.write.ts +4 -1
  323. package/packages/bundled-features/src/tags/handlers/remove-tag.write.ts +1 -1
  324. package/packages/bundled-features/src/tags/handlers/update-tag.write.ts +1 -1
  325. package/packages/bundled-features/src/tags/index.ts +12 -12
  326. package/packages/bundled-features/src/tags/screens.ts +1 -1
  327. package/packages/bundled-features/src/tags/web/client-plugin.tsx +1 -3
  328. package/packages/bundled-features/src/tags/{constants.ts → web/constants.ts} +4 -1
  329. package/packages/bundled-features/src/tags/web/entity-tags.tsx +1 -2
  330. package/packages/bundled-features/src/tags/web/i18n.ts +2 -2
  331. package/packages/bundled-features/src/tags/web/index.ts +2 -3
  332. package/packages/bundled-features/src/tags/web/tag-chip.tsx +0 -1
  333. package/packages/bundled-features/src/tags/web/tag-filter.tsx +1 -2
  334. package/packages/bundled-features/src/tags/web/tag-manager.tsx +5 -4
  335. package/packages/bundled-features/src/tags/web/tag-picker.tsx +0 -1
  336. package/packages/bundled-features/src/tags/web/tag-section.tsx +1 -2
  337. package/packages/bundled-features/src/tags/web/tags-cell.tsx +1 -2
  338. package/packages/bundled-features/src/template-resolver/README.md +1 -1
  339. package/packages/bundled-features/src/template-resolver/api.ts +75 -28
  340. package/packages/bundled-features/src/template-resolver/changes.json +63 -0
  341. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +62 -4
  342. package/packages/bundled-features/src/template-resolver/compile-steps-block.ts +2 -2
  343. package/packages/bundled-features/src/template-resolver/document-ops.ts +5 -5
  344. package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +39 -4
  345. package/packages/bundled-features/src/template-resolver/feature.ts +88 -38
  346. package/packages/bundled-features/src/template-resolver/handlers/by-slug.query.ts +6 -1
  347. package/packages/bundled-features/src/template-resolver/handlers/by-tenant.query.ts +6 -2
  348. package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
  349. package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -1
  350. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +20 -7
  351. package/packages/bundled-features/src/template-resolver/handlers/collection-shared.ts +0 -6
  352. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +69 -60
  353. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +7 -1
  354. package/packages/bundled-features/src/template-resolver/handlers/discard-draft.write.ts +37 -14
  355. package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +8 -2
  356. package/packages/bundled-features/src/template-resolver/handlers/document-blocks.query.ts +2 -2
  357. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +5 -2
  358. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +4 -2
  359. package/packages/bundled-features/src/template-resolver/handlers/import-bundle.write.ts +37 -28
  360. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +10 -5
  361. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +5 -2
  362. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +132 -70
  363. package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +106 -97
  364. package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +62 -49
  365. package/packages/bundled-features/src/template-resolver/handlers/resource-link-pdf.write.ts +44 -29
  366. package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +52 -36
  367. package/packages/bundled-features/src/template-resolver/handlers/resource-shared.ts +1 -1
  368. package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +127 -107
  369. package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +38 -0
  370. package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +31 -0
  371. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +106 -112
  372. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +111 -104
  373. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +1 -1
  374. package/packages/bundled-features/src/template-resolver/handlers/template-gates.ts +6 -6
  375. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +2 -2
  376. package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +56 -28
  377. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +38 -29
  378. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +8 -2
  379. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +4 -2
  380. package/packages/bundled-features/src/template-resolver/i18n.ts +25 -0
  381. package/packages/bundled-features/src/template-resolver/index.ts +68 -60
  382. package/packages/bundled-features/src/template-resolver/layout-appearance.ts +1 -1
  383. package/packages/bundled-features/src/template-resolver/layout-regions.ts +1 -1
  384. package/packages/bundled-features/src/template-resolver/seeding.ts +16 -7
  385. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +2 -2
  386. package/packages/bundled-features/src/template-resolver/table.ts +1 -1
  387. package/packages/bundled-features/src/template-resolver/template-bundle.ts +2 -2
  388. package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +82 -0
  389. package/packages/bundled-features/src/template-resolver/template-draft.ts +1 -1
  390. package/packages/bundled-features/src/template-resolver/template-edit-policy.ts +91 -0
  391. package/packages/bundled-features/src/template-resolver/template-meta.ts +2 -2
  392. package/packages/bundled-features/src/template-resolver/template-preview.ts +22 -12
  393. package/packages/bundled-features/src/template-resolver/template-usage.ts +1 -1
  394. package/packages/bundled-features/src/template-resolver/template-validation.ts +33 -12
  395. package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
  396. package/packages/bundled-features/src/template-resolver/user-content-table.ts +1 -1
  397. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +4 -5
  398. package/packages/bundled-features/src/template-resolver/{constants.ts → web/constants.ts} +10 -10
  399. package/packages/bundled-features/src/template-resolver/{document-blocks.ts → web/document-blocks.ts} +3 -2
  400. package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +31 -3
  401. package/packages/bundled-features/src/template-resolver/web/document-editor.tsx +0 -1
  402. package/packages/bundled-features/src/template-resolver/web/document-images.ts +28 -0
  403. package/packages/bundled-features/src/template-resolver/{document-schema.ts → web/document-schema.ts} +5 -1
  404. package/packages/bundled-features/src/template-resolver/{document-steps.ts → web/document-steps.ts} +0 -1
  405. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +48 -11
  406. package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +4 -3
  407. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +1 -2
  408. package/packages/bundled-features/src/template-resolver/web/i18n.ts +8 -1
  409. package/packages/bundled-features/src/template-resolver/web/index.ts +13 -14
  410. package/packages/bundled-features/src/template-resolver/{mail-constants.ts → web/mail-constants.ts} +0 -1
  411. package/packages/bundled-features/src/template-resolver/{pdf-constants.ts → web/pdf-constants.ts} +0 -1
  412. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor-lazy.tsx +0 -1
  413. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +5 -4
  414. package/packages/bundled-features/src/template-resolver/{placeholder-text.ts → web/placeholder-text.ts} +0 -1
  415. package/packages/bundled-features/src/template-resolver/{qualified-names.ts → web/qualified-names.ts} +2 -1
  416. package/packages/bundled-features/src/template-resolver/web/use-stable-by-key.ts +0 -1
  417. package/packages/bundled-features/src/tenant/handlers/add-member.write.ts +1 -1
  418. package/packages/bundled-features/src/tenant/index.ts +7 -7
  419. package/packages/bundled-features/src/tenant/invitation-table.ts +1 -1
  420. package/packages/bundled-features/src/tenant/invited-membership.ts +1 -1
  421. package/packages/bundled-features/src/tenant/last-tenant-admin.ts +1 -1
  422. package/packages/bundled-features/src/tenant/member-role-options.ts +1 -1
  423. package/packages/bundled-features/src/tenant/screens.ts +2 -2
  424. package/packages/bundled-features/src/tenant/web/client-plugin.tsx +1 -2
  425. package/packages/bundled-features/src/tenant/{constants.ts → web/constants.ts} +3 -6
  426. package/packages/bundled-features/src/tenant/web/index.ts +0 -1
  427. package/packages/bundled-features/src/tenant/web/member-roles-cell.tsx +0 -1
  428. package/packages/bundled-features/src/tenant/web/member-status-cell.tsx +0 -1
  429. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +2 -2
  430. package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
  431. package/packages/bundled-features/src/tier-engine/feature.ts +7 -7
  432. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +1 -1
  433. package/packages/bundled-features/src/tier-engine/index.ts +8 -8
  434. package/packages/bundled-features/src/tier-engine/web/client-plugin.tsx +2 -3
  435. package/packages/bundled-features/src/tier-engine/{constants.ts → web/constants.ts} +2 -3
  436. package/packages/bundled-features/src/tier-engine/{i18n.ts → web/i18n.ts} +0 -1
  437. package/packages/bundled-features/src/tier-engine/web/index.ts +0 -1
  438. package/packages/bundled-features/src/user/handlers/create.write.ts +1 -1
  439. package/packages/bundled-features/src/user/handlers/update-roles.ts +1 -1
  440. package/packages/bundled-features/src/user/handlers/update.write.ts +1 -1
  441. package/packages/bundled-features/src/user/index.ts +1 -1
  442. package/packages/bundled-features/src/user/invited-global-roles.ts +1 -1
  443. package/packages/bundled-features/src/user/schema/user.ts +1 -1
  444. package/packages/bundled-features/src/user/{constants.ts → web/constants.ts} +0 -1
  445. package/packages/bundled-features/src/user-data-rights/changes.json +14 -0
  446. package/packages/bundled-features/src/user-data-rights/env.ts +1 -1
  447. package/packages/bundled-features/src/user-data-rights/feature.ts +9 -9
  448. package/packages/bundled-features/src/user-data-rights/index.ts +1 -1
  449. package/packages/bundled-features/src/user-data-rights/lib/resolve-tenant-model.ts +1 -1
  450. package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +1 -1
  451. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +2 -3
  452. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +0 -1
  453. package/packages/bundled-features/src/user-data-rights/{constants.ts → web/constants.ts} +11 -12
  454. package/packages/bundled-features/src/user-data-rights/web/default-translations.ts +91 -0
  455. package/packages/bundled-features/src/user-data-rights/web/i18n.ts +41 -91
  456. package/packages/bundled-features/src/user-data-rights/web/index.ts +1 -2
  457. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +1 -2
  458. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +0 -1
  459. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +0 -1
  460. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +10 -1
  461. package/packages/bundled-features/src/user-profile/feature.ts +2 -2
  462. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +1 -1
  463. package/packages/bundled-features/src/user-profile/index.ts +3 -2
  464. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +2 -3
  465. package/packages/bundled-features/src/user-profile/{constants.ts → web/constants.ts} +0 -1
  466. package/packages/bundled-features/src/user-profile/{i18n.ts → web/i18n.ts} +0 -1
  467. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +2 -3
  468. package/packages/bundled-features/src/waitlist/changes.json +6 -0
  469. package/packages/bundled-features/src/waitlist/entity.ts +1 -1
  470. package/packages/bundled-features/src/waitlist/feature.ts +5 -5
  471. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +3 -3
  472. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +5 -1
  473. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  474. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +3 -3
  475. package/packages/bundled-features/src/waitlist/import.ts +1 -1
  476. package/packages/bundled-features/src/waitlist/index.ts +11 -11
  477. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +1 -1
  478. package/packages/bundled-features/src/waitlist/link-on-signup.ts +1 -1
  479. package/packages/bundled-features/src/waitlist/mail.ts +7 -6
  480. package/packages/bundled-features/src/waitlist/payloads.ts +1 -1
  481. package/packages/bundled-features/src/waitlist/screens.ts +1 -1
  482. package/packages/bundled-features/src/waitlist/{constants.ts → web/constants.ts} +0 -1
  483. package/samples/apps/styleguide/src/features/content/web.tsx +0 -1
  484. package/samples/apps/ui-walkthrough/src/app/client.tsx +2 -0
  485. package/samples/apps/ui-walkthrough/src/app/help-action.tsx +37 -0
  486. package/samples/apps/ui-walkthrough/src/app/seed-rental.ts +17 -1
  487. package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +13 -0
  488. package/samples/apps/ui-walkthrough/src/app/server.ts +2 -1
  489. package/samples/apps/ui-walkthrough/src/app/shell.tsx +6 -0
  490. package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +20 -0
  491. package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +35 -7
  492. package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +6 -0
  493. package/samples/apps/ui-walkthrough/src/features/rental/entities.ts +27 -0
  494. package/samples/apps/ui-walkthrough/src/features/rental/feature.ts +120 -2
  495. package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +94 -0
  496. package/samples/apps/ui-walkthrough/src/features/rental/invoice-receive.ts +19 -0
  497. package/samples/apps/ui-walkthrough/src/features/rental/lease-support.ts +32 -1
  498. package/samples/apps/ui-walkthrough/src/features/rental/qualified-names.ts +5 -0
  499. package/samples/apps/ui-walkthrough/src/features/rental/receipts-upload.ts +70 -0
  500. package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +156 -0
  501. package/samples/apps/ui-walkthrough/src/features/subscription-plans/feature.ts +103 -0
  502. package/samples/apps/ui-walkthrough/src/features/subscription-plans/i18n.ts +36 -0
  503. package/samples/apps/ui-walkthrough/src/features/subscription-plans/index.ts +2 -0
  504. package/samples/apps/ui-walkthrough/src/features/subscription-plans/seed.ts +21 -0
  505. package/samples/apps/ui-walkthrough/src/features/tasks/i18n.ts +8 -0
  506. package/samples/apps/ui-walkthrough/src/run-config.ts +43 -3
  507. package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +1 -1
  508. package/samples/apps/use-all-bundled/feature-manifest.json +5 -5
  509. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +1 -1
  510. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +3 -1
  511. package/samples/recipes/compose-stacks/README.md +1 -2
  512. package/samples/recipes/delivery-notifications/README.md +1 -1
  513. package/samples/recipes/embedded/README.md +8 -0
  514. package/samples/recipes/embedded/src/feature.ts +8 -0
  515. package/samples/recipes/embedded/src/handlers/invoice-receive.write.ts +37 -0
  516. package/samples/recipes/embedded/src/screens/invoice-receive.screen.ts +56 -0
  517. package/samples/recipes/legal-pages/README.md +2 -2
  518. package/samples/recipes/legal-pages/src/feature.ts +1 -1
  519. package/samples/recipes/reference-data/src/feature.ts +3 -7
  520. package/packages/bundled-features/src/admin-shell/i18n.ts +0 -54
  521. package/packages/bundled-features/src/audit/i18n.ts +0 -25
  522. package/packages/bundled-features/src/auth-mfa/web/qrcode-browser.d.ts +0 -11
  523. package/packages/bundled-features/src/jobs/i18n.ts +0 -55
  524. package/packages/bundled-features/src/managed-pages/i18n.ts +0 -63
  525. package/packages/bundled-features/src/presets/dsgvo-self-service.ts +0 -35
  526. package/packages/bundled-features/src/user-data-rights/i18n.ts +0 -44
@@ -5,10 +5,11 @@ import {
5
5
  SYSTEM_TENANT_ID,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
7
  import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
8
- import type { DocumentHtmlKind } from "../constants.ts";
9
8
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
9
+ import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
10
10
  import { isHiddenSystemDraft, toWorkingRow } from "../template-draft.ts";
11
11
  import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.ts";
12
+ import type { DocumentHtmlKind } from "../web/constants.ts";
12
13
  import { parseStoredJson } from "./template-gates.ts";
13
14
 
14
15
  export type DocumentBase = {
@@ -45,7 +46,12 @@ export async function loadDocumentBase(
45
46
  tenantId: user.tenantId,
46
47
  ...where,
47
48
  });
48
- if (own !== undefined && !isSystemOnlyTemplateHiddenFrom(user, ctx.registry, own)) {
49
+ // A locked override is neither shown nor edited by a non-SystemAdmin; the served system default is.
50
+ const ownIsVisible =
51
+ own !== undefined &&
52
+ !isSystemOnlyTemplateHiddenFrom(user, ctx.registry, own) &&
53
+ isRowServedTo(deliveryPolicyOf(ctx.registry), user, own);
54
+ if (own !== undefined && ownIsVisible) {
49
55
  const working = toWorkingRow(own, user.tenantId);
50
56
  return {
51
57
  rowId: String(own.id),
@@ -1,11 +1,11 @@
1
1
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { NotFoundError } from "@cosmicdrift/kumiko-framework/errors";
3
3
  import * as z from "zod";
4
- import { DOCUMENT_HTML_KINDS } from "../constants.ts";
5
- import { documentBlocksForKind } from "../document-blocks.ts";
6
4
  import { documentBlocksOf } from "../document-ops.ts";
7
5
  import { parseDocumentJson } from "../document-sanitizer.ts";
8
6
  import { resolveTemplateVariables } from "../template-validation.ts";
7
+ import { DOCUMENT_HTML_KINDS } from "../web/constants.ts";
8
+ import { documentBlocksForKind } from "../web/document-blocks.ts";
9
9
  import { loadDocumentBase } from "./document-base.ts";
10
10
  import { localeSchema, templateSlugSchema } from "./shared.ts";
11
11
  import { knownResourceKeysFor } from "./validate.query.ts";
@@ -3,16 +3,18 @@ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
3
3
  import { defineQueryHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { NotFoundError, ValidationError } from "@cosmicdrift/kumiko-framework/errors";
5
5
  import * as z from "zod";
6
+ import { filterDeliveredTo } from "../api.ts";
6
7
  import {
7
8
  isFileAttachmentEntry,
8
9
  isPdfAttachmentLink,
9
10
  type LinkedResourceEntry,
10
11
  parseLinkedResourceEntries,
11
12
  } from "../linked-resources.ts";
12
- import { TemplateResolverErrors } from "../qualified-names.ts";
13
13
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
14
14
  import type { TemplateBundle } from "../template-bundle.ts";
15
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
15
16
  import { readTemplateResource } from "../template-resources.ts";
17
+ import { TemplateResolverErrors } from "../web/qualified-names.ts";
16
18
  import { kindSchema, templateSlugSchema } from "./shared.ts";
17
19
  import { parseStoredJson, storedRecord } from "./template-gates.ts";
18
20
 
@@ -94,7 +96,8 @@ export const exportBundleQuery = defineQueryHandler({
94
96
  ? { tenantId: SYSTEM_TENANT_ID, slug, kind, scope: "system", status: "active" }
95
97
  : { tenantId: query.user.tenantId, slug, kind, scope: "tenant" },
96
98
  );
97
- const rows = found
99
+ const policy = deliveryPolicyOf(ctx.registry);
100
+ const rows = (await filterDeliveredTo(ctx.db, policy, query.user, found))
98
101
  .filter((row) => row.status !== "archived")
99
102
  .sort((a, b) => a.locale.localeCompare(b.locale));
100
103
  const first = rows[0];
@@ -2,6 +2,7 @@ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
4
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
5
+ import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
5
6
  import { draftViewerTenantId, isHiddenSystemDraft, toWorkingRow } from "../template-draft.ts";
6
7
  import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.ts";
7
8
 
@@ -15,7 +16,7 @@ export const findByIdQuery = defineQueryHandler({
15
16
  schema: z.object({ id: z.string().min(1) }),
16
17
  access: { roles: ["TenantAdmin", "SystemAdmin", "User"] },
17
18
  description:
18
- "Reads the version of one template resource an editor works on, by row id: the open draft if there is one (status draft), else the stored version, with content, variable schema and scope, but only when it belongs to the caller's tenant or is a served system default (a never-served system draft is visible to a SystemAdmin only); `active` is the version number and since-time the resolver serves, null when none is served. Use it to load a template into the admin editor.",
19
+ "Reads the version of one template resource an editor works on, by row id: the open draft if there is one (status draft), else the stored version, with content, variable schema and scope, but only when it belongs to the caller's tenant or is a served system default (an override of a template that is not tenantEditable is not delivered and is visible to a SystemAdmin only) (a never-served system draft is visible to a SystemAdmin only); `active` is the version number and since-time the resolver serves, null when none is served. Use it to load a template into the admin editor.",
19
20
  handler: async (query, ctx) => {
20
21
  const stored = await fetchOne<TemplateResourceRow>(ctx.db, templateResourcesTable, {
21
22
  id: query.payload.id,
@@ -23,7 +24,8 @@ export const findByIdQuery = defineQueryHandler({
23
24
  if (
24
25
  !stored ||
25
26
  isHiddenSystemDraft(query.user, stored) ||
26
- isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, stored)
27
+ isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, stored) ||
28
+ !isRowServedTo(deliveryPolicyOf(ctx.registry), query.user, stored)
27
29
  ) {
28
30
  return null;
29
31
  }
@@ -1,33 +1,42 @@
1
1
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import * as z from "zod";
3
3
  import { templateBundleSchema } from "../template-bundle.ts";
4
+ import {
5
+ refuseTemplateEdit,
6
+ type TemplateEditPolicy,
7
+ templateEditAccess,
8
+ } from "../template-edit-policy.ts";
4
9
  import { importTemplateBundle, prepareTemplateBundleBeforeTransaction } from "./bundle-import.ts";
5
10
 
6
- export const importBundleWrite = defineWriteHandler({
7
- name: "import-bundle",
8
- schema: z.object({ bundle: templateBundleSchema, overwrite: z.boolean().default(false) }),
9
- access: { roles: ["TenantAdmin", "SystemAdmin"] },
10
- description:
11
- "Imports a template bundle (all locales plus resource files, as produced by export-bundle) into the caller's tenant as drafts; it refuses a locale that already has an override unless overwrite is set, and publish makes the drafts live.",
12
- beforeTransaction: (event, ctx) =>
13
- prepareTemplateBundleBeforeTransaction({
14
- ctx,
15
- user: event.user,
16
- tenantId: event.user.tenantId,
17
- scope: "tenant",
18
- status: "draft",
19
- bundle: event.payload.bundle,
20
- overwrite: event.payload.overwrite,
21
- }),
22
- handler: (event, ctx) =>
23
- importTemplateBundle({
24
- ctx,
25
- user: event.user,
26
- tenantId: event.user.tenantId,
27
- scope: "tenant",
28
- status: "draft",
29
- bundle: event.payload.bundle,
30
- overwrite: event.payload.overwrite,
31
- prepared: event.prepared,
32
- }),
33
- });
11
+ export function makeImportBundleWrite(policy: TemplateEditPolicy) {
12
+ return defineWriteHandler({
13
+ name: "import-bundle",
14
+ schema: z.object({ bundle: templateBundleSchema, overwrite: z.boolean().default(false) }),
15
+ access: templateEditAccess(policy.tenantEditable),
16
+ description:
17
+ "Imports a template bundle (all locales plus resource files, as produced by export-bundle) into the caller's tenant as drafts; it refuses a locale that already has an override unless overwrite is set, and publish makes the drafts live. Outside the templates the app lists in tenantEditable only a SystemAdmin may use it.",
18
+ beforeTransaction: async (event, ctx) =>
19
+ refuseTemplateEdit(policy, event.user, event.payload.bundle) ??
20
+ prepareTemplateBundleBeforeTransaction({
21
+ ctx,
22
+ user: event.user,
23
+ tenantId: event.user.tenantId,
24
+ scope: "tenant",
25
+ status: "draft",
26
+ bundle: event.payload.bundle,
27
+ overwrite: event.payload.overwrite,
28
+ }),
29
+ handler: async (event, ctx) =>
30
+ refuseTemplateEdit(policy, event.user, event.payload.bundle) ??
31
+ importTemplateBundle({
32
+ ctx,
33
+ user: event.user,
34
+ tenantId: event.user.tenantId,
35
+ scope: "tenant",
36
+ status: "draft",
37
+ bundle: event.payload.bundle,
38
+ overwrite: event.payload.overwrite,
39
+ prepared: event.prepared,
40
+ }),
41
+ });
42
+ }
@@ -1,9 +1,10 @@
1
1
  import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
- import { FALLBACK_LOCALE } from "../constants.ts";
4
+ import { filterDeliveredTo } from "../api.ts";
5
5
  import { type LayoutRegions, readLayoutRegions } from "../layout-regions.ts";
6
6
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
7
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
7
8
  import {
8
9
  type ActiveInfo,
9
10
  draftViewerTenantId,
@@ -12,6 +13,7 @@ import {
12
13
  type WorkingRow,
13
14
  } from "../template-draft.ts";
14
15
  import { type MailLayoutMeta, readMailLayoutMeta } from "../template-meta.ts";
16
+ import { FALLBACK_LOCALE } from "../web/constants.ts";
15
17
  import { localeSchema, templateSlugSchema } from "./shared.ts";
16
18
  import { parseStoredJson } from "./template-gates.ts";
17
19
 
@@ -141,10 +143,13 @@ export const layoutSourceQuery = defineQueryHandler({
141
143
  handler: async (query, ctx): Promise<LayoutSourceResponse> => {
142
144
  const { kind, slug, locale } = query.payload;
143
145
  const isSystemAdmin = query.user.roles.includes("SystemAdmin");
144
- const rows = await selectMany<TemplateResourceRow>(ctx.db, templateResourcesTable, {
145
- kind,
146
- slug,
147
- });
146
+ const policy = deliveryPolicyOf(ctx.registry);
147
+ const rows = await filterDeliveredTo(
148
+ ctx.db,
149
+ policy,
150
+ query.user,
151
+ await selectMany<TemplateResourceRow>(ctx.db, templateResourcesTable, { kind, slug }),
152
+ );
148
153
  const { tenantRow, systemRow } = pickEditedRows(rows, query.user, locale);
149
154
  return buildLayoutSource({ kind, locale, isSystemAdmin, tenantRow, systemRow });
150
155
  },
@@ -1,10 +1,11 @@
1
1
  import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
- import { TEMPLATE_KINDS, TEMPLATE_STATUSES } from "../constants.ts";
5
4
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
5
+ import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
6
6
  import { isHiddenSystemDraft } from "../template-draft.ts";
7
7
  import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.ts";
8
+ import { TEMPLATE_KINDS, TEMPLATE_STATUSES } from "../web/constants.ts";
8
9
 
9
10
  // ctx.db is tenant-scoped even for SystemAdmin: every caller sees its own
10
11
  // tenant's rows plus the system defaults, never another tenant's rows.
@@ -45,11 +46,13 @@ export const listQuery = defineQueryHandler({
45
46
  limit: 500,
46
47
  })) as TemplateResourceRow[];
47
48
 
49
+ const deliveryPolicy = deliveryPolicyOf(ctx.registry);
48
50
  return rows
49
51
  .filter(
50
52
  (row) =>
51
53
  !isHiddenSystemDraft(query.user, row) &&
52
- !isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, row),
54
+ !isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, row) &&
55
+ isRowServedTo(deliveryPolicy, query.user, row),
53
56
  )
54
57
  .map((row) => ({
55
58
  id: String(row.id),
@@ -1,8 +1,12 @@
1
1
  import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
- import { DEFAULT_MAIL_LAYOUT_SLUG, FALLBACK_LOCALE, type TemplateStatus } from "../constants.ts";
5
4
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
5
+ import {
6
+ deliveryPolicyOf,
7
+ isTenantOverrideServed,
8
+ type TemplateDeliveryPolicy,
9
+ } from "../template-delivery-policy.ts";
6
10
  import {
7
11
  activeSinceOf,
8
12
  activeVersionOf,
@@ -11,14 +15,21 @@ import {
11
15
  parseTemplateDraft,
12
16
  servedVersionOf,
13
17
  } from "../template-draft.ts";
18
+ import { mayEditTemplate, type TemplateEditPolicy } from "../template-edit-policy.ts";
14
19
  import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.ts";
15
20
  import { collectTemplateUsage, type EffectiveMailLayoutSlugs } from "../template-usage.ts";
21
+ import {
22
+ DEFAULT_MAIL_LAYOUT_SLUG,
23
+ FALLBACK_LOCALE,
24
+ type TemplateStatus,
25
+ } from "../web/constants.ts";
16
26
  import { storedRecord } from "./template-gates.ts";
17
27
 
18
28
  const OVERVIEW_KINDS = ["mail", "document-pdf", "mail-layout", "pdf-layout"] as const;
19
29
  type OverviewKind = (typeof OVERVIEW_KINDS)[number];
20
30
 
21
31
  const OVERVIEW_ROW_LIMIT = 5000;
32
+ const LOCKED_OVERRIDE_I18N_KEY = "templateResolver.overview.lockedOverride";
22
33
 
23
34
  export type OverviewOrigin = "tenant" | "system";
24
35
  export type OverviewKindGroup = "mail" | "pdf" | "layout";
@@ -44,6 +55,13 @@ export type OverviewRow = {
44
55
  readonly activeSince: string | null;
45
56
  readonly systemVersion: number | null;
46
57
  readonly layoutSlug: string | null;
58
+ /** SystemAdmin only: a tenant override is stored but not delivered because the template is not unlocked for tenants. */
59
+ readonly lockedOverride: boolean;
60
+ readonly lockedOverrideI18nKey: string | null;
61
+ /** Tenant row a reset acts on (resetToSystem takes a row id, the overview row is a slug group); set only while a system version exists to fall back to. */
62
+ readonly lockedOverrideId: string | null;
63
+ /** False when a locked override has no system version to fall back to, so a reset would be refused. */
64
+ readonly canResetLockedOverride: boolean;
47
65
  readonly modifiedAt: string;
48
66
  readonly usedBy: readonly OverviewUsage[];
49
67
  readonly usedByCount: number;
@@ -87,23 +105,54 @@ function preferredRow(rows: readonly TemplateResourceRow[]): TemplateResourceRow
87
105
  );
88
106
  }
89
107
 
90
- type EffectiveRows = { readonly origin: OverviewOrigin; readonly rows: TemplateResourceRow[] };
108
+ type EffectiveRows = {
109
+ readonly origin: OverviewOrigin;
110
+ readonly rows: TemplateResourceRow[];
111
+ readonly lockedOverride: boolean;
112
+ readonly lockedOverrideId: string | null;
113
+ };
91
114
 
92
- function effectiveRowsOf(rows: readonly TemplateResourceRow[]): EffectiveRows | null {
115
+ // A tenant row of a template that is not unlocked is not delivered, so the system version is the effective one.
116
+ function effectiveRowsOf(
117
+ rows: readonly TemplateResourceRow[],
118
+ policy: TemplateDeliveryPolicy,
119
+ ): EffectiveRows | null {
93
120
  const tenantRows = rows.filter((row) => row.scope === "tenant");
94
121
  const systemRows = rows.filter((row) => row.scope === "system");
95
122
  const live = (list: TemplateResourceRow[]) => list.filter((row) => row.status !== "archived");
96
123
  const liveTenant = live(tenantRows);
97
- if (liveTenant.length > 0) return { origin: "tenant", rows: liveTenant };
124
+ const tenantServed = tenantRows.every((row) => isTenantOverrideServed(policy, row));
125
+ if (!tenantServed && liveTenant.length > 0) {
126
+ const liveSystem = live(systemRows);
127
+ if (systemRows.length === 0)
128
+ return { origin: "tenant", rows: liveTenant, lockedOverride: true, lockedOverrideId: null };
129
+ const lockedRow = preferredRow(liveTenant);
130
+ return {
131
+ origin: "system",
132
+ rows: liveSystem.length > 0 ? liveSystem : systemRows,
133
+ lockedOverride: true,
134
+ lockedOverrideId: lockedRow === undefined ? null : String(lockedRow.id),
135
+ };
136
+ }
137
+ if (liveTenant.length > 0)
138
+ return { origin: "tenant", rows: liveTenant, lockedOverride: false, lockedOverrideId: null };
98
139
  if (systemRows.length > 0) {
99
140
  const liveSystem = live(systemRows);
100
- return { origin: "system", rows: liveSystem.length > 0 ? liveSystem : systemRows };
141
+ return {
142
+ origin: "system",
143
+ rows: liveSystem.length > 0 ? liveSystem : systemRows,
144
+ lockedOverride: false,
145
+ lockedOverrideId: null,
146
+ };
101
147
  }
102
- return tenantRows.length > 0 ? { origin: "tenant", rows: tenantRows } : null;
148
+ return tenantRows.length > 0
149
+ ? { origin: "tenant", rows: tenantRows, lockedOverride: false, lockedOverrideId: null }
150
+ : null;
103
151
  }
104
152
 
105
153
  export function effectiveMailLayoutSlugs(
106
154
  rows: readonly TemplateResourceRow[],
155
+ policy: TemplateDeliveryPolicy,
107
156
  ): EffectiveMailLayoutSlugs {
108
157
  const byLocale = new Map<string, TemplateResourceRow[]>();
109
158
  for (const row of rows) {
@@ -113,7 +162,10 @@ export function effectiveMailLayoutSlugs(
113
162
  }
114
163
  const bySlug = new Map<string, Map<string, string>>();
115
164
  for (const group of byLocale.values()) {
116
- const effective = effectiveRowsOf(group)?.rows[0];
165
+ const effectiveRows = effectiveRowsOf(group, policy);
166
+ // A locked tenant row without a system row is not delivered, so it names no layout.
167
+ if (effectiveRows?.lockedOverride && effectiveRows.origin === "tenant") continue;
168
+ const effective = effectiveRows?.rows[0];
117
169
  // All-archived: the renderer falls back to the code-registered template.
118
170
  if (effective === undefined || effective.status === "archived") continue;
119
171
  const locales = bySlug.get(effective.slug) ?? new Map<string, string>();
@@ -190,6 +242,7 @@ function versionFieldsOf(
190
242
  function buildDrafts(
191
243
  groups: ReadonlyMap<string, readonly TemplateResourceRow[]>,
192
244
  user: { readonly tenantId: string; readonly roles: readonly string[] },
245
+ policy: TemplateDeliveryPolicy,
193
246
  ): {
194
247
  readonly drafts: OverviewDraft[];
195
248
  readonly layoutSlugByDocument: Map<string, string>;
@@ -197,7 +250,7 @@ function buildDrafts(
197
250
  const layoutSlugByDocument = new Map<string, string>();
198
251
  const drafts: OverviewDraft[] = [];
199
252
  for (const [id, groupRows] of groups) {
200
- const effective = effectiveRowsOf(groupRows);
253
+ const effective = effectiveRowsOf(groupRows, policy);
201
254
  const preferred = effective === null ? undefined : preferredRow(effective.rows);
202
255
  if (effective === null || preferred === undefined) continue;
203
256
  if (!isOverviewKind(preferred.kind) || !isTemplateStatus(preferred.status)) continue;
@@ -217,6 +270,10 @@ function buildDrafts(
217
270
  status: preferred.status,
218
271
  ...versionFieldsOf(user, preferred, groupRows),
219
272
  layoutSlug,
273
+ lockedOverride: effective.lockedOverride,
274
+ lockedOverrideI18nKey: effective.lockedOverride ? LOCKED_OVERRIDE_I18N_KEY : null,
275
+ lockedOverrideId: effective.lockedOverrideId,
276
+ canResetLockedOverride: effective.lockedOverrideId !== null,
220
277
  modifiedAt: modifiedAtOf(preferred),
221
278
  });
222
279
  }
@@ -271,68 +328,73 @@ const filterSchema = z.object({
271
328
  value: z.array(z.string()),
272
329
  });
273
330
 
274
- export const overviewQuery = defineQueryHandler({
275
- name: "overview",
276
- schema: z.object({
277
- search: z.string().optional(),
278
- filters: z.array(filterSchema).optional(),
279
- layoutSlug: z.string().optional(),
280
- sort: z.string().optional(),
281
- sortDirection: z.enum(["asc", "desc"]).optional(),
282
- limit: z.number().int().min(1).max(200).default(50),
283
- offset: z.number().int().min(0).optional(),
284
- totalCount: z.boolean().optional(),
285
- }),
286
- access: { roles: ["TenantAdmin", "SystemAdmin"] },
287
- description:
288
- "Lists mail, PDF and layout templates as one row per slug and kind for the caller's tenant (optionally only the mails and PDFs using one layout slug): where the effective version comes from (own override or system), its locales, status and version (the served one; `draftVersion` is set when an unpublished draft waits beside it, `activeSince` says since when the served version applies), the system version it overrides, the layout it uses and which notifications or templates use it; templates of notifications registered with `systemOnly` are listed for SystemAdmins only; use it to browse and filter all templates at a glance.",
289
- handler: async (query, ctx) => {
290
- const payload = query.payload;
291
- const fetchedRows = await selectMany<TemplateResourceRow>(
292
- ctx.db,
293
- templateResourcesTable,
294
- { kind: { in: [...OVERVIEW_KINDS] } },
295
- { orderBy: { col: "id", direction: "asc" }, limit: OVERVIEW_ROW_LIMIT + 1 },
296
- );
297
- const truncated = fetchedRows.length > OVERVIEW_ROW_LIMIT;
298
- const rows = truncated ? fetchedRows.slice(0, OVERVIEW_ROW_LIMIT) : fetchedRows;
299
- if (truncated) {
300
- ctx.log?.warn("template overview: row limit reached, result is incomplete", {
301
- limit: OVERVIEW_ROW_LIMIT,
302
- });
303
- }
331
+ export function makeOverviewQuery(policy: TemplateEditPolicy) {
332
+ return defineQueryHandler({
333
+ name: "overview",
334
+ schema: z.object({
335
+ search: z.string().optional(),
336
+ filters: z.array(filterSchema).optional(),
337
+ layoutSlug: z.string().optional(),
338
+ sort: z.string().optional(),
339
+ sortDirection: z.enum(["asc", "desc"]).optional(),
340
+ limit: z.number().int().min(1).max(200).default(50),
341
+ offset: z.number().int().min(0).optional(),
342
+ totalCount: z.boolean().optional(),
343
+ }),
344
+ access: { roles: ["TenantAdmin", "SystemAdmin"] },
345
+ description:
346
+ "Lists mail, PDF and layout templates as one row per slug and kind for the caller's tenant (optionally only the mails and PDFs using one layout slug): where the effective version comes from (own override or system), its locales, status and version (the served one; `draftVersion` is set when an unpublished draft waits beside it, `activeSince` says since when the served version applies), the system version it overrides, the layout it uses and which notifications or templates use it; templates of notifications registered with `systemOnly` are listed for SystemAdmins only, and a TenantAdmin sees only the templates the app lists in tenantEditable; a tenant override of a template that is not listed is not delivered, so the row shows the system version with `lockedOverride` true (SystemAdmin only); use it to browse and filter all templates at a glance.",
347
+ handler: async (query, ctx) => {
348
+ const payload = query.payload;
349
+ const fetchedRows = await selectMany<TemplateResourceRow>(
350
+ ctx.db,
351
+ templateResourcesTable,
352
+ { kind: { in: [...OVERVIEW_KINDS] } },
353
+ { orderBy: { col: "id", direction: "asc" }, limit: OVERVIEW_ROW_LIMIT + 1 },
354
+ );
355
+ const truncated = fetchedRows.length > OVERVIEW_ROW_LIMIT;
356
+ const rows = truncated ? fetchedRows.slice(0, OVERVIEW_ROW_LIMIT) : fetchedRows;
357
+ if (truncated) {
358
+ ctx.log?.warn("template overview: row limit reached, result is incomplete", {
359
+ limit: OVERVIEW_ROW_LIMIT,
360
+ });
361
+ }
304
362
 
305
- const visibleRows = rows.filter(
306
- (row) =>
307
- !isHiddenSystemDraft(query.user, row) &&
308
- !isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, row),
309
- );
310
- const { drafts, layoutSlugByDocument } = buildDrafts(
311
- groupBySlugAndKind(visibleRows),
312
- query.user,
313
- );
314
- const effectiveLayouts = effectiveMailLayoutSlugs(visibleRows);
315
- const overviewRows = drafts.map((draft) =>
316
- withUsage(draft, layoutSlugByDocument, ctx.registry, effectiveLayouts),
317
- );
318
- const filtered = filterRows(
319
- overviewRows,
320
- payload.search,
321
- payload.filters ?? [],
322
- payload.layoutSlug,
323
- );
363
+ const visibleRows = rows.filter(
364
+ (row) =>
365
+ !isHiddenSystemDraft(query.user, row) &&
366
+ !isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, row) &&
367
+ mayEditTemplate(policy, query.user, row),
368
+ );
369
+ const deliveryPolicy = deliveryPolicyOf(ctx.registry);
370
+ const { drafts, layoutSlugByDocument } = buildDrafts(
371
+ groupBySlugAndKind(visibleRows),
372
+ query.user,
373
+ deliveryPolicy,
374
+ );
375
+ const effectiveLayouts = effectiveMailLayoutSlugs(visibleRows, deliveryPolicy);
376
+ const overviewRows = drafts.map((draft) =>
377
+ withUsage(draft, layoutSlugByDocument, ctx.registry, effectiveLayouts),
378
+ );
379
+ const filtered = filterRows(
380
+ overviewRows,
381
+ payload.search,
382
+ payload.filters ?? [],
383
+ payload.layoutSlug,
384
+ );
324
385
 
325
- const sortField: SortField =
326
- payload.sort !== undefined && isSortField(payload.sort) ? payload.sort : "modifiedAt";
327
- const direction = (payload.sortDirection ?? "desc") === "desc" ? -1 : 1;
328
- filtered.sort((a, b) => direction * compareBy(sortField, a, b) || a.id.localeCompare(b.id));
386
+ const sortField: SortField =
387
+ payload.sort !== undefined && isSortField(payload.sort) ? payload.sort : "modifiedAt";
388
+ const direction = (payload.sortDirection ?? "desc") === "desc" ? -1 : 1;
389
+ filtered.sort((a, b) => direction * compareBy(sortField, a, b) || a.id.localeCompare(b.id));
329
390
 
330
- const offset = payload.offset ?? 0;
331
- return {
332
- rows: filtered.slice(offset, offset + payload.limit),
333
- nextCursor: null,
334
- total: filtered.length,
335
- truncated,
336
- } satisfies OverviewResponse;
337
- },
338
- });
391
+ const offset = payload.offset ?? 0;
392
+ return {
393
+ rows: filtered.slice(offset, offset + payload.limit),
394
+ nextCursor: null,
395
+ total: filtered.length,
396
+ truncated,
397
+ } satisfies OverviewResponse;
398
+ },
399
+ });
400
+ }