@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,6 +1,6 @@
1
- // Bewusst OHNE i18n-Export: das Server-Barrel muss von Server-Samples
2
- // ohne jsx-tsconfig kompilierbar bleiben (i18n zieht kumiko-renderer →
3
- // .tsx). Translations kommen via ./web (userProfileClient).
1
+ // Deliberately no i18n export: the server barrel must remain compilable by server samples
2
+ // without a JSX tsconfig (i18n pulls in kumiko-renderer → .tsx). Translations are provided
3
+ // through ./web (userProfileClient).
4
4
 
5
5
  export { createUserProfileFeature, type UserProfileFeatureOptions } from "./feature.ts";
6
6
  export {
@@ -25,7 +25,7 @@ export type UserProfileClientFeature = {
25
25
  };
26
26
 
27
27
  // Supplies the ChangeEmail/ChangePassword extension components for the
28
- // declarative `profile` projectionDetail screen (fw#2312, ../feature.ts,
28
+ // declarative `profile` projectionDetail screen (../feature.ts,
29
29
  // registered there server-side) plus the default translations. Apps add it
30
30
  // via createKumikoApp({ clientFeatures: [userProfileClient()] }) and place
31
31
  // the screen (id "profile") via r.nav — the screen itself has no r.nav of
@@ -5,7 +5,7 @@ export const USER_PROFILE_FEATURE = "user-profile" as const;
5
5
 
6
6
  export const PROFILE_SCREEN_ID = "profile" as const;
7
7
 
8
- // EditExtensionSection `__component` markers (fw#2312) — change-password and
8
+ // EditExtensionSection `__component` markers — change-password and
9
9
  // change-email stay React components (re-auth flows a declarative action
10
10
  // can't express); deletion moved to declarative fields/actions on the screen
11
11
  // itself (feature.ts), same split as user-data-rights' privacy-center.
@@ -1,5 +1,5 @@
1
1
  // Change-password and change-email sections for the declarative `profile`
2
- // projectionDetail screen (fw#2312, ../feature.ts). Both keep re-auth flows
2
+ // projectionDetail screen (../feature.ts). Both keep re-auth flows
3
3
  // a declarative action can't express, so they stay React `EditExtensionSection`
4
4
  // components; account deletion moved to declarative fields/actions on the
5
5
  // screen itself — same split as user-data-rights' privacy-center
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "version": "0.388.0",
4
+ "type": "fix",
5
+ "title": "Link-on-signup failures, legacy re-run and purge audit order",
6
+ "detail": "link-on-signup throws when the entry update fails and the entry is still invited, so the consumer redelivers. The offlot legacy migration skips rows that are already imports. purge writes its audit event before shredding keys."
7
+ },
8
+ {
9
+ "version": "0.388.0",
10
+ "type": "fix",
11
+ "title": "Admin notice language comes from adminLocale",
12
+ "detail": "The admin notice mail used the request locale, which is the entrant's browser language. The new adminLocale option (en, de or es, default en) sets the operator's language."
13
+ },
14
+ {
15
+ "version": "0.388.0",
16
+ "type": "fix",
17
+ "title": "Legacy migration dry run counts the streams it would archive",
18
+ "detail": "The dry run now runs the read-only archive checks and reports archivedStreams without writing; the CLI prints \"would archive\" for it."
19
+ },
2
20
  {
3
21
  "version": "0.379.0",
4
22
  "type": "improvement",
@@ -74,8 +74,9 @@ export const purgeHandler = defineWriteHandler<"purge", typeof PurgeSchema, Wait
74
74
  }),
75
75
  );
76
76
  }
77
- await purgeWaitlistRows(db, rows, event.user.id);
77
+ // Audit first: purgeWaitlistRows shreds KMS keys, which a later failure cannot roll back.
78
78
  await appendAudit(ctx, WAITLIST_PURGED_EVENT_QN, rows.length);
79
+ await purgeWaitlistRows(db, rows, event.user.id);
79
80
  return { isSuccess: true, data: { purged: rows.length } };
80
81
  },
81
82
  });
@@ -73,9 +73,10 @@ async function hasOpenEntryForEmail(email: string, ctx: HandlerContext): Promise
73
73
  return found.rows.length > 0;
74
74
  }
75
75
 
