@cosmicdrift/kumiko-bundled-features 0.366.0 → 0.368.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 (365) hide show
  1. package/dist/audit/handlers/details.query.js +1 -1
  2. package/dist/audit/handlers/list.query.js +1 -1
  3. package/dist/audit/run-escape-hatch-retention.js +1 -1
  4. package/dist/auth-email-password/bootstrap.js +1 -1
  5. package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +6 -3
  6. package/dist/auth-email-password/handlers/invite-accept.write.js +6 -3
  7. package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
  8. package/dist/auth-email-password/handlers/invite-signup-complete.write.js +6 -3
  9. package/dist/auth-email-password/handlers/signup-confirm.write.js +1 -1
  10. package/dist/auth-email-password/seeding.js +2 -2
  11. package/dist/auth-foundation/feature.d.ts +4 -0
  12. package/dist/auth-foundation/feature.js +37 -33
  13. package/dist/auth-foundation/index.d.ts +1 -1
  14. package/dist/auth-foundation/index.js +1 -1
  15. package/dist/auth-mfa/db/queries.js +1 -2
  16. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +1 -1
  17. package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
  18. package/dist/auth-mfa/handlers/reencrypt.job.js +2 -3
  19. package/dist/auth-mfa/handlers/status.query.js +1 -1
  20. package/dist/auth-mfa/handlers/verify.write.js +1 -1
  21. package/dist/auth-mfa/mfa-code-verifier.js +1 -1
  22. package/dist/auth-mfa/mfa-status-checker.js +1 -1
  23. package/dist/auth-mfa-user-data/index.d.ts +4 -0
  24. package/dist/auth-mfa-user-data/index.js +13 -9
  25. package/dist/billing-foundation/billing-info-query.js +1 -1
  26. package/dist/billing-foundation/feature.d.ts +1 -0
  27. package/dist/billing-foundation/feature.js +5 -6
  28. package/dist/billing-foundation/handlers/create-portal-session.write.js +1 -1
  29. package/dist/billing-foundation/projection.js +1 -2
  30. package/dist/cap-counter/calendar-cap-usage-reservation.d.ts +7 -0
  31. package/dist/cap-counter/calendar-cap-usage-reservation.js +28 -2
  32. package/dist/cap-counter/cap-reservation.d.ts +16 -0
  33. package/dist/cap-counter/cap-reservation.js +144 -14
  34. package/dist/cap-counter/feature.d.ts +4 -0
  35. package/dist/cap-counter/feature.js +74 -68
  36. package/dist/cap-counter/handlers/increment-rolling.write.js +3 -4
  37. package/dist/cap-counter/index.d.ts +3 -2
  38. package/dist/cap-counter/index.js +3 -2
  39. package/dist/cap-counter/tables.js +10 -3
  40. package/dist/cap-overview/handlers/caps-usage.query.js +1 -2
  41. package/dist/cap-overview/handlers/tenant-caps-list.query.js +1 -2
  42. package/dist/cap-overview/handlers/tenant-options.query.js +1 -1
  43. package/dist/channel-email/email-channel.d.ts +5 -1
  44. package/dist/channel-email/email-channel.js +8 -2
  45. package/dist/channel-email/feature.js +1 -1
  46. package/dist/channel-in-app/handlers/inbox.query.js +1 -1
  47. package/dist/channel-in-app/handlers/mark-all-read.write.js +1 -1
  48. package/dist/channel-in-app/handlers/mark-read.write.js +1 -1
  49. package/dist/channel-in-app/handlers/unread-count.query.js +1 -1
  50. package/dist/channel-in-app/tables.js +1 -2
  51. package/dist/compliance-profiles/handlers/for-tenant.query.js +1 -1
  52. package/dist/compliance-profiles/handlers/needs-profile.query.js +1 -1
  53. package/dist/compliance-profiles/handlers/set-profile.write.js +1 -2
  54. package/dist/compliance-profiles/resolve-for-tenant.js +1 -1
  55. package/dist/compliance-profiles/seeding.js +3 -5
  56. package/dist/compliance-profiles-ops/index.d.ts +8 -0
  57. package/dist/compliance-profiles-ops/index.js +19 -15
  58. package/dist/config/db/queries/resolver.js +1 -1
  59. package/dist/config/handlers/reencrypt.job.js +2 -2
  60. package/dist/config/resolver.js +1 -1
  61. package/dist/config/write-helpers.js +1 -1
  62. package/dist/crypto-shredding/handlers/forget-subject.write.js +6 -3
  63. package/dist/custom-fields/db/queries/field-access.js +1 -1
  64. package/dist/custom-fields/db/queries/projection.js +1 -1
  65. package/dist/custom-fields/db/queries/quota.js +1 -1
  66. package/dist/custom-fields/db/queries/retention.js +1 -2
  67. package/dist/custom-fields/db/queries/user-data-rights.js +1 -1
  68. package/dist/custom-fields/feature.d.ts +20 -2
  69. package/dist/custom-fields/feature.js +9 -13
  70. package/dist/custom-fields/handlers/clear-custom-field.write.js +2 -2
  71. package/dist/custom-fields/handlers/delete-system-field.write.js +2 -2
  72. package/dist/custom-fields/handlers/delete-tenant-field.write.js +2 -2
  73. package/dist/custom-fields/handlers/set-custom-field.write.js +2 -2
  74. package/dist/custom-fields/wire-for-entity.js +4 -4
  75. package/dist/data-retention/resolve-for-tenant.js +1 -1
  76. package/dist/data-retention/run-retention-cleanup.js +17 -13
  77. package/dist/delivery/address-opt-out.js +1 -2
  78. package/dist/delivery/attempt-log-retention.js +1 -1
  79. package/dist/delivery/channel-context.js +2 -1
  80. package/dist/delivery/db/queries/address-opt-outs.js +1 -1
  81. package/dist/delivery/db/queries/preferences.js +1 -1
  82. package/dist/delivery/delivery-service.d.ts +2 -0
  83. package/dist/delivery/delivery-service.js +46 -11
  84. package/dist/delivery/feature.js +2 -2
  85. package/dist/delivery/handlers/log.query.js +2 -3
  86. package/dist/delivery/handlers/preferences.query.js +1 -1
  87. package/dist/delivery/handlers/unsubscribe-address.write.d.ts +6 -0
  88. package/dist/delivery/handlers/unsubscribe-address.write.js +8 -5
  89. package/dist/delivery/index.d.ts +3 -0
  90. package/dist/delivery/index.js +2 -0
  91. package/dist/delivery/testing.d.ts +2 -0
  92. package/dist/delivery/types.d.ts +2 -1
  93. package/dist/delivery/unsubscribe-link.d.ts +25 -0
  94. package/dist/delivery/unsubscribe-link.js +40 -0
  95. package/dist/delivery/unsubscribe-page-strings.d.ts +11 -0
  96. package/dist/delivery/unsubscribe-page-strings.js +15 -0
  97. package/dist/delivery/unsubscribe.d.ts +3 -0
  98. package/dist/delivery/unsubscribe.js +65 -29
  99. package/dist/delivery/upsert-preference.js +1 -2
  100. package/dist/derivatives-sharp/feature.d.ts +4 -0
  101. package/dist/derivatives-sharp/feature.js +15 -11
  102. package/dist/derivatives-sharp/index.d.ts +1 -1
  103. package/dist/derivatives-sharp/index.js +1 -1
  104. package/dist/document-ingest-foundation/feature.d.ts +7 -0
  105. package/dist/document-ingest-foundation/feature.js +94 -90
  106. package/dist/document-ingest-foundation/forget-extract-with-file-ref.js +3 -3
  107. package/dist/document-ingest-foundation/index.d.ts +1 -1
  108. package/dist/document-ingest-foundation/index.js +1 -1
  109. package/dist/feature-toggles/global-feature-state-table.js +1 -2
  110. package/dist/feature-toggles/handlers/set.write.js +3 -5
  111. package/dist/feature-toggles/toggle-runtime.js +1 -1
  112. package/dist/file-derivatives/feature.d.ts +1 -0
  113. package/dist/file-derivatives/feature.js +2 -1
  114. package/dist/file-derivatives/handlers/public-variant-by-file-ref.query.js +1 -1
  115. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  116. package/dist/file-foundation/feature.d.ts +6 -0
  117. package/dist/file-foundation/feature.js +29 -25
  118. package/dist/file-foundation/index.d.ts +1 -1
  119. package/dist/file-foundation/index.js +1 -1
  120. package/dist/file-foundation/read-file-ref-content.js +1 -1
  121. package/dist/file-provider-inmemory/feature.d.ts +4 -0
  122. package/dist/file-provider-inmemory/feature.js +24 -20
  123. package/dist/file-provider-inmemory/index.d.ts +1 -1
  124. package/dist/file-provider-inmemory/index.js +1 -1
  125. package/dist/file-provider-s3/env-feature.d.ts +3 -0
  126. package/dist/file-provider-s3/env-feature.js +46 -0
  127. package/dist/file-provider-s3/feature.d.ts +26 -0
  128. package/dist/file-provider-s3/feature.js +84 -72
  129. package/dist/file-provider-s3/index.d.ts +1 -1
  130. package/dist/file-provider-s3/index.js +1 -1
  131. package/dist/file-provider-s3/lib/index.d.ts +3 -0
  132. package/dist/file-provider-s3/lib/index.js +2 -0
  133. package/dist/{files-provider-s3 → file-provider-s3/lib}/s3-provider.js +19 -19
  134. package/dist/file-provider-s3-env/index.d.ts +8 -1
  135. package/dist/file-provider-s3-env/index.js +7 -2
  136. package/dist/files-provider-s3/index.d.ts +5 -3
  137. package/dist/files-provider-s3/index.js +5 -2
  138. package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +1 -1
  139. package/dist/files-tenant-data/hooks.js +1 -2
  140. package/dist/folders/feature.d.ts +6 -2
  141. package/dist/folders/feature.js +4 -2
  142. package/dist/folders-user-data/index.d.ts +4 -0
  143. package/dist/folders-user-data/index.js +21 -17
  144. package/dist/form-draft/db/queries/cleanup.js +1 -1
  145. package/dist/form-draft/db/queries/draft-count.js +1 -1
  146. package/dist/form-draft/db/queries/owned-file-refs.js +1 -2
  147. package/dist/form-draft/feature.d.ts +4 -0
  148. package/dist/form-draft/feature.js +5 -1
  149. package/dist/form-draft/handlers/cleanup.job.js +2 -2
  150. package/dist/form-draft/index.d.ts +1 -1
  151. package/dist/form-draft/index.js +1 -1
  152. package/dist/form-draft/lookup.js +1 -1
  153. package/dist/form-draft-user-data/index.d.ts +4 -0
  154. package/dist/form-draft-user-data/index.js +13 -9
  155. package/dist/inbound-mail-foundation/feature.d.ts +4 -0
  156. package/dist/inbound-mail-foundation/feature.js +151 -147
  157. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +1 -2
  158. package/dist/inbound-mail-foundation/index.d.ts +1 -1
  159. package/dist/inbound-mail-foundation/index.js +1 -1
  160. package/dist/inbound-mail-foundation/oauth-access-token.js +1 -2
  161. package/dist/inbound-mail-foundation/projection.js +1 -2
  162. package/dist/inbound-mail-foundation/watch-supervisor.js +1 -1
  163. package/dist/inbound-provider-imap/feature.d.ts +4 -0
  164. package/dist/inbound-provider-imap/feature.js +16 -12
  165. package/dist/inbound-provider-imap/index.d.ts +1 -1
  166. package/dist/inbound-provider-imap/index.js +1 -1
  167. package/dist/inbound-provider-inmemory/feature.d.ts +4 -0
  168. package/dist/inbound-provider-inmemory/feature.js +14 -10
  169. package/dist/inbound-provider-inmemory/index.d.ts +1 -1
  170. package/dist/inbound-provider-inmemory/index.js +1 -1
  171. package/dist/jobs/db/queries/retention.js +1 -1
  172. package/dist/jobs/db/queries/stale-run-sweep.js +1 -1
  173. package/dist/jobs/handlers/detail.query.js +1 -1
  174. package/dist/jobs/handlers/list.query.js +1 -2
  175. package/dist/jobs/handlers/retry.write.js +1 -1
  176. package/dist/jobs/handlers/tenant-failures.query.js +1 -1
  177. package/dist/jobs/handlers/tenant-runs.query.js +1 -1
  178. package/dist/jobs/job-run-logger.js +1 -2
  179. package/dist/jobs/tenant-job-failure-table.js +1 -2
  180. package/dist/jobs/tenant-job-run-table.js +1 -2
  181. package/dist/ledger/feature.d.ts +6 -2
  182. package/dist/ledger/feature.js +4 -2
  183. package/dist/mail-foundation/feature.d.ts +23 -1
  184. package/dist/mail-foundation/feature.js +76 -49
  185. package/dist/mail-foundation/index.d.ts +1 -1
  186. package/dist/mail-foundation/index.js +1 -1
  187. package/dist/mail-transport-inmemory/feature.d.ts +4 -0
  188. package/dist/mail-transport-inmemory/feature.js +20 -16
  189. package/dist/mail-transport-inmemory/index.d.ts +1 -1
  190. package/dist/mail-transport-inmemory/index.js +1 -1
  191. package/dist/mail-transport-smtp/feature.d.ts +16 -0
  192. package/dist/mail-transport-smtp/feature.js +85 -79
  193. package/dist/mail-transport-smtp/index.d.ts +1 -1
  194. package/dist/mail-transport-smtp/index.js +1 -1
  195. package/dist/managed-pages/handlers/by-slug.query.js +1 -1
  196. package/dist/managed-pages/handlers/by-tenant-published.query.js +1 -2
  197. package/dist/managed-pages/handlers/set.write.js +1 -2
  198. package/dist/managed-pages/seeding.js +3 -5
  199. package/dist/metrics/compute.d.ts +1 -1
  200. package/dist/metrics/filters.d.ts +1 -1
  201. package/dist/metrics/filters.js +1 -1
  202. package/dist/metrics/validate.js +1 -1
  203. package/dist/notes-history/feature.d.ts +7 -2
  204. package/dist/notes-history/feature.js +4 -2
  205. package/dist/notes-history/handlers/add-note.write.js +1 -1
  206. package/dist/notes-history-user-data/hooks.js +1 -1
  207. package/dist/notes-history-user-data/index.d.ts +4 -0
  208. package/dist/notes-history-user-data/index.js +21 -17
  209. package/dist/personal-access-tokens/feature.d.ts +4 -1
  210. package/dist/personal-access-tokens/feature.js +10 -2
  211. package/dist/personal-access-tokens/handlers/create.write.js +1 -1
  212. package/dist/personal-access-tokens/handlers/list.query.js +2 -2
  213. package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
  214. package/dist/personal-access-tokens/resolver.js +1 -1
  215. package/dist/personal-access-tokens/revoke-for-user.js +1 -1
  216. package/dist/personal-access-tokens/roles.js +3 -5
  217. package/dist/personal-access-tokens/screens.js +2 -0
  218. package/dist/readiness/feature.d.ts +8 -0
  219. package/dist/readiness/feature.js +18 -14
  220. package/dist/readiness/index.d.ts +1 -1
  221. package/dist/readiness/index.js +1 -1
  222. package/dist/secrets/db/queries/read.js +1 -1
  223. package/dist/secrets/feature.d.ts +3 -0
  224. package/dist/secrets/feature.js +3 -2
  225. package/dist/secrets/handlers/rotate.job.js +2 -3
  226. package/dist/secrets/secrets-context.js +3 -4
  227. package/dist/sessions/db/queries/cleanup.js +1 -1
  228. package/dist/sessions/handlers/detail.query.js +1 -1
  229. package/dist/sessions/handlers/list.query.js +2 -2
  230. package/dist/sessions/handlers/mine.query.js +1 -1
  231. package/dist/sessions/handlers/revoke-all-for-user.write.js +1 -1
  232. package/dist/sessions/handlers/revoke-all-others.write.js +1 -1
  233. package/dist/sessions/handlers/revoke.write.js +1 -1
  234. package/dist/sessions/session-callbacks.js +4 -6
  235. package/dist/sessions/testing.d.ts +1 -1
  236. package/dist/tags/feature.d.ts +6 -2
  237. package/dist/tags/feature.js +4 -2
  238. package/dist/template-resolver/api.js +1 -1
  239. package/dist/template-resolver/compile-document-body.js +47 -11
  240. package/dist/template-resolver/document-sanitizer.d.ts +2 -0
  241. package/dist/template-resolver/document-sanitizer.js +16 -1
  242. package/dist/template-resolver/document-schema.d.ts +2 -0
  243. package/dist/template-resolver/document-schema.js +31 -0
  244. package/dist/template-resolver/handlers/bundle-import.js +4 -3
  245. package/dist/template-resolver/handlers/by-slug.query.js +1 -1
  246. package/dist/template-resolver/handlers/by-tenant.query.js +1 -2
  247. package/dist/template-resolver/handlers/collection-item.query.js +1 -1
  248. package/dist/template-resolver/handlers/collection-list.query.js +1 -2
  249. package/dist/template-resolver/handlers/collection-set.write.js +1 -1
  250. package/dist/template-resolver/handlers/copy-locale.write.js +4 -3
  251. package/dist/template-resolver/handlers/diff-to-system.query.js +1 -1
  252. package/dist/template-resolver/handlers/export-bundle.query.js +1 -1
  253. package/dist/template-resolver/handlers/find-by-id.query.js +6 -2
  254. package/dist/template-resolver/handlers/layout-source.query.js +1 -1
  255. package/dist/template-resolver/handlers/list.query.js +4 -2
  256. package/dist/template-resolver/handlers/overview.query.js +5 -3
  257. package/dist/template-resolver/handlers/reset-to-system.write.js +1 -1
  258. package/dist/template-resolver/handlers/resource-remove.write.js +1 -1
  259. package/dist/template-resolver/handlers/set.write.js +1 -1
  260. package/dist/template-resolver/handlers/template-write.d.ts +2 -1
  261. package/dist/template-resolver/handlers/template-write.js +13 -2
  262. package/dist/template-resolver/handlers/tenant-overrides.query.js +1 -1
  263. package/dist/template-resolver/handlers/toggle-status.write.js +1 -1
  264. package/dist/template-resolver/handlers/usage.query.js +1 -1
  265. package/dist/template-resolver/handlers/validate.query.js +1 -1
  266. package/dist/template-resolver/index.d.ts +3 -2
  267. package/dist/template-resolver/index.js +3 -2
  268. package/dist/template-resolver/qualified-names.d.ts +1 -0
  269. package/dist/template-resolver/qualified-names.js +1 -0
  270. package/dist/template-resolver/seeding.d.ts +4 -0
  271. package/dist/template-resolver/seeding.js +43 -9
  272. package/dist/template-resolver/store-template-resource.js +1 -1
  273. package/dist/template-resolver/template-preview.js +3 -1
  274. package/dist/template-resolver/template-resources.js +1 -1
  275. package/dist/template-resolver/template-system-only.d.ts +8 -0
  276. package/dist/template-resolver/template-system-only.js +11 -0
  277. package/dist/template-resolver/template-validation.js +42 -28
  278. package/dist/template-resolver/testing.js +1 -1
  279. package/dist/template-resolver/web/i18n.js +1 -0
  280. package/dist/template-resolver-user-data/index.d.ts +4 -0
  281. package/dist/template-resolver-user-data/index.js +17 -13
  282. package/dist/tenant/handlers/active-tenant-ids.query.js +1 -1
  283. package/dist/tenant/handlers/add-member.write.js +1 -2
  284. package/dist/tenant/handlers/cancel-invitation.write.js +1 -1
  285. package/dist/tenant/handlers/invitations.query.js +1 -1
  286. package/dist/tenant/handlers/me.query.js +1 -1
  287. package/dist/tenant/handlers/member-directory.query.js +1 -1
  288. package/dist/tenant/handlers/members.query.js +1 -1
  289. package/dist/tenant/handlers/memberships.query.js +1 -1
  290. package/dist/tenant/handlers/remove-member.write.js +1 -2
  291. package/dist/tenant/handlers/resolve-user-ids.query.js +1 -1
  292. package/dist/tenant/handlers/team-list.query.js +1 -1
  293. package/dist/tenant/handlers/tenant-directory.query.js +1 -1
  294. package/dist/tenant/handlers/update-member-roles.write.js +1 -2
  295. package/dist/tenant/invited-membership.js +2 -3
  296. package/dist/tenant/last-tenant-admin.js +1 -2
  297. package/dist/tenant/seeding.js +12 -6
  298. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +1 -2
  299. package/dist/tenant-lifecycle/handlers/request-destruction.write.js +1 -2
  300. package/dist/tenant-lifecycle/lib/revoke-tenant-sessions.js +1 -1
  301. package/dist/tenant-lifecycle/lifecycle-gate.js +1 -1
  302. package/dist/tenant-lifecycle/run-tenant-destroy.js +3 -5
  303. package/dist/tenant-lifecycle/stages.js +10 -6
  304. package/dist/tenant-lifecycle/testing.d.ts +1 -1
  305. package/dist/tenant-lifecycle/testing.js +2 -2
  306. package/dist/tenant-settings/feature.d.ts +1 -0
  307. package/dist/tenant-settings/feature.js +2 -1
  308. package/dist/tier-engine/feature.d.ts +1 -8
  309. package/dist/tier-engine/feature.js +71 -78
  310. package/dist/tier-engine/handlers/get-tenant-tier.query.js +2 -3
  311. package/dist/tier-engine/handlers/set-tenant-tier.write.js +1 -2
  312. package/dist/user/db/queries/stream-tenant-backfill.js +1 -1
  313. package/dist/user/handlers/create.write.js +1 -2
  314. package/dist/user/handlers/find-for-auth.query.js +1 -1
  315. package/dist/user/handlers/list.query.js +1 -1
  316. package/dist/user/handlers/update-roles.js +1 -2
  317. package/dist/user/index.d.ts +1 -1
  318. package/dist/user/index.js +1 -1
  319. package/dist/user/invited-global-roles.js +2 -3
  320. package/dist/user/principal-status.d.ts +4 -0
  321. package/dist/user/principal-status.js +9 -3
  322. package/dist/user/resolve-display-names.js +1 -1
  323. package/dist/user/seeding.js +5 -6
  324. package/dist/user-data-rights/audit-download.js +2 -2
  325. package/dist/user-data-rights/db/queries/export-jobs.js +1 -1
  326. package/dist/user-data-rights/db/queries/forget-cleanup.js +1 -1
  327. package/dist/user-data-rights/handlers/download-by-job.query.js +1 -1
  328. package/dist/user-data-rights/handlers/download-by-token.query.js +1 -1
  329. package/dist/user-data-rights/handlers/export-status.query.js +1 -1
  330. package/dist/user-data-rights/handlers/list-download-attempts.query.js +1 -1
  331. package/dist/user-data-rights/handlers/my-audit-log.query.js +1 -1
  332. package/dist/user-data-rights/handlers/request-export.write.js +1 -2
  333. package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +3 -3
  334. package/dist/user-data-rights/lib/deny-if-target-outside-admin-tenant.d.ts +1 -1
  335. package/dist/user-data-rights/lib/deny-if-target-outside-admin-tenant.js +1 -1
  336. package/dist/user-data-rights/lib/update-user-lifecycle.d.ts +1 -0
  337. package/dist/user-data-rights/lib/update-user-lifecycle.js +3 -3
  338. package/dist/user-data-rights/run-export-jobs.js +2 -3
  339. package/dist/user-data-rights/run-forget-cleanup.js +9 -5
  340. package/dist/user-data-rights/run-user-export.js +9 -5
  341. package/dist/waitlist/handlers/invite.write.js +1 -2
  342. package/dist/waitlist/handlers/reject.write.js +1 -1
  343. package/dist/waitlist/lib.js +1 -2
  344. package/dist/workflow-runner/event-subscriber.js +1 -1
  345. package/dist/workflow-runner/feature.d.ts +4 -0
  346. package/dist/workflow-runner/feature.js +44 -40
  347. package/dist/workflow-runner/handlers/resume-run.write.js +1 -1
  348. package/dist/workflow-runner/index.d.ts +1 -1
  349. package/dist/workflow-runner/index.js +1 -1
  350. package/dist/workflow-runner/pending-projection.js +1 -1
  351. package/package.json +28 -11
  352. package/src/cap-counter/changes.json +13 -0
  353. package/src/channel-email/changes.json +6 -0
  354. package/src/crypto-shredding/changes.json +6 -0
  355. package/src/delivery/changes.json +12 -0
  356. package/src/file-provider-s3/changes.json +10 -1
  357. package/src/personal-access-tokens/changes.json +6 -0
  358. package/src/template-resolver/changes.json +25 -0
  359. package/src/user/changes.json +6 -0
  360. package/src/user-data-rights/changes.json +6 -0
  361. package/dist/file-provider-s3-env/feature.d.ts +0 -3
  362. package/dist/file-provider-s3-env/feature.js +0 -46
  363. /package/dist/{files-provider-s3 → file-provider-s3/lib}/env-helper.d.ts +0 -0
  364. /package/dist/{files-provider-s3 → file-provider-s3/lib}/env-helper.js +0 -0
  365. /package/dist/{files-provider-s3 → file-provider-s3/lib}/s3-provider.d.ts +0 -0
