@cosmicdrift/kumiko-samples 0.378.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 (506) 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-overview/feature.ts +1 -1
  132. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
  133. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +2 -2
  134. package/packages/bundled-features/src/cap-overview/index.ts +9 -9
  135. package/packages/bundled-features/src/cap-overview/screens.ts +2 -2
  136. package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +1 -2
  137. package/packages/bundled-features/src/cap-overview/web/cap-usage-bar.tsx +1 -2
  138. package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +0 -2
  139. package/packages/bundled-features/src/cap-overview/web/client-plugin.tsx +3 -4
  140. package/packages/bundled-features/src/cap-overview/{constants.ts → web/constants.ts} +0 -1
  141. package/packages/bundled-features/src/cap-overview/web/index.ts +0 -1
  142. package/packages/bundled-features/src/cap-overview/{usage-math.ts → web/usage-math.ts} +1 -2
  143. package/packages/bundled-features/src/compliance-profiles/feature.ts +5 -5
  144. package/packages/bundled-features/src/compliance-profiles/index.ts +6 -6
  145. package/packages/bundled-features/src/compliance-profiles/web/client-plugin.tsx +2 -3
  146. package/packages/bundled-features/src/compliance-profiles/web/compliance-profile-catalog.tsx +1 -2
  147. package/packages/bundled-features/src/compliance-profiles/{constants.ts → web/constants.ts} +0 -1
  148. package/packages/bundled-features/src/compliance-profiles/web/i18n.ts +0 -1
  149. package/packages/bundled-features/src/compliance-profiles/web/index.ts +0 -1
  150. package/packages/bundled-features/src/config/index.ts +6 -6
  151. package/packages/bundled-features/src/config/web/client-plugin.ts +1 -2
  152. package/packages/bundled-features/src/config/{constants.ts → web/constants.ts} +0 -1
  153. package/packages/bundled-features/src/config/web/i18n.ts +0 -1
  154. package/packages/bundled-features/src/config/web/index.ts +1 -3
  155. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  156. package/packages/bundled-features/src/custom-fields/feature.ts +8 -8
  157. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
  158. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +1 -1
  159. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
  160. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +4 -4
  161. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
  162. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +1 -1
  163. package/packages/bundled-features/src/custom-fields/index.ts +8 -8
  164. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +1 -1
  165. package/packages/bundled-features/src/custom-fields/schemas.ts +1 -1
  166. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +1 -2
  167. package/packages/bundled-features/src/custom-fields/{constants.ts → web/constants.ts} +18 -19
  168. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +1 -2
  169. package/packages/bundled-features/src/custom-fields/web/i18n.ts +0 -1
  170. package/packages/bundled-features/src/custom-fields/web/index.ts +2 -3
  171. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +1 -2
  172. package/packages/bundled-features/src/delivery/address-opt-out.ts +1 -1
  173. package/packages/bundled-features/src/delivery/attempt-log-retention.ts +24 -8
  174. package/packages/bundled-features/src/delivery/changes.json +6 -0
  175. package/packages/bundled-features/src/delivery/constants.ts +2 -2
  176. package/packages/bundled-features/src/delivery/i18n.ts +1 -1
  177. package/packages/bundled-features/src/delivery/unsubscribe-page.ts +1 -1
  178. package/packages/bundled-features/src/delivery/web/client-plugin.tsx +6 -7
  179. package/packages/bundled-features/src/delivery/web/delivery-channel-cell.tsx +0 -1
  180. package/packages/bundled-features/src/delivery/web/delivery-error-cell.tsx +0 -1
  181. package/packages/bundled-features/src/delivery/web/delivery-status-cell.tsx +1 -2
  182. package/packages/bundled-features/src/delivery/web/delivery-time-cell.tsx +0 -1
  183. package/packages/bundled-features/src/delivery/web/delivery-type-cell.tsx +0 -1
  184. package/packages/bundled-features/src/delivery/web/index.ts +0 -1
  185. package/packages/bundled-features/src/delivery/{public-names.ts → web/public-names.ts} +0 -1
  186. package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
  187. package/packages/bundled-features/src/document-ingest-foundation/events.ts +4 -0
  188. package/packages/bundled-features/src/document-ingest-foundation/executor.ts +2 -1
  189. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +18 -4
  190. package/packages/bundled-features/src/document-ingest-foundation/index.ts +1 -0
  191. package/packages/bundled-features/src/feature-toggles/feature.ts +7 -7
  192. package/packages/bundled-features/src/feature-toggles/handlers/list.query.ts +1 -1
  193. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
  194. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +3 -3
  195. package/packages/bundled-features/src/feature-toggles/index.ts +6 -6
  196. package/packages/bundled-features/src/feature-toggles/web/client-plugin.tsx +1 -2
  197. package/packages/bundled-features/src/feature-toggles/{constants.ts → web/constants.ts} +0 -1
  198. package/packages/bundled-features/src/feature-toggles/web/i18n.ts +0 -1
  199. package/packages/bundled-features/src/feature-toggles/web/index.ts +0 -1
  200. package/packages/bundled-features/src/files/changes.json +7 -0
  201. package/packages/bundled-features/src/folders/feature.ts +1 -1
  202. package/packages/bundled-features/src/folders/handlers/clear-folder.write.ts +1 -1
  203. package/packages/bundled-features/src/folders/handlers/delete-folder.write.ts +1 -1
  204. package/packages/bundled-features/src/folders/handlers/set-folder.write.ts +1 -1
  205. package/packages/bundled-features/src/folders/index.ts +8 -8
  206. package/packages/bundled-features/src/folders/web/client-plugin.tsx +1 -3
  207. package/packages/bundled-features/src/folders/{constants.ts → web/constants.ts} +0 -1
  208. package/packages/bundled-features/src/folders/web/folder-manager.tsx +1 -2
  209. package/packages/bundled-features/src/folders/web/folder-section.tsx +1 -2
  210. package/packages/bundled-features/src/folders/web/i18n.ts +0 -1
  211. package/packages/bundled-features/src/folders/web/index.ts +1 -2
  212. package/packages/bundled-features/src/folders/web/tree.ts +0 -1
  213. package/packages/bundled-features/src/form-draft/changes.json +7 -0
  214. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +25 -11
  215. package/packages/bundled-features/src/form-draft/decrypt-draft.ts +24 -0
  216. package/packages/bundled-features/src/form-draft/entity.ts +6 -9
  217. package/packages/bundled-features/src/form-draft/feature.ts +1 -1
  218. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +26 -5
  219. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  220. package/packages/bundled-features/src/form-draft/handlers/get.query.ts +6 -7
  221. package/packages/bundled-features/src/form-draft/handlers/list.query.ts +13 -7
  222. package/packages/bundled-features/src/form-draft/handlers/save.write.ts +5 -5
  223. package/packages/bundled-features/src/form-draft/index.ts +8 -8
  224. package/packages/bundled-features/src/form-draft/lookup.ts +10 -4
  225. package/packages/bundled-features/src/form-draft/schemas.ts +1 -1
  226. package/packages/bundled-features/src/form-draft/{constants.ts → web/constants.ts} +0 -1
  227. package/packages/bundled-features/src/form-draft-user-data/hooks.ts +2 -2
  228. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +10 -10
  229. package/packages/bundled-features/src/jobs/feature.ts +7 -7
  230. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  231. package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +1 -1
  232. package/packages/bundled-features/src/jobs/index.ts +1 -1
  233. package/packages/bundled-features/src/jobs/web/client-plugin.tsx +2 -3
  234. package/packages/bundled-features/src/jobs/{constants.ts → web/constants.ts} +0 -1
  235. package/packages/bundled-features/src/jobs/web/default-translations.ts +7 -0
  236. package/packages/bundled-features/src/jobs/web/i18n.ts +53 -7
  237. package/packages/bundled-features/src/jobs/web/index.ts +0 -1
  238. package/packages/bundled-features/src/ledger/changes.json +7 -0
  239. package/packages/bundled-features/src/ledger/entity.ts +1 -1
  240. package/packages/bundled-features/src/ledger/feature.ts +1 -1
  241. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +2 -10
  242. package/packages/bundled-features/src/ledger/handlers/create-transaction.write.ts +1 -1
  243. package/packages/bundled-features/src/ledger/handlers/reports.query.ts +1 -1
  244. package/packages/bundled-features/src/ledger/handlers/reverse-transaction.write.ts +1 -1
  245. package/packages/bundled-features/src/ledger/index.ts +13 -13
  246. package/packages/bundled-features/src/ledger/recurring.ts +1 -1
  247. package/packages/bundled-features/src/ledger/reports.ts +1 -1
  248. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  249. package/packages/bundled-features/src/ledger/{constants.ts → web/constants.ts} +0 -1
  250. package/packages/bundled-features/src/ledger/web/index.ts +11 -12
  251. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  252. package/packages/bundled-features/src/legal-pages/feature.ts +5 -5
  253. package/packages/bundled-features/src/legal-pages/index.ts +11 -11
  254. package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +1 -1
  255. package/packages/bundled-features/src/legal-pages/lib/validate-routes.ts +1 -1
  256. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +1 -2
  257. package/packages/bundled-features/src/legal-pages/{constants.ts → web/constants.ts} +6 -8
  258. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -1
  259. package/packages/bundled-features/src/managed-pages/feature.ts +1 -1
  260. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +1 -2
  261. package/packages/bundled-features/src/managed-pages/web/default-translations.ts +17 -0
  262. package/packages/bundled-features/src/managed-pages/web/i18n.ts +59 -16
  263. package/packages/bundled-features/src/managed-pages/web/index.ts +1 -2
  264. package/packages/bundled-features/src/metrics/compute.ts +1 -1
  265. package/packages/bundled-features/src/metrics/feature.ts +6 -6
  266. package/packages/bundled-features/src/metrics/index.ts +8 -8
  267. package/packages/bundled-features/src/metrics/types.ts +1 -1
  268. package/packages/bundled-features/src/metrics/validate.ts +1 -1
  269. package/packages/bundled-features/src/metrics/{constants.ts → web/constants.ts} +0 -1
  270. package/packages/bundled-features/src/metrics/window.ts +1 -1
  271. package/packages/bundled-features/src/notes-history/feature.ts +1 -1
  272. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  273. package/packages/bundled-features/src/notes-history/index.ts +8 -8
  274. package/packages/bundled-features/src/notes-history/web/client-plugin.tsx +1 -3
  275. package/packages/bundled-features/src/notes-history/{constants.ts → web/constants.ts} +0 -1
  276. package/packages/bundled-features/src/notes-history/web/i18n.ts +0 -1
  277. package/packages/bundled-features/src/notes-history/web/index.ts +2 -3
  278. package/packages/bundled-features/src/notes-history/web/notes-section.tsx +2 -3
  279. package/packages/bundled-features/src/personal-access-tokens/feature.ts +12 -10
  280. package/packages/bundled-features/src/personal-access-tokens/handlers/available-scopes.query.ts +1 -1
  281. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +1 -1
  282. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  283. package/packages/bundled-features/src/personal-access-tokens/hash.ts +1 -1
  284. package/packages/bundled-features/src/personal-access-tokens/i18n.ts +2 -2
  285. package/packages/bundled-features/src/personal-access-tokens/index.ts +5 -5
  286. package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -1
  287. package/packages/bundled-features/src/personal-access-tokens/schema/api-token.ts +1 -1
  288. package/packages/bundled-features/src/personal-access-tokens/screens.ts +2 -2
  289. package/packages/bundled-features/src/personal-access-tokens/{constants.ts → web/constants.ts} +0 -1
  290. package/packages/bundled-features/src/personal-access-tokens/{scopes.ts → web/scopes.ts} +0 -1
  291. package/packages/bundled-features/src/presets/changes.json +7 -0
  292. package/packages/bundled-features/src/presets/index.ts +0 -1
  293. package/packages/bundled-features/src/presets/security-baseline.ts +1 -1
  294. package/packages/bundled-features/src/renderer-foundation/types.ts +1 -1
  295. package/packages/bundled-features/src/secrets/feature.ts +1 -1
  296. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +1 -1
  297. package/packages/bundled-features/src/secrets/handlers/list.query.ts +1 -1
  298. package/packages/bundled-features/src/secrets/handlers/set.write.ts +1 -1
  299. package/packages/bundled-features/src/secrets/i18n.ts +1 -1
  300. package/packages/bundled-features/src/secrets/index.ts +8 -8
  301. package/packages/bundled-features/src/secrets/{constants.ts → web/constants.ts} +0 -1
  302. package/packages/bundled-features/src/secrets/write-gate.ts +1 -1
  303. package/packages/bundled-features/src/sessions/feature.ts +7 -4
  304. package/packages/bundled-features/src/sessions/{i18n.ts → web/i18n.ts} +0 -1
  305. package/packages/bundled-features/src/shared/index.ts +6 -1
  306. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +10 -2
  307. package/packages/bundled-features/src/shared/web/translate-or-raw.ts +0 -1
  308. package/packages/bundled-features/src/subscription-stripe/feature.ts +2 -0
  309. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +19 -0
  310. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +1 -0
  311. package/packages/bundled-features/src/tags/changes.json +6 -0
  312. package/packages/bundled-features/src/tags/feature.ts +1 -1
  313. package/packages/bundled-features/src/tags/handlers/assign-tag.write.ts +11 -7
  314. package/packages/bundled-features/src/tags/handlers/create-tag.write.ts +1 -1
  315. package/packages/bundled-features/src/tags/handlers/delete-tag.write.ts +4 -1
  316. package/packages/bundled-features/src/tags/handlers/remove-tag.write.ts +1 -1
  317. package/packages/bundled-features/src/tags/handlers/update-tag.write.ts +1 -1
  318. package/packages/bundled-features/src/tags/index.ts +12 -12
  319. package/packages/bundled-features/src/tags/screens.ts +1 -1
  320. package/packages/bundled-features/src/tags/web/client-plugin.tsx +1 -3
  321. package/packages/bundled-features/src/tags/{constants.ts → web/constants.ts} +4 -1
  322. package/packages/bundled-features/src/tags/web/entity-tags.tsx +1 -2
  323. package/packages/bundled-features/src/tags/web/i18n.ts +2 -2
  324. package/packages/bundled-features/src/tags/web/index.ts +2 -3
  325. package/packages/bundled-features/src/tags/web/tag-chip.tsx +0 -1
  326. package/packages/bundled-features/src/tags/web/tag-filter.tsx +1 -2
  327. package/packages/bundled-features/src/tags/web/tag-manager.tsx +5 -4
  328. package/packages/bundled-features/src/tags/web/tag-picker.tsx +0 -1
  329. package/packages/bundled-features/src/tags/web/tag-section.tsx +1 -2
  330. package/packages/bundled-features/src/tags/web/tags-cell.tsx +1 -2
  331. package/packages/bundled-features/src/template-resolver/README.md +1 -1
  332. package/packages/bundled-features/src/template-resolver/api.ts +75 -28
  333. package/packages/bundled-features/src/template-resolver/changes.json +43 -0
  334. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +1 -1
  335. package/packages/bundled-features/src/template-resolver/compile-steps-block.ts +2 -2
  336. package/packages/bundled-features/src/template-resolver/document-ops.ts +5 -5
  337. package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +4 -4
  338. package/packages/bundled-features/src/template-resolver/feature.ts +13 -4
  339. package/packages/bundled-features/src/template-resolver/handlers/by-slug.query.ts +6 -1
  340. package/packages/bundled-features/src/template-resolver/handlers/by-tenant.query.ts +6 -2
  341. package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
  342. package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -1
  343. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +19 -2
  344. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
  345. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +7 -1
  346. package/packages/bundled-features/src/template-resolver/handlers/discard-draft.write.ts +1 -1
  347. package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +8 -2
  348. package/packages/bundled-features/src/template-resolver/handlers/document-blocks.query.ts +2 -2
  349. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +5 -2
  350. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +4 -2
  351. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +10 -5
  352. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +5 -2
  353. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +68 -10
  354. package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
  355. package/packages/bundled-features/src/template-resolver/handlers/resource-shared.ts +1 -1
  356. package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +1 -1
  357. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
  358. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +1 -1
  359. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +1 -1
  360. package/packages/bundled-features/src/template-resolver/handlers/template-gates.ts +6 -6
  361. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +2 -2
  362. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +8 -2
  363. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +4 -2
  364. package/packages/bundled-features/src/template-resolver/i18n.ts +25 -0
  365. package/packages/bundled-features/src/template-resolver/index.ts +60 -59
  366. package/packages/bundled-features/src/template-resolver/layout-appearance.ts +1 -1
  367. package/packages/bundled-features/src/template-resolver/layout-regions.ts +1 -1
  368. package/packages/bundled-features/src/template-resolver/seeding.ts +16 -7
  369. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +2 -2
  370. package/packages/bundled-features/src/template-resolver/table.ts +1 -1
  371. package/packages/bundled-features/src/template-resolver/template-bundle.ts +2 -2
  372. package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +82 -0
  373. package/packages/bundled-features/src/template-resolver/template-draft.ts +1 -1
  374. package/packages/bundled-features/src/template-resolver/template-edit-policy.ts +2 -2
  375. package/packages/bundled-features/src/template-resolver/template-meta.ts +2 -2
  376. package/packages/bundled-features/src/template-resolver/template-preview.ts +14 -10
  377. package/packages/bundled-features/src/template-resolver/template-usage.ts +1 -1
  378. package/packages/bundled-features/src/template-resolver/template-validation.ts +2 -2
  379. package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
  380. package/packages/bundled-features/src/template-resolver/user-content-table.ts +1 -1
  381. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +4 -5
  382. package/packages/bundled-features/src/template-resolver/{constants.ts → web/constants.ts} +7 -10
  383. package/packages/bundled-features/src/template-resolver/{document-blocks.ts → web/document-blocks.ts} +0 -1
  384. package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +2 -3
  385. package/packages/bundled-features/src/template-resolver/web/document-editor.tsx +0 -1
  386. package/packages/bundled-features/src/template-resolver/{document-images.ts → web/document-images.ts} +0 -1
  387. package/packages/bundled-features/src/template-resolver/{document-schema.ts → web/document-schema.ts} +0 -1
  388. package/packages/bundled-features/src/template-resolver/{document-steps.ts → web/document-steps.ts} +0 -1
  389. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +6 -7
  390. package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +2 -3
  391. package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +1 -2
  392. package/packages/bundled-features/src/template-resolver/web/i18n.ts +2 -1
  393. package/packages/bundled-features/src/template-resolver/web/index.ts +13 -14
  394. package/packages/bundled-features/src/template-resolver/{mail-constants.ts → web/mail-constants.ts} +0 -1
  395. package/packages/bundled-features/src/template-resolver/{pdf-constants.ts → web/pdf-constants.ts} +0 -1
  396. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor-lazy.tsx +0 -1
  397. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +5 -4
  398. package/packages/bundled-features/src/template-resolver/{placeholder-text.ts → web/placeholder-text.ts} +0 -1
  399. package/packages/bundled-features/src/template-resolver/{qualified-names.ts → web/qualified-names.ts} +0 -1
  400. package/packages/bundled-features/src/template-resolver/web/use-stable-by-key.ts +0 -1
  401. package/packages/bundled-features/src/tenant/handlers/add-member.write.ts +1 -1
  402. package/packages/bundled-features/src/tenant/index.ts +7 -7
  403. package/packages/bundled-features/src/tenant/invitation-table.ts +1 -1
  404. package/packages/bundled-features/src/tenant/invited-membership.ts +1 -1
  405. package/packages/bundled-features/src/tenant/last-tenant-admin.ts +1 -1
  406. package/packages/bundled-features/src/tenant/member-role-options.ts +1 -1
  407. package/packages/bundled-features/src/tenant/screens.ts +2 -2
  408. package/packages/bundled-features/src/tenant/web/client-plugin.tsx +1 -2
  409. package/packages/bundled-features/src/tenant/{constants.ts → web/constants.ts} +3 -6
  410. package/packages/bundled-features/src/tenant/web/index.ts +0 -1
  411. package/packages/bundled-features/src/tenant/web/member-roles-cell.tsx +0 -1
  412. package/packages/bundled-features/src/tenant/web/member-status-cell.tsx +0 -1
  413. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +2 -2
  414. package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
  415. package/packages/bundled-features/src/tier-engine/feature.ts +7 -7
  416. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +1 -1
  417. package/packages/bundled-features/src/tier-engine/index.ts +8 -8
  418. package/packages/bundled-features/src/tier-engine/web/client-plugin.tsx +2 -3
  419. package/packages/bundled-features/src/tier-engine/{constants.ts → web/constants.ts} +2 -3
  420. package/packages/bundled-features/src/tier-engine/{i18n.ts → web/i18n.ts} +0 -1
  421. package/packages/bundled-features/src/tier-engine/web/index.ts +0 -1
  422. package/packages/bundled-features/src/user/handlers/create.write.ts +1 -1
  423. package/packages/bundled-features/src/user/handlers/update-roles.ts +1 -1
  424. package/packages/bundled-features/src/user/handlers/update.write.ts +1 -1
  425. package/packages/bundled-features/src/user/index.ts +1 -1
  426. package/packages/bundled-features/src/user/invited-global-roles.ts +1 -1
  427. package/packages/bundled-features/src/user/schema/user.ts +1 -1
  428. package/packages/bundled-features/src/user/{constants.ts → web/constants.ts} +0 -1
  429. package/packages/bundled-features/src/user-data-rights/changes.json +14 -0
  430. package/packages/bundled-features/src/user-data-rights/env.ts +1 -1
  431. package/packages/bundled-features/src/user-data-rights/feature.ts +9 -9
  432. package/packages/bundled-features/src/user-data-rights/index.ts +1 -1
  433. package/packages/bundled-features/src/user-data-rights/lib/resolve-tenant-model.ts +1 -1
  434. package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +1 -1
  435. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +2 -3
  436. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +0 -1
  437. package/packages/bundled-features/src/user-data-rights/{constants.ts → web/constants.ts} +11 -12
  438. package/packages/bundled-features/src/user-data-rights/web/default-translations.ts +91 -0
  439. package/packages/bundled-features/src/user-data-rights/web/i18n.ts +41 -91
  440. package/packages/bundled-features/src/user-data-rights/web/index.ts +1 -2
  441. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +1 -2
  442. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +0 -1
  443. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +0 -1
  444. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +10 -1
  445. package/packages/bundled-features/src/user-profile/feature.ts +2 -2
  446. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +1 -1
  447. package/packages/bundled-features/src/user-profile/index.ts +3 -2
  448. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +2 -3
  449. package/packages/bundled-features/src/user-profile/{constants.ts → web/constants.ts} +0 -1
  450. package/packages/bundled-features/src/user-profile/{i18n.ts → web/i18n.ts} +0 -1
  451. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +2 -3
  452. package/packages/bundled-features/src/waitlist/changes.json +6 -0
  453. package/packages/bundled-features/src/waitlist/entity.ts +1 -1
  454. package/packages/bundled-features/src/waitlist/feature.ts +5 -5
  455. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +3 -3
  456. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +5 -1
  457. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  458. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +3 -3
  459. package/packages/bundled-features/src/waitlist/import.ts +1 -1
  460. package/packages/bundled-features/src/waitlist/index.ts +11 -11
  461. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +1 -1
  462. package/packages/bundled-features/src/waitlist/link-on-signup.ts +1 -1
  463. package/packages/bundled-features/src/waitlist/mail.ts +7 -6
  464. package/packages/bundled-features/src/waitlist/payloads.ts +1 -1
  465. package/packages/bundled-features/src/waitlist/screens.ts +1 -1
  466. package/packages/bundled-features/src/waitlist/{constants.ts → web/constants.ts} +0 -1
  467. package/samples/apps/styleguide/src/features/content/web.tsx +0 -1
  468. package/samples/apps/ui-walkthrough/src/app/client.tsx +2 -0
  469. package/samples/apps/ui-walkthrough/src/app/seed-rental.ts +17 -1
  470. package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +11 -0
  471. package/samples/apps/ui-walkthrough/src/app/server.ts +2 -1
  472. package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +35 -7
  473. package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +6 -0
  474. package/samples/apps/ui-walkthrough/src/features/rental/entities.ts +27 -0
  475. package/samples/apps/ui-walkthrough/src/features/rental/feature.ts +61 -7
  476. package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +48 -24
  477. package/samples/apps/ui-walkthrough/src/features/rental/invoice-receive.ts +0 -1
  478. package/samples/apps/ui-walkthrough/src/features/rental/lease-support.ts +17 -1
  479. package/samples/apps/ui-walkthrough/src/features/rental/qualified-names.ts +3 -0
  480. package/samples/apps/ui-walkthrough/src/features/rental/receipts-upload.ts +70 -0
  481. package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +90 -13
  482. package/samples/apps/ui-walkthrough/src/features/rental/web/index.ts +0 -2
  483. package/samples/apps/ui-walkthrough/src/features/subscription-plans/feature.ts +103 -0
  484. package/samples/apps/ui-walkthrough/src/features/subscription-plans/i18n.ts +36 -0
  485. package/samples/apps/ui-walkthrough/src/features/subscription-plans/index.ts +2 -0
  486. package/samples/apps/ui-walkthrough/src/features/subscription-plans/seed.ts +21 -0
  487. package/samples/apps/ui-walkthrough/src/run-config.ts +11 -0
  488. package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +1 -1
  489. package/samples/apps/use-all-bundled/feature-manifest.json +4 -4
  490. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +1 -1
  491. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +3 -1
  492. package/samples/recipes/compose-stacks/README.md +1 -2
  493. package/samples/recipes/embedded/README.md +5 -5
  494. package/samples/recipes/embedded/src/handlers/invoice-receive.write.ts +0 -1
  495. package/samples/recipes/embedded/src/screens/invoice-receive.screen.ts +9 -12
  496. package/samples/recipes/legal-pages/README.md +2 -2
  497. package/samples/recipes/legal-pages/src/feature.ts +1 -1
  498. package/samples/recipes/reference-data/src/feature.ts +3 -7
  499. package/packages/bundled-features/src/admin-shell/i18n.ts +0 -54
  500. package/packages/bundled-features/src/audit/i18n.ts +0 -25
  501. package/packages/bundled-features/src/auth-mfa/web/qrcode-browser.d.ts +0 -11
  502. package/packages/bundled-features/src/jobs/i18n.ts +0 -55
  503. package/packages/bundled-features/src/managed-pages/i18n.ts +0 -63
  504. package/packages/bundled-features/src/presets/dsgvo-self-service.ts +0 -35
  505. package/packages/bundled-features/src/user-data-rights/i18n.ts +0 -44
  506. package/samples/apps/ui-walkthrough/src/features/rental/web/upload-standard-layout.tsx +0 -61