76
- // The resolver usually reads config; run it outside the handler transaction's
77
- // critical section so a failing statement cannot abort the transaction that holds
78
- // the entry, and a slow resolver does not extend the per-email advisory lock.
76
+ // The resolver usually reads config. It runs before the per-email advisory lock so a
77
+ // slow resolver does not extend the lock. It still shares the handler transaction: a
78
+ // thrown JS error is swallowed here, but a failed SQL statement inside it would abort
79
+ // the transaction, so resolvers must not issue statements that can fail.
79
80
  async function resolveAdminRecipient(
80
81
  opts: WaitlistOptions,
81
82
  ctx: HandlerContext,
@@ -175,8 +176,7 @@ export function createSubmitHandler(opts: WaitlistOptions) {
175
176
  message: payload.message,
176
177
  }),
177
178
  priority: "normal",
178
- // Operator-facing: the request locale, not the one the entrant picked in the form.
179
- locale: resolveWaitlistMailLocale(ctx.locale),
179
+ locale: resolveWaitlistMailLocale(opts.adminLocale),
180
180
  });
181
181
  });
182
182
 
@@ -38,6 +38,11 @@ export function waitlistImportId(sourceKey: string): string {
38
38
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
39
39
  }
40
40
 
41
+ // The version nibble marks ids minted by waitlistImportId; legacy row ids are random UUIDs.
42
+ export function isWaitlistImportId(id: string): boolean {
43
+ return id[14] === "5";
44
+ }
45
+
41
46
  function presentOnly(fields: Record<string, unknown>): Record<string, unknown> {
42
47
  return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));
43
48
  }
