@cosmicdrift/kumiko-bundled-features 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 (643) hide show
  1. package/LICENSE +21 -57
  2. package/dist/agent-tools/tool-catalog.js +1 -1
  3. package/dist/agent-tools/tool-dispatch.d.ts +7 -7
  4. package/dist/agent-tools/tool-dispatch.js +9 -9
  5. package/dist/audit/handlers/audit-events.js +1 -1
  6. package/dist/audit/screens.js +1 -1
  7. package/dist/auth-email-password/feature.js +1 -1
  8. package/dist/auth-email-password/handlers/change-password.write.js +3 -3
  9. package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
  10. package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
  11. package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
  12. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  13. package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
  14. package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
  15. package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
  16. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  17. package/dist/auth-email-password/handlers/login.write.js +1 -1
  18. package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
  19. package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
  20. package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
  21. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  22. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
  23. package/dist/auth-email-password/index.js +5 -5
  24. package/dist/auth-email-password/lockout-store.js +1 -1
  25. package/dist/auth-email-password/seeding.d.ts +42 -45
  26. package/dist/auth-email-password/seeding.js +51 -53
  27. package/dist/auth-email-password/signup-token-store.js +8 -8
  28. package/dist/auth-email-password/testing.js +3 -3
  29. package/dist/auth-email-password/web/auth-client.d.ts +2 -2
  30. package/dist/auth-email-password/web/auth-client.js +36 -37
  31. package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
  32. package/dist/auth-email-password/web/auth-gate.js +15 -16
  33. package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
  34. package/dist/auth-email-password/web/client-plugin.js +4 -5
  35. package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
  36. package/dist/auth-email-password/web/constants.js +3 -3
  37. package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
  38. package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
  39. package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
  40. package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
  41. package/dist/auth-email-password/web/index.js +5 -5
  42. package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
  43. package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
  44. package/dist/auth-email-password/web/login-screen.d.ts +1 -1
  45. package/dist/auth-email-password/web/login-screen.js +2 -3
  46. package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
  47. package/dist/auth-email-password/web/reset-password-screen.js +12 -13
  48. package/dist/auth-email-password/web/session.d.ts +10 -9
  49. package/dist/auth-email-password/web/session.js +28 -29
  50. package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
  51. package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
  52. package/dist/auth-email-password/web/signup-screen.js +13 -13
  53. package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
  54. package/dist/auth-email-password/web/tenant-switcher.js +21 -22
  55. package/dist/auth-email-password/web/use-shell-user.js +12 -13
  56. package/dist/auth-email-password/web/user-menu.d.ts +4 -4
  57. package/dist/auth-email-password/web/user-menu.js +12 -13
  58. package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
  59. package/dist/auth-email-password/web/verify-email-screen.js +9 -10
  60. package/dist/auth-foundation/boot-checks.js +4 -4
  61. package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
  62. package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
  63. package/dist/auth-foundation/types.js +2 -2
  64. package/dist/auth-mfa/feature-exports.d.ts +2 -2
  65. package/dist/auth-mfa/feature.js +8 -0
  66. package/dist/auth-mfa/handlers/disable.write.js +3 -3
  67. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
  68. package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
  69. package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
  70. package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
  71. package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
  72. package/dist/auth-mfa/handlers/verify.write.js +1 -1
  73. package/dist/auth-mfa/token-secrets.js +1 -1
  74. package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
  75. package/dist/auth-mfa/web/client-plugin.js +1 -1
  76. package/dist/auth-mfa/web/i18n.js +8 -4
  77. package/dist/auth-mfa/web/index.js +4 -4
  78. package/dist/auth-mfa/web/mfa-client.js +17 -16
  79. package/dist/auth-mfa/web/mfa-code-or-recovery-field.d.ts +11 -0
  80. package/dist/auth-mfa/web/mfa-code-or-recovery-field.js +12 -0
  81. package/dist/auth-mfa/web/mfa-disable-dialog.js +14 -3
  82. package/dist/auth-mfa/web/mfa-regenerate-recovery-dialog.js +14 -3
  83. package/dist/auth-mfa/web/mfa-setup-preauth-screen.js +10 -5
  84. package/dist/auth-mfa/web/mfa-verify-screen.js +32 -11
  85. package/dist/billing-foundation/aggregate-id.d.ts +5 -5
  86. package/dist/billing-foundation/aggregate-id.js +10 -11
  87. package/dist/billing-foundation/checkout-core.d.ts +9 -14
  88. package/dist/billing-foundation/checkout-core.js +24 -39
  89. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +8 -2
  90. package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +1 -0
  91. package/dist/billing-foundation/consumer-protection/consent-gate.js +1 -0
  92. package/dist/billing-foundation/consumer-protection/issue-confirmation.js +9 -3
  93. package/dist/billing-foundation/consumer-protection/mail-notifications.js +3 -1
  94. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +4 -2
  95. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +6 -5
  96. package/dist/billing-foundation/consumer-protection/termination-record.d.ts +5 -1
  97. package/dist/billing-foundation/consumer-protection/termination-record.js +27 -17
  98. package/dist/billing-foundation/consumer-protection/termination-request.js +12 -7
  99. package/dist/billing-foundation/consumer-protection/termination-revoke.js +12 -7
  100. package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
  101. package/dist/billing-foundation/consumer-protection/termination-texts.js +3 -0
  102. package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +5 -2
  103. package/dist/billing-foundation/consumer-protection/withdrawal-period.js +8 -9
  104. package/dist/billing-foundation/entities.js +27 -27
  105. package/dist/billing-foundation/events.d.ts +1 -0
  106. package/dist/billing-foundation/events.js +19 -17
  107. package/dist/billing-foundation/feature.js +45 -44
  108. package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
  109. package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
  110. package/dist/billing-foundation/handlers/billing-plans.query.js +35 -5
  111. package/dist/billing-foundation/handlers/create-checkout-session.write.js +19 -17
  112. package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
  113. package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
  114. package/dist/billing-foundation/handlers/plan-switch-preview.query.d.ts +13 -0
  115. package/dist/billing-foundation/handlers/plan-switch-preview.query.js +48 -0
  116. package/dist/billing-foundation/handlers/process-event.write.d.ts +6 -0
  117. package/dist/billing-foundation/handlers/process-event.write.js +28 -22
  118. package/dist/billing-foundation/handlers/start-plan-checkout.write.js +32 -5
  119. package/dist/billing-foundation/handlers/switch-plan.write.d.ts +2 -2
  120. package/dist/billing-foundation/handlers/switch-plan.write.js +56 -64
  121. package/dist/billing-foundation/handlers/sync-subscription.write.js +12 -1
  122. package/dist/billing-foundation/i18n.js +22 -0
  123. package/dist/billing-foundation/index.d.ts +1 -1
  124. package/dist/billing-foundation/plan-catalog.d.ts +21 -5
  125. package/dist/billing-foundation/plan-catalog.js +25 -16
  126. package/dist/billing-foundation/plan-switch.d.ts +12 -0
  127. package/dist/billing-foundation/plan-switch.js +60 -0
  128. package/dist/billing-foundation/projection.d.ts +15 -11
  129. package/dist/billing-foundation/projection.js +38 -37
  130. package/dist/billing-foundation/subscription-tier-sync.js +3 -3
  131. package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
  132. package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
  133. package/dist/billing-foundation/types.d.ts +97 -42
  134. package/dist/billing-foundation/types.js +29 -20
  135. package/dist/billing-foundation/validate-options.js +17 -0
  136. package/dist/billing-foundation/web/billing-plans-panel.js +82 -36
  137. package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +17 -3
  138. package/dist/billing-foundation/web/checkout-consent-dialog.js +14 -10
  139. package/dist/billing-foundation/web/constants.d.ts +4 -0
  140. package/dist/billing-foundation/web/constants.js +4 -0
  141. package/dist/billing-foundation/web/plan-price.d.ts +15 -0
  142. package/dist/billing-foundation/web/plan-price.js +32 -0
  143. package/dist/billing-foundation/web/plan-switch-confirm-dialog.d.ts +15 -0
  144. package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +66 -0
  145. package/dist/cap-counter/aggregate-id.js +8 -9
  146. package/dist/cap-counter/cap-reservation.js +5 -1
  147. package/dist/cap-counter/constants.js +11 -12
  148. package/dist/cap-counter/enforce-cap.d.ts +59 -62
  149. package/dist/cap-counter/enforce-cap.js +49 -49
  150. package/dist/cap-counter/entity.js +29 -29
  151. package/dist/cap-counter/feature.js +34 -35
  152. package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
  153. package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
  154. package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
  155. package/dist/cap-counter/stock-cap-guard.js +8 -2
  156. package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
  157. package/dist/channel-email/feature.js +1 -1
  158. package/dist/channel-email/smtp-transport.d.ts +18 -17
  159. package/dist/channel-email/smtp-transport.js +24 -21
  160. package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
  161. package/dist/compliance-profiles/feature.js +4 -4
  162. package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
  163. package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
  164. package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
  165. package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
  166. package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
  167. package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
  168. package/dist/compliance-profiles/schema/profile-selection.js +18 -23
  169. package/dist/compliance-profiles/seeding.js +14 -15
  170. package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
  171. package/dist/compliance-profiles-ops/index.js +2 -2
  172. package/dist/config/handlers/cascade.query.d.ts +5 -0
  173. package/dist/config/handlers/cascade.query.js +4 -3
  174. package/dist/config/handlers/readiness.query.d.ts +4 -4
  175. package/dist/config/handlers/readiness.query.js +1 -1
  176. package/dist/config/handlers/reencrypt.job.js +4 -5
  177. package/dist/config/handlers/set.write.js +4 -4
  178. package/dist/config/handlers/values.query.d.ts +5 -0
  179. package/dist/config/handlers/values.query.js +4 -3
  180. package/dist/config/resolver.js +4 -4
  181. package/dist/config/table.js +10 -10
  182. package/dist/config/write-helpers.d.ts +1 -0
  183. package/dist/config/write-helpers.js +19 -10
  184. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
  185. package/dist/crypto-shredding/handlers/forget-subject.write.js +25 -21
  186. package/dist/custom-fields/aggregate-id.d.ts +12 -13
  187. package/dist/custom-fields/aggregate-id.js +16 -17
  188. package/dist/custom-fields/entity.js +49 -47
  189. package/dist/custom-fields/events.js +7 -8
  190. package/dist/custom-fields/feature.d.ts +14 -14
  191. package/dist/custom-fields/feature.js +53 -54
  192. package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
  193. package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
  194. package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
  195. package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
  196. package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
  197. package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
  198. package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
  199. package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
  200. package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
  201. package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
  202. package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
  203. package/dist/custom-fields/lib/field-access.js +2 -2
  204. package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
  205. package/dist/custom-fields/lib/quota.js +1 -1
  206. package/dist/custom-fields/lib/value-schema.js +10 -12
  207. package/dist/custom-fields/run-retention.js +3 -3
  208. package/dist/custom-fields/schemas.js +14 -14
  209. package/dist/custom-fields/web/client-plugin.js +2 -5
  210. package/dist/custom-fields/web/constants.js +2 -2
  211. package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
  212. package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
  213. package/dist/custom-fields/wire-for-entity.js +65 -67
  214. package/dist/custom-fields/wire-user-data-rights.js +3 -3
  215. package/dist/data-retention/_internal/parse-override.js +2 -3
  216. package/dist/data-retention/feature.js +11 -18
  217. package/dist/data-retention/handlers/policy-for.query.js +6 -6
  218. package/dist/data-retention/keep-for.d.ts +7 -7
  219. package/dist/data-retention/keep-for.js +15 -15
  220. package/dist/data-retention/override-schema.d.ts +3 -4
  221. package/dist/data-retention/override-schema.js +13 -15
  222. package/dist/data-retention/presets.d.ts +4 -5
  223. package/dist/data-retention/presets.js +18 -23
  224. package/dist/data-retention/resolve-tenant-preset.js +17 -16
  225. package/dist/data-retention/resolver.d.ts +12 -12
  226. package/dist/data-retention/resolver.js +24 -23
  227. package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
  228. package/dist/data-retention/run-retention-cleanup.js +61 -51
  229. package/dist/data-retention/schema/tenant-retention-override.js +13 -11
  230. package/dist/delivery/channel-context.js +6 -3
  231. package/dist/delivery/db/queries/preferences.js +2 -2
  232. package/dist/delivery/delivery-service.js +22 -7
  233. package/dist/delivery/feature.js +2 -2
  234. package/dist/delivery/handlers/log.query.js +1 -1
  235. package/dist/delivery/handlers/preferences.query.d.ts +1 -1
  236. package/dist/delivery/handlers/preferences.query.js +20 -1
  237. package/dist/delivery/handlers/unsubscribe-page-chrome.query.js +1 -1
  238. package/dist/delivery/tables.js +9 -8
  239. package/dist/delivery/unsubscribe-link.d.ts +3 -1
  240. package/dist/delivery/unsubscribe-page-strings.d.ts +1 -0
  241. package/dist/delivery/unsubscribe-page-strings.js +1 -0
  242. package/dist/delivery/unsubscribe-page.d.ts +2 -0
  243. package/dist/delivery/unsubscribe-page.js +5 -0
  244. package/dist/delivery/unsubscribe.js +29 -11
  245. package/dist/document-ingest-foundation/entity.js +4 -4
  246. package/dist/document-ingest-foundation/events.js +2 -2
  247. package/dist/document-ingest-foundation/feature.js +2 -2
  248. package/dist/document-ingest-foundation/pages.js +1 -1
  249. package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
  250. package/dist/feature-toggles/compose-tier-resolver.js +1 -1
  251. package/dist/feature-toggles/feature.js +1 -1
  252. package/dist/feature-toggles/global-feature-state-table.js +1 -1
  253. package/dist/feature-toggles/handlers/registered.query.js +5 -5
  254. package/dist/feature-toggles/toggle-sync-signal.js +1 -1
  255. package/dist/feature-toggles/web/constants.js +1 -1
  256. package/dist/file-derivatives/feature.d.ts +1 -1
  257. package/dist/file-derivatives/feature.js +1 -1
  258. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  259. package/dist/file-derivatives/presets.js +1 -1
  260. package/dist/file-foundation/feature.js +6 -6
  261. package/dist/file-foundation/index.d.ts +1 -1
  262. package/dist/file-foundation/index.js +1 -1
  263. package/dist/file-foundation/read-file-ref-content.d.ts +3 -0
  264. package/dist/file-foundation/read-file-ref-content.js +6 -1
  265. package/dist/file-provider-inmemory/feature.d.ts +1 -1
  266. package/dist/file-provider-inmemory/feature.js +16 -16
  267. package/dist/file-provider-s3/env-named-feature.d.ts +0 -2
  268. package/dist/file-provider-s3/feature.js +16 -16
  269. package/dist/file-provider-s3/lib/s3-provider.js +6 -6
  270. package/dist/files/feature.js +6 -6
  271. package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
  272. package/dist/files-tenant-data/hooks.js +24 -26
  273. package/dist/files-tenant-data/index.js +1 -1
  274. package/dist/folders/feature.d.ts +1 -1
  275. package/dist/folders/web/folder-manager.js +2 -2
  276. package/dist/folders/web/tree.js +5 -5
  277. package/dist/form-draft/db/queries/cleanup.js +3 -3
  278. package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
  279. package/dist/form-draft/decrypt-draft.js +5 -1
  280. package/dist/form-draft/entity.js +3 -3
  281. package/dist/form-draft/feature.js +4 -5
  282. package/dist/form-draft/handlers/discard.write.js +1 -1
  283. package/dist/form-draft/release-file-refs.js +6 -6
  284. package/dist/form-draft/schemas.js +3 -3
  285. package/dist/form-draft/web/constants.js +0 -2
  286. package/dist/host-routing/dispatch.js +11 -20
  287. package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
  288. package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
  289. package/dist/inbound-mail-foundation/connect-routes.js +4 -3
  290. package/dist/inbound-mail-foundation/constants.d.ts +22 -24
  291. package/dist/inbound-mail-foundation/constants.js +30 -33
  292. package/dist/inbound-mail-foundation/entities.d.ts +12 -12
  293. package/dist/inbound-mail-foundation/entities.js +47 -48
  294. package/dist/inbound-mail-foundation/events.d.ts +4 -3
  295. package/dist/inbound-mail-foundation/events.js +50 -47
  296. package/dist/inbound-mail-foundation/feature.js +39 -39
  297. package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
  298. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
  299. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
  300. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
  301. package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
  302. package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
  303. package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
  304. package/dist/inbound-mail-foundation/handlers/update-account.write.d.ts +2 -2
  305. package/dist/inbound-mail-foundation/handlers/update-account.write.js +22 -14
  306. package/dist/inbound-mail-foundation/i18n.js +0 -1
  307. package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
  308. package/dist/inbound-mail-foundation/oauth-state.js +11 -10
  309. package/dist/inbound-mail-foundation/projection.d.ts +4 -4
  310. package/dist/inbound-mail-foundation/projection.js +31 -29
  311. package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
  312. package/dist/inbound-mail-foundation/provider-factory.js +9 -9
  313. package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
  314. package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
  315. package/dist/inbound-mail-foundation/screens.js +0 -3
  316. package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
  317. package/dist/inbound-mail-foundation/types.d.ts +49 -49
  318. package/dist/inbound-mail-foundation/types.js +21 -21
  319. package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
  320. package/dist/inbound-mail-foundation/watch-supervisor.js +85 -67
  321. package/dist/inbound-provider-imap/credential-document.js +13 -13
  322. package/dist/inbound-provider-imap/feature.d.ts +2 -2
  323. package/dist/inbound-provider-imap/feature.js +42 -40
  324. package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
  325. package/dist/inbound-provider-imap/imap-client.js +20 -19
  326. package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
  327. package/dist/inbound-provider-inmemory/feature.js +19 -19
  328. package/dist/jobs/db/queries/retention.js +2 -2
  329. package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
  330. package/dist/jobs/events.js +1 -1
  331. package/dist/jobs/feature.d.ts +1 -0
  332. package/dist/jobs/feature.js +13 -10
  333. package/dist/jobs/handlers/detail.query.js +4 -4
  334. package/dist/jobs/handlers/list.query.js +1 -1
  335. package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
  336. package/dist/jobs/handlers/reindex-entity.job.js +1 -1
  337. package/dist/jobs/handlers/retry.write.js +1 -1
  338. package/dist/jobs/handlers/tenant-failures.query.d.ts +1 -1
  339. package/dist/jobs/handlers/tenant-failures.query.js +45 -41
  340. package/dist/jobs/handlers/tenant-runs.query.d.ts +1 -1
  341. package/dist/jobs/handlers/tenant-runs.query.js +54 -50
  342. package/dist/jobs/job-instant.js +1 -1
  343. package/dist/jobs/job-run-logger.js +15 -15
  344. package/dist/jobs/job-run-table.js +3 -3
  345. package/dist/jobs/screens.js +1 -1
  346. package/dist/jobs/tenant-job-failure-table.js +1 -1
  347. package/dist/jobs/tenant-job-run-table.js +1 -1
  348. package/dist/ledger/entity.js +5 -5
  349. package/dist/ledger/feature.js +3 -3
  350. package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
  351. package/dist/ledger/recurring.js +12 -12
  352. package/dist/ledger/schemas.js +1 -1
  353. package/dist/ledger/web/constants.js +2 -2
  354. package/dist/ledger/web/index.js +7 -7
  355. package/dist/legal-pages/feature.d.ts +4 -4
  356. package/dist/legal-pages/feature.js +25 -26
  357. package/dist/legal-pages/markdown.js +3 -3
  358. package/dist/legal-pages/web/client-plugin.js +23 -24
  359. package/dist/legal-pages/web/index.js +0 -1
  360. package/dist/mail-foundation/feature.d.ts +5 -5
  361. package/dist/mail-foundation/feature.js +27 -25
  362. package/dist/mail-transport-inmemory/feature.d.ts +4 -4
  363. package/dist/mail-transport-inmemory/feature.js +27 -28
  364. package/dist/mail-transport-smtp/feature.js +20 -20
  365. package/dist/managed-pages/branding.js +6 -6
  366. package/dist/managed-pages/feature.d.ts +26 -26
  367. package/dist/managed-pages/feature.js +34 -34
  368. package/dist/managed-pages/handlers/by-slug.query.js +5 -6
  369. package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
  370. package/dist/managed-pages/handlers/set.write.js +5 -7
  371. package/dist/managed-pages/screens/page-screens.js +11 -11
  372. package/dist/managed-pages/seeding.js +8 -8
  373. package/dist/managed-pages/table.js +13 -12
  374. package/dist/managed-pages/web/client-plugin.d.ts +1 -1
  375. package/dist/managed-pages/web/client-plugin.js +5 -5
  376. package/dist/managed-pages/web/i18n.js +1 -1
  377. package/dist/notes-history/entity.js +4 -4
  378. package/dist/notes-history/feature.d.ts +2 -2
  379. package/dist/notes-history-user-data/hooks.js +1 -1
  380. package/dist/page-render/layout.js +9 -9
  381. package/dist/page-render/markdown.js +11 -11
  382. package/dist/page-render/security-headers.js +7 -6
  383. package/dist/personal-access-tokens/feature.d.ts +1 -1
  384. package/dist/personal-access-tokens/feature.js +9 -5
  385. package/dist/personal-access-tokens/roles.js +2 -2
  386. package/dist/readiness/handlers/status.query.js +3 -3
  387. package/dist/renderer-foundation/api.js +12 -13
  388. package/dist/renderer-foundation/constants.js +2 -2
  389. package/dist/renderer-foundation/feature.js +7 -7
  390. package/dist/renderer-pdf/render-table-pdf.d.ts +1 -1
  391. package/dist/renderer-pdf/render-table-pdf.js +22 -10
  392. package/dist/secrets/feature.js +9 -9
  393. package/dist/secrets/web/constants.js +2 -2
  394. package/dist/seo/feature.js +3 -3
  395. package/dist/sessions/constants.d.ts +1 -1
  396. package/dist/sessions/constants.js +1 -1
  397. package/dist/sessions/feature.d.ts +2 -2
  398. package/dist/sessions/feature.js +12 -8
  399. package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
  400. package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
  401. package/dist/sessions/handlers/revoke.write.js +1 -1
  402. package/dist/sessions/schema/user-session.js +4 -4
  403. package/dist/sessions/screens.js +2 -2
  404. package/dist/sessions/session-callbacks.js +2 -2
  405. package/dist/sessions/session-revoked-event.js +2 -2
  406. package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
  407. package/dist/shared/decrypt-stored-pii.d.ts +1 -0
  408. package/dist/shared/decrypt-stored-pii.js +7 -2
  409. package/dist/shared/encrypt-for-direct-write.js +1 -1
  410. package/dist/shared/index.d.ts +1 -1
  411. package/dist/shared/index.js +1 -1
  412. package/dist/shared/mail-template-body.d.ts +6 -2
  413. package/dist/shared/mail-template-body.js +7 -4
  414. package/dist/shared/map-with-concurrency.js +5 -4
  415. package/dist/shared/parent-visibility.js +2 -2
  416. package/dist/shared/password-hashing.js +1 -1
  417. package/dist/shared/signup-handover.js +1 -2
  418. package/dist/shared/single-use-token-store.js +1 -1
  419. package/dist/step-dispatcher/feature.js +1 -0
  420. package/dist/subscription-dodo/client.d.ts +17 -0
  421. package/dist/subscription-dodo/client.js +31 -0
  422. package/dist/subscription-dodo/constants.d.ts +12 -0
  423. package/dist/subscription-dodo/constants.js +19 -0
  424. package/dist/subscription-dodo/feature.d.ts +37 -0
  425. package/dist/subscription-dodo/feature.js +144 -0
  426. package/dist/subscription-dodo/index.d.ts +2 -0
  427. package/dist/subscription-dodo/index.js +4 -0
  428. package/dist/subscription-dodo/plugin-methods.d.ts +23 -0
  429. package/dist/subscription-dodo/plugin-methods.js +260 -0
  430. package/dist/subscription-dodo/runtime.d.ts +27 -0
  431. package/dist/subscription-dodo/runtime.js +89 -0
  432. package/dist/subscription-dodo/verify-webhook.d.ts +37 -0
  433. package/dist/subscription-dodo/verify-webhook.js +189 -0
  434. package/dist/subscription-mollie/constants.js +15 -17
  435. package/dist/subscription-mollie/feature.d.ts +17 -18
  436. package/dist/subscription-mollie/feature.js +24 -24
  437. package/dist/subscription-mollie/index.js +3 -3
  438. package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
  439. package/dist/subscription-mollie/plugin-methods.js +15 -14
  440. package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
  441. package/dist/subscription-mollie/verify-webhook.js +27 -27
  442. package/dist/subscription-stripe/constants.js +4 -6
  443. package/dist/subscription-stripe/feature.d.ts +14 -14
  444. package/dist/subscription-stripe/feature.js +36 -34
  445. package/dist/subscription-stripe/index.js +6 -6
  446. package/dist/subscription-stripe/plugin-methods.js +18 -18
  447. package/dist/subscription-stripe/runtime.d.ts +1 -1
  448. package/dist/subscription-stripe/runtime.js +8 -7
  449. package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
  450. package/dist/subscription-stripe/verify-webhook.js +59 -61
  451. package/dist/tags/feature.d.ts +3 -3
  452. package/dist/tags/screens.js +1 -1
  453. package/dist/template-resolver/api.d.ts +3 -2
  454. package/dist/template-resolver/api.js +34 -12
  455. package/dist/template-resolver/compile-document-body.js +1 -0
  456. package/dist/template-resolver/feature.js +2 -2
  457. package/dist/template-resolver/handlers/bundle-import.js +3 -3
  458. package/dist/template-resolver/handlers/copy-locale.write.d.ts +5 -1
  459. package/dist/template-resolver/handlers/copy-locale.write.js +22 -7
  460. package/dist/template-resolver/handlers/diff-to-system.query.js +3 -2
  461. package/dist/template-resolver/handlers/document-base.js +3 -2
  462. package/dist/template-resolver/handlers/find-by-id.query.js +8 -7
  463. package/dist/template-resolver/handlers/list.query.js +6 -7
  464. package/dist/template-resolver/handlers/overview.query.d.ts +3 -0
  465. package/dist/template-resolver/handlers/overview.query.js +6 -3
  466. package/dist/template-resolver/handlers/shared.js +2 -2
  467. package/dist/template-resolver/handlers/template-write.js +3 -3
  468. package/dist/template-resolver/handlers/tenant-override-counts.query.js +1 -3
  469. package/dist/template-resolver/handlers/tenant-override-selection.d.ts +2 -1
  470. package/dist/template-resolver/handlers/tenant-overrides.query.js +28 -5
  471. package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
  472. package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
  473. package/dist/template-resolver/handlers/usage.query.d.ts +2 -1
  474. package/dist/template-resolver/handlers/usage.query.js +26 -16
  475. package/dist/template-resolver/handlers/validate.query.js +7 -2
  476. package/dist/template-resolver/seeding.js +30 -14
  477. package/dist/template-resolver/store-template-resource.d.ts +1 -0
  478. package/dist/template-resolver/store-template-resource.js +19 -4
  479. package/dist/template-resolver/table.js +10 -11
  480. package/dist/template-resolver/template-delivery-policy.d.ts +0 -5
  481. package/dist/template-resolver/template-delivery-policy.js +0 -6
  482. package/dist/template-resolver/template-meta.js +7 -4
  483. package/dist/template-resolver/template-preview.js +4 -3
  484. package/dist/template-resolver/web/client-plugin.js +2 -2
  485. package/dist/template-resolver/web/constants.d.ts +2 -2
  486. package/dist/template-resolver/web/constants.js +3 -3
  487. package/dist/template-resolver/web/index.d.ts +1 -0
  488. package/dist/template-resolver/web/index.js +1 -0
  489. package/dist/template-resolver/web/mail-layout-constants.d.ts +5 -0
  490. package/dist/template-resolver/web/mail-layout-constants.js +7 -0
  491. package/dist/tenant/feature.js +7 -7
  492. package/dist/tenant/handlers/member-directory.query.d.ts +1 -0
  493. package/dist/tenant/handlers/member-directory.query.js +11 -4
  494. package/dist/tenant/handlers/members.query.js +1 -1
  495. package/dist/tenant/handlers/team-list.query.js +1 -1
  496. package/dist/tenant/handlers/tenant-directory.query.d.ts +1 -0
  497. package/dist/tenant/handlers/tenant-directory.query.js +9 -5
  498. package/dist/tenant/invitation-table.js +37 -40
  499. package/dist/tenant/membership-table.js +3 -3
  500. package/dist/tenant/schema/tenant.js +7 -9
  501. package/dist/tenant/screens.js +1 -1
  502. package/dist/tenant/seeding.d.ts +6 -5
  503. package/dist/tenant/seeding.js +12 -12
  504. package/dist/tenant/testing.js +5 -6
  505. package/dist/tenant/web/constants.js +2 -2
  506. package/dist/tenant-handover/events.js +5 -7
  507. package/dist/tenant-handover/feature.js +1 -1
  508. package/dist/tenant-handover/grant.js +1 -1
  509. package/dist/tenant-handover/handlers/claim.write.js +1 -1
  510. package/dist/tenant-handover/move-entity-graph.js +8 -9
  511. package/dist/tenant-handover/signup-handover-provider.js +1 -2
  512. package/dist/tenant-handover/transfer-graph.js +4 -5
  513. package/dist/tenant-lifecycle/boot-checks.js +1 -1
  514. package/dist/tenant-lifecycle/constants.d.ts +1 -0
  515. package/dist/tenant-lifecycle/constants.js +4 -0
  516. package/dist/tenant-lifecycle/feature.js +1 -1
  517. package/dist/tenant-lifecycle/run-tenant-destroy.js +2 -2
  518. package/dist/tenant-settings/constants.js +1 -1
  519. package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
  520. package/dist/tenant-settings/tenant-defaults.js +9 -2
  521. package/dist/tier-engine/aggregate-id.d.ts +11 -11
  522. package/dist/tier-engine/aggregate-id.js +15 -16
  523. package/dist/tier-engine/compose-app.d.ts +14 -14
  524. package/dist/tier-engine/compose-app.js +1 -1
  525. package/dist/tier-engine/entity.js +18 -19
  526. package/dist/tier-engine/feature.d.ts +19 -17
  527. package/dist/tier-engine/feature.js +68 -69
  528. package/dist/tier-engine/handlers/active-tier.query.js +6 -7
  529. package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
  530. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +7 -8
  531. package/dist/tier-engine/handlers/set-tenant-tier.write.js +7 -4
  532. package/dist/tier-engine/tier-resolver.js +2 -2
  533. package/dist/tier-engine/trial.js +8 -8
  534. package/dist/tier-engine/web/constants.js +2 -2
  535. package/dist/tier-engine/web/index.js +4 -4
  536. package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
  537. package/dist/user/handlers/create.write.js +4 -4
  538. package/dist/user/schema/user.d.ts +11 -11
  539. package/dist/user/schema/user.js +45 -44
  540. package/dist/user/seeding.d.ts +15 -15
  541. package/dist/user/seeding.js +28 -28
  542. package/dist/user/testing.js +3 -3
  543. package/dist/user-data-rights/audit-download.d.ts +8 -8
  544. package/dist/user-data-rights/audit-download.js +19 -20
  545. package/dist/user-data-rights/boot-checks.js +1 -1
  546. package/dist/user-data-rights/deletion-token.js +1 -1
  547. package/dist/user-data-rights/feature.d.ts +49 -50
  548. package/dist/user-data-rights/feature.js +54 -53
  549. package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
  550. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
  551. package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
  552. package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
  553. package/dist/user-data-rights/handlers/export-status.query.js +8 -9
  554. package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
  555. package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
  556. package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
  557. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
  558. package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
  559. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
  560. package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
  561. package/dist/user-data-rights/handlers/request-export.write.js +42 -41
  562. package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
  563. package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
  564. package/dist/user-data-rights/index.js +8 -10
  565. package/dist/user-data-rights/lib/default-mailers.js +3 -3
  566. package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
  567. package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
  568. package/dist/user-data-rights/run-export-jobs.js +130 -237
  569. package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
  570. package/dist/user-data-rights/run-forget-cleanup.js +65 -83
  571. package/dist/user-data-rights/run-user-export.d.ts +34 -33
  572. package/dist/user-data-rights/run-user-export.js +55 -57
  573. package/dist/user-data-rights/schema/download-attempt.js +11 -11
  574. package/dist/user-data-rights/schema/download-token.js +37 -41
  575. package/dist/user-data-rights/schema/export-job.d.ts +4 -4
  576. package/dist/user-data-rights/schema/export-job.js +65 -67
  577. package/dist/user-data-rights/token-helpers.d.ts +8 -9
  578. package/dist/user-data-rights/token-helpers.js +21 -25
  579. package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
  580. package/dist/user-data-rights/web/client-plugin.js +1 -1
  581. package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
  582. package/dist/user-data-rights/web/constants.js +1 -1
  583. package/dist/user-data-rights/web/index.js +5 -5
  584. package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
  585. package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
  586. package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
  587. package/dist/user-data-rights/zip-path.d.ts +15 -15
  588. package/dist/user-data-rights/zip-path.js +41 -40
  589. package/dist/user-data-rights-defaults/feature.js +15 -15
  590. package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
  591. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
  592. package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
  593. package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
  594. package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
  595. package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
  596. package/dist/user-profile/handlers/change-email.write.js +13 -13
  597. package/dist/user-profile/index.js +3 -3
  598. package/dist/user-profile/web/client-plugin.js +1 -1
  599. package/dist/user-profile/web/constants.js +1 -1
  600. package/dist/user-profile/web/profile-screen.js +1 -1
  601. package/dist/waitlist/handlers/export-purge.write.js +2 -1
  602. package/dist/waitlist/handlers/submit.write.js +5 -5
  603. package/dist/waitlist/import.d.ts +1 -0
  604. package/dist/waitlist/import.js +4 -0
  605. package/dist/waitlist/legacy-migrate.js +17 -6
  606. package/dist/waitlist/link-on-signup.js +18 -6
  607. package/dist/waitlist/options.d.ts +3 -0
  608. package/dist/workflow-runner/aggregate-id.d.ts +1 -1
  609. package/dist/workflow-runner/aggregate-id.js +1 -1
  610. package/dist/workflow-runner/event-subscriber.js +4 -5
  611. package/dist/workflow-runner/event-trigger.js +4 -17
  612. package/dist/workflow-runner/feature.js +2 -2
  613. package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
  614. package/dist/workflow-runner/pending-projection.js +6 -7
  615. package/dist/workflow-runner/runner.js +6 -6
  616. package/dist/workflow-runner/tables.js +6 -6
  617. package/dist/workflow-runner/workflow-registry.js +1 -1
  618. package/package.json +20 -10
  619. package/src/agent-tools/changes.json +6 -0
  620. package/src/audit/changes.json +12 -0
  621. package/src/auth-mfa/changes.json +6 -0
  622. package/src/billing-foundation/changes.json +55 -0
  623. package/src/cap-counter/changes.json +18 -0
  624. package/src/channel-email/changes.json +6 -0
  625. package/src/config/changes.json +12 -0
  626. package/src/crypto-shredding/changes.json +6 -0
  627. package/src/delivery/changes.json +30 -0
  628. package/src/form-draft/changes.json +6 -0
  629. package/src/host-routing/changes.json +6 -0
  630. package/src/inbound-mail-foundation/changes.json +18 -0
  631. package/src/jobs/changes.json +13 -0
  632. package/src/mail-foundation/changes.json +6 -0
  633. package/src/renderer-pdf/changes.json +6 -0
  634. package/src/step-dispatcher/changes.json +6 -0
  635. package/src/subscription-dodo/changes.json +14 -0
  636. package/src/subscription-stripe/changes.json +12 -0
  637. package/src/template-resolver/changes.json +48 -0
  638. package/src/tenant/changes.json +6 -0
  639. package/src/tenant-lifecycle/changes.json +6 -0
  640. package/src/tier-engine/changes.json +6 -0
  641. package/src/waitlist/changes.json +18 -0
  642. package/dist/billing-foundation/consumer-protection/stored-user-email.d.ts +0 -1
  643. package/dist/billing-foundation/consumer-protection/stored-user-email.js +0 -8
