@cosmicdrift/kumiko-samples 0.386.0 → 0.388.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 (530) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +1 -1
  3. package/package.json +2 -2
  4. package/packages/bundled-features/package.json +9 -2
  5. package/packages/bundled-features/src/agent-tools/changes.json +6 -0
  6. package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
  7. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +9 -9
  8. package/packages/bundled-features/src/audit/changes.json +12 -0
  9. package/packages/bundled-features/src/audit/handlers/audit-events.ts +1 -1
  10. package/packages/bundled-features/src/audit/screens.ts +1 -1
  11. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
  12. package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
  13. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
  14. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
  17. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
  18. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  19. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
  20. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
  21. package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
  22. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
  23. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
  24. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
  25. package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
  26. package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
  27. package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
  28. package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
  29. package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
  30. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
  31. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
  32. package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
  33. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
  34. package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
  35. package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
  36. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
  37. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
  38. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
  39. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
  40. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
  41. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
  42. package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
  43. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
  44. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
  45. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
  46. package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
  47. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
  48. package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
  49. package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
  50. package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
  51. package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
  52. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  53. package/packages/bundled-features/src/auth-mfa/feature-exports.ts +2 -2
  54. package/packages/bundled-features/src/auth-mfa/feature.ts +6 -0
  55. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
  56. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
  57. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
  58. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  59. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
  60. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
  61. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  62. package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
  63. package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
  64. package/packages/bundled-features/src/auth-mfa/web/i18n.ts +9 -4
  65. package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
  66. package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
  67. package/packages/bundled-features/src/auth-mfa/web/mfa-code-or-recovery-field.tsx +68 -0
  68. package/packages/bundled-features/src/auth-mfa/web/mfa-disable-dialog.tsx +23 -13
  69. package/packages/bundled-features/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +23 -13
  70. package/packages/bundled-features/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +15 -6
  71. package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +71 -24
  72. package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
  73. package/packages/bundled-features/src/billing-foundation/changes.json +55 -0
  74. package/packages/bundled-features/src/billing-foundation/checkout-core.ts +32 -42
  75. package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +8 -2
  76. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +2 -0
  77. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +14 -3
  78. package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +3 -4
  79. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +12 -6
  80. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +35 -19
  81. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +12 -8
  82. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +14 -8
  83. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +5 -0
  84. package/packages/bundled-features/src/billing-foundation/consumer-protection/withdrawal-period.ts +8 -10
  85. package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
  86. package/packages/bundled-features/src/billing-foundation/events.ts +23 -21
  87. package/packages/bundled-features/src/billing-foundation/feature.ts +45 -44
  88. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
  89. package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +71 -6
  90. package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +19 -17
  91. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
  92. package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
  93. package/packages/bundled-features/src/billing-foundation/handlers/plan-switch-preview.query.ts +65 -0
  94. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +29 -22
  95. package/packages/bundled-features/src/billing-foundation/handlers/start-plan-checkout.write.ts +44 -8
  96. package/packages/bundled-features/src/billing-foundation/handlers/switch-plan.write.ts +72 -82
  97. package/packages/bundled-features/src/billing-foundation/handlers/sync-subscription.write.ts +14 -1
  98. package/packages/bundled-features/src/billing-foundation/i18n.ts +22 -0
  99. package/packages/bundled-features/src/billing-foundation/index.ts +2 -0
  100. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +62 -27
  101. package/packages/bundled-features/src/billing-foundation/plan-switch.ts +84 -0
  102. package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
  103. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
  104. package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
  105. package/packages/bundled-features/src/billing-foundation/types.ts +144 -66
  106. package/packages/bundled-features/src/billing-foundation/validate-options.ts +19 -0
  107. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +123 -51
  108. package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +89 -42
  109. package/packages/bundled-features/src/billing-foundation/web/constants.ts +4 -0
  110. package/packages/bundled-features/src/billing-foundation/web/plan-price.ts +55 -0
  111. package/packages/bundled-features/src/billing-foundation/web/plan-switch-confirm-dialog.tsx +224 -0
  112. package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
  113. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
  114. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +5 -1
  115. package/packages/bundled-features/src/cap-counter/changes.json +18 -0
  116. package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
  117. package/packages/bundled-features/src/cap-counter/enforce-cap.ts +66 -68
  118. package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
  119. package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
  120. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
  121. package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
  122. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -2
  123. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
  124. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
  125. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  126. package/packages/bundled-features/src/channel-email/changes.json +6 -0
  127. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  128. package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
  129. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
  130. package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
  131. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
  132. package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
  133. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
  134. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
  135. package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
  136. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
  137. package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
  138. package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
  139. package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
  140. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
  141. package/packages/bundled-features/src/config/changes.json +12 -0
  142. package/packages/bundled-features/src/config/handlers/cascade.query.ts +4 -2
  143. package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
  144. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
  145. package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
  146. package/packages/bundled-features/src/config/handlers/values.query.ts +4 -2
  147. package/packages/bundled-features/src/config/resolver.ts +4 -4
  148. package/packages/bundled-features/src/config/table.ts +10 -10
  149. package/packages/bundled-features/src/config/write-helpers.ts +28 -9
  150. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  151. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +23 -21
  152. package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
  153. package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
  154. package/packages/bundled-features/src/custom-fields/events.ts +7 -8
  155. package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
  156. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
  157. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
  158. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
  159. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
  160. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
  161. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
  162. package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
  163. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  164. package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
  165. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
  166. package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
  167. package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
  168. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
  169. package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
  170. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
  171. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
  172. package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
  173. package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
  174. package/packages/bundled-features/src/data-retention/feature.ts +11 -18
  175. package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
  176. package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
  177. package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
  178. package/packages/bundled-features/src/data-retention/presets.ts +18 -23
  179. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  180. package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
  181. package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
  182. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
  183. package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
  184. package/packages/bundled-features/src/delivery/changes.json +30 -0
  185. package/packages/bundled-features/src/delivery/channel-context.ts +9 -3
  186. package/packages/bundled-features/src/delivery/db/queries/preferences.ts +2 -2
  187. package/packages/bundled-features/src/delivery/delivery-service.ts +35 -5
  188. package/packages/bundled-features/src/delivery/feature.ts +3 -3
  189. package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
  190. package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +20 -1
  191. package/packages/bundled-features/src/delivery/handlers/unsubscribe-page-chrome.query.ts +1 -1
  192. package/packages/bundled-features/src/delivery/tables.ts +9 -8
  193. package/packages/bundled-features/src/delivery/unsubscribe-link.ts +3 -1
  194. package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +1 -0
  195. package/packages/bundled-features/src/delivery/unsubscribe-page.ts +6 -0
  196. package/packages/bundled-features/src/delivery/unsubscribe.ts +40 -19
  197. package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
  198. package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
  199. package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
  200. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
  201. package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
  202. package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
  203. package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
  204. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
  205. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  206. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
  207. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  208. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  209. package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
  210. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  211. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  212. package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
  213. package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
  214. package/packages/bundled-features/src/file-foundation/index.ts +1 -0
  215. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -1
  216. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
  217. package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +0 -2
  218. package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
  219. package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
  220. package/packages/bundled-features/src/files/README.md +1 -1
  221. package/packages/bundled-features/src/files/feature.ts +6 -6
  222. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
  223. package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
  224. package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
  225. package/packages/bundled-features/src/folders/feature.ts +1 -1
  226. package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
  227. package/packages/bundled-features/src/folders/web/tree.ts +5 -5
  228. package/packages/bundled-features/src/form-draft/changes.json +6 -0
  229. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +3 -3
  230. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
  231. package/packages/bundled-features/src/form-draft/decrypt-draft.ts +4 -1
  232. package/packages/bundled-features/src/form-draft/entity.ts +3 -3
  233. package/packages/bundled-features/src/form-draft/feature.ts +4 -5
  234. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  235. package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
  236. package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
  237. package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
  238. package/packages/bundled-features/src/host-routing/README.md +1 -1
  239. package/packages/bundled-features/src/host-routing/changes.json +6 -0
  240. package/packages/bundled-features/src/host-routing/dispatch.ts +16 -17
  241. package/packages/bundled-features/src/host-routing/options.ts +2 -1
  242. package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
  243. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
  244. package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
  245. package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
  246. package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
  247. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
  248. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
  249. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
  250. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
  251. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
  252. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
  253. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
  254. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
  255. package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
  256. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +27 -15
  257. package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +0 -1
  258. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
  259. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
  260. package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
  261. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
  262. package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +0 -3
  263. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
  264. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +70 -70
  265. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +101 -84
  266. package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
  267. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
  268. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
  269. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
  270. package/packages/bundled-features/src/jobs/changes.json +13 -0
  271. package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
  272. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
  273. package/packages/bundled-features/src/jobs/events.ts +1 -1
  274. package/packages/bundled-features/src/jobs/feature.ts +20 -11
  275. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
  276. package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
  277. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  278. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
  279. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  280. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +45 -40
  281. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +63 -59
  282. package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
  283. package/packages/bundled-features/src/jobs/job-run-logger.ts +19 -19
  284. package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
  285. package/packages/bundled-features/src/jobs/screens.ts +1 -1
  286. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  287. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  288. package/packages/bundled-features/src/ledger/entity.ts +5 -5
  289. package/packages/bundled-features/src/ledger/feature.ts +3 -3
  290. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
  291. package/packages/bundled-features/src/ledger/recurring.ts +12 -12
  292. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  293. package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
  294. package/packages/bundled-features/src/ledger/web/index.ts +7 -7
  295. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  296. package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
  297. package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
  298. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
  299. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
  300. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  301. package/packages/bundled-features/src/mail-foundation/feature.ts +31 -30
  302. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
  303. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
  304. package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
  305. package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
  306. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
  307. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
  308. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
  309. package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
  310. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
  311. package/packages/bundled-features/src/managed-pages/table.ts +16 -15
  312. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
  313. package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
  314. package/packages/bundled-features/src/notes-history/entity.ts +4 -4
  315. package/packages/bundled-features/src/notes-history/feature.ts +2 -2
  316. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  317. package/packages/bundled-features/src/page-render/layout.ts +9 -9
  318. package/packages/bundled-features/src/page-render/markdown.ts +11 -11
  319. package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
  320. package/packages/bundled-features/src/personal-access-tokens/feature.ts +9 -6
  321. package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
  322. package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
  323. package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
  324. package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
  325. package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
  326. package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
  327. package/packages/bundled-features/src/renderer-pdf/changes.json +6 -0
  328. package/packages/bundled-features/src/renderer-pdf/render-table-pdf.ts +27 -10
  329. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  330. package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
  331. package/packages/bundled-features/src/seo/feature.ts +3 -3
  332. package/packages/bundled-features/src/sessions/constants.ts +1 -1
  333. package/packages/bundled-features/src/sessions/feature.ts +16 -11
  334. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
  335. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
  336. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  337. package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
  338. package/packages/bundled-features/src/sessions/screens.ts +2 -2
  339. package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
  340. package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
  341. package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
  342. package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +11 -1
  343. package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
  344. package/packages/bundled-features/src/shared/index.ts +1 -1
  345. package/packages/bundled-features/src/shared/mail-template-body.ts +10 -3
  346. package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
  347. package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
  348. package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
  349. package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
  350. package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
  351. package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
  352. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -0
  353. package/packages/bundled-features/src/subscription-dodo/changes.json +14 -0
  354. package/packages/bundled-features/src/subscription-dodo/client.ts +45 -0
  355. package/packages/bundled-features/src/subscription-dodo/constants.ts +24 -0
  356. package/packages/bundled-features/src/subscription-dodo/feature.ts +207 -0
  357. package/packages/bundled-features/src/subscription-dodo/index.ts +16 -0
  358. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +345 -0
  359. package/packages/bundled-features/src/subscription-dodo/runtime.ts +126 -0
  360. package/packages/bundled-features/src/subscription-dodo/verify-webhook.ts +262 -0
  361. package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
  362. package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
  363. package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
  364. package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
  365. package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
  366. package/packages/bundled-features/src/subscription-stripe/changes.json +12 -0
  367. package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
  368. package/packages/bundled-features/src/subscription-stripe/feature.ts +45 -43
  369. package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
  370. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
  371. package/packages/bundled-features/src/subscription-stripe/runtime.ts +9 -8
  372. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
  373. package/packages/bundled-features/src/tags/feature.ts +3 -3
  374. package/packages/bundled-features/src/tags/screens.ts +1 -1
  375. package/packages/bundled-features/src/template-resolver/api.ts +41 -14
  376. package/packages/bundled-features/src/template-resolver/changes.json +48 -0
  377. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +1 -0
  378. package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
  379. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +3 -2
  380. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +27 -5
  381. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +3 -2
  382. package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +3 -2
  383. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +8 -7
  384. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +19 -20
  385. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +15 -5
  386. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
  387. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
  388. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-counts.query.ts +9 -5
  389. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +8 -6
  390. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +44 -5
  391. package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
  392. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
  393. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +37 -26
  394. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +7 -2
  395. package/packages/bundled-features/src/template-resolver/seeding.ts +36 -18
  396. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +22 -4
  397. package/packages/bundled-features/src/template-resolver/table.ts +13 -14
  398. package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +0 -11
  399. package/packages/bundled-features/src/template-resolver/template-meta.ts +12 -4
  400. package/packages/bundled-features/src/template-resolver/template-preview.ts +11 -3
  401. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
  402. package/packages/bundled-features/src/template-resolver/web/constants.ts +7 -5
  403. package/packages/bundled-features/src/template-resolver/web/index.ts +7 -0
  404. package/packages/bundled-features/src/template-resolver/web/mail-layout-constants.ts +8 -0
  405. package/packages/bundled-features/src/tenant/changes.json +6 -0
  406. package/packages/bundled-features/src/tenant/feature.ts +7 -7
  407. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +10 -4
  408. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  409. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  410. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  411. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +8 -5
  412. package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
  413. package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
  414. package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
  415. package/packages/bundled-features/src/tenant/screens.ts +1 -1
  416. package/packages/bundled-features/src/tenant/seeding.ts +19 -18
  417. package/packages/bundled-features/src/tenant/testing.ts +5 -6
  418. package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
  419. package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
  420. package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
  421. package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
  422. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  423. package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
  424. package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
  425. package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
  426. package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
  427. package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
  428. package/packages/bundled-features/src/tenant-lifecycle/constants.ts +5 -0
  429. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
  430. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +7 -3
  431. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
  432. package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
  433. package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
  434. package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
  435. package/packages/bundled-features/src/tier-engine/changes.json +6 -0
  436. package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
  437. package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
  438. package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
  439. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
  440. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
  441. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +12 -9
  442. package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
  443. package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
  444. package/packages/bundled-features/src/tier-engine/web/constants.ts +3 -3
  445. package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
  446. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
  447. package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
  448. package/packages/bundled-features/src/user/schema/user.ts +45 -44
  449. package/packages/bundled-features/src/user/seeding.ts +40 -40
  450. package/packages/bundled-features/src/user/testing.ts +3 -3
  451. package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
  452. package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
  453. package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
  454. package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
  455. package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
  456. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
  457. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
  458. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
  459. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
  460. package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
  461. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
  462. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
  463. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
  464. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
  465. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
  466. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
  467. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
  468. package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
  469. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
  470. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
  471. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +169 -280
  472. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +87 -108
  473. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
  474. package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
  475. package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
  476. package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
  477. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
  478. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
  479. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
  480. package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
  481. package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
  482. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
  483. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
  484. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
  485. package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
  486. package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
  487. package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
  488. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
  489. package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
  490. package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
  491. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
  492. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
  493. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
  494. package/packages/bundled-features/src/user-profile/index.ts +3 -3
  495. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
  496. package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
  497. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
  498. package/packages/bundled-features/src/waitlist/changes.json +18 -0
  499. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +2 -1
  500. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +5 -5
  501. package/packages/bundled-features/src/waitlist/import.ts +5 -0
  502. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +22 -3
  503. package/packages/bundled-features/src/waitlist/link-on-signup.ts +20 -10
  504. package/packages/bundled-features/src/waitlist/options.ts +3 -0
  505. package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
  506. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
  507. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
  508. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  509. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
  510. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
  511. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
  512. package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
  513. package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
  514. package/samples/apps/styleguide/src/features/widgets/i18n.ts +11 -0
  515. package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +24 -0
  516. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-constants.ts +5 -0
  517. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +90 -15
  518. package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +16 -6
  519. package/samples/apps/use-all-bundled/feature-manifest.json +120 -3
  520. package/samples/apps/use-all-bundled/src/run-config.ts +9 -3
  521. package/samples/recipes/auth-mfa/README.md +5 -0
  522. package/samples/recipes/auth-mfa/package.json +5 -2
  523. package/samples/recipes/auth-mfa/src/web/confirmation-code-step.tsx +49 -0
  524. package/samples/recipes/auth-mfa/tsconfig.json +8 -0
  525. package/samples/recipes/env-composition/README.md +3 -1
  526. package/samples/recipes/env-composition/src/env.ts +2 -0
  527. package/samples/recipes/legal-pages/README.md +1 -1
  528. package/samples/recipes/rate-limiting/README.md +18 -0
  529. package/samples/recipes/rate-limiting/src/feature.ts +12 -0
  530. package/packages/bundled-features/src/billing-foundation/consumer-protection/stored-user-email.ts +0 -12
