@tinyrack/issuary-server 0.22.0 → 0.24.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.
- package/dist/entities/oauth-client.entity.d.ts +0 -18
- package/dist/entities/oauth-client.entity.d.ts.map +1 -1
- package/dist/entities/oauth-code.entity.d.ts +0 -18
- package/dist/entities/oauth-code.entity.d.ts.map +1 -1
- package/dist/entities/oauth-device-code.entity.d.ts +0 -18
- package/dist/entities/oauth-device-code.entity.d.ts.map +1 -1
- package/dist/entities/revoked-token.entity.d.ts +0 -18
- package/dist/entities/revoked-token.entity.d.ts.map +1 -1
- package/dist/entities/terms-content.entity.d.ts +0 -9
- package/dist/entities/terms-content.entity.d.ts.map +1 -1
- package/dist/entities/terms.entity.d.ts +0 -9
- package/dist/entities/terms.entity.d.ts.map +1 -1
- package/dist/entities/user-consent.entity.d.ts +0 -18
- package/dist/entities/user-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-terms-consent.entity.d.ts +0 -9
- package/dist/entities/user-terms-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-totp-recovery-code.entity.d.ts +0 -9
- package/dist/entities/user-totp-recovery-code.entity.d.ts.map +1 -1
- package/dist/entities/user-totp.entity.d.ts +0 -9
- package/dist/entities/user-totp.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.d.ts +0 -9
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +0 -4
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/entrypoints/app.d.ts +0 -59
- package/dist/entrypoints/app.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts +20 -23
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.js +104 -134
- package/dist/entrypoints/database/postgres/compiled-functions.js.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts +20 -23
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.js +104 -134
- package/dist/entrypoints/database/sqlite/compiled-functions.js.map +1 -1
- package/dist/lib/config/branding.d.ts +0 -4
- package/dist/lib/config/branding.d.ts.map +1 -1
- package/dist/lib/config/branding.js +0 -14
- package/dist/lib/config/branding.js.map +1 -1
- package/dist/lib/config/resolved.d.ts +0 -3
- package/dist/lib/config/resolved.d.ts.map +1 -1
- package/dist/lib/config/security.d.ts +0 -2
- package/dist/lib/config/security.d.ts.map +1 -1
- package/dist/lib/config/security.js +0 -5
- package/dist/lib/config/security.js.map +1 -1
- package/dist/middleware/auth.d.ts +0 -8
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +0 -64
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/session.d.ts +0 -9
- package/dist/middleware/session.d.ts.map +1 -1
- package/dist/middleware/session.js +0 -18
- package/dist/middleware/session.js.map +1 -1
- package/dist/migrations/postgres/Migration20260825140000_drop_password_reset_required.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260825140000_drop_password_reset_required.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260825140000_drop_password_reset_required.js +19 -0
- package/dist/migrations/postgres/Migration20260825140000_drop_password_reset_required.js.map +1 -0
- package/dist/migrations/postgres/index.d.ts.map +1 -1
- package/dist/migrations/postgres/index.js +2 -0
- package/dist/migrations/postgres/index.js.map +1 -1
- package/dist/migrations/sqlite/Migration20260825140000_drop_password_reset_required.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260825140000_drop_password_reset_required.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260825140000_drop_password_reset_required.js +19 -0
- package/dist/migrations/sqlite/Migration20260825140000_drop_password_reset_required.js.map +1 -0
- package/dist/migrations/sqlite/index.d.ts.map +1 -1
- package/dist/migrations/sqlite/index.js +2 -0
- package/dist/migrations/sqlite/index.js.map +1 -1
- package/dist/repositories/oauth-code.repository.d.ts +2 -2
- package/dist/repositories/oauth-code.repository.d.ts.map +1 -1
- package/dist/repositories/oauth-code.repository.js +3 -7
- package/dist/repositories/oauth-code.repository.js.map +1 -1
- package/dist/repositories/oauth-device-code.repository.d.ts +4 -4
- package/dist/repositories/oauth-device-code.repository.d.ts.map +1 -1
- package/dist/repositories/oauth-device-code.repository.js +6 -18
- package/dist/repositories/oauth-device-code.repository.js.map +1 -1
- package/dist/repositories/user-totp-recovery-code.repository.d.ts +1 -7
- package/dist/repositories/user-totp-recovery-code.repository.d.ts.map +1 -1
- package/dist/repositories/user-totp-recovery-code.repository.js +1 -2
- package/dist/repositories/user-totp-recovery-code.repository.js.map +1 -1
- package/dist/repositories/user-totp.repository.d.ts +0 -9
- package/dist/repositories/user-totp.repository.d.ts.map +1 -1
- package/dist/routes/api/auth/index.d.ts +0 -52
- package/dist/routes/api/auth/index.d.ts.map +1 -1
- package/dist/routes/api/auth/index.js +0 -2
- package/dist/routes/api/auth/index.js.map +1 -1
- package/dist/routes/api/auth/passkey/verify/post.d.ts +0 -37
- package/dist/routes/api/auth/passkey/verify/post.d.ts.map +1 -1
- package/dist/routes/api/auth/passkey/verify/post.js +2 -8
- package/dist/routes/api/auth/passkey/verify/post.js.map +1 -1
- package/dist/routes/api/config/get.d.ts +0 -4
- package/dist/routes/api/config/get.d.ts.map +1 -1
- package/dist/routes/api/config/get.js +0 -2
- package/dist/routes/api/config/get.js.map +1 -1
- package/dist/routes/api/config/index.d.ts +0 -4
- package/dist/routes/api/config/index.d.ts.map +1 -1
- package/dist/routes/api/index.d.ts +0 -56
- package/dist/routes/api/index.d.ts.map +1 -1
- package/dist/routes/index.d.ts +0 -56
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/oauth/device/get-post.js +5 -5
- package/dist/routes/oauth/device/get-post.js.map +1 -1
- package/dist/schemas/error.d.ts +0 -25
- package/dist/schemas/error.d.ts.map +1 -1
- package/dist/schemas/error.js +0 -1
- package/dist/schemas/error.js.map +1 -1
- package/dist/schemas/response.d.ts +0 -24
- package/dist/schemas/response.d.ts.map +1 -1
- package/dist/schemas/response.js +0 -13
- package/dist/schemas/response.js.map +1 -1
- package/dist/seeders/config.seeder.js +0 -1
- package/dist/seeders/config.seeder.js.map +1 -1
- package/dist/services/container.d.ts +0 -3
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +0 -15
- package/dist/services/container.js.map +1 -1
- package/dist/services/oauth-client.service.d.ts +0 -1
- package/dist/services/oauth-client.service.d.ts.map +1 -1
- package/dist/services/oauth-client.service.js +2 -17
- package/dist/services/oauth-client.service.js.map +1 -1
- package/dist/services/oauth-connect.service.d.ts.map +1 -1
- package/dist/services/oauth-connect.service.js +0 -4
- package/dist/services/oauth-connect.service.js.map +1 -1
- package/dist/services/oauth-token.service.d.ts.map +1 -1
- package/dist/services/oauth-token.service.js +4 -4
- package/dist/services/oauth-token.service.js.map +1 -1
- package/dist/services/password-auth.service.d.ts.map +1 -1
- package/dist/services/password-auth.service.js +3 -12
- package/dist/services/password-auth.service.js.map +1 -1
- package/dist/services/security.service.d.ts +0 -8
- package/dist/services/security.service.d.ts.map +1 -1
- package/dist/services/security.service.js +21 -82
- package/dist/services/security.service.js.map +1 -1
- package/dist/services/totp.service.js +2 -2
- package/dist/services/totp.service.js.map +1 -1
- package/package.json +2 -1
- package/public/assets/2fa-6btYq1AL.js +2 -0
- package/public/assets/{2fa-C37MUkye.js.map → 2fa-6btYq1AL.js.map} +1 -1
- package/public/assets/2fa-D3ieXkuh.js +2 -0
- package/public/assets/{2fa-kiqzGSz2.js.map → 2fa-D3ieXkuh.js.map} +1 -1
- package/public/assets/2fa-Dxh4Kxy-.js +2 -0
- package/public/assets/{2fa-BgveHSB_.js.map → 2fa-Dxh4Kxy-.js.map} +1 -1
- package/public/assets/2fa-UcpXAI9J.js +2 -0
- package/public/assets/{2fa-UL_cNRnQ.js.map → 2fa-UcpXAI9J.js.map} +1 -1
- package/public/assets/{DialogHandle-Zvz8SgS0.js → DialogHandle-tiMUnjZQ.js} +2 -2
- package/public/assets/{DialogHandle-Zvz8SgS0.js.map → DialogHandle-tiMUnjZQ.js.map} +1 -1
- package/public/assets/admin-B8RQbf4_.js +2 -0
- package/public/assets/admin-B8RQbf4_.js.map +1 -0
- package/public/assets/admin-users-Dz1QNdy3.js +2 -0
- package/public/assets/{admin-users-CwTJdiih.js.map → admin-users-Dz1QNdy3.js.map} +1 -1
- package/public/assets/alert-leqyvHOp.js.map +1 -1
- package/public/assets/{auth-choice-row-BlSsUI7d.js → auth-choice-row-DWzfcZQY.js} +2 -2
- package/public/assets/{auth-choice-row-BlSsUI7d.js.map → auth-choice-row-DWzfcZQY.js.map} +1 -1
- package/public/assets/{auth-field-HwxENJnB.js → auth-field-DsLGh1U-.js} +2 -2
- package/public/assets/{auth-field-HwxENJnB.js.map → auth-field-DsLGh1U-.js.map} +1 -1
- package/public/assets/auth-layout-DGTylGtX.js +2 -0
- package/public/assets/auth-layout-DGTylGtX.js.map +1 -0
- package/public/assets/{auth-page-header-CIs08f5Y.js → auth-page-header-COvqWINf.js} +2 -2
- package/public/assets/auth-page-header-COvqWINf.js.map +1 -0
- package/public/assets/authorization-context-banner-DVx1TsPY.js +2 -0
- package/public/assets/authorization-context-banner-DVx1TsPY.js.map +1 -0
- package/public/assets/{avatar-CttWiIv3.js → avatar-BCLugfaZ.js} +2 -2
- package/public/assets/{avatar-CttWiIv3.js.map → avatar-BCLugfaZ.js.map} +1 -1
- package/public/assets/badge-CsOfUji0.js.map +1 -1
- package/public/assets/{checkbox-CJrRV8S1.js → checkbox-CFVDS3zJ.js} +2 -2
- package/public/assets/{checkbox-CJrRV8S1.js.map → checkbox-CFVDS3zJ.js.map} +1 -1
- package/public/assets/config-DTQCUlfZ.js +2 -0
- package/public/assets/config-DTQCUlfZ.js.map +1 -0
- package/public/assets/{consent-BIhxtXHx.js → consent-CKOohdYI.js} +2 -2
- package/public/assets/{consent-BIhxtXHx.js.map → consent-CKOohdYI.js.map} +1 -1
- package/public/assets/{consent-DRmENn26.js → consent-ChiWc7Ql.js} +2 -2
- package/public/assets/{consent-DRmENn26.js.map → consent-ChiWc7Ql.js.map} +1 -1
- package/public/assets/createLucideIcon-BPpAIXR_.js.map +1 -1
- package/public/assets/{email-CVRDeJ78.js → email-Crjg1dcr.js} +2 -2
- package/public/assets/{email-CVRDeJ78.js.map → email-Crjg1dcr.js.map} +1 -1
- package/public/assets/email-UcpXAI9J.js +2 -0
- package/public/assets/{email-UL_cNRnQ.js.map → email-UcpXAI9J.js.map} +1 -1
- package/public/assets/error-VfMv226c.js +2 -0
- package/public/assets/{error-2VPY5w8V.js.map → error-VfMv226c.js.map} +1 -1
- package/public/assets/{field-DDt6F9TZ.js → field-89zKYDVL.js} +2 -2
- package/public/assets/{field-DDt6F9TZ.js.map → field-89zKYDVL.js.map} +1 -1
- package/public/assets/forgot-Dr88fVMq.js +2 -0
- package/public/assets/{forgot-DzDcduho.js.map → forgot-Dr88fVMq.js.map} +1 -1
- package/public/assets/forgot-UcpXAI9J.js +2 -0
- package/public/assets/{forgot-UL_cNRnQ.js.map → forgot-UcpXAI9J.js.map} +1 -1
- package/public/assets/{index-DZyHRhbQ.css → index-CDD8owGK.css} +1 -1
- package/public/assets/index-CZ0rWM7l.js +11 -0
- package/public/assets/index-CZ0rWM7l.js.map +1 -0
- package/public/assets/{initial-avatar-CZzHAPm3.js → initial-avatar-ocwNWL38.js} +2 -2
- package/public/assets/{initial-avatar-CZzHAPm3.js.map → initial-avatar-ocwNWL38.js.map} +1 -1
- package/public/assets/{input-CNRpSR08.js → input-GPigtjgi.js} +2 -2
- package/public/assets/{input-CNRpSR08.js.map → input-GPigtjgi.js.map} +1 -1
- package/public/assets/{labeled-separator-fnKySKv2.js → labeled-separator-CV7nb0XW.js} +2 -2
- package/public/assets/{labeled-separator-fnKySKv2.js.map → labeled-separator-CV7nb0XW.js.map} +1 -1
- package/public/assets/link-C-WdTj3F.js.map +1 -1
- package/public/assets/login-CQeTLmIu.js +2 -0
- package/public/assets/login-CQeTLmIu.js.map +1 -0
- package/public/assets/login-UcpXAI9J.js +2 -0
- package/public/assets/login-UcpXAI9J.js.map +1 -0
- package/public/assets/{logout-CHdmF_16.js → logout-B5T52P8u.js} +2 -2
- package/public/assets/{logout-CHdmF_16.js.map → logout-B5T52P8u.js.map} +1 -1
- package/public/assets/{modal-sCM_zT82.js → modal-BV3gpI-p.js} +2 -2
- package/public/assets/{modal-sCM_zT82.js.map → modal-BV3gpI-p.js.map} +1 -1
- package/public/assets/{mutationOptions-CrswitPs.js → mutationOptions-DyYFUbyn.js} +2 -2
- package/public/assets/{mutationOptions-CrswitPs.js.map → mutationOptions-DyYFUbyn.js.map} +1 -1
- package/public/assets/passkey-Bf7n49Z7.js +2 -0
- package/public/assets/{passkey-CEx1VZ5R.js.map → passkey-Bf7n49Z7.js.map} +1 -1
- package/public/assets/passkey-CT3G7pCL.js +2 -0
- package/public/assets/{passkey-CU8x9J2w.js.map → passkey-CT3G7pCL.js.map} +1 -1
- package/public/assets/passkey-J1qnYp9A.js +2 -0
- package/public/assets/{passkey-B2Blw47e.js.map → passkey-J1qnYp9A.js.map} +1 -1
- package/public/assets/passkey-UcpXAI9J.js +2 -0
- package/public/assets/{passkey-UL_cNRnQ.js.map → passkey-UcpXAI9J.js.map} +1 -1
- package/public/assets/password-BKI5GTRs.js +2 -0
- package/public/assets/password-BKI5GTRs.js.map +1 -0
- package/public/assets/password-UcpXAI9J.js +2 -0
- package/public/assets/password-UcpXAI9J.js.map +1 -0
- package/public/assets/password-reset-sU5KkBKi.js +2 -0
- package/public/assets/{password-reset-CIacHnvA.js.map → password-reset-sU5KkBKi.js.map} +1 -1
- package/public/assets/{password-strength-C0Zkrrct.js → password-strength-DTWF07Px.js} +2 -2
- package/public/assets/{password-strength-C0Zkrrct.js.map → password-strength-DTWF07Px.js.map} +1 -1
- package/public/assets/{pin-input-BlD4tPZJ.js → pin-input-BGOLfkwL.js} +2 -2
- package/public/assets/{pin-input-BlD4tPZJ.js.map → pin-input-BGOLfkwL.js.map} +1 -1
- package/public/assets/{profile-D43Yq-6S.js → profile-DSTMtoUf.js} +2 -2
- package/public/assets/{profile-D43Yq-6S.js.map → profile-DSTMtoUf.js.map} +1 -1
- package/public/assets/profile-RpDmbWNA.js +2 -0
- package/public/assets/profile-RpDmbWNA.js.map +1 -0
- package/public/assets/provider-logos-u1YURWQr.js.map +1 -1
- package/public/assets/recovery-DbgpqG6f.js +2 -0
- package/public/assets/{recovery-CLExnfYX.js.map → recovery-DbgpqG6f.js.map} +1 -1
- package/public/assets/register-B2Lixapy.js +2 -0
- package/public/assets/{register-CZUyWXRO.js.map → register-B2Lixapy.js.map} +1 -1
- package/public/assets/register-UcpXAI9J.js +2 -0
- package/public/assets/{register-UL_cNRnQ.js.map → register-UcpXAI9J.js.map} +1 -1
- package/public/assets/reset-C-Qjl2Qy.js +2 -0
- package/public/assets/reset-C-Qjl2Qy.js.map +1 -0
- package/public/assets/reset-UcpXAI9J.js +2 -0
- package/public/assets/{reset-UL_cNRnQ.js.map → reset-UcpXAI9J.js.map} +1 -1
- package/public/assets/{select-CWdSzsVo.js → select-BKx4bF4A.js} +2 -2
- package/public/assets/{select-CWdSzsVo.js.map → select-BKx4bF4A.js.map} +1 -1
- package/public/assets/select-UcpXAI9J.js +2 -0
- package/public/assets/{select-UL_cNRnQ.js.map → select-UcpXAI9J.js.map} +1 -1
- package/public/assets/{separator-BWGym8uM.js → separator-B0Bvh1he.js} +2 -2
- package/public/assets/{separator-BWGym8uM.js.map → separator-B0Bvh1he.js.map} +1 -1
- package/public/assets/shell-header-bar-CgyNXbPS.js +2 -0
- package/public/assets/shell-header-bar-CgyNXbPS.js.map +1 -0
- package/public/assets/{terms-D43Yq-6S.js → terms-DSTMtoUf.js} +2 -2
- package/public/assets/{terms-D43Yq-6S.js.map → terms-DSTMtoUf.js.map} +1 -1
- package/public/assets/{terms-COVFmzyl.js → terms-Vgpg5IZK.js} +2 -2
- package/public/assets/{terms-COVFmzyl.js.map → terms-Vgpg5IZK.js.map} +1 -1
- package/public/assets/{terms-checkbox-list-Cw0zB-lO.js → terms-checkbox-list-DqbXU4qw.js} +2 -2
- package/public/assets/{terms-checkbox-list-Cw0zB-lO.js.map → terms-checkbox-list-DqbXU4qw.js.map} +1 -1
- package/public/assets/{totp-BfCm6IWl.js → totp-BNZ904Zm.js} +2 -2
- package/public/assets/{totp-BfCm6IWl.js.map → totp-BNZ904Zm.js.map} +1 -1
- package/public/assets/totp-Cjns-PoB.js +2 -0
- package/public/assets/{totp-BFJEXxk0.js.map → totp-Cjns-PoB.js.map} +1 -1
- package/public/assets/totp-g0-s50HZ.js +2 -0
- package/public/assets/{totp-MINhsVxT.js.map → totp-g0-s50HZ.js.map} +1 -1
- package/public/assets/use-totp-setup-CtTaklH-.js +3 -0
- package/public/assets/{use-totp-setup-C7Zk_2IY.js.map → use-totp-setup-CtTaklH-.js.map} +1 -1
- package/public/assets/{useAriaLabelledBy-CiOCg6X5.js → useAriaLabelledBy-7uIPXK-0.js} +2 -2
- package/public/assets/{useAriaLabelledBy-CiOCg6X5.js.map → useAriaLabelledBy-7uIPXK-0.js.map} +1 -1
- package/public/assets/{useMutation-ZLFeJg75.js → useMutation-BWZ0G4Td.js} +2 -2
- package/public/assets/{useMutation-ZLFeJg75.js.map → useMutation-BWZ0G4Td.js.map} +1 -1
- package/public/assets/useQuery-pOdkMV4B.js +2 -0
- package/public/assets/{useQuery-BvMz34BW.js.map → useQuery-pOdkMV4B.js.map} +1 -1
- package/public/assets/users-B1hvVo3B.js +2 -0
- package/public/assets/users-B1hvVo3B.js.map +1 -0
- package/public/index.html +4 -5
- package/dist/routes/api/auth/password/reset-required/post.d.ts +0 -18
- package/dist/routes/api/auth/password/reset-required/post.d.ts.map +0 -1
- package/dist/routes/api/auth/password/reset-required/post.js +0 -39
- package/dist/routes/api/auth/password/reset-required/post.js.map +0 -1
- package/dist/services/legacy-credential-retirement.service.d.ts +0 -20
- package/dist/services/legacy-credential-retirement.service.d.ts.map +0 -1
- package/dist/services/legacy-credential-retirement.service.js +0 -90
- package/dist/services/legacy-credential-retirement.service.js.map +0 -1
- package/public/assets/2fa-BgveHSB_.js +0 -2
- package/public/assets/2fa-C37MUkye.js +0 -2
- package/public/assets/2fa-UL_cNRnQ.js +0 -2
- package/public/assets/2fa-kiqzGSz2.js +0 -2
- package/public/assets/admin-DbDuu6AI.js +0 -2
- package/public/assets/admin-DbDuu6AI.js.map +0 -1
- package/public/assets/admin-users-CwTJdiih.js +0 -2
- package/public/assets/auth-layout-CoeqNhTT.js +0 -2
- package/public/assets/auth-layout-CoeqNhTT.js.map +0 -1
- package/public/assets/auth-page-header-CIs08f5Y.js.map +0 -1
- package/public/assets/authorization-context-banner-BbtQmMYH.js +0 -2
- package/public/assets/authorization-context-banner-BbtQmMYH.js.map +0 -1
- package/public/assets/config-v3-oy_ef.js +0 -2
- package/public/assets/config-v3-oy_ef.js.map +0 -1
- package/public/assets/email-UL_cNRnQ.js +0 -2
- package/public/assets/error-2VPY5w8V.js +0 -2
- package/public/assets/forgot-DzDcduho.js +0 -2
- package/public/assets/forgot-UL_cNRnQ.js +0 -2
- package/public/assets/index-gliHKncz.js +0 -11
- package/public/assets/index-gliHKncz.js.map +0 -1
- package/public/assets/link-BN90emXr.js +0 -2
- package/public/assets/link-BN90emXr.js.map +0 -1
- package/public/assets/lock-keyhole-Cz72xkCn.js +0 -2
- package/public/assets/lock-keyhole-Cz72xkCn.js.map +0 -1
- package/public/assets/login-C6m2qSUt.js +0 -2
- package/public/assets/login-C6m2qSUt.js.map +0 -1
- package/public/assets/login-UL_cNRnQ.js +0 -2
- package/public/assets/login-UL_cNRnQ.js.map +0 -1
- package/public/assets/passkey-B2Blw47e.js +0 -2
- package/public/assets/passkey-CEx1VZ5R.js +0 -2
- package/public/assets/passkey-CU8x9J2w.js +0 -2
- package/public/assets/passkey-UL_cNRnQ.js +0 -2
- package/public/assets/password-BhU_a0cR.js +0 -2
- package/public/assets/password-BhU_a0cR.js.map +0 -1
- package/public/assets/password-UL_cNRnQ.js +0 -2
- package/public/assets/password-UL_cNRnQ.js.map +0 -1
- package/public/assets/password-reset-CIacHnvA.js +0 -2
- package/public/assets/profile-D1cEjfs8.js +0 -2
- package/public/assets/profile-D1cEjfs8.js.map +0 -1
- package/public/assets/recovery-CLExnfYX.js +0 -2
- package/public/assets/register-CZUyWXRO.js +0 -2
- package/public/assets/register-UL_cNRnQ.js +0 -2
- package/public/assets/reset-N3RQTYEB.js +0 -2
- package/public/assets/reset-N3RQTYEB.js.map +0 -1
- package/public/assets/reset-UL_cNRnQ.js +0 -2
- package/public/assets/reset-required-Cv5edDS6.js +0 -2
- package/public/assets/reset-required-Cv5edDS6.js.map +0 -1
- package/public/assets/reset-required-UL_cNRnQ.js +0 -2
- package/public/assets/reset-required-UL_cNRnQ.js.map +0 -1
- package/public/assets/select-UL_cNRnQ.js +0 -2
- package/public/assets/shell-header-bar-C9AB5lT-.js +0 -2
- package/public/assets/shell-header-bar-C9AB5lT-.js.map +0 -1
- package/public/assets/totp-BFJEXxk0.js +0 -2
- package/public/assets/totp-MINhsVxT.js +0 -2
- package/public/assets/use-totp-setup-C7Zk_2IY.js +0 -3
- package/public/assets/useQuery-BvMz34BW.js +0 -2
- package/public/assets/users-COM7u3A-.js +0 -2
- package/public/assets/users-COM7u3A-.js.map +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,U as t,Z as n,i as r,n as i,q as a,r as o,s,t as c}from"./createLucideIcon-BPpAIXR_.js";import{Dn as l,i as u,n as d,r as f,sr as p,t as m}from"./config-v3-oy_ef.js";import{t as h}from"./mutationOptions-CrswitPs.js";import{t as g}from"./useMutation-ZLFeJg75.js";import{A as _,D as v,t as y,tt as b}from"./shell-header-bar-C9AB5lT-.js";import{t as x}from"./useQuery-BvMz34BW.js";import{a as S,i as C,n as w,r as T,t as E}from"./use-totp-setup-C7Zk_2IY.js";import{t as D}from"./auth-field-HwxENJnB.js";import{t as O}from"./fingerprint-pattern-DP62Vk8x.js";import{t as k}from"./key-round-CdvHb8vT.js";import{i as A}from"./provider-logos-u1YURWQr.js";import{n as ee,t as te}from"./logout-CHdmF_16.js";import{t as j}from"./shield-check-D_p8H0ni.js";import{t as M}from"./trash-2-DZdKBLvC.js";import{t as N}from"./triangle-alert-CqNn0kPs.js";import{t as P}from"./zod-C87S6Tec.js";import{B as F,C as ne,R as I,S as L,T as re,w as R,x as ie,z}from"./index-gliHKncz.js";import{t as ae}from"./badge-CsOfUji0.js";import{t as oe}from"./auth-page-header-CIs08f5Y.js";import{t as B}from"./alert-leqyvHOp.js";import{t as se}from"./initial-avatar-CZzHAPm3.js";import{t as V}from"./promise-OpBtq8tG.js";import{n as H,t as U}from"./modal-sCM_zT82.js";import{a as W,i as G,n as K,r as q}from"./passkey-B2Blw47e.js";import{r as J,t as Y}from"./standard-schema-e8gtSzGE.js";import{n as ce,r as le}from"./totp-BfCm6IWl.js";var ue=c(`cloud`,[[`path`,{d:`M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z`,key:`p7xjir`}]]),de=c(`link-2-off`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7`,key:`10o201`}],[`path`,{d:`M15 7h2a5 5 0 0 1 4 8`,key:`1d3206`}],[`line`,{x1:`8`,x2:`12`,y1:`12`,y2:`12`,key:`rvw6j4`}],[`line`,{x1:`2`,x2:`22`,y1:`2`,y2:`22`,key:`a6p6uj`}]]),fe=c(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]),pe=c(`settings`,[[`path`,{d:`M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915`,key:`1i5ecw`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),me=c(`smartphone`,[[`rect`,{width:`14`,height:`20`,x:`5`,y:`2`,rx:`2`,ry:`2`,key:`1yt0o3`}],[`path`,{d:`M12 18h.01`,key:`mhygvu`}]]),X=n(e(),1),Z=a();function he({isConfigManaged:e,isDeletionEnabled:t,onDeleteClick:n}){let{t:a}=r();return t?(0,Z.jsxs)(F.Root,{className:`border-tinyrack-danger-border bg-tinyrack-danger-surface`,variant:`outlined`,children:[(0,Z.jsxs)(F.Header,{className:`border-tinyrack-danger-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-tinyrack-sm`,children:[(0,Z.jsx)(N,{"aria-hidden":!0,className:`size-tinyrack-lg text-tinyrack-danger`}),(0,Z.jsx)(F.Title,{className:`text-tinyrack-danger`,children:a(`profile.dangerZone.title`)})]}),(0,Z.jsx)(F.Description,{children:a(`profile.dangerZone.description`)})]}),(0,Z.jsx)(F.Content,{className:`px-tinyrack-lg py-tinyrack-md`,children:(0,Z.jsxs)(`div`,{className:`flex items-center justify-between gap-tinyrack-lg`,children:[(0,Z.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-tinyrack-3xs`,children:[(0,Z.jsx)(i,{as:`p`,variant:`bodySm`,weight:`medium`,children:a(`profile.deleteAccount.title`)}),(0,Z.jsx)(i,{as:`p`,color:`muted`,variant:`caption`,children:a(e?`profile.deleteAccount.configManaged`:`profile.deleteAccount.description`)})]}),(0,Z.jsxs)(s,{appearance:`outline`,"data-testid":`profile-delete-account`,disabled:e,intent:`danger`,onClick:n,type:`button`,uiSize:`sm`,children:[(0,Z.jsx)(M,{"aria-hidden":!0,className:`size-tinyrack-lg`}),a(`profile.deleteAccount.button`)]})]})})]}):null}function Q({icon:e,active:t,title:n,status:r,note:a,actions:o}){let s;return s=(0,X.isValidElement)(e)?e:(0,Z.jsx)(e,{"aria-hidden":!0,className:`size-tinyrack-lg ${t?`text-tinyrack-success`:`text-tinyrack-text-muted`}`}),(0,Z.jsxs)(`div`,{className:`flex items-center justify-between gap-tinyrack-lg p-tinyrack-lg`,children:[(0,Z.jsxs)(`div`,{className:`flex min-w-0 flex-1 items-center gap-tinyrack-md`,children:[(0,Z.jsx)(`div`,{className:`flex size-9 shrink-0 items-center justify-center rounded-tinyrack-md ${t?`bg-tinyrack-success-surface`:`bg-tinyrack-surface-muted`}`,children:s}),(0,Z.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-tinyrack-3xs`,children:[(0,Z.jsx)(i,{as:`div`,variant:`bodySm`,weight:`medium`,children:n}),(0,Z.jsx)(i,{as:`div`,color:`muted`,variant:`caption`,children:r}),a]})]}),o&&(0,Z.jsx)(`div`,{className:`flex shrink-0 flex-wrap justify-end gap-tinyrack-xs`,children:o})]})}function ge({providers:e,unlinkingProvider:t,getAuthorizeUrl:n,onUnlinkRequest:i}){let{t:a}=r();return e.length===0?null:(0,Z.jsxs)(F.Root,{variant:`outlined`,children:[(0,Z.jsxs)(F.Header,{className:`border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md`,children:[(0,Z.jsx)(F.Title,{children:a(`profile.linkedAccounts.title`)}),(0,Z.jsx)(F.Description,{children:a(`profile.linkedAccounts.description`)})]}),(0,Z.jsx)(F.Content,{className:`divide-y divide-tinyrack-border p-0`,children:e.map(e=>(0,Z.jsx)(Q,{actions:e.linked?(0,Z.jsx)(s,{appearance:`ghost`,intent:`danger`,loading:t===e.id,loadingLabel:a(`profile.linkedAccounts.unlinking`),onClick:()=>i(e),type:`button`,uiSize:`sm`,children:t===e.id?void 0:a(`profile.linkedAccounts.unlink`)}):(0,Z.jsx)(z,{appearance:`outline`,intent:`neutral`,render:(0,Z.jsx)(`a`,{href:n(e.id,`link`,`/profile`)}),uiSize:`sm`,children:a(`profile.linkedAccounts.link`)}),active:e.linked,icon:(0,Z.jsx)(A,{className:`size-tinyrack-lg`,iconUrl:e.icon_url,providerId:e.id}),status:e.linked?a(`profile.linkedAccounts.connected`):a(`profile.linkedAccounts.notConnected`),title:e.display_name},e.id))})]})}function _e({passkeyCount:e,onOpenModal:t}){let{t:n}=r(),i=e>0;return(0,Z.jsx)(Q,{actions:(0,Z.jsx)(s,{appearance:`ghost`,intent:`primary`,onClick:()=>t(i?`manage`:`setup`),type:`button`,uiSize:`sm`,children:n(i?`profile.passkey.manage`:`profile.passkey.add`)}),active:i,icon:O,status:i?n(`profile.passkey.status.enabled`,{count:e}):n(`profile.passkey.status.disabled`),title:n(`profile.passkey.title`)})}function ve({hasPassword:e,hasLinkedOAuth:t,isConfigManaged:n,hasSecondFactorOnly:a,onOpenModal:o}){let{t:c}=r();return(0,Z.jsx)(Q,{actions:n?void 0:e?(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(s,{appearance:`ghost`,"data-testid":`profile-password-change`,intent:`primary`,onClick:()=>o(`change`),type:`button`,uiSize:`sm`,children:c(`profile.password.change`)}),t?(0,Z.jsx)(s,{appearance:`ghost`,"data-testid":`profile-password-remove`,intent:`danger`,onClick:()=>o(`remove`),type:`button`,uiSize:`sm`,children:c(`profile.password.remove`)}):null,!t&&a&&(0,Z.jsxs)(v.Root,{children:[(0,Z.jsx)(v.Trigger,{render:(0,Z.jsx)(s,{appearance:`ghost`,disabled:!0,type:`button`,uiSize:`sm`,children:c(`profile.password.remove`)})}),(0,Z.jsx)(v.Portal,{children:(0,Z.jsx)(v.Positioner,{children:(0,Z.jsx)(v.Popup,{className:`max-w-tinyrack-measure-lg rounded-tinyrack-md border border-tinyrack-border bg-tinyrack-surface p-tinyrack-md text-tinyrack-text text-tinyrack-xs shadow-tinyrack-overlay`,children:(0,Z.jsxs)(`div`,{className:`flex items-start gap-tinyrack-sm`,children:[(0,Z.jsx)(S,{"aria-hidden":!0,className:`size-tinyrack-lg shrink-0 text-tinyrack-warning`}),(0,Z.jsx)(`div`,{children:c(`profile.password.removeDisabledReason`)})]})})})})]})]}):(0,Z.jsx)(s,{appearance:`ghost`,"data-testid":`profile-password-set`,intent:`primary`,onClick:()=>o(`set`),type:`button`,uiSize:`sm`,children:c(`profile.password.set`)}),active:e,icon:k,note:n?(0,Z.jsxs)(i,{as:`div`,className:`flex items-center gap-tinyrack-xs`,color:`muted`,variant:`caption`,children:[(0,Z.jsx)(pe,{"aria-hidden":!0,className:`size-tinyrack-md shrink-0`}),(0,Z.jsx)(`span`,{children:c(`profile.password.configManaged`)})]}):void 0,status:c(e?`profile.password.status.set`:`profile.password.status.notSet`),title:c(`profile.password.title`)})}function ye({totpEnabled:e,recoveryCodesMissing:t,onOpenModal:n}){let{t:i}=r();return(0,Z.jsx)(Q,{actions:e?(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(s,{appearance:`ghost`,"data-testid":`profile-totp-regenerate`,intent:`primary`,onClick:()=>n(`regenerate`),type:`button`,uiSize:`sm`,children:i(`profile.totp.regenerate`)}),(0,Z.jsx)(s,{appearance:`ghost`,"data-testid":`profile-totp-disable`,intent:`danger`,onClick:()=>n(`disable`),type:`button`,uiSize:`sm`,children:i(`profile.totp.disable`)})]}):(0,Z.jsx)(s,{appearance:`ghost`,"data-testid":`profile-totp-enable`,intent:`primary`,onClick:()=>n(`setup`),type:`button`,uiSize:`sm`,children:i(`profile.totp.enable`)}),active:e,icon:j,status:i(e?t?`profile.totp.status.recoveryCodesMissing`:`profile.totp.status.enabled`:`profile.totp.status.disabled`),title:i(`profile.totp.title`)})}var be={error:I,warning:N,info:S};function $({variant:e,children:t}){return(0,Z.jsx)(B,{"data-testid":`alert-banner-${e}`,icon:be[e],type:e,children:t})}function xe({isOpen:e,onClose:t,providerName:n,isPending:i,onConfirm:a}){let{t:o}=r(),[c,l]=(0,X.useState)(null),u=()=>{i||(l(null),t())};return(0,Z.jsx)(U,{description:o(`profile.linkedAccounts.unlinkModal.description`,{provider:n}),icon:de,isOpen:e,onClose:u,preventClose:i,title:o(`profile.linkedAccounts.unlinkModal.title`),variant:`destructive`,children:(0,Z.jsxs)(`div`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,children:[(0,Z.jsx)($,{variant:`warning`,children:o(`profile.linkedAccounts.unlinkModal.warning`,{provider:n})}),c&&(0,Z.jsx)($,{variant:`error`,children:c}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`unlink-oauth-cancel`,disabled:i,intent:`neutral`,onClick:u,type:`button`,uiSize:`sm`,children:o(`profile.linkedAccounts.unlinkModal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`unlink-oauth-unlink`,disabled:i,intent:`danger`,loading:i,loadingLabel:o(`profile.linkedAccounts.unlinking`),onClick:async()=>{l(null);try{await a(),u()}catch{l(o(`profile.linkedAccounts.unlinkError`))}},type:`button`,uiSize:`sm`,children:o(`profile.linkedAccounts.unlink`)})]})]})})}function Se({label:e,value:t}){return(0,Z.jsxs)(`div`,{className:`flex items-center justify-between gap-tinyrack-lg px-tinyrack-lg py-tinyrack-md`,children:[(0,Z.jsx)(i,{className:`shrink-0`,color:`muted`,variant:`caption`,children:e}),(0,Z.jsx)(i,{truncate:!0,variant:`bodySm`,weight:`medium`,children:t})]})}function Ce({user:e}){let{t}=r();return(0,Z.jsxs)(F.Root,{variant:`outlined`,children:[(0,Z.jsxs)(F.Header,{className:`border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md`,children:[(0,Z.jsx)(F.Title,{children:t(`profile.account.title`)}),(0,Z.jsx)(F.Description,{children:t(`profile.account.description`)})]}),(0,Z.jsxs)(F.Content,{className:`divide-y divide-tinyrack-border p-0`,children:[(0,Z.jsx)(Se,{label:t(`profile.id.label`),value:e.sub}),(0,Z.jsx)(Se,{label:t(`profile.email.label`),value:e.email})]})]})}function we({children:e,headerActions:t}){return(0,Z.jsxs)(`div`,{className:`flex min-h-dvh flex-col bg-tinyrack-surface`,children:[(0,Z.jsx)(_,{}),(0,Z.jsx)(y,{actions:t,brand:!0}),(0,Z.jsx)(`main`,{className:`flex flex-1 justify-center px-tinyrack-lg py-tinyrack-xl`,children:(0,Z.jsx)(`div`,{className:`auth-enter flex w-full max-w-tinyrack-overlay-md flex-col gap-tinyrack-xl`,children:e})})]})}var Te=h({mutationFn:async e=>u(await f.api.user.password.$post({json:e}))}),Ee=h({mutationFn:async e=>u(await f.api.user.password.$put({json:e}))}),De=h({mutationFn:async e=>u(await f.api.user.password.$delete({json:e}))});function Oe({isOpen:e,onClose:t}){let{t:n}=r(),i=p(),{data:a}=b(m),c=a.auth.password.policy,l=J({resolver:Y((0,X.useMemo)(()=>P.object({currentPassword:P.string().min(1,n(`validation.password.required`)),newPassword:P.string().min(c.min_length,n(`validation.password.min`,{count:c.min_length})).max(c.max_length,n(`validation.password.max`,{count:c.max_length})),confirmPassword:P.string()}).refine(e=>e.newPassword===e.confirmPassword,{message:n(`validation.confirmPassword.mismatch`),path:[`confirmPassword`]}),[c.max_length,c.min_length,n])),defaultValues:{currentPassword:``,newPassword:``,confirmPassword:``}}),u=g({...Ee,onSuccess:()=>{i.invalidateQueries({queryKey:L.queryKey}),d()}}),d=()=>{l.reset(),t()},f=l.handleSubmit(async e=>{try{await u.mutateAsync({current_password:e.currentPassword,new_password:e.newPassword})}catch(e){e instanceof o&&e.code===`INVALID_CURRENT_PASSWORD`?l.setError(`currentPassword`,{message:n(`profile.password.changeModal.invalidCurrent`)}):l.setError(`root`,{message:n(`profile.password.changeModal.error`)})}});return(0,Z.jsx)(U,{description:n(`profile.password.changeModal.description`),icon:k,isOpen:e,onClose:d,title:n(`profile.password.changeModal.title`),children:(0,Z.jsxs)(`form`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,onSubmit:f,children:[(0,Z.jsx)(D,{error:l.formState.errors.currentPassword,errorTestId:`change-password-error-currentPassword`,id:`current-password`,label:n(`profile.password.changeModal.currentPassword`),placeholder:n(`profile.password.changeModal.currentPasswordPlaceholder`),...l.register(`currentPassword`),type:`password`}),(0,Z.jsx)(D,{error:l.formState.errors.newPassword,errorTestId:`change-password-error-newPassword`,id:`new-password-change`,label:n(`profile.password.changeModal.newPassword`),placeholder:n(`profile.password.changeModal.newPasswordPlaceholder`),...l.register(`newPassword`),type:`password`}),(0,Z.jsx)(D,{error:l.formState.errors.confirmPassword,errorTestId:`change-password-error-confirmPassword`,id:`confirm-password-change`,label:n(`profile.password.changeModal.confirmPassword`),placeholder:n(`profile.password.changeModal.confirmPasswordPlaceholder`),...l.register(`confirmPassword`),type:`password`}),l.formState.errors.root&&(0,Z.jsx)($,{variant:`error`,children:l.formState.errors.root.message}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`change-password-cancel`,disabled:u.isPending,intent:`neutral`,onClick:d,type:`button`,uiSize:`sm`,children:n(`profile.password.changeModal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`change-password-submit`,disabled:u.isPending,intent:`primary`,loading:u.isPending,loadingLabel:n(`profile.password.changeModal.submitting`),type:`submit`,uiSize:`sm`,children:u.isPending?void 0:n(`profile.password.changeModal.submit`)})]})]})})}var ke=h({mutationFn:async()=>u(await f.api.user.$delete())});function Ae({isOpen:e,onClose:t,retentionDays:n}){let{t:i}=r(),a=l(),o=p(),c=J({resolver:Y((0,X.useMemo)(()=>P.object({confirmation:P.string().refine(e=>e.toLowerCase()===i(`profile.deleteAccount.modal.confirmPlaceholder`).toLowerCase(),{message:i(`validation.confirmText.mismatch`)})}),[i])),defaultValues:{confirmation:``}}),u=g({...ke,onSuccess:async()=>{o.setQueryData(L.queryKey,{user:null}),await V(),a.navigate({to:`/login`})}}),d=()=>{u.isPending||(c.reset(),t())},f=c.handleSubmit(async()=>{try{await u.mutateAsync()}catch{c.setError(`root`,{message:i(`profile.deleteAccount.error`)})}});return(0,Z.jsx)(U,{icon:M,isOpen:e,onClose:d,preventClose:u.isPending,title:i(`profile.deleteAccount.modal.title`),variant:`destructive`,children:(0,Z.jsxs)(`form`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,onSubmit:f,children:[(0,Z.jsx)($,{variant:`error`,children:(0,Z.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-xs`,children:[(0,Z.jsx)(`p`,{children:i(`profile.deleteAccount.modal.description`,{days:n})}),(0,Z.jsx)(`p`,{className:`text-tinyrack-xs opacity-tinyrack-hover`,children:i(`profile.deleteAccount.modal.warning`)})]})}),(0,Z.jsx)(D,{autoComplete:`off`,error:c.formState.errors.confirmation,errorTestId:`delete-account-error`,id:`delete-confirmation`,label:i(`profile.deleteAccount.modal.confirmLabel`),placeholder:i(`profile.deleteAccount.modal.confirmPlaceholder`),...c.register(`confirmation`),type:`text`}),c.formState.errors.root&&(0,Z.jsx)($,{variant:`error`,children:c.formState.errors.root.message}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`delete-account-cancel`,disabled:u.isPending,intent:`neutral`,onClick:d,type:`button`,uiSize:`sm`,children:i(`profile.deleteAccount.modal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`delete-account-submit`,disabled:u.isPending,intent:`danger`,loading:u.isPending,loadingLabel:i(`profile.deleteAccount.modal.confirming`),type:`submit`,uiSize:`sm`,children:u.isPending?void 0:i(`profile.deleteAccount.modal.confirm`)})]})]})})}function je({isOpen:e,onClose:t}){let{t:n}=r(),i=p(),a=J({resolver:Y((0,X.useMemo)(()=>P.object({code:P.string().length(6,n(`validation.totp.length`)).regex(/^\d{6}$/,n(`validation.totp.digits`))}),[n])),defaultValues:{code:``}}),c=g({...ce,onSuccess:()=>{i.invalidateQueries({queryKey:L.queryKey}),l()}}),l=()=>{a.reset(),t()},u=a.handleSubmit(async e=>{try{await c.mutateAsync({code:e.code})}catch(e){if(e instanceof o&&e.code===`CANNOT_REMOVE_LAST_SECOND_FACTOR`){a.setError(`code`,{message:n(`profile.totp.disableModal.cannotRemoveLastSecondFactor`)});return}a.setError(`code`,{message:n(`profile.totp.disableModal.error`)})}});return(0,Z.jsx)(U,{description:n(`profile.totp.disableModal.description`),icon:j,isOpen:e,onClose:l,title:n(`profile.totp.disableModal.title`),variant:`destructive`,children:(0,Z.jsxs)(`form`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,onSubmit:u,children:[(0,Z.jsx)($,{variant:`warning`,children:n(`profile.totp.disableModal.warning`)}),(0,Z.jsx)(D,{autoComplete:`one-time-code`,error:a.formState.errors.code,errorTestId:`disable-totp-error`,id:`disable-totp-code`,inputMode:`numeric`,label:n(`profile.totp.disableModal.codeLabel`),maxLength:6,pattern:`[0-9]*`,placeholder:`000000`,...a.register(`code`),type:`text`}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`disable-totp-cancel`,disabled:c.isPending,intent:`neutral`,onClick:l,type:`button`,uiSize:`sm`,children:n(`profile.totp.disableModal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`disable-totp-submit`,disabled:c.isPending,intent:`danger`,loading:c.isPending,loadingLabel:n(`profile.totp.disableModal.disabling`),type:`submit`,uiSize:`sm`,children:c.isPending?void 0:n(`profile.totp.disableModal.disable`)})]})]})})}function Me({isOpen:e,onClose:n,onAddNew:i}){let{t:a}=r(),c=p(),[l,u]=(0,X.useState)(null),[f,m]=(0,X.useState)(null),[h,_]=(0,X.useState)(null),[v,y]=(0,X.useState)(null),{data:b,isLoading:S}=x({...q,enabled:e}),C=g({...K,onSuccess:()=>{c.invalidateQueries({queryKey:d.passkeys()}),c.invalidateQueries({queryKey:L.queryKey})},onSettled:()=>{m(null)}}),w=(0,X.useCallback)(()=>{u(null),m(null),_(null),y(null),n()},[n]),T=e=>{_(e.id),y(null)},E=()=>{_(null),y(null)},D=async e=>{m(e.id),_(null);try{await C.mutateAsync({id:e.id})}catch(e){if(e instanceof o&&e.code===`CANNOT_REMOVE_LAST_SECOND_FACTOR`){y(a(`profile.passkey.manageModal.cannotRemoveLastSecondFactor`));return}y(a(`profile.passkey.manageModal.deleteError`))}},k=e=>new Date(e).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`}),A=b?.passkeys||[];return(0,Z.jsxs)(U,{icon:O,isOpen:e,onClose:w,size:`lg`,title:a(`profile.passkey.manageModal.title`),children:[(0,Z.jsxs)(`div`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-sm`,children:[v&&(0,Z.jsx)($,{variant:`error`,children:v}),S&&(0,Z.jsx)(`div`,{className:`flex justify-center py-tinyrack-xl`,children:(0,Z.jsx)(t,{uiSize:`md`})}),!S&&A.length===0&&(0,Z.jsx)(`div`,{className:`py-tinyrack-xl text-center text-tinyrack-sm text-tinyrack-text-muted`,"data-testid":`passkeys-empty`,children:(0,Z.jsx)(`p`,{children:a(`profile.passkey.manageModal.noPasskeys`)})}),!S&&A.length>0&&(0,Z.jsx)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:A.map(e=>(0,Z.jsx)(Ne,{formatDate:k,isConfirmingDelete:h===e.id,isDeleting:f===e.id,isEditing:l?.id===e.id,onCancelDelete:E,onCancelEdit:()=>u(null),onConfirmDelete:()=>D(e),onEdit:()=>u(e),onRequestDelete:()=>T(e),passkey:e},e.id))})]}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`manage-passkeys-close`,intent:`neutral`,onClick:w,type:`button`,uiSize:`sm`,children:a(`profile.passkey.manageModal.close`)}),(0,Z.jsx)(s,{"data-testid":`manage-passkeys-add-new`,intent:`primary`,onClick:()=>{w(),i()},type:`button`,uiSize:`sm`,children:a(`profile.passkey.manageModal.addNew`)})]})]})}function Ne({passkey:e,isDeleting:t,isEditing:n,isConfirmingDelete:i,onEdit:a,onCancelEdit:o,onRequestDelete:c,onConfirmDelete:l,onCancelDelete:u,formatDate:f}){let{t:m}=r(),h=p(),_=J({resolver:Y((0,X.useMemo)(()=>P.object({name:P.string().min(1,m(`validation.passkey.name.required`)).max(100,m(`validation.passkey.name.max`))}),[m])),defaultValues:{name:e.name||``}}),v=g({...W,onSuccess:()=>{h.invalidateQueries({queryKey:d.passkeys()}),o()}}),y=_.handleSubmit(async t=>{try{await v.mutateAsync({id:e.id,name:t.name})}catch{_.setError(`name`,{message:m(`profile.passkey.manageModal.renameError`)})}});return n?(0,Z.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-xs rounded-tinyrack-md bg-tinyrack-surface-muted p-tinyrack-sm`,onSubmit:y,children:[(0,Z.jsx)(D,{"data-testid":`passkey-rename-input`,error:_.formState.errors.name,errorTestId:`passkey-rename-error`,hideLabel:!0,label:m(`profile.passkey.manageModal.nameLabel`),placeholder:m(`profile.passkey.manageModal.namePlaceholder`),..._.register(`name`),type:`text`}),(0,Z.jsxs)(`div`,{className:`flex justify-end gap-tinyrack-xs`,children:[(0,Z.jsx)(s,{appearance:`ghost`,disabled:v.isPending,onClick:()=>{_.reset(),o()},type:`button`,uiSize:`sm`,children:m(`profile.passkey.manageModal.cancelEdit`)}),(0,Z.jsx)(s,{disabled:v.isPending,intent:`primary`,type:`submit`,uiSize:`sm`,children:v.isPending?m(`profile.passkey.manageModal.saving`):m(`profile.passkey.manageModal.save`)})]})]}):i?(0,Z.jsxs)(`div`,{className:`flex items-center justify-between rounded-tinyrack-md border border-tinyrack-danger-border bg-tinyrack-danger-surface p-tinyrack-sm text-tinyrack-on-danger`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-tinyrack-sm`,children:[(0,Z.jsx)(M,{className:`size-tinyrack-lg`}),(0,Z.jsx)(`span`,{className:`text-tinyrack-xs`,children:m(`profile.passkey.manageModal.deleteConfirmInline`)})]}),(0,Z.jsxs)(`div`,{className:`flex gap-tinyrack-xs`,children:[(0,Z.jsx)(s,{appearance:`ghost`,onClick:u,type:`button`,uiSize:`sm`,children:m(`profile.passkey.manageModal.cancelEdit`)}),(0,Z.jsx)(s,{intent:`danger`,onClick:l,type:`button`,uiSize:`sm`,children:m(`profile.passkey.manageModal.delete`)})]})]}):(0,Z.jsxs)(`div`,{className:`flex items-center justify-between rounded-tinyrack-md bg-tinyrack-surface-muted p-tinyrack-sm`,"data-testid":`passkey-item`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-tinyrack-sm`,children:[e.device_type===`multiDevice`?(0,Z.jsx)(ue,{className:`size-tinyrack-lg text-tinyrack-primary`}):(0,Z.jsx)(me,{className:`size-tinyrack-lg text-tinyrack-primary`}),(0,Z.jsxs)(`div`,{children:[(0,Z.jsx)(`div`,{className:`font-tinyrack-medium text-tinyrack-xs`,children:e.name||m(`profile.passkey.manageModal.unnamedPasskey`)}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-tinyrack-xs text-tinyrack-text-muted text-tinyrack-xs`,children:[(0,Z.jsx)(`span`,{children:m(`profile.passkey.manageModal.createdAt`,{date:f(e.created_at)})}),e.backed_up&&(0,Z.jsx)(ae,{uiSize:`md`,variant:`success`,children:m(`profile.passkey.manageModal.backedUp`)})]})]})]}),(0,Z.jsxs)(`div`,{className:`flex gap-tinyrack-xs`,children:[(0,Z.jsx)(s,{appearance:`ghost`,"aria-label":m(`profile.passkey.manageModal.rename`),onClick:a,type:`button`,uiSize:`sm`,children:(0,Z.jsx)(fe,{className:`size-tinyrack-lg`})}),(0,Z.jsx)(s,{appearance:`ghost`,"aria-label":m(`profile.passkey.manageModal.delete`),disabled:t,intent:`danger`,loading:t,onClick:c,type:`button`,uiSize:`sm`,children:t?void 0:(0,Z.jsx)(M,{className:`size-tinyrack-lg`})})]})]})}function Pe({isOpen:e,onClose:t}){let{t:n}=r(),i=l(),a=p(),{data:s}=b(m),[c,u]=(0,X.useState)(`verify`),[d,f]=(0,X.useState)(null),[h,_]=(0,X.useState)(null),v=g({...le,onSuccess:async e=>{f(e),u(`recovery`),await a.invalidateQueries({queryKey:L.queryKey})}}),y=(0,X.useCallback)(()=>{u(`verify`),f(null),_(null),v.reset()},[v]),x=(0,X.useCallback)(()=>{y(),t()},[t,y]),S=(0,X.useCallback)(async e=>{_(null);try{await v.mutateAsync({code:e})}catch(e){if(e instanceof o){if(e.code===`INVALID_TOTP_CODE`)throw e;if(e.code===`UNAUTHORIZED`){a.setQueryData(L.queryKey,{user:null}),await V(),i.navigate({to:`/login`});return}if(e.code===`TOTP_NOT_ENABLED`||e.code===`VALIDATION_ERROR`){await a.invalidateQueries({queryKey:L.queryKey}),x();return}}_(n(`profile.totp.regenerateModal.unexpectedError`))}},[x,v,a,i,n]);return s.auth.password.totp.enabled?(0,Z.jsx)(U,{description:n(c===`verify`?`profile.totp.regenerateModal.description`:`profile.totp.regenerateModal.recoveryDescription`),icon:j,isOpen:e,onClose:x,preventClose:c===`recovery`,size:`sm`,title:n(c===`verify`?`profile.totp.regenerateModal.title`:`profile.totp.regenerateModal.recoveryTitle`),children:c===`verify`?(0,Z.jsxs)(`div`,{className:`mt-tinyrack-lg`,children:[h&&(0,Z.jsx)(`div`,{className:`mb-tinyrack-md`,children:(0,Z.jsx)($,{variant:`error`,children:h})}),(0,Z.jsx)(T,{invalidMessage:n(`profile.totp.regenerateModal.error`),isPending:v.isPending,onSubmit:S,pendingText:n(`profile.totp.regenerateModal.submitting`),submitLabel:n(`profile.totp.regenerateModal.submit`)})]}):(0,Z.jsx)(`div`,{className:`mt-tinyrack-lg`,children:(0,Z.jsx)(C,{onConfirm:x,recoveryCodes:d?.recovery_codes??[]})})}):null}function Fe({isOpen:e,onClose:t}){let{t:n}=r(),i=p(),a=J({resolver:Y((0,X.useMemo)(()=>P.object({currentPassword:P.string().min(1,n(`validation.password.required`))}),[n])),defaultValues:{currentPassword:``}}),c=g({...De,onSuccess:()=>{i.invalidateQueries({queryKey:L.queryKey}),l()}}),l=()=>{a.reset(),t()},u=a.handleSubmit(async e=>{try{await c.mutateAsync({current_password:e.currentPassword})}catch(e){if(e instanceof o){if(e.code===`INVALID_CURRENT_PASSWORD`){a.setError(`currentPassword`,{message:n(`profile.password.removeModal.invalidCurrent`)});return}if(e.code===`CANNOT_REMOVE_LAST_AUTH_METHOD`){a.setError(`root`,{message:n(`profile.password.removeModal.noOAuth`)});return}if(e.code===`CANNOT_REMOVE_PASSWORD_WITH_SECOND_FACTOR_ONLY`){a.setError(`root`,{message:n(`profile.password.removeModal.noOAuthWith2FA`)});return}}a.setError(`root`,{message:n(`profile.password.removeModal.error`)})}});return(0,Z.jsx)(U,{description:n(`profile.password.removeModal.description`),icon:k,isOpen:e,onClose:l,title:n(`profile.password.removeModal.title`),variant:`destructive`,children:(0,Z.jsxs)(`form`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,onSubmit:u,children:[(0,Z.jsx)(D,{error:a.formState.errors.currentPassword,errorTestId:`remove-password-error`,id:`current-password-remove`,label:n(`profile.password.removeModal.currentPassword`),placeholder:n(`profile.password.removeModal.currentPasswordPlaceholder`),...a.register(`currentPassword`),type:`password`}),a.formState.errors.root&&(0,Z.jsx)($,{variant:`error`,children:a.formState.errors.root.message}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`remove-password-cancel`,disabled:c.isPending,intent:`neutral`,onClick:l,type:`button`,uiSize:`sm`,children:n(`profile.password.removeModal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`remove-password-submit`,disabled:c.isPending,intent:`danger`,loading:c.isPending,loadingLabel:n(`profile.password.removeModal.submitting`),type:`submit`,uiSize:`sm`,children:c.isPending?void 0:n(`profile.password.removeModal.submit`)})]})]})})}function Ie({isOpen:e,onClose:t}){let{t:n}=r(),i=p(),{data:a}=b(m),o=a.auth.password.policy,c=J({resolver:Y((0,X.useMemo)(()=>P.object({password:P.string().min(o.min_length,n(`validation.password.min`,{count:o.min_length})).max(o.max_length,n(`validation.password.max`,{count:o.max_length})),confirmPassword:P.string()}).refine(e=>e.password===e.confirmPassword,{message:n(`validation.confirmPassword.mismatch`),path:[`confirmPassword`]}),[o.max_length,o.min_length,n])),defaultValues:{password:``,confirmPassword:``}}),l=g({...Te,onSuccess:()=>{i.invalidateQueries({queryKey:L.queryKey}),u()}}),u=()=>{c.reset(),t()},d=c.handleSubmit(async e=>{try{await l.mutateAsync({password:e.password})}catch{c.setError(`root`,{message:n(`profile.password.setModal.error`)})}});return(0,Z.jsx)(U,{description:n(`profile.password.setModal.description`),icon:k,isOpen:e,onClose:u,title:n(`profile.password.setModal.title`),children:(0,Z.jsxs)(`form`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,onSubmit:d,children:[(0,Z.jsx)(D,{error:c.formState.errors.password,errorTestId:`set-password-error-password`,id:`new-password`,label:n(`profile.password.setModal.newPassword`),placeholder:n(`profile.password.setModal.newPasswordPlaceholder`),...c.register(`password`),type:`password`}),(0,Z.jsx)(D,{error:c.formState.errors.confirmPassword,errorTestId:`set-password-error-confirmPassword`,id:`confirm-password`,label:n(`profile.password.setModal.confirmPassword`),placeholder:n(`profile.password.setModal.confirmPasswordPlaceholder`),...c.register(`confirmPassword`),type:`password`}),c.formState.errors.root&&(0,Z.jsx)($,{variant:`error`,children:c.formState.errors.root.message}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`set-password-cancel`,disabled:l.isPending,intent:`neutral`,onClick:u,type:`button`,uiSize:`sm`,children:n(`profile.password.setModal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`set-password-submit`,disabled:l.isPending,intent:`primary`,loading:l.isPending,loadingLabel:n(`profile.password.setModal.submitting`),type:`submit`,uiSize:`sm`,children:l.isPending?void 0:n(`profile.password.setModal.submit`)})]})]})})}function Le({isOpen:e,onClose:n,isRequired:i=!1,canSwitchToTotp:a=!1,onSwitchToTotp:o}){let{t:c}=r(),l=p(),[u,f]=(0,X.useState)(`name`),[m,h]=(0,X.useState)(null),_=J({resolver:Y((0,X.useMemo)(()=>P.object({name:P.string().max(100,c(`validation.passkey.name.max`)).optional().transform(e=>e?.trim()||void 0)}),[c])),defaultValues:{name:``}}),v=g({...G,onSuccess:()=>{l.invalidateQueries({queryKey:d.passkeys()}),l.invalidateQueries({queryKey:L.queryKey}),y()},onError:e=>{f(`name`),e.name===`NotAllowedError`?h(c(`profile.passkey.setupModal.cancelled`)):h(c(`profile.passkey.setupModal.error`))}}),y=(0,X.useCallback)(()=>{_.reset(),f(`name`),h(null),n()},[_,n]),b=_.handleSubmit(async e=>{f(`register`),h(null);try{await v.mutateAsync({name:e.name})}catch{}}),x=v.isPending;return(0,Z.jsxs)(U,{description:i?c(`profile.passkey.setupModal.requiredDescription`):void 0,icon:O,isOpen:e,onClose:y,preventClose:i,size:`sm`,title:c(`profile.passkey.setupModal.title`),children:[u===`name`&&(0,Z.jsxs)(`form`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,onSubmit:b,children:[(0,Z.jsx)(`p`,{className:`text-tinyrack-text-muted text-tinyrack-xs`,children:c(`profile.passkey.setupModal.description`)}),m&&(0,Z.jsx)($,{variant:`error`,children:m}),(0,Z.jsx)(D,{error:_.formState.errors.name,errorTestId:`setup-passkey-error`,hint:c(`profile.passkey.setupModal.nameHint`),id:`passkey-name`,label:c(`profile.passkey.setupModal.nameLabel`),placeholder:c(`profile.passkey.setupModal.namePlaceholder`),..._.register(`name`),type:`text`}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`setup-passkey-cancel`,intent:`neutral`,onClick:y,type:`button`,uiSize:`sm`,children:c(`profile.passkey.setupModal.cancel`)}),(0,Z.jsx)(s,{"data-testid":`setup-passkey-continue`,intent:`primary`,type:`submit`,uiSize:`sm`,children:c(`profile.passkey.setupModal.continue`)})]}),a&&o&&(0,Z.jsx)(`p`,{className:`mt-tinyrack-sm text-center text-tinyrack-xs`,children:(0,Z.jsx)(s,{appearance:`ghost`,intent:`primary`,onClick:o,type:`button`,uiSize:`sm`,children:c(`profile.passkey.setupModal.switchToTotp`)})})]}),u===`register`&&(0,Z.jsxs)(`div`,{className:`mt-tinyrack-lg`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-col items-center gap-tinyrack-md py-tinyrack-xl`,"data-testid":`setup-passkey-loading`,children:[(0,Z.jsx)(t,{uiSize:`md`}),(0,Z.jsx)(`p`,{className:`text-center text-tinyrack-text-muted text-tinyrack-xs`,children:c(`profile.passkey.setupModal.waitingForDevice`)})]}),(0,Z.jsx)(H,{children:(0,Z.jsx)(s,{appearance:`outline`,"data-testid":`setup-passkey-cancel`,disabled:x,intent:`neutral`,onClick:y,type:`button`,uiSize:`sm`,children:c(`profile.passkey.setupModal.cancel`)})})]})]})}function Re({isOpen:e,onClose:n,isRequired:i=!1,canSwitchToPasskey:a=!1,onSwitchToPasskey:o}){let{t:c}=r(),{step:l,setupData:u,recoveryCodes:d,isSetupPending:f,isVerifyPending:p,isConfirmPending:m,startSetup:h,verify:g,goToVerify:_,goToQr:v,confirmRecoveryCodes:y,reset:b}=E({autoStart:!1,onConfirmSuccess:()=>{b(),n()}}),x=(0,X.useCallback)(()=>{b(),n()},[n,b]),S=(0,X.useCallback)(()=>{!u&&!f&&h()},[u,f,h]);e&&!u&&!f&&l!==`error`&&S();let D=(0,X.useCallback)(async e=>{await g(e)},[g]),O=c(l===`recovery`?`setupTotp.recoveryCodes.title`:`profile.totp.setupModal.title`);return(0,Z.jsxs)(U,{description:i?c(`profile.totp.setupModal.requiredDescription`):void 0,icon:j,isOpen:e,onClose:x,preventClose:i||l===`recovery`,size:`sm`,title:O,children:[f&&(0,Z.jsx)(`div`,{className:`flex justify-center py-tinyrack-xl`,"data-testid":`setup-totp-loading`,children:(0,Z.jsx)(t,{uiSize:`md`})}),l===`error`&&(0,Z.jsxs)(`div`,{className:`mt-tinyrack-lg flex flex-col gap-tinyrack-md`,children:[(0,Z.jsx)($,{variant:`error`,children:c(`profile.totp.setupModal.setupError`)}),(0,Z.jsxs)(H,{children:[(0,Z.jsx)(s,{appearance:`outline`,intent:`neutral`,onClick:x,type:`button`,uiSize:`sm`,children:c(`profile.totp.setupModal.cancel`)}),(0,Z.jsx)(s,{intent:`primary`,onClick:h,type:`button`,uiSize:`sm`,children:c(`profile.totp.setupModal.retry`)})]})]}),u&&l===`qr`&&(0,Z.jsx)(`div`,{className:`mt-tinyrack-lg`,children:(0,Z.jsx)(w,{additionalActions:(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(H,{children:(0,Z.jsx)(s,{appearance:`outline`,intent:`neutral`,onClick:x,type:`button`,uiSize:`sm`,children:c(`profile.totp.setupModal.cancel`)})}),a&&o&&(0,Z.jsx)(`p`,{className:`mt-tinyrack-sm text-center text-tinyrack-xs`,children:(0,Z.jsx)(s,{appearance:`ghost`,intent:`primary`,onClick:o,type:`button`,uiSize:`sm`,children:c(`profile.totp.setupModal.switchToPasskey`)})})]}),onNext:_,setupData:u})}),u&&l===`verify`&&(0,Z.jsx)(`div`,{className:`mt-tinyrack-lg`,children:(0,Z.jsx)(T,{isPending:p,onBack:v,onSubmit:D})}),l===`recovery`&&d.length>0&&(0,Z.jsx)(`div`,{className:`mt-tinyrack-lg`,children:(0,Z.jsx)(C,{isLoading:m,onConfirm:y,recoveryCodes:d})})]})}var ze={access_denied:`oauth.error.accessDenied`,temporarily_unavailable:`oauth.error.temporarilyUnavailable`,server_error:`oauth.error.serverError`};function Be(){let{t:e}=r(),t=l(),n=p(),a=ie.useSearch().oauth_error,o=a?e(ze[a]??`oauth.error.failed`):void 0,[c,u]=(0,X.useState)(null),[d,f]=(0,X.useState)(null),[h,_]=(0,X.useState)(null),[v,y]=(0,X.useState)(null),[x,S]=(0,X.useState)(null),[C,w]=(0,X.useState)(!1),{data:T}=b(L),{data:E}=b(R),{data:D}=b(m),O=g({...te,onSuccess:async()=>{n.setQueryData(L.queryKey,{user:null}),await V(),t.navigate({to:`/login`})},onSettled:()=>{n.invalidateQueries({queryKey:L.queryKey})}}),k=g({...re,onSuccess:()=>{n.invalidateQueries({queryKey:R.queryKey})},onSettled:()=>{u(null)}}),A=async()=>{d&&(u(d.id),await k.mutateAsync(d.id))};if(!T.user)return null;let j=T.user,M=E.available_providers,N=M.some(e=>e.linked),P=j.managed_by===`config`,z=D.auth.password,ae=D.auth.passkey,H=z.totp.enabled,U=ae.enabled,W=D.account_deletion.enabled,G=D.account_deletion.retention,K=(()=>{let e=G.match(/^(\d+)([dmy])$/);if(!e)return 30;let t=parseInt(e[1],10);switch(e[2]){case`d`:return t;case`m`:return t*30;case`y`:return t*365;default:return 30}})(),q=!P&&H,J=!P&&U,Y=M.length>0;return(0,Z.jsxs)(we,{headerActions:(0,Z.jsx)(s,{appearance:`ghost`,"aria-label":e(`profile.logout`),"data-testid":`profile-logout`,disabled:O.isPending,loading:O.isPending,onClick:()=>O.mutate(),type:`button`,uiSize:`sm`,children:O.isPending?void 0:(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(ee,{"aria-hidden":!0,className:`size-tinyrack-lg`}),(0,Z.jsx)(`span`,{className:`hidden sm:inline`,children:e(`profile.logout`)})]})}),children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-tinyrack-lg`,children:[(0,Z.jsx)(se,{email:j.email,size:`lg`}),(0,Z.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-tinyrack-3xs`,children:[(0,Z.jsx)(oe,{title:e(`profile.title`)}),(0,Z.jsx)(i,{as:`p`,color:`muted`,"data-testid":`profile-user-email`,truncate:!0,variant:`bodySm`,children:j.email})]})]}),o&&(0,Z.jsx)(B,{icon:I,type:`error`,children:o}),j&&(0,Z.jsx)(Ce,{user:j}),(0,Z.jsxs)(F.Root,{variant:`outlined`,children:[(0,Z.jsxs)(F.Header,{className:`border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md`,children:[(0,Z.jsx)(F.Title,{children:e(`profile.security.title`)}),(0,Z.jsx)(F.Description,{children:e(`profile.security.description`)})]}),q&&j.totp_recovery_codes_missing&&(0,Z.jsx)(`div`,{className:`border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md`,"data-testid":`profile-totp-recovery-warning`,children:(0,Z.jsx)(B,{icon:I,type:`warning`,children:e(`profile.totp.recoveryCodesMissing`)})}),(0,Z.jsxs)(F.Content,{className:`divide-y divide-tinyrack-border p-0`,children:[(0,Z.jsx)(ve,{hasLinkedOAuth:N,hasPassword:j.has_password,hasSecondFactorOnly:j.has_password&&!N&&(j.totp_registered||j.passkey_count>0),isConfigManaged:P,onOpenModal:_}),q&&(0,Z.jsx)(ye,{onOpenModal:y,recoveryCodesMissing:j.totp_recovery_codes_missing,totpEnabled:j.totp_registered}),J&&(0,Z.jsx)(_e,{onOpenModal:S,passkeyCount:j.passkey_count})]})]}),Y&&(0,Z.jsx)(ge,{getAuthorizeUrl:ne,onUnlinkRequest:e=>f({id:e.id,name:e.display_name}),providers:M,unlinkingProvider:c}),(0,Z.jsx)(he,{isConfigManaged:P,isDeletionEnabled:W,onDeleteClick:()=>w(!0)}),(0,Z.jsx)(Ie,{isOpen:h===`set`,onClose:()=>_(null)}),(0,Z.jsx)(Oe,{isOpen:h===`change`,onClose:()=>_(null)}),(0,Z.jsx)(Fe,{isOpen:h===`remove`,onClose:()=>_(null)}),(0,Z.jsx)(Re,{isOpen:v===`setup`,onClose:()=>y(null)}),(0,Z.jsx)(je,{isOpen:v===`disable`,onClose:()=>y(null)}),(0,Z.jsx)(Pe,{isOpen:v===`regenerate`,onClose:()=>y(null)}),(0,Z.jsx)(Le,{isOpen:x===`setup`,onClose:()=>S(null)}),(0,Z.jsx)(Me,{isOpen:x===`manage`,onAddNew:()=>S(`setup`),onClose:()=>S(null)}),(0,Z.jsx)(xe,{isOpen:d!==null,isPending:k.isPending,onClose:()=>f(null),onConfirm:A,providerName:d?.name??``}),(0,Z.jsx)(Ae,{isOpen:C,onClose:()=>w(!1),retentionDays:K})]})}export{Be as component};
|
|
2
|
-
//# sourceMappingURL=profile-D1cEjfs8.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"profile-D1cEjfs8.js","names":["__iconNode","__iconNode","__iconNode","__iconNode","useMutation","useQueryClient","useSuspenseQuery","useRouter","TRButton","TRCard","TRText","CircleAlertIcon","LogOutIcon","useState","useTranslation","AuthPageHeader","DangerZoneSection","LinkedAccountsSection","PasskeySection","PasswordSection","TotpSection","UnlinkOAuthModal","UserInfoSection","Alert","InitialAvatar","AppLayout","ChangePasswordModal","DeleteAccountModal","DisableTotpModal","ManagePasskeysModal","RegenerateTotpRecoveryCodesModal","RemovePasswordModal","SetPasswordModal","SetupPasskeyModal","SetupTotpModal","tick","appConfigQueryOptions","logoutMutationOptions","getOAuthAuthorizeUrl","oauthAccountsQueryOptions","unlinkOAuthMutationOptions","getSessionQueryOptions","PasswordModalType","TotpModalType","PasskeyModalType","OAUTH_ERROR_I18N_MAP","Record","access_denied","temporarily_unavailable","server_error","Route","Profile","t","router","queryClient","search","useSearch","oauthError","oauth_error","oauthErrorMessage","undefined","unlinkingProvider","setUnlinkingProvider","unlinkModal","setUnlinkModal","id","name","passwordModal","setPasswordModal","totpModal","setTotpModal","passkeyModal","setPasskeyModal","showDeleteModal","setShowDeleteModal","data","session","oauthAccountsData","appConfig","logoutMutation","onSuccess","setQueryData","queryKey","user","navigate","to","onSettled","invalidateQueries","unlinkMutation","handleUnlinkConfirm","mutateAsync","availableProviders","available_providers","hasLinkedOAuth","some","p","linked","isConfigManaged","managed_by","passwordAuthMethod","auth","password","passkeyAuthMethod","passkey","totpEnabled","totp","enabled","passkeyEnabled","accountDeletionEnabled","account_deletion","retentionPeriod","retention","retentionDays","match","value","parseInt","unit","showPasswordSection","showTotpSection","showPasskeySection","showLinkedAccounts","length","hasSecurityOptions","isPending","mutate","email","totp_recovery_codes_missing","has_password","totp_registered","passkey_count","provider","display_name","component"],"sources":["../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/cloud.mjs","../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/link-2-off.mjs","../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/pencil.mjs","../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/settings.mjs","../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/smartphone.mjs","../../../frontend/src/components/profile/danger-zone-section.tsx","../../../frontend/src/components/profile/security-row.tsx","../../../frontend/src/components/profile/linked-accounts-section.tsx","../../../frontend/src/components/profile/passkey-section.tsx","../../../frontend/src/components/profile/password-section.tsx","../../../frontend/src/components/profile/totp-section.tsx","../../../frontend/src/components/ui/alert-banner.tsx","../../../frontend/src/components/profile/unlink-oauth-modal.tsx","../../../frontend/src/components/profile/user-info-section.tsx","../../../frontend/src/features/layout/app-layout.tsx","../../../frontend/src/queries/password.ts","../../../frontend/src/features/profile/change-password-modal.tsx","../../../frontend/src/queries/account.ts","../../../frontend/src/features/profile/delete-account-modal.tsx","../../../frontend/src/features/profile/disable-totp-modal.tsx","../../../frontend/src/features/profile/manage-passkeys-modal.tsx","../../../frontend/src/features/profile/regenerate-totp-recovery-codes-modal.tsx","../../../frontend/src/features/profile/remove-password-modal.tsx","../../../frontend/src/features/profile/set-password-modal.tsx","../../../frontend/src/features/profile/setup-passkey-modal.tsx","../../../frontend/src/features/profile/setup-totp-modal.tsx","../../../frontend/src/routes/profile/index.tsx?tsr-split=component"],"sourcesContent":["/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z\", key: \"p7xjir\" }]\n];\nconst Cloud = createLucideIcon(\"cloud\", __iconNode);\n\nexport { __iconNode, Cloud as default };\n//# sourceMappingURL=cloud.mjs.map\n","/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M9 17H7A5 5 0 0 1 7 7\", key: \"10o201\" }],\n [\"path\", { d: \"M15 7h2a5 5 0 0 1 4 8\", key: \"1d3206\" }],\n [\"line\", { x1: \"8\", x2: \"12\", y1: \"12\", y2: \"12\", key: \"rvw6j4\" }],\n [\"line\", { x1: \"2\", x2: \"22\", y1: \"2\", y2: \"22\", key: \"a6p6uj\" }]\n];\nconst Link2Off = createLucideIcon(\"link-2-off\", __iconNode);\n\nexport { __iconNode, Link2Off as default };\n//# sourceMappingURL=link-2-off.mjs.map\n","/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\",\n key: \"1a8usu\"\n }\n ],\n [\"path\", { d: \"m15 5 4 4\", key: \"1mk7zo\" }]\n];\nconst Pencil = createLucideIcon(\"pencil\", __iconNode);\n\nexport { __iconNode, Pencil as default };\n//# sourceMappingURL=pencil.mjs.map\n","/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\",\n key: \"1i5ecw\"\n }\n ],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }]\n];\nconst Settings = createLucideIcon(\"settings\", __iconNode);\n\nexport { __iconNode, Settings as default };\n//# sourceMappingURL=settings.mjs.map\n","/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"14\", height: \"20\", x: \"5\", y: \"2\", rx: \"2\", ry: \"2\", key: \"1yt0o3\" }],\n [\"path\", { d: \"M12 18h.01\", key: \"mhygvu\" }]\n];\nconst Smartphone = createLucideIcon(\"smartphone\", __iconNode);\n\nexport { __iconNode, Smartphone as default };\n//# sourceMappingURL=smartphone.mjs.map\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { TRCard } from '@tinyrack/ui/components/card';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport { Trash2Icon, TriangleAlertIcon } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\n\ninterface DangerZoneSectionProps {\n isConfigManaged: boolean;\n isDeletionEnabled: boolean;\n onDeleteClick: () => void;\n}\n\nexport function DangerZoneSection({\n isConfigManaged,\n isDeletionEnabled,\n onDeleteClick,\n}: DangerZoneSectionProps) {\n const { t } = useTranslation();\n\n if (!isDeletionEnabled) {\n return null;\n }\n\n return (\n <TRCard.Root\n className=\"border-tinyrack-danger-border bg-tinyrack-danger-surface\"\n variant=\"outlined\"\n >\n <TRCard.Header className=\"border-tinyrack-danger-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md\">\n <div className=\"flex items-center gap-tinyrack-sm\">\n <TriangleAlertIcon\n aria-hidden\n className=\"size-tinyrack-lg text-tinyrack-danger\"\n />\n <TRCard.Title className=\"text-tinyrack-danger\">\n {t('profile.dangerZone.title')}\n </TRCard.Title>\n </div>\n <TRCard.Description>\n {t('profile.dangerZone.description')}\n </TRCard.Description>\n </TRCard.Header>\n <TRCard.Content className=\"px-tinyrack-lg py-tinyrack-md\">\n <div className=\"flex items-center justify-between gap-tinyrack-lg\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-tinyrack-3xs\">\n <TRText as=\"p\" variant=\"bodySm\" weight=\"medium\">\n {t('profile.deleteAccount.title')}\n </TRText>\n <TRText as=\"p\" color=\"muted\" variant=\"caption\">\n {isConfigManaged\n ? t('profile.deleteAccount.configManaged')\n : t('profile.deleteAccount.description')}\n </TRText>\n </div>\n <TRButton\n appearance=\"outline\"\n data-testid=\"profile-delete-account\"\n disabled={isConfigManaged}\n intent=\"danger\"\n onClick={onDeleteClick}\n type=\"button\"\n uiSize=\"sm\"\n >\n <Trash2Icon aria-hidden className=\"size-tinyrack-lg\" />\n {t('profile.deleteAccount.button')}\n </TRButton>\n </div>\n </TRCard.Content>\n </TRCard.Root>\n );\n}\n","import { TRText } from '@tinyrack/ui/components/text';\nimport type { LucideIcon } from 'lucide-react';\nimport { isValidElement, type ReactNode } from 'react';\n\ntype SecurityRowProps = {\n /**\n * A lucide glyph, which gets tinted with the row's state, or a ready-made\n * node for marks that carry their own colour — a provider's brand logo.\n */\n icon: LucideIcon | ReactNode;\n /** Tints the icon tile. \"Configured\" rather than \"enabled\" — a linked OAuth\n * account and a set password are both active states. */\n active: boolean;\n title: string;\n status: string;\n /** Secondary line under the status, e.g. a config-managed caveat. */\n note?: ReactNode;\n /** Trailing controls. */\n actions?: ReactNode;\n};\n\n/**\n * One credential the account has, or does not.\n *\n * Password, TOTP, passkeys, and each linked provider were four copies of the\n * same row — a tinted icon tile, a title, a status line, a trailing action\n * cluster — which is how they drifted into three different paddings.\n */\nexport function SecurityRow({\n icon,\n active,\n title,\n status,\n note,\n actions,\n}: SecurityRowProps) {\n /*\n Discriminated by `isValidElement`, not `typeof … === 'function'`: lucide\n icons are `forwardRef` objects, so a typeof check reads them as data and\n React then throws on rendering `{$$typeof, render}` as a child. An\n already-rendered mark is an element; a component is not.\n */\n let mark: ReactNode;\n if (isValidElement(icon)) {\n mark = icon;\n } else {\n const Icon = icon as LucideIcon;\n mark = (\n <Icon\n aria-hidden\n className={`size-tinyrack-lg ${\n active ? 'text-tinyrack-success' : 'text-tinyrack-text-muted'\n }`}\n />\n );\n }\n\n return (\n <div className=\"flex items-center justify-between gap-tinyrack-lg p-tinyrack-lg\">\n <div className=\"flex min-w-0 flex-1 items-center gap-tinyrack-md\">\n <div\n className={`flex size-9 shrink-0 items-center justify-center rounded-tinyrack-md ${\n active ? 'bg-tinyrack-success-surface' : 'bg-tinyrack-surface-muted'\n }`}\n >\n {mark}\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col gap-tinyrack-3xs\">\n <TRText as=\"div\" variant=\"bodySm\" weight=\"medium\">\n {title}\n </TRText>\n <TRText as=\"div\" color=\"muted\" variant=\"caption\">\n {status}\n </TRText>\n {note}\n </div>\n </div>\n {actions && (\n <div className=\"flex shrink-0 flex-wrap justify-end gap-tinyrack-xs\">\n {actions}\n </div>\n )}\n </div>\n );\n}\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { TRCard } from '@tinyrack/ui/components/card';\nimport { TRLinkButton } from '@tinyrack/ui/components/link-button';\nimport { useTranslation } from 'react-i18next';\nimport { ProviderMark } from '#frontend/components/auth/provider-logos.tsx';\nimport { SecurityRow } from '#frontend/components/profile/security-row.tsx';\n\ninterface OAuthProvider {\n id: string;\n display_name: string;\n icon_url?: string;\n linked: boolean;\n}\n\ninterface LinkedAccountsSectionProps {\n providers: OAuthProvider[];\n unlinkingProvider: string | null;\n getAuthorizeUrl: (\n providerId: string,\n mode?: 'login' | 'register' | 'link',\n returnUrl?: string,\n ) => string;\n onUnlinkRequest: (provider: OAuthProvider) => void;\n}\n\nexport function LinkedAccountsSection({\n providers,\n unlinkingProvider,\n getAuthorizeUrl,\n onUnlinkRequest,\n}: LinkedAccountsSectionProps) {\n const { t } = useTranslation();\n\n if (providers.length === 0) {\n return null;\n }\n\n return (\n <TRCard.Root variant=\"outlined\">\n <TRCard.Header className=\"border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md\">\n <TRCard.Title>{t('profile.linkedAccounts.title')}</TRCard.Title>\n <TRCard.Description>\n {t('profile.linkedAccounts.description')}\n </TRCard.Description>\n </TRCard.Header>\n <TRCard.Content className=\"divide-y divide-tinyrack-border p-0\">\n {providers.map((provider) => (\n <SecurityRow\n actions={\n provider.linked ? (\n <TRButton\n appearance=\"ghost\"\n intent=\"danger\"\n loading={unlinkingProvider === provider.id}\n loadingLabel={t('profile.linkedAccounts.unlinking')}\n onClick={() => onUnlinkRequest(provider)}\n type=\"button\"\n uiSize=\"sm\"\n >\n {unlinkingProvider !== provider.id\n ? t('profile.linkedAccounts.unlink')\n : undefined}\n </TRButton>\n ) : (\n <TRLinkButton\n appearance=\"outline\"\n intent=\"neutral\"\n render={\n <a\n href={getAuthorizeUrl(provider.id, 'link', '/profile')}\n />\n }\n uiSize=\"sm\"\n >\n {t('profile.linkedAccounts.link')}\n </TRLinkButton>\n )\n }\n active={provider.linked}\n /*\n The real brand mark, not a generic link glyph. The sign-in screen\n shows the Google logo; showing a chain link for the same provider\n on a screen the user reaches minutes later reads as a different\n product.\n */\n icon={\n <ProviderMark\n className=\"size-tinyrack-lg\"\n iconUrl={provider.icon_url}\n providerId={provider.id}\n />\n }\n key={provider.id}\n status={\n provider.linked\n ? t('profile.linkedAccounts.connected')\n : t('profile.linkedAccounts.notConnected')\n }\n title={provider.display_name}\n />\n ))}\n </TRCard.Content>\n </TRCard.Root>\n );\n}\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { FingerprintIcon } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { SecurityRow } from '#frontend/components/profile/security-row.tsx';\n\ntype PasskeyModalType = 'setup' | 'manage' | null;\n\ninterface PasskeySectionProps {\n passkeyCount: number;\n onOpenModal: (type: PasskeyModalType) => void;\n}\n\nexport function PasskeySection({\n passkeyCount,\n onOpenModal,\n}: PasskeySectionProps) {\n const { t } = useTranslation();\n const hasPasskeys = passkeyCount > 0;\n\n return (\n <SecurityRow\n actions={\n <TRButton\n appearance=\"ghost\"\n intent=\"primary\"\n onClick={() => onOpenModal(hasPasskeys ? 'manage' : 'setup')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {hasPasskeys ? t('profile.passkey.manage') : t('profile.passkey.add')}\n </TRButton>\n }\n active={hasPasskeys}\n icon={FingerprintIcon}\n status={\n hasPasskeys\n ? t('profile.passkey.status.enabled', { count: passkeyCount })\n : t('profile.passkey.status.disabled')\n }\n title={t('profile.passkey.title')}\n />\n );\n}\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport { TRTooltip } from '@tinyrack/ui/components/tooltip';\nimport { InfoIcon, KeyRoundIcon, SettingsIcon } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { SecurityRow } from '#frontend/components/profile/security-row.tsx';\n\ntype PasswordModalType = 'set' | 'change' | 'remove' | null;\n\ninterface PasswordSectionProps {\n hasPassword: boolean;\n hasLinkedOAuth: boolean;\n isConfigManaged: boolean;\n hasSecondFactorOnly: boolean;\n onOpenModal: (type: PasswordModalType) => void;\n}\n\nexport function PasswordSection({\n hasPassword,\n hasLinkedOAuth,\n isConfigManaged,\n hasSecondFactorOnly,\n onOpenModal,\n}: PasswordSectionProps) {\n const { t } = useTranslation();\n\n return (\n <SecurityRow\n actions={\n isConfigManaged ? undefined : hasPassword ? (\n <>\n <TRButton\n appearance=\"ghost\"\n data-testid=\"profile-password-change\"\n intent=\"primary\"\n onClick={() => onOpenModal('change')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.change')}\n </TRButton>\n {hasLinkedOAuth ? (\n <TRButton\n appearance=\"ghost\"\n data-testid=\"profile-password-remove\"\n intent=\"danger\"\n onClick={() => onOpenModal('remove')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.remove')}\n </TRButton>\n ) : null}\n {!hasLinkedOAuth && hasSecondFactorOnly && (\n <TRTooltip.Root>\n <TRTooltip.Trigger\n render={\n <TRButton\n appearance=\"ghost\"\n disabled\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.remove')}\n </TRButton>\n }\n />\n <TRTooltip.Portal>\n <TRTooltip.Positioner>\n <TRTooltip.Popup className=\"max-w-tinyrack-measure-lg rounded-tinyrack-md border border-tinyrack-border bg-tinyrack-surface p-tinyrack-md text-tinyrack-text text-tinyrack-xs shadow-tinyrack-overlay\">\n <div className=\"flex items-start gap-tinyrack-sm\">\n <InfoIcon\n aria-hidden\n className=\"size-tinyrack-lg shrink-0 text-tinyrack-warning\"\n />\n <div>{t('profile.password.removeDisabledReason')}</div>\n </div>\n </TRTooltip.Popup>\n </TRTooltip.Positioner>\n </TRTooltip.Portal>\n </TRTooltip.Root>\n )}\n </>\n ) : (\n <TRButton\n appearance=\"ghost\"\n data-testid=\"profile-password-set\"\n intent=\"primary\"\n onClick={() => onOpenModal('set')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.set')}\n </TRButton>\n )\n }\n active={hasPassword}\n icon={KeyRoundIcon}\n note={\n isConfigManaged ? (\n <TRText\n as=\"div\"\n className=\"flex items-center gap-tinyrack-xs\"\n color=\"muted\"\n variant=\"caption\"\n >\n <SettingsIcon aria-hidden className=\"size-tinyrack-md shrink-0\" />\n <span>{t('profile.password.configManaged')}</span>\n </TRText>\n ) : undefined\n }\n status={\n hasPassword\n ? t('profile.password.status.set')\n : t('profile.password.status.notSet')\n }\n title={t('profile.password.title')}\n />\n );\n}\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { ShieldCheckIcon } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { SecurityRow } from '#frontend/components/profile/security-row.tsx';\n\ntype TotpModalType = 'setup' | 'disable' | 'regenerate' | null;\n\ninterface TotpSectionProps {\n totpEnabled: boolean;\n recoveryCodesMissing: boolean;\n onOpenModal: (type: TotpModalType) => void;\n}\n\nexport function TotpSection({\n totpEnabled,\n recoveryCodesMissing,\n onOpenModal,\n}: TotpSectionProps) {\n const { t } = useTranslation();\n\n return (\n <SecurityRow\n actions={\n totpEnabled ? (\n <>\n <TRButton\n appearance=\"ghost\"\n data-testid=\"profile-totp-regenerate\"\n intent=\"primary\"\n onClick={() => onOpenModal('regenerate')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.regenerate')}\n </TRButton>\n <TRButton\n appearance=\"ghost\"\n data-testid=\"profile-totp-disable\"\n intent=\"danger\"\n onClick={() => onOpenModal('disable')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.disable')}\n </TRButton>\n </>\n ) : (\n <TRButton\n appearance=\"ghost\"\n data-testid=\"profile-totp-enable\"\n intent=\"primary\"\n onClick={() => onOpenModal('setup')}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.enable')}\n </TRButton>\n )\n }\n active={totpEnabled}\n icon={ShieldCheckIcon}\n status={\n totpEnabled\n ? recoveryCodesMissing\n ? t('profile.totp.status.recoveryCodesMissing')\n : t('profile.totp.status.enabled')\n : t('profile.totp.status.disabled')\n }\n title={t('profile.totp.title')}\n />\n );\n}\n","import { CircleAlertIcon, InfoIcon, TriangleAlertIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { Alert } from '#frontend/components/ui/alert.tsx';\n\ntype AlertBannerVariant = 'error' | 'warning' | 'info';\n\ninterface AlertBannerProps {\n variant: AlertBannerVariant;\n children: ReactNode;\n}\n\nconst variantIcons: Record<AlertBannerVariant, typeof TriangleAlertIcon> = {\n error: CircleAlertIcon,\n warning: TriangleAlertIcon,\n info: InfoIcon,\n};\n\n/**\n * Status banner built on the design system's {@link Alert} (which wraps\n * `TRAlert`). Kept as a thin alias so existing call sites and the\n * `alert-banner-*` test ids stay stable while the visuals come from\n * `@tinyrack/ui`.\n */\nexport function AlertBanner({ variant, children }: AlertBannerProps) {\n return (\n <Alert\n data-testid={`alert-banner-${variant}`}\n icon={variantIcons[variant]}\n type={variant}\n >\n {children}\n </Alert>\n );\n}\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { Link2OffIcon } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\n\ninterface UnlinkOAuthModalProps {\n isOpen: boolean;\n onClose: () => void;\n providerName: string;\n isPending: boolean;\n onConfirm: () => Promise<void>;\n}\n\nexport function UnlinkOAuthModal({\n isOpen,\n onClose,\n providerName,\n isPending,\n onConfirm,\n}: UnlinkOAuthModalProps) {\n const { t } = useTranslation();\n const [error, setError] = useState<string | null>(null);\n\n const handleClose = () => {\n if (isPending) return;\n setError(null);\n onClose();\n };\n\n const handleConfirm = async () => {\n setError(null);\n try {\n await onConfirm();\n handleClose();\n } catch {\n setError(t('profile.linkedAccounts.unlinkError'));\n }\n };\n\n return (\n <Modal\n description={t('profile.linkedAccounts.unlinkModal.description', {\n provider: providerName,\n })}\n icon={Link2OffIcon}\n isOpen={isOpen}\n onClose={handleClose}\n preventClose={isPending}\n title={t('profile.linkedAccounts.unlinkModal.title')}\n variant=\"destructive\"\n >\n <div className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\">\n <AlertBanner variant=\"warning\">\n {t('profile.linkedAccounts.unlinkModal.warning', {\n provider: providerName,\n })}\n </AlertBanner>\n\n {error && <AlertBanner variant=\"error\">{error}</AlertBanner>}\n\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"unlink-oauth-cancel\"\n disabled={isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.linkedAccounts.unlinkModal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"unlink-oauth-unlink\"\n disabled={isPending}\n intent=\"danger\"\n loading={isPending}\n loadingLabel={t('profile.linkedAccounts.unlinking')}\n onClick={handleConfirm}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.linkedAccounts.unlink')}\n </TRButton>\n </ModalActions>\n </div>\n </Modal>\n );\n}\n","import { TRCard } from '@tinyrack/ui/components/card';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport { useTranslation } from 'react-i18next';\n\nfunction InfoRow({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"flex items-center justify-between gap-tinyrack-lg px-tinyrack-lg py-tinyrack-md\">\n <TRText className=\"shrink-0\" color=\"muted\" variant=\"caption\">\n {label}\n </TRText>\n <TRText truncate variant=\"bodySm\" weight=\"medium\">\n {value}\n </TRText>\n </div>\n );\n}\n\ninterface UserInfoSectionProps {\n user: {\n sub: string;\n email: string;\n };\n}\n\nexport function UserInfoSection({ user }: UserInfoSectionProps) {\n const { t } = useTranslation();\n\n return (\n <TRCard.Root variant=\"outlined\">\n <TRCard.Header className=\"border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md\">\n <TRCard.Title>{t('profile.account.title')}</TRCard.Title>\n <TRCard.Description>\n {t('profile.account.description')}\n </TRCard.Description>\n </TRCard.Header>\n <TRCard.Content className=\"divide-y divide-tinyrack-border p-0\">\n <InfoRow label={t('profile.id.label')} value={user.sub} />\n <InfoRow label={t('profile.email.label')} value={user.email} />\n </TRCard.Content>\n </TRCard.Root>\n );\n}\n","import { Toaster } from '#frontend/components/ui/toaster.tsx';\nimport { ShellHeaderBar } from '#frontend/features/layout/shell-header-bar.tsx';\n\ntype AppLayoutProps = {\n children: React.ReactNode;\n /** Trailing header action — the profile's sign-out. */\n headerActions?: React.ReactNode;\n};\n\n/**\n * The shell for signed-in screens that are not the admin console.\n *\n * Shares the auth surface's vocabulary — the canvas, the header bar, the\n * entrance, the token-owned rhythm — but drops the brand panel and runs full\n * width. A settings page is a list of cards to work through, not a single task\n * to focus on, so surrendering the leading columns to a permanent brand column\n * would be paying prime space for decoration.\n *\n * Deliberately not extracted into a wrapper shared with `AuthLayout`: that one\n * is a twelve-column grid because it has a panel to place, and its content\n * stack carries a mobile-only card that would be a box inside a box here.\n * The genuinely shared piece is `ShellHeaderBar`.\n */\nexport function AppLayout({ children, headerActions }: AppLayoutProps) {\n return (\n <div className=\"flex min-h-dvh flex-col bg-tinyrack-surface\">\n {/*\n Profile hosts the TOTP recovery-codes step, which confirms a copy with\n a toast. Without a viewport here that confirmation would go nowhere on\n the one screen where losing the codes is unrecoverable.\n */}\n <Toaster />\n <ShellHeaderBar actions={headerActions} brand />\n <main className=\"flex flex-1 justify-center px-tinyrack-lg py-tinyrack-xl\">\n {/*\n The stack owns vertical rhythm so screens compose as a flat list of\n blocks instead of each one hand-rolling margins that drift apart.\n */}\n <div className=\"auth-enter flex w-full max-w-tinyrack-overlay-md flex-col gap-tinyrack-xl\">\n {children}\n </div>\n </main>\n </div>\n );\n}\n","import { mutationOptions } from '@tanstack/react-query';\nimport type { InferRequestType } from 'hono/client';\nimport { client, jsonOk } from '#frontend/libs/api.ts';\n\n/**\n * Set password for OAuth-only users\n */\nexport type SetPasswordParams = InferRequestType<\n (typeof client.api.user.password)['$post']\n>['json'];\n\nexport const setPasswordMutationOptions = mutationOptions({\n mutationFn: async (values: SetPasswordParams) => {\n const res = await client.api.user.password.$post({\n json: values,\n });\n return jsonOk(res);\n },\n});\n\n/**\n * Change password for users who already have a password\n */\nexport type ChangePasswordParams = InferRequestType<\n (typeof client.api.user.password)['$put']\n>['json'];\n\nexport const changePasswordMutationOptions = mutationOptions({\n mutationFn: async (values: ChangePasswordParams) => {\n const res = await client.api.user.password.$put({\n json: values,\n });\n return jsonOk(res);\n },\n});\n\n/**\n * Remove password (only if user has at least one\n * OAuth account linked)\n */\nexport type RemovePasswordParams = InferRequestType<\n (typeof client.api.user.password)['$delete']\n>['json'];\n\nexport const removePasswordMutationOptions = mutationOptions({\n mutationFn: async (values: RemovePasswordParams) => {\n const res = await client.api.user.password.$delete({\n json: values,\n });\n return jsonOk(res);\n },\n});\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { KeyRoundIcon } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { IssuaryError } from '#frontend/libs/error.ts';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { changePasswordMutationOptions } from '#frontend/queries/password.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ninterface ChangePasswordModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function ChangePasswordModal({\n isOpen,\n onClose,\n}: ChangePasswordModalProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n const passwordPolicy = configData.auth.password.policy;\n\n const schema = useMemo(\n () =>\n z\n .object({\n currentPassword: z.string().min(1, t('validation.password.required')),\n newPassword: z\n .string()\n .min(\n passwordPolicy.min_length,\n t('validation.password.min', {\n count: passwordPolicy.min_length,\n }),\n )\n .max(\n passwordPolicy.max_length,\n t('validation.password.max', {\n count: passwordPolicy.max_length,\n }),\n ),\n confirmPassword: z.string(),\n })\n .refine((data) => data.newPassword === data.confirmPassword, {\n message: t('validation.confirmPassword.mismatch'),\n path: ['confirmPassword'],\n }),\n [passwordPolicy.max_length, passwordPolicy.min_length, t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: {\n currentPassword: '',\n newPassword: '',\n confirmPassword: '',\n },\n });\n\n const mutation = useMutation({\n ...changePasswordMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n handleClose();\n },\n });\n\n const handleClose = () => {\n form.reset();\n onClose();\n };\n\n const handleSubmit = form.handleSubmit(async (data) => {\n try {\n await mutation.mutateAsync({\n current_password: data.currentPassword,\n new_password: data.newPassword,\n });\n } catch (err) {\n if (\n err instanceof IssuaryError &&\n err.code === 'INVALID_CURRENT_PASSWORD'\n ) {\n form.setError('currentPassword', {\n message: t('profile.password.changeModal.invalidCurrent'),\n });\n } else {\n form.setError('root', {\n message: t('profile.password.changeModal.error'),\n });\n }\n }\n });\n\n return (\n <Modal\n description={t('profile.password.changeModal.description')}\n icon={KeyRoundIcon}\n isOpen={isOpen}\n onClose={handleClose}\n title={t('profile.password.changeModal.title')}\n >\n <form\n className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\"\n onSubmit={handleSubmit}\n >\n <AuthField\n error={form.formState.errors.currentPassword}\n errorTestId=\"change-password-error-currentPassword\"\n id=\"current-password\"\n label={t('profile.password.changeModal.currentPassword')}\n placeholder={t(\n 'profile.password.changeModal.currentPasswordPlaceholder',\n )}\n {...form.register('currentPassword')}\n type=\"password\"\n />\n <AuthField\n error={form.formState.errors.newPassword}\n errorTestId=\"change-password-error-newPassword\"\n id=\"new-password-change\"\n label={t('profile.password.changeModal.newPassword')}\n placeholder={t('profile.password.changeModal.newPasswordPlaceholder')}\n {...form.register('newPassword')}\n type=\"password\"\n />\n <AuthField\n error={form.formState.errors.confirmPassword}\n errorTestId=\"change-password-error-confirmPassword\"\n id=\"confirm-password-change\"\n label={t('profile.password.changeModal.confirmPassword')}\n placeholder={t(\n 'profile.password.changeModal.confirmPasswordPlaceholder',\n )}\n {...form.register('confirmPassword')}\n type=\"password\"\n />\n {form.formState.errors.root && (\n <AlertBanner variant=\"error\">\n {form.formState.errors.root.message}\n </AlertBanner>\n )}\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"change-password-cancel\"\n disabled={mutation.isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.changeModal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"change-password-submit\"\n disabled={mutation.isPending}\n intent=\"primary\"\n loading={mutation.isPending}\n loadingLabel={t('profile.password.changeModal.submitting')}\n type=\"submit\"\n uiSize=\"sm\"\n >\n {mutation.isPending\n ? undefined\n : t('profile.password.changeModal.submit')}\n </TRButton>\n </ModalActions>\n </form>\n </Modal>\n );\n}\n","import { mutationOptions } from '@tanstack/react-query';\nimport type { InferResponseType } from 'hono/client';\nimport { client, jsonOk } from '#frontend/libs/api.ts';\n\nexport type AccountDeletionResponse = InferResponseType<\n (typeof client.api.user)['$delete'],\n 200\n>;\n\nexport const deleteAccountMutationOptions = mutationOptions({\n mutationFn: async () => {\n const res = await client.api.user.$delete();\n return jsonOk(res);\n },\n});\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useRouter } from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { Trash2Icon } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { deleteAccountMutationOptions } from '#frontend/queries/account.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ninterface DeleteAccountModalProps {\n isOpen: boolean;\n onClose: () => void;\n retentionDays: number;\n}\n\nexport function DeleteAccountModal({\n isOpen,\n onClose,\n retentionDays,\n}: DeleteAccountModalProps) {\n const { t } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n\n const schema = useMemo(\n () =>\n z.object({\n confirmation: z\n .string()\n .refine(\n (val) =>\n val.toLowerCase() ===\n t('profile.deleteAccount.modal.confirmPlaceholder').toLowerCase(),\n { message: t('validation.confirmText.mismatch') },\n ),\n }),\n [t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: { confirmation: '' },\n });\n\n const mutation = useMutation({\n ...deleteAccountMutationOptions,\n onSuccess: async () => {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: null,\n });\n await tick();\n router.navigate({ to: '/login' });\n },\n });\n\n const handleClose = () => {\n if (mutation.isPending) return;\n form.reset();\n onClose();\n };\n\n const handleSubmit = form.handleSubmit(async () => {\n try {\n await mutation.mutateAsync();\n } catch {\n form.setError('root', {\n message: t('profile.deleteAccount.error'),\n });\n }\n });\n\n return (\n <Modal\n icon={Trash2Icon}\n isOpen={isOpen}\n onClose={handleClose}\n preventClose={mutation.isPending}\n title={t('profile.deleteAccount.modal.title')}\n variant=\"destructive\"\n >\n <form\n className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\"\n onSubmit={handleSubmit}\n >\n <AlertBanner variant=\"error\">\n <div className=\"flex flex-col gap-tinyrack-xs\">\n <p>\n {t('profile.deleteAccount.modal.description', {\n days: retentionDays,\n })}\n </p>\n <p className=\"text-tinyrack-xs opacity-tinyrack-hover\">\n {t('profile.deleteAccount.modal.warning')}\n </p>\n </div>\n </AlertBanner>\n\n <AuthField\n autoComplete=\"off\"\n error={form.formState.errors.confirmation}\n errorTestId=\"delete-account-error\"\n id=\"delete-confirmation\"\n label={t('profile.deleteAccount.modal.confirmLabel')}\n placeholder={t('profile.deleteAccount.modal.confirmPlaceholder')}\n {...form.register('confirmation')}\n type=\"text\"\n />\n\n {form.formState.errors.root && (\n <AlertBanner variant=\"error\">\n {form.formState.errors.root.message}\n </AlertBanner>\n )}\n\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"delete-account-cancel\"\n disabled={mutation.isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.deleteAccount.modal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"delete-account-submit\"\n disabled={mutation.isPending}\n intent=\"danger\"\n loading={mutation.isPending}\n loadingLabel={t('profile.deleteAccount.modal.confirming')}\n type=\"submit\"\n uiSize=\"sm\"\n >\n {mutation.isPending\n ? undefined\n : t('profile.deleteAccount.modal.confirm')}\n </TRButton>\n </ModalActions>\n </form>\n </Modal>\n );\n}\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { ShieldCheckIcon } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { IssuaryError } from '#frontend/libs/error.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\nimport { disableTotpMutationOptions } from '#frontend/queries/totp.ts';\n\ninterface DisableTotpModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function DisableTotpModal({ isOpen, onClose }: DisableTotpModalProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n\n const schema = useMemo(\n () =>\n z.object({\n code: z\n .string()\n .length(6, t('validation.totp.length'))\n .regex(/^\\d{6}$/, t('validation.totp.digits')),\n }),\n [t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: { code: '' },\n });\n\n const mutation = useMutation({\n ...disableTotpMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n handleClose();\n },\n });\n\n const handleClose = () => {\n form.reset();\n onClose();\n };\n\n const handleSubmit = form.handleSubmit(async (data) => {\n try {\n await mutation.mutateAsync({ code: data.code });\n } catch (error) {\n if (error instanceof IssuaryError) {\n if (error.code === 'CANNOT_REMOVE_LAST_SECOND_FACTOR') {\n form.setError('code', {\n message: t(\n 'profile.totp.disableModal.cannotRemoveLastSecondFactor',\n ),\n });\n return;\n }\n }\n form.setError('code', {\n message: t('profile.totp.disableModal.error'),\n });\n }\n });\n\n return (\n <Modal\n description={t('profile.totp.disableModal.description')}\n icon={ShieldCheckIcon}\n isOpen={isOpen}\n onClose={handleClose}\n title={t('profile.totp.disableModal.title')}\n variant=\"destructive\"\n >\n <form\n className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\"\n onSubmit={handleSubmit}\n >\n <AlertBanner variant=\"warning\">\n {t('profile.totp.disableModal.warning')}\n </AlertBanner>\n\n <AuthField\n autoComplete=\"one-time-code\"\n error={form.formState.errors.code}\n errorTestId=\"disable-totp-error\"\n id=\"disable-totp-code\"\n inputMode=\"numeric\"\n label={t('profile.totp.disableModal.codeLabel')}\n maxLength={6}\n pattern=\"[0-9]*\"\n placeholder=\"000000\"\n {...form.register('code')}\n type=\"text\"\n />\n\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"disable-totp-cancel\"\n disabled={mutation.isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.disableModal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"disable-totp-submit\"\n disabled={mutation.isPending}\n intent=\"danger\"\n loading={mutation.isPending}\n loadingLabel={t('profile.totp.disableModal.disabling')}\n type=\"submit\"\n uiSize=\"sm\"\n >\n {mutation.isPending\n ? undefined\n : t('profile.totp.disableModal.disable')}\n </TRButton>\n </ModalActions>\n </form>\n </Modal>\n );\n}\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { TRBadge } from '@tinyrack/ui/components/badge';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { TRSpinner } from '@tinyrack/ui/components/spinner';\nimport {\n CloudIcon,\n FingerprintIcon,\n PencilIcon,\n SmartphoneIcon,\n Trash2Icon,\n} from 'lucide-react';\nimport { useCallback, useMemo, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { IssuaryError } from '#frontend/libs/error.ts';\nimport { queryKeys } from '#frontend/queries/keys.ts';\nimport {\n deletePasskeyMutationOptions,\n getPasskeysQueryOptions,\n type PasskeyInfo,\n renamePasskeyMutationOptions,\n} from '#frontend/queries/passkey.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ninterface ManagePasskeysModalProps {\n isOpen: boolean;\n onClose: () => void;\n onAddNew: () => void;\n}\n\nexport function ManagePasskeysModal({\n isOpen,\n onClose,\n onAddNew,\n}: ManagePasskeysModalProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n const [editingPasskey, setEditingPasskey] = useState<PasskeyInfo | null>(\n null,\n );\n const [deletingId, setDeletingId] = useState<string | null>(null);\n const [confirmingDeleteId, setConfirmingDeleteId] = useState<string | null>(\n null,\n );\n const [deleteError, setDeleteError] = useState<string | null>(null);\n\n const { data: passkeysData, isLoading } = useQuery({\n ...getPasskeysQueryOptions,\n enabled: isOpen,\n });\n\n const deleteMutation = useMutation({\n ...deletePasskeyMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: queryKeys.passkeys() });\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n onSettled: () => {\n setDeletingId(null);\n },\n });\n\n const handleClose = useCallback(() => {\n setEditingPasskey(null);\n setDeletingId(null);\n setConfirmingDeleteId(null);\n setDeleteError(null);\n onClose();\n }, [onClose]);\n\n const handleRequestDelete = (passkey: PasskeyInfo) => {\n setConfirmingDeleteId(passkey.id);\n setDeleteError(null);\n };\n\n const handleCancelDelete = () => {\n setConfirmingDeleteId(null);\n setDeleteError(null);\n };\n\n const handleConfirmDelete = async (passkey: PasskeyInfo) => {\n setDeletingId(passkey.id);\n setConfirmingDeleteId(null);\n try {\n await deleteMutation.mutateAsync({ id: passkey.id });\n } catch (error) {\n if (error instanceof IssuaryError) {\n if (error.code === 'CANNOT_REMOVE_LAST_SECOND_FACTOR') {\n setDeleteError(\n t('profile.passkey.manageModal.cannotRemoveLastSecondFactor'),\n );\n return;\n }\n }\n setDeleteError(t('profile.passkey.manageModal.deleteError'));\n }\n };\n\n const formatDate = (dateString: string) => {\n return new Date(dateString).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n };\n\n const passkeys = passkeysData?.passkeys || [];\n\n return (\n <Modal\n icon={FingerprintIcon}\n isOpen={isOpen}\n onClose={handleClose}\n size=\"lg\"\n title={t('profile.passkey.manageModal.title')}\n >\n <div className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-sm\">\n {deleteError && (\n <AlertBanner variant=\"error\">{deleteError}</AlertBanner>\n )}\n\n {isLoading && (\n <div className=\"flex justify-center py-tinyrack-xl\">\n <TRSpinner uiSize=\"md\" />\n </div>\n )}\n\n {!isLoading && passkeys.length === 0 && (\n <div\n className=\"py-tinyrack-xl text-center text-tinyrack-sm text-tinyrack-text-muted\"\n data-testid=\"passkeys-empty\"\n >\n <p>{t('profile.passkey.manageModal.noPasskeys')}</p>\n </div>\n )}\n\n {!isLoading && passkeys.length > 0 && (\n <div className=\"flex flex-col gap-tinyrack-sm\">\n {passkeys.map((passkey) => (\n <PasskeyItem\n formatDate={formatDate}\n isConfirmingDelete={confirmingDeleteId === passkey.id}\n isDeleting={deletingId === passkey.id}\n isEditing={editingPasskey?.id === passkey.id}\n key={passkey.id}\n onCancelDelete={handleCancelDelete}\n onCancelEdit={() => setEditingPasskey(null)}\n onConfirmDelete={() => handleConfirmDelete(passkey)}\n onEdit={() => setEditingPasskey(passkey)}\n onRequestDelete={() => handleRequestDelete(passkey)}\n passkey={passkey}\n />\n ))}\n </div>\n )}\n </div>\n\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"manage-passkeys-close\"\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.manageModal.close')}\n </TRButton>\n <TRButton\n data-testid=\"manage-passkeys-add-new\"\n intent=\"primary\"\n onClick={() => {\n handleClose();\n onAddNew();\n }}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.manageModal.addNew')}\n </TRButton>\n </ModalActions>\n </Modal>\n );\n}\n\ninterface PasskeyItemProps {\n passkey: PasskeyInfo;\n isDeleting: boolean;\n isEditing: boolean;\n isConfirmingDelete: boolean;\n onEdit: () => void;\n onCancelEdit: () => void;\n onRequestDelete: () => void;\n onConfirmDelete: () => void;\n onCancelDelete: () => void;\n formatDate: (dateString: string) => string;\n}\n\nfunction PasskeyItem({\n passkey,\n isDeleting,\n isEditing,\n isConfirmingDelete,\n onEdit,\n onCancelEdit,\n onRequestDelete,\n onConfirmDelete,\n onCancelDelete,\n formatDate,\n}: PasskeyItemProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n\n const schema = useMemo(\n () =>\n z.object({\n name: z\n .string()\n .min(1, t('validation.passkey.name.required'))\n .max(100, t('validation.passkey.name.max')),\n }),\n [t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: { name: passkey.name || '' },\n });\n\n const renameMutation = useMutation({\n ...renamePasskeyMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: queryKeys.passkeys() });\n onCancelEdit();\n },\n });\n\n const handleRename = form.handleSubmit(async (data) => {\n try {\n await renameMutation.mutateAsync({ id: passkey.id, name: data.name });\n } catch {\n form.setError('name', {\n message: t('profile.passkey.manageModal.renameError'),\n });\n }\n });\n\n if (isEditing) {\n return (\n <form\n className=\"flex flex-col gap-tinyrack-xs rounded-tinyrack-md bg-tinyrack-surface-muted p-tinyrack-sm\"\n onSubmit={handleRename}\n >\n <AuthField\n data-testid=\"passkey-rename-input\"\n error={form.formState.errors.name}\n errorTestId=\"passkey-rename-error\"\n hideLabel\n label={t('profile.passkey.manageModal.nameLabel')}\n placeholder={t('profile.passkey.manageModal.namePlaceholder')}\n {...form.register('name')}\n type=\"text\"\n />\n <div className=\"flex justify-end gap-tinyrack-xs\">\n <TRButton\n appearance=\"ghost\"\n disabled={renameMutation.isPending}\n onClick={() => {\n form.reset();\n onCancelEdit();\n }}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.manageModal.cancelEdit')}\n </TRButton>\n <TRButton\n disabled={renameMutation.isPending}\n intent=\"primary\"\n type=\"submit\"\n uiSize=\"sm\"\n >\n {renameMutation.isPending\n ? t('profile.passkey.manageModal.saving')\n : t('profile.passkey.manageModal.save')}\n </TRButton>\n </div>\n </form>\n );\n }\n\n if (isConfirmingDelete) {\n return (\n <div className=\"flex items-center justify-between rounded-tinyrack-md border border-tinyrack-danger-border bg-tinyrack-danger-surface p-tinyrack-sm text-tinyrack-on-danger\">\n <div className=\"flex items-center gap-tinyrack-sm\">\n <Trash2Icon className=\"size-tinyrack-lg\" />\n <span className=\"text-tinyrack-xs\">\n {t('profile.passkey.manageModal.deleteConfirmInline')}\n </span>\n </div>\n <div className=\"flex gap-tinyrack-xs\">\n <TRButton\n appearance=\"ghost\"\n onClick={onCancelDelete}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.manageModal.cancelEdit')}\n </TRButton>\n <TRButton\n intent=\"danger\"\n onClick={onConfirmDelete}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.manageModal.delete')}\n </TRButton>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className=\"flex items-center justify-between rounded-tinyrack-md bg-tinyrack-surface-muted p-tinyrack-sm\"\n data-testid=\"passkey-item\"\n >\n <div className=\"flex items-center gap-tinyrack-sm\">\n {passkey.device_type === 'multiDevice' ? (\n <CloudIcon className=\"size-tinyrack-lg text-tinyrack-primary\" />\n ) : (\n <SmartphoneIcon className=\"size-tinyrack-lg text-tinyrack-primary\" />\n )}\n <div>\n <div className=\"font-tinyrack-medium text-tinyrack-xs\">\n {passkey.name || t('profile.passkey.manageModal.unnamedPasskey')}\n </div>\n <div className=\"flex items-center gap-tinyrack-xs text-tinyrack-text-muted text-tinyrack-xs\">\n <span>\n {t('profile.passkey.manageModal.createdAt', {\n date: formatDate(passkey.created_at),\n })}\n </span>\n {passkey.backed_up && (\n <TRBadge uiSize=\"md\" variant=\"success\">\n {t('profile.passkey.manageModal.backedUp')}\n </TRBadge>\n )}\n </div>\n </div>\n </div>\n <div className=\"flex gap-tinyrack-xs\">\n <TRButton\n appearance=\"ghost\"\n aria-label={t('profile.passkey.manageModal.rename')}\n onClick={onEdit}\n type=\"button\"\n uiSize=\"sm\"\n >\n <PencilIcon className=\"size-tinyrack-lg\" />\n </TRButton>\n <TRButton\n appearance=\"ghost\"\n aria-label={t('profile.passkey.manageModal.delete')}\n disabled={isDeleting}\n intent=\"danger\"\n loading={isDeleting}\n onClick={onRequestDelete}\n type=\"button\"\n uiSize=\"sm\"\n >\n {isDeleting ? undefined : <Trash2Icon className=\"size-tinyrack-lg\" />}\n </TRButton>\n </div>\n </div>\n );\n}\n","import {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport { useRouter } from '@tanstack/react-router';\nimport { ShieldCheckIcon } from 'lucide-react';\nimport { useCallback, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { RecoveryCodesStep } from '#frontend/components/totp/recovery-codes-step.tsx';\nimport { VerifyStep } from '#frontend/components/totp/verify-step.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal } from '#frontend/components/ui/modal.tsx';\nimport { IssuaryError } from '#frontend/libs/error.ts';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\nimport {\n type RegenerateTotpRecoveryCodesResponse,\n regenerateTotpRecoveryCodesMutationOptions,\n} from '#frontend/queries/totp.ts';\n\ninterface RegenerateTotpRecoveryCodesModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\ntype RegenerateStep = 'verify' | 'recovery';\n\nexport function RegenerateTotpRecoveryCodesModal({\n isOpen,\n onClose,\n}: RegenerateTotpRecoveryCodesModalProps) {\n const { t } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const { data: appConfig } = useSuspenseQuery(appConfigQueryOptions);\n const [step, setStep] = useState<RegenerateStep>('verify');\n const [response, setResponse] =\n useState<RegenerateTotpRecoveryCodesResponse | null>(null);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const mutation = useMutation({\n ...regenerateTotpRecoveryCodesMutationOptions,\n onSuccess: async (data) => {\n setResponse(data);\n setStep('recovery');\n await queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n const reset = useCallback(() => {\n setStep('verify');\n setResponse(null);\n setErrorMessage(null);\n mutation.reset();\n }, [mutation]);\n\n const handleClose = useCallback(() => {\n reset();\n onClose();\n }, [onClose, reset]);\n\n const handleVerify = useCallback(\n async (code: string) => {\n setErrorMessage(null);\n\n try {\n await mutation.mutateAsync({ code });\n } catch (error) {\n if (error instanceof IssuaryError) {\n if (error.code === 'INVALID_TOTP_CODE') {\n throw error;\n }\n\n if (error.code === 'UNAUTHORIZED') {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: null,\n });\n await tick();\n router.navigate({ to: '/login' });\n return;\n }\n\n if (\n error.code === 'TOTP_NOT_ENABLED' ||\n error.code === 'VALIDATION_ERROR'\n ) {\n await queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n handleClose();\n return;\n }\n }\n\n setErrorMessage(t('profile.totp.regenerateModal.unexpectedError'));\n }\n },\n [handleClose, mutation, queryClient, router, t],\n );\n\n if (!appConfig.auth.password.totp.enabled) {\n return null;\n }\n\n return (\n <Modal\n description={\n step === 'verify'\n ? t('profile.totp.regenerateModal.description')\n : t('profile.totp.regenerateModal.recoveryDescription')\n }\n icon={ShieldCheckIcon}\n isOpen={isOpen}\n onClose={handleClose}\n preventClose={step === 'recovery'}\n size=\"sm\"\n title={\n step === 'verify'\n ? t('profile.totp.regenerateModal.title')\n : t('profile.totp.regenerateModal.recoveryTitle')\n }\n >\n {step === 'verify' ? (\n <div className=\"mt-tinyrack-lg\">\n {errorMessage && (\n <div className=\"mb-tinyrack-md\">\n <AlertBanner variant=\"error\">{errorMessage}</AlertBanner>\n </div>\n )}\n <VerifyStep\n invalidMessage={t('profile.totp.regenerateModal.error')}\n isPending={mutation.isPending}\n onSubmit={handleVerify}\n pendingText={t('profile.totp.regenerateModal.submitting')}\n submitLabel={t('profile.totp.regenerateModal.submit')}\n />\n </div>\n ) : (\n <div className=\"mt-tinyrack-lg\">\n <RecoveryCodesStep\n onConfirm={handleClose}\n recoveryCodes={response?.recovery_codes ?? []}\n />\n </div>\n )}\n </Modal>\n );\n}\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { KeyRoundIcon } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { IssuaryError } from '#frontend/libs/error.ts';\nimport { removePasswordMutationOptions } from '#frontend/queries/password.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ninterface RemovePasswordModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function RemovePasswordModal({\n isOpen,\n onClose,\n}: RemovePasswordModalProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n\n const schema = useMemo(\n () =>\n z.object({\n currentPassword: z.string().min(1, t('validation.password.required')),\n }),\n [t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: { currentPassword: '' },\n });\n\n const mutation = useMutation({\n ...removePasswordMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n handleClose();\n },\n });\n\n const handleClose = () => {\n form.reset();\n onClose();\n };\n\n const handleSubmit = form.handleSubmit(async (data) => {\n try {\n await mutation.mutateAsync({\n current_password: data.currentPassword,\n });\n } catch (err) {\n if (err instanceof IssuaryError) {\n if (err.code === 'INVALID_CURRENT_PASSWORD') {\n form.setError('currentPassword', {\n message: t('profile.password.removeModal.invalidCurrent'),\n });\n return;\n }\n if (err.code === 'CANNOT_REMOVE_LAST_AUTH_METHOD') {\n form.setError('root', {\n message: t('profile.password.removeModal.noOAuth'),\n });\n return;\n }\n if (err.code === 'CANNOT_REMOVE_PASSWORD_WITH_SECOND_FACTOR_ONLY') {\n form.setError('root', {\n message: t('profile.password.removeModal.noOAuthWith2FA'),\n });\n return;\n }\n }\n form.setError('root', {\n message: t('profile.password.removeModal.error'),\n });\n }\n });\n\n return (\n <Modal\n description={t('profile.password.removeModal.description')}\n icon={KeyRoundIcon}\n isOpen={isOpen}\n onClose={handleClose}\n title={t('profile.password.removeModal.title')}\n variant=\"destructive\"\n >\n <form\n className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\"\n onSubmit={handleSubmit}\n >\n <AuthField\n error={form.formState.errors.currentPassword}\n errorTestId=\"remove-password-error\"\n id=\"current-password-remove\"\n label={t('profile.password.removeModal.currentPassword')}\n placeholder={t(\n 'profile.password.removeModal.currentPasswordPlaceholder',\n )}\n {...form.register('currentPassword')}\n type=\"password\"\n />\n {form.formState.errors.root && (\n <AlertBanner variant=\"error\">\n {form.formState.errors.root.message}\n </AlertBanner>\n )}\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"remove-password-cancel\"\n disabled={mutation.isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.removeModal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"remove-password-submit\"\n disabled={mutation.isPending}\n intent=\"danger\"\n loading={mutation.isPending}\n loadingLabel={t('profile.password.removeModal.submitting')}\n type=\"submit\"\n uiSize=\"sm\"\n >\n {mutation.isPending\n ? undefined\n : t('profile.password.removeModal.submit')}\n </TRButton>\n </ModalActions>\n </form>\n </Modal>\n );\n}\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { KeyRoundIcon } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { setPasswordMutationOptions } from '#frontend/queries/password.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ninterface SetPasswordModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function SetPasswordModal({ isOpen, onClose }: SetPasswordModalProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n const passwordPolicy = configData.auth.password.policy;\n\n const schema = useMemo(\n () =>\n z\n .object({\n password: z\n .string()\n .min(\n passwordPolicy.min_length,\n t('validation.password.min', {\n count: passwordPolicy.min_length,\n }),\n )\n .max(\n passwordPolicy.max_length,\n t('validation.password.max', {\n count: passwordPolicy.max_length,\n }),\n ),\n confirmPassword: z.string(),\n })\n .refine((data) => data.password === data.confirmPassword, {\n message: t('validation.confirmPassword.mismatch'),\n path: ['confirmPassword'],\n }),\n [passwordPolicy.max_length, passwordPolicy.min_length, t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: { password: '', confirmPassword: '' },\n });\n\n const mutation = useMutation({\n ...setPasswordMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n handleClose();\n },\n });\n\n const handleClose = () => {\n form.reset();\n onClose();\n };\n\n const handleSubmit = form.handleSubmit(async (data) => {\n try {\n await mutation.mutateAsync({ password: data.password });\n } catch (error) {\n void error;\n form.setError('root', {\n message: t('profile.password.setModal.error'),\n });\n }\n });\n\n return (\n <Modal\n description={t('profile.password.setModal.description')}\n icon={KeyRoundIcon}\n isOpen={isOpen}\n onClose={handleClose}\n title={t('profile.password.setModal.title')}\n >\n <form\n className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\"\n onSubmit={handleSubmit}\n >\n <AuthField\n error={form.formState.errors.password}\n errorTestId=\"set-password-error-password\"\n id=\"new-password\"\n label={t('profile.password.setModal.newPassword')}\n placeholder={t('profile.password.setModal.newPasswordPlaceholder')}\n {...form.register('password')}\n type=\"password\"\n />\n <AuthField\n error={form.formState.errors.confirmPassword}\n errorTestId=\"set-password-error-confirmPassword\"\n id=\"confirm-password\"\n label={t('profile.password.setModal.confirmPassword')}\n placeholder={t(\n 'profile.password.setModal.confirmPasswordPlaceholder',\n )}\n {...form.register('confirmPassword')}\n type=\"password\"\n />\n {form.formState.errors.root && (\n <AlertBanner variant=\"error\">\n {form.formState.errors.root.message}\n </AlertBanner>\n )}\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"set-password-cancel\"\n disabled={mutation.isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.password.setModal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"set-password-submit\"\n disabled={mutation.isPending}\n intent=\"primary\"\n loading={mutation.isPending}\n loadingLabel={t('profile.password.setModal.submitting')}\n type=\"submit\"\n uiSize=\"sm\"\n >\n {mutation.isPending\n ? undefined\n : t('profile.password.setModal.submit')}\n </TRButton>\n </ModalActions>\n </form>\n </Modal>\n );\n}\n","import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { TRSpinner } from '@tinyrack/ui/components/spinner';\nimport { FingerprintIcon } from 'lucide-react';\nimport { useCallback, useMemo, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport z from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { queryKeys } from '#frontend/queries/keys.ts';\nimport { registerPasskeyMutationOptions } from '#frontend/queries/passkey.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ninterface SetupPasskeyModalProps {\n isOpen: boolean;\n onClose: () => void;\n isRequired?: boolean;\n canSwitchToTotp?: boolean;\n onSwitchToTotp?: () => void;\n}\n\ntype SetupStep = 'name' | 'register';\n\nexport function SetupPasskeyModal({\n isOpen,\n onClose,\n isRequired = false,\n canSwitchToTotp = false,\n onSwitchToTotp,\n}: SetupPasskeyModalProps) {\n const { t } = useTranslation();\n const queryClient = useQueryClient();\n const [step, setStep] = useState<SetupStep>('name');\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const schema = useMemo(\n () =>\n z.object({\n name: z\n .string()\n .max(100, t('validation.passkey.name.max'))\n .optional()\n .transform((val) => val?.trim() || undefined),\n }),\n [t],\n );\n\n const form = useForm({\n resolver: standardSchemaResolver(schema),\n defaultValues: { name: '' },\n });\n\n const registerMutation = useMutation({\n ...registerPasskeyMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: queryKeys.passkeys() });\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n handleClose();\n },\n onError: (error) => {\n setStep('name');\n if (error.name === 'NotAllowedError') {\n setErrorMessage(t('profile.passkey.setupModal.cancelled'));\n } else {\n setErrorMessage(t('profile.passkey.setupModal.error'));\n }\n },\n });\n\n const handleClose = useCallback(() => {\n form.reset();\n setStep('name');\n setErrorMessage(null);\n onClose();\n }, [form, onClose]);\n\n const handleRegister = form.handleSubmit(async (data) => {\n setStep('register');\n setErrorMessage(null);\n try {\n await registerMutation.mutateAsync({ name: data.name });\n } catch {\n // Error handling is done via mutation callbacks\n }\n });\n\n const isPending = registerMutation.isPending;\n\n return (\n <Modal\n description={\n isRequired\n ? t('profile.passkey.setupModal.requiredDescription')\n : undefined\n }\n icon={FingerprintIcon}\n isOpen={isOpen}\n onClose={handleClose}\n preventClose={isRequired}\n size=\"sm\"\n title={t('profile.passkey.setupModal.title')}\n >\n {step === 'name' && (\n <form\n className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\"\n onSubmit={handleRegister}\n >\n <p className=\"text-tinyrack-text-muted text-tinyrack-xs\">\n {t('profile.passkey.setupModal.description')}\n </p>\n\n {errorMessage && (\n <AlertBanner variant=\"error\">{errorMessage}</AlertBanner>\n )}\n\n <AuthField\n error={form.formState.errors.name}\n errorTestId=\"setup-passkey-error\"\n hint={t('profile.passkey.setupModal.nameHint')}\n id=\"passkey-name\"\n label={t('profile.passkey.setupModal.nameLabel')}\n placeholder={t('profile.passkey.setupModal.namePlaceholder')}\n {...form.register('name')}\n type=\"text\"\n />\n\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"setup-passkey-cancel\"\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.setupModal.cancel')}\n </TRButton>\n <TRButton\n data-testid=\"setup-passkey-continue\"\n intent=\"primary\"\n type=\"submit\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.setupModal.continue')}\n </TRButton>\n </ModalActions>\n {canSwitchToTotp && onSwitchToTotp && (\n <p className=\"mt-tinyrack-sm text-center text-tinyrack-xs\">\n <TRButton\n appearance=\"ghost\"\n intent=\"primary\"\n onClick={onSwitchToTotp}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.setupModal.switchToTotp')}\n </TRButton>\n </p>\n )}\n </form>\n )}\n\n {step === 'register' && (\n <div className=\"mt-tinyrack-lg\">\n <div\n className=\"flex flex-col items-center gap-tinyrack-md py-tinyrack-xl\"\n data-testid=\"setup-passkey-loading\"\n >\n <TRSpinner uiSize=\"md\" />\n <p className=\"text-center text-tinyrack-text-muted text-tinyrack-xs\">\n {t('profile.passkey.setupModal.waitingForDevice')}\n </p>\n </div>\n\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n data-testid=\"setup-passkey-cancel\"\n disabled={isPending}\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.passkey.setupModal.cancel')}\n </TRButton>\n </ModalActions>\n </div>\n )}\n </Modal>\n );\n}\n","import { TRButton } from '@tinyrack/ui/components/button';\nimport { TRSpinner } from '@tinyrack/ui/components/spinner';\nimport { ShieldCheckIcon } from 'lucide-react';\nimport { useCallback } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { QrStep } from '#frontend/components/totp/qr-step.tsx';\nimport { RecoveryCodesStep } from '#frontend/components/totp/recovery-codes-step.tsx';\nimport { VerifyStep } from '#frontend/components/totp/verify-step.tsx';\nimport { AlertBanner } from '#frontend/components/ui/alert-banner.tsx';\nimport { Modal, ModalActions } from '#frontend/components/ui/modal.tsx';\nimport { useTotpSetup } from '#frontend/features/totp/use-totp-setup.ts';\n\ninterface SetupTotpModalProps {\n isOpen: boolean;\n onClose: () => void;\n isRequired?: boolean;\n canSwitchToPasskey?: boolean;\n onSwitchToPasskey?: () => void;\n}\n\nexport function SetupTotpModal({\n isOpen,\n onClose,\n isRequired = false,\n canSwitchToPasskey = false,\n onSwitchToPasskey,\n}: SetupTotpModalProps) {\n const { t } = useTranslation();\n\n const {\n step,\n setupData,\n recoveryCodes,\n isSetupPending,\n isVerifyPending,\n isConfirmPending,\n startSetup,\n verify,\n goToVerify,\n goToQr,\n confirmRecoveryCodes,\n reset,\n } = useTotpSetup({\n autoStart: false,\n onConfirmSuccess: () => {\n reset();\n onClose();\n },\n });\n\n const handleClose = useCallback(() => {\n reset();\n onClose();\n }, [onClose, reset]);\n\n const handleModalOpen = useCallback(() => {\n if (!setupData && !isSetupPending) {\n startSetup();\n }\n }, [setupData, isSetupPending, startSetup]);\n\n if (isOpen && !setupData && !isSetupPending && step !== 'error') {\n handleModalOpen();\n }\n\n const handleVerify = useCallback(\n async (code: string) => {\n await verify(code);\n },\n [verify],\n );\n\n const modalTitle =\n step === 'recovery'\n ? t('setupTotp.recoveryCodes.title')\n : t('profile.totp.setupModal.title');\n\n return (\n <Modal\n description={\n isRequired\n ? t('profile.totp.setupModal.requiredDescription')\n : undefined\n }\n icon={ShieldCheckIcon}\n isOpen={isOpen}\n onClose={handleClose}\n preventClose={isRequired || step === 'recovery'}\n size=\"sm\"\n title={modalTitle}\n >\n {isSetupPending && (\n <div\n className=\"flex justify-center py-tinyrack-xl\"\n data-testid=\"setup-totp-loading\"\n >\n <TRSpinner uiSize=\"md\" />\n </div>\n )}\n\n {step === 'error' && (\n <div className=\"mt-tinyrack-lg flex flex-col gap-tinyrack-md\">\n <AlertBanner variant=\"error\">\n {t('profile.totp.setupModal.setupError')}\n </AlertBanner>\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.setupModal.cancel')}\n </TRButton>\n <TRButton\n intent=\"primary\"\n onClick={startSetup}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.setupModal.retry')}\n </TRButton>\n </ModalActions>\n </div>\n )}\n\n {setupData && step === 'qr' && (\n <div className=\"mt-tinyrack-lg\">\n <QrStep\n additionalActions={\n <>\n <ModalActions>\n <TRButton\n appearance=\"outline\"\n intent=\"neutral\"\n onClick={handleClose}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.setupModal.cancel')}\n </TRButton>\n </ModalActions>\n {canSwitchToPasskey && onSwitchToPasskey && (\n <p className=\"mt-tinyrack-sm text-center text-tinyrack-xs\">\n <TRButton\n appearance=\"ghost\"\n intent=\"primary\"\n onClick={onSwitchToPasskey}\n type=\"button\"\n uiSize=\"sm\"\n >\n {t('profile.totp.setupModal.switchToPasskey')}\n </TRButton>\n </p>\n )}\n </>\n }\n onNext={goToVerify}\n setupData={setupData}\n />\n </div>\n )}\n\n {setupData && step === 'verify' && (\n <div className=\"mt-tinyrack-lg\">\n <VerifyStep\n isPending={isVerifyPending}\n onBack={goToQr}\n onSubmit={handleVerify}\n />\n </div>\n )}\n\n {step === 'recovery' && recoveryCodes.length > 0 && (\n <div className=\"mt-tinyrack-lg\">\n <RecoveryCodesStep\n isLoading={isConfirmPending}\n onConfirm={confirmRecoveryCodes}\n recoveryCodes={recoveryCodes}\n />\n </div>\n )}\n </Modal>\n );\n}\n","import {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport {\n createFileRoute,\n type ErrorComponentProps,\n redirect,\n useRouter,\n} from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { TRCard } from '@tinyrack/ui/components/card';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport { CircleAlertIcon, LogOutIcon } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { z } from 'zod';\nimport { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { DangerZoneSection } from '#frontend/components/profile/danger-zone-section.tsx';\nimport { LinkedAccountsSection } from '#frontend/components/profile/linked-accounts-section.tsx';\nimport { PasskeySection } from '#frontend/components/profile/passkey-section.tsx';\nimport { PasswordSection } from '#frontend/components/profile/password-section.tsx';\nimport { TotpSection } from '#frontend/components/profile/totp-section.tsx';\nimport { UnlinkOAuthModal } from '#frontend/components/profile/unlink-oauth-modal.tsx';\nimport { UserInfoSection } from '#frontend/components/profile/user-info-section.tsx';\nimport { Alert } from '#frontend/components/ui/alert.tsx';\nimport { InitialAvatar } from '#frontend/components/ui/initial-avatar.tsx';\nimport { RouteErrorFallback } from '#frontend/components/ui/route-error-fallback.tsx';\nimport { AppLayout } from '#frontend/features/layout/app-layout.tsx';\nimport { ChangePasswordModal } from '#frontend/features/profile/change-password-modal.tsx';\nimport { DeleteAccountModal } from '#frontend/features/profile/delete-account-modal.tsx';\nimport { DisableTotpModal } from '#frontend/features/profile/disable-totp-modal.tsx';\nimport { ManagePasskeysModal } from '#frontend/features/profile/manage-passkeys-modal.tsx';\nimport { RegenerateTotpRecoveryCodesModal } from '#frontend/features/profile/regenerate-totp-recovery-codes-modal.tsx';\nimport { RemovePasswordModal } from '#frontend/features/profile/remove-password-modal.tsx';\nimport { SetPasswordModal } from '#frontend/features/profile/set-password-modal.tsx';\nimport { SetupPasskeyModal } from '#frontend/features/profile/setup-passkey-modal.tsx';\nimport { SetupTotpModal } from '#frontend/features/profile/setup-totp-modal.tsx';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { logoutMutationOptions } from '#frontend/queries/logout.ts';\nimport {\n getOAuthAuthorizeUrl,\n oauthAccountsQueryOptions,\n unlinkOAuthMutationOptions,\n} from '#frontend/queries/oauth.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\ntype PasswordModalType = 'set' | 'change' | 'remove' | null;\ntype TotpModalType = 'setup' | 'disable' | 'regenerate' | null;\ntype PasskeyModalType = 'setup' | 'manage' | null;\n\nconst SearchSchema = z.object({\n oauth_error: z.string().optional(),\n oauth_error_description: z.string().optional(),\n});\n\nconst OAUTH_ERROR_I18N_MAP: Record<string, string> = {\n access_denied: 'oauth.error.accessDenied',\n temporarily_unavailable: 'oauth.error.temporarilyUnavailable',\n server_error: 'oauth.error.serverError',\n};\n\nfunction ProfileError(props: ErrorComponentProps) {\n return (\n <RouteErrorFallback\n {...props}\n onUnauthorized={() => {\n window.location.href = '/login';\n }}\n />\n );\n}\n\nexport const Route = createFileRoute('/profile/')({\n component: Profile,\n errorComponent: ProfileError,\n validateSearch: SearchSchema,\n beforeLoad: async ({ context }) => {\n if (!context.user) {\n throw redirect({\n to: '/login',\n });\n }\n },\n loader: async ({ context }) => {\n await Promise.all([\n context.queryClient.ensureQueryData(getSessionQueryOptions),\n context.queryClient.ensureQueryData(oauthAccountsQueryOptions),\n context.queryClient.ensureQueryData(appConfigQueryOptions),\n ]);\n },\n});\n\nfunction Profile() {\n const { t } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n\n const oauthError = search.oauth_error;\n const oauthErrorMessage = oauthError\n ? t(OAUTH_ERROR_I18N_MAP[oauthError] ?? 'oauth.error.failed')\n : undefined;\n const [unlinkingProvider, setUnlinkingProvider] = useState<string | null>(\n null,\n );\n const [unlinkModal, setUnlinkModal] = useState<{\n id: string;\n name: string;\n } | null>(null);\n const [passwordModal, setPasswordModal] = useState<PasswordModalType>(null);\n const [totpModal, setTotpModal] = useState<TotpModalType>(null);\n const [passkeyModal, setPasskeyModal] = useState<PasskeyModalType>(null);\n const [showDeleteModal, setShowDeleteModal] = useState(false);\n\n const { data: session } = useSuspenseQuery(getSessionQueryOptions);\n const { data: oauthAccountsData } = useSuspenseQuery(\n oauthAccountsQueryOptions,\n );\n const { data: appConfig } = useSuspenseQuery(appConfigQueryOptions);\n\n const logoutMutation = useMutation({\n ...logoutMutationOptions,\n onSuccess: async () => {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: null,\n });\n await tick();\n router.navigate({\n to: '/login',\n });\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n const unlinkMutation = useMutation({\n ...unlinkOAuthMutationOptions,\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: oauthAccountsQueryOptions.queryKey,\n });\n },\n onSettled: () => {\n setUnlinkingProvider(null);\n },\n });\n\n const handleUnlinkConfirm = async () => {\n if (!unlinkModal) return;\n setUnlinkingProvider(unlinkModal.id);\n await unlinkMutation.mutateAsync(unlinkModal.id);\n };\n\n if (!session.user) {\n return null;\n }\n\n const user = session.user;\n const availableProviders = oauthAccountsData.available_providers;\n const hasLinkedOAuth = availableProviders.some((p) => p.linked);\n const isConfigManaged = user.managed_by === 'config';\n\n const passwordAuthMethod = appConfig.auth.password;\n const passkeyAuthMethod = appConfig.auth.passkey;\n const totpEnabled = passwordAuthMethod.totp.enabled;\n const passkeyEnabled = passkeyAuthMethod.enabled;\n\n const accountDeletionEnabled = appConfig.account_deletion.enabled;\n const retentionPeriod = appConfig.account_deletion.retention;\n\n const retentionDays = (() => {\n const match = retentionPeriod.match(/^(\\d+)([dmy])$/);\n if (!match) return 30;\n const value = parseInt(match[1], 10);\n const unit = match[2];\n switch (unit) {\n case 'd':\n return value;\n case 'm':\n return value * 30;\n case 'y':\n return value * 365;\n default:\n return 30;\n }\n })();\n\n const showPasswordSection = true;\n const showTotpSection = !isConfigManaged && totpEnabled;\n const showPasskeySection = !isConfigManaged && passkeyEnabled;\n const showLinkedAccounts = availableProviders.length > 0;\n const hasSecurityOptions =\n showPasswordSection || showTotpSection || showPasskeySection;\n\n return (\n <AppLayout\n headerActions={\n <TRButton\n appearance=\"ghost\"\n /*\n The visible label collapses below `sm:`, which would leave the\n control unnamed on a phone. `profile.logout` is the same string\n the label renders, so this does not shadow it.\n */\n aria-label={t('profile.logout')}\n data-testid=\"profile-logout\"\n disabled={logoutMutation.isPending}\n loading={logoutMutation.isPending}\n onClick={() => logoutMutation.mutate()}\n type=\"button\"\n uiSize=\"sm\"\n >\n {logoutMutation.isPending ? undefined : (\n <>\n <LogOutIcon aria-hidden className=\"size-tinyrack-lg\" />\n <span className=\"hidden sm:inline\">{t('profile.logout')}</span>\n </>\n )}\n </TRButton>\n }\n >\n <div className=\"flex items-center gap-tinyrack-lg\">\n <InitialAvatar email={user.email} size=\"lg\" />\n <div className=\"flex min-w-0 flex-col gap-tinyrack-3xs\">\n <AuthPageHeader title={t('profile.title')} />\n {/*\n Rendered here rather than as the header's `subtitle`: this node\n carries a testid and needs to truncate, neither of which the\n shared header does, and growing its API for one non-auth caller\n would be the wrong trade.\n */}\n <TRText\n as=\"p\"\n color=\"muted\"\n data-testid=\"profile-user-email\"\n truncate\n variant=\"bodySm\"\n >\n {user.email}\n </TRText>\n </div>\n </div>\n\n {oauthErrorMessage && (\n <Alert icon={CircleAlertIcon} type=\"error\">\n {oauthErrorMessage}\n </Alert>\n )}\n\n {user && <UserInfoSection user={user} />}\n\n {hasSecurityOptions && (\n <TRCard.Root variant=\"outlined\">\n <TRCard.Header className=\"border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md\">\n <TRCard.Title>{t('profile.security.title')}</TRCard.Title>\n <TRCard.Description>\n {t('profile.security.description')}\n </TRCard.Description>\n </TRCard.Header>\n {showTotpSection && user.totp_recovery_codes_missing && (\n <div\n className=\"border-tinyrack-border border-b-tinyrack-default px-tinyrack-lg py-tinyrack-md\"\n data-testid=\"profile-totp-recovery-warning\"\n >\n <Alert icon={CircleAlertIcon} type=\"warning\">\n {t('profile.totp.recoveryCodesMissing')}\n </Alert>\n </div>\n )}\n <TRCard.Content className=\"divide-y divide-tinyrack-border p-0\">\n {showPasswordSection && (\n <PasswordSection\n hasLinkedOAuth={hasLinkedOAuth}\n hasPassword={user.has_password}\n hasSecondFactorOnly={\n user.has_password &&\n !hasLinkedOAuth &&\n (user.totp_registered || user.passkey_count > 0)\n }\n isConfigManaged={isConfigManaged}\n onOpenModal={setPasswordModal}\n />\n )}\n {showTotpSection && (\n <TotpSection\n onOpenModal={setTotpModal}\n recoveryCodesMissing={user.totp_recovery_codes_missing}\n totpEnabled={user.totp_registered}\n />\n )}\n {showPasskeySection && (\n <PasskeySection\n onOpenModal={setPasskeyModal}\n passkeyCount={user.passkey_count}\n />\n )}\n </TRCard.Content>\n </TRCard.Root>\n )}\n\n {showLinkedAccounts && (\n <LinkedAccountsSection\n getAuthorizeUrl={getOAuthAuthorizeUrl}\n onUnlinkRequest={(provider) =>\n setUnlinkModal({\n id: provider.id,\n name: provider.display_name,\n })\n }\n providers={availableProviders}\n unlinkingProvider={unlinkingProvider}\n />\n )}\n\n <DangerZoneSection\n isConfigManaged={isConfigManaged}\n isDeletionEnabled={accountDeletionEnabled}\n onDeleteClick={() => setShowDeleteModal(true)}\n />\n\n <SetPasswordModal\n isOpen={passwordModal === 'set'}\n onClose={() => setPasswordModal(null)}\n />\n <ChangePasswordModal\n isOpen={passwordModal === 'change'}\n onClose={() => setPasswordModal(null)}\n />\n <RemovePasswordModal\n isOpen={passwordModal === 'remove'}\n onClose={() => setPasswordModal(null)}\n />\n\n <SetupTotpModal\n isOpen={totpModal === 'setup'}\n onClose={() => setTotpModal(null)}\n />\n <DisableTotpModal\n isOpen={totpModal === 'disable'}\n onClose={() => setTotpModal(null)}\n />\n <RegenerateTotpRecoveryCodesModal\n isOpen={totpModal === 'regenerate'}\n onClose={() => setTotpModal(null)}\n />\n\n <SetupPasskeyModal\n isOpen={passkeyModal === 'setup'}\n onClose={() => setPasskeyModal(null)}\n />\n <ManagePasskeysModal\n isOpen={passkeyModal === 'manage'}\n onAddNew={() => setPasskeyModal('setup')}\n onClose={() => setPasskeyModal(null)}\n />\n\n <UnlinkOAuthModal\n isOpen={unlinkModal !== null}\n isPending={unlinkMutation.isPending}\n onClose={() => setUnlinkModal(null)}\n onConfirm={handleUnlinkConfirm}\n providerName={unlinkModal?.name ?? ''}\n />\n\n <DeleteAccountModal\n isOpen={showDeleteModal}\n onClose={() => setShowDeleteModal(false)}\n retentionDays={retentionDays}\n />\n </AppLayout>\n );\n}\n"],"x_google_ignoreList":[0,1,2,3,4],"mappings":"s4CAYA,IAAM,GAAQ,EAAiB,QAASA,CAFtC,CAAC,OAAQ,CAAE,EAAG,sDAAuD,IAAK,QAAS,CAAC,CAE9CA,CAAU,ECG5C,GAAW,EAAiB,aAAcC,CAL9C,CAAC,OAAQ,CAAE,EAAG,wBAAyB,IAAK,QAAS,CAAC,EACtD,CAAC,OAAQ,CAAE,EAAG,wBAAyB,IAAK,QAAS,CAAC,EACtD,CAAC,OAAQ,CAAE,GAAI,IAAK,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,IAAK,QAAS,CAAC,EACjE,CAAC,OAAQ,CAAE,GAAI,IAAK,GAAI,KAAM,GAAI,IAAK,GAAI,KAAM,IAAK,QAAS,CAAC,CAElBA,CAAU,ECIpD,GAAS,EAAiB,SAAUC,CATxC,CACE,OACA,CACE,EAAG,mIACH,IAAK,QACP,CACF,EACA,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAS,CAAC,CAEFA,CAAU,ECA9C,GAAW,EAAiB,WAAYC,CAT5C,CACE,OACA,CACE,EAAG,0UACH,IAAK,QACP,CACF,EACA,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,IAAK,IAAK,QAAS,CAAC,CAEZA,CAAU,ECNlD,GAAa,EAAiB,aAAc,CAHhD,CAAC,OAAQ,CAAE,MAAO,KAAM,OAAQ,KAAM,EAAG,IAAK,EAAG,IAAK,GAAI,IAAK,GAAI,IAAK,IAAK,QAAS,CAAC,EACvF,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAS,CAAC,CAEK,CAAU,mBCD5D,SAAA,GAAA,CAAA,kBAAA,oBAAA,iBAAA,+zCA0DA,CC1CA,SAAgB,EAAY,CAC1B,OACA,SACA,QACA,SACA,OACA,WACmB,CAOnB,IAAI,EAeJ,MAdA,CAIE,GAJF,EAAA,EAAA,eAAA,CAAmB,CAAI,EACd,GAIL,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAA,GACA,UAAW,oBACT,EAAS,wBAA0B,4BAEtC,CAAA,GAKH,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,2EAAf,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,4DAAf,EACE,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAW,wEACT,EAAS,8BAAgC,uCAG1C,CACE,CAAA,GACL,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,yDAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,GAAG,MAAM,QAAQ,SAAS,OAAO,kBACtC,CACK,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,GAAG,MAAM,MAAM,QAAQ,QAAQ,mBACpC,CACK,CAAA,EACP,CACE,GACF,IACJ,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,+DACZ,CACE,CAAA,CAEJ,GAET,CC3DA,SAAgB,GAAsB,CACpC,YACA,oBACA,kBACA,mBAC6B,CAC7B,GAAM,CAAE,KAAM,EAAe,EAM7B,OAJI,EAAU,SAAW,EAChB,MAIP,EAAA,EAAA,KAAA,CAAC,EAAO,KAAR,CAAa,QAAQ,oBAArB,EACE,EAAA,EAAA,KAAA,CAAC,EAAO,OAAR,CAAe,UAAU,0FAAzB,EACE,EAAA,EAAA,IAAA,CAAC,EAAO,MAAR,CAAA,SAAe,EAAE,8BAA8B,CAAgB,CAAA,GAC/D,EAAA,EAAA,IAAA,CAAC,EAAO,YAAR,CAAA,SACG,EAAE,oCAAoC,CACrB,CAAA,CACP,KACf,EAAA,EAAA,IAAA,CAAC,EAAO,QAAR,CAAgB,UAAU,+CACvB,EAAU,IAAK,IACd,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,QACE,EAAS,QACP,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,OAAO,SACP,QAAS,IAAsB,EAAS,GACxC,aAAc,EAAE,kCAAkC,EAClD,YAAe,EAAgB,CAAQ,EACvC,KAAK,SACL,OAAO,cAEN,IAAsB,EAAS,GAE5B,IAAA,GADA,EAAE,+BAA+B,CAE7B,CAAA,GAEV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,OAAO,UACP,QACE,EAAA,EAAA,IAAA,CAAC,IAAD,CACE,KAAM,EAAgB,EAAS,GAAI,OAAQ,UAAU,CACtD,CAAA,EAEH,OAAO,cAEN,EAAE,6BAA6B,CACpB,CAAA,EAGlB,OAAQ,EAAS,OAOjB,MACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAU,mBACV,QAAS,EAAS,SAClB,WAAY,EAAS,EACtB,CAAA,EAGH,OACE,EAAS,OACL,EAAE,kCAAkC,EACpC,EAAE,qCAAqC,EAE7C,MAAO,EAAS,YACjB,EAPM,EAAS,EAOf,CACF,CACa,CAAA,CACL,GAEjB,CC5FA,SAAgB,GAAe,CAC7B,eACA,eACsB,CACtB,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAEnC,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,SACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,OAAO,UACP,YAAe,EAAY,EAAc,SAAW,OAAO,EAC3D,KAAK,SACL,OAAO,cAEQ,EAAd,EAAgB,yBAA8B,qBAAqB,CAC5D,CAAA,EAEZ,OAAQ,EACR,KAAM,EACN,OACE,EACI,EAAE,iCAAkC,CAAE,MAAO,CAAa,CAAC,EAC3D,EAAE,iCAAiC,EAEzC,MAAO,EAAE,uBAAuB,CACjC,CAAA,CAEL,CCzBA,SAAgB,GAAgB,CAC9B,cACA,iBACA,kBACA,sBACA,eACuB,CACvB,GAAM,CAAE,KAAM,EAAe,EAE7B,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,QACE,EAAkB,IAAA,GAAY,GAC5B,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,cAAY,0BACZ,OAAO,UACP,YAAe,EAAY,QAAQ,EACnC,KAAK,SACL,OAAO,cAEN,EAAE,yBAAyB,CACpB,CAAA,EACT,GACC,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,cAAY,0BACZ,OAAO,SACP,YAAe,EAAY,QAAQ,EACnC,KAAK,SACL,OAAO,cAEN,EAAE,yBAAyB,CACpB,CAAA,EACR,KACH,CAAC,GAAkB,IAClB,EAAA,EAAA,KAAA,CAAC,EAAU,KAAX,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAU,QAAX,CACE,QACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,SAAA,GACA,KAAK,SACL,OAAO,cAEN,EAAE,yBAAyB,CACpB,CAAA,CAEb,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAU,OAAX,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAU,WAAX,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAU,MAAX,CAAiB,UAAU,sLACzB,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,4CAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAA,GACA,UAAU,iDACX,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAA,SAAM,EAAE,uCAAuC,CAAO,CAAA,CACnD,GACU,CAAA,CACG,CAAA,CACN,CAAA,CACJ,CAAA,CAAA,CAElB,CAAA,CAAA,GAEF,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,cAAY,uBACZ,OAAO,UACP,YAAe,EAAY,KAAK,EAChC,KAAK,SACL,OAAO,cAEN,EAAE,sBAAsB,CACjB,CAAA,EAGd,OAAQ,EACR,KAAM,EACN,KACE,GACE,EAAA,EAAA,KAAA,CAAC,EAAD,CACE,GAAG,MACH,UAAU,oCACV,MAAM,QACN,QAAQ,mBAJV,EAME,EAAA,EAAA,IAAA,CAAC,GAAD,CAAc,cAAA,GAAY,UAAU,2BAA6B,CAAA,GACjE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,EAAE,gCAAgC,CAAQ,CAAA,CAC3C,IACN,IAAA,GAEN,OAEM,EADJ,EACM,8BACA,gCAAgC,EAExC,MAAO,EAAE,wBAAwB,CAClC,CAAA,CAEL,CC1GA,SAAgB,GAAY,CAC1B,cACA,uBACA,eACmB,CACnB,GAAM,CAAE,KAAM,EAAe,EAE7B,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,QACE,GACE,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,cAAY,0BACZ,OAAO,UACP,YAAe,EAAY,YAAY,EACvC,KAAK,SACL,OAAO,cAEN,EAAE,yBAAyB,CACpB,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,cAAY,uBACZ,OAAO,SACP,YAAe,EAAY,SAAS,EACpC,KAAK,SACL,OAAO,cAEN,EAAE,sBAAsB,CACjB,CAAA,CACV,CAAA,CAAA,GAEF,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,cAAY,sBACZ,OAAO,UACP,YAAe,EAAY,OAAO,EAClC,KAAK,SACL,OAAO,cAEN,EAAE,qBAAqB,CAChB,CAAA,EAGd,OAAQ,EACR,KAAM,EACN,OAGQ,EAFN,EACI,EACI,2CACA,8BACF,8BAA8B,EAEtC,MAAO,EAAE,oBAAoB,CAC9B,CAAA,CAEL,CC5DA,IAAM,GAAqE,CACzE,MAAO,EACP,QAAS,EACT,KAAM,CACR,EAQA,SAAgB,EAAY,CAAE,UAAS,YAA8B,CACnE,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAa,gBAAgB,IAC7B,KAAM,GAAa,GACnB,KAAM,EAEL,UACI,CAAA,CAEX,CClBA,SAAgB,GAAiB,CAC/B,SACA,UACA,eACA,YACA,aACwB,CACxB,GAAM,CAAE,KAAM,EAAe,EACvB,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAoC,IAAI,EAEhD,MAAoB,CACpB,IACJ,EAAS,IAAI,EACb,EAAQ,EACV,EAYA,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAAa,EAAE,iDAAkD,CAC/D,SAAU,CACZ,CAAC,EACD,KAAM,GACE,SACR,QAAS,EACT,aAAc,EACd,MAAO,EAAE,0CAA0C,EACnD,QAAQ,wBAER,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,wDAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,mBAClB,EAAE,6CAA8C,CAC/C,SAAU,CACZ,CAAC,CACU,CAAA,EAEZ,IAAS,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAAS,CAAmB,CAAA,GAE3D,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,sBACZ,SAAU,EACV,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,2CAA2C,CACtC,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,sBACZ,SAAU,EACV,OAAO,SACP,QAAS,EACT,aAAc,EAAE,kCAAkC,EAClD,QAAS,SAjDe,CAChC,EAAS,IAAI,EACb,GAAI,CACF,MAAM,EAAU,EAChB,EAAY,CACd,MAAQ,CACN,EAAS,EAAE,oCAAoC,CAAC,CAClD,CACF,EA0CU,KAAK,SACL,OAAO,cAEN,EAAE,+BAA+B,CAC1B,CAAA,CACE,CAAA,CAAA,CACX,GACA,CAAA,CAEX,CCtFA,SAAS,GAAQ,CAAE,QAAO,SAA2C,CACnE,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,2FAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,UAAU,WAAW,MAAM,QAAQ,QAAQ,mBAChD,CACK,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,SAAA,GAAS,QAAQ,SAAS,OAAO,kBACtC,CACK,CAAA,CACL,GAET,CASA,SAAgB,GAAgB,CAAE,QAA8B,CAC9D,GAAM,CAAE,GAAM,EAAe,EAE7B,OACE,EAAA,EAAA,KAAA,CAAC,EAAO,KAAR,CAAa,QAAQ,oBAArB,EACE,EAAA,EAAA,KAAA,CAAC,EAAO,OAAR,CAAe,UAAU,0FAAzB,EACE,EAAA,EAAA,IAAA,CAAC,EAAO,MAAR,CAAA,SAAe,EAAE,uBAAuB,CAAgB,CAAA,GACxD,EAAA,EAAA,IAAA,CAAC,EAAO,YAAR,CAAA,SACG,EAAE,6BAA6B,CACd,CAAA,CACP,KACf,EAAA,EAAA,KAAA,CAAC,EAAO,QAAR,CAAgB,UAAU,+CAA1B,EACE,EAAA,EAAA,IAAA,CAAC,GAAD,CAAS,MAAO,EAAE,kBAAkB,EAAG,MAAO,EAAK,GAAM,CAAA,GACzD,EAAA,EAAA,IAAA,CAAC,GAAD,CAAS,MAAO,EAAE,qBAAqB,EAAG,MAAO,EAAK,KAAQ,CAAA,CAChD,GACL,GAEjB,CClBA,SAAgB,GAAU,CAAE,WAAU,iBAAiC,CACrE,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,uDAAf,EAME,EAAA,EAAA,IAAA,CAAC,EAAD,CAAU,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CAAgB,QAAS,EAAe,MAAA,EAAO,CAAA,GAC/C,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,qEAKd,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,4EACZ,UACE,CAAA,CACD,CAAA,CACH,GAET,CCjCA,IAAa,GAA6B,EAAgB,CACxD,WAAY,KAAO,IAIV,EAAO,MAHI,EAAO,IAAI,KAAK,SAAS,MAAM,CAC/C,KAAM,CACR,CAAC,CACgB,CAErB,CAAC,EASY,GAAgC,EAAgB,CAC3D,WAAY,KAAO,IAIV,EAAO,MAHI,EAAO,IAAI,KAAK,SAAS,KAAK,CAC9C,KAAM,CACR,CAAC,CACgB,CAErB,CAAC,EAUY,GAAgC,EAAgB,CAC3D,WAAY,KAAO,IAIV,EAAO,MAHI,EAAO,IAAI,KAAK,SAAS,QAAQ,CACjD,KAAM,CACR,CAAC,CACgB,CAErB,CAAC,EC1BD,SAAgB,GAAoB,CAClC,SACA,WAC2B,CAC3B,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAC7B,CAAE,KAAM,GAAe,EAAiB,CAAqB,EAC7D,EAAiB,EAAW,KAAK,SAAS,OA8B1C,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KA3BR,EACG,OAAO,CACN,gBAAiB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,EAAE,8BAA8B,CAAC,EACpE,YAAa,EACV,OAAO,CAAC,CACR,IACC,EAAe,WACf,EAAE,0BAA2B,CAC3B,MAAO,EAAe,UACxB,CAAC,CACH,CAAC,CACA,IACC,EAAe,WACf,EAAE,0BAA2B,CAC3B,MAAO,EAAe,UACxB,CAAC,CACH,EACF,gBAAiB,EAAE,OAAO,CAC5B,CAAC,CAAC,CACD,OAAQ,GAAS,EAAK,cAAgB,EAAK,gBAAiB,CAC3D,QAAS,EAAE,qCAAqC,EAChD,KAAM,CAAC,iBAAiB,CAC1B,CAAC,EACL,CAAC,EAAe,WAAY,EAAe,WAAY,CAAC,CAIvB,CAAM,EACvC,cAAe,CACb,gBAAiB,GACjB,YAAa,GACb,gBAAiB,EACnB,CACF,CAAC,EAEK,EAAW,EAAY,CAC3B,GAAG,GACH,cAAiB,CACf,EAAY,kBAAkB,CAC5B,SAAU,EAAuB,QACnC,CAAC,EACD,EAAY,CACd,CACF,CAAC,EAEK,MAAoB,CACxB,EAAK,MAAM,EACX,EAAQ,CACV,EAEM,EAAe,EAAK,aAAa,KAAO,IAAS,CACrD,GAAI,CACF,MAAM,EAAS,YAAY,CACzB,iBAAkB,EAAK,gBACvB,aAAc,EAAK,WACrB,CAAC,CACH,OAAS,EAAK,CAEV,aAAe,GACf,EAAI,OAAS,2BAEb,EAAK,SAAS,kBAAmB,CAC/B,QAAS,EAAE,6CAA6C,CAC1D,CAAC,EAED,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,oCAAoC,CACjD,CAAC,CAEL,CACF,CAAC,EAED,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAAa,EAAE,0CAA0C,EACzD,KAAM,EACE,SACR,QAAS,EACT,MAAO,EAAE,oCAAoC,YAE7C,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,+CACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,gBAC7B,YAAY,wCACZ,GAAG,mBACH,MAAO,EAAE,8CAA8C,EACvD,YAAa,EACX,yDACF,EACA,GAAI,EAAK,SAAS,iBAAiB,EACnC,KAAK,UACN,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,YAC7B,YAAY,oCACZ,GAAG,sBACH,MAAO,EAAE,0CAA0C,EACnD,YAAa,EAAE,qDAAqD,EACpE,GAAI,EAAK,SAAS,aAAa,EAC/B,KAAK,UACN,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,gBAC7B,YAAY,wCACZ,GAAG,0BACH,MAAO,EAAE,8CAA8C,EACvD,YAAa,EACX,yDACF,EACA,GAAI,EAAK,SAAS,iBAAiB,EACnC,KAAK,UACN,CAAA,EACA,EAAK,UAAU,OAAO,OACrB,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAClB,EAAK,UAAU,OAAO,KAAK,OACjB,CAAA,GAEf,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,yBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,qCAAqC,CAChC,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,yBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EAAS,UAClB,aAAc,EAAE,yCAAyC,EACzD,KAAK,SACL,OAAO,cAEN,EAAS,UACN,IAAA,GACA,EAAE,qCAAqC,CACnC,CAAA,CACE,CAAA,CAAA,CACV,GACD,CAAA,CAEX,CChLA,IAAa,GAA+B,EAAgB,CAC1D,WAAY,SAEH,EAAO,MADI,EAAO,IAAI,KAAK,QAAQ,CACzB,CAErB,CAAC,ECQD,SAAgB,GAAmB,CACjC,SACA,UACA,iBAC0B,CAC1B,GAAM,CAAE,KAAM,EAAe,EACvB,EAAS,EAAU,EACnB,EAAc,EAAe,EAiB7B,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KAdR,EAAE,OAAO,CACP,aAAc,EACX,OAAO,CAAC,CACR,OACE,GACC,EAAI,YAAY,IAChB,EAAE,gDAAgD,CAAC,CAAC,YAAY,EAClE,CAAE,QAAS,EAAE,iCAAiC,CAAE,CAClD,CACJ,CAAC,EACH,CAAC,CAAC,CAI+B,CAAM,EACvC,cAAe,CAAE,aAAc,EAAG,CACpC,CAAC,EAEK,EAAW,EAAY,CAC3B,GAAG,GACH,UAAW,SAAY,CACrB,EAAY,aAAa,EAAuB,SAAU,CACxD,KAAM,IACR,CAAC,EACD,MAAM,EAAK,EACX,EAAO,SAAS,CAAE,GAAI,QAAS,CAAC,CAClC,CACF,CAAC,EAEK,MAAoB,CACpB,EAAS,YACb,EAAK,MAAM,EACX,EAAQ,EACV,EAEM,EAAe,EAAK,aAAa,SAAY,CACjD,GAAI,CACF,MAAM,EAAS,YAAY,CAC7B,MAAQ,CACN,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,6BAA6B,CAC1C,CAAC,CACH,CACF,CAAC,EAED,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,KAAM,EACE,SACR,QAAS,EACT,aAAc,EAAS,UACvB,MAAO,EAAE,mCAAmC,EAC5C,QAAQ,wBAER,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,+CACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,kBACnB,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,yCAAf,EACE,EAAA,EAAA,IAAA,CAAC,IAAD,CAAA,SACG,EAAE,0CAA2C,CAC5C,KAAM,CACR,CAAC,CACA,CAAA,GACH,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,mDACV,EAAE,qCAAqC,CACvC,CAAA,CACA,GACM,CAAA,GAEb,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAa,MACb,MAAO,EAAK,UAAU,OAAO,aAC7B,YAAY,uBACZ,GAAG,sBACH,MAAO,EAAE,0CAA0C,EACnD,YAAa,EAAE,gDAAgD,EAC/D,GAAI,EAAK,SAAS,cAAc,EAChC,KAAK,MACN,CAAA,EAEA,EAAK,UAAU,OAAO,OACrB,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAClB,EAAK,UAAU,OAAO,KAAK,OACjB,CAAA,GAGf,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,wBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,oCAAoC,CAC/B,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,wBACZ,SAAU,EAAS,UACnB,OAAO,SACP,QAAS,EAAS,UAClB,aAAc,EAAE,wCAAwC,EACxD,KAAK,SACL,OAAO,cAEN,EAAS,UACN,IAAA,GACA,EAAE,qCAAqC,CACnC,CAAA,CACE,CAAA,CAAA,CACV,GACD,CAAA,CAEX,CClIA,SAAgB,GAAiB,CAAE,SAAQ,WAAkC,CAC3E,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAa7B,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KAVR,EAAE,OAAO,CACP,KAAM,EACH,OAAO,CAAC,CACR,OAAO,EAAG,EAAE,wBAAwB,CAAC,CAAC,CACtC,MAAM,UAAW,EAAE,wBAAwB,CAAC,CACjD,CAAC,EACH,CAAC,CAAC,CAI+B,CAAM,EACvC,cAAe,CAAE,KAAM,EAAG,CAC5B,CAAC,EAEK,EAAW,EAAY,CAC3B,GAAG,GACH,cAAiB,CACf,EAAY,kBAAkB,CAC5B,SAAU,EAAuB,QACnC,CAAC,EACD,EAAY,CACd,CACF,CAAC,EAEK,MAAoB,CACxB,EAAK,MAAM,EACX,EAAQ,CACV,EAEM,EAAe,EAAK,aAAa,KAAO,IAAS,CACrD,GAAI,CACF,MAAM,EAAS,YAAY,CAAE,KAAM,EAAK,IAAK,CAAC,CAChD,OAAS,EAAO,CACd,GAAI,aAAiB,GACf,EAAM,OAAS,mCAAoC,CACrD,EAAK,SAAS,OAAQ,CACpB,QAAS,EACP,wDACF,CACF,CAAC,EACD,MACF,CAEF,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,iCAAiC,CAC9C,CAAC,CACH,CACF,CAAC,EAED,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAAa,EAAE,uCAAuC,EACtD,KAAM,EACE,SACR,QAAS,EACT,MAAO,EAAE,iCAAiC,EAC1C,QAAQ,wBAER,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,+CACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,mBAClB,EAAE,mCAAmC,CAC3B,CAAA,GAEb,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAa,gBACb,MAAO,EAAK,UAAU,OAAO,KAC7B,YAAY,qBACZ,GAAG,oBACH,UAAU,UACV,MAAO,EAAE,qCAAqC,EAC9C,UAAW,EACX,QAAQ,SACR,YAAY,SACZ,GAAI,EAAK,SAAS,MAAM,EACxB,KAAK,MACN,CAAA,GAED,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,sBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,kCAAkC,CAC7B,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,sBACZ,SAAU,EAAS,UACnB,OAAO,SACP,QAAS,EAAS,UAClB,aAAc,EAAE,qCAAqC,EACrD,KAAK,SACL,OAAO,cAEN,EAAS,UACN,IAAA,GACA,EAAE,mCAAmC,CACjC,CAAA,CACE,CAAA,CAAA,CACV,GACD,CAAA,CAEX,CCpGA,SAAgB,GAAoB,CAClC,SACA,UACA,YAC2B,CAC3B,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAC7B,CAAC,EAAgB,IAAA,EAAA,EAAA,SAAA,CACrB,IACF,EACM,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAAyC,IAAI,EAC1D,CAAC,EAAoB,IAAA,EAAA,EAAA,SAAA,CACzB,IACF,EACM,CAAC,EAAa,IAAA,EAAA,EAAA,SAAA,CAA0C,IAAI,EAE5D,CAAE,KAAM,EAAc,aAAc,EAAS,CACjD,GAAG,EACH,QAAS,CACX,CAAC,EAEK,EAAiB,EAAY,CACjC,GAAG,EACH,cAAiB,CACf,EAAY,kBAAkB,CAAE,SAAU,EAAU,SAAS,CAAE,CAAC,EAChE,EAAY,kBAAkB,CAC5B,SAAU,EAAuB,QACnC,CAAC,CACH,EACA,cAAiB,CACf,EAAc,IAAI,CACpB,CACF,CAAC,EAEK,GAAA,EAAA,EAAA,YAAA,KAAgC,CACpC,EAAkB,IAAI,EACtB,EAAc,IAAI,EAClB,EAAsB,IAAI,EAC1B,EAAe,IAAI,EACnB,EAAQ,CACV,EAAG,CAAC,CAAO,CAAC,EAEN,EAAuB,GAAyB,CACpD,EAAsB,EAAQ,EAAE,EAChC,EAAe,IAAI,CACrB,EAEM,MAA2B,CAC/B,EAAsB,IAAI,EAC1B,EAAe,IAAI,CACrB,EAEM,EAAsB,KAAO,IAAyB,CAC1D,EAAc,EAAQ,EAAE,EACxB,EAAsB,IAAI,EAC1B,GAAI,CACF,MAAM,EAAe,YAAY,CAAE,GAAI,EAAQ,EAAG,CAAC,CACrD,OAAS,EAAO,CACd,GAAI,aAAiB,GACf,EAAM,OAAS,mCAAoC,CACrD,EACE,EAAE,0DAA0D,CAC9D,EACA,MACF,CAEF,EAAe,EAAE,yCAAyC,CAAC,CAC7D,CACF,EAEM,EAAc,GACX,IAAI,KAAK,CAAU,CAAC,CAAC,mBAAmB,IAAA,GAAW,CACxD,KAAM,UACN,MAAO,QACP,IAAK,SACP,CAAC,EAGG,EAAW,GAAc,UAAY,CAAC,EAE5C,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CACE,KAAM,EACE,SACR,QAAS,EACT,KAAK,KACL,MAAO,EAAE,mCAAmC,WAL9C,EAOE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,wDAAf,CACG,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAAS,CAAyB,CAAA,EAGxD,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,+CACb,EAAA,EAAA,IAAA,CAAC,EAAD,CAAW,OAAO,IAAM,CAAA,CACrB,CAAA,EAGN,CAAC,GAAa,EAAS,SAAW,IACjC,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAU,uEACV,cAAY,2BAEZ,EAAA,EAAA,IAAA,CAAC,IAAD,CAAA,SAAI,EAAE,wCAAwC,CAAK,CAAA,CAChD,CAAA,EAGN,CAAC,GAAa,EAAS,OAAS,IAC/B,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,yCACZ,EAAS,IAAK,IACb,EAAA,EAAA,IAAA,CAAC,GAAD,CACc,aACZ,mBAAoB,IAAuB,EAAQ,GACnD,WAAY,IAAe,EAAQ,GACnC,UAAW,GAAgB,KAAO,EAAQ,GAE1C,eAAgB,EAChB,iBAAoB,EAAkB,IAAI,EAC1C,oBAAuB,EAAoB,CAAO,EAClD,WAAc,EAAkB,CAAO,EACvC,oBAAuB,EAAoB,CAAO,EACzC,SACV,EAPM,EAAQ,EAOd,CACF,CACE,CAAA,CAEJ,KAEL,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,wBACZ,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,mCAAmC,CAC9B,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,0BACZ,OAAO,UACP,YAAe,CACb,EAAY,EACZ,EAAS,CACX,EACA,KAAK,SACL,OAAO,cAEN,EAAE,oCAAoC,CAC/B,CAAA,CACE,CAAA,CAAA,CACT,GAEX,CAeA,SAAS,GAAY,CACnB,UACA,aACA,YACA,qBACA,SACA,eACA,kBACA,kBACA,iBACA,cACmB,CACnB,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAa7B,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KAVR,EAAE,OAAO,CACP,KAAM,EACH,OAAO,CAAC,CACR,IAAI,EAAG,EAAE,kCAAkC,CAAC,CAAC,CAC7C,IAAI,IAAK,EAAE,6BAA6B,CAAC,CAC9C,CAAC,EACH,CAAC,CAAC,CAI+B,CAAM,EACvC,cAAe,CAAE,KAAM,EAAQ,MAAQ,EAAG,CAC5C,CAAC,EAEK,EAAiB,EAAY,CACjC,GAAG,EACH,cAAiB,CACf,EAAY,kBAAkB,CAAE,SAAU,EAAU,SAAS,CAAE,CAAC,EAChE,EAAa,CACf,CACF,CAAC,EAEK,EAAe,EAAK,aAAa,KAAO,IAAS,CACrD,GAAI,CACF,MAAM,EAAe,YAAY,CAAE,GAAI,EAAQ,GAAI,KAAM,EAAK,IAAK,CAAC,CACtE,MAAQ,CACN,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,yCAAyC,CACtD,CAAC,CACH,CACF,CAAC,EA6ED,OA3EI,GAEA,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,4FACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,uBACZ,MAAO,EAAK,UAAU,OAAO,KAC7B,YAAY,uBACZ,UAAA,GACA,MAAO,EAAE,uCAAuC,EAChD,YAAa,EAAE,6CAA6C,EAC5D,GAAI,EAAK,SAAS,MAAM,EACxB,KAAK,MACN,CAAA,GACD,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,4CAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,SAAU,EAAe,UACzB,YAAe,CACb,EAAK,MAAM,EACX,EAAa,CACf,EACA,KAAK,SACL,OAAO,cAEN,EAAE,wCAAwC,CACnC,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,SAAU,EAAe,UACzB,OAAO,UACP,KAAK,SACL,OAAO,cAEN,EAAe,UACZ,EAAE,oCAAoC,EACtC,EAAE,kCAAkC,CAChC,CAAA,CACP,GACD,IAIN,GAEA,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,uKAAf,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,6CAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,UAAU,kBAAoB,CAAA,GAC1C,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,4BACb,EAAE,iDAAiD,CAChD,CAAA,CACH,KACL,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,gCAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,wCAAwC,CACnC,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,OAAO,SACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,oCAAoC,CAC/B,CAAA,CACP,GACF,KAKP,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAU,gGACV,cAAY,wBAFd,EAIE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,6CAAf,CACG,EAAQ,cAAgB,eACvB,EAAA,EAAA,IAAA,CAAC,GAAD,CAAW,UAAU,wCAA0C,CAAA,GAE/D,EAAA,EAAA,IAAA,CAAC,GAAD,CAAgB,UAAU,wCAA0C,CAAA,GAEtE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,iDACZ,EAAQ,MAAQ,EAAE,4CAA4C,CAC5D,CAAA,GACL,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,uFAAf,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SACG,EAAE,wCAAyC,CAC1C,KAAM,EAAW,EAAQ,UAAU,CACrC,CAAC,CACG,CAAA,EACL,EAAQ,YACP,EAAA,EAAA,IAAA,CAAC,GAAD,CAAS,OAAO,KAAK,QAAQ,mBAC1B,EAAE,sCAAsC,CAClC,CAAA,CAER,GACF,CAAA,CAAA,CACF,KACL,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,gCAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,aAAY,EAAE,oCAAoC,EAClD,QAAS,EACT,KAAK,SACL,OAAO,eAEP,EAAA,EAAA,IAAA,CAAC,GAAD,CAAY,UAAU,kBAAoB,CAAA,CAClC,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,aAAY,EAAE,oCAAoC,EAClD,SAAU,EACV,OAAO,SACP,QAAS,EACT,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAa,IAAA,IAAY,EAAA,EAAA,IAAA,CAAC,EAAD,CAAY,UAAU,kBAAoB,CAAA,CAC5D,CAAA,CACP,GACF,GAET,CClWA,SAAgB,GAAiC,CAC/C,SACA,WACwC,CACxC,GAAM,CAAE,KAAM,EAAe,EACvB,EAAS,EAAU,EACnB,EAAc,EAAe,EAC7B,CAAE,KAAM,GAAc,EAAiB,CAAqB,EAC5D,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAoC,QAAQ,EACnD,CAAC,EAAU,IAAA,EAAA,EAAA,SAAA,CACsC,IAAI,EACrD,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAA2C,IAAI,EAE9D,EAAW,EAAY,CAC3B,GAAG,GACH,UAAW,KAAO,IAAS,CACzB,EAAY,CAAI,EAChB,EAAQ,UAAU,EAClB,MAAM,EAAY,kBAAkB,CAClC,SAAU,EAAuB,QACnC,CAAC,CACH,CACF,CAAC,EAEK,GAAA,EAAA,EAAA,YAAA,KAA0B,CAC9B,EAAQ,QAAQ,EAChB,EAAY,IAAI,EAChB,EAAgB,IAAI,EACpB,EAAS,MAAM,CACjB,EAAG,CAAC,CAAQ,CAAC,EAEP,GAAA,EAAA,EAAA,YAAA,KAAgC,CACpC,EAAM,EACN,EAAQ,CACV,EAAG,CAAC,EAAS,CAAK,CAAC,EAEb,GAAA,EAAA,EAAA,YAAA,CACJ,KAAO,IAAiB,CACtB,EAAgB,IAAI,EAEpB,GAAI,CACF,MAAM,EAAS,YAAY,CAAE,MAAK,CAAC,CACrC,OAAS,EAAO,CACd,GAAI,aAAiB,EAAc,CACjC,GAAI,EAAM,OAAS,oBACjB,MAAM,EAGR,GAAI,EAAM,OAAS,eAAgB,CACjC,EAAY,aAAa,EAAuB,SAAU,CACxD,KAAM,IACR,CAAC,EACD,MAAM,EAAK,EACX,EAAO,SAAS,CAAE,GAAI,QAAS,CAAC,EAChC,MACF,CAEA,GACE,EAAM,OAAS,oBACf,EAAM,OAAS,mBACf,CACA,MAAM,EAAY,kBAAkB,CAClC,SAAU,EAAuB,QACnC,CAAC,EACD,EAAY,EACZ,MACF,CACF,CAEA,EAAgB,EAAE,8CAA8C,CAAC,CACnE,CACF,EACA,CAAC,EAAa,EAAU,EAAa,EAAQ,CAAC,CAChD,EAMA,OAJK,EAAU,KAAK,SAAS,KAAK,SAKhC,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAEM,EADJ,IAAS,SACH,2CACA,kDAAkD,EAE1D,KAAM,EACE,SACR,QAAS,EACT,aAAc,IAAS,WACvB,KAAK,KACL,MAEM,EADJ,IAAS,SACH,qCACA,4CAA4C,WAGnD,IAAS,UACR,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,0BAAf,CACG,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAAS,CAA0B,CAAA,CACrD,CAAA,GAEP,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,eAAgB,EAAE,oCAAoC,EACtD,UAAW,EAAS,UACpB,SAAU,EACV,YAAa,EAAE,yCAAyC,EACxD,YAAa,EAAE,qCAAqC,CACrD,CAAA,CACE,KAEL,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAW,EACX,cAAe,GAAU,gBAAkB,CAAC,CAC7C,CAAA,CACE,CAAA,CAEF,CAAA,EA5CA,IA8CX,CCnIA,SAAgB,GAAoB,CAClC,SACA,WAC2B,CAC3B,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAU7B,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KAPR,EAAE,OAAO,CACP,gBAAiB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAG,EAAE,8BAA8B,CAAC,CACtE,CAAC,EACH,CAAC,CAAC,CAI+B,CAAM,EACvC,cAAe,CAAE,gBAAiB,EAAG,CACvC,CAAC,EAEK,EAAW,EAAY,CAC3B,GAAG,GACH,cAAiB,CACf,EAAY,kBAAkB,CAC5B,SAAU,EAAuB,QACnC,CAAC,EACD,EAAY,CACd,CACF,CAAC,EAEK,MAAoB,CACxB,EAAK,MAAM,EACX,EAAQ,CACV,EAEM,EAAe,EAAK,aAAa,KAAO,IAAS,CACrD,GAAI,CACF,MAAM,EAAS,YAAY,CACzB,iBAAkB,EAAK,eACzB,CAAC,CACH,OAAS,EAAK,CACZ,GAAI,aAAe,EAAc,CAC/B,GAAI,EAAI,OAAS,2BAA4B,CAC3C,EAAK,SAAS,kBAAmB,CAC/B,QAAS,EAAE,6CAA6C,CAC1D,CAAC,EACD,MACF,CACA,GAAI,EAAI,OAAS,iCAAkC,CACjD,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,sCAAsC,CACnD,CAAC,EACD,MACF,CACA,GAAI,EAAI,OAAS,iDAAkD,CACjE,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,6CAA6C,CAC1D,CAAC,EACD,MACF,CACF,CACA,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,oCAAoC,CACjD,CAAC,CACH,CACF,CAAC,EAED,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAAa,EAAE,0CAA0C,EACzD,KAAM,EACE,SACR,QAAS,EACT,MAAO,EAAE,oCAAoC,EAC7C,QAAQ,wBAER,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,+CACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,gBAC7B,YAAY,wBACZ,GAAG,0BACH,MAAO,EAAE,8CAA8C,EACvD,YAAa,EACX,yDACF,EACA,GAAI,EAAK,SAAS,iBAAiB,EACnC,KAAK,UACN,CAAA,EACA,EAAK,UAAU,OAAO,OACrB,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAClB,EAAK,UAAU,OAAO,KAAK,OACjB,CAAA,GAEf,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,yBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,qCAAqC,CAChC,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,yBACZ,SAAU,EAAS,UACnB,OAAO,SACP,QAAS,EAAS,UAClB,aAAc,EAAE,yCAAyC,EACzD,KAAK,SACL,OAAO,cAEN,EAAS,UACN,IAAA,GACA,EAAE,qCAAqC,CACnC,CAAA,CACE,CAAA,CAAA,CACV,GACD,CAAA,CAEX,CCzHA,SAAgB,GAAiB,CAAE,SAAQ,WAAkC,CAC3E,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAC7B,CAAE,KAAM,GAAe,EAAiB,CAAqB,EAC7D,EAAiB,EAAW,KAAK,SAAS,OA6B1C,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KA1BR,EACG,OAAO,CACN,SAAU,EACP,OAAO,CAAC,CACR,IACC,EAAe,WACf,EAAE,0BAA2B,CAC3B,MAAO,EAAe,UACxB,CAAC,CACH,CAAC,CACA,IACC,EAAe,WACf,EAAE,0BAA2B,CAC3B,MAAO,EAAe,UACxB,CAAC,CACH,EACF,gBAAiB,EAAE,OAAO,CAC5B,CAAC,CAAC,CACD,OAAQ,GAAS,EAAK,WAAa,EAAK,gBAAiB,CACxD,QAAS,EAAE,qCAAqC,EAChD,KAAM,CAAC,iBAAiB,CAC1B,CAAC,EACL,CAAC,EAAe,WAAY,EAAe,WAAY,CAAC,CAIvB,CAAM,EACvC,cAAe,CAAE,SAAU,GAAI,gBAAiB,EAAG,CACrD,CAAC,EAEK,EAAW,EAAY,CAC3B,GAAG,GACH,cAAiB,CACf,EAAY,kBAAkB,CAC5B,SAAU,EAAuB,QACnC,CAAC,EACD,EAAY,CACd,CACF,CAAC,EAEK,MAAoB,CACxB,EAAK,MAAM,EACX,EAAQ,CACV,EAEM,EAAe,EAAK,aAAa,KAAO,IAAS,CACrD,GAAI,CACF,MAAM,EAAS,YAAY,CAAE,SAAU,EAAK,QAAS,CAAC,CACxD,MAAgB,CAEd,EAAK,SAAS,OAAQ,CACpB,QAAS,EAAE,iCAAiC,CAC9C,CAAC,CACH,CACF,CAAC,EAED,OACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAAa,EAAE,uCAAuC,EACtD,KAAM,EACE,SACR,QAAS,EACT,MAAO,EAAE,iCAAiC,YAE1C,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,+CACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,SAC7B,YAAY,8BACZ,GAAG,eACH,MAAO,EAAE,uCAAuC,EAChD,YAAa,EAAE,kDAAkD,EACjE,GAAI,EAAK,SAAS,UAAU,EAC5B,KAAK,UACN,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,gBAC7B,YAAY,qCACZ,GAAG,mBACH,MAAO,EAAE,2CAA2C,EACpD,YAAa,EACX,sDACF,EACA,GAAI,EAAK,SAAS,iBAAiB,EACnC,KAAK,UACN,CAAA,EACA,EAAK,UAAU,OAAO,OACrB,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAClB,EAAK,UAAU,OAAO,KAAK,OACjB,CAAA,GAEf,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,sBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,kCAAkC,CAC7B,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,sBACZ,SAAU,EAAS,UACnB,OAAO,UACP,QAAS,EAAS,UAClB,aAAc,EAAE,sCAAsC,EACtD,KAAK,SACL,OAAO,cAEN,EAAS,UACN,IAAA,GACA,EAAE,kCAAkC,CAChC,CAAA,CACE,CAAA,CAAA,CACV,GACD,CAAA,CAEX,CChIA,SAAgB,GAAkB,CAChC,SACA,UACA,aAAa,GACb,kBAAkB,GAClB,kBACyB,CACzB,GAAM,CAAE,KAAM,EAAe,EACvB,EAAc,EAAe,EAC7B,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAA+B,MAAM,EAC5C,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAA2C,IAAI,EAc9D,EAAO,EAAQ,CACnB,SAAU,GAAA,EAAA,EAAA,QAAA,KAXR,EAAE,OAAO,CACP,KAAM,EACH,OAAO,CAAC,CACR,IAAI,IAAK,EAAE,6BAA6B,CAAC,CAAC,CAC1C,SAAS,CAAC,CACV,UAAW,GAAQ,GAAK,KAAK,GAAK,IAAA,EAAS,CAChD,CAAC,EACH,CAAC,CAAC,CAI+B,CAAM,EACvC,cAAe,CAAE,KAAM,EAAG,CAC5B,CAAC,EAEK,EAAmB,EAAY,CACnC,GAAG,EACH,cAAiB,CACf,EAAY,kBAAkB,CAAE,SAAU,EAAU,SAAS,CAAE,CAAC,EAChE,EAAY,kBAAkB,CAC5B,SAAU,EAAuB,QACnC,CAAC,EACD,EAAY,CACd,EACA,QAAU,GAAU,CAClB,EAAQ,MAAM,EACV,EAAM,OAAS,kBACjB,EAAgB,EAAE,sCAAsC,CAAC,EAEzD,EAAgB,EAAE,kCAAkC,CAAC,CAEzD,CACF,CAAC,EAEK,GAAA,EAAA,EAAA,YAAA,KAAgC,CACpC,EAAK,MAAM,EACX,EAAQ,MAAM,EACd,EAAgB,IAAI,EACpB,EAAQ,CACV,EAAG,CAAC,EAAM,CAAO,CAAC,EAEZ,EAAiB,EAAK,aAAa,KAAO,IAAS,CACvD,EAAQ,UAAU,EAClB,EAAgB,IAAI,EACpB,GAAI,CACF,MAAM,EAAiB,YAAY,CAAE,KAAM,EAAK,IAAK,CAAC,CACxD,MAAQ,CAER,CACF,CAAC,EAEK,EAAY,EAAiB,UAEnC,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CACE,YACE,EACI,EAAE,gDAAgD,EAClD,IAAA,GAEN,KAAM,EACE,SACR,QAAS,EACT,aAAc,EACd,KAAK,KACL,MAAO,EAAE,kCAAkC,WAX7C,CAaG,IAAS,SACR,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,+CACV,SAAU,WAFZ,EAIE,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,qDACV,EAAE,wCAAwC,CAC1C,CAAA,EAEF,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAAS,CAA0B,CAAA,GAG1D,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAO,EAAK,UAAU,OAAO,KAC7B,YAAY,sBACZ,KAAM,EAAE,qCAAqC,EAC7C,GAAG,eACH,MAAO,EAAE,sCAAsC,EAC/C,YAAa,EAAE,4CAA4C,EAC3D,GAAI,EAAK,SAAS,MAAM,EACxB,KAAK,MACN,CAAA,GAED,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,uBACZ,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,mCAAmC,CAC9B,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,cAAY,yBACZ,OAAO,UACP,KAAK,SACL,OAAO,cAEN,EAAE,qCAAqC,CAChC,CAAA,CACE,CAAA,CAAA,EACb,GAAmB,IAClB,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,wDACX,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,yCAAyC,CACpC,CAAA,CACT,CAAA,CAED,IAGP,IAAS,aACR,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAU,4DACV,cAAY,iCAFd,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAW,OAAO,IAAM,CAAA,GACxB,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,iEACV,EAAE,6CAA6C,CAC/C,CAAA,CACA,KAEL,EAAA,EAAA,IAAA,CAAC,EAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,cAAY,uBACZ,SAAU,EACV,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,mCAAmC,CAC9B,CAAA,CACE,CAAA,CACX,GAEF,GAEX,CChLA,SAAgB,GAAe,CAC7B,SACA,UACA,aAAa,GACb,qBAAqB,GACrB,qBACsB,CACtB,GAAM,CAAE,KAAM,EAAe,EAEvB,CACJ,OACA,YACA,gBACA,iBACA,kBACA,mBACA,aACA,SACA,aACA,SACA,uBACA,SACE,EAAa,CACf,UAAW,GACX,qBAAwB,CACtB,EAAM,EACN,EAAQ,CACV,CACF,CAAC,EAEK,GAAA,EAAA,EAAA,YAAA,KAAgC,CACpC,EAAM,EACN,EAAQ,CACV,EAAG,CAAC,EAAS,CAAK,CAAC,EAEb,GAAA,EAAA,EAAA,YAAA,KAAoC,CACpC,CAAC,GAAa,CAAC,GACjB,EAAW,CAEf,EAAG,CAAC,EAAW,EAAgB,CAAU,CAAC,EAEtC,GAAU,CAAC,GAAa,CAAC,GAAkB,IAAS,SACtD,EAAgB,EAGlB,IAAM,GAAA,EAAA,EAAA,YAAA,CACJ,KAAO,IAAiB,CACtB,MAAM,EAAO,CAAI,CACnB,EACA,CAAC,CAAM,CACT,EAEM,EAEA,EADJ,IAAS,WACH,gCACA,+BAA+B,EAEvC,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CACE,YACE,EACI,EAAE,6CAA6C,EAC/C,IAAA,GAEN,KAAM,EACE,SACR,QAAS,EACT,aAAc,GAAc,IAAS,WACrC,KAAK,KACL,MAAO,WAXT,CAaG,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAU,qCACV,cAAY,+BAEZ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAW,OAAO,IAAM,CAAA,CACrB,CAAA,EAGN,IAAS,UACR,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,wDAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,QAAQ,iBAClB,EAAE,oCAAoC,CAC5B,CAAA,GACb,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,gCAAgC,CAC3B,CAAA,GACV,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,+BAA+B,CAC1B,CAAA,CACE,CAAA,CAAA,CACX,IAGN,GAAa,IAAS,OACrB,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,mBACE,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,UACX,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,gCAAgC,CAC3B,CAAA,CACE,CAAA,EACb,GAAsB,IACrB,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAU,wDACX,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QACX,OAAO,UACP,QAAS,EACT,KAAK,SACL,OAAO,cAEN,EAAE,yCAAyC,CACpC,CAAA,CACT,CAAA,CAEL,CAAA,CAAA,EAEJ,OAAQ,EACG,WACZ,CAAA,CACE,CAAA,EAGN,GAAa,IAAS,WACrB,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAW,EACX,OAAQ,EACR,SAAU,CACX,CAAA,CACE,CAAA,EAGN,IAAS,YAAc,EAAc,OAAS,IAC7C,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAW,EACX,UAAW,EACI,eAChB,CAAA,CACE,CAAA,CAEF,GAEX,CC/HA,IAAM0C,GAA+C,CACnDE,cAAe,2BACfC,wBAAyB,qCACzBC,aAAc,yBAChB,EAiCA,SAASE,IAAU,CACjB,GAAM,CAAEC,KAAMtC,EAAe,EACvBuC,EAAS9C,EAAU,EACnB+C,EAAcjD,EAAe,EAG7BoD,EAFSP,GAAMM,UAEFD,CAAAA,CAAOG,YACpBC,EAAoBF,EACtBL,EAAEP,GAAqBY,IAAe,oBAAoB,EAC1DG,IAAAA,GACE,CAACC,EAAmBC,IAAAA,EAAAA,EAAAA,SAAAA,CACxB,IACF,EACM,CAACC,EAAaC,IAAAA,EAAAA,EAAAA,SAAAA,CAGV,IAAI,EACR,CAACG,EAAeC,IAAAA,EAAAA,EAAAA,SAAAA,CAAgD,IAAI,EACpE,CAACC,EAAWC,IAAAA,EAAAA,EAAAA,SAAAA,CAAwC,IAAI,EACxD,CAACC,EAAcC,IAAAA,EAAAA,EAAAA,SAAAA,CAA8C,IAAI,EACjE,CAACC,EAAiBC,IAAAA,EAAAA,EAAAA,SAAAA,CAA+B,EAAK,EAEtD,CAAEC,KAAMC,GAAYtE,EAAiBmC,CAAsB,EAC3D,CAAEkC,KAAME,GAAsBvE,EAClCiC,CACF,EACM,CAAEoC,KAAMG,GAAcxE,EAAiB8B,CAAqB,EAE5D2C,EAAiB3E,EAAY,CACjC,GAAGiC,GACH2C,UAAW,SAAY,CACrB1B,EAAY2B,aAAaxC,EAAuByC,SAAU,CACxDC,KAAM,IACR,CAAC,EACD,MAAMhD,EAAK,EACXkB,EAAO+B,SAAS,CACdC,GAAI,QACN,CAAC,CACH,EACAC,cAAiB,CACfhC,EAAYiC,kBAAkB,CAC5BL,SAAUzC,EAAuByC,QACnC,CAAC,CACH,CACF,CAAC,EAEKM,EAAiBpF,EAAY,CACjC,GAAGoC,GACHwC,cAAiB,CACf1B,EAAYiC,kBAAkB,CAC5BL,SAAU3C,EAA0B2C,QACtC,CAAC,CACH,EACAI,cAAiB,CACfxB,EAAqB,IAAI,CAC3B,CACF,CAAC,EAEK2B,EAAsB,SAAY,CACjC1B,IACLD,EAAqBC,EAAYE,EAAE,EACnC,MAAMuB,EAAeE,YAAY3B,EAAYE,EAAE,EACjD,EAEA,GAAI,CAACW,EAAQO,KACX,OAAO,KAGT,IAAMA,EAAOP,EAAQO,KACfQ,EAAqBd,EAAkBe,oBACvCC,EAAiBF,EAAmBG,KAAMC,GAAMA,EAAEC,MAAM,EACxDC,EAAkBd,EAAKe,aAAe,SAEtCC,EAAqBrB,EAAUsB,KAAKC,SACpCC,GAAoBxB,EAAUsB,KAAKG,QACnCC,EAAcL,EAAmBM,KAAKC,QACtCC,EAAiBL,GAAkBI,QAEnCE,EAAyB9B,EAAU+B,iBAAiBH,QACpDI,EAAkBhC,EAAU+B,iBAAiBE,UAE7CC,OAAuB,CAC3B,IAAMC,EAAQH,EAAgBG,MAAM,gBAAgB,EACpD,GAAI,CAACA,EAAO,MAAO,IACnB,IAAMC,EAAQC,SAASF,EAAM,GAAI,EAAE,EAEnC,OADaA,EAAM,GACnB,CACE,IAAK,IACH,OAAOC,EACT,IAAK,IACH,OAAOA,EAAQ,GACjB,IAAK,IACH,OAAOA,EAAQ,IACjB,QACE,MAAO,GACX,CACF,EAAA,CAAG,EAGGI,EAAkB,CAACrB,GAAmBO,EACtCe,EAAqB,CAACtB,GAAmBU,EACzCa,EAAqB7B,EAAmB8B,OAAS,EAIvD,OACE,EAAA,EAAA,KAAA,CAAC,GAAD,CACE,eACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,WAAW,QAMX,aAAYrE,EAAE,gBAAgB,EAC9B,cAAY,iBACZ,SAAU2B,EAAe4C,UACzB,QAAS5C,EAAe4C,UACxB,YAAe5C,EAAe6C,OAAO,EACrC,KAAK,SACL,OAAO,cAEN7C,EAAe4C,UAAY/D,IAAAA,IAC1B,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,GAAD,CAAY,cAAA,GAAY,UAAU,kBAAkB,CAAA,GACpD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAU,4BAAoBR,EAAE,gBAAgB,CAAQ,CAAA,CAChE,CAAA,CAAA,CAEM,CAAA,WAvBd,EA0BE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,6CAAf,EACE,EAAA,EAAA,IAAA,CAAC,GAAD,CAAe,MAAO+B,EAAK0C,MAAO,KAAK,IAAI,CAAA,GAC3C,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,kDAAf,EACE,EAAA,EAAA,IAAA,CAAC,GAAD,CAAgB,MAAOzE,EAAE,eAAe,CAAE,CAAA,GAO1C,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,GAAG,IACH,MAAM,QACN,cAAY,qBACZ,SAAA,GACA,QAAQ,kBAEP+B,EAAK0C,KACA,CAAA,CACL,GACF,IAEJlE,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,KAAMhD,EAAiB,KAAK,iBAChCgD,CACI,CAAA,EAGRwB,IAAQ,EAAA,EAAA,IAAA,CAAC,GAAD,CAAuBA,MAAK,CAAA,GAGnC,EAAA,EAAA,KAAA,CAAC,EAAO,KAAR,CAAa,QAAQ,oBAArB,EACE,EAAA,EAAA,KAAA,CAAC,EAAO,OAAR,CAAe,UAAU,0FAAzB,EACE,EAAA,EAAA,IAAA,CAAC,EAAO,MAAR,CAAA,SAAe/B,EAAE,wBAAwB,CAAgB,CAAA,GACzD,EAAA,EAAA,IAAA,CAAC,EAAO,YAAR,CAAA,SACGA,EAAE,8BAA8B,CACf,CAAA,CACP,IACdkE,GAAmBnC,EAAK2C,8BACvB,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAU,iFACV,cAAY,0CAEZ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,KAAMnH,EAAiB,KAAK,mBAChCyC,EAAE,mCAAmC,CACjC,CAAA,CACJ,CAAA,GAEP,EAAA,EAAA,KAAA,CAAC,EAAO,QAAR,CAAgB,UAAU,+CAA1B,EAEI,EAAA,EAAA,IAAA,CAAC,GAAD,CACkByC,iBAChB,YAAaV,EAAK4C,aAClB,oBACE5C,EAAK4C,cACL,CAAClC,IACAV,EAAK6C,iBAAmB7C,EAAK8C,cAAgB,GAE/BhC,kBACjB,YAAa7B,CAAiB,CAAA,EAGjCkD,IACC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,YAAahD,EACb,qBAAsBa,EAAK2C,4BAC3B,YAAa3C,EAAK6C,eAAgB,CAAA,EAGrCT,IACC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,YAAa/C,EACb,aAAcW,EAAK8C,aAAc,CAAA,CAGvB,GACL,IAGdT,IACC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,gBAAiBlF,GACjB,gBAAkB4F,GAChBlE,EAAe,CACbC,GAAIiE,EAASjE,GACbC,KAAMgE,EAASC,YACjB,CAAC,EAEH,UAAWxC,EACQ9B,mBAAkB,CAAA,GAIzC,EAAA,EAAA,IAAA,CAAC,GAAD,CACmBoC,kBACjB,kBAAmBW,EACnB,kBAAqBlC,EAAmB,EAAI,CAAE,CAAA,GAGhD,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQP,IAAkB,MAC1B,YAAeC,EAAiB,IAAI,CAAE,CAAA,GAExC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQD,IAAkB,SAC1B,YAAeC,EAAiB,IAAI,CAAE,CAAA,GAExC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQD,IAAkB,SAC1B,YAAeC,EAAiB,IAAI,CAAE,CAAA,GAGxC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQC,IAAc,QACtB,YAAeC,EAAa,IAAI,CAAE,CAAA,GAEpC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQD,IAAc,UACtB,YAAeC,EAAa,IAAI,CAAE,CAAA,GAEpC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQD,IAAc,aACtB,YAAeC,EAAa,IAAI,CAAE,CAAA,GAGpC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQC,IAAiB,QACzB,YAAeC,EAAgB,IAAI,CAAE,CAAA,GAEvC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQD,IAAiB,SACzB,aAAgBC,EAAgB,OAAO,EACvC,YAAeA,EAAgB,IAAI,CAAE,CAAA,GAGvC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQT,IAAgB,KACxB,UAAWyB,EAAemC,UAC1B,YAAe3D,EAAe,IAAI,EAClC,UAAWyB,EACX,aAAc1B,GAAaG,MAAQ,EAAG,CAAA,GAGxC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,OAAQO,EACR,YAAeC,EAAmB,EAAK,EACxBsC,eAAc,CAAA,CAEtB,GAEf"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,q as r,r as i,s as a}from"./createLucideIcon-BPpAIXR_.js";import{Dn as o,sr as s}from"./config-v3-oy_ef.js";import{t as c}from"./useMutation-ZLFeJg75.js";import{t as l}from"./link-BN90emXr.js";import{c as u,o as d}from"./zod-C87S6Tec.js";import{F as f,N as p,R as m,S as h,j as g,t as _}from"./index-gliHKncz.js";import{t as v}from"./auth-page-header-CIs08f5Y.js";import{t as y}from"./alert-leqyvHOp.js";import{t as b}from"./auth-layout-CoeqNhTT.js";import{t as x}from"./promise-OpBtq8tG.js";import{t as S}from"./field-DDt6F9TZ.js";import{t as C}from"./input-CNRpSR08.js";import{n as w,t as T}from"./auth-footer-Cz5ivsDc.js";import{r as E,t as D}from"./standard-schema-e8gtSzGE.js";import{a as O}from"./totp-BfCm6IWl.js";import{t as k}from"./labeled-separator-fnKySKv2.js";var A=t(e()),j=r(),M={SECOND_FACTOR_SESSION_EXPIRED:`SECOND_FACTOR_SESSION_EXPIRED`,INVALID_RECOVERY_CODE:`INVALID_RECOVERY_CODE`,NO_RECOVERY_CODES_AVAILABLE:`NO_RECOVERY_CODES_AVAILABLE`,TOTP_NOT_ENABLED:`TOTP_NOT_ENABLED`},N=5;function P(){let{t:e}=n(),t=o(),r=s(),P=_.useSearch(),F=(0,A.useRef)(null),[I,L]=(0,A.useState)(!1),[R,z]=(0,A.useState)(N),B=(0,A.useMemo)(()=>d({code:u().transform(e=>e.toUpperCase()).pipe(u().regex(/^[A-HJ-NP-TV-Z2-9]{4}(?:-[A-HJ-NP-TV-Z2-9]{4}){3}$/,e(`verifyRecovery.error.invalid`)))}),[e]),V=c({...O,onSuccess:async e=>{r.setQueryData(h.queryKey,{user:e.user}),await x(),f(P)?window.location.href=g(P):t.navigate({to:`/profile`})},onSettled:()=>{r.invalidateQueries({queryKey:h.queryKey})}}),{register:H,setError:U,handleSubmit:W,setValue:G,formState:{errors:K}}=E({defaultValues:{code:``},resolver:D(B)}),q=(0,A.useCallback)(()=>{t.navigate({to:`/login`,search:p(P)})},[t,P]);(0,A.useEffect)(()=>{if(!I)return;let e=setInterval(()=>{z(t=>t<=1?(clearInterval(e),q(),0):t-1)},1e3);return()=>clearInterval(e)},[I,q]);let J=async t=>{try{await V.mutateAsync(t)}catch(t){if(t instanceof i)switch(t.code){case M.SECOND_FACTOR_SESSION_EXPIRED:L(!0),z(N);return;case M.TOTP_NOT_ENABLED:q();return;case M.NO_RECOVERY_CODES_AVAILABLE:U(`code`,{type:`manual`,message:e(`verifyRecovery.error.noCodesAvailable`)}),G(`code`,``),F.current?.focus();return;case M.INVALID_RECOVERY_CODE:U(`code`,{type:`manual`,message:e(`verifyRecovery.error.invalid`)}),G(`code`,``),F.current?.focus();return}U(`code`,{type:`manual`,message:e(`verifyRecovery.error.invalid`)}),G(`code`,``),F.current?.focus()}},{ref:Y,...X}=H(`code`);return(0,j.jsxs)(b,{children:[(0,j.jsx)(v,{subtitle:e(`verifyRecovery.subtitle`),title:e(`verifyRecovery.title`)}),I&&(0,j.jsx)(y,{"data-testid":`recovery-session-expired`,icon:m,type:`warning`,children:(0,j.jsxs)(`span`,{className:`flex flex-col items-start gap-tinyrack-3xs`,children:[(0,j.jsx)(`span`,{children:e(`verifyRecovery.error.expired`)}),(0,j.jsx)(`span`,{className:`text-tinyrack-sm opacity-tinyrack-hover`,children:e(`verifyRecovery.redirecting`,{seconds:R})}),(0,j.jsx)(a,{appearance:`ghost`,intent:`neutral`,onClick:q,type:`button`,uiSize:`sm`,children:e(`verifyRecovery.redirectNow`)})]})}),(0,j.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-lg`,onSubmit:W(J),children:[(0,j.jsxs)(S.Root,{children:[(0,j.jsx)(C,{...X,autoComplete:`off`,className:`w-full text-center font-tinyrack-mono`,"data-testid":`recovery-code-input`,disabled:I,placeholder:e(`verifyRecovery.placeholder`),ref:e=>{Y(e),F.current=e},type:`text`}),K.code&&(0,j.jsx)(`div`,{className:`tr-field-error`,"data-testid":`recovery-error`,children:K.code.message})]}),I?(0,j.jsx)(a,{className:`w-full`,disabled:!0,intent:`primary`,type:`button`,uiSize:`lg`,children:e(`verifyRecovery.submit`)}):(0,j.jsx)(a,{className:`w-full`,intent:`primary`,loading:V.isPending,loadingLabel:e(`verifyRecovery.submitting`),type:`submit`,uiSize:`lg`,children:e(`verifyRecovery.submit`)})]}),(0,j.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-md`,children:[(0,j.jsx)(k,{label:e(`common.or`)}),(0,j.jsx)(a,{appearance:`ghost`,className:`w-full`,"data-testid":`recovery-back-to-totp`,intent:`neutral`,onClick:()=>t.navigate({to:`/verify/totp`,search:p(P)}),type:`button`,children:e(`verifyRecovery.backToTotp`)})]}),(0,j.jsx)(T,{children:(0,j.jsx)(w,{link:(0,j.jsx)(l,{search:p(P),to:`/login`,children:e(`verifyRecovery.backToLogin`)})})})]})}export{P as component};
|
|
2
|
-
//# sourceMappingURL=recovery-CLExnfYX.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,q as r,r as ee,s as i}from"./createLucideIcon-BPpAIXR_.js";import{i as a,r as o,sr as s,t as c}from"./config-v3-oy_ef.js";import{t as l}from"./mutationOptions-CrswitPs.js";import{t as u}from"./useMutation-ZLFeJg75.js";import{tt as d}from"./shell-header-bar-C9AB5lT-.js";import{t as f}from"./link-BN90emXr.js";import{t as p}from"./auth-field-HwxENJnB.js";import{t as m}from"./authorization-context-banner-BbtQmMYH.js";import{t as h}from"./lock-7NRyvXBS.js";import{t as g}from"./mail-D0B_1Dzd.js";import{a as _,c as v,i as y,o as b,r as x}from"./zod-C87S6Tec.js";import{E as S,F as C,N as w,S as T,V as te,j as ne,k as E}from"./index-gliHKncz.js";import{t as D}from"./auth-page-header-CIs08f5Y.js";import{t as O}from"./auth-layout-CoeqNhTT.js";import{t as k}from"./promise-OpBtq8tG.js";import{n as A,t as j}from"./auth-footer-Cz5ivsDc.js";import{r as M,t as N}from"./standard-schema-e8gtSzGE.js";import{t as P}from"./password-strength-C0Zkrrct.js";import{t as F}from"./terms-checkbox-list-Cw0zB-lO.js";import{t as I}from"./labeled-separator-fnKySKv2.js";var L=t(e()),R=l({mutationFn:async e=>a(await o.api.auth.register.$post({json:e,header:{}}))}),z=r();function B(){let{t:e,i18n:t}=n(),r=te(),a=s(),o=S.useSearch(),l=o.lang??t.language,B=(0,L.useDeferredValue)(l),{data:V}=d(c),{data:H}=d(E(B)),U=V.auth.password.enabled,W=V.auth.password.policy,G=H.terms.length>0,K=(0,L.useMemo)(()=>H.terms.filter(e=>e.consentMode===`explicit`),[H.terms]),q=K.length>0,J=V.registration.signup_notice?.[l]??V.registration.signup_notice?.[V.i18n.fallback_language],Y=(0,L.useMemo)(()=>b({email:v().min(1,e(`validation.email.required`)).pipe(y(e(`validation.email.invalid`))),password:v().min(W.min_length,e(`validation.password.min`,{count:W.min_length})).max(W.max_length,e(`validation.password.max`,{count:W.max_length})),termsConsents:b(Object.fromEntries(K.map(t=>[t.id,t.required?_(!0,{message:e(`validation.terms.required`)}):x()])))}),[K,W.max_length,W.min_length,e]),X=u({...R,onSuccess:async(e,t)=>{let n=e.user;if(n.email_verification_required&&!n.email_verified)return r({to:`/verify/email`,search:{email:t.email,...w(o)}});if(a.setQueryData(T.queryKey,{user:n}),await k(),n.second_factor_required){let e=[];return V.auth.password.totp.enabled&&e.push(`totp`),V.auth.passkey.enabled&&e.push(`passkey`),e.length===1?e[0]===`totp`?r({to:`/setup/totp`,search:w(o)}):r({to:`/setup/passkey`,search:{...w(o),passkey_name:`default`}}):r({to:`/setup/2fa`,search:w(o)})}C(o)?window.location.href=ne(o):r({to:`/profile`})},onError:t=>{t instanceof ee?t.code===`REGISTRATION_EMAIL_NOT_ALLOWED`?Q(`email`,{type:`manual`,message:e(`register.error.emailNotAllowed`)}):t.code===`REGISTRATION_DISABLED`?Q(`email`,{type:`manual`,message:e(`register.error.registrationDisabled`)}):Q(`email`,{type:`manual`,message:e(`register.error.emailExists`)}):Q(`email`,{type:`manual`,message:e(`register.error.emailExists`)})},onSettled:async()=>{await a.invalidateQueries({queryKey:T.queryKey})}}),{register:Z,setError:Q,handleSubmit:re,control:ie,setValue:ae,watch:oe,formState:{errors:$}}=M({defaultValues:{email:``,password:``,termsConsents:Object.fromEntries(K.map(e=>[e.id,!1]))},resolver:N(Y),mode:`onChange`}),se=oe(`password`);return(0,z.jsxs)(O,{children:[(0,z.jsx)(D,{subtitle:e(`register.subtitle`),title:e(`register.title`)}),(0,z.jsx)(m,{search:o}),U&&(0,z.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-lg`,onSubmit:re(e=>{let t=G?K.map(t=>({termsId:t.id,agreed:e.termsConsents[t.id]??!1})):void 0;X.mutate({email:e.email,password:e.password,consents:t})}),children:[(0,z.jsx)(p,{autoComplete:`email`,error:$.email,icon:g,label:e(`register.email.label`),placeholder:e(`register.email.placeholder`),...Z(`email`),type:`email`}),(0,z.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:[(0,z.jsx)(p,{autoComplete:`new-password`,error:$.password,hint:e(`register.password.hint`,{count:W.min_length}),icon:h,label:e(`register.password.label`),placeholder:e(`register.password.placeholder`),...Z(`password`),type:`password`}),(0,z.jsx)(P,{password:se,policy:W})]}),(0,z.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-md`,children:[J&&(0,z.jsx)(`div`,{className:`text-center text-tinyrack-text-muted text-tinyrack-xs`,children:(0,z.jsx)(`div`,{className:`prose prose-sm text-tinyrack-xs! **:text-tinyrack-xs!`,dangerouslySetInnerHTML:{__html:J},"data-testid":`terms-implicit-notice`})}),J&&q&&(0,z.jsx)(I,{label:e(`terms.additionalOptionalConsent`)}),G&&q&&(0,z.jsx)(F,{control:ie,disabled:X.isPending,errors:$,setValue:ae,terms:K})]}),(0,z.jsx)(i,{className:`w-full`,intent:`primary`,loading:X.isPending,loadingLabel:e(`register.submitting`),type:`submit`,uiSize:`lg`,children:e(`register.submit`)})]}),(0,z.jsx)(j,{children:(0,z.jsx)(A,{link:(0,z.jsx)(f,{search:w(o),to:`/login`,children:e(`register.link.login`)}),text:e(`register.footer.haveAccount`)})})]})}export{B as component};
|
|
2
|
-
//# sourceMappingURL=register-CZUyWXRO.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,q as r,s as i}from"./createLucideIcon-BPpAIXR_.js";import{t as a}from"./config-v3-oy_ef.js";import{t as o}from"./useMutation-ZLFeJg75.js";import{tt as s}from"./shell-header-bar-C9AB5lT-.js";import{t as c}from"./link-BN90emXr.js";import{t as l}from"./circle-check-6QTLhwM_.js";import{t as u}from"./auth-field-HwxENJnB.js";import{t as d}from"./key-round-CdvHb8vT.js";import{t as f}from"./lock-keyhole-Cz72xkCn.js";import{t as p}from"./lock-7NRyvXBS.js";import{c as m,o as h}from"./zod-C87S6Tec.js";import{L as g,R as _,V as v,c as y}from"./index-gliHKncz.js";import{t as b}from"./auth-page-header-CIs08f5Y.js";import{t as x}from"./alert-leqyvHOp.js";import{t as S}from"./auth-layout-CoeqNhTT.js";import{n as C,t as w}from"./auth-footer-Cz5ivsDc.js";import{r as T,t as E}from"./standard-schema-e8gtSzGE.js";import{n as D}from"./password-reset-CIacHnvA.js";import{t as O}from"./password-strength-C0Zkrrct.js";var k=t(e()),A=r();function j(){let{t:e}=n(),t=v(),{token:r}=y.useSearch(),[j,M]=(0,k.useState)(!1),{data:N}=s(a),P=N.auth.password.policy,F=(0,k.useMemo)(()=>h({token:m().min(1,e(`validation.token.required`)),password:m().min(P.min_length,e(`validation.password.min`,{count:P.min_length})).max(P.max_length,e(`validation.password.max`,{count:P.max_length})),confirmPassword:m().min(1,e(`validation.confirmPassword.required`))}).refine(e=>e.password===e.confirmPassword,{message:e(`validation.confirmPassword.mismatch`),path:[`confirmPassword`]}),[P.max_length,P.min_length,e]),I=o({...D,onSuccess:()=>{M(!0)}}),{register:L,setError:R,handleSubmit:z,watch:B,formState:{errors:V}}=T({defaultValues:{token:r||``,password:``,confirmPassword:``},resolver:E(F)}),H=B(`password`);return j?(0,A.jsx)(S,{children:(0,A.jsx)(`div`,{"data-testid":`alert-success`,children:(0,A.jsx)(g,{description:(0,A.jsxs)(A.Fragment,{children:[e(`resetPassword.success.subtitle`),(0,A.jsx)(`br`,{}),e(`resetPassword.success.description`)]}),icon:l,title:e(`resetPassword.success.title`),tone:`success`,children:(0,A.jsx)(i,{className:`w-full`,"data-testid":`reset-password-go-login`,intent:`primary`,onClick:()=>t({to:`/login`}),type:`button`,uiSize:`lg`,children:e(`resetPassword.success.goToLogin`)})})})}):(0,A.jsxs)(S,{children:[(0,A.jsx)(b,{subtitle:e(`resetPassword.subtitle`),title:e(`resetPassword.title`)}),(0,A.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-lg`,onSubmit:z(async t=>{try{await I.mutateAsync({token:t.token,password:t.password})}catch(t){t&&typeof t==`object`&&`code`in t?t.code===`INVALID_PASSWORD_RESET_TOKEN`?R(`token`,{type:`manual`,message:e(`resetPassword.error.invalidToken`)}):t.code===`USER_NOT_EDITABLE`&&R(`token`,{type:`manual`,message:e(`resetPassword.error.notEditable`)}):R(`token`,{type:`manual`,message:e(`resetPassword.error.invalidToken`)})}}),children:[!r&&(0,A.jsx)(u,{error:V.token,icon:d,label:e(`resetPassword.token.label`),placeholder:e(`resetPassword.token.placeholder`),...L(`token`),type:`text`}),r&&V.token&&(0,A.jsx)(x,{"data-testid":`reset-password-token-error`,icon:_,type:`error`,children:V.token.message}),(0,A.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:[(0,A.jsx)(u,{autoComplete:`new-password`,error:V.password,icon:p,label:e(`resetPassword.password.label`),placeholder:e(`resetPassword.password.placeholder`),...L(`password`),type:`password`}),(0,A.jsx)(O,{password:H,policy:P})]}),(0,A.jsx)(u,{autoComplete:`new-password`,error:V.confirmPassword,icon:f,label:e(`resetPassword.confirmPassword.label`),placeholder:e(`resetPassword.confirmPassword.placeholder`),...L(`confirmPassword`),type:`password`}),(0,A.jsx)(i,{className:`w-full`,intent:`primary`,loading:I.isPending,loadingLabel:e(`resetPassword.submitting`),type:`submit`,uiSize:`lg`,children:e(`resetPassword.submit`)})]}),(0,A.jsx)(w,{children:(0,A.jsx)(C,{link:(0,A.jsx)(c,{"data-testid":`reset-password-back-to-login`,to:`/login`,children:e(`resetPassword.backToLogin`)})})})]})}export{j as component};
|
|
2
|
-
//# sourceMappingURL=reset-N3RQTYEB.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reset-N3RQTYEB.js","names":["standardSchemaResolver","useMutation","useSuspenseQuery","Link","useNavigate","TRButton","CircleAlertIcon","CircleCheckIcon","KeyRoundIcon","LockIcon","LockKeyholeIcon","useMemo","useState","useForm","useTranslation","z","AuthField","AuthFooter","AuthFooterLink","AuthOutcome","AuthPageHeader","PasswordStrength","Alert","AuthLayout","appConfigQueryOptions","resetPasswordMutationOptions","Route","ResetPasswordFormValues","token","password","confirmPassword","ResetPassword","t","navigate","search","useSearch","queryToken","resetSuccess","setResetSuccess","data","configData","passwordPolicy","auth","policy","resetPasswordSchema","object","string","min","min_length","count","max","max_length","refine","message","path","resetPasswordMutation","onSuccess","register","setError","handleSubmit","watch","formState","errors","defaultValues","resolver","passwordValue","onSubmit","values","mutateAsync","error","code","type","to","isPending","component"],"sources":["../../../frontend/src/routes/password/reset/index.tsx?tsr-split=component"],"sourcesContent":["import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useSuspenseQuery } from '@tanstack/react-query';\nimport {\n createFileRoute,\n Link,\n redirect,\n useNavigate,\n} from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport {\n CircleAlertIcon,\n CircleCheckIcon,\n KeyRoundIcon,\n LockIcon,\n LockKeyholeIcon,\n} from 'lucide-react';\nimport { useMemo, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { z } from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport {\n AuthFooter,\n AuthFooterLink,\n} from '#frontend/components/auth/auth-footer.tsx';\nimport { AuthOutcome } from '#frontend/components/auth/auth-outcome.tsx';\nimport { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { PasswordStrength } from '#frontend/components/auth/password-strength.tsx';\nimport { Alert } from '#frontend/components/ui/alert.tsx';\nimport { RouteErrorFallback } from '#frontend/components/ui/route-error-fallback.tsx';\nimport { AuthLayout } from '#frontend/features/layout/auth-layout.tsx';\n\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { resetPasswordMutationOptions } from '#frontend/queries/password-reset.ts';\n\nconst SearchSchema = z.object({\n token: z.string().default(''),\n});\n\nexport const Route = createFileRoute('/password/reset/')({\n component: ResetPassword,\n errorComponent: RouteErrorFallback,\n validateSearch: SearchSchema,\n beforeLoad: async ({ context }) => {\n const config = await context.queryClient.ensureQueryData(\n appConfigQueryOptions,\n );\n const isPasswordAuthEnabled = config.auth.password.enabled;\n if (!isPasswordAuthEnabled) {\n throw redirect({ to: '/login' });\n }\n },\n loader: async ({ context }) => {\n await context.queryClient.ensureQueryData(appConfigQueryOptions);\n },\n});\n\ntype ResetPasswordFormValues = {\n token: string;\n password: string;\n confirmPassword: string;\n};\n\nfunction ResetPassword() {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const search = Route.useSearch();\n const { token: queryToken } = search;\n const [resetSuccess, setResetSuccess] = useState(false);\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n const passwordPolicy = configData.auth.password.policy;\n\n const resetPasswordSchema = useMemo(\n () =>\n z\n .object({\n token: z.string().min(1, t('validation.token.required')),\n password: z\n .string()\n .min(\n passwordPolicy.min_length,\n t('validation.password.min', {\n count: passwordPolicy.min_length,\n }),\n )\n .max(\n passwordPolicy.max_length,\n t('validation.password.max', {\n count: passwordPolicy.max_length,\n }),\n ),\n confirmPassword: z\n .string()\n .min(1, t('validation.confirmPassword.required')),\n })\n .refine((data) => data.password === data.confirmPassword, {\n message: t('validation.confirmPassword.mismatch'),\n path: ['confirmPassword'],\n }),\n [passwordPolicy.max_length, passwordPolicy.min_length, t],\n );\n\n const resetPasswordMutation = useMutation({\n ...resetPasswordMutationOptions,\n onSuccess: () => {\n setResetSuccess(true);\n },\n });\n\n const {\n register,\n setError,\n handleSubmit,\n watch,\n formState: { errors },\n } = useForm<ResetPasswordFormValues>({\n defaultValues: {\n token: queryToken || '',\n password: '',\n confirmPassword: '',\n },\n resolver: standardSchemaResolver(resetPasswordSchema),\n });\n\n const passwordValue = watch('password');\n\n const onSubmit = async (values: ResetPasswordFormValues) => {\n try {\n await resetPasswordMutation.mutateAsync({\n token: values.token,\n password: values.password,\n });\n } catch (error) {\n if (error && typeof error === 'object' && 'code' in error) {\n if (error.code === 'INVALID_PASSWORD_RESET_TOKEN') {\n setError('token', {\n type: 'manual',\n message: t('resetPassword.error.invalidToken'),\n });\n } else if (error.code === 'USER_NOT_EDITABLE') {\n setError('token', {\n type: 'manual',\n message: t('resetPassword.error.notEditable'),\n });\n }\n } else {\n setError('token', {\n type: 'manual',\n message: t('resetPassword.error.invalidToken'),\n });\n }\n }\n };\n\n if (resetSuccess) {\n return (\n <AuthLayout>\n {/*\n The testid stays on a wrapper: e2e treats \"the success alert\" as the\n whole terminal state, which is now the outcome block rather than a\n banner stacked above a header.\n */}\n <div data-testid=\"alert-success\">\n <AuthOutcome\n description={\n <>\n {t('resetPassword.success.subtitle')}\n <br />\n {t('resetPassword.success.description')}\n </>\n }\n icon={CircleCheckIcon}\n title={t('resetPassword.success.title')}\n tone=\"success\"\n >\n <TRButton\n className=\"w-full\"\n data-testid=\"reset-password-go-login\"\n intent=\"primary\"\n onClick={() => navigate({ to: '/login' })}\n type=\"button\"\n uiSize=\"lg\"\n >\n {t('resetPassword.success.goToLogin')}\n </TRButton>\n </AuthOutcome>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('resetPassword.subtitle')}\n title={t('resetPassword.title')}\n />\n\n <form\n className=\"flex flex-col gap-tinyrack-lg\"\n onSubmit={handleSubmit(onSubmit)}\n >\n {!queryToken && (\n <AuthField\n error={errors.token}\n icon={KeyRoundIcon}\n label={t('resetPassword.token.label')}\n placeholder={t('resetPassword.token.placeholder')}\n {...register('token')}\n type=\"text\"\n />\n )}\n\n {/*\n A token that arrived in the URL has no field to attach an error to,\n so a rejected link is reported as a banner above the form. The form\n stays put: the user can paste a fresh token without a round trip.\n */}\n {queryToken && errors.token && (\n <Alert\n data-testid=\"reset-password-token-error\"\n icon={CircleAlertIcon}\n type=\"error\"\n >\n {errors.token.message}\n </Alert>\n )}\n\n <div className=\"flex flex-col gap-tinyrack-sm\">\n <AuthField\n autoComplete=\"new-password\"\n error={errors.password}\n icon={LockIcon}\n label={t('resetPassword.password.label')}\n placeholder={t('resetPassword.password.placeholder')}\n {...register('password')}\n type=\"password\"\n />\n\n <PasswordStrength password={passwordValue} policy={passwordPolicy} />\n </div>\n\n <AuthField\n autoComplete=\"new-password\"\n error={errors.confirmPassword}\n icon={LockKeyholeIcon}\n label={t('resetPassword.confirmPassword.label')}\n placeholder={t('resetPassword.confirmPassword.placeholder')}\n {...register('confirmPassword')}\n type=\"password\"\n />\n\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n loading={resetPasswordMutation.isPending}\n loadingLabel={t('resetPassword.submitting')}\n type=\"submit\"\n uiSize=\"lg\"\n >\n {t('resetPassword.submit')}\n </TRButton>\n </form>\n\n <AuthFooter>\n <AuthFooterLink\n link={\n <Link data-testid=\"reset-password-back-to-login\" to=\"/login\">\n {t('resetPassword.backToLogin')}\n </Link>\n }\n />\n </AuthFooter>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,q as r,s as i}from"./createLucideIcon-BPpAIXR_.js";import{t as a}from"./config-v3-oy_ef.js";import{t as o}from"./useMutation-ZLFeJg75.js";import{tt as s}from"./shell-header-bar-C9AB5lT-.js";import{t as c}from"./circle-check-6QTLhwM_.js";import{t as l}from"./auth-field-HwxENJnB.js";import{t as u}from"./lock-keyhole-Cz72xkCn.js";import{t as d}from"./lock-7NRyvXBS.js";import{c as f,o as p}from"./zod-C87S6Tec.js";import{L as m,R as h,V as g}from"./index-gliHKncz.js";import{t as _}from"./auth-page-header-CIs08f5Y.js";import{t as v}from"./alert-leqyvHOp.js";import{t as y}from"./auth-layout-CoeqNhTT.js";import{r as b,t as x}from"./standard-schema-e8gtSzGE.js";import{r as S}from"./password-reset-CIacHnvA.js";import{t as C}from"./password-strength-C0Zkrrct.js";var w=t(e()),T=r();function E(){let{t:e}=n(),t=g(),[r,E]=(0,w.useState)(!1),{data:D}=s(a),O=D.auth.password.policy,k=(0,w.useMemo)(()=>p({password:f().min(O.min_length,e(`validation.password.min`,{count:O.min_length})).max(O.max_length,e(`validation.password.max`,{count:O.max_length})),confirmPassword:f().min(1,e(`validation.confirmPassword.required`))}).refine(e=>e.password===e.confirmPassword,{message:e(`validation.confirmPassword.mismatch`),path:[`confirmPassword`]}),[O.max_length,O.min_length,e]),A=o({...S,onSuccess:()=>E(!0)}),{register:j,handleSubmit:M,watch:N,formState:{errors:P}}=b({defaultValues:{password:``,confirmPassword:``},resolver:x(k)});return r?(0,T.jsx)(y,{children:(0,T.jsx)(m,{description:e(`resetRequiredPassword.success.description`),icon:c,title:e(`resetRequiredPassword.success.title`),tone:`success`,children:(0,T.jsx)(i,{className:`w-full`,intent:`primary`,onClick:()=>t({to:`/login`}),type:`button`,uiSize:`lg`,children:e(`resetPassword.success.goToLogin`)})})}):(0,T.jsxs)(y,{children:[(0,T.jsx)(_,{subtitle:e(`resetRequiredPassword.subtitle`),title:e(`resetRequiredPassword.title`)}),(0,T.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-lg`,onSubmit:M(e=>A.mutate({password:e.password})),children:[A.isError&&(0,T.jsx)(v,{icon:h,type:`error`,children:e(`resetRequiredPassword.error.expired`)}),(0,T.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:[(0,T.jsx)(l,{autoComplete:`new-password`,error:P.password,icon:d,label:e(`resetPassword.password.label`),...j(`password`),type:`password`}),(0,T.jsx)(C,{password:N(`password`),policy:O})]}),(0,T.jsx)(l,{autoComplete:`new-password`,error:P.confirmPassword,icon:u,label:e(`resetPassword.confirmPassword.label`),...j(`confirmPassword`),type:`password`}),(0,T.jsx)(i,{className:`w-full`,intent:`primary`,loading:A.isPending,loadingLabel:e(`resetPassword.submitting`),type:`submit`,uiSize:`lg`,children:e(`resetPassword.submit`)}),A.isError&&(0,T.jsx)(i,{className:`w-full`,intent:`neutral`,onClick:()=>t({to:`/login`}),type:`button`,uiSize:`lg`,children:e(`resetPassword.success.goToLogin`)})]})]})}export{E as component};
|
|
2
|
-
//# sourceMappingURL=reset-required-Cv5edDS6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reset-required-Cv5edDS6.js","names":["standardSchemaResolver","useMutation","useSuspenseQuery","useNavigate","TRButton","CircleAlertIcon","CircleCheckIcon","LockIcon","LockKeyholeIcon","useMemo","useState","useForm","useTranslation","z","AuthField","AuthOutcome","AuthPageHeader","PasswordStrength","Alert","AuthLayout","appConfigQueryOptions","resetRequiredPasswordMutationOptions","FormValues","password","confirmPassword","ResetRequiredPassword","t","navigate","success","setSuccess","data","config","policy","auth","schema","object","string","min","min_length","count","max","max_length","refine","value","message","path","mutation","onSuccess","register","handleSubmit","watch","formState","errors","defaultValues","resolver","to","values","mutate","isError","isPending","component"],"sources":["../../../frontend/src/routes/password/reset-required/index.tsx?tsr-split=component"],"sourcesContent":["import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport { useMutation, useSuspenseQuery } from '@tanstack/react-query';\nimport { createFileRoute, redirect, useNavigate } from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport {\n CircleAlertIcon,\n CircleCheckIcon,\n LockIcon,\n LockKeyholeIcon,\n} from 'lucide-react';\nimport { useMemo, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { z } from 'zod';\nimport { AuthField } from '#frontend/components/auth/auth-field.tsx';\nimport { AuthOutcome } from '#frontend/components/auth/auth-outcome.tsx';\nimport { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { PasswordStrength } from '#frontend/components/auth/password-strength.tsx';\nimport { Alert } from '#frontend/components/ui/alert.tsx';\nimport { RouteErrorFallback } from '#frontend/components/ui/route-error-fallback.tsx';\nimport { AuthLayout } from '#frontend/features/layout/auth-layout.tsx';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { resetRequiredPasswordMutationOptions } from '#frontend/queries/password-reset.ts';\n\nexport const Route = createFileRoute('/password/reset-required/')({\n component: ResetRequiredPassword,\n errorComponent: RouteErrorFallback,\n beforeLoad: async ({ context }) => {\n const config = await context.queryClient.ensureQueryData(\n appConfigQueryOptions,\n );\n if (!config.auth.password.enabled || !config.auth.passkey.enabled) {\n throw redirect({ to: '/login' });\n }\n },\n});\n\ntype FormValues = {\n password: string;\n confirmPassword: string;\n};\n\nfunction ResetRequiredPassword() {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const [success, setSuccess] = useState(false);\n const { data: config } = useSuspenseQuery(appConfigQueryOptions);\n const policy = config.auth.password.policy;\n const schema = useMemo(\n () =>\n z\n .object({\n password: z\n .string()\n .min(\n policy.min_length,\n t('validation.password.min', { count: policy.min_length }),\n )\n .max(\n policy.max_length,\n t('validation.password.max', { count: policy.max_length }),\n ),\n confirmPassword: z\n .string()\n .min(1, t('validation.confirmPassword.required')),\n })\n .refine((value) => value.password === value.confirmPassword, {\n message: t('validation.confirmPassword.mismatch'),\n path: ['confirmPassword'],\n }),\n [policy.max_length, policy.min_length, t],\n );\n const mutation = useMutation({\n ...resetRequiredPasswordMutationOptions,\n onSuccess: () => setSuccess(true),\n });\n const {\n register,\n handleSubmit,\n watch,\n formState: { errors },\n } = useForm<FormValues>({\n defaultValues: { password: '', confirmPassword: '' },\n resolver: standardSchemaResolver(schema),\n });\n\n if (success) {\n return (\n <AuthLayout>\n <AuthOutcome\n description={t('resetRequiredPassword.success.description')}\n icon={CircleCheckIcon}\n title={t('resetRequiredPassword.success.title')}\n tone=\"success\"\n >\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n onClick={() => navigate({ to: '/login' })}\n type=\"button\"\n uiSize=\"lg\"\n >\n {t('resetPassword.success.goToLogin')}\n </TRButton>\n </AuthOutcome>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('resetRequiredPassword.subtitle')}\n title={t('resetRequiredPassword.title')}\n />\n <form\n className=\"flex flex-col gap-tinyrack-lg\"\n onSubmit={handleSubmit((values) =>\n mutation.mutate({ password: values.password }),\n )}\n >\n {mutation.isError && (\n <Alert icon={CircleAlertIcon} type=\"error\">\n {t('resetRequiredPassword.error.expired')}\n </Alert>\n )}\n <div className=\"flex flex-col gap-tinyrack-sm\">\n <AuthField\n autoComplete=\"new-password\"\n error={errors.password}\n icon={LockIcon}\n label={t('resetPassword.password.label')}\n {...register('password')}\n type=\"password\"\n />\n <PasswordStrength password={watch('password')} policy={policy} />\n </div>\n <AuthField\n autoComplete=\"new-password\"\n error={errors.confirmPassword}\n icon={LockKeyholeIcon}\n label={t('resetPassword.confirmPassword.label')}\n {...register('confirmPassword')}\n type=\"password\"\n />\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n loading={mutation.isPending}\n loadingLabel={t('resetPassword.submitting')}\n type=\"submit\"\n uiSize=\"lg\"\n >\n {t('resetPassword.submit')}\n </TRButton>\n {mutation.isError && (\n <TRButton\n className=\"w-full\"\n intent=\"neutral\"\n onClick={() => navigate({ to: '/login' })}\n type=\"button\"\n uiSize=\"lg\"\n >\n {t('resetPassword.success.goToLogin')}\n </TRButton>\n )}\n </form>\n </AuthLayout>\n );\n}\n"],"mappings":"yyBA0CA,SAASyB,GAAwB,CAC/B,GAAM,CAAEC,KAAMd,EAAe,EACvBe,EAAWxB,EAAY,EACvB,CAACyB,EAASC,IAAAA,EAAAA,EAAAA,SAAAA,CAAuB,EAAK,EACtC,CAAEC,KAAMC,GAAW7B,EAAiBkB,CAAqB,EACzDY,EAASD,EAAOE,KAAKV,SAASS,OAC9BE,GAAAA,EAAAA,EAAAA,QAAAA,KAEFrB,EACU,CACNU,SAAUV,EACA,CAAC,CACRwB,IACCL,EAAOM,WACPZ,EAAE,0BAA2B,CAAEa,MAAOP,EAAOM,UAAW,CAAC,CAC3D,CAAC,CACAE,IACCR,EAAOS,WACPf,EAAE,0BAA2B,CAAEa,MAAOP,EAAOS,UAAW,CAAC,CAC3D,EACFjB,gBAAiBX,EACP,CAAC,CACRwB,IAAI,EAAGX,EAAE,qCAAqC,CAAC,CACpD,CAAC,CAAC,CACDgB,OAAQC,GAAUA,EAAMpB,WAAaoB,EAAMnB,gBAAiB,CAC3DoB,QAASlB,EAAE,qCAAqC,EAChDmB,KAAM,CAAC,iBAAiB,CAC1B,CAAC,EACL,CAACb,EAAOS,WAAYT,EAAOM,WAAYZ,CAAC,CAC1C,EACMoB,EAAW7C,EAAY,CAC3B,GAAGoB,EACH0B,cAAiBlB,EAAW,EAAI,CAClC,CAAC,EACK,CACJmB,WACAC,eACAC,QACAC,UAAW,CAAEC,WACXzC,EAAoB,CACtB0C,cAAe,CAAE9B,SAAU,GAAIC,gBAAiB,EAAG,EACnD8B,SAAUtD,EAAuBkC,CAAM,CACzC,CAAC,EAyBD,OAvBIN,GAEA,EAAA,EAAA,IAAA,CAAC,EAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,YAAaF,EAAE,2CAA2C,EAC1D,KAAMpB,EACN,MAAOoB,EAAE,qCAAqC,EAC9C,KAAK,oBAEL,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAU,SACV,OAAO,UACP,YAAeC,EAAS,CAAE4B,GAAI,QAAS,CAAC,EACxC,KAAK,SACL,OAAO,cAEN7B,EAAE,iCAAiC,CAC5B,CAAA,CACC,CAAA,CACH,CAAA,GAKd,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,SAAUA,EAAE,gCAAgC,EAC5C,MAAOA,EAAE,6BAA6B,CAAE,CAAA,GAE1C,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,gCACV,SAAUuB,EAAcO,GACtBV,EAASW,OAAO,CAAElC,SAAUiC,EAAOjC,QAAS,CAAC,CAC/C,WAJF,CAMGuB,EAASY,UACR,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,KAAMrD,EAAiB,KAAK,iBAChCqB,EAAE,qCAAqC,CACnC,CAAA,GAET,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,yCAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAa,eACb,MAAO0B,EAAO7B,SACd,KAAMhB,EACN,MAAOmB,EAAE,8BAA8B,EACvC,GAAIsB,EAAS,UAAU,EACvB,KAAK,UAAU,CAAA,GAEjB,EAAA,EAAA,IAAA,CAAC,EAAD,CAAkB,SAAUE,EAAM,UAAU,EAAWlB,QAAO,CAAA,CAC3D,KACL,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAa,eACb,MAAOoB,EAAO5B,gBACd,KAAMhB,EACN,MAAOkB,EAAE,qCAAqC,EAC9C,GAAIsB,EAAS,iBAAiB,EAC9B,KAAK,UAAU,CAAA,GAEjB,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAU,SACV,OAAO,UACP,QAASF,EAASa,UAClB,aAAcjC,EAAE,0BAA0B,EAC1C,KAAK,SACL,OAAO,cAENA,EAAE,sBAAsB,CACjB,CAAA,EACToB,EAASY,UACR,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAU,SACV,OAAO,UACP,YAAe/B,EAAS,CAAE4B,GAAI,QAAS,CAAC,EACxC,KAAK,SACL,OAAO,cAEN7B,EAAE,iCAAiC,CAC5B,CAAA,CAER,GACI,CAAA,CAAA,CAEhB"}
|