@@ -1,19 +1,19 @@
1
- // Stripe-Plugin-Methoden für die POST-tenant-resolution-Phase:
1
+ // Stripe plugin methods for the POST-tenant-resolution phase:
2
2
  // createCheckoutSession, createPortalSession, cancelSubscription,
3
- // retrieveSubscription, retrievePrices, planSwitchSession.
3
+ // retrieveSubscription, retrievePrices, and planSwitchSession.
4
4
  //
5
- // Werden vom Plugin-build (feature.ts) als methods auf dem
6
- // SubscriptionProviderPlugin registriert. Anders als
7
- // verifyAndParseWebhook (= pre-tenant) bekommen diese den vollen
8
- // HandlerContext — sie lösen den Stripe-Client zur CALL-Zeit aus dem
9
- // runtime auf (api-key aus system-secrets, audited), statt aus einem
10
- // mount-time-Closure. Key-Rotation wirkt damit ohne Redeploy.
5
+ // The plugin build (`feature.ts`) registers these as methods on
6
+ // `SubscriptionProviderPlugin`. Unlike verifyAndParseWebhook (= pre-tenant),
7
+ // they receive the full HandlerContext and resolve the Stripe client from
8
+ // the runtime at call time (using the audited api-key from system-secrets),
9
+ // rather than from a mount-time closure. Key rotation therefore works
10
+ // without a redeploy.
11
11
  //