@@ -1,35 +1,34 @@
1
- // verifyAndParseStripeWebhook — Stripe-spezifische sig-verify +
2
- // event-mapping. Wird vom Plugin-Build (feature.ts) als
3
- // `verifyAndParseWebhook` registriert.
1
+ // verifyAndParseStripeWebhook — Stripe-specific signature verification +
2
+ // event mapping. Registered by the plugin build (feature.ts) as
3
+ // `verifyAndParseWebhook`.
4
4
  //
5
5
  // **Steps:**
6
- // 1. Sig-verify via stripe.webhooks.constructEvent (HMAC-SHA-256
7
- // gegen rawBody + Stripe-Signature-Header). Wirft bei mismatch
8
- // oder älter als 5min (Replay-Protection).
6
+ // 1. Verify the signature via stripe.webhooks.constructEvent (HMAC-SHA-256
7
+ // against rawBody + Stripe-Signature header). Throws on mismatch or
8
+ // timestamps older than 5 minutes (replay protection).
9
9
  // 1b. checkout.session.completed / .async_payment_succeeded branch off
10
10
  // here into a PaymentEvent (one-off-payment, own aggregate) — see
11
- // "One-off-payment" section below. Everything else falls through.
12
- // 2. Event-type-Filter: nur die 5 event-types die wir auf
13
- // SubscriptionEventTypes mappen kommen weiter; alles andere
14
- // returnt null (foundation antwortet 200 ignored).
15
- // 3. Stripe-payload → SubscriptionEvent normalisieren
16
- // (status-mapping, tenant-id aus metadata, price-to-tier-Lookup).
11
+ // the "One-off-payment" section below. Everything else falls through.
12
+ // 2. Event-type filter: only the 5 event types mapped to
13
+ // SubscriptionEventTypes continue; everything else returns null
14
+ // (the foundation responds with 200 ignored).
15
+ // 3. Normalize the Stripe payload into a SubscriptionEvent
16
+ // (status mapping, tenant ID from metadata, price-to-tier lookup).
17
17
  //