@@ -1,8 +1,8 @@
1
1
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
2
2
  import { isResourceImageContentType } from "../shared/index.js";
3
3
  import { rewriteStepsBlock } from "./compile-steps-block.js";
4
- import { withParsedDocument } from "./document-sanitizer.js";
5
- import { DOCUMENT_TEXT_ALIGNMENTS, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
4
+ import { conditionScopeElement, withParsedDocument } from "./document-sanitizer.js";
5
+ import { DOCUMENT_CONDITION_ATTRIBUTE, DOCUMENT_TEXT_ALIGNMENTS, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
6
6
  // Private-use characters mark where a Handlebars expression goes. Author text
7
7
  // is scrubbed of them first and every `{`/`}` is entity-encoded before the
8
8
  // markers are swapped for real expressions, so the only Handlebars syntax in
@@ -34,19 +34,24 @@ function resolveReference(name, scope, variables) {
34
34
  }
35
35
  return { path: scope === null ? name : `@root.${name}`, def: ownVariable(variables, name) };
36
36
  }
37
- function valueExpression(path, def) {
37
+ // The sanitized rich text value always consists of blocks; inside a line of
38
+ // other text it renders inline so no paragraph ends up inside a paragraph.
39
+ function valueExpression(path, def, isWholeBlock) {
38
40
  if (def?.type === "money")
39
41
  return `{{money ${path}}}`;
40
42
  if (def?.type === "date")
41
43
  return `{{date ${path}}}`;
42
- if (def?.type === "richText")
43
- return `{{richText ${path}}}`;
44
+ if (def?.type === "percent")
45
+ return `{{percent ${path}}}`;
46
+ if (def?.type === "richText") {
47
+ return isWholeBlock ? `{{richText ${path}}}` : `{{richText ${path} inline=true}}`;
48
+ }
44
49
  return `{{${path}}}`;
45
50
  }
46
51
  function rewriteVariable(element, state) {
47
52
  const name = element.getAttribute("data-variable") ?? "";
48
53
  const replacement = element.ownerDocument.createTextNode(isDocumentReferenceName(name)
49
- ? marker(state, valueExpression(...pathAndDef(name, element, state)))
54
+ ? marker(state, valueExpression(...pathAndDef(name, element, state), state.blockRichTextSpans.has(element)))
50
55
  : "");
51
56
  element.replaceWith(replacement);
52
57
  }
@@ -76,10 +81,25 @@ function wrapVariableOnlyBlock(block, state) {
76
81
  // skip: a line with static content or several placeholders stays as it is
77
82
  if (name === null)
78
83
  return;
79
- const [path] = pathAndDef(name, block, state);
80
- const document = block.ownerDocument;
81
- block.before(document.createTextNode(marker(state, `{{#if ${path} includeZero=true}}`)));
82
- block.after(document.createTextNode(marker(state, "{{/if}}")));
84
+ const [path, def] = pathAndDef(name, block, state);
85
+ const host = def?.type === "richText" && block.tagName === "P" ? richTextBlockHost(block, state) : block;
86
+ const document = host.ownerDocument;
87
+ host.before(document.createTextNode(marker(state, `{{#if ${path} includeZero=true}}`)));
88
+ host.after(document.createTextNode(marker(state, "{{/if}}")));
89
+ }
90
+ // A paragraph cannot hold the paragraphs of a rich text value, a div can; it
91
+ // keeps the paragraph's attributes so alignment and size still apply.
92
+ function richTextBlockHost(paragraph, state) {
93
+ const host = paragraph.ownerDocument.createElement("div");
94
+ for (const attribute of Array.from(paragraph.attributes)) {
95
+ host.setAttribute(attribute.name, attribute.value ?? "");
96
+ }
97
+ for (const span of Array.from(paragraph.querySelectorAll("span[data-variable]"))) {
98
+ state.blockRichTextSpans.add(span);
99
+ }
100
+ host.append(...Array.from(paragraph.childNodes));
101
+ paragraph.replaceWith(host);
102
+ return host;
83
103
  }
84
104
  function rewriteLink(element, state) {
85
105
  const href = element.getAttribute("href") ?? "";
@@ -110,6 +130,19 @@ function rewriteRepeatRow(row, state) {
110
130
  row.removeAttribute("data-repeat-header");
111
131
  }
112
132
  }
133
+ function rewriteConditionalBlock(block, state) {
134
+ const name = block.getAttribute(DOCUMENT_CONDITION_ATTRIBUTE) ?? "";
135
+ block.removeAttribute(DOCUMENT_CONDITION_ATTRIBUTE);
136
+ if (!isDocumentReferenceName(name)) {
137
+ block.remove();
138
+ // skip: a condition on a name that cannot be a variable never shows
139
+ return;
140
+ }
141
+ const [path] = pathAndDef(name, conditionScopeElement(block), state);
142
+ const document = block.ownerDocument;
143
+ block.before(document.createTextNode(marker(state, `{{#if ${path} includeZero=true}}`)));
144
+ block.after(document.createTextNode(marker(state, "{{/if}}")));
145
+ }
113
146
  function stripActiveContent(element) {
114
147
  for (const attribute of Array.from(element.attributes)) {
115
148
  if (/^on/i.test(attribute.name))
@@ -223,7 +256,7 @@ function rewriteLinks(root, state, options) {
223
256
  // rewritten in document order; list rows last so their placeholders still see
224
257
  // the `tr[data-each]` ancestor.
225
258
  export function compileDocumentBodyToHandlebars(html, variables, options = {}) {
226
- const state = { variables, expressions: [] };
259
+ const state = { variables, expressions: [], blockRichTextSpans: new Set() };
227
260
  const scrubbed = html.replaceAll(EXPRESSION_OPEN, "").replaceAll(EXPRESSION_CLOSE, "");
228
261
  const compiled = withParsedDocument(scrubbed, (root) => {
229
262
  stripScriptsAndActiveContent(root, options);
@@ -240,6 +273,9 @@ export function compileDocumentBodyToHandlebars(html, variables, options = {}) {
240
273
  color: options.stepsColor,
241
274
  });
242
275
  }
276
+ for (const block of Array.from(root.querySelectorAll(`[${DOCUMENT_CONDITION_ATTRIBUTE}]`))) {
277
+ rewriteConditionalBlock(block, state);
278
+ }
243
279
  for (const block of Array.from(root.querySelectorAll(VARIABLE_ONLY_BLOCK_SELECTOR))) {
244
280
  wrapVariableOnlyBlock(block, state);
245
281
  }
@@ -24,9 +24,11 @@ export type SanitizeBodyResult = {
24
24
  export declare function violation(code: DocumentViolationCode, detail: string, message: string): DocumentViolation;
25
25
  export declare function withParsedDocument<T>(html: string, read: (body: ScanElement) => T): T;
26
26
  export declare function sanitizeDocumentHtml(html: string): SanitizeHtmlResult;
27
+ export declare function flattenParagraphsToLineBreaks(sanitizedHtml: string): string;
27
28
  export declare function sanitizeTemplateBody(input: {
28
29
  readonly kind: string;
29
30
  readonly contentFormat: ContentFormat;
30
31
  readonly content: string | null;
31
32
  }): SanitizeBodyResult;
32
33
  export declare function documentViolationsToFieldIssues(violations: readonly DocumentViolation[]): FieldIssue[];
34
+ export declare function conditionScopeElement(block: ScanElement): ScanElement;
@@ -2,7 +2,7 @@ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
2
2
  import { generateHTML, generateJSON } from "@tiptap/html/server";
3
3
  import { Window } from "happy-dom";
4
4
  import { DOCUMENT_HTML_KINDS } from "./constants.js";
5
- import { documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
5
+ import { DOCUMENT_CONDITION_ATTRIBUTE, documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
6
6
  import { isDocumentStepKey } from "./document-steps.js";
7
7
  export function violation(code, detail, message) {
8
8
  return { code, detail, message };
@@ -56,6 +56,7 @@ function scanImage(element, out) {
56
56
  const REFERENCE_ATTRIBUTES = [
57
57
  ["data-variable", isDocumentReferenceName],
58
58
  ["data-each", isDocumentReferenceName],
59
+ [DOCUMENT_CONDITION_ATTRIBUTE, isDocumentReferenceName],
59
60
  ["data-resource", isDocumentResourceKey],
60
61
  ["data-steps", isDocumentReferenceName],
61
62
  ["data-step", isDocumentStepKey],
@@ -155,6 +156,15 @@ export function sanitizeDocumentHtml(html) {
155
156
  html: generateHTML(generateJSON(html, documentExtensions), documentExtensions),
156
157
  };
157
158
  }
159
+ // For a sanitized value placed inside a line of text: paragraphs become line
160
+ // breaks. Other blocks (lists, headings) cannot be made inline and stay as they are.
161
+ export function flattenParagraphsToLineBreaks(sanitizedHtml) {
162
+ return withParsedDocument(sanitizedHtml, (body) => {
163
+ const blocks = Array.from(body.children);
164
+ const isParagraphsOnly = blocks.length === body.childNodes.length && blocks.every((block) => block.tagName === "P");
165
+ return isParagraphsOnly ? blocks.map((block) => block.innerHTML).join("<br>") : sanitizedHtml;
166
+ });
167
+ }
158
168
  // Snippets accept any format, but their html is as untrusted as a mail body.
159
169
  function isSanitizedHtmlKind(kind) {
160
170
  return kind === "snippet" || isOneOf(DOCUMENT_HTML_KINDS, kind);
@@ -202,3 +212,8 @@ export function documentViolationsToFieldIssues(violations) {
202
212
  params: { detail: item.detail },
203
213
  }));
204
214
  }
215
+ // A repeat row's own data-if is decided per list, outside the row's item scope,
216
+ // because the compiled {{#if}} lands outside its {{#each}}.
217
+ export function conditionScopeElement(block) {
218
+ return block.matches("tr[data-each]") ? (block.parentElement ?? block) : block;
219
+ }
@@ -19,4 +19,6 @@ export declare const DOCUMENT_TEXT_ALIGNMENTS: readonly ["left", "center", "righ
19
19
  export type DocumentTextAlignment = (typeof DOCUMENT_TEXT_ALIGNMENTS)[number];
20
20
  export declare const DocumentTextAlign: Extension<any, any>;
21
21
  export declare const DocumentTextSize: Extension<any, any>;
22
+ export declare const DOCUMENT_CONDITION_ATTRIBUTE = "data-if";
23
+ export declare const DocumentCondition: Extension<any, any>;
22
24
  export declare const documentExtensions: Extensions;
@@ -284,6 +284,36 @@ export const DocumentTextSize = Extension.create({
284
284
  ];
285
285
  },
286
286
  });
287
+ // A block shown only when the named variable has a value (data-if, the
288
+ // conditional counterpart of data-each). Table rows qualify so an invoice can
289
+ // drop a discount line; tiptap merges the attribute into paragraph, heading
290
+ // and row markup only.
291
+ export const DOCUMENT_CONDITION_ATTRIBUTE = "data-if";
292
+ export const DocumentCondition = Extension.create({
293
+ name: "documentCondition",
294
+ addGlobalAttributes() {
295
+ return [
296
+ {
297
+ types: ["paragraph", "heading", "tableRow"],
298
+ attributes: {
299
+ showIf: {
300
+ default: null,
301
+ parseHTML: (element) => {
302
+ const name = element.getAttribute(DOCUMENT_CONDITION_ATTRIBUTE);
303
+ return name !== null && isDocumentReferenceName(name) ? name : null;
304
+ },
305
+ renderHTML: (attributes) => {
306
+ const name = attributes["showIf"];
307
+ return typeof name === "string" && isDocumentReferenceName(name)
308
+ ? { [DOCUMENT_CONDITION_ATTRIBUTE]: name }
309
+ : {};
310
+ },
311
+ },
312
+ },
313
+ },
314
+ ];
315
+ },
316
+ });
287
317
  export const documentExtensions = [
288
318
  StarterKit.configure({
289
319
  blockquote: false,
@@ -318,4 +348,5 @@ export const documentExtensions = [
318
348
  DocumentSteps,
319
349
  DocumentTextAlign,
320
350
  DocumentTextSize,
351
+ DocumentCondition,
321
352
  ];
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
3
3
  import { requireForTenant } from "../../shared/index.js";
4
4
  import { attachmentLimitFailure, attachmentNeedsMailTemplate, createPreparedBundleResourceEntry, prepareTemplateAttachmentBeforeTransaction, prepareTemplateResourceBeforeTransaction, readTemplateResourceMaxBytes, releaseAll, } from "../store-template-resource.js";
@@ -7,7 +7,7 @@ import { attachTemplateResources } from "../template-resources.js";
7
7
  import { resolveTemplateVariables } from "../template-validation.js";
8
8
  import { MAX_FILE_ATTACHMENTS_PER_TEMPLATE } from "./resource-shared.js";
9
9
  import { evaluateTemplateWrite } from "./template-gates.js";
10
- import { refuseTenantScopeUnderSystemTenant, writeTemplateRow, } from "./template-write.js";
10
+ import { refuseSystemOnlyTenantOverride, refuseTenantScopeUnderSystemTenant, writeTemplateRow, } from "./template-write.js";
11
11
  export function targetExistsIssue(locale) {
12
12
  return {
13
13
  path: "locale",
@@ -61,7 +61,8 @@ function checkBundleAttachments(bundle) {
61
61
  // beforeTransaction half: validates the bundle and uploads every resource file to the target
62
62
  // tenant's storage. A failed or throwing upload releases the ones before it.
63
63
  export async function prepareTemplateBundleBeforeTransaction(args) {
64
- const refused = refuseTenantScopeUnderSystemTenant(args.scope, args.tenantId);
64
+ const refused = refuseTenantScopeUnderSystemTenant(args.scope, args.tenantId) ??
65
+ refuseSystemOnlyTenantOverride(args.ctx.registry, args.scope, args.bundle.slug, args.bundle.kind);
65
66
  if (refused !== null)
66
67
  return refused;
67
68
  const issues = await collectBundleIssues(args, args.status);
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { TEXT_BLOCK_KIND } from "../constants.js";
@@ -1,5 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { castTenantRows } from "@cosmicdrift/kumiko-framework/db";
1
+ import { castTenantRows, selectMany } from "@cosmicdrift/kumiko-framework/db";
3
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
4
3
  import * as z from "zod";
5
4
  import { TEXT_BLOCK_KIND } from "../constants.js";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { collectionStore, DEFAULT_COLLECTION_ACCESS, toCollectionEntry, } from "./collection-shared.js";
@@ -1,5 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { castTenantRows } from "@cosmicdrift/kumiko-framework/db";
1
+ import { castTenantRows, selectMany } from "@cosmicdrift/kumiko-framework/db";
3
2
  import { defineQueryHandler, } from "@cosmicdrift/kumiko-framework/engine";
4
3
  import * as z from "zod";
5
4
  import { collectionStore, DEFAULT_COLLECTION_ACCESS, toCollectionEntry, } from "./collection-shared.js";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { ValidationError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { AccessDeniedError, NotFoundError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
@@ -15,7 +15,7 @@ import { resolveTemplateVariables } from "../template-validation.js";
15
15
  import { targetExistsIssue } from "./bundle-import.js";
16
16
  import { kindSchema, localeSchema, templateSlugSchema } from "./shared.js";
17
17
  import { parseStoredJson, storedRecord } from "./template-gates.js";
18
- import { refuseTenantScopeUnderSystemTenant, writeTemplateRow } from "./template-write.js";
18
+ import { refuseSystemOnlyTenantOverride, refuseTenantScopeUnderSystemTenant, writeTemplateRow, } from "./template-write.js";
19
19
  function readDbFor(ctx, scope) {
20
20
  return scope === "system" ? requireForTenant(ctx, SYSTEM_TENANT_ID).db : ctx.db;
21
21
  }
@@ -59,7 +59,8 @@ async function checkCopyRequest(ctx, event) {
59
59
  }));
60
60
  }
61
61
  const tenantId = scope === "system" ? SYSTEM_TENANT_ID : event.user.tenantId;
62
- const refused = refuseTenantScopeUnderSystemTenant(scope, tenantId);
62
+ const refused = refuseTenantScopeUnderSystemTenant(scope, tenantId) ??
63
+ refuseSystemOnlyTenantOverride(ctx.registry, scope, slug, kind);
63
64
  if (refused !== null)
64
65
  return refused;
65
66
  const readDb = readDbFor(ctx, scope);
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { NotFoundError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,5 +1,5 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
+ 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";
@@ -1,8 +1,9 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { templateResourcesTable } from "../table.js";
5
5
  import { draftViewerTenantId, isHiddenSystemDraft, toWorkingRow } from "../template-draft.js";
6
+ import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.js";
6
7
  // Admin-Lookup für UI-Edit-Flow. Returnt das raw Template inkl. draft/
7
8
  // archived Status. Tenant-Isolation: User sieht nur Templates des
8
9
  // eigenen Tenants oder SYSTEM_TENANT (system-defaults sind public-
@@ -17,8 +18,11 @@ export const findByIdQuery = defineQueryHandler({
17
18
  const stored = await fetchOne(ctx.db, templateResourcesTable, {
18
19
  id: query.payload.id,
19
20
  });
20
- if (!stored || isHiddenSystemDraft(query.user, stored))
21
+ if (!stored ||
22
+ isHiddenSystemDraft(query.user, stored) ||
23
+ isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, stored)) {
21
24
  return null;
25
+ }
22
26
  const row = toWorkingRow(stored, draftViewerTenantId(query.user, stored));
23
27
  const isOwnTenant = row.tenantId === query.user.tenantId;
24
28
  const isSystemTemplate = row.scope === "system";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { FALLBACK_LOCALE } from "../constants.js";
@@ -1,9 +1,10 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { TEMPLATE_KINDS, TEMPLATE_STATUSES } from "../constants.js";
5
5
  import { templateResourcesTable } from "../table.js";
6
6
  import { isHiddenSystemDraft } from "../template-draft.js";
7
+ import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.js";
7
8
  // ctx.db is tenant-scoped even for SystemAdmin: every caller sees its own
8
9
  // tenant's rows plus the system defaults, never another tenant's rows.
9
10
  export const listQuery = defineQueryHandler({
@@ -39,7 +40,8 @@ export const listQuery = defineQueryHandler({
39
40
  limit: 500,
40
41
  }));
41
42
  return rows
42
- .filter((row) => !isHiddenSystemDraft(query.user, row))
43
+ .filter((row) => !isHiddenSystemDraft(query.user, row) &&
44
+ !isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, row))
43
45
  .map((row) => ({
44
46
  id: String(row.id),
45
47
  tenantId: row.tenantId,
@@ -1,9 +1,10 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { DEFAULT_MAIL_LAYOUT_SLUG, FALLBACK_LOCALE } from "../constants.js";
5
5
  import { templateResourcesTable } from "../table.js";
6
6
  import { activeSinceOf, activeVersionOf, draftViewerTenantId, isHiddenSystemDraft, parseTemplateDraft, servedVersionOf, } from "../template-draft.js";
7
+ import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.js";
7
8
  import { collectTemplateUsage } from "../template-usage.js";
8
9
  import { storedRecord } from "./template-gates.js";
9
10
  const OVERVIEW_KINDS = ["mail", "document-pdf", "mail-layout", "pdf-layout"];
@@ -183,7 +184,7 @@ export const overviewQuery = defineQueryHandler({
183
184
  totalCount: z.boolean().optional(),
184
185
  }),
185
186
  access: { roles: ["TenantAdmin", "SystemAdmin"] },
186
- description: "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; use it to browse and filter all templates at a glance.",
187
+ description: "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.",
187
188
  handler: async (query, ctx) => {
188
189
  const payload = query.payload;
189
190
  const fetchedRows = await selectMany(ctx.db, templateResourcesTable, { kind: { in: [...OVERVIEW_KINDS] } }, { orderBy: { col: "id", direction: "asc" }, limit: OVERVIEW_ROW_LIMIT + 1 });
@@ -194,7 +195,8 @@ export const overviewQuery = defineQueryHandler({
194
195
  limit: OVERVIEW_ROW_LIMIT,
195
196
  });
196
197
  }
197
- const visibleRows = rows.filter((row) => !isHiddenSystemDraft(query.user, row));
198
+ const visibleRows = rows.filter((row) => !isHiddenSystemDraft(query.user, row) &&
199
+ !isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, row));
198
200
  const { drafts, layoutSlugByDocument } = buildDrafts(groupBySlugAndKind(visibleRows), query.user);
199
201
  const effectiveLayouts = effectiveMailLayoutSlugs(visibleRows);
200
202
  const overviewRows = drafts.map((draft) => withUsage(draft, layoutSlugByDocument, ctx.registry, effectiveLayouts));
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { NotFoundError, ValidationError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { type HandlerContext, type SessionUser, type TemplateVariables, type TenantId, type WriteResult } from "@cosmicdrift/kumiko-framework/engine";
1
+ import { type HandlerContext, type Registry, type SessionUser, type TemplateVariables, type TenantId, type WriteResult } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { type WriteFailure } from "@cosmicdrift/kumiko-framework/errors";
3
3
  import type { ContentFormat, TemplateKind } from "../constants.js";
4
4
  import type { TemplateWriteScope } from "../layout-regions.js";
@@ -32,6 +32,7 @@ export type TemplateRowWrite = {
32
32
  readonly payload: TemplateRowPayload;
33
33
  };
34
34
  export declare function refuseTenantScopeUnderSystemTenant(scope: TemplateWriteScope, tenantId: string): WriteResult<never> | null;
35
+ export declare function refuseSystemOnlyTenantOverride(registry: Registry, scope: TemplateWriteScope, slug: string, kind: string): WriteFailure | null;
35
36
  export type GatedTemplateWrite = {
36
37
  readonly ok: true;
37
38
  readonly evaluated: Extract<TemplateWriteResult, {
@@ -1,9 +1,11 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { AccessDeniedError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { requireForTenant } from "../../shared/index.js";
5
+ import { TemplateResolverErrors } from "../qualified-names.js";
5
6
  import { templateResourcesTable } from "../table.js";
6
7
  import { activationChanges, serializeTemplateDraft } from "../template-draft.js";
8
+ import { isSystemOnlyTemplate } from "../template-system-only.js";
7
9
  import { executor } from "./shared.js";
8
10
  import { evaluateTemplateWrite, } from "./template-gates.js";
9
11
  // The tenant-scope-under-system-tenant ban lives here so no write path can
@@ -16,6 +18,14 @@ export function refuseTenantScopeUnderSystemTenant(scope, tenantId) {
16
18
  details: { reason: "system_tenant_override_not_allowed_use_upsert_system" },
17
19
  }));
18
20
  }
21
+ export function refuseSystemOnlyTenantOverride(registry, scope, slug, kind) {
22
+ if (scope !== "tenant" || !isSystemOnlyTemplate(registry, slug, kind))
23
+ return null;
24
+ return writeFailure(new AccessDeniedError({
25
+ i18nKey: "templateResolver.errors.systemOnlyTemplate",
26
+ details: { reason: TemplateResolverErrors.systemOnlyTemplate },
27
+ }));
28
+ }
19
29
  // Evaluation plus the publish rule: a row that goes active must not carry
20
30
  // publish issues, a draft may.
21
31
  export function gateTemplateWrite(input, status) {
@@ -63,7 +73,8 @@ function updateChanges(existing, status, fields) {
63
73
  // separately.
64
74
  export async function writeTemplateRow(args) {
65
75
  const { ctx, user, tenantId, scope, status, payload } = args;
66
- const refused = refuseTenantScopeUnderSystemTenant(scope, tenantId);
76
+ const refused = refuseTenantScopeUnderSystemTenant(scope, tenantId) ??
77
+ refuseSystemOnlyTenantOverride(ctx.registry, scope, payload.slug, payload.kind);
67
78
  if (refused !== null)
68
79
  return refused;
69
80
  const { db, streamTenantId } = requireForTenant(ctx, tenantId);
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
4
  import { TenantQueries } from "../../tenant/index.js";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { NotFoundError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
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
4
  import { TEMPLATE_KINDS } from "../constants.js";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
4
  import { imageResourceKeysOf } from "../linked-resources.js";
@@ -1,8 +1,8 @@
1
1
  export { createTemplateResolverApi, type ResolveRequest, requireTemplateResolver, TemplateNotFoundError, type TemplateResolverApi, type TemplateResource, } from "./api.js";
2
2
  export { type CompileDocumentBodyOptions, collectDocumentResourceKeys, compileDocumentBodyToHandlebars, toResourceDataUri, } from "./compile-document-body.js";
3
3
  export { CONTENT_FORMATS, type ContentFormat, DEFAULT_MAIL_LAYOUT_SLUG, DEFAULT_PDF_LAYOUT_SLUG, DOCUMENT_HTML_KINDS, type DocumentHtmlKind, FALLBACK_LOCALE, NON_RENDER_KINDS, type NonRenderKind, PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, type PdfOrientation, type PdfPageFormat, RENDER_KINDS, type RenderKind, SYSTEM_TENANT_ID, TEMPLATE_KINDS, TEMPLATE_SCOPES, TEMPLATE_STATUSES, TEXT_BLOCK_KIND, type TemplateKind, type TemplateScope, type TemplateStatus, UPSERT_KINDS, type UpsertKind, } from "./constants.js";
4
- export { type DocumentViolation, type DocumentViolationCode, documentViolationsToFieldIssues, type SanitizeBodyResult, type SanitizeHtmlResult, sanitizeDocumentHtml, sanitizeTemplateBody, } from "./document-sanitizer.js";
5
- export { DOCUMENT_NODE_NAMES, DOCUMENT_TEXT_ALIGNMENTS, DocumentButton, DocumentDivider, DocumentLink, DocumentPageBreak, DocumentResource, DocumentTable, DocumentTableCell, DocumentTableHeader, DocumentTableRow, DocumentTextAlign, type DocumentTextAlignment, DocumentVariable, documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
4
+ export { type DocumentViolation, type DocumentViolationCode, documentViolationsToFieldIssues, flattenParagraphsToLineBreaks, type SanitizeBodyResult, type SanitizeHtmlResult, sanitizeDocumentHtml, sanitizeTemplateBody, } from "./document-sanitizer.js";
5
+ export { DOCUMENT_CONDITION_ATTRIBUTE, DOCUMENT_NODE_NAMES, DOCUMENT_TEXT_ALIGNMENTS, DocumentButton, DocumentCondition, DocumentDivider, DocumentLink, DocumentPageBreak, DocumentResource, DocumentTable, DocumentTableCell, DocumentTableHeader, DocumentTableRow, DocumentTextAlign, type DocumentTextAlignment, DocumentVariable, documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
6
6
  export { createTemplateResolverFeature } from "./feature.js";
7
7
  export type { LayoutSourceResponse, LayoutSourceRow } from "./handlers/layout-source.query.js";
8
8
  export type { OverviewKindGroup, OverviewOrigin, OverviewResponse, OverviewRow, OverviewUsage, } from "./handlers/overview.query.js";
@@ -19,6 +19,7 @@ export { type TemplateBundle, templateBundleSchema } from "./template-bundle.js"
19
19
  export { isMailTemplateMeta, type LayoutTemplateMeta, MAIL_CATEGORIES, MAIL_TONES, type MailCategory, type MailLayoutMeta, type MailTemplateMeta, type MailTone, type PdfTemplateMeta, parseTemplateMeta, pdfAttachmentFileNamePatternSchema, readMailLayoutMeta, readPdfTemplateMeta, type TemplateMeta, type TemplateMetaIssue, type TemplateMetaResult, templateSlugSchema, } from "./template-meta.js";
20
20
  export { type DocumentDraftOutcome, evaluateDocumentDraft } from "./template-preview.js";
21
21
  export { readTemplateResource, type TemplateResourceFile } from "./template-resources.js";
22
+ export { isSystemOnlyTemplate } from "./template-system-only.js";
22
23
  export { collectTemplateUsage, type TemplateUsageEntry } from "./template-usage.js";
23
24
  export { hasPlaceholderProblems, resolveTemplateVariables, SYSTEM_PLACEHOLDERS, systemPlaceholdersFor, type TemplateValidation, validateTemplatePlaceholders, } from "./template-validation.js";
24
25
  export { type UserContentEntryRow, userContentEntriesTable, userContentEntryEntity, } from "./user-content-table.js";
@@ -1,8 +1,8 @@
1
1
  export { createTemplateResolverApi, requireTemplateResolver, TemplateNotFoundError, } from "./api.js";
2
2
  export { collectDocumentResourceKeys, compileDocumentBodyToHandlebars, toResourceDataUri, } from "./compile-document-body.js";
3
3
  export { CONTENT_FORMATS, DEFAULT_MAIL_LAYOUT_SLUG, DEFAULT_PDF_LAYOUT_SLUG, DOCUMENT_HTML_KINDS, FALLBACK_LOCALE, NON_RENDER_KINDS, PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, RENDER_KINDS, SYSTEM_TENANT_ID, TEMPLATE_KINDS, TEMPLATE_SCOPES, TEMPLATE_STATUSES, TEXT_BLOCK_KIND, UPSERT_KINDS, } from "./constants.js";
4
- export { documentViolationsToFieldIssues, sanitizeDocumentHtml, sanitizeTemplateBody, } from "./document-sanitizer.js";
5
- export { DOCUMENT_NODE_NAMES, DOCUMENT_TEXT_ALIGNMENTS, DocumentButton, DocumentDivider, DocumentLink, DocumentPageBreak, DocumentResource, DocumentTable, DocumentTableCell, DocumentTableHeader, DocumentTableRow, DocumentTextAlign, DocumentVariable, documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
4
+ export { documentViolationsToFieldIssues, flattenParagraphsToLineBreaks, sanitizeDocumentHtml, sanitizeTemplateBody, } from "./document-sanitizer.js";
5
+ export { DOCUMENT_CONDITION_ATTRIBUTE, DOCUMENT_NODE_NAMES, DOCUMENT_TEXT_ALIGNMENTS, DocumentButton, DocumentCondition, DocumentDivider, DocumentLink, DocumentPageBreak, DocumentResource, DocumentTable, DocumentTableCell, DocumentTableHeader, DocumentTableRow, DocumentTextAlign, DocumentVariable, documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
6
6
  export { createTemplateResolverFeature } from "./feature.js";
7
7
  export { localeSchema } from "./handlers/shared.js";
8
8
  export { isHexColor, mailLayoutAppearance, } from "./layout-appearance.js";
@@ -17,6 +17,7 @@ export { templateBundleSchema } from "./template-bundle.js";
17
17
  export { isMailTemplateMeta, MAIL_CATEGORIES, MAIL_TONES, parseTemplateMeta, pdfAttachmentFileNamePatternSchema, readMailLayoutMeta, readPdfTemplateMeta, templateSlugSchema, } from "./template-meta.js";
18
18
  export { evaluateDocumentDraft } from "./template-preview.js";
19
19
  export { readTemplateResource } from "./template-resources.js";
20
+ export { isSystemOnlyTemplate } from "./template-system-only.js";
20
21
  export { collectTemplateUsage } from "./template-usage.js";
21
22
  export { hasPlaceholderProblems, resolveTemplateVariables, SYSTEM_PLACEHOLDERS, systemPlaceholdersFor, validateTemplatePlaceholders, } from "./template-validation.js";
22
23
  export { userContentEntriesTable, userContentEntryEntity, } from "./user-content-table.js";
@@ -44,6 +44,7 @@ export declare const TemplateResolverErrors: {
44
44
  readonly alreadyArchived: "template_already_archived";
45
45
  readonly targetExists: "target_exists";
46
46
  readonly systemResourcesNeedSystemTenant: "system_resources_need_system_tenant";
47
+ readonly systemOnlyTemplate: "system_only_template";
47
48
  readonly bundleLocalesDiffer: "bundle_locales_differ";
48
49
  readonly resourceTooLarge: "template_resource_too_large";
49
50
  readonly resourceUnsupportedImage: "template_resource_unsupported_image";
@@ -55,6 +55,7 @@ export const TemplateResolverErrors = {
55
55
  alreadyArchived: "template_already_archived",
56
56
  targetExists: "target_exists",
57
57
  systemResourcesNeedSystemTenant: "system_resources_need_system_tenant",
58
+ systemOnlyTemplate: "system_only_template",
58
59
  bundleLocalesDiffer: "bundle_locales_differ",
59
60
  resourceTooLarge: "template_resource_too_large",
60
61
  resourceUnsupportedImage: "template_resource_unsupported_image",
@@ -1,5 +1,6 @@
1
1
  import { type DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { type Registry, type SessionUser, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
3
+ import type { Dispatcher } from "@cosmicdrift/kumiko-framework/pipeline";
3
4
  import { type SeedIfExists } from "@cosmicdrift/kumiko-framework/seeding";
4
5
  import { type ContentFormat, type UpsertKind } from "./constants.js";
5
6
  import type { TemplateBundle } from "./template-bundle.js";
@@ -24,6 +25,9 @@ export declare function seedSystemTemplate(db: DbConnection, opts: SeedSystemTem
24
25
  export type SeedSystemTemplateBundleOptions = {
25
26
  readonly by?: SessionUser;
26
27
  readonly ifExists?: SeedIfExists;
28
+ /** Required for bundles with resources (e.g. a `logo`): the files go through the
29
+ * import-bundle-system write, which needs the file provider of the system tenant. */
30
+ readonly dispatcher?: Dispatcher;
27
31
  };
28
32
  export declare function seedSystemTemplateBundle(db: DbConnection, bundle: TemplateBundle, opts?: SeedSystemTemplateBundleOptions): Promise<{
29
33
  ids: Record<string, string>;