12
- // **Type-Ableitung:** die options-shapes der methods werden
13
- // **direkt vom Plugin-Contract** abgeleitet (`Parameters<NonNullable
14
- // <SubscriptionProviderPlugin["...method"]>>[1]`). Wenn Foundation den
15
- // Contract erweitert (z.B. neuer optionaler Field), bemerkt der
16
- // Stripe-Plugin das beim TS-Compile, nicht erst zur Laufzeit.
12
+ // **Type derivation:** method option shapes are derived **directly from the
13
+ // plugin contract** (`Parameters<NonNullable
14
+ // <SubscriptionProviderPlugin["...method"]>>[1]`). If Foundation extends the
15
+ // contract (for example, with a new optional field), the Stripe plugin detects
16
+ // it at TypeScript compile time rather than at runtime.
17
17
  import { createHash } from "node:crypto";
18
18
  import { KNOWN_RECURRING_INTERVALS, SubscriptionCancelTimings, } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
19
19
  import { ConflictError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
@@ -79,11 +79,11 @@ function isUnknownCustomerStripeError(error) {
79
79
  }
80
80
  export function createStripeCheckoutSession(runtime, { paymentInvoiceCreation = true } = {}) {
81
81
  return async (ctx, options) => {
82
- // #104-Invariante: ohne billing-live darf keine Stripe-Session
83
- // entstehen (sk_test_-Keys in prod erzeugen sonst einen Test-Mode-
84
- // Checkout). Throw VOR jedem Stripe-Call. Früher hielt diese Schranke
85
- // das ungemountete Plugin; jetzt mountet stripe immer, also gatet der
86
- // billing-live-config-key write-side.
82
+ // Invariant: without billing-live, no Stripe session may be created
83
+ // (sk_test_-keys in production would otherwise create a test-mode checkout).
84
+ // Throw before every Stripe call. The guard used to be provided by the
85
+ // unmounted plugin; Stripe is now always mounted, so the
86
+ // billing-live-config-key gates the write side.
87
87
  await runtime.assertBillingLive(ctx);
88
88
  const stripe = await runtime.clientForCtx(ctx);
89
89
  const mode = options.mode ?? "subscription";
@@ -19,7 +19,7 @@ export type StripeRuntimeDeps = {
19
19
  export type StripeCtxRuntime = {
20
20
  readonly clientForCtx: (ctx: HandlerContext) => Promise<Stripe>;
21
21
  /** Throws FeatureDisabledError unless `billing-live` config is true. The
22
- * #104 invariant: no Stripe session may be created while billing is not
22
+ * invariant: no Stripe session may be created while billing is not
23
23
  * live (sk_test_ keys in prod must not produce a live checkout).
24
24
  * `handlerName` names the write-handler in the thrown error — defaults to
25
25
  * "create-checkout-session" for existing callers, but plan-switch/portal
@@ -27,7 +27,7 @@
27
27
  import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
28
28
  import { SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
29
29
  import { FeatureDisabledError, UnconfiguredError } from "@cosmicdrift/kumiko-framework/errors";
30
- import { parseJsonOrThrow } from "@cosmicdrift/kumiko-framework/utils";
30
+ import { parseJsonSafe } from "@cosmicdrift/kumiko-framework/utils";
31
31
  import Stripe from "stripe";
32
32
  import { SUBSCRIPTION_STRIPE_FEATURE } from "./constants.js";
33
33
  const API_KEY_HINT = "Set the Stripe API key via config:write:set on `subscription-stripe:config:api-key` (or seed it from STRIPE_API_KEY during the env bridge).";
@@ -41,7 +41,7 @@ export function createStripeClientCache() {
41
41
  if (cached)
42
42
  return cached;
43
43
  // No apiVersion pin — a string literal breaks consumers' typecheck on newer
44
- // stripe SDKs (#256); the SDK's own default keeps wire-version and types aligned.
44
+ // stripe SDKs; the SDK's own default keeps wire-version and types aligned.
45
45
  const client = new Stripe(apiKey);
46
46
  cache.set(apiKey, client);
47
47
  return client;
@@ -52,14 +52,15 @@ export function createStripeClientCache() {
52
52
  // (the un-audited webhook path + the audited ctx read here) therefore returns
53
53
  // the JSON-quoted string and must parse it back. The factory fallback is a
54
54
  // plain env string and stays raw — so parsing is applied only to the store
55
- // read, never to the fallback.
55
+ // read, never to the fallback. The error must not carry the input: the JSON
56
+ // parser's own message would repeat the credential into logs and the 401 body.
56
57
  function parseStoredSecret(raw) {
57
58
  if (raw === undefined || raw.length === 0)
58
59
  return undefined;
59
- // parseJsonOrThrow is the sanctioned safe-parse (same helper the config
60
- // resolver's deserializeValue uses for this very value) — mirrors how the
61
- // store round-trips a backing:"secrets" text value.
62
- const parsed = parseJsonOrThrow(raw, "subscription-stripe credential (backing:secrets)");
60
+ const parsed = parseJsonSafe(raw, undefined);
61
+ if (parsed === undefined) {
62
+ throw new Error("subscription-stripe credential (backing:secrets) is not valid JSON");
63
+ }
63
64
  return typeof parsed === "string" && parsed.length > 0 ? parsed : undefined;
64
65
  }
65
66
  export function createStripeRuntimes(deps) {
@@ -5,17 +5,17 @@ import Stripe from "stripe";
5
5
  import type { StripeWebhookRuntime } from "./runtime.ts";
6
6
  export declare function isResourceMissingStripeError(error: unknown): error is Stripe.errors.StripeInvalidRequestError;
7
7
  export type StripeWebhookOptions = {
8
- /** Price-to-tier-Map. Plugin liest die price-id aus dem event und
9
- * mapped auf tier-name. Fehlt die price-id im Mapping → null. App-
10
- * spezifisch, bleibt eine factory-option (kein Secret). */
8
+ /** Price-to-tier map. The plugin reads the price ID from the event and
9
+ * maps it to a tier name. Returns null when the price ID is not mapped.
10
+ * App-specific and remains a factory option, not a secret. */
11
11
  readonly priceToTier: Readonly<Record<string, string>>;
12
12
  };
13
13
  /**
14
- * Stripe-webhook-handler. Implementiert den Plugin-Contract
15
- * `verifyAndParseWebhook`. **Pre-tenant-resolution** — kein
16
- * HandlerContext; statt eines mount-time-Clients löst der `runtime` den
17
- * Stripe-Client + das webhook-secret zur Call-Zeit aus dem optionalen
18
- * system-SecretsContext (3. Arg) auf.
14
+ * Stripe webhook handler implementing the plugin contract
15
+ * `verifyAndParseWebhook`. **Pre-tenant resolution** — there is no
16
+ * HandlerContext; instead of using a mount-time client, `runtime` resolves
17
+ * the Stripe client and webhook secret at call time from the optional
18
+ * system SecretsContext (third argument).
19
19
  */
20
20
  export declare function verifyAndParseStripeWebhook(runtime: StripeWebhookRuntime, options: StripeWebhookOptions): (rawBody: string, headers: Record<string, string>, systemSecrets?: SecretsContext) => Promise<SubscriptionEvent | PaymentEvent | null>;
21
21
  export type MappedStripeSubscriptionState = {
@@ -37,7 +37,7 @@ export declare function mapStripeSubscriptionState(sub: Pick<Stripe.Subscription
37
37
  export declare function stripeCancelAtIso(sub: Pick<Stripe.Subscription, "cancel_at" | "cancel_at_period_end">, currentPeriodEndIso: string): string | null;
38
38
  /** Stripe-event-type → normalisiert. null = ignore. */
39
39
  export declare function mapStripeEventType(stripeType: string): SubscriptionEventType | null;
40
- /** Stripe-status → normalisiert. Defensive: unbekannte Status →
41
- * incomplete (Plugin sollte das nicht erreichen, aber wir wollen
42
- * kein ungültiger status-string in der DB). */
40
+ /** Maps Stripe statuses to normalized statuses. Unknown statuses are
41
+ * mapped defensively to incomplete; the plugin should not receive them, but
42
+ * an invalid status string must not be stored in the database. */
43
43
  export declare function mapStripeStatus(stripeStatus: Stripe.Subscription.Status): SubscriptionStatus;
@@ -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
  import { BillingEventKinds, parseProviderConsentId, SubscriptionEventTypes, SubscriptionStatuses, } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
35
34
  import { ExtraRouteRejection } from "@cosmicdrift/kumiko-framework/api";
@@ -47,11 +46,11 @@ function transientProviderRejection(error) {
47
46
  return new ExtraRouteRejection(503, { error: { code: "subscription_provider_transient" } }, `stripe retrieve failed: ${error instanceof Error ? error.message : String(error)}`);
48
47
  }
49
48
  /**
50
- * Stripe-webhook-handler. Implementiert den Plugin-Contract
51
- * `verifyAndParseWebhook`. **Pre-tenant-resolution** — kein
52
- * HandlerContext; statt eines mount-time-Clients löst der `runtime` den
53
- * Stripe-Client + das webhook-secret zur Call-Zeit aus dem optionalen
54
- * system-SecretsContext (3. Arg) auf.
49
+ * Stripe webhook handler implementing the plugin contract
50
+ * `verifyAndParseWebhook`. **Pre-tenant resolution** — there is no
51
+ * HandlerContext; instead of using a mount-time client, `runtime` resolves
52
+ * the Stripe client and webhook secret at call time from the optional
53
+ * system SecretsContext (third argument).
55
54
  */
56
55
  export function verifyAndParseStripeWebhook(runtime, options) {
57
56
  return async (rawBody, headers, systemSecrets) => {
@@ -59,15 +58,15 @@ export function verifyAndParseStripeWebhook(runtime, options) {
59
58
  if (!sigHeader) {
60
59
  throw new Error("subscription-stripe: stripe-signature header missing");
61
60
  }
62
- // 0. Runtime-resolve: api-key (für client + lazy-fetch) + webhook-
63
- // secret (für sig-verify) aus system-secrets, Fallback factory-
64
- // options. Wirft wenn beide unkonfiguriert.
61
+ // 0. Resolve at runtime: obtain the API key (for the client and lazy fetch)
62
+ // and webhook secret (for signature verification) from system secrets,
63
+ // falling back to the factory options. Throws if neither is configured.
65
64
  const { stripe, webhookSecret } = await runtime.resolve(systemSecrets);
66
- // 1. Sig-verify. constructEvent throws bei mismatch (= invalid sig)
67
- // oder timestamp-tolerance-violation (default 5min). Foundation
68
- // mapped throw → HTTP 401. Applies to BOTH branches below — the
69
- // payment-branch only branches off AFTER this check; there's no
70
- // path that bypasses signature verification.
65
+ // 1. Verify the signature. constructEvent throws on a mismatch (invalid
66
+ // signature) or timestamp-tolerance violation (default: 5 minutes).
67
+ // The foundation maps the thrown error to HTTP 401. This applies to
68
+ // BOTH branches below: the payment branch is selected only AFTER this
69
+ // check, so no path bypasses signature verification.
71
70
  let event;
72
71
  try {
73
72
  event = await stripe.webhooks.constructEventAsync(rawBody, sigHeader, webhookSecret);
@@ -84,28 +83,27 @@ export function verifyAndParseStripeWebhook(runtime, options) {
84
83
  if (isCheckoutSessionEventType(event.type)) {
85
84
  return await parsePaymentEvent(event, stripe);
86
85
  }
87
- // 2. Event-type-Filter — wir kennen nur 5.
86
+ // 2. Event-type filter — only 5 event types are supported.
88
87
  const normalizedType = mapStripeEventType(event.type);
89
88
  if (!normalizedType) {
90
89
  return null; // foundation returnt 200 ignored
91
90
  }
92
- // 3. Payload-extraction. Stripe liefert je nach event.type
93
- // verschiedene data.object-shapes. Wir extrahieren die
94
- // Subscription-Daten — entweder direkt (subscription-events)
95
- // oder via lazy-fetch (invoice-events).
91
+ // 3. Extract the payload. Stripe uses different data.object shapes
92
+ // depending on event.type. Extract subscription data either directly
93
+ // (subscription events) or through a lazy fetch (invoice events).
96
94
  const sub = await extractSubscriptionFromEvent(event, stripe);
97
95
  if (!sub) {
98
- // event-type war unter den 5 (oben gefiltert), aber payload-shape
99
- // matched nicht — Stripe-SDK-Schema-Drift, defensive null.
96
+ // The event type passed the 5-item filter, but its payload shape did not
97
+ // match — treat this as Stripe SDK schema drift and return null defensively.
100
98
  return null;
101
99
  }
102
- // 4. Tenant-resolution aus metadata. App-Builder setzt
103
- // `metadata.tenantId` beim createCheckoutSession-call.
100
+ // 4. Resolve the tenant from metadata. The app builder sets
101
+ // `metadata.tenantId` when calling createCheckoutSession.
104
102
  const tenantId = sub.metadata?.["tenantId"];
105
103
  if (!tenantId || tenantId.length === 0) {
106
- // Subscription ohne tenant-metadata → kann kein subscription
107
- // erstellen ohne tenant-resolution. Drop the event silent
108
- // (foundation 200 ignored). App-Owner-Bug, nicht foundation-Bug.
104
+ // A subscription without tenant metadata cannot be created without tenant
105
+ // resolution. Drop the event silently (the foundation responds with 200
106
+ // ignored). This is an app-owner error, not a foundation error.
109
107
  return null;
110
108
  }
111
109
  // 5+6. Price-to-tier-Mapping + status/period-end/cancel_at — shared with
@@ -151,7 +149,7 @@ export function mapStripeSubscriptionState(sub, priceToTier) {
151
149
  const periodEndUnixSec = sub.items.data[0]?.current_period_end ?? 0;
152
150
  // Stripe returns Unix-seconds; Temporal.Instant.fromEpochMilliseconds
153
151
  // expects ms. Multiply, then ISO. (No-Date-API-Guard forbids
154
- // `new Date()` — static import above, not the ambient global, see #1490.)
152
+ // `new Date()` — static import above, not the ambient global.)
155
153
  const currentPeriodEnd = Temporal.Instant.fromEpochMilliseconds(periodEndUnixSec * 1000).toString();
156
154
  const cancelAt = stripeCancelAtIso(sub, currentPeriodEnd);
157
155
  return { status, tier, currentPeriodEnd, cancelAt };
@@ -187,9 +185,9 @@ export function mapStripeEventType(stripeType) {
187
185
  return null;
188
186
  }
189
187
  }
190
- /** Stripe-status → normalisiert. Defensive: unbekannte Status →
191
- * incomplete (Plugin sollte das nicht erreichen, aber wir wollen
192
- * kein ungültiger status-string in der DB). */
188
+ /** Maps Stripe statuses to normalized statuses. Unknown statuses are
189
+ * mapped defensively to incomplete; the plugin should not receive them, but
190
+ * an invalid status string must not be stored in the database. */
193
191
  export function mapStripeStatus(stripeStatus) {
194
192
  switch (stripeStatus) {
195
193
  case "active":
@@ -215,9 +213,9 @@ export function mapStripeStatus(stripeStatus) {
215
213
  return SubscriptionStatuses.incomplete;
216
214
  }
217
215
  }
218
- /** Holt die Subscription aus dem Event. Subscription-events haben sie
219
- * direkt im data.object; invoice-events haben nur die subscription-id
220
- * und brauchen einen lazy-fetch via stripe.subscriptions.retrieve. */
216
+ /** Gets the subscription from the event. Subscription events include it
217
+ * directly in data.object; invoice events include only the subscription ID
218
+ * and require a lazy fetch via stripe.subscriptions.retrieve. */
221
219
  // @wrapper-known semantic-alias
222
220
  async function extractSubscriptionFromEvent(event, stripe) {
223
221
  switch (event.type) {
@@ -227,16 +225,16 @@ async function extractSubscriptionFromEvent(event, stripe) {
227
225
  return event.data.object; // @cast-boundary engine-bridge
228
226
  case StripeEventTypes.invoicePaid:
229
227
  case StripeEventTypes.invoicePaymentFailed: {
230
- // Lazy-fetch der subscription. invoice.subscription ist eine
231
- // string-id (Stripe-Webhooks expanden nicht auto). Wir holen das
232
- // full subscription-Object damit der downstream-mapping
233
- // (status, tier via priceId, period-end) konsistent funktioniert.
228
+ // Lazy-fetch the subscription. invoice.subscription is a string ID because
229
+ // Stripe webhooks do not expand it automatically. Fetch the full
230
+ // subscription so downstream status, tier via priceId, and period-end
231
+ // mapping remain consistent.
234
232
  const invoice = event.data.object; // @cast-boundary engine-bridge
235
233
  const subRef = invoice // @cast-boundary engine-payload
236
234
  .subscription;
237
235
  if (!subRef) {
238
- // Invoice ohne subscription-reference (= one-shot-invoice, nicht
239
- // recurring). Nicht unsere Domain — ignorieren.
236
+ // An invoice without a subscription reference is a one-shot invoice, not a
237
+ // recurring invoice. It is outside this domain and should be ignored.
240
238
  return null;
241
239
  }
242
240
  const subId = typeof subRef === "string" ? subRef : subRef.id;
@@ -21,9 +21,9 @@ export type TagsFeatureOptions = {
21
21
  /** Row-level ownership on the tag-assignment rows themselves — orthogonal to
22
22
  * `access`, which only gates whether a caller may dispatch assign/remove/list
23
23
  * at all. `ownership.read` is no longer what keeps a caller from reading
24
- * assignments on host entities they can't see: that gate is default-on since
25
- * fw#2766 and derives from the entity's `parentRef`. Use `ownership.read` for
26
- * an ADDITIONAL row rule on the assignment row itself; it is AND-ed with the
24
+ * assignments on host entities they can't see: that gate is default-on and
25
+ * derives from the entity's `parentRef`. Use `ownership.read` for an
26
+ * ADDITIONAL row rule on the assignment row itself; it is AND-ed with the
27
27
  * host-visibility gate, never a replacement for it. Applies only to
28
28
  * `tag-assignment`; the `tag` catalog stays tenant-wide by design.
29
29
  *
@@ -1,6 +1,6 @@
1
1
  import { i18nKey, } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { DEFAULT_TAG_ACCESS, TAGS_EDIT_SCREEN_ID, TAGS_SCREEN_ID } from "./web/constants.js";
3
- // Declarative catalog screens (Phase-3 / #2312). Access matches create/update/
3
+ // Declarative catalog screens. Access matches create/update/
4
4
  // delete so createTagsFeature({ access|roles }) stays consistent. TagManager
5
5
  // remains for TagPicker/TagSection — only the standalone admin screen moved.
6
6
  export function createTagListScreen(access = DEFAULT_TAG_ACCESS) {
@@ -80,10 +80,11 @@ export type TemplateResolverApi = {
80
80
  readonly resolveLayout: (args: ResolveLayoutRequest) => Promise<TemplateResource>;
81
81
  };
82
82
  export declare function createTemplateResolverApi(db: DbRunner | TenantDb, registry: Registry): TemplateResolverApi;
83
- export declare function isRowDelivered(db: DbRunner | TenantDb, policy: TemplateDeliveryPolicy, row: TemplateResourceRow): Promise<boolean>;
83
+ type DeliveredRowKey = Pick<TemplateResourceRow, "tenantId" | "kind" | "slug">;
84
+ export declare function isRowDelivered(db: DbRunner | TenantDb, policy: TemplateDeliveryPolicy, row: DeliveredRowKey): Promise<boolean>;
84
85
  export declare function isRowDeliveredTo(db: DbRunner | TenantDb, policy: TemplateDeliveryPolicy, user: {
85
86
  readonly roles: readonly string[];
86
- }, row: TemplateResourceRow): Promise<boolean>;
87
+ }, row: DeliveredRowKey): Promise<boolean>;
87
88
  export declare function filterDeliveredTo(db: DbRunner | TenantDb, policy: TemplateDeliveryPolicy, user: {
88
89
  readonly roles: readonly string[];
89
90
  }, rows: readonly TemplateResourceRow[]): Promise<TemplateResourceRow[]>;
@@ -69,9 +69,31 @@ export async function isRowDelivered(db, policy, row) {
69
69
  export async function isRowDeliveredTo(db, policy, user, row) {
70
70
  return isSystemAdmin(user) || (await isRowDelivered(db, policy, row));
71
71
  }
72
+ // One system-slug lookup per kind instead of one query per row, because by-tenant is anonymous.
72
73
  export async function filterDeliveredTo(db, policy, user, rows) {
73
- const flags = await Promise.all(rows.map((row) => isRowDeliveredTo(db, policy, user, row)));
74
- return rows.filter((_, index) => flags[index]);
74
+ if (isSystemAdmin(user))
75
+ return [...rows];
76
+ const served = rows.filter((row) => isRowServed(policy, row));
77
+ const shadowable = served.filter((row) => row.tenantId !== SYSTEM_TENANT_ID && isServedByCollectionOnly(policy, row));
78
+ const slugsByKind = new Map();
79
+ for (const row of shadowable) {
80
+ const slugs = slugsByKind.get(row.kind) ?? new Set();
81
+ slugs.add(row.slug);
82
+ slugsByKind.set(row.kind, slugs);
83
+ }
84
+ const systemKeys = new Set();
85
+ for (const [kind, slugs] of slugsByKind) {
86
+ const systemRows = await selectMany(db, templateResourcesTable, {
87
+ tenantId: SYSTEM_TENANT_ID,
88
+ kind,
89
+ slug: [...slugs],
90
+ });
91
+ for (const systemRow of systemRows)
92
+ systemKeys.add(`${kind}|${systemRow.slug}`);
93
+ }
94
+ return served.filter((row) => row.tenantId === SYSTEM_TENANT_ID ||
95
+ !isServedByCollectionOnly(policy, row) ||
96
+ !systemKeys.has(`${row.kind}|${row.slug}`));
75
97
  }
76
98
  export async function systemTemplateExists(db, kind, slug) {
77
99
  const rows = await selectMany(db, templateResourcesTable, { tenantId: SYSTEM_TENANT_ID, slug, kind }, { limit: 1 });
@@ -89,19 +111,19 @@ function pickActiveLayoutRow(rows, locale) {
89
111
  async function fetchTemplate(db, tenantId, slug, kind, locale) {
90
112
  const rows = await selectMany(db, templateResourcesTable, { tenantId, slug, kind, locale }, { limit: 1 });
91
113
  // @cast-boundary db-row — db.select returnt unbenanntes unknown[],
92
- // Row-Shape ist via templateResourcesTable + buildBaseColumns garantiert.
114
+ // The row shape is guaranteed by templateResourcesTable + buildBaseColumns.
93
115
  return rows[0] ?? null;
94
116
  }
95
117
  function toPublic(row) {
96
118
  // @cast-boundary db-row — Drizzle-Schema typisiert kind/contentFormat/
97
- // scope/status als generic text. CHECK-Constraints in der DB schränken
98
- // sie auf die Union-Types ein; Cast assertet das Schema-Wissen.
119
+ // scope/status as generic text. Database CHECK constraints restrict
120
+ // them to the union types; the cast asserts that schema knowledge.
99
121
  const kind = row.kind;
100
- // @cast-boundary db-row — siehe kind.
122
+ // @cast-boundary db-row — see kind.
101
123
  const contentFormat = row.contentFormat;
102
- // @cast-boundary db-row — siehe kind.
124
+ // @cast-boundary db-row — see kind.
103
125
  const scope = row.scope;
104
- // @cast-boundary db-row — siehe kind.
126
+ // @cast-boundary db-row — see kind.
105
127
  const status = row.status;
106
128
  const linkedEntries = parseLinkedResourceEntries(row.linkedResources);
107
129
  return {
@@ -143,7 +165,7 @@ function parseJson(raw) {
143
165
  try {
144
166
  const parsed = JSON.parse(raw);
145
167
  // @cast-boundary engine-payload — JSON.parse returnt unknown, typeof-Guard
146
- // grenzt auf object ein; Record<string, unknown> ist der minimale common-shape.
168
+ // narrows it to object; Record<string, unknown> is the minimal common shape.
147
169
  return typeof parsed === "object" && parsed !== null ? parsed : {};
148
170
  }
149
171
  catch {
@@ -158,11 +180,11 @@ export class TemplateNotFoundError extends Error {
158
180
  this.name = "TemplateNotFoundError";
159
181
  }
160
182
  }
161
- // Single point of truth für "dieser Handler braucht template-resolver".
162
- // Pattern symmetrisch zu requireTextContent.
183
+ // Single source of truth for "this handler requires template-resolver".
184
+ // Pattern symmetric with requireTextContent.
163
185
  export function requireTemplateResolver(ctx, callerName) {
164
186
  // @cast-boundary engine-bridge — templateResolver kommt per extraContext
165
- // aus App-Bootstrap, Framework-Container kennt das Feld nicht von sich aus.
187
+ // from App-Bootstrap; the framework container does not know this field on its own.
166
188
  const api = ctx.templateResolver;
167
189
  if (!api) {
168
190
  throw new InternalError({
@@ -320,6 +320,7 @@ export function compileDocumentBodyToHandlebars(html, variables, options = {}) {
320
320
  for (const element of Array.from(root.querySelectorAll("div[data-images]"))) {
321
321
  rewriteImagesBlock(element, state, options);
322
322
  }
323
+ // Order matters: the conditional wraps first so the row's #each lands inside the #if (evaluated once per list).
323
324
  for (const block of Array.from(root.querySelectorAll(`[${DOCUMENT_CONDITION_ATTRIBUTE}]`))) {
324
325
  rewriteConditionalBlock(block, state);
325
326
  }
@@ -29,7 +29,7 @@ import { tenantOverridesQuery } from "./handlers/tenant-overrides.query.js";
29
29
  import { makeArchiveSystemWrite, makeArchiveWrite, makePublishSystemWrite, makePublishWrite, } from "./handlers/toggle-status.write.js";
30
30
  import { upsertSystemWrite } from "./handlers/upsert-system.write.js";
31
31
  import { makeUpsertTenantWrite } from "./handlers/upsert-tenant.write.js";
32
- import { usageQuery } from "./handlers/usage.query.js";
32
+ import { makeUsageQuery } from "./handlers/usage.query.js";
33
33
  import { validateQuery } from "./handlers/validate.query.js";
34
34
  import { TEMPLATE_RESOLVER_I18N } from "./i18n.js";
35
35
  import { templateResourceEntity } from "./table.js";
@@ -127,7 +127,7 @@ export function createTemplateResolverFeature(opts = {}) {
127
127
  list: r.queryHandler(listQuery),
128
128
  bySlug: r.queryHandler(bySlugQuery),
129
129
  byTenant: r.queryHandler(byTenantQuery),
130
- usage: r.queryHandler(usageQuery),
130
+ usage: r.queryHandler(makeUsageQuery(policy)),
131
131
  overview: r.queryHandler(makeOverviewQuery(policy)),
132
132
  layoutSource: r.queryHandler(layoutSourceQuery),
133
133
  tenantOverrides: r.queryHandler(tenantOverridesQuery),
@@ -1,7 +1,7 @@
1
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
- import { attachmentLimitFailure, attachmentNeedsMailTemplate, createPreparedBundleResourceEntry, prepareTemplateAttachmentBeforeTransaction, prepareTemplateResourceBeforeTransaction, readTemplateResourceMaxBytes, releaseAll, } from "../store-template-resource.js";
4
+ import { attachmentLimitFailure, attachmentNeedsMailTemplate, createPreparedBundleResourceEntry, prepareTemplateAttachmentBeforeTransaction, prepareTemplateResourceBeforeTransaction, readTemplateResourceMaxBytes, releaseAfterFailure, releaseAll, } from "../store-template-resource.js";
5
5
  import { templateResourcesTable } from "../table.js";
6
6
  import { attachTemplateResources } from "../template-resources.js";
7
7
  import { resolveTemplateVariables } from "../template-validation.js";
@@ -94,7 +94,7 @@ export async function prepareTemplateBundleBeforeTransaction(args) {
94
94
  })
95
95
  : await prepareTemplateResourceBeforeTransaction(common);
96
96
  if (!result.isSuccess) {
97
- await releaseAll(releases);
97
+ await releaseAfterFailure(args.ctx, releases);
98
98
  return result;
99
99
  }
100
100
  if (result.release)
@@ -103,7 +103,7 @@ export async function prepareTemplateBundleBeforeTransaction(args) {
103
103
  }
104
104
  }
105
105
  catch (cause) {
106
- await releaseAll(releases);
106
+ await releaseAfterFailure(args.ctx, releases);
107
107
  throw cause;
108
108
  }
109
109
  return { isSuccess: true, data: prepared, release: () => releaseAll(releases) };
@@ -17,4 +17,8 @@ export declare function makeCopyLocaleWrite(policy: TemplateEditPolicy): import(
17
17
  system: "system";
18
18
  tenant: "tenant";
19
19
  }>>;
20
- }, z.core.$strip>, import("./template-write.ts").WrittenTemplateRow, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, readonly import("../store-template-resource.ts").PreparedLinkedResourceCopy[]>;
20
+ }, z.core.$strip>, import("./template-write.ts").WrittenTemplateRow, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, {
21
+ sourceId: string | number;
22
+ sourceVersion: number;
23
+ copies: readonly import("../store-template-resource.ts").PreparedLinkedResourceCopy[];
24
+ }>;
@@ -1,6 +1,6 @@
1
1
  import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
- import { AccessDeniedError, NotFoundError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
3
+ import { AccessDeniedError, NotFoundError, ValidationError, VersionConflictError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
5
5
  import * as z from "zod";
6
6
  import { requireForTenant } from "../../shared/index.js";
@@ -111,14 +111,19 @@ export function makeCopyLocaleWrite(policy) {
111
111
  const request = await checkCopyRequest(ctx, policy, event);
112
112
  if (!request.isSuccess)
113
113
  return request;
114
- if (!request.data.sourceIsForeign)
115
- return { isSuccess: true, data: [] };
116
- return prepareLinkedResourceCopiesBeforeTransaction({
114
+ const { source, tenantId, sourceIsForeign, sourceResources } = request.data;
115
+ const sourceStamp = { sourceId: source.id, sourceVersion: source.version };
116
+ if (!sourceIsForeign)
117
+ return { isSuccess: true, data: { ...sourceStamp, copies: [] } };
118
+ const prepared = await prepareLinkedResourceCopiesBeforeTransaction({
117
119
  ctx,
118
120
  user: event.user,
119
- tenantId: request.data.tenantId,
120
- resources: request.data.sourceResources,
121
+ tenantId,
122
+ resources: sourceResources,
121
123
  });
124
+ if (!prepared.isSuccess)
125
+ return prepared;
126
+ return { ...prepared, data: { ...sourceStamp, copies: prepared.data } };
122
127
  },
123
128
  handler: async (event, ctx) => {
124
129
  const { slug, kind, toLocale } = event.payload;
@@ -126,6 +131,16 @@ export function makeCopyLocaleWrite(policy) {
126
131
  if (!request.isSuccess)
127
132
  return request;
128
133
  const { scope, tenantId, source, contentFormat, sourceResources, sourceIsForeign } = request.data;
134
+ // The uploads were prepared for the source as it was before the transaction; a source that
135
+ // changed since (own row created or deleted, edited) no longer matches them.
136
+ if (event.prepared.sourceId !== source.id ||
137
+ event.prepared.sourceVersion !== source.version) {
138
+ return writeFailure(new VersionConflictError({
139
+ entityId: source.id,
140
+ expectedVersion: event.prepared.sourceVersion,
141
+ currentVersion: source.version,
142
+ }));
143
+ }
129
144
  const variableSchema = storedRecord(source.variableSchema);
130
145
  const written = await writeTemplateRow({
131
146
  ctx,
@@ -149,7 +164,7 @@ export function makeCopyLocaleWrite(policy) {
149
164
  if (!written.isSuccess)
150
165
  return written;
151
166
  const resources = sourceIsForeign
152
- ? await createLinkedResourceCopies({ ctx, user: event.user, tenantId }, event.prepared)
167
+ ? await createLinkedResourceCopies({ ctx, user: event.user, tenantId }, event.prepared.copies)
153
168
  : { isSuccess: true, data: sourceResources };
154
169
  if (!resources.isSuccess)
155
170
  return resources;