@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
@@ -8,7 +8,7 @@ import type { MfaTokenSecretsEnv } from "./token-secrets.ts";
8
8
 
9
9
  export type BindMfaRevokeAllOtherSessions = (
10
10
  revoker: (userId: string, currentSid: string | undefined) => Promise<number>,
11
- ) => void;
11
+ ) => () => void;
12
12
 
13
13
  // Reads the late-bind setter off a mounted auth-mfa feature's exports —
14
14
  // mirrors sessions' own bindAutoRevokeFromFeature. run{Prod,Dev}App call
@@ -79,7 +79,7 @@ export function bindMfaTokenSecretsFromFeature(
79
79
  return undefined;
80
80
  }
81
81
 
82
- export type BindRevokeAllPatTokens = (revoker: (userId: string) => Promise<number>) => void;
82
+ export type BindRevokeAllPatTokens = (revoker: (userId: string) => Promise<number>) => () => void;
83
83
 
84
84
  // Reads the late-bind setter off a mounted auth-mfa feature's exports —
85
85
  // run{Prod,Dev}App call this once the personal-access-tokens feature (if
@@ -220,10 +220,16 @@ export function createAuthMfaFeature(
220
220
 
221
221
  const bindRevokeAllOtherSessions: BindMfaRevokeAllOtherSessions = (revoker) => {
222
222
  revokeAllOtherSessions = revoker;
223
+ return () => {
224
+ if (revokeAllOtherSessions === revoker) revokeAllOtherSessions = undefined;
225
+ };
223
226
  };
224
227
 
225
228
  const bindRevokeAllPatTokens: BindRevokeAllPatTokens = (revoker) => {
226
229
  revokeAllPatTokens = revoker;
230
+ return () => {
231
+ if (revokeAllPatTokens === revoker) revokeAllPatTokens = undefined;
232
+ };
227
233
  };
228
234
 
229
235
  return {
@@ -45,9 +45,9 @@ export function createDisableHandler(opts: DisableOptions) {
45
45
  if (!row) return mfaNotEnabled();
46
46
 
47
47
  // Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts
48
- // (#1467): without ctx.redis, verifyMfaFactor's TOTP-replay burn is
49
- // skipped, and a code observed once (phishing proxy/shoulder-surfing)
50
- // could be replayed within the ±1-step window to disable MFA outright.
48
+ // without ctx.redis, verifyMfaFactor's TOTP-replay burn is skipped, and
49
+ // a code observed once (phishing proxy/shoulder-surfing) could be
50
+ // replayed within the ±1-step window to disable MFA outright.
51
51
  // "no ctx.redis means no one gets through MFA login" doesn't cover
52
52
  // this route — it's session-authed, and JWTs issued before Redis was
53
53
  // unwired stay valid until they expire.
@@ -150,8 +150,8 @@ export function createEnableConfirmPreauthHandler(opts: EnableConfirmPreauthOpti
150
150
  // re-enrollment until an operator manually disables MFA. NOT fixed by
151
151
  // this ordering: burnToken() above still runs before this check, so a
152
152
  // mid-flight restricted/deleted user still burns their setup token
153
- // (framework#1523/5) — moving the burn later would need care around
154
- // the existing userId-unique-constraint backstop between the
153
+ // — moving the burn later would need care around the
154
+ // existing userId-unique-constraint backstop between the
155
155
  // `existing` check above and executor.create() below.
156
156
  const systemUser = createSystemUser(tenantId, ["SystemAdmin"]);
157
157
  const userRow = (await ctx.queryAs(systemUser, UserQueries.findForAuth, {
@@ -207,10 +207,10 @@ export function createEnableConfirmPreauthHandler(opts: EnableConfirmPreauthOpti
207
207
  id: userId,
208
208
  tenantId,
209
209
  roles: mergedRoles,
210
- // This endpoint logs the user in directly (fw#1760), so a stored
210
+ // This endpoint logs the user in directly, so a stored
211
211
  // timezone must survive the preauth-MFA-enrollment login just like
212
212
  // a plain password login does — same helper as verify.write.ts /
213
- // invite-accept-with-login.write.ts (#1759).
213
+ // invite-accept-with-login.write.ts.
214
214
  ...sessionTimezoneField(userRow?.timezone),
215
215
  ...sessionLocaleField(userRow?.locale),
216
216
  };
@@ -56,8 +56,8 @@ export function createEnableConfirmHandler(opts: EnableConfirmOptions) {
56
56
  // already rules that out).
57
57
  if (verify.payload.userId !== event.user.id) return invalidSetupToken();
58
58
 
59
- // Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts
60
- // (#1467): session-authed (lower risk — the caller already has a
59
+ // Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts:
60
+ // session-authed (lower risk — the caller already has a
61
61
  // valid JWT), but silently skipping the single-use burn here would
62
62
  // still let a double-confirm race complete twice instead of the
63
63
  // second seeing invalidSetupToken(). Checked before the TOTP verify
@@ -55,7 +55,7 @@ export function createEnableStartPreauthHandler(opts: EnableStartPreauthOptions)
55
55
  );
56
56
  // Same generic "sign in again" error as an expired/invalid MFA
57
57
  // challenge token — both mean the login-flow token expired, no
58
- // distinct i18n needed (see #1465's scoping comment).
58
+ // distinct i18n needed.
59
59
  if (!verified.ok) return invalidChallengeToken();
60
60
  const { userId, tenantId } = verified.payload;
61
61
 
@@ -154,7 +154,7 @@ export async function mfaReencryptJob(
154
154
 
155
155
  // After PII peel (when configured), values must be current-cipher
156
156
  // envelopes — non-JSON/non-envelope is not a supported legacy decrypt
157
- // path (#1541, mirrors config #1513).
157
+ // path, matching config behavior.
158
158
  const totpClass = classifyStoredEnvelope(envelopeValues.totpSecret, targetVersion);
159
159
  const recoveryClass = classifyStoredEnvelope(envelopeValues.recoveryCodes, targetVersion);
160
160
  if (totpClass === "unrecognized" || recoveryClass === "unrecognized") {
@@ -47,11 +47,11 @@ export function createRegenerateRecoveryHandler(opts: RegenerateRecoveryOptions)
47
47
  // count, since either way the presented code is consumed/irrelevant
48
48
  // afterward.
49
49
  //
50
- // Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts
51
- // (#1467): without ctx.redis, verifyMfaFactor's TOTP-replay burn is
52
- // skipped, letting an observed code be replayed within the ±1-step
53
- // window to regenerate (and thus invalidate) recovery codes — a
54
- // session-authed route, so pre-unwiring JWTs stay a valid attack path.
50
+ // Fail closed, matching verify.write.ts/enable-confirm-preauth.write.ts:
51
+ // without ctx.redis, verifyMfaFactor's TOTP-replay burn is skipped,
52
+ // letting an observed code be replayed within the ±1-step window to
53
+ // regenerate (and thus invalidate) recovery codes — a session-authed
54
+ // route, so pre-unwiring JWTs stay a valid attack path.
55
55
  if (!ctx.redis) {
56
56
  return writeFailure(
57
57
  new InternalError({
@@ -67,7 +67,7 @@ export function createMfaVerifyHandler(opts: MfaVerifyOptions) {
67
67
  if (!verified.ok) return invalidChallengeToken();
68
68
  const { userId, tenantId } = verified.payload;
69
69
 
70
- // Fail closed, matching enable-confirm-preauth.write.ts (#1467):
70
+ // Fail closed, matching enable-confirm-preauth.write.ts:
71
71
  // this route sits behind a challenge token from a successful login,
72
72
  // but its own secret is still just a short TOTP/recovery code —
73
73
  // silently skipping the brute-force cap and single-use burn when
@@ -18,7 +18,7 @@ const CHALLENGE_TOKEN_PURPOSE = "mfa-challenge-token-v1";
18
18
 
19
19
  // A blank or whitespace-only override is treated as absent — an empty env
20
20
  // var (MFA_SETUP_TOKEN_SECRET="") must fall back to derivation, not sign
21
- // tokens with an empty/near-empty HMAC key (fw#1623).
21
+ // tokens with an empty/near-empty HMAC key.
22
22
  function resolveSecret(override: string | undefined, fallback: () => string): string {
23
23
  return override !== undefined && override.trim() !== "" ? override : fallback();
24
24
  }
@@ -1,4 +1,4 @@
1
- // Client-Feature-Factory für auth-mfa — mirrors emailPasswordClient()'s
1
+ // Client feature factory for auth-mfa — mirrors emailPasswordClient()'s
2
2
  // shape so apps register both the same way:
3
3
  // createKumikoApp({ clientFeatures: [emailPasswordClient(), authMfaClient()] }).
4
4
  // No gates: MfaVerifyScreen isn't a route gate, it's a state swap wired
@@ -12,7 +12,7 @@ import type { ComponentType, ReactNode } from "react";
12
12
  import { defaultTranslations, mergeTranslations } from "./i18n.ts";
13
13
 
14
14
  export type AuthMfaClientOptions = {
15
- /** Key-Overrides pro Locale, gemerged mit den Default-Bundles (de/en). */
15
+ /** Key overrides per locale, merged with the default bundles (de/en). */
16
16
  readonly translations?: TranslationsByLocale;
17
17
  };
18
18
 
@@ -1,6 +1,6 @@
1
- // Default-Bundles für die auth-mfa Feature-UI. Merged in mit
2
- // authMfaClient() analog zu emailPasswordClient() aus auth-email-password.
3
- // Keys folgen `auth.mfa.<area>.<slug>`.
1
+ // Default bundles for the auth-mfa feature UI, merged by
2
+ // authMfaClient() analogously to emailPasswordClient() from auth-email-password.
3
+ // Keys follow `auth.mfa.<area>.<slug>`.
4
4
 
5
5
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
6
6
 
@@ -13,6 +13,11 @@ export const defaultTranslations: TranslationsByLocale = {
13
13
  "auth.mfa.verify.submit": "Verify",
14
14
  "auth.mfa.verify.submitting": "…",
15
15
  "auth.mfa.verify.backToLogin": "Back to login",
16
+ "auth.mfa.verify.recoveryCode": "Recovery code",
17
+ "auth.mfa.verify.recoverySubtitle":
18
+ "Enter one of the recovery codes you saved when you set up two-factor authentication.",
19
+ "auth.mfa.verify.useAuthenticatorCode": "Use the code from your app",
20
+ "auth.mfa.verify.useRecoveryCode": "Use a recovery code instead",
16
21
  "auth.mfa.errors.invalidCode": "Invalid code. Please try again.",
17
22
  "auth.mfa.errors.invalidTotpCode": "Invalid code. Please try again.",
18
23
  "auth.mfa.errors.invalidChallengeToken": "Your sign-in has expired. Please sign in again.",
@@ -43,7 +48,7 @@ export const defaultTranslations: TranslationsByLocale = {
43
48
  "auth.mfa.disable.title": "Disable two-factor authentication",
44
49
  "auth.mfa.disable.description":
45
50
  "Confirm with a code from your authenticator app or a recovery code. Your account will then be protected by your password alone.",
46
- "auth.mfa.disable.code": "Code from your authenticator app or a recovery code",
51
+ "auth.mfa.disable.code": "Code from your authenticator app",
47
52
  "auth.mfa.disable.confirm": "Disable",
48
53
  "auth.mfa.disable.cancel": "Cancel",
49
54
  "auth.mfa.disable.trigger": "Disable two-factor authentication",
@@ -1,7 +1,7 @@
1
- // Public exports für die Browser-Seite des auth-mfa Features. Sub-Path-
2
- // Export `@cosmicdrift/kumiko-bundled-features/auth-mfa/web` — Server-Seite
3
- // (defineFeature) bleibt frei von React-/DOM-Deps, siehe auth-email-
4
- // password/web/index.ts für die selbe Trennung.
1
+ // Public exports for the browser side of the auth-mfa feature. The subpath
2
+ // export `@cosmicdrift/kumiko-bundled-features/auth-mfa/web` keeps the server
3
+ // side (`defineFeature`) free of React/DOM dependencies, matching the same
4
+ // separation in auth-email-password/web/index.ts.
5
5
 
6
6
  export type { AuthMfaClientFeature, AuthMfaClientOptions } from "./client-plugin.ts";
7
7
  export { authMfaClient } from "./client-plugin.ts";
@@ -1,10 +1,10 @@
1
- // Browser-Seite von POST /api/auth/mfa/verify — completes the two-step
2
- // login LoginScreen started when the server responded mfaRequired. Same
3
- // fetch/CSRF pattern as auth-email-password's login() (pre-session, no
4
- // csrfHeader() — there's no session yet to protect). Response shape is
1
+ // Browser side of POST /api/auth/mfa/verify — completes the two-step
2
+ // login that LoginScreen started when the server responded with mfaRequired.
3
+ // Uses the same fetch/CSRF pattern as auth-email-password's login(), but runs
4
+ // before a session exists, so it does not call csrfHeader(). The response is
5
5
  // byte-identical to /auth/login's ({isSuccess, token, user} | {isSuccess:
6
- // false, error}) since auth-routes.ts mints via the same
7
- // mintSessionAndRespond() for both routes.
6
+ // false, error}) because auth-routes.ts uses mintSessionAndRespond() for both
7
+ // routes.
8
8
 
9
9
  // kumiko-lint-ignore cross-feature-import client-only types, the feature's server barrel has no web/ re-export
10
10
  import {
@@ -76,11 +76,12 @@ export type MfaSetupPreauthStartResult =
76
76
  | { readonly kind: "success"; readonly data: MfaSetupPreauthStart }
77
77
  | { readonly kind: "failure"; readonly error: LoginFailure };
78
78
 
79
- // Browser-Seite von POST /api/auth/mfa/preauth-enable-start — lets a user
79
+ // Browser side of POST /api/auth/mfa/preauth-enable-start — lets a user
80
80
  // blocked at login by MFA enforcement generate a TOTP secret/QR without a
81
- // session, using the preauthSetupToken login()'s mfa-setup-required result
82
- // carries. No JWT/cookie here (see auth-routes.ts's route comment) — the
83
- // response's setupToken is consumed by confirmMfaSetupPreauth below.
81
+ // session, using the preauthSetupToken carried by login()'s
82
+ // mfa-setup-required result. No JWT/cookie is issued here (see the route
83
+ // comment in auth-routes.ts); the response's
84
+ // setupToken is consumed by confirmMfaSetupPreauth below.
84
85
  export async function startMfaSetupPreauth(
85
86
  preauthSetupToken: string,
86
87
  accountLabel: string,
@@ -139,12 +140,12 @@ export async function startMfaSetupPreauth(
139
140
  };
140
141
  }
141
142
 
142
- // Browser-Seite von POST /api/auth/mfa/preauth-confirm — completes both
143
- // the enrollment startMfaSetupPreauth began and the login mfa-setup-
144
- // required block. Response shape mirrors /auth/mfa/verify's (mints via
145
- // the same mintSessionAndRespond()), same as verifyMfaChallenge above —
146
- // kept as its own function rather than a shared helper so this file's
147
- // two already-tested request shapes stay independently editable.
143
+ // Browser side of POST /api/auth/mfa/preauth-confirm — completes both the
144
+ // enrollment started by startMfaSetupPreauth and the login
145
+ // mfa-setup-required block. Its response mirrors /auth/mfa/verify's and is
146
+ // minted via the same mintSessionAndRespond(). It remains a separate function
147
+ // so this file's two already-tested request shapes stay independently
148
+ // editable.
148
149
  export async function confirmMfaSetupPreauth(
149
150
  setupToken: string,
150
151
  code: string,
@@ -0,0 +1,68 @@
1
+ import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
2
+ import type { ReactNode } from "react";
3
+
4
+ export type MfaCodeOrRecoveryFieldProps = {
5
+ readonly id: string;
6
+ readonly codeLabel: string;
7
+ readonly code: string;
8
+ readonly onCodeChange: (code: string) => void;
9
+ readonly useRecovery: boolean;
10
+ readonly onUseRecoveryChange: (useRecovery: boolean) => void;
11
+ readonly disabled?: boolean;
12
+ };
13
+
14
+ export function MfaCodeOrRecoveryField({
15
+ id,
16
+ codeLabel,
17
+ code,
18
+ onCodeChange,
19
+ useRecovery,
20
+ onUseRecoveryChange,
21
+ disabled,
22
+ }: MfaCodeOrRecoveryFieldProps): ReactNode {
23
+ const t = useTranslation();
24
+ const { Button, Field, Input } = usePrimitives();
25
+
26
+ return (
27
+ <>
28
+ <Field id={id} label={useRecovery ? t("auth.mfa.verify.recoveryCode") : codeLabel} required>
29
+ {useRecovery ? (
30
+ <Input
31
+ kind="text"
32
+ id={id}
33
+ name={id}
34
+ value={code}
35
+ onChange={onCodeChange}
36
+ disabled={disabled}
37
+ autoFocus
38
+ autoComplete="off"
39
+ />
40
+ ) : (
41
+ <Input
42
+ kind="code"
43
+ length={6}
44
+ id={id}
45
+ name={id}
46
+ value={code}
47
+ onChange={onCodeChange}
48
+ disabled={disabled}
49
+ autoFocus
50
+ />
51
+ )}
52
+ </Field>
53
+ <Button
54
+ type="button"
55
+ variant="link"
56
+ disabled={disabled}
57
+ onClick={() => {
58
+ onUseRecoveryChange(!useRecovery);
59
+ onCodeChange("");
60
+ }}
61
+ >
62
+ {useRecovery
63
+ ? t("auth.mfa.verify.useAuthenticatorCode")
64
+ : t("auth.mfa.verify.useRecoveryCode")}
65
+ </Button>
66
+ </>
67
+ );
68
+ }
@@ -12,6 +12,7 @@
12
12
  import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
13
13
  import { type ReactNode, useState } from "react";
14
14
  import { AuthMfaHandlers } from "./constants.ts";
15
+ import { MfaCodeOrRecoveryField } from "./mfa-code-or-recovery-field.tsx";
15
16
 
16
17
  export type MfaDisableDialogProps = {
17
18
  readonly open: boolean;
@@ -28,13 +29,24 @@ export function MfaDisableDialog({
28
29
  onError,
29
30
  }: MfaDisableDialogProps): ReactNode {
30
31
  const t = useTranslation();
31
- const { Dialog, Field, Input } = usePrimitives();
32
+ const { Dialog } = usePrimitives();
32
33
  const dispatcher = useDispatcher();
33
34
  const [code, setCode] = useState("");
35
+ const [useRecovery, setUseRecovery] = useState(false);
36
+
37
+ const reset = (): void => {
38
+ setCode("");
39
+ setUseRecovery(false);
40
+ };
41
+
42
+ const handleOpenChange = (nextOpen: boolean): void => {
43
+ if (!nextOpen) reset();
44
+ onOpenChange(nextOpen);
45
+ };
34
46
 
35
47
  const confirm = async (): Promise<void> => {
36
48
  const res = await dispatcher.write<{ disabled: boolean }>(AuthMfaHandlers.disable, { code });
37
- setCode("");
49
+ reset();
38
50
  if (!res.isSuccess) {
39
51
  onError(res.error.i18nKey);
40
52
  return;
@@ -45,7 +57,7 @@ export function MfaDisableDialog({
45
57
  return (
46
58
  <Dialog
47
59
  open={open}
48
- onOpenChange={onOpenChange}
60
+ onOpenChange={handleOpenChange}
49
61
  variant="danger"
50
62
  title={t("auth.mfa.disable.title")}
51
63
  description={t("auth.mfa.disable.description")}
@@ -54,16 +66,14 @@ export function MfaDisableDialog({
54
66
  onConfirm={confirm}
55
67
  testId="mfa-disable-dialog"
56
68
  >
57
- <Field id="mfa-disable-code" label={t("auth.mfa.disable.code")} required>
58
- <Input
59
- kind="text"
60
- id="mfa-disable-code"
61
- name="mfa-disable-code"
62
- value={code}
63
- onChange={setCode}
64
- autoComplete="one-time-code"
65
- />
66
- </Field>
69
+ <MfaCodeOrRecoveryField
70
+ id="mfa-disable-code"
71
+ codeLabel={t("auth.mfa.disable.code")}
72
+ code={code}
73
+ onCodeChange={setCode}
74
+ useRecovery={useRecovery}
75
+ onUseRecoveryChange={setUseRecovery}
76
+ />
67
77
  </Dialog>
68
78
  );
69
79
  }
@@ -9,6 +9,7 @@
9
9
  import { useDispatcher, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
10
10
  import { type ReactNode, useState } from "react";
11
11
  import { AuthMfaHandlers } from "./constants.ts";
12
+ import { MfaCodeOrRecoveryField } from "./mfa-code-or-recovery-field.tsx";
12
13
 
13
14
  export type MfaRegenerateRecoveryDialogProps = {
14
15
  readonly open: boolean;
@@ -25,16 +26,27 @@ export function MfaRegenerateRecoveryDialog({
25
26
  onError,
26
27
  }: MfaRegenerateRecoveryDialogProps): ReactNode {
27
28
  const t = useTranslation();
28
- const { Dialog, Field, Input } = usePrimitives();
29
+ const { Dialog } = usePrimitives();
29
30
  const dispatcher = useDispatcher();
30
31
  const [code, setCode] = useState("");
32
+ const [useRecovery, setUseRecovery] = useState(false);
33
+
34
+ const reset = (): void => {
35
+ setCode("");
36
+ setUseRecovery(false);
37
+ };
38
+
39
+ const handleOpenChange = (nextOpen: boolean): void => {
40
+ if (!nextOpen) reset();
41
+ onOpenChange(nextOpen);
42
+ };
31
43
 
32
44
  const confirm = async (): Promise<void> => {
33
45
  const res = await dispatcher.write<{ recoveryCodes: readonly string[] }>(
34
46
  AuthMfaHandlers.regenerateRecovery,
35
47
  { code },
36
48
  );
37
- setCode("");
49
+ reset();
38
50
  if (!res.isSuccess) {
39
51
  onError(res.error.i18nKey);
40
52
  return;
@@ -45,7 +57,7 @@ export function MfaRegenerateRecoveryDialog({
45
57
  return (
46
58
  <Dialog
47
59
  open={open}
48
- onOpenChange={onOpenChange}
60
+ onOpenChange={handleOpenChange}
49
61
  title={t("auth.mfa.regenerate.title")}
50
62
  description={t("auth.mfa.regenerate.description")}
51
63
  confirmLabel={t("auth.mfa.regenerate.confirm")}
@@ -53,16 +65,14 @@ export function MfaRegenerateRecoveryDialog({
53
65
  onConfirm={confirm}
54
66
  testId="mfa-regenerate-recovery-dialog"
55
67
  >
56
- <Field id="mfa-regenerate-code" label={t("auth.mfa.regenerate.code")} required>
57
- <Input
58
- kind="text"
59
- id="mfa-regenerate-code"
60
- name="mfa-regenerate-code"
61
- value={code}
62
- onChange={setCode}
63
- autoComplete="one-time-code"
64
- />
65
- </Field>
68
+ <MfaCodeOrRecoveryField
69
+ id="mfa-regenerate-code"
70
+ codeLabel={t("auth.mfa.regenerate.code")}
71
+ code={code}
72
+ onCodeChange={setCode}
73
+ useRecovery={useRecovery}
74
+ onUseRecoveryChange={setUseRecovery}
75
+ />
66
76
  </Dialog>
67
77
  );
68
78
  }
@@ -79,6 +79,7 @@ export function MfaSetupPreauthScreen({
79
79
  const [setup, setSetup] = useState<SetupState | null>(null);
80
80
  const [acknowledged, setAcknowledged] = useState(false);
81
81
  const [code, setCode] = useState("");
82
+ const [attempt, setAttempt] = useState(0);
82
83
  const [busy, setBusy] = useState(false);
83
84
  const [error, setError] = useState<string | null>(null);
84
85
  const [retryAfterSeconds, setRetryAfterSeconds] = useState<number | null>(null);
@@ -109,13 +110,13 @@ export function MfaSetupPreauthScreen({
109
110
  }
110
111
  };
111
112
 
112
- const confirmSetup = async (): Promise<void> => {
113
- if (!setup) return;
113
+ const confirmSetup = async (submittedCode: string): Promise<void> => {
114
+ if (!setup || busy) return;
114
115
  setBusy(true);
115
116
  setError(null);
116
117
  setRetryAfterSeconds(null);
117
118
  try {
118
- const res = await confirmMfaSetupPreauth(setup.setupToken, code);
119
+ const res = await confirmMfaSetupPreauth(setup.setupToken, submittedCode);
119
120
  if (res.kind !== "success") {
120
121
  setError(res.error.reason);
121
122
  setRetryAfterSeconds(res.error.retryAfterSeconds ?? null);
@@ -130,7 +131,11 @@ export function MfaSetupPreauthScreen({
130
131
  setSetup(null);
131
132
  setAcknowledged(false);
132
133
  setCode("");
134
+ return;
133
135
  }
136
+ // Remount: the field was disabled during confirm and lost focus.
137
+ setCode("");
138
+ setAttempt((n) => n + 1);
134
139
  return;
135
140
  }
136
141
  onSuccess?.(res.data.landingPath);
@@ -143,7 +148,7 @@ export function MfaSetupPreauthScreen({
143
148
 
144
149
  const onSubmit = (e?: FormEvent): void => {
145
150
  e?.preventDefault();
146
- void confirmSetup();
151
+ void confirmSetup(code);
147
152
  };
148
153
 
149
154
  return (
@@ -226,13 +231,17 @@ export function MfaSetupPreauthScreen({
226
231
 
227
232
  <Field id="mfa-setup-preauth-code" label={t("auth.mfa.enable.code")} required>
228
233
  <Input
229
- kind="text"
234
+ key={attempt}
235
+ kind="code"
236
+ length={6}
230
237
  id="mfa-setup-preauth-code"
231
238
  name="mfa-setup-preauth-code"
232
239
  value={code}
233
240
  onChange={setCode}
241
+ onComplete={(next) => void confirmSetup(next)}
234
242
  disabled={busy || !acknowledged}
235
- autoComplete="one-time-code"
243
+ hasError={error !== null}
244
+ autoFocus={attempt > 0}
236
245
  />
237
246
  </Field>
238
247