@@ -9,6 +9,7 @@ import {
9
9
  createTenantDb,
10
10
  selectMany,
11
11
  table,
12
+ tableExists,
12
13
  text as textColumn,
13
14
  timestamp,
14
15
  transaction,
@@ -23,9 +24,16 @@ import {
23
24
  } from "@cosmicdrift/kumiko-framework/event-store";
24
25
  import type { DbConnection } from "@cosmicdrift/kumiko-types/db-connection";
25
26
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
26
- import { importWaitlistEntry, type WaitlistImportEntry, waitlistImportId } from "./import.ts";
27
+ import {
28
+ importWaitlistEntry,
29
+ isWaitlistImportId,
30
+ type WaitlistImportEntry,
31
+ waitlistImportId,
32
+ } from "./import.ts";
27
33
  import { WAITLIST_STATUS, type WaitlistStatus } from "./web/constants.ts";
28
34
 
35
+ const ARCHIVED_STREAMS_TABLE = "public.kumiko_archived_streams";
36
+
29
37
  export const LEGACY_WAITLIST_SOURCES = ["offlot", "publicstatus"] as const;
30
38
  export type LegacyWaitlistSource = (typeof LEGACY_WAITLIST_SOURCES)[number];
31
39
 
@@ -210,15 +218,19 @@ async function archiveLegacyStream(
210
218
  db: DbConnection,
211
219
  legacyId: string,
212
220
  importedId: string,
221
+ dryRun: boolean,
213
222
  ): Promise<number> {
214
223
  if (legacyId === importedId) return 0;
215
- if (await isStreamArchived(db, SYSTEM_TENANT_ID, legacyId)) return 0;
224
+ // A dry run never creates the archive table, so a missing one means nothing is archived yet.
225
+ const archiveTableReady = !dryRun || (await tableExists(db, ARCHIVED_STREAMS_TABLE));
226
+ if (archiveTableReady && (await isStreamArchived(db, SYSTEM_TENANT_ID, legacyId))) return 0;
216
227
  const legacyEvents = await countWhere(db, eventsTable, {
217
228
  tenantId: SYSTEM_TENANT_ID,
218
229
  aggregateId: legacyId,
219
230
  aggregateType: LEGACY_AGGREGATE_TYPE,
220
231
  });
221
232
  if (legacyEvents === 0) return 0;
233
+ if (dryRun) return 1;
222
234
  await archiveStream(db, {
223
235
  tenantId: SYSTEM_TENANT_ID,
224
236
  aggregateId: legacyId,
@@ -243,6 +255,12 @@ export async function migrateLegacyWaitlist(
243
255
  let archivedStreams = 0;
244
256
  if (!options.dryRun && options.from === "offlot") await createArchivedStreamsTable(db);
245
257
  for (const row of rows) {
258
+ // The offlot default source is the entity table: rows a previous run imported
259
+ // are already migrated entries and must neither be re-imported nor archived.
260
+ if (options.from === "offlot" && isWaitlistImportId(String(row["id"]))) {
261
+ skipped += 1;
262
+ continue;
263
+ }
246
264
  const entry =
247
265
  options.from === "offlot"
248
266
  ? await mapOfflotRow(row)
@@ -257,11 +275,12 @@ export async function migrateLegacyWaitlist(
257
275
  if (outcome === "created") created += 1;
258
276
  else skipped += 1;
259
277
  });
260
- if (!options.dryRun && options.from === "offlot") {
278
+ if (options.from === "offlot") {
261
279
  archivedStreams += await archiveLegacyStream(
262
280
  db,
263
281
  String(row["id"]),
264
282
  waitlistImportId(entry.sourceKey),
283
+ options.dryRun,
265
284
  );
266
285
  }
267
286
  }
@@ -75,22 +75,25 @@ export const linkWaitlistOnSignup: MultiStreamApplyFn = async (event, tx) => {
75
75
  if (typeof user?.email !== "string") return;
76
76
  const email = normalizeEmail(await decryptStoredPii(user.email, "email", PII_DECRYPT_REASON));
77
77
 
78
- const found = await waitlistExecutor.list(
79
- {
80
- filter: { field: "email", op: "eq", value: email },
81
- filters: [{ field: "status", op: "in", value: [WAITLIST_STATUS.Invited] }],
82
- },
83
- platformActor(),
84
- db,
85
- );
86
- const invited = [...found.rows].sort(newestSubmittedFirst)[0];
78
+ const findInvited = async () => {
79
+ const found = await waitlistExecutor.list(
80
+ {
81
+ filter: { field: "email", op: "eq", value: email },
82
+ filters: [{ field: "status", op: "in", value: [WAITLIST_STATUS.Invited] }],
83
+ },
84
+ platformActor(),
85
+ db,
86
+ );
87
+ return [...found.rows].sort(newestSubmittedFirst)[0];
88
+ };
89
+ const invited = await findInvited();
87
90
  // skip: the signup email has no invited waitlist entry (open signup or stale invite).
88
91
  if (!invited) return;
89
92
  const { id, version } = invited;
90
93
  // skip: defensive guard on the row shape.
91
94
  if (typeof id !== "string" || typeof version !== "number") return;
92
95
 
93
- await waitlistExecutor.update(
96
+ const updated = await waitlistExecutor.update(
94
97
  {
95
98
  id,
96
99
  version,
@@ -103,4 +106,11 @@ export const linkWaitlistOnSignup: MultiStreamApplyFn = async (event, tx) => {
103
106
  platformActor(),
104
107
  db,
105
108
  );
109
+ // skip: linked.
110
+ if (updated.isSuccess) return;
111
+ // A concurrent admin change that already moved the entry out of `invited` makes the link
112
+ // moot; otherwise throw so the at-least-once consumer redelivers.
113
+ // skip: the entry left `invited` concurrently.
114
+ if ((await findInvited())?.id !== id) return;
115
+ throw new Error(`waitlist:link-on-signup: could not link waitlist entry ${id}`);
106
116
  };
@@ -24,6 +24,9 @@ export type WaitlistOptions = {
24
24
  * string or an absent option sends none. Best effort, never fails the submit,
25
25
  * also when the resolver throws or rejects. */
26
26
  readonly notifyRecipient?: (ctx: HandlerContext) => string | null | Promise<string | null>;
27
+ /** Language of the admin notice mail (en, de or es; anything else falls back to en).
28
+ * Not taken from the request: a submit comes from the entrant, not the operator. */
29
+ readonly adminLocale?: string;
27
30
  /** Default `{ mode: "own-tenant", role: "TenantAdmin" }`. */
28
31
  readonly invite?: WaitlistInviteOptions;
29
32
  /** Default: 5 submits per IP per 10 minutes. Pass `{ disabled: true, reason }`
@@ -12,7 +12,7 @@ const WORKFLOW_RUN_NAMESPACE = "1f8a6c3e-7d2b-4a91-9e3f-5c8b2a41d6f0";
12
12
  * race on `expectedVersion` and have the loser fail the unique constraint
13
13
  * instead of silently double-running. It does NOT dedup sequential
14
14
  * re-triggers of the same key — those land as version 2, 3, ... on the same
15
- * stream and each starts its own run; that's out of scope for #2478.
15
+ * stream and each starts its own run; that's out of scope.
16
16
  */
17
17
  // @wrapper-known uuid-domain
18
18
  export function workflowRunAggregateId(workflowName: string, key: string): string {
@@ -1,6 +1,5 @@
1
1
  // event-subscriber — wakes up pending waitForEvent suspensions when their
2
- // awaited domain event arrives (framework#2513 Phase 3b, D4 in
3
- // workflow-resume-loop.md).
2
+ // awaited domain event arrives (in workflow-resume-loop.md).
4
3
  //
5
4
  // registerEventTrigger (event-trigger.ts) calls registerEventWakeup for
6
5
  // every workflow it registers, building ONE MultiStreamProjection PER
@@ -17,12 +16,12 @@
17
16
  // already in hand, has no such hazard — same reasoning event-trigger.ts
18
17
  // already applies to the run-start MSP.
19
18
  //
20
- // This subscriber never resumes a run itself (D3, workflow-resume-loop.md):
19
+ // This subscriber never resumes a run itself (in workflow-resume-loop.md):
21
20
  // the MultiStreamApplyContext it runs in has no callFeature/runStepList
22
21
  // access, only unsafeAppendEvent/loadAggregate. It writes triggerEventType
23
22
  // + triggerEventRef + wakeAt=now() onto the matching pending row(s); the
24
- // existing resume-due-runs job (Phase 2) picks the row up on its next
25
- // cron tick — the one resume path stays exactly the one Phase 2 built.
23
+ // existing resume-due-runs job picks the row up on its next
24
+ // cron tick — the resume path remains unchanged.
26
25
 
27
26
  import { selectMany, updateMany } from "@cosmicdrift/kumiko-framework/db";
28
27
  import type {
@@ -26,6 +26,7 @@ import {
26
26
  WORKFLOW_AGGREGATE_TYPE,
27
27
  WORKFLOW_RUN_FAILED_TYPE,
28
28
  WorkflowStepError,
29
+ walkStepInstances,
29
30
  } from "@cosmicdrift/kumiko-framework/engine";
30
31
  import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
31
32
  import { workflowRunAggregateId } from "./aggregate-id.ts";
@@ -51,18 +52,6 @@ const STEP_KINDS_NEEDING_HANDLER_CONTEXT: ReadonlySet<string> = new Set([
51
52
  "unsafeProjectionDelete",
52
53
  ]);
53
54
 
54
- function* walkStepInstances(steps: readonly StepInstance[]): Generator<StepInstance, void, void> {
55
- for (const step of steps) {
56
- yield step;
57
- const { args } = step;
58
- if (typeof args !== "object" || args === null) continue;
59
- for (const path of getStep(step.kind)?.subPaths ?? []) {
60
- const nested: unknown = path in args ? Reflect.get(args, path) : undefined;
61
- if (Array.isArray(nested)) yield* walkStepInstances(nested);
62
- }
63
- }
64
- }
65
-
66
55
  export function assertEventTriggerStepsSupported(workflow: WorkflowDefinition): void {
67
56
  let steps: readonly StepInstance[];
68
57
  try {
@@ -80,7 +69,7 @@ export function assertEventTriggerStepsSupported(workflow: WorkflowDefinition):
80
69
  { cause: error },
81
70
  );
82
71
  }
83
- for (const step of walkStepInstances(steps)) {
72
+ for (const step of walkStepInstances(steps, `workflow "${workflow.name}" eventTrigger`)) {
84
73
  if (getStep(step.kind) === undefined) {
85
74
  throw new Error(`Workflow "${workflow.name}" uses unknown step kind "${step.kind}"`);
86
75
  }
@@ -95,13 +84,13 @@ export function assertEventTriggerStepsSupported(workflow: WorkflowDefinition):
95
84
 
96
85
  export function registerEventTrigger(r: FeatureRegistrar, workflow: WorkflowDefinition): void {
97
86
  // Populate the workflow-registry unconditionally, before the event-trigger
98
- // guard below — resume-run (framework#2513 Phase 2) looks workflows up by
87
+ // guard below — resume-run looks workflows up by
99
88
  // name regardless of trigger kind, and a cron-triggered workflow that never
100
89
  // reaches the MSP branch still needs to be resumable.
101
90
  registerWorkflow(workflow);
102
91
 
103
92
  // Independent of trigger.kind — a cron-triggered workflow can still have
104
- // waitForEvent steps in its pipeline (framework#2513 Phase 3b, D4).
93
+ // waitForEvent steps in its pipeline.
105
94
  registerEventWakeup(r, workflow);
106
95
 
107
96
  // skip: cron-triggered workflows have no domain event to project off — they
@@ -9,8 +9,8 @@
9
9
  // `workflowRunnerFeature` documents that dependency and reserves the
10
10
  // picker/manifest slot.
11
11
  //
12
- // It also registers the resume loop (framework#2513 Phase 2 + 3b):
13
- // - the workflow_run_pending MSP (Phase 1) materialises suspended
12
+ // It also registers the resume loop:
13
+ // - the workflow_run_pending MSP materialises suspended
14
14
  // wait/waitForEvent/retry steps into a pending-set table
15
15
  // - the `resume-due-runs` cron job (perTenant) scans that table for
16
16
  // `wakeAt < now()` rows and dispatches `resume-run` per row — the job
@@ -1,10 +1,10 @@
1
1
  // resume-run — wakes one suspended workflow step. Dispatched by the
2
- // resume-due-runs job (framework#2513 Phase 2), never called directly by a
2
+ // resume-due-runs job, never called directly by a
3
3
  // user — r.systemScope() + access: { roles: [SYSTEM_ROLE] } enforce that.
4
4
  //
5
5
  // The job does nothing but SELECT + dispatch; all resume logic lives here,
6
6
  // adapted from samples/recipes/workflow-engine/src/resume-loop.ts:
7
- // 1. Q7 fingerprint check FIRST — before claiming, before any pipeline
7
+ // 1. Fingerprint check FIRST — before claiming, before any pipeline
8
8
  // work. A changed workflow definition fails loud (WORKFLOW_RUN_FAILED,
9
9
  // reason "workflow_definition_changed"), never a silent skip.
10
10
  // 2. Claim via a savepoint-scoped WORKFLOW_RESUMED append (ctx.tryAppendEvent,
@@ -23,8 +23,8 @@
23
23
  // shows up here in its shredded form, and an unloadable one (archived
24
24
  // stream) fails the run. The pending row's own
25
25
  // triggerEventType/triggerEventRef columns are a DIFFERENT thing: for a
26
- // waitForEvent suspension they point at the AWAITED event the Phase 3b
27
- // event-subscriber matched (NULL until then, and NULL forever on a
26
+ // waitForEvent suspension they point at the AWAITED event the event-subscriber
27
+ // matched (NULL until then, and NULL forever on a
28
28
  // timeout-without-a-match). That event's payload becomes the resumed
29
29
  // pipeline's result for the skipped waitForEvent step itself (see
30
30
  // resultKey on steps/wait-for-event.ts) — pre-seeded into stepsAcc below so
@@ -4,13 +4,12 @@
4
4
  // Insert (upsert, for idempotent at-least-once redelivery) on every
5
5
  // suspension: wait, waitForEvent, retry. Delete on WORKFLOW_RESUMED or a
6
6
  // terminal run outcome (completed/failed) — a run only ever has one row
7
- // pending at a time (D1: a later suspension always targets a fresh
8
- // stepIndex, since the prior one was resumed away first), so deleting by
7
+ // pending at a time (a later suspension always targets a fresh stepIndex,
8
+ // since the prior one was resumed away first), so deleting by
9
9
  // (tenantId, runId) alone is exact.
10
10
  //
11
- // No resume logic here — framework#2513 Phase 2 owns the job that reads
12
- // this table and dispatches the actual resume. This projection only writes
13
- // the rows.
11
+ // No resume logic here — the job that reads this table and dispatches the
12
+ // actual resume is separate. This projection only writes the rows.
14
13
 
15
14
  import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
16
15
  import { deleteMany, fetchOne, upsertOnConflict } from "@cosmicdrift/kumiko-framework/db";
@@ -81,8 +80,8 @@ async function upsertPending(tx: DbRunner, row: PendingRow): Promise<void> {
81
80
  workflowRunPendingTable,
82
81
  {
83
82
  ...row,
84
- // Phase 3's event-subscriber writes these when the awaited event
85
- // arrives — Phase 1 never touches them, insert or update.
83
+ // The event-subscriber writes these when the awaited event
84
+ // arrives — they are never touched here, on insert or update.
86
85
  triggerEventType: null,
87
86
  triggerEventRef: null,
88
87
  triggerPayload: null,
@@ -2,12 +2,12 @@
2
2
  // pipeline until first suspension or completion, and writing run-completed.
3
3
  //
4
4
  // wait / retry / waitForEvent suspensions are all resumable — the
5
- // resume-due-runs job + resume-run handler (framework#2513 Phase 2) wake
6
- // wait/retry via a plain wakeAt timeout; waitForEvent additionally gets
7
- // woken early by the event-subscriber (Phase 3b, event-subscriber.ts) when
8
- // its awaited event arrives, and by the same wakeAt timeout otherwise
9
- // (D1's `wakeAt ?? timeoutAt`). startAndRunWorkflow returns a silent
10
- // "suspended" outcome for all three instead of throwing.
5
+ // resume-due-runs job + resume-run handler wake wait/retry via a plain
6
+ // wakeAt timeout; waitForEvent additionally gets woken early by the
7
+ // event-subscriber (event-subscriber.ts) when its awaited event arrives,
8
+ // and by the same wakeAt timeout otherwise (D1's `wakeAt ?? timeoutAt`).
9
+ // startAndRunWorkflow returns a silent "suspended" outcome for all three
10
+ // instead of throwing.
11
11
 
12
12
  import type {
13
13
  HandlerContext,
@@ -12,12 +12,12 @@ import {
12
12
  } from "@cosmicdrift/kumiko-framework/db";
13
13
 
14
14
  // workflow_run_pending — one row per currently-suspended workflow step.
15
- // Read-side of the resume loop (framework#2513 Phase 1): the wait /
15
+ // Read-side of the resume loop: the wait /
16
16
  // waitForEvent / retry steps already write their suspension onto the
17
17
  // workflow-run event stream, but scanning kumiko_events for due runs
18
18
  // doesn't scale (see samples/recipes/workflow-engine/postgres-resume-loop.ts,
19
19
  // which does exactly that). This table is kept in sync by
20
- // pending-projection.ts's MultiStreamProjection so Phase 2's resume job can
20
+ // pending-projection.ts's MultiStreamProjection so the resume job can
21
21
  // do an indexed `wakeAt < now()` scan instead.
22
22
  //
23
23
  // **Unmanaged table** — same reasoning as delivery/tables.ts'
@@ -31,7 +31,7 @@ import {
31
31
  // key only, see aggregate-id.ts), so two tenants triggering the same
32
32
  // workflow with the same idempotencyKey get the SAME run_id. Without
33
33
  // tenant_id in the key, a same-stepIndex suspension from tenant B would
34
- // upsert onto tenant A's row and silently steal it (framework#2513).
34
+ // upsert onto tenant A's row and silently steal it.
35
35
  export const workflowRunPendingTable = pgTable(
36
36
  "workflow_run_pending",
37
37
  {
@@ -45,14 +45,14 @@ export const workflowRunPendingTable = pgTable(
45
45
  // which step suspended.
46
46
  wakeAt: instant("wake_at").notNull(),
47
47
  retryAttempt: integer("retry_attempt"),
48
- // Q7 snapshot fingerprint — Phase 2 compares this against the current
48
+ // Snapshot fingerprint — compares this against the current
49
49
  // workflow definition's fingerprint before resuming.
50
50
  definitionFingerprint: text("definition_fingerprint"),
51
51
  // Set only for waitForEvent suspensions; NULL for wait/retry.
52
52
  waitEventType: text("wait_event_type"),
53
53
  matchExpr: jsonb("match_expr"),
54
- // Written by the Phase 3 event-subscriber when the awaited event
55
- // arrives — always NULL in Phase 1/2. The row points at the awaited event
54
+ // Written by the event subscriber when the awaited event
55
+ // arrives — always NULL initially. The row points at the awaited event
56
56
  // ({ eventId, aggregateId, version }); resume-run re-reads it from the
57
57
  // event store, so erasing the event also covers the workflow.
58
58
  triggerEventType: text("trigger_event_type"),
@@ -1,6 +1,6 @@
1
1
  // workflow-registry — process-local lookup from workflow name to its
2
2
  // WorkflowDefinition. registerEventTrigger populates it at feature-
3
- // registration time; resume-run (Phase 2) is the only reader — it has
3
+ // registration time; resume-run is the only reader — it has
4
4
  // nothing but a workflow name on the pending row and needs the live
5
5
  // definition to rebuild the pipeline + recompute the Q7 fingerprint.
6
6
  //
@@ -119,6 +119,17 @@ export const WIDGETS_I18N = {
119
119
  "widgets:catalog:status-maintenance": { de: "maintenance", en: "maintenance" },
120
120
  "widgets:catalog:repayment-model": { de: "Tilgungsmodell", en: "Repayment model" },
121
121
  "widgets:catalog:mode-annuity": { de: "Annuität", en: "Annuity" },
122
+ "widgets:catalog:choice-cards": { de: "Zahlungsanbieter", en: "Payment provider" },
123
+ "widgets:catalog:choice-direct": { de: "Direkt", en: "Direct" },
124
+ "widgets:catalog:choice-direct-description": {
125
+ de: "Rechnung vom Anbieter der App",
126
+ en: "Invoiced by the app operator",
127
+ },
128
+ "widgets:catalog:choice-reseller": { de: "Reseller", en: "Reseller" },
129
+ "widgets:catalog:choice-reseller-description": {
130
+ de: "Verkäufer ist der Reseller, inklusive Umsatzsteuer",
131
+ en: "Sold by the reseller, VAT included",
132
+ },
122
133
  "widgets:catalog:mode-fixed": { de: "Feste Rate", en: "Fixed rate" },
123
134
  "widgets:catalog:model": { de: "Modell", en: "Model" },
124
135
  "widgets:catalog:nominal-rate": { de: "Sollzins", en: "Nominal rate" },
@@ -6,6 +6,7 @@ import {
6
6
  AiTextArea,
7
7
  AiTextField,
8
8
  BooleanField,
9
+ ChoiceCards,
9
10
  CollapsibleSection,
10
11
  ComparisonTable,
11
12
  DateField,
@@ -50,6 +51,7 @@ export function Widgets(): ReactNode {
50
51
  const t = useTranslation();
51
52
  const locale = useLocale().locale();
52
53
  const [mode, setMode] = useState<"annuity" | "fixed">("annuity");
54
+ const [provider, setProvider] = useState<"direct" | "reseller">("direct");
53
55
  const [drawerOpen, setDrawerOpen] = useState(false);
54
56
  const [belowHeaderDrawerOpen, setBelowHeaderDrawerOpen] = useState(false);
55
57
  const [floatingPanelOpen, setFloatingPanelOpen] = useState(false);
@@ -181,6 +183,28 @@ export function Widgets(): ReactNode {
181
183
  />
182
184
  </SectionCard>
183
185
 
186
+ <SectionCard title={t("widgets:catalog:choice-cards")}>
187
+ <ChoiceCards
188
+ value={provider}
189
+ onChange={setProvider}
190
+ ariaLabel={t("widgets:catalog:choice-cards")}
191
+ options={[
192
+ {
193
+ value: "direct",
194
+ title: t("widgets:catalog:choice-direct"),
195
+ description: t("widgets:catalog:choice-direct-description"),
196
+ aside: "9,00 €",
197
+ },
198
+ {
199
+ value: "reseller",
200
+ title: t("widgets:catalog:choice-reseller"),
201
+ description: t("widgets:catalog:choice-reseller-description"),
202
+ aside: "9,90 €",
203
+ },
204
+ ]}
205
+ />
206
+ </SectionCard>
207
+
184
208
  <CollapsibleSection title={t("widgets:catalog:advanced-settings")}>
185
209
  <EmptyState
186
210
  title={t("widgets:catalog:no-extra-repayments-title")}
@@ -4,6 +4,7 @@
4
4
  // runs in a Playwright worker and must not pull the server import chain).
5
5
 
6
6
  export const GALLERY_PROVIDER = "gallery-mock-provider";
7
+ export const GALLERY_MOR_PROVIDER = "gallery-mock-mor";
7
8
  export const GALLERY_TERMS_SLUG = "gallery-terms";
8
9
  export const GALLERY_OPERATOR_EMAIL = "billing@gallery.example";
9
10
  export const GALLERY_PLAN_PATH = "/tenant-admin/billing-plans";
@@ -14,3 +15,7 @@ export const GALLERY_TENANT_HOST = "localhost";
14
15
  export const GALLERY_APEX_HOST = "127.0.0.1";
15
16
 
16
17
  export const GALLERY_PRICE_IDS = { starter: "price_gallery_starter", pro: "price_gallery_pro" };
18
+ export const GALLERY_MOR_PRICE_IDS = {
19
+ starter: "price_gallery_mor_starter",
20
+ pro: "price_gallery_mor_pro",
21
+ };