18
- // **Runtime-keys (pre-tenant):** api-key + webhook-secret kommen NICHT
19
- // mehr aus einem mount-time-Closure, sondern werden zur Webhook-Zeit aus
20
- // dem `StripeWebhookRuntime` aufgelöst. Der foundation-webhook-handler
21
- // reicht einen system-scoped SecretsContext als 3. Arg durch; der runtime
22
- // liest beide Keys daraus (un-audited, system-internal) mit Fallback auf
23
- // die factory-options. Damit rotiert ein Key ohne Redeploy — und der
24
- // invoice-lazy-fetch (unten) nutzt denselben rotierten Client wie der
25
- // sig-verify, kein split-brain.
18
+ // **Runtime keys (pre-tenant):** the API key and webhook secret no longer
19
+ // come from a mount-time closure; they are resolved from `StripeWebhookRuntime`
20
+ // at webhook time. The foundation webhook handler passes a system-scoped
21
+ // SecretsContext as the third argument; the runtime reads both keys from it
22
+ // (unaudited, system-internal), falling back to the factory options. This
23
+ // allows key rotation without a redeploy, and the invoice lazy-fetch below
24
+ // uses the same rotated client as signature verification, avoiding split-brain.
26
25
  //
27
26
  // **Invoice-event lazy-fetch:**