@@ -23,7 +23,7 @@ const features = [
23
23
  const app = createKumikoApp({
24
24
  features,
25
25
  extraContext: ({ db }) => ({
26
- templateResolver: createTemplateResolverApi(db),
26
+ templateResolver: createTemplateResolverApi(db, registry),
27
27
  }),
28
28
  });
29
29
  ```
@@ -4,12 +4,10 @@
4
4
 
5
5
  import type { DbRunner, TenantDb } from "@cosmicdrift/kumiko-framework/db";
6
6
  import { selectMany } from "@cosmicdrift/kumiko-framework/db";
7
- import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
7
+ import type { Registry, SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
8
8
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
9
9
  import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
10
10
  import type { FileAttachmentRef } from "../renderer-foundation/index.ts";
11
- import type { ContentFormat, TemplateKind } from "./constants.ts";
12
- import { FALLBACK_LOCALE, SYSTEM_TENANT_ID } from "./constants.ts";
13
11
  import {
14
12
  fileAttachmentsOf,
15
13
  imageLinksOf,
@@ -18,8 +16,16 @@ import {
18
16
  type TemplatePdfAttachmentLink,
19
17
  } from "./linked-resources.ts";
20
18
  import { type TemplateResourceRow, templateResourcesTable } from "./table.ts";
21
- import { activeVersionOf, servedVersionOf } from "./template-draft.ts";
19
+ import {
20
+ deliveryPolicyOf,
21
+ isRowServed,
22
+ isServedByCollectionOnly,
23
+ type TemplateDeliveryPolicy,
24
+ } from "./template-delivery-policy.ts";
25
+ import { activeVersionOf, isSystemAdmin, servedVersionOf } from "./template-draft.ts";
22
26
  import { parseTemplateMeta, type TemplateMeta } from "./template-meta.ts";
27
+ import type { ContentFormat, TemplateKind } from "./web/constants.ts";
28
+ import { FALLBACK_LOCALE, SYSTEM_TENANT_ID } from "./web/constants.ts";
23
29
 
24
30
  // Public TemplateResource: what consumers see. Hides DB-internal columns
25
31
  // (insertedById, internal id-type) but keeps the fields needed for rendering.
@@ -68,15 +74,11 @@ export type ResolveLayoutRequest = {
68
74
 
69
75
  export type TemplateResolverApi = {
70
76
  /**
71
- * Findet ein konkretes Template by (tenantId, slug, kind, locale).
72
- * Kein Locale-Fallback, keine Override-Hierarchie — Raw-Lookup für
73
- * Admin-UI-Edits und Konformitäts-Tests. Für Render-Aufrufe immer
74
- * `resolveTemplate` nutzen.
77
+ * Raw lookup by (tenantId, slug, kind, locale): no locale fallback, no override
78
+ * hierarchy. Render paths must use `resolveTemplate`. `scope: "system"` forces
79
+ * SYSTEM_TENANT_ID and ignores the passed tenantId.
75
80
  *
76
- * `scope: "system"` zwingt Lookup gegen SYSTEM_TENANT_ID (ignoriert
77
- * den übergebenen tenantId). Default = Lookup gegen den übergebenen
78
- * tenantId direkt (Caller wählt entweder Tenant oder System per
79
- * tenantId).
81
+ * Tenant rows of a template that is not tenantEditable are not returned.
80
82
  */
81
83
  readonly findExact: (args: {
82
84
  readonly tenantId: TenantId;
@@ -87,18 +89,10 @@ export type TemplateResolverApi = {
87
89
  }) => Promise<TemplateResource | null>;
88
90
 
89
91
  /**
90
- * Resolver mit 4-Stufen-Fallback (siehe template-resolver.md):
91
- * 1. tenant + requested-locale
92
- * 2. system + requested-locale
93
- * 3. tenant + FALLBACK_LOCALE
94
- * 4. system + FALLBACK_LOCALE
95
- * Resource-Substitution wird hier NICHT ausgeführt — das macht der
96
- * Caller (renderer-foundation-Plugin) je nach kind-passendem Modus
97
- * (inline-base64 vs. signed-url). API liefert TemplateResource pur.
98
- *
99
- * **Caller-Invariante:** `tenantId` MUSS vom Server kommen (typisch
100
- * `ctx.user.tenantId`). Niemals direkt aus User-Input — sonst kann
101
- * User cross-tenant Templates abfragen (Tenant-Isolation gebrochen).
92
+ * Four-step fallback: tenant+locale, system+locale, tenant+FALLBACK_LOCALE,
93
+ * system+FALLBACK_LOCALE (see template-resolver.md).
94
+ * Tenant rows count only for templates unlocked for tenants (tenantEditable,
95
+ * or a collection with access); locked overrides are skipped but stay stored.
102
96
  */
103
97
  readonly resolveTemplate: (args: ResolveRequest) => Promise<TemplateResource>;
104
98
 
@@ -114,12 +108,18 @@ export type TemplateResolverApi = {
114
108
  readonly resolveLayout: (args: ResolveLayoutRequest) => Promise<TemplateResource>;
115
109
  };
116
110
 
117
- export function createTemplateResolverApi(db: DbRunner | TenantDb): TemplateResolverApi {
111
+ export function createTemplateResolverApi(
112
+ db: DbRunner | TenantDb,
113
+ registry: Registry,
114
+ ): TemplateResolverApi {
115
+ const deliveryPolicy = deliveryPolicyOf(registry);
116
+ // A collection entry must not shadow a system template of the same slug that the app did not unlock.
117
+ const isServed = (row: TemplateResourceRow) => isRowDelivered(db, deliveryPolicy, row);
118
118
  return {
119
119
  findExact: async ({ tenantId, slug, kind, locale, scope }) => {
120
120
  const effectiveTenantId = scope === "system" ? SYSTEM_TENANT_ID : tenantId;
121
121
  const row = await fetchTemplate(db, effectiveTenantId, slug, kind, locale);
122
- return row ? toPublic(row) : null;
122
+ return row && (await isServed(row)) ? toPublic(row) : null;
123
123
  },
124
124
 
125
125
  resolveTemplate: async ({ tenantId, slug, kind, locale }) => {
@@ -135,14 +135,16 @@ export function createTemplateResolverApi(db: DbRunner | TenantDb): TemplateReso
135
135
  : []),
136
136
  ];
137
137
  for (const c of candidates) {
138
+ if (!isRowServed(deliveryPolicy, { tenantId: c.tid, kind, slug })) continue;
138
139
  const row = await fetchTemplate(db, c.tid, slug, kind, c.loc);
139
- if (row && row.status === "active") return toPublic(row);
140
+ if (row && row.status === "active" && (await isServed(row))) return toPublic(row);
140
141
  }
141
142
  throw new TemplateNotFoundError({ slug, kind, locale });
142
143
  },
143
144
 
144
145
  resolveLayout: async ({ tenantId, slug, kind, locale }) => {
145
146
  for (const tid of [tenantId, SYSTEM_TENANT_ID]) {
147
+ if (!isRowServed(deliveryPolicy, { tenantId: tid, kind, slug })) continue;
146
148
  const rows = await selectMany<TemplateResourceRow>(db, templateResourcesTable, {
147
149
  tenantId: tid,
148
150
  slug,
@@ -156,6 +158,51 @@ export function createTemplateResolverApi(db: DbRunner | TenantDb): TemplateReso
156
158
  };
157
159
  }
158
160
 
161
+ // The one delivery rule for a stored row: unlocked, and a collection entry never shadows a system
162
+ // template of the same slug that the app did not unlock.
163
+ export async function isRowDelivered(
164
+ db: DbRunner | TenantDb,
165
+ policy: TemplateDeliveryPolicy,
166
+ row: TemplateResourceRow,
167
+ ): Promise<boolean> {
168
+ if (!isRowServed(policy, row)) return false;
169
+ if (row.tenantId === SYSTEM_TENANT_ID || !isServedByCollectionOnly(policy, row)) return true;
170
+ return !(await systemTemplateExists(db, row.kind, row.slug));
171
+ }
172
+
173
+ export async function isRowDeliveredTo(
174
+ db: DbRunner | TenantDb,
175
+ policy: TemplateDeliveryPolicy,
176
+ user: { readonly roles: readonly string[] },
177
+ row: TemplateResourceRow,
178
+ ): Promise<boolean> {
179
+ return isSystemAdmin(user) || (await isRowDelivered(db, policy, row));
180
+ }
181
+
182
+ export async function filterDeliveredTo(
183
+ db: DbRunner | TenantDb,
184
+ policy: TemplateDeliveryPolicy,
185
+ user: { readonly roles: readonly string[] },
186
+ rows: readonly TemplateResourceRow[],
187
+ ): Promise<TemplateResourceRow[]> {
188
+ const flags = await Promise.all(rows.map((row) => isRowDeliveredTo(db, policy, user, row)));
189
+ return rows.filter((_, index) => flags[index]);
190
+ }
191
+
192
+ export async function systemTemplateExists(
193
+ db: DbRunner | TenantDb,
194
+ kind: string,
195
+ slug: string,
196
+ ): Promise<boolean> {
197
+ const rows = await selectMany(
198
+ db,
199
+ templateResourcesTable,
200
+ { tenantId: SYSTEM_TENANT_ID, slug, kind },
201
+ { limit: 1 },
202
+ );
203
+ return rows.length > 0;
204
+ }
205
+
159
206
  function pickActiveLayoutRow(
160
207
  rows: readonly TemplateResourceRow[],
161
208
  locale: string,
@@ -268,7 +315,7 @@ export function requireTemplateResolver(
268
315
  throw new InternalError({
269
316
  message:
270
317
  `[${callerName}] ctx.templateResolver missing — App-Bootstrap muss ` +
271
- `extraContext: { templateResolver: createTemplateResolverApi(db) } setzen ` +
318
+ `extraContext: { templateResolver: createTemplateResolverApi(db, registry) } setzen ` +
272
319
  `(siehe template-resolver/README.md).`,
273
320
  });
274
321
  }
@@ -1,4 +1,47 @@
1
1
  [
2
+ {
3
+ "version": "0.379.0",
4
+ "type": "improvement",
5
+ "title": "Titles for the template-resolver write handlers",
6
+ "detail": "Every agent-callable template-resolver write handler now has a title in de, en, es, fr and it, so the AI assistant names actions such as \"Edit template draft\" instead of \"template-resolver:write:patch-draft\". The handlers of mounted content collections (`<id>-set`) stay untitled because their names depend on the app. The empty-field hint of the placeholder line editor now ends in an ellipsis inside the field instead of running past it."
7
+ },
8
+ {
9
+ "version": "0.379.0",
10
+ "type": "breaking",
11
+ "title": "Overrides of locked templates are no longer served",
12
+ "detail": "A tenant override of a mail, PDF or layout template is delivered (mail send, PDF render, linked PDFs, layouts, previews, export bundles, document blocks, overview, text blocks) only while the template is listed in tenantEditable. A locked override stays stored and has no effect; listing the template makes it effective again, nothing is deleted. A SystemAdmin sees locked overrides in the overview (`lockedOverride`, `lockedOverrideI18nKey`) and can reset or archive them with the existing handlers; the template-resolver queries do not show them to a TenantAdmin; the audit log keeps the history. Tenant rows of a collection mounted with `access` are served, except for a slug that has a system template outside tenantEditable: that system template wins, and the collection `-set` handler refuses such a slug for a non-SystemAdmin. createTemplateResolverApi(db) became createTemplateResolverApi(db, registry) because the delivery policy is read from the mounted feature; without the mounted feature no tenant override is served.",
13
+ "migration": "Overrides of templates that are not tenantEditable are no longer served; enable the template via tenantEditable to keep using them. Pass the registry as second argument to createTemplateResolverApi (ctx.registry in handlers, stack.registry in tests). Tenant rows without a system counterpart (for example text blocks seeded directly into a tenant) are hidden as well unless listed in tenantEditable."
14
+ },
15
+ {
16
+ "version": "0.379.0",
17
+ "type": "improvement",
18
+ "title": "Overview label for locked template overrides",
19
+ "detail": "Adds templateResolver.overview.lockedOverride."
20
+ },
21
+ {
22
+ "version": "0.379.0",
23
+ "type": "improvement",
24
+ "title": "Mail rendering follows the template delivery policy",
25
+ "detail": "Resolves templates through createTemplateResolverApi(db, registry); overrides of locked templates fall back to the system version."
26
+ },
27
+ {
28
+ "version": "0.379.0",
29
+ "type": "improvement",
30
+ "title": "PDF rendering follows the template delivery policy",
31
+ "detail": "Resolves templates through createTemplateResolverApi(db, registry); overrides of locked templates fall back to the system version."
32
+ },
33
+ {
34
+ "version": "0.379.0",
35
+ "type": "improvement",
36
+ "title": "Samples follow the createTemplateResolverApi(db, registry) signature",
37
+ "detail": "Recipes and sample apps build the template resolver API with the registry as second argument."
38
+ },
39
+ {
40
+ "version": "0.379.0",
41
+ "type": "improvement",
42
+ "title": "seedSystemTemplate accepts titleI18nKey",
43
+ "detail": "A seeded template can store an i18n key as its title (titleI18nKey, exclusive with title). The overview returns the key; the document-designer overview, mail editor and PDF link modal translate it and fall back to the raw text. Templates without a key behave as before; no migration."
44
+ },
2
45
  {
3
46
  "version": "0.378.0",
4
47
  "type": "improvement",
@@ -11,7 +11,7 @@ import {
11
11
  isDocumentPlaceholderHref,
12
12
  isDocumentReferenceName,
13
13
  isDocumentResourceKey,
14
- } from "./document-schema.ts";
14
+ } from "./web/document-schema.ts";
15
15
 
16
16
  // Private-use characters mark where a Handlebars expression goes. Author text
17
17
  // is scrubbed of them first and every `{`/`}` is entity-encoded before the
@@ -1,7 +1,7 @@
1
1
  import type { Element as ScanElement } from "happy-dom";
2
- import { isDocumentReferenceName } from "./document-schema.ts";
3
- import { readDocumentSteps } from "./document-steps.ts";
4
2
  import { isHexColor } from "./layout-appearance.ts";
3
+ import { isDocumentReferenceName } from "./web/document-schema.ts";
4
+ import { readDocumentSteps } from "./web/document-steps.ts";
5
5
 
6
6
  export const DEFAULT_STEPS_COLOR = "#1f5468";
7
7
  const TODO_BAR_COLOR = "#ECEDEA";
@@ -1,17 +1,17 @@
1
1
  import type { FieldIssue } from "@cosmicdrift/kumiko-framework/errors";
2
2
  import { getSchema, type JSONContent } from "@tiptap/core";
3
3
  import * as z from "zod";
4
- import type { DocumentHtmlKind } from "./constants.ts";
5
- import { documentBlocksForKind } from "./document-blocks.ts";
4
+ import { toVariableDef } from "./template-validation.ts";
5
+ import type { DocumentHtmlKind } from "./web/constants.ts";
6
+ import { documentBlocksForKind } from "./web/document-blocks.ts";
6
7
  import {
7
8
  DOCUMENT_TEXT_ALIGNMENTS,
8
9
  documentExtensions,
9
10
  isDocumentPlaceholderHref,
10
11
  isDocumentReferenceName,
11
12
  isDocumentResourceKey,
12
- } from "./document-schema.ts";
13
- import { contentToLine, lineToContent, singleLine } from "./placeholder-text.ts";
14
- import { toVariableDef } from "./template-validation.ts";
13
+ } from "./web/document-schema.ts";
14
+ import { contentToLine, lineToContent, singleLine } from "./web/placeholder-text.ts";
15
15
 
16
16
  export const MAX_DOCUMENT_OPS = 50;
17
17
 
@@ -5,8 +5,8 @@ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
5
5
  import type { JSONContent } from "@tiptap/core";
6
6
  import { generateHTML, generateJSON } from "@tiptap/html/server";
7
7
  import { type Element as ScanElement, Window } from "happy-dom";
8
- import type { ContentFormat } from "./constants.ts";
9
- import { DOCUMENT_HTML_KINDS } from "./constants.ts";
8
+ import type { ContentFormat } from "./web/constants.ts";
9
+ import { DOCUMENT_HTML_KINDS } from "./web/constants.ts";
10
10
  import {
11
11
  DOCUMENT_CONDITION_ATTRIBUTE,
12
12
  documentExtensions,
@@ -14,8 +14,8 @@ import {
14
14
  isDocumentPlaceholderHref,
15
15
  isDocumentReferenceName,
16
16
  isDocumentResourceKey,
17
- } from "./document-schema.ts";
18
- import { isDocumentStepKey } from "./document-steps.ts";
17
+ } from "./web/document-schema.ts";
18
+ import { isDocumentStepKey } from "./web/document-steps.ts";
19
19
 
20
20
  export type DocumentViolationCode =
21
21
  | "script_element"
@@ -3,7 +3,6 @@ import {
3
3
  createSystemConfig,
4
4
  defineFeature,
5
5
  } from "@cosmicdrift/kumiko-framework/engine";
6
- import { DEFAULT_COLLECTION_ACCESS, isCollectionRefusedKind } from "./constants.ts";
7
6
  import { bySlugQuery } from "./handlers/by-slug.query.ts";
8
7
  import { byTenantQuery } from "./handlers/by-tenant.query.ts";
9
8
  import { makeCollectionItemQuery } from "./handlers/collection-item.query.ts";
@@ -43,9 +42,12 @@ import { upsertSystemWrite } from "./handlers/upsert-system.write.ts";
43
42
  import { makeUpsertTenantWrite } from "./handlers/upsert-tenant.write.ts";
44
43
  import { usageQuery } from "./handlers/usage.query.ts";
45
44
  import { validateQuery } from "./handlers/validate.query.ts";
45
+ import { TEMPLATE_RESOLVER_I18N } from "./i18n.ts";
46
46
  import { templateResourceEntity } from "./table.ts";
47
+ import type { TemplateDeliveryPolicy } from "./template-delivery-policy.ts";
47
48
  import type { TenantEditableTemplate } from "./template-edit-policy.ts";
48
49
  import { userContentEntryEntity } from "./user-content-table.ts";
50
+ import { DEFAULT_COLLECTION_ACCESS, isCollectionRefusedKind } from "./web/constants.ts";
49
51
 
50
52
  // template-resolver — structured template storage with tenant-override
51
53
  // hierarchy, locale fallback and resource linking via file-foundation.
@@ -112,13 +114,19 @@ export function createTemplateResolverFeature(opts: TemplateResolverOptions = {}
112
114
  const tenantEditable = opts.tenantEditable ?? [];
113
115
  assertTenantEditableValid(tenantEditable);
114
116
  const policy = { tenantEditable };
117
+ const deliveryPolicy: TemplateDeliveryPolicy = {
118
+ tenantEditable: tenantEditable.map(({ kind, slug }) => ({ kind, slug })),
119
+ collectionKinds: collections
120
+ .filter((c) => c.ownership !== "user" && c.access !== undefined)
121
+ .map((c) => c.kind),
122
+ };
115
123
  const hasUserOwned = collections.some((c) => c.ownership === "user");
116
124
  return defineFeature("template-resolver", (r) => {
117
125
  r.describe(
118
126
  [
119
127
  "Every piece of editable text lives here, in one entity: mail bodies, notification texts, PDF document templates, AI prompts and plain text blocks. What a record is used for is the `kind` (`notification`, `mail`, `mail-layout`, `document-pdf`, `pdf-layout`, `ai-prompt`, `text-block`, `snippet`, `image-snapshot`).",
120
128
  "Reading is one call — `ctx.templateResolver.resolveTemplate({ tenantId, slug, kind, locale })`. It walks four levels: tenant+locale, system+locale, tenant+fallback-locale, system+fallback-locale. A tenant overrides a system default by simply having its own record; no application code changes. Writing programmatically goes through the `upsertSystem`, `upsertTenant`, `publish` and `archive` write handlers; a SystemAdmin retires or restores a system default with `publishSystem` and `archiveSystem`, and a tenant drops its override with `resetToSystem`. Saving a draft over an active template keeps the active version served and stores the edit beside it (column `draft`); `publish` makes it the served version, `discardDraft` / `discardDraftSystem` throws it away.",
121
- 'Editing templates is for SystemAdmin only. A TenantAdmin edits only the templates the app unlocks at the mount site, `createTemplateResolverFeature({ tenantEditable: [{ kind: "mail", slug: "status-update", access: { roles: ["TenantAdmin"] } }] })`, and every write handler enforces that on the server (override, draft, publish, archive, reset, copy-locale, import, resources, `set`). Each entry carries the `access` roles allowed to edit it, because a bundled feature cannot know the host\'s roles. Reading and delivery do not depend on it: a tenant override that exists is served. A collection mounted without `access` is SystemAdmin only.',
129
+ 'Editing templates is for SystemAdmin only. A TenantAdmin edits only the templates the app unlocks at the mount site, `createTemplateResolverFeature({ tenantEditable: [{ kind: "mail", slug: "status-update", access: { roles: ["TenantAdmin"] } }] })`, and every write handler enforces that on the server (override, draft, publish, archive, reset, copy-locale, import, resources, `set`). Each entry carries the `access` roles allowed to edit it, because a bundled feature cannot know the host\'s roles. The same list decides delivery: a tenant override is served (mail, PDF, layouts, text blocks) only while its template is listed in tenantEditable; otherwise the system version is served. A locked override stays stored, a SystemAdmin sees it in the overview marked as not delivered, and listing the template makes it effective again. Tenant rows of a collection mounted with `access` are always served. A collection mounted without `access` is SystemAdmin only.',
122
130
  "Text an editor should be able to change belongs in a collection, declared at mount: `createTemplateResolverFeature({ collections: [{ id, kind, access: { roles }, nav }] })`. It appears in the navigation, and `access` is part of the mount because a bundled feature cannot know the host's roles. Each collection gets its own `<id>-list` / `<id>-item` / `<id>-set` handlers, so the dispatcher enforces the separation.",
123
131
  "How a collection is edited follows from `contentFormat`: `plain` gives a text area, `rich` a small WYSIWYG (bold, italic, headings, lists, links), `markdown` a text area that stores markdown text (same insertable chips as `plain`). All three offer the collection's `variableSchema` as insertable chips and a preview rendered with sample data — an editor sees what `{{firstName}}` becomes without sending a mail. An app can register its own editor for a format; the last `clientFeature` that registers a format wins (a conflict logs a warning).",
124
132
  'A collection is tenant-wide by default. With `ownership: "user"` every user keeps their own entries — mail signatures being the obvious case. Those rows live in the separate `user-content-entry` entity and count as user data, so mounting one also requires the `template-resolver-user-data` feature and a migration on the app side.',
@@ -138,6 +146,7 @@ export function createTemplateResolverFeature(opts: TemplateResolverOptions = {}
138
146
  resourceMaxBytes: createSystemConfig("number", { default: 2_097_152, bounds: { min: 1 } }),
139
147
  },
140
148
  });
149
+ r.translations({ keys: TEMPLATE_RESOLVER_I18N });
141
150
  r.entity({ name: "template-resource", ...templateResourceEntity });
142
151
  // Only when the app actually mounts a user-owned collection: the entity's
143
152
  // `content` is `userOwned`, which makes it subject data — the boot guard
@@ -190,7 +199,7 @@ export function createTemplateResolverFeature(opts: TemplateResolverOptions = {}
190
199
  });
191
200
  r.queryHandler(makeCollectionListQuery(collection));
192
201
  r.queryHandler(makeCollectionItemQuery(collection));
193
- r.writeHandler(makeCollectionSetWrite(collection));
202
+ r.writeHandler(makeCollectionSetWrite(collection, policy));
194
203
  }
195
204
 
196
205
  // Visual-tree actions for the text-block content tree. The handle is
@@ -204,6 +213,6 @@ export function createTemplateResolverFeature(opts: TemplateResolverOptions = {}
204
213
  create: { args: { folder: emptyString } },
205
214
  });
206
215
 
207
- return { handlers, queries, treeHandle };
216
+ return { handlers, queries, treeHandle, deliveryPolicy };
208
217
  });
209
218
  }
@@ -1,8 +1,10 @@
1
1
  import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
- import { TEXT_BLOCK_KIND } from "../constants.ts";
4
+ import { isRowDeliveredTo } from "../api.ts";
5
5
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
6
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
7
+ import { TEXT_BLOCK_KIND } from "../web/constants.ts";
6
8
 
7
9
  // Public read of a single text-block by (tenantId, slug, locale). Anonymous
8
10
  // must be listed explicitly — `openToAll` alone is auth-only (regression
@@ -39,6 +41,9 @@ export const bySlugQuery = defineQueryHandler({
39
41
  });
40
42
 
41
43
  if (!row) return null;
44
+ if (!(await isRowDeliveredTo(ctx.db, deliveryPolicyOf(ctx.registry), query.user, row))) {
45
+ return null;
46
+ }
42
47
  return {
43
48
  slug: row.slug,
44
49
  locale: row.locale,
@@ -2,8 +2,10 @@ import { castTenantRows, selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
4
  import * as z from "zod";
5
- import { TEXT_BLOCK_KIND } from "../constants.ts";
5
+ import { filterDeliveredTo } from "../api.ts";
6
6
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
7
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
8
+ import { TEXT_BLOCK_KIND } from "../web/constants.ts";
7
9
 
8
10
  // All text-blocks of one tenant — feeds the public content tree sidebar.
9
11
  // Anonymous is listed explicitly so no-JWT visitors get the sidebar on public
@@ -39,8 +41,10 @@ export const byTenantQuery = defineQueryHandler({
39
41
  const rows = castTenantRows<TemplateResourceRow>(
40
42
  await selectMany(ctx.db, templateResourcesTable, { tenantId, kind: TEXT_BLOCK_KIND }),
41
43
  );
44
+ const policy = deliveryPolicyOf(ctx.registry);
45
+ const served = await filterDeliveredTo(ctx.db, policy, query.user, rows);
42
46
  return {
43
- blocks: rows.map((row) => ({
47
+ blocks: served.map((row) => ({
44
48
  slug: row.slug,
45
49
  locale: row.locale,
46
50
  title: row.title,
@@ -4,7 +4,7 @@ import {
4
4
  defineQueryHandler,
5
5
  } from "@cosmicdrift/kumiko-framework/engine";
6
6
  import * as z from "zod";
7
- import { DEFAULT_COLLECTION_ACCESS } from "../constants.ts";
7
+ import { DEFAULT_COLLECTION_ACCESS } from "../web/constants.ts";
8
8
  import {
9
9
  type CollectionEntryRow,
10
10
  collectionStore,
@@ -4,7 +4,7 @@ import {
4
4
  defineQueryHandler,
5
5
  } from "@cosmicdrift/kumiko-framework/engine";
6
6
  import * as z from "zod";
7
- import { DEFAULT_COLLECTION_ACCESS } from "../constants.ts";
7
+ import { DEFAULT_COLLECTION_ACCESS } from "../web/constants.ts";
8
8
  import {
9
9
  type CollectionEntryRow,
10
10
  collectionStore,
@@ -7,8 +7,10 @@ import {
7
7
  import { ValidationError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
8
8
  import * as z from "zod";
9
9
  import { requireForTenant } from "../../shared/index.ts";
10
- import { DEFAULT_COLLECTION_ACCESS, isCollectionRefusedKind } from "../constants.ts";
10
+ import { systemTemplateExists } from "../api.ts";
11
11
  import { documentViolationsToFieldIssues, sanitizeTemplateBody } from "../document-sanitizer.ts";
12
+ import { refuseTemplateEdit, type TemplateEditPolicy } from "../template-edit-policy.ts";
13
+ import { DEFAULT_COLLECTION_ACCESS, isCollectionRefusedKind } from "../web/constants.ts";
12
14
  import { type CollectionEntryRow, collectionStore } from "./collection-shared.ts";
13
15
  import { contentFormatSchema, folderSchema, localeSchema, slugSchema } from "./shared.ts";
14
16
 
@@ -19,7 +21,10 @@ import { contentFormatSchema, folderSchema, localeSchema, slugSchema } from "./s
19
21
  //
20
22
  // Like set.write this publishes on save (status active, empty variableSchema)
21
23
  // — the draft stage lives on upsertTenant + publish.
22
- export function makeCollectionSetWrite(collection: ContentCollectionDefinition) {
24
+ export function makeCollectionSetWrite(
25
+ collection: ContentCollectionDefinition,
26
+ editPolicy: TemplateEditPolicy,
27
+ ) {
23
28
  const store = collectionStore(collection);
24
29
  return defineWriteHandler({
25
30
  name: `${collection.id}-set`,
@@ -75,6 +80,18 @@ export function makeCollectionSetWrite(collection: ContentCollectionDefinition)
75
80
  );
76
81
  }
77
82
 
83
+ // The collection's access must not open a system template that the app did not unlock.
84
+ if (
85
+ collection.ownership !== "user" &&
86
+ (await systemTemplateExists(db, collection.kind, event.payload.slug))
87
+ ) {
88
+ const refused = refuseTemplateEdit(editPolicy, event.user, {
89
+ slug: event.payload.slug,
90
+ kind: collection.kind,
91
+ });
92
+ if (refused) return refused;
93
+ }
94
+
78
95
  const existing = await fetchOne<CollectionEntryRow>(db, store.table, {
79
96
  tenantId,
80
97
  slug: event.payload.slug,
@@ -16,9 +16,7 @@ import {
16
16
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
17
17
  import * as z from "zod";
18
18
  import { requireForTenant } from "../../shared/index.ts";
19
- import { CONTENT_FORMATS, type ContentFormat } from "../constants.ts";
20
19
  import { type LinkedResourceEntry, parseLinkedResourceEntries } from "../linked-resources.ts";
21
- import { TemplateResolverErrors } from "../qualified-names.ts";
22
20
  import {
23
21
  createLinkedResourceCopies,
24
22
  prepareLinkedResourceCopiesBeforeTransaction,
@@ -32,6 +30,8 @@ import {
32
30
  } from "../template-edit-policy.ts";
33
31
  import { attachTemplateResources } from "../template-resources.ts";
34
32
  import { resolveTemplateVariables } from "../template-validation.ts";
33
+ import { CONTENT_FORMATS, type ContentFormat } from "../web/constants.ts";
34
+ import { TemplateResolverErrors } from "../web/qualified-names.ts";
35
35
  import { targetExistsIssue } from "./bundle-import.ts";
36
36
  import { kindSchema, localeSchema, templateSlugSchema } from "./shared.ts";
37
37
  import { parseStoredJson, storedRecord } from "./template-gates.ts";
@@ -3,6 +3,7 @@ import { defineQueryHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framew
3
3
  import { NotFoundError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
5
5
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
6
+ import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
6
7
  import { isHiddenSystemDraft } from "../template-draft.ts";
7
8
  import { buildOverrideDiff } from "./override-diff.ts";
8
9
 
@@ -16,7 +17,12 @@ export const diffToSystemQuery = defineQueryHandler({
16
17
  const tenantRow = await fetchOne<TemplateResourceRow>(ctx.db, templateResourcesTable, {
17
18
  id: query.payload.id,
18
19
  });
19
- if (!tenantRow || tenantRow.tenantId !== query.user.tenantId || tenantRow.scope !== "tenant") {
20
+ if (
21
+ !tenantRow ||
22
+ tenantRow.tenantId !== query.user.tenantId ||
23
+ tenantRow.scope !== "tenant" ||
24
+ !isRowServedTo(deliveryPolicyOf(ctx.registry), query.user, tenantRow)
25
+ ) {
20
26
  throw new NotFoundError("template-resource", query.payload.id);
21
27
  }
22
28
  const systemRow = await fetchOne<TemplateResourceRow>(ctx.db, templateResourcesTable, {
@@ -1,12 +1,12 @@
1
1
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { NotFoundError, ValidationError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
3
3
  import * as z from "zod";
4
- import { TemplateResolverErrors } from "../qualified-names.ts";
5
4
  import {
6
5
  refuseMissingTemplate,
7
6
  refuseTemplateEdit,
8
7
  type TemplateEditPolicy,
9
8
  } from "../template-edit-policy.ts";
9
+ import { TemplateResolverErrors } from "../web/qualified-names.ts";
10
10
  import { executor } from "./shared.ts";
11
11
  import { loadTargetRow, type StatusTarget, writeAccessFor } from "./toggle-status.write.ts";
12
12
 
@@ -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
  }