28
- // Invoice payloads carry only the subscription id (Stripe does not expand
29
- // subscription in webhooks), so the plugin lazy-fetches via
27
+ // Invoice payloads carry only the subscription ID (Stripe does not expand
28
+ // subscriptions in webhooks), so the plugin lazy-fetches via
30
29
  // `stripe.subscriptions.retrieve(subId)` to get the full subscription for
31
30
  // status/tier/period-end mapping. resource_missing (deleted between webhook
32
- // and retrieve) returns null; any other Stripe error becomes 503 so Stripe
31
+ // and retrieval) returns null; any other Stripe error becomes 503 so Stripe
33
32
  // redelivers.
34
33
 
35
34
  import type {
@@ -77,18 +76,18 @@ function transientProviderRejection(error: unknown): ExtraRouteRejection {
77
76
  // =============================================================================
78
77
 
79
78
  export type StripeWebhookOptions = {
80
- /** Price-to-tier-Map. Plugin liest die price-id aus dem event und
81
- * mapped auf tier-name. Fehlt die price-id im Mapping → null. App-
82
- * spezifisch, bleibt eine factory-option (kein Secret). */
79
+ /** Price-to-tier map. The plugin reads the price ID from the event and
80
+ * maps it to a tier name. Returns null when the price ID is not mapped.
81
+ * App-specific and remains a factory option, not a secret. */
83
82
  readonly priceToTier: Readonly<Record<string, string>>;
84
83
  };
85
84
 
86
85
  /**
87
- * Stripe-webhook-handler. Implementiert den Plugin-Contract
88
- * `verifyAndParseWebhook`. **Pre-tenant-resolution** — kein
89
- * HandlerContext; statt eines mount-time-Clients löst der `runtime` den
90
- * Stripe-Client + das webhook-secret zur Call-Zeit aus dem optionalen
91
- * system-SecretsContext (3. Arg) auf.
86
+ * Stripe webhook handler implementing the plugin contract
87
+ * `verifyAndParseWebhook`. **Pre-tenant resolution** — there is no
88
+ * HandlerContext; instead of using a mount-time client, `runtime` resolves
89
+ * the Stripe client and webhook secret at call time from the optional
90
+ * system SecretsContext (third argument).
92
91
  */
93
92
  export function verifyAndParseStripeWebhook(
94
93
  runtime: StripeWebhookRuntime,
@@ -104,16 +103,16 @@ export function verifyAndParseStripeWebhook(
104
103
  throw new Error("subscription-stripe: stripe-signature header missing");
105
104
  }
106
105
 
107
- // 0. Runtime-resolve: api-key (für client + lazy-fetch) + webhook-
108
- // secret (für sig-verify) aus system-secrets, Fallback factory-
109
- // options. Wirft wenn beide unkonfiguriert.
106
+ // 0. Resolve at runtime: obtain the API key (for the client and lazy fetch)
107
+ // and webhook secret (for signature verification) from system secrets,
108
+ // falling back to the factory options. Throws if neither is configured.
110
109
  const { stripe, webhookSecret } = await runtime.resolve(systemSecrets);
111
110
 
112
- // 1. Sig-verify. constructEvent throws bei mismatch (= invalid sig)
113
- // oder timestamp-tolerance-violation (default 5min). Foundation
114
- // mapped throw → HTTP 401. Applies to BOTH branches below — the
115
- // payment-branch only branches off AFTER this check; there's no
116
- // path that bypasses signature verification.
111
+ // 1. Verify the signature. constructEvent throws on a mismatch (invalid
112
+ // signature) or timestamp-tolerance violation (default: 5 minutes).
113
+ // The foundation maps the thrown error to HTTP 401. This applies to
114
+ // BOTH branches below: the payment branch is selected only AFTER this
115
+ // check, so no path bypasses signature verification.
117
116
  let event: Stripe.Event;
118
117
  try {
119
118
  event = await stripe.webhooks.constructEventAsync(rawBody, sigHeader, webhookSecret);
@@ -131,30 +130,29 @@ export function verifyAndParseStripeWebhook(
131
130
  return await parsePaymentEvent(event, stripe);
132
131
  }
133
132
 
134
- // 2. Event-type-Filter — wir kennen nur 5.
133
+ // 2. Event-type filter — only 5 event types are supported.
135
134
  const normalizedType = mapStripeEventType(event.type);
136
135
  if (!normalizedType) {
137
136
  return null; // foundation returnt 200 ignored
138
137
  }
139
138
 
140
- // 3. Payload-extraction. Stripe liefert je nach event.type
141
- // verschiedene data.object-shapes. Wir extrahieren die
142
- // Subscription-Daten — entweder direkt (subscription-events)
143
- // oder via lazy-fetch (invoice-events).
139
+ // 3. Extract the payload. Stripe uses different data.object shapes
140
+ // depending on event.type. Extract subscription data either directly
141
+ // (subscription events) or through a lazy fetch (invoice events).
144
142
  const sub = await extractSubscriptionFromEvent(event, stripe);
145
143
  if (!sub) {
146
- // event-type war unter den 5 (oben gefiltert), aber payload-shape
147
- // matched nicht — Stripe-SDK-Schema-Drift, defensive null.
144
+ // The event type passed the 5-item filter, but its payload shape did not
145
+ // match — treat this as Stripe SDK schema drift and return null defensively.
148
146
  return null;
149
147
  }
150
148
 
151
- // 4. Tenant-resolution aus metadata. App-Builder setzt
152
- // `metadata.tenantId` beim createCheckoutSession-call.
149
+ // 4. Resolve the tenant from metadata. The app builder sets
150
+ // `metadata.tenantId` when calling createCheckoutSession.
153
151
  const tenantId = sub.metadata?.["tenantId"];
154
152
  if (!tenantId || tenantId.length === 0) {
155
- // Subscription ohne tenant-metadata → kann kein subscription
156
- // erstellen ohne tenant-resolution. Drop the event silent
157
- // (foundation 200 ignored). App-Owner-Bug, nicht foundation-Bug.
153
+ // A subscription without tenant metadata cannot be created without tenant
154
+ // resolution. Drop the event silently (the foundation responds with 200
155
+ // ignored). This is an app-owner error, not a foundation error.
158
156
  return null;
159
157
  }
160
158
 
@@ -218,7 +216,7 @@ export function mapStripeSubscriptionState(
218
216
  const periodEndUnixSec = sub.items.data[0]?.current_period_end ?? 0;
219
217
  // Stripe returns Unix-seconds; Temporal.Instant.fromEpochMilliseconds
220
218
  // expects ms. Multiply, then ISO. (No-Date-API-Guard forbids
221
- // `new Date()` — static import above, not the ambient global, see #1490.)
219
+ // `new Date()` — static import above, not the ambient global.)
222
220
  const currentPeriodEnd = Temporal.Instant.fromEpochMilliseconds(
223
221
  periodEndUnixSec * 1000,
224
222
  ).toString();
@@ -264,9 +262,9 @@ export function mapStripeEventType(stripeType: string): SubscriptionEventType |
264
262
  }
265
263
  }
266
264
 
267
- /** Stripe-status → normalisiert. Defensive: unbekannte Status →
268
- * incomplete (Plugin sollte das nicht erreichen, aber wir wollen
269
- * kein ungültiger status-string in der DB). */
265
+ /** Maps Stripe statuses to normalized statuses. Unknown statuses are
266
+ * mapped defensively to incomplete; the plugin should not receive them, but
267
+ * an invalid status string must not be stored in the database. */
270
268
  export function mapStripeStatus(stripeStatus: Stripe.Subscription.Status): SubscriptionStatus {
271
269
  switch (stripeStatus) {
272
270
  case "active":
@@ -293,9 +291,9 @@ export function mapStripeStatus(stripeStatus: Stripe.Subscription.Status): Subsc
293
291
  }
294
292
  }
295
293
 
296
- /** Holt die Subscription aus dem Event. Subscription-events haben sie
297
- * direkt im data.object; invoice-events haben nur die subscription-id
298
- * und brauchen einen lazy-fetch via stripe.subscriptions.retrieve. */
294
+ /** Gets the subscription from the event. Subscription events include it
295
+ * directly in data.object; invoice events include only the subscription ID
296
+ * and require a lazy fetch via stripe.subscriptions.retrieve. */
299
297
  // @wrapper-known semantic-alias
300
298
  async function extractSubscriptionFromEvent(
301
299
  event: Stripe.Event,
@@ -308,16 +306,16 @@ async function extractSubscriptionFromEvent(
308
306
  return event.data.object as Stripe.Subscription; // @cast-boundary engine-bridge
309
307
  case StripeEventTypes.invoicePaid:
310
308
  case StripeEventTypes.invoicePaymentFailed: {
311
- // Lazy-fetch der subscription. invoice.subscription ist eine
312
- // string-id (Stripe-Webhooks expanden nicht auto). Wir holen das
313
- // full subscription-Object damit der downstream-mapping
314
- // (status, tier via priceId, period-end) konsistent funktioniert.
309
+ // Lazy-fetch the subscription. invoice.subscription is a string ID because
310
+ // Stripe webhooks do not expand it automatically. Fetch the full
311
+ // subscription so downstream status, tier via priceId, and period-end
312
+ // mapping remain consistent.
315
313
  const invoice = event.data.object as Stripe.Invoice; // @cast-boundary engine-bridge
316
314
  const subRef = (invoice as { subscription?: string | Stripe.Subscription | null }) // @cast-boundary engine-payload
317
315
  .subscription;
318
316
  if (!subRef) {
319
- // Invoice ohne subscription-reference (= one-shot-invoice, nicht
320
- // recurring). Nicht unsere Domain — ignorieren.
317
+ // An invoice without a subscription reference is a one-shot invoice, not a
318
+ // recurring invoice. It is outside this domain and should be ignored.
321
319
  return null;
322
320
  }
323
321
  const subId = typeof subRef === "string" ? subRef : subRef.id;
@@ -150,9 +150,9 @@ export type TagsFeatureOptions = {
150
150
  /** Row-level ownership on the tag-assignment rows themselves — orthogonal to
151
151
  * `access`, which only gates whether a caller may dispatch assign/remove/list
152
152
  * at all. `ownership.read` is no longer what keeps a caller from reading
153
- * assignments on host entities they can't see: that gate is default-on since
154
- * fw#2766 and derives from the entity's `parentRef`. Use `ownership.read` for
155
- * an ADDITIONAL row rule on the assignment row itself; it is AND-ed with the
153
+ * assignments on host entities they can't see: that gate is default-on and
154
+ * derives from the entity's `parentRef`. Use `ownership.read` for an
155
+ * ADDITIONAL row rule on the assignment row itself; it is AND-ed with the
156
156
  * host-visibility gate, never a replacement for it. Applies only to
157
157
  * `tag-assignment`; the `tag` catalog stays tenant-wide by design.
158
158
  *
@@ -6,7 +6,7 @@ import {
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
7
  import { DEFAULT_TAG_ACCESS, TAGS_EDIT_SCREEN_ID, TAGS_SCREEN_ID } from "./web/constants.ts";
8
8
 
9
- // Declarative catalog screens (Phase-3 / #2312). Access matches create/update/
9
+ // Declarative catalog screens. Access matches create/update/
10
10
  // delete so createTagsFeature({ access|roles }) stays consistent. TagManager
11
11
  // remains for TagPicker/TagSection — only the standalone admin screen moved.
12
12
 
@@ -158,12 +158,14 @@ export function createTemplateResolverApi(
158
158
  };
159
159
  }
160
160
 
161
+ type DeliveredRowKey = Pick<TemplateResourceRow, "tenantId" | "kind" | "slug">;
162
+
161
163
  // The one delivery rule for a stored row: unlocked, and a collection entry never shadows a system
162
164
  // template of the same slug that the app did not unlock.
163
165
  export async function isRowDelivered(
164
166
  db: DbRunner | TenantDb,
165
167
  policy: TemplateDeliveryPolicy,
166
- row: TemplateResourceRow,
168
+ row: DeliveredRowKey,
167
169
  ): Promise<boolean> {
168
170
  if (!isRowServed(policy, row)) return false;
169
171
  if (row.tenantId === SYSTEM_TENANT_ID || !isServedByCollectionOnly(policy, row)) return true;
@@ -174,19 +176,44 @@ export async function isRowDeliveredTo(
174
176
  db: DbRunner | TenantDb,
175
177
  policy: TemplateDeliveryPolicy,
176
178
  user: { readonly roles: readonly string[] },
177
- row: TemplateResourceRow,
179
+ row: DeliveredRowKey,
178
180
  ): Promise<boolean> {
179
181
  return isSystemAdmin(user) || (await isRowDelivered(db, policy, row));
180
182
  }
181
183
 
184
+ // One system-slug lookup per kind instead of one query per row, because by-tenant is anonymous.
182
185
  export async function filterDeliveredTo(
183
186
  db: DbRunner | TenantDb,
184
187
  policy: TemplateDeliveryPolicy,
185
188
  user: { readonly roles: readonly string[] },
186
189
  rows: readonly TemplateResourceRow[],
187
190
  ): Promise<TemplateResourceRow[]> {
188
- const flags = await Promise.all(rows.map((row) => isRowDeliveredTo(db, policy, user, row)));
189
- return rows.filter((_, index) => flags[index]);
191
+ if (isSystemAdmin(user)) return [...rows];
192
+ const served = rows.filter((row) => isRowServed(policy, row));
193
+ const shadowable = served.filter(
194
+ (row) => row.tenantId !== SYSTEM_TENANT_ID && isServedByCollectionOnly(policy, row),
195
+ );
196
+ const slugsByKind = new Map<string, Set<string>>();
197
+ for (const row of shadowable) {
198
+ const slugs = slugsByKind.get(row.kind) ?? new Set<string>();
199
+ slugs.add(row.slug);
200
+ slugsByKind.set(row.kind, slugs);
201
+ }
202
+ const systemKeys = new Set<string>();
203
+ for (const [kind, slugs] of slugsByKind) {
204
+ const systemRows = await selectMany<TemplateResourceRow>(db, templateResourcesTable, {
205
+ tenantId: SYSTEM_TENANT_ID,
206
+ kind,
207
+ slug: [...slugs],
208
+ });
209
+ for (const systemRow of systemRows) systemKeys.add(`${kind}|${systemRow.slug}`);
210
+ }
211
+ return served.filter(
212
+ (row) =>
213
+ row.tenantId === SYSTEM_TENANT_ID ||
214
+ !isServedByCollectionOnly(policy, row) ||
215
+ !systemKeys.has(`${row.kind}|${row.slug}`),
216
+ );
190
217
  }
191
218
 
192
219
  export async function systemTemplateExists(
@@ -232,20 +259,20 @@ async function fetchTemplate(
232
259
  { limit: 1 },
233
260
  );
234
261
  // @cast-boundary db-row — db.select returnt unbenanntes unknown[],
235
- // Row-Shape ist via templateResourcesTable + buildBaseColumns garantiert.
262
+ // The row shape is guaranteed by templateResourcesTable + buildBaseColumns.
236
263
  return (rows[0] as TemplateResourceRow | undefined) ?? null;
237
264
  }
238
265
 
239
266
  function toPublic(row: TemplateResourceRow): TemplateResource {
240
267
  // @cast-boundary db-row — Drizzle-Schema typisiert kind/contentFormat/
241
- // scope/status als generic text. CHECK-Constraints in der DB schränken
242
- // sie auf die Union-Types ein; Cast assertet das Schema-Wissen.
268
+ // scope/status as generic text. Database CHECK constraints restrict
269
+ // them to the union types; the cast asserts that schema knowledge.
243
270
  const kind = row.kind as TemplateKind;
244
- // @cast-boundary db-row — siehe kind.
271
+ // @cast-boundary db-row — see kind.
245
272
  const contentFormat = row.contentFormat as ContentFormat;
246
- // @cast-boundary db-row — siehe kind.
273
+ // @cast-boundary db-row — see kind.
247
274
  const scope = row.scope as "system" | "tenant";
248
- // @cast-boundary db-row — siehe kind.
275
+ // @cast-boundary db-row — see kind.
249
276
  const status = row.status as "draft" | "active" | "archived";
250
277
  const linkedEntries = parseLinkedResourceEntries(row.linkedResources);
251
278
  return {
@@ -286,7 +313,7 @@ function parseJson(raw: string | null): Record<string, unknown> {
286
313
  try {
287
314
  const parsed = JSON.parse(raw);
288
315
  // @cast-boundary engine-payload — JSON.parse returnt unknown, typeof-Guard
289
- // grenzt auf object ein; Record<string, unknown> ist der minimale common-shape.
316
+ // narrows it to object; Record<string, unknown> is the minimal common shape.
290
317
  return typeof parsed === "object" && parsed !== null ? (parsed as Record<string, unknown>) : {};
291
318
  } catch {
292
319
  return {};
@@ -302,14 +329,14 @@ export class TemplateNotFoundError extends Error {
302
329
  }
303
330
  }
304
331
 
305
- // Single point of truth für "dieser Handler braucht template-resolver".
306
- // Pattern symmetrisch zu requireTextContent.
332
+ // Single source of truth for "this handler requires template-resolver".
333
+ // Pattern symmetric with requireTextContent.
307
334
  export function requireTemplateResolver(
308
335
  ctx: { readonly templateResolver?: TemplateResolverApi } | object,
309
336
  callerName: string,
310
337
  ): TemplateResolverApi {
311
338
  // @cast-boundary engine-bridge — templateResolver kommt per extraContext
312
- // aus App-Bootstrap, Framework-Container kennt das Feld nicht von sich aus.
339
+ // from App-Bootstrap; the framework container does not know this field on its own.
313
340
  const api = (ctx as { templateResolver?: TemplateResolverApi }).templateResolver;
314
341
  if (!api) {
315
342
  throw new InternalError({
@@ -1,4 +1,52 @@
1
1
  [
2
+ {
3
+ "version": "0.388.0",
4
+ "type": "fix",
5
+ "title": "Template overrides, key collisions and by-tenant queries",
6
+ "detail": "link-pdf refuses a key that already holds an inline image (key_in_use). by-tenant no longer runs a query per row, tenant-override-counts selects only the needed columns, and tenant-overrides resolves names beyond the first 200 tenants or users through the new ids filter of the tenant and member directories. Notification preference and form-draft cleanup queries bind array parameters as Postgres array literals."
7
+ },
8
+ {
9
+ "version": "0.388.0",
10
+ "type": "fix",
11
+ "title": "Re-seeding keeps archived system templates, drops stale drafts and adds only missing bundle locales",
12
+ "detail": "A boot-time re-seed no longer reactivates an archived system template and clears an open system draft when the seeded content changes. A bundle with resources seeded with ifExists skip imports only the missing locales instead of overwriting existing system rows. copy-locale fails with version_conflict when its source changed between the upload and the transaction, and releases the uploaded files."
13
+ },
14
+ {
15
+ "version": "0.388.0",
16
+ "type": "fix",
17
+ "title": "isCollectionRefusedKind is a type predicate",
18
+ "detail": "isCollectionRefusedKind accepts unknown and narrows to the refused kinds; tier-engine's isTierAssignmentSource shares the isOneOf implementation. Behavior is unchanged."
19
+ },
20
+ {
21
+ "version": "0.388.0",
22
+ "type": "fix",
23
+ "title": "Layout usage list matches the overview",
24
+ "detail": "The usage query of a mail layout filters the mail rows by the caller's visibility like the overview and logs a warning when the 5000-row limit cuts the result."
25
+ },
26
+ {
27
+ "version": "0.388.0",
28
+ "type": "fix",
29
+ "title": "Admin views follow the delivery rule of rendering",
30
+ "detail": "List, find-by-id, diff-to-system, validate, preview and the document base hide a collection row that a locked system template of the same slug shadows, as mail, PDF and the resolver already do."
31
+ },
32
+ {
33
+ "version": "0.388.0",
34
+ "type": "fix",
35
+ "title": "Seeded title key must look like a namespace:key",
36
+ "detail": "seedSystemTemplate rejects a titleI18nKey without a namespace prefix or with whitespace, so free text cannot pass as a key and show up raw in the UI."
37
+ },
38
+ {
39
+ "version": "0.388.0",
40
+ "type": "fix",
41
+ "title": "Failing release keeps the upload error",
42
+ "detail": "When releasing already uploaded files fails after a refused upload in copy-locale or bundle import, the release error is logged and the original error is returned, and the releases run once."
43
+ },
44
+ {
45
+ "version": "0.388.0",
46
+ "type": "fix",
47
+ "title": "Mail layout enums and hex color pattern are exported client-side",
48
+ "detail": "The layout editor imports the width, font, accent line and button style lists plus the hex pattern from the template-resolver web barrel instead of keeping copies, so editor and server validation cannot drift."
49
+ },
2
50
  {
3
51
  "version": "0.384.0",
4
52
  "type": "improvement",
@@ -432,6 +432,7 @@ export function compileDocumentBodyToHandlebars(
432
432
  for (const element of Array.from(root.querySelectorAll("div[data-images]"))) {
433
433
  rewriteImagesBlock(element, state, options);
434
434
  }
435
+ // Order matters: the conditional wraps first so the row's #each lands inside the #if (evaluated once per list).
435
436
  for (const block of Array.from(root.querySelectorAll(`[${DOCUMENT_CONDITION_ATTRIBUTE}]`))) {
436
437
  rewriteConditionalBlock(block, state);
437
438
  }
@@ -41,7 +41,7 @@ import {
41
41
  } from "./handlers/toggle-status.write.ts";
42
42
  import { upsertSystemWrite } from "./handlers/upsert-system.write.ts";
43
43
  import { makeUpsertTenantWrite } from "./handlers/upsert-tenant.write.ts";
44
- import { usageQuery } from "./handlers/usage.query.ts";
44
+ import { makeUsageQuery } from "./handlers/usage.query.ts";
45
45
  import { validateQuery } from "./handlers/validate.query.ts";
46
46
  import { TEMPLATE_RESOLVER_I18N } from "./i18n.ts";
47
47
  import { templateResourceEntity } from "./table.ts";
@@ -181,7 +181,7 @@ export function createTemplateResolverFeature(opts: TemplateResolverOptions = {}
181
181
  list: r.queryHandler(listQuery),
182
182
  bySlug: r.queryHandler(bySlugQuery),
183
183
  byTenant: r.queryHandler(byTenantQuery),
184
- usage: r.queryHandler(usageQuery),
184
+ usage: r.queryHandler(makeUsageQuery(policy)),
185
185
  overview: r.queryHandler(makeOverviewQuery(policy)),
186
186
  layoutSource: r.queryHandler(layoutSourceQuery),
187
187
  tenantOverrides: r.queryHandler(tenantOverridesQuery),
@@ -23,6 +23,7 @@ import {
23
23
  prepareTemplateResourceBeforeTransaction,
24
24
  type Release,
25
25
  readTemplateResourceMaxBytes,
26
+ releaseAfterFailure,
26
27
  releaseAll,
27
28
  } from "../store-template-resource.ts";
28
29
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
@@ -152,14 +153,14 @@ export async function prepareTemplateBundleBeforeTransaction(
152
153
  })
153
154
  : await prepareTemplateResourceBeforeTransaction(common);
154
155
  if (!result.isSuccess) {
155
- await releaseAll(releases);
156
+ await releaseAfterFailure(args.ctx, releases);
156
157
  return result;
157
158
  }
158
159
  if (result.release) releases.push(result.release);
159
160
  prepared.set(key, result.data);
160
161
  }
161
162
  } catch (cause) {
162
- await releaseAll(releases);
163
+ await releaseAfterFailure(args.ctx, releases);
163
164
  throw cause;
164
165
  }
165
166
  return { isSuccess: true, data: prepared, release: () => releaseAll(releases) };
@@ -11,6 +11,7 @@ import {
11
11
  AccessDeniedError,
12
12
  NotFoundError,
13
13
  ValidationError,
14
+ VersionConflictError,
14
15
  writeFailure,
15
16
  } from "@cosmicdrift/kumiko-framework/errors";
16
17
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
@@ -172,13 +173,17 @@ export function makeCopyLocaleWrite(policy: TemplateEditPolicy) {
172
173
  beforeTransaction: async (event, ctx) => {
173
174
  const request = await checkCopyRequest(ctx, policy, event);
174
175
  if (!request.isSuccess) return request;
175
- if (!request.data.sourceIsForeign) return { isSuccess: true, data: [] };
176
- return prepareLinkedResourceCopiesBeforeTransaction({
176
+ const { source, tenantId, sourceIsForeign, sourceResources } = request.data;
177
+ const sourceStamp = { sourceId: source.id, sourceVersion: source.version };
178
+ if (!sourceIsForeign) return { isSuccess: true, data: { ...sourceStamp, copies: [] } };
179
+ const prepared = await prepareLinkedResourceCopiesBeforeTransaction({
177
180
  ctx,
178
181
  user: event.user,
179
- tenantId: request.data.tenantId,
180
- resources: request.data.sourceResources,
182
+ tenantId,
183
+ resources: sourceResources,
181
184
  });
185
+ if (!prepared.isSuccess) return prepared;
186
+ return { ...prepared, data: { ...sourceStamp, copies: prepared.data } };
182
187
  },
183
188
  handler: async (event, ctx) => {
184
189
  const { slug, kind, toLocale } = event.payload;
@@ -186,6 +191,20 @@ export function makeCopyLocaleWrite(policy: TemplateEditPolicy) {
186
191
  if (!request.isSuccess) return request;
187
192
  const { scope, tenantId, source, contentFormat, sourceResources, sourceIsForeign } =
188
193
  request.data;
194
+ // The uploads were prepared for the source as it was before the transaction; a source that
195
+ // changed since (own row created or deleted, edited) no longer matches them.
196
+ if (
197
+ event.prepared.sourceId !== source.id ||
198
+ event.prepared.sourceVersion !== source.version
199
+ ) {
200
+ return writeFailure(
201
+ new VersionConflictError({
202
+ entityId: source.id,
203
+ expectedVersion: event.prepared.sourceVersion,
204
+ currentVersion: source.version,
205
+ }),
206
+ );
207
+ }
189
208
 
190
209
  const variableSchema = storedRecord(source.variableSchema);
191
210
  const written = await writeTemplateRow({
@@ -209,7 +228,10 @@ export function makeCopyLocaleWrite(policy: TemplateEditPolicy) {
209
228
  });
210
229
  if (!written.isSuccess) return written;
211
230
  const resources = sourceIsForeign
212
- ? await createLinkedResourceCopies({ ctx, user: event.user, tenantId }, event.prepared)
231
+ ? await createLinkedResourceCopies(
232
+ { ctx, user: event.user, tenantId },
233
+ event.prepared.copies,
234
+ )
213
235
  : { isSuccess: true as const, data: sourceResources };
214
236
  if (!resources.isSuccess) return resources;
215
237
  const attached = await attachTemplateResources(ctx, {
@@ -2,8 +2,9 @@ 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";
5
+ import { isRowDeliveredTo } from "../api.ts";
5
6
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
6
- import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
7
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
7
8
  import { isHiddenSystemDraft } from "../template-draft.ts";
8
9
  import { buildOverrideDiff } from "./override-diff.ts";
9
10
 
@@ -21,7 +22,7 @@ export const diffToSystemQuery = defineQueryHandler({
21
22
  !tenantRow ||
22
23
  tenantRow.tenantId !== query.user.tenantId ||
23
24
  tenantRow.scope !== "tenant" ||
24
- !isRowServedTo(deliveryPolicyOf(ctx.registry), query.user, tenantRow)
25
+ !(await isRowDeliveredTo(ctx.db, deliveryPolicyOf(ctx.registry), query.user, tenantRow))
25
26
  ) {
26
27
  throw new NotFoundError("template-resource", query.payload.id);
27
28
  }
@@ -5,8 +5,9 @@ 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 { isRowDeliveredTo } from "../api.ts";
8
9
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
9
- import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
10
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
10
11
  import { isHiddenSystemDraft, toWorkingRow } from "../template-draft.ts";
11
12
  import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.ts";
12
13
  import type { DocumentHtmlKind } from "../web/constants.ts";
@@ -50,7 +51,7 @@ export async function loadDocumentBase(
50
51
  const ownIsVisible =
51
52
  own !== undefined &&
52
53
  !isSystemOnlyTemplateHiddenFrom(user, ctx.registry, own) &&
53
- isRowServedTo(deliveryPolicyOf(ctx.registry), user, own);
54
+ (await isRowDeliveredTo(ctx.db, deliveryPolicyOf(ctx.registry), user, own));
54
55
  if (own !== undefined && ownIsVisible) {
55
56
  const working = toWorkingRow(own, user.tenantId);
56
57
  return {
@@ -1,16 +1,17 @@
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 { isRowDeliveredTo } from "../api.ts";
4
5
  import { type TemplateResourceRow, templateResourcesTable } from "../table.ts";
5
- import { deliveryPolicyOf, isRowServedTo } from "../template-delivery-policy.ts";
6
+ import { deliveryPolicyOf } from "../template-delivery-policy.ts";
6
7
  import { draftViewerTenantId, isHiddenSystemDraft, toWorkingRow } from "../template-draft.ts";
7
8
  import { isSystemOnlyTemplateHiddenFrom } from "../template-system-only.ts";
8
9
 
9
- // Admin-Lookup für UI-Edit-Flow. Returnt das raw Template inkl. draft/
10
- // archived Status. Tenant-Isolation: User sieht nur Templates des
11
- // eigenen Tenants oder SYSTEM_TENANT (system-defaults sind public-
12
- // readable); ctx.db is tenant-scoped for every role, so the check below is defense in depth. Anonymous bleibt aus — Public-
13
- // Read geht über resolveTemplate aus der API, nicht hier.
10
+ // Admin lookup for the UI editing flow. Returns the raw template, including draft/
11
+ // archived status. Tenant isolation: users see only templates belonging to their own
12
+ // tenant or SYSTEM_TENANT (system defaults are publicly readable); ctx.db is tenant-
13
+ // scoped for every role, so the check below is defense in depth. Anonymous access is
14
+ // excluded—public reads go through resolveTemplate in the API, not here.
14
15
  export const findByIdQuery = defineQueryHandler({
15
16
  name: "find-by-id",
16
17
  schema: z.object({ id: z.string().min(1) }),
@@ -25,7 +26,7 @@ export const findByIdQuery = defineQueryHandler({
25
26
  !stored ||
26
27
  isHiddenSystemDraft(query.user, stored) ||
27
28
  isSystemOnlyTemplateHiddenFrom(query.user, ctx.registry, stored) ||
28
- !isRowServedTo(deliveryPolicyOf(ctx.registry), query.user, stored)
29
+ !(await isRowDeliveredTo(ctx.db, deliveryPolicyOf(ctx.registry), query.user, stored))
29
30
  ) {
30
31
  return null;
31
32
  }