@tinyrack/issuary-server 0.21.0 → 0.22.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 +18 -0
- package/dist/entities/oauth-client.entity.d.ts.map +1 -1
- package/dist/entities/oauth-code.entity.d.ts +18 -0
- package/dist/entities/oauth-code.entity.d.ts.map +1 -1
- package/dist/entities/oauth-device-code.entity.d.ts +18 -0
- package/dist/entities/oauth-device-code.entity.d.ts.map +1 -1
- package/dist/entities/revoked-token.entity.d.ts +18 -0
- package/dist/entities/revoked-token.entity.d.ts.map +1 -1
- package/dist/entities/terms-content.entity.d.ts +9 -0
- package/dist/entities/terms-content.entity.d.ts.map +1 -1
- package/dist/entities/terms.entity.d.ts +9 -0
- package/dist/entities/terms.entity.d.ts.map +1 -1
- package/dist/entities/user-consent.entity.d.ts +18 -0
- package/dist/entities/user-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-terms-consent.entity.d.ts +9 -0
- package/dist/entities/user-terms-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-totp-recovery-code.entity.d.ts +9 -0
- package/dist/entities/user-totp-recovery-code.entity.d.ts.map +1 -1
- package/dist/entities/user-totp.entity.d.ts +9 -0
- package/dist/entities/user-totp.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.d.ts +9 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +4 -0
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/entrypoints/app.d.ts +53 -0
- package/dist/entrypoints/app.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts +23 -20
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.js +134 -104
- package/dist/entrypoints/database/postgres/compiled-functions.js.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts +23 -20
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.js +134 -104
- package/dist/entrypoints/database/sqlite/compiled-functions.js.map +1 -1
- package/dist/lib/config/resolved.d.ts +1 -0
- package/dist/lib/config/resolved.d.ts.map +1 -1
- package/dist/lib/config/security.d.ts +2 -0
- package/dist/lib/config/security.d.ts.map +1 -1
- package/dist/lib/config/security.js +5 -0
- package/dist/lib/config/security.js.map +1 -1
- package/dist/middleware/auth.d.ts +8 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +64 -0
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/session.d.ts +9 -0
- package/dist/middleware/session.d.ts.map +1 -1
- package/dist/middleware/session.js +18 -0
- package/dist/middleware/session.js.map +1 -1
- package/dist/migrations/postgres/Migration20260825110000_add_password_reset_required.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260825110000_add_password_reset_required.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260825110000_add_password_reset_required.js +11 -0
- package/dist/migrations/postgres/Migration20260825110000_add_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/Migration20260825110000_add_password_reset_required.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260825110000_add_password_reset_required.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260825110000_add_password_reset_required.js +10 -0
- package/dist/migrations/sqlite/Migration20260825110000_add_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 +7 -3
- 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 +18 -6
- package/dist/repositories/oauth-device-code.repository.js.map +1 -1
- package/dist/repositories/user-totp-recovery-code.repository.d.ts +7 -1
- package/dist/repositories/user-totp-recovery-code.repository.d.ts.map +1 -1
- package/dist/repositories/user-totp-recovery-code.repository.js +2 -1
- package/dist/repositories/user-totp-recovery-code.repository.js.map +1 -1
- package/dist/repositories/user-totp.repository.d.ts +9 -0
- package/dist/repositories/user-totp.repository.d.ts.map +1 -1
- package/dist/routes/api/auth/index.d.ts +52 -0
- package/dist/routes/api/auth/index.d.ts.map +1 -1
- package/dist/routes/api/auth/index.js +2 -0
- package/dist/routes/api/auth/index.js.map +1 -1
- package/dist/routes/api/auth/passkey/verify/post.d.ts +37 -0
- package/dist/routes/api/auth/passkey/verify/post.d.ts.map +1 -1
- package/dist/routes/api/auth/passkey/verify/post.js +8 -2
- package/dist/routes/api/auth/passkey/verify/post.js.map +1 -1
- package/dist/routes/api/auth/password/reset-required/post.d.ts +18 -0
- package/dist/routes/api/auth/password/reset-required/post.d.ts.map +1 -0
- package/dist/routes/api/auth/password/reset-required/post.js +39 -0
- package/dist/routes/api/auth/password/reset-required/post.js.map +1 -0
- package/dist/routes/api/index.d.ts +52 -0
- package/dist/routes/api/index.d.ts.map +1 -1
- package/dist/routes/index.d.ts +52 -0
- 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 +25 -0
- package/dist/schemas/error.d.ts.map +1 -1
- package/dist/schemas/error.js +1 -0
- package/dist/schemas/error.js.map +1 -1
- package/dist/schemas/response.d.ts +22 -0
- package/dist/schemas/response.d.ts.map +1 -1
- package/dist/schemas/response.js +8 -0
- package/dist/schemas/response.js.map +1 -1
- package/dist/seeders/config.seeder.js +2 -1
- package/dist/seeders/config.seeder.js.map +1 -1
- package/dist/services/container.d.ts +1 -0
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +15 -0
- package/dist/services/container.js.map +1 -1
- package/dist/services/legacy-credential-retirement.service.d.ts +20 -0
- package/dist/services/legacy-credential-retirement.service.d.ts.map +1 -0
- package/dist/services/legacy-credential-retirement.service.js +90 -0
- package/dist/services/legacy-credential-retirement.service.js.map +1 -0
- package/dist/services/oauth-client.service.d.ts +1 -0
- package/dist/services/oauth-client.service.d.ts.map +1 -1
- package/dist/services/oauth-client.service.js +17 -2
- 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 +4 -0
- 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 +12 -3
- package/dist/services/password-auth.service.js.map +1 -1
- package/dist/services/security.service.d.ts +8 -0
- package/dist/services/security.service.d.ts.map +1 -1
- package/dist/services/security.service.js +85 -22
- 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 +1 -1
- package/public/assets/2fa-BgveHSB_.js +2 -0
- package/public/assets/{2fa-B5vLgDXQ.js.map → 2fa-BgveHSB_.js.map} +1 -1
- package/public/assets/2fa-C37MUkye.js +2 -0
- package/public/assets/{2fa-CCOTIHDZ.js.map → 2fa-C37MUkye.js.map} +1 -1
- package/public/assets/2fa-UL_cNRnQ.js +2 -0
- package/public/assets/{2fa-C5vUVgr_.js.map → 2fa-UL_cNRnQ.js.map} +1 -1
- package/public/assets/2fa-kiqzGSz2.js +2 -0
- package/public/assets/{2fa-BqsM_D-X.js.map → 2fa-kiqzGSz2.js.map} +1 -1
- package/public/assets/{DialogHandle-BmtK2pRn.js → DialogHandle-Zvz8SgS0.js} +2 -2
- package/public/assets/{DialogHandle-BmtK2pRn.js.map → DialogHandle-Zvz8SgS0.js.map} +1 -1
- package/public/assets/admin-DbDuu6AI.js +2 -0
- package/public/assets/{admin-BPijkLw-.js.map → admin-DbDuu6AI.js.map} +1 -1
- package/public/assets/admin-users-CwTJdiih.js +2 -0
- package/public/assets/{admin-users-DvPbw1Vq.js.map → admin-users-CwTJdiih.js.map} +1 -1
- package/public/assets/{auth-choice-row-BCGjuedo.js → auth-choice-row-BlSsUI7d.js} +2 -2
- package/public/assets/{auth-choice-row-BCGjuedo.js.map → auth-choice-row-BlSsUI7d.js.map} +1 -1
- package/public/assets/{auth-field-DD8kvl--.js → auth-field-HwxENJnB.js} +2 -2
- package/public/assets/{auth-field-DD8kvl--.js.map → auth-field-HwxENJnB.js.map} +1 -1
- package/public/assets/{auth-layout-VtpryDof.js → auth-layout-CoeqNhTT.js} +2 -2
- package/public/assets/{auth-layout-VtpryDof.js.map → auth-layout-CoeqNhTT.js.map} +1 -1
- package/public/assets/{auth-page-header-CIn2E4zI.js → auth-page-header-CIs08f5Y.js} +2 -2
- package/public/assets/{auth-page-header-CIn2E4zI.js.map → auth-page-header-CIs08f5Y.js.map} +1 -1
- package/public/assets/{authorization-context-banner-SOuBHWIb.js → authorization-context-banner-BbtQmMYH.js} +2 -2
- package/public/assets/{authorization-context-banner-SOuBHWIb.js.map → authorization-context-banner-BbtQmMYH.js.map} +1 -1
- package/public/assets/{avatar-BEQjf2x6.js → avatar-CttWiIv3.js} +2 -2
- package/public/assets/{avatar-BEQjf2x6.js.map → avatar-CttWiIv3.js.map} +1 -1
- package/public/assets/{checkbox-gdHnSFQ-.js → checkbox-CJrRV8S1.js} +2 -2
- package/public/assets/{checkbox-gdHnSFQ-.js.map → checkbox-CJrRV8S1.js.map} +1 -1
- package/public/assets/config-v3-oy_ef.js +2 -0
- package/public/assets/config-v3-oy_ef.js.map +1 -0
- package/public/assets/{consent-BqqFDdsr.js → consent-BIhxtXHx.js} +2 -2
- package/public/assets/{consent-BqqFDdsr.js.map → consent-BIhxtXHx.js.map} +1 -1
- package/public/assets/{consent-CfRbz2R7.js → consent-DRmENn26.js} +2 -2
- package/public/assets/{consent-CfRbz2R7.js.map → consent-DRmENn26.js.map} +1 -1
- package/public/assets/{email-CKKakxPJ.js → email-CVRDeJ78.js} +2 -2
- package/public/assets/{email-CKKakxPJ.js.map → email-CVRDeJ78.js.map} +1 -1
- package/public/assets/email-UL_cNRnQ.js +2 -0
- package/public/assets/{email-C5vUVgr_.js.map → email-UL_cNRnQ.js.map} +1 -1
- package/public/assets/error-2VPY5w8V.js +2 -0
- package/public/assets/{error-BMXxpgfR.js.map → error-2VPY5w8V.js.map} +1 -1
- package/public/assets/{field-Cn4H1CUj.js → field-DDt6F9TZ.js} +2 -2
- package/public/assets/{field-Cn4H1CUj.js.map → field-DDt6F9TZ.js.map} +1 -1
- package/public/assets/forgot-DzDcduho.js +2 -0
- package/public/assets/{forgot-rO9sByfV.js.map → forgot-DzDcduho.js.map} +1 -1
- package/public/assets/forgot-UL_cNRnQ.js +2 -0
- package/public/assets/{forgot-C5vUVgr_.js.map → forgot-UL_cNRnQ.js.map} +1 -1
- package/public/assets/index-gliHKncz.js +11 -0
- package/public/assets/index-gliHKncz.js.map +1 -0
- package/public/assets/{initial-avatar-CtuDUz_W.js → initial-avatar-CZzHAPm3.js} +2 -2
- package/public/assets/{initial-avatar-CtuDUz_W.js.map → initial-avatar-CZzHAPm3.js.map} +1 -1
- package/public/assets/{input-CzQki7k6.js → input-CNRpSR08.js} +2 -2
- package/public/assets/{input-CzQki7k6.js.map → input-CNRpSR08.js.map} +1 -1
- package/public/assets/{labeled-separator-CV7nb0XW.js → labeled-separator-fnKySKv2.js} +2 -2
- package/public/assets/{labeled-separator-CV7nb0XW.js.map → labeled-separator-fnKySKv2.js.map} +1 -1
- package/public/assets/link-BN90emXr.js +2 -0
- package/public/assets/link-BN90emXr.js.map +1 -0
- package/public/assets/lock-keyhole-Cz72xkCn.js +2 -0
- package/public/assets/lock-keyhole-Cz72xkCn.js.map +1 -0
- package/public/assets/login-C6m2qSUt.js +2 -0
- package/public/assets/login-C6m2qSUt.js.map +1 -0
- package/public/assets/login-UL_cNRnQ.js +2 -0
- package/public/assets/login-UL_cNRnQ.js.map +1 -0
- package/public/assets/{logout-B5T52P8u.js → logout-CHdmF_16.js} +2 -2
- package/public/assets/{logout-B5T52P8u.js.map → logout-CHdmF_16.js.map} +1 -1
- package/public/assets/{modal-BDQFucjz.js → modal-sCM_zT82.js} +2 -2
- package/public/assets/{modal-BDQFucjz.js.map → modal-sCM_zT82.js.map} +1 -1
- package/public/assets/{mutationOptions-DyYFUbyn.js → mutationOptions-CrswitPs.js} +2 -2
- package/public/assets/{mutationOptions-DyYFUbyn.js.map → mutationOptions-CrswitPs.js.map} +1 -1
- package/public/assets/passkey-B2Blw47e.js +2 -0
- package/public/assets/{passkey-J1qnYp9A.js.map → passkey-B2Blw47e.js.map} +1 -1
- package/public/assets/passkey-CEx1VZ5R.js +2 -0
- package/public/assets/{passkey-CynCz1Dt.js.map → passkey-CEx1VZ5R.js.map} +1 -1
- package/public/assets/passkey-CU8x9J2w.js +2 -0
- package/public/assets/{passkey-BE9JvJOP.js.map → passkey-CU8x9J2w.js.map} +1 -1
- package/public/assets/passkey-UL_cNRnQ.js +2 -0
- package/public/assets/{passkey-C5vUVgr_.js.map → passkey-UL_cNRnQ.js.map} +1 -1
- package/public/assets/password-BhU_a0cR.js +2 -0
- package/public/assets/password-BhU_a0cR.js.map +1 -0
- package/public/assets/password-UL_cNRnQ.js +2 -0
- package/public/assets/password-UL_cNRnQ.js.map +1 -0
- package/public/assets/password-reset-CIacHnvA.js +2 -0
- package/public/assets/{password-reset-sU5KkBKi.js.map → password-reset-CIacHnvA.js.map} +1 -1
- package/public/assets/{password-strength-BeSOu_Ga.js → password-strength-C0Zkrrct.js} +2 -2
- package/public/assets/{password-strength-BeSOu_Ga.js.map → password-strength-C0Zkrrct.js.map} +1 -1
- package/public/assets/{pin-input-Cc-VkrQ3.js → pin-input-BlD4tPZJ.js} +2 -2
- package/public/assets/{pin-input-Cc-VkrQ3.js.map → pin-input-BlD4tPZJ.js.map} +1 -1
- package/public/assets/{profile-BcjsVYOx.js → profile-D1cEjfs8.js} +2 -2
- package/public/assets/{profile-BcjsVYOx.js.map → profile-D1cEjfs8.js.map} +1 -1
- package/public/assets/{profile-B5NaJfeS.js → profile-D43Yq-6S.js} +2 -2
- package/public/assets/{profile-B5NaJfeS.js.map → profile-D43Yq-6S.js.map} +1 -1
- package/public/assets/recovery-CLExnfYX.js +2 -0
- package/public/assets/{recovery-PnUATiUi.js.map → recovery-CLExnfYX.js.map} +1 -1
- package/public/assets/register-CZUyWXRO.js +2 -0
- package/public/assets/{register-DQXhru0_.js.map → register-CZUyWXRO.js.map} +1 -1
- package/public/assets/register-UL_cNRnQ.js +2 -0
- package/public/assets/{register-C5vUVgr_.js.map → register-UL_cNRnQ.js.map} +1 -1
- package/public/assets/reset-N3RQTYEB.js +2 -0
- package/public/assets/reset-N3RQTYEB.js.map +1 -0
- package/public/assets/reset-UL_cNRnQ.js +2 -0
- package/public/assets/{reset-C5vUVgr_.js.map → reset-UL_cNRnQ.js.map} +1 -1
- package/public/assets/reset-required-Cv5edDS6.js +2 -0
- package/public/assets/reset-required-Cv5edDS6.js.map +1 -0
- package/public/assets/reset-required-UL_cNRnQ.js +2 -0
- package/public/assets/reset-required-UL_cNRnQ.js.map +1 -0
- package/public/assets/{select-DqZynXSt.js → select-CWdSzsVo.js} +2 -2
- package/public/assets/{select-DqZynXSt.js.map → select-CWdSzsVo.js.map} +1 -1
- package/public/assets/select-UL_cNRnQ.js +2 -0
- package/public/assets/{select-C5vUVgr_.js.map → select-UL_cNRnQ.js.map} +1 -1
- package/public/assets/{separator-B0Bvh1he.js → separator-BWGym8uM.js} +2 -2
- package/public/assets/{separator-B0Bvh1he.js.map → separator-BWGym8uM.js.map} +1 -1
- package/public/assets/shell-header-bar-C9AB5lT-.js +2 -0
- package/public/assets/{shell-header-bar-CjG5qvPg.js.map → shell-header-bar-C9AB5lT-.js.map} +1 -1
- package/public/assets/{terms-BHDAgn-H.js → terms-COVFmzyl.js} +2 -2
- package/public/assets/{terms-BHDAgn-H.js.map → terms-COVFmzyl.js.map} +1 -1
- package/public/assets/{terms-B5NaJfeS.js → terms-D43Yq-6S.js} +2 -2
- package/public/assets/{terms-B5NaJfeS.js.map → terms-D43Yq-6S.js.map} +1 -1
- package/public/assets/{terms-checkbox-list-6jteUTIZ.js → terms-checkbox-list-Cw0zB-lO.js} +2 -2
- package/public/assets/{terms-checkbox-list-6jteUTIZ.js.map → terms-checkbox-list-Cw0zB-lO.js.map} +1 -1
- package/public/assets/totp-BFJEXxk0.js +2 -0
- package/public/assets/{totp-CJtfVNEq.js.map → totp-BFJEXxk0.js.map} +1 -1
- package/public/assets/{totp-BNZ904Zm.js → totp-BfCm6IWl.js} +2 -2
- package/public/assets/{totp-BNZ904Zm.js.map → totp-BfCm6IWl.js.map} +1 -1
- package/public/assets/totp-MINhsVxT.js +2 -0
- package/public/assets/{totp-ECvOUcFx.js.map → totp-MINhsVxT.js.map} +1 -1
- package/public/assets/use-totp-setup-C7Zk_2IY.js +3 -0
- package/public/assets/{use-totp-setup-BbS3XcZA.js.map → use-totp-setup-C7Zk_2IY.js.map} +1 -1
- package/public/assets/{useAriaLabelledBy-ByuMi3Ry.js → useAriaLabelledBy-CiOCg6X5.js} +2 -2
- package/public/assets/{useAriaLabelledBy-ByuMi3Ry.js.map → useAriaLabelledBy-CiOCg6X5.js.map} +1 -1
- package/public/assets/{useMutation-BWZ0G4Td.js → useMutation-ZLFeJg75.js} +2 -2
- package/public/assets/{useMutation-BWZ0G4Td.js.map → useMutation-ZLFeJg75.js.map} +1 -1
- package/public/assets/useQuery-BvMz34BW.js +2 -0
- package/public/assets/{useQuery-Ckxjmvtl.js.map → useQuery-BvMz34BW.js.map} +1 -1
- package/public/assets/{users-CmFxrCQT.js → users-COM7u3A-.js} +2 -2
- package/public/assets/{users-CmFxrCQT.js.map → users-COM7u3A-.js.map} +1 -1
- package/public/index.html +4 -3
- package/public/assets/2fa-B5vLgDXQ.js +0 -2
- package/public/assets/2fa-BqsM_D-X.js +0 -2
- package/public/assets/2fa-C5vUVgr_.js +0 -2
- package/public/assets/2fa-CCOTIHDZ.js +0 -2
- package/public/assets/admin-BPijkLw-.js +0 -2
- package/public/assets/admin-users-DvPbw1Vq.js +0 -2
- package/public/assets/config-DTQCUlfZ.js +0 -2
- package/public/assets/config-DTQCUlfZ.js.map +0 -1
- package/public/assets/email-C5vUVgr_.js +0 -2
- package/public/assets/error-BMXxpgfR.js +0 -2
- package/public/assets/forgot-C5vUVgr_.js +0 -2
- package/public/assets/forgot-rO9sByfV.js +0 -2
- package/public/assets/index-CS23Ozt6.js +0 -11
- package/public/assets/index-CS23Ozt6.js.map +0 -1
- package/public/assets/login-C5vUVgr_.js +0 -2
- package/public/assets/login-C5vUVgr_.js.map +0 -1
- package/public/assets/login-nukebli4.js +0 -2
- package/public/assets/login-nukebli4.js.map +0 -1
- package/public/assets/passkey-BE9JvJOP.js +0 -2
- package/public/assets/passkey-C5vUVgr_.js +0 -2
- package/public/assets/passkey-CynCz1Dt.js +0 -2
- package/public/assets/passkey-J1qnYp9A.js +0 -2
- package/public/assets/password-C5vUVgr_.js +0 -2
- package/public/assets/password-C5vUVgr_.js.map +0 -1
- package/public/assets/password-RkUttbhD.js +0 -2
- package/public/assets/password-RkUttbhD.js.map +0 -1
- package/public/assets/password-reset-sU5KkBKi.js +0 -2
- package/public/assets/recovery-PnUATiUi.js +0 -2
- package/public/assets/register-C5vUVgr_.js +0 -2
- package/public/assets/register-DQXhru0_.js +0 -2
- package/public/assets/reset-C5vUVgr_.js +0 -2
- package/public/assets/reset-CQgIa3yf.js +0 -2
- package/public/assets/reset-CQgIa3yf.js.map +0 -1
- package/public/assets/select-C5vUVgr_.js +0 -2
- package/public/assets/shell-header-bar-CjG5qvPg.js +0 -2
- package/public/assets/totp-CJtfVNEq.js +0 -2
- package/public/assets/totp-ECvOUcFx.js +0 -2
- package/public/assets/use-totp-setup-BbS3XcZA.js +0 -3
- package/public/assets/useQuery-Ckxjmvtl.js +0 -2
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-C5vUVgr_.js","names":["RouteErrorFallback","SplitErrorComponent","errorComponent"],"sources":["../../../frontend/src/routes/login/index.tsx?tsr-split=errorComponent"],"sourcesContent":["import {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport { createFileRoute, redirect, useRouter } from '@tanstack/react-router';\nimport { CircleAlertIcon, FingerprintIcon, MailIcon } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { z } from 'zod';\nimport { AuthMethodTile } from '#frontend/components/auth/auth-method-tile.tsx';\nimport { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { AuthorizationContextBanner } from '#frontend/components/auth/authorization-context-banner.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 {\n buildAuthenticatedAuthorizeUrl,\n extractOAuthParams,\n hasAuthorizationContext,\n isOAuthFlow,\n OAuthSearchSchema,\n} from '#frontend/libs/oauth-search.ts';\nimport { classifyPasskeyError } from '#frontend/libs/passkey-error.ts';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { getAuthorizationContextQueryOptions } from '#frontend/queries/authorization-context.ts';\nimport {\n type AppConfigs,\n appConfigQueryOptions,\n} from '#frontend/queries/config.ts';\nimport { authenticateWithPasskeyMutationOptions } from '#frontend/queries/passkey.ts';\nimport {\n type AuthResponse,\n getSessionQueryOptions,\n} from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema.extend({\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 registration_email_not_allowed: 'oauth.error.registrationEmailNotAllowed',\n};\n\nexport const Route = createFileRoute('/login/')({\n component: Login,\n errorComponent: RouteErrorFallback,\n validateSearch: SearchSchema,\n loaderDeps: ({ search }) => ({\n search,\n }),\n loader: async ({ context, deps }) => {\n const config = await context.queryClient.ensureQueryData(\n appConfigQueryOptions,\n );\n\n if (shouldRedirectToPassword(config, deps.search)) {\n throw redirect({\n to: '/login/password',\n search: extractOAuthParams(deps.search),\n replace: true,\n });\n }\n\n if (hasAuthorizationContext(deps.search)) {\n await context.queryClient.ensureQueryData(\n getAuthorizationContextQueryOptions(deps.search),\n );\n }\n },\n});\n\nfunction shouldRedirectToPassword(\n config: AppConfigs,\n search: z.infer<typeof SearchSchema>,\n): boolean {\n if (search.oauth_error) {\n return false;\n }\n\n return (\n config.auth.password.enabled &&\n !config.auth.passkey.enabled &&\n config.identity_providers.length === 0\n );\n}\n\nfunction Login() {\n const { t, i18n } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n\n const lang = search.lang ?? i18n.language;\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n\n // Get implicit notice from config for OAuth signup\n const implicitNotice =\n configData.registration.signup_notice?.[lang] ??\n configData.registration.signup_notice?.[configData.i18n.fallback_language];\n const oauthProviders = configData.identity_providers;\n\n const oauthError = search.oauth_error;\n const oauthErrorMessage = oauthError\n ? t(OAUTH_ERROR_I18N_MAP[oauthError] ?? 'oauth.error.failed')\n : undefined;\n\n const isPasswordAuthEnabled = configData.auth.password.enabled;\n const isPasskeyEnabled = configData.auth.passkey.enabled;\n const [passkeyError, setPasskeyError] = useState<string | null>(null);\n\n const handlePasskeySuccess = async (data: AuthResponse) => {\n if (data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, data);\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href = buildAuthenticatedAuthorizeUrl(search);\n } else {\n router.navigate({ to: '/profile' });\n }\n }\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n };\n\n const passkeyLoginMutation = useMutation({\n ...authenticateWithPasskeyMutationOptions,\n onSuccess: (data) => {\n setPasskeyError(null);\n handlePasskeySuccess(data);\n },\n onError: (error) => {\n const reason = classifyPasskeyError(error);\n if (reason === 'unsupported') {\n setPasskeyError(t('login.passkey.error.unsupported'));\n return;\n }\n\n setPasskeyError(t('login.passkey.error.failed'));\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n const buildOAuthUrl = (providerId: string) => {\n let oauthUrl = `/api/oauth/${providerId}/authorize?mode=login`;\n\n if (isOAuthFlow(search)) {\n const authUrl = new URL(buildAuthenticatedAuthorizeUrl(search));\n const returnUrl = `${authUrl.pathname}${authUrl.search}${authUrl.hash}`;\n oauthUrl += `&return_url=${encodeURIComponent(returnUrl)}`;\n }\n\n return oauthUrl;\n };\n\n const buildPasswordLoginHref = () => {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(extractOAuthParams(search))) {\n if (value !== undefined) {\n const stringValue = String(value);\n params.set(\n key,\n key === 'account_selected'\n ? decodeURIComponent(stringValue).replaceAll('\"', '')\n : stringValue,\n );\n }\n }\n const query = params.toString();\n return query ? `/login/password?${query}` : '/login/password';\n };\n\n return (\n <AuthLayout>\n {/*\n Branding title and subtitle are rendered once, by the brand panel in\n the layout. Repeating them here would give the page two copies of the\n product name and two heading nodes with the same text.\n */}\n <AuthPageHeader\n subtitle={t('login.selectMethod.subtitle') || undefined}\n title={t('login.title')}\n />\n\n <AuthorizationContextBanner search={search} />\n\n {oauthErrorMessage && (\n <Alert icon={CircleAlertIcon} type=\"error\">\n {oauthErrorMessage}\n </Alert>\n )}\n\n {passkeyError && (\n <Alert icon={CircleAlertIcon} type=\"error\">\n {passkeyError}\n </Alert>\n )}\n\n <div className=\"flex flex-col gap-tinyrack-sm\">\n {oauthProviders.map((provider) => (\n <AuthMethodTile\n icon={provider.icon_url}\n key={provider.id}\n label={provider.display_name}\n providerType={provider.type}\n // Leaves the SPA for the provider, so a plain anchor rather than a\n // router link. No children here — the tile supplies them, and an\n // element passed to `render` would override them.\n render={<a href={buildOAuthUrl(provider.id)} />}\n />\n ))}\n\n {isPasswordAuthEnabled && (\n <AuthMethodTile\n icon={<MailIcon aria-hidden className=\"size-tinyrack-xl\" />}\n label={t('login.method.password')}\n render={<a href={buildPasswordLoginHref()} />}\n />\n )}\n\n {isPasskeyEnabled && (\n <AuthMethodTile\n disabled={passkeyLoginMutation.isPending}\n icon={<FingerprintIcon aria-hidden className=\"size-tinyrack-xl\" />}\n isLoading={passkeyLoginMutation.isPending}\n label={t('login.method.passkey')}\n onClick={() => {\n setPasskeyError(null);\n passkeyLoginMutation.mutate();\n }}\n />\n )}\n </div>\n\n {implicitNotice && (\n <div\n className=\"prose prose-sm text-center text-tinyrack-text-muted text-tinyrack-xs! **:text-tinyrack-xs!\"\n dangerouslySetInnerHTML={{ __html: implicitNotice }}\n />\n )}\n </AuthLayout>\n );\n}\n"],"mappings":"wCAcsF,IAAAC,EAA7ED"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,n as r,q as i,s as a}from"./createLucideIcon-BPpAIXR_.js";import{On as o,Sr as s,t as c}from"./config-DTQCUlfZ.js";import{t as l}from"./useMutation-BWZ0G4Td.js";import{tt as u}from"./shell-header-bar-CjG5qvPg.js";import{t as d}from"./fingerprint-pattern-DP62Vk8x.js";import{t as f}from"./authorization-context-banner-SOuBHWIb.js";import{a as p,n as m,r as h,t as g}from"./provider-logos-u1YURWQr.js";import{t as _}from"./mail-D0B_1Dzd.js";import{F as v,N as y,R as b,S as x,b as S,j as C,z as w}from"./index-CS23Ozt6.js";import{t as T}from"./auth-page-header-CIn2E4zI.js";import{t as E}from"./alert-leqyvHOp.js";import{t as D}from"./auth-layout-VtpryDof.js";import{t as O}from"./promise-OpBtq8tG.js";import{t as k}from"./passkey-error-ZqqPQUta.js";import{t as A}from"./passkey-J1qnYp9A.js";var j=t(e()),M=i(),N={google:(0,M.jsx)(h,{className:`size-tinyrack-xl`}),github:(0,M.jsx)(m,{className:`size-tinyrack-xl`}),apple:(0,M.jsx)(g,{className:`size-tinyrack-xl`})};function P({icon:e,label:t,providerType:n,render:i,onClick:o,isLoading:s,disabled:c}){let l;l=n&&n!==`generic_oauth`?N[n]:typeof e==`string`?(0,M.jsx)(`img`,{alt:``,className:`size-tinyrack-xl`,src:e}):e||(0,M.jsx)(p,{"aria-hidden":!0,className:`size-tinyrack-xl`});let u=(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(`span`,{className:`flex size-tinyrack-xl shrink-0 items-center justify-center`,children:l}),(0,M.jsx)(r,{truncate:!0,variant:`body`,children:t})]}),d=`w-full justify-start gap-tinyrack-md transition-colors duration-tinyrack-fast ease-tinyrack-standard`;return i?(0,M.jsx)(w,{appearance:`outline`,className:`cursor-pointer ${d}`,intent:`neutral`,render:i,uiSize:`lg`,children:u}):(0,M.jsx)(a,{appearance:`outline`,className:d,disabled:c,intent:`neutral`,loading:s,onClick:o,type:`button`,uiSize:`lg`,children:u})}var F={access_denied:`oauth.error.accessDenied`,temporarily_unavailable:`oauth.error.temporarilyUnavailable`,server_error:`oauth.error.serverError`,registration_email_not_allowed:`oauth.error.registrationEmailNotAllowed`};function I(){let{t:e,i18n:t}=n(),r=o(),i=s(),a=S.useSearch(),p=a.lang??t.language,{data:m}=u(c),h=m.registration.signup_notice?.[p]??m.registration.signup_notice?.[m.i18n.fallback_language],g=m.identity_providers,w=a.oauth_error,N=w?e(F[w]??`oauth.error.failed`):void 0,I=m.auth.password.enabled,L=m.auth.passkey.enabled,[R,z]=(0,j.useState)(null),B=async e=>{e.user&&(i.setQueryData(x.queryKey,e),await O(),v(a)?window.location.href=C(a):r.navigate({to:`/profile`})),i.invalidateQueries({queryKey:x.queryKey})},V=l({...A,onSuccess:e=>{z(null),B(e)},onError:t=>{if(k(t)===`unsupported`){z(e(`login.passkey.error.unsupported`));return}z(e(`login.passkey.error.failed`))},onSettled:()=>{i.invalidateQueries({queryKey:x.queryKey})}}),H=e=>{let t=`/api/oauth/${e}/authorize?mode=login`;if(v(a)){let e=new URL(C(a)),n=`${e.pathname}${e.search}${e.hash}`;t+=`&return_url=${encodeURIComponent(n)}`}return t};return(0,M.jsxs)(D,{children:[(0,M.jsx)(T,{subtitle:e(`login.selectMethod.subtitle`)||void 0,title:e(`login.title`)}),(0,M.jsx)(f,{search:a}),N&&(0,M.jsx)(E,{icon:b,type:`error`,children:N}),R&&(0,M.jsx)(E,{icon:b,type:`error`,children:R}),(0,M.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:[g.map(e=>(0,M.jsx)(P,{icon:e.icon_url,label:e.display_name,providerType:e.type,render:(0,M.jsx)(`a`,{href:H(e.id)})},e.id)),I&&(0,M.jsx)(P,{icon:(0,M.jsx)(_,{"aria-hidden":!0,className:`size-tinyrack-xl`}),label:e(`login.method.password`),render:(0,M.jsx)(`a`,{href:(()=>{let e=new URLSearchParams;for(let[t,n]of Object.entries(y(a)))if(n!==void 0){let r=String(n);e.set(t,t===`account_selected`?decodeURIComponent(r).replaceAll(`"`,``):r)}let t=e.toString();return t?`/login/password?${t}`:`/login/password`})()})}),L&&(0,M.jsx)(P,{disabled:V.isPending,icon:(0,M.jsx)(d,{"aria-hidden":!0,className:`size-tinyrack-xl`}),isLoading:V.isPending,label:e(`login.method.passkey`),onClick:()=>{z(null),V.mutate()}})]}),h&&(0,M.jsx)(`div`,{className:`prose prose-sm text-center text-tinyrack-text-muted text-tinyrack-xs! **:text-tinyrack-xs!`,dangerouslySetInnerHTML:{__html:h}})]})}export{I as component};
|
|
2
|
-
//# sourceMappingURL=login-nukebli4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-nukebli4.js","names":["useMutation","useQueryClient","useSuspenseQuery","useRouter","CircleAlertIcon","FingerprintIcon","MailIcon","useState","useTranslation","AuthMethodTile","AuthPageHeader","AuthorizationContextBanner","Alert","AuthLayout","buildAuthenticatedAuthorizeUrl","extractOAuthParams","isOAuthFlow","classifyPasskeyError","tick","appConfigQueryOptions","authenticateWithPasskeyMutationOptions","getSessionQueryOptions","OAUTH_ERROR_I18N_MAP","Record","access_denied","temporarily_unavailable","server_error","registration_email_not_allowed","Route","Login","t","i18n","router","queryClient","search","useSearch","lang","language","data","configData","implicitNotice","registration","signup_notice","fallback_language","oauthProviders","identity_providers","oauthError","oauth_error","oauthErrorMessage","undefined","isPasswordAuthEnabled","auth","password","enabled","isPasskeyEnabled","passkey","passkeyError","setPasskeyError","handlePasskeySuccess","AuthResponse","user","setQueryData","queryKey","window","location","href","navigate","to","invalidateQueries","passkeyLoginMutation","onSuccess","onError","error","reason","onSettled","buildOAuthUrl","providerId","oauthUrl","authUrl","URL","returnUrl","pathname","hash","encodeURIComponent","buildPasswordLoginHref","params","URLSearchParams","key","value","Object","entries","stringValue","String","set","decodeURIComponent","replaceAll","query","toString","map","provider","icon_url","id","display_name","type","isPending","mutate","__html","component"],"sources":["../../../frontend/src/components/auth/auth-method-tile.tsx","../../../frontend/src/routes/login/index.tsx?tsr-split=component"],"sourcesContent":["import { TRButton } from '@tinyrack/ui/components/button';\nimport { TRLinkButton } from '@tinyrack/ui/components/link-button';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport { LinkIcon } from 'lucide-react';\nimport type { ReactElement, ReactNode } from 'react';\nimport {\n AppleLogo,\n GithubLogo,\n GoogleLogo,\n} from '#frontend/components/auth/provider-logos.tsx';\nimport type { OAuthProviderType } from '#frontend/queries/config.ts';\n\ntype AuthMethodTileBaseProps = {\n /** A provider icon URL, or a ready-made element. */\n icon?: string | ReactNode;\n label: string;\n providerType?: OAuthProviderType;\n};\n\ntype AuthMethodTileProps = AuthMethodTileBaseProps &\n (\n | {\n /** Navigating method (OAuth, or the email form). Must be a real anchor. */\n render: ReactElement;\n onClick?: never;\n isLoading?: never;\n disabled?: never;\n }\n | {\n render?: never;\n /** In-page method (passkey), which runs a ceremony instead of navigating. */\n onClick: () => void;\n isLoading?: boolean;\n disabled?: boolean;\n }\n );\n\nconst PROVIDER_LOGOS: Record<\n Exclude<OAuthProviderType, 'generic_oauth'>,\n ReactNode\n> = {\n google: <GoogleLogo className=\"size-tinyrack-xl\" />,\n github: <GithubLogo className=\"size-tinyrack-xl\" />,\n apple: <AppleLogo className=\"size-tinyrack-xl\" />,\n};\n\n/**\n * One sign-in method on the method chooser.\n *\n * Full-width rows at every breakpoint. The previous three-across grid gave\n * each tile a third of the card, so provider names wrapped onto two lines and\n * the icons and labels never lined up between tiles.\n */\nexport function AuthMethodTile({\n icon,\n label,\n providerType,\n render,\n onClick,\n isLoading,\n disabled,\n}: AuthMethodTileProps) {\n let leading: ReactNode;\n if (providerType && providerType !== 'generic_oauth') {\n leading = PROVIDER_LOGOS[providerType];\n } else if (typeof icon === 'string') {\n leading = <img alt=\"\" className=\"size-tinyrack-xl\" src={icon} />;\n } else if (icon) {\n leading = icon;\n } else {\n leading = <LinkIcon aria-hidden className=\"size-tinyrack-xl\" />;\n }\n\n const content = (\n <>\n <span className=\"flex size-tinyrack-xl shrink-0 items-center justify-center\">\n {leading}\n </span>\n <TRText truncate variant=\"body\">\n {label}\n </TRText>\n </>\n );\n\n const className =\n 'w-full justify-start gap-tinyrack-md transition-colors duration-tinyrack-fast ease-tinyrack-standard';\n\n if (render) {\n return (\n <TRLinkButton\n appearance=\"outline\"\n className={`cursor-pointer ${className}`}\n intent=\"neutral\"\n render={render}\n uiSize=\"lg\"\n >\n {content}\n </TRLinkButton>\n );\n }\n\n return (\n <TRButton\n appearance=\"outline\"\n className={className}\n disabled={disabled}\n intent=\"neutral\"\n loading={isLoading}\n onClick={onClick}\n type=\"button\"\n uiSize=\"lg\"\n >\n {content}\n </TRButton>\n );\n}\n","import {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport { createFileRoute, redirect, useRouter } from '@tanstack/react-router';\nimport { CircleAlertIcon, FingerprintIcon, MailIcon } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { z } from 'zod';\nimport { AuthMethodTile } from '#frontend/components/auth/auth-method-tile.tsx';\nimport { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { AuthorizationContextBanner } from '#frontend/components/auth/authorization-context-banner.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 {\n buildAuthenticatedAuthorizeUrl,\n extractOAuthParams,\n hasAuthorizationContext,\n isOAuthFlow,\n OAuthSearchSchema,\n} from '#frontend/libs/oauth-search.ts';\nimport { classifyPasskeyError } from '#frontend/libs/passkey-error.ts';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { getAuthorizationContextQueryOptions } from '#frontend/queries/authorization-context.ts';\nimport {\n type AppConfigs,\n appConfigQueryOptions,\n} from '#frontend/queries/config.ts';\nimport { authenticateWithPasskeyMutationOptions } from '#frontend/queries/passkey.ts';\nimport {\n type AuthResponse,\n getSessionQueryOptions,\n} from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema.extend({\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 registration_email_not_allowed: 'oauth.error.registrationEmailNotAllowed',\n};\n\nexport const Route = createFileRoute('/login/')({\n component: Login,\n errorComponent: RouteErrorFallback,\n validateSearch: SearchSchema,\n loaderDeps: ({ search }) => ({\n search,\n }),\n loader: async ({ context, deps }) => {\n const config = await context.queryClient.ensureQueryData(\n appConfigQueryOptions,\n );\n\n if (shouldRedirectToPassword(config, deps.search)) {\n throw redirect({\n to: '/login/password',\n search: extractOAuthParams(deps.search),\n replace: true,\n });\n }\n\n if (hasAuthorizationContext(deps.search)) {\n await context.queryClient.ensureQueryData(\n getAuthorizationContextQueryOptions(deps.search),\n );\n }\n },\n});\n\nfunction shouldRedirectToPassword(\n config: AppConfigs,\n search: z.infer<typeof SearchSchema>,\n): boolean {\n if (search.oauth_error) {\n return false;\n }\n\n return (\n config.auth.password.enabled &&\n !config.auth.passkey.enabled &&\n config.identity_providers.length === 0\n );\n}\n\nfunction Login() {\n const { t, i18n } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n\n const lang = search.lang ?? i18n.language;\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n\n // Get implicit notice from config for OAuth signup\n const implicitNotice =\n configData.registration.signup_notice?.[lang] ??\n configData.registration.signup_notice?.[configData.i18n.fallback_language];\n const oauthProviders = configData.identity_providers;\n\n const oauthError = search.oauth_error;\n const oauthErrorMessage = oauthError\n ? t(OAUTH_ERROR_I18N_MAP[oauthError] ?? 'oauth.error.failed')\n : undefined;\n\n const isPasswordAuthEnabled = configData.auth.password.enabled;\n const isPasskeyEnabled = configData.auth.passkey.enabled;\n const [passkeyError, setPasskeyError] = useState<string | null>(null);\n\n const handlePasskeySuccess = async (data: AuthResponse) => {\n if (data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, data);\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href = buildAuthenticatedAuthorizeUrl(search);\n } else {\n router.navigate({ to: '/profile' });\n }\n }\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n };\n\n const passkeyLoginMutation = useMutation({\n ...authenticateWithPasskeyMutationOptions,\n onSuccess: (data) => {\n setPasskeyError(null);\n handlePasskeySuccess(data);\n },\n onError: (error) => {\n const reason = classifyPasskeyError(error);\n if (reason === 'unsupported') {\n setPasskeyError(t('login.passkey.error.unsupported'));\n return;\n }\n\n setPasskeyError(t('login.passkey.error.failed'));\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n const buildOAuthUrl = (providerId: string) => {\n let oauthUrl = `/api/oauth/${providerId}/authorize?mode=login`;\n\n if (isOAuthFlow(search)) {\n const authUrl = new URL(buildAuthenticatedAuthorizeUrl(search));\n const returnUrl = `${authUrl.pathname}${authUrl.search}${authUrl.hash}`;\n oauthUrl += `&return_url=${encodeURIComponent(returnUrl)}`;\n }\n\n return oauthUrl;\n };\n\n const buildPasswordLoginHref = () => {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(extractOAuthParams(search))) {\n if (value !== undefined) {\n const stringValue = String(value);\n params.set(\n key,\n key === 'account_selected'\n ? decodeURIComponent(stringValue).replaceAll('\"', '')\n : stringValue,\n );\n }\n }\n const query = params.toString();\n return query ? `/login/password?${query}` : '/login/password';\n };\n\n return (\n <AuthLayout>\n {/*\n Branding title and subtitle are rendered once, by the brand panel in\n the layout. Repeating them here would give the page two copies of the\n product name and two heading nodes with the same text.\n */}\n <AuthPageHeader\n subtitle={t('login.selectMethod.subtitle') || undefined}\n title={t('login.title')}\n />\n\n <AuthorizationContextBanner search={search} />\n\n {oauthErrorMessage && (\n <Alert icon={CircleAlertIcon} type=\"error\">\n {oauthErrorMessage}\n </Alert>\n )}\n\n {passkeyError && (\n <Alert icon={CircleAlertIcon} type=\"error\">\n {passkeyError}\n </Alert>\n )}\n\n <div className=\"flex flex-col gap-tinyrack-sm\">\n {oauthProviders.map((provider) => (\n <AuthMethodTile\n icon={provider.icon_url}\n key={provider.id}\n label={provider.display_name}\n providerType={provider.type}\n // Leaves the SPA for the provider, so a plain anchor rather than a\n // router link. No children here — the tile supplies them, and an\n // element passed to `render` would override them.\n render={<a href={buildOAuthUrl(provider.id)} />}\n />\n ))}\n\n {isPasswordAuthEnabled && (\n <AuthMethodTile\n icon={<MailIcon aria-hidden className=\"size-tinyrack-xl\" />}\n label={t('login.method.password')}\n render={<a href={buildPasswordLoginHref()} />}\n />\n )}\n\n {isPasskeyEnabled && (\n <AuthMethodTile\n disabled={passkeyLoginMutation.isPending}\n icon={<FingerprintIcon aria-hidden className=\"size-tinyrack-xl\" />}\n isLoading={passkeyLoginMutation.isPending}\n label={t('login.method.passkey')}\n onClick={() => {\n setPasskeyError(null);\n passkeyLoginMutation.mutate();\n }}\n />\n )}\n </div>\n\n {implicitNotice && (\n <div\n className=\"prose prose-sm text-center text-tinyrack-text-muted text-tinyrack-xs! **:text-tinyrack-xs!\"\n dangerouslySetInnerHTML={{ __html: implicitNotice }}\n />\n )}\n </AuthLayout>\n );\n}\n"],"mappings":"q0BAqCA,EAAA,wJAOA,EASA,SAAA,EAAA,CAAA,OAAA,QAAA,eAAA,SAAA,UAAA,YAAA,YAAA,quBA8DA,CC1EA,IAAMsB,EAA+C,CACnDE,cAAe,2BACfC,wBAAyB,qCACzBC,aAAc,0BACdC,+BAAgC,yCAClC,EA6CA,SAASE,GAAQ,CACf,GAAM,CAAEC,IAAGC,QAASvB,EAAe,EAC7BwB,EAAS7B,EAAU,EACnB8B,EAAchC,EAAe,EAC7BiC,EAASN,EAAMO,UAAU,EAEzBC,EAAOF,EAAOE,MAAQL,EAAKM,SAC3B,CAAEC,KAAMC,GAAerC,EAAiBiB,CAAqB,EAG7DqB,EACJD,EAAWE,aAAaC,gBAAgBN,IACxCG,EAAWE,aAAaC,gBAAgBH,EAAWR,KAAKY,mBACpDC,EAAiBL,EAAWM,mBAE5BC,EAAaZ,EAAOa,YACpBC,EAAoBF,EACtBhB,EAAER,EAAqBwB,IAAe,oBAAoB,EAC1DG,IAAAA,GAEEC,EAAwBX,EAAWY,KAAKC,SAASC,QACjDC,EAAmBf,EAAWY,KAAKI,QAAQF,QAC3C,CAACG,EAAcC,IAAAA,EAAAA,EAAAA,SAAAA,CAA2C,IAAI,EAE9DC,EAAuB,KAAOpB,IAAuB,CACrDA,EAAKsB,OACP3B,EAAY4B,aAAaxC,EAAuByC,SAAUxB,CAAI,EAC9D,MAAMpB,EAAK,EAEPF,EAAYkB,CAAM,EACpB6B,OAAOC,SAASC,KAAOnD,EAA+BoB,CAAM,EAE5DF,EAAOkC,SAAS,CAAEC,GAAI,UAAW,CAAC,GAGtClC,EAAYmC,kBAAkB,CAC5BN,SAAUzC,EAAuByC,QACnC,CAAC,CACH,EAEMO,EAAuBrE,EAAY,CACvC,GAAGoB,EACHkD,UAAYhC,GAAS,CACnBmB,EAAgB,IAAI,EACpBC,EAAqBpB,CAAI,CAC3B,EACAiC,QAAUC,GAAU,CAElB,GADevD,EAAqBuD,CAChCC,IAAW,cAAe,CAC5BhB,EAAgB3B,EAAE,iCAAiC,CAAC,EACpD,MACF,CAEA2B,EAAgB3B,EAAE,4BAA4B,CAAC,CACjD,EACA4C,cAAiB,CACfzC,EAAYmC,kBAAkB,CAC5BN,SAAUzC,EAAuByC,QACnC,CAAC,CACH,CACF,CAAC,EAEKa,EAAiBC,GAAuB,CAC5C,IAAIC,EAAW,cAAcD,EAAU,uBAEvC,GAAI5D,EAAYkB,CAAM,EAAG,CACvB,IAAM4C,EAAU,IAAIC,IAAIjE,EAA+BoB,CAAM,CAAC,EACxD8C,EAAY,GAAGF,EAAQG,WAAWH,EAAQ5C,SAAS4C,EAAQI,OACjEL,GAAY,eAAeM,mBAAmBH,CAAS,GACzD,CAEA,OAAOH,CACT,EAmBA,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EAME,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,SAAU/C,EAAE,6BAA6B,GAAKmB,IAAAA,GAC9C,MAAOnB,EAAE,aAAa,CAAE,CAAA,GAG1B,EAAA,EAAA,IAAA,CAAC,EAAD,CAAoCI,QAAO,CAAA,EAE1Cc,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,KAAM5C,EAAiB,KAAK,iBAChC4C,CACI,CAAA,EAGRQ,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,KAAMpD,EAAiB,KAAK,iBAChCoD,CACI,CAAA,GAGT,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,yCAAf,CACGZ,EAAesD,IAAKC,IACnB,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,KAAMA,EAASC,SAEf,MAAOD,EAASG,aAChB,aAAcH,EAASI,KAIvB,QAAQ,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,KAAM5B,EAAcwB,EAASE,EAAE,CAAE,CAAA,CAAI,EAN3CF,EAASE,EAMkC,CAEnD,EAEAnD,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,EAAA,EAAA,IAAA,CAAC,EAAD,CAAU,cAAA,GAAY,UAAU,kBAAkB,CAAA,EACxD,MAAOpB,EAAE,uBAAuB,EAChC,QAAQ,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UA7DgB,CACnC,IAAMuD,EAAS,IAAIC,gBACnB,IAAK,GAAM,CAACC,EAAKC,KAAUC,OAAOC,QAAQ3E,EAAmBmB,CAAM,CAAC,EAClE,GAAIsD,IAAUvC,IAAAA,GAAW,CACvB,IAAM0C,EAAcC,OAAOJ,CAAK,EAChCH,EAAOQ,IACLN,EACAA,IAAQ,mBACJO,mBAAmBH,CAAW,CAAC,CAACI,WAAW,IAAK,EAAE,EAClDJ,CACN,CACF,CAEF,IAAMK,EAAQX,EAAOY,SAAS,EAC9B,OAAOD,EAAQ,mBAAmBA,IAAU,iBAC9C,EA8C2BZ,CAAuB,CAAE,CAAA,CAAI,CAAA,EAIjD9B,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,SAAUe,EAAqBmC,UAC/B,MAAM,EAAA,EAAA,IAAA,CAAC,EAAD,CAAiB,cAAA,GAAY,UAAU,kBAAkB,CAAA,EAC/D,UAAWnC,EAAqBmC,UAChC,MAAO1E,EAAE,sBAAsB,EAC/B,YAAe,CACb2B,EAAgB,IAAI,EACpBY,EAAqBoC,OAAO,CAC9B,CAAE,CAAA,CAGH,IAEJjE,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAU,6FACV,wBAAyB,CAAEkE,OAAQlE,CAAe,CAAE,CAAA,CAG9C,CAAA,CAAA,CAEhB"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,n as r,q as i,s as a,t as o}from"./createLucideIcon-BPpAIXR_.js";import{On as s,Sn as c,Sr as l,t as u}from"./config-DTQCUlfZ.js";import{t as d}from"./useMutation-BWZ0G4Td.js";import{tt as f}from"./shell-header-bar-CjG5qvPg.js";import{t as p}from"./auth-field-DD8kvl--.js";import{t as m}from"./fingerprint-pattern-DP62Vk8x.js";import{t as h}from"./shield-check-D_p8H0ni.js";import{c as g,o as _}from"./zod-C87S6Tec.js";import{F as v,N as y,R as b,S as x,j as S,u as C,z as w}from"./index-CS23Ozt6.js";import{t as T}from"./auth-page-header-CIn2E4zI.js";import{t as E}from"./alert-leqyvHOp.js";import{t as D}from"./auth-layout-VtpryDof.js";import{t as O}from"./promise-OpBtq8tG.js";import{n as k,t as A}from"./auth-footer-Cz5ivsDc.js";import{t as j}from"./passkey-error-ZqqPQUta.js";import{i as M}from"./passkey-J1qnYp9A.js";import{r as N,t as P}from"./standard-schema-e8gtSzGE.js";var F=o(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]),I=t(e()),L=i();function R(){let{t:e}=n(),t=s(),i=l(),o=C.useSearch(),{data:R}=f(u),[z,B]=(0,I.useState)(o.passkey_name?`registering`:`form`),[V,H]=(0,I.useState)(``),U=(0,I.useRef)(!1),W=R.auth.password.enabled&&R.auth.password.two_factor.enrollment_required&&R.auth.password.totp.enabled,{register:G,handleSubmit:K,formState:{errors:q}}=N({defaultValues:{name:``},resolver:P((0,I.useMemo)(()=>_({name:g().max(100,e(`validation.passkey.name.max`))}),[e]))}),J=d({...M,onSuccess:async e=>{e.second_factor_setup_completed&&e.user?(i.setQueryData(x.queryKey,{user:e.user}),await O(),v(o)?window.location.href=S(o):t.navigate({to:`/profile`})):(i.invalidateQueries({queryKey:x.queryKey}),t.navigate({to:`/profile`}))},onError:t=>{switch(B(`error`),j(t)){case`unsupported`:H(e(`setupPasskey.error.unsupported`));return;case`not_allowed`:H(e(`setupPasskey.error.notAllowed`));return;case`expired`:H(e(`setupPasskey.error.expired`));return;case`user_mismatch`:case`verification_failed`:H(e(`setupPasskey.error.failed`));return}},onSettled:()=>{i.invalidateQueries({queryKey:x.queryKey})}});return(0,I.useEffect)(()=>{o.passkey_name&&!U.current&&(U.current=!0,J.mutate({name:o.passkey_name}))},[J,o.passkey_name]),z===`registering`?(0,L.jsxs)(D,{children:[(0,L.jsx)(T,{subtitle:e(`setupPasskey.subtitle`),title:e(`setupPasskey.title`)}),(0,L.jsxs)(`div`,{className:`flex flex-col items-center gap-tinyrack-lg py-tinyrack-xl`,children:[(0,L.jsx)(m,{"aria-hidden":!0,className:`size-tinyrack-3xl animate-pulse text-tinyrack-primary`}),(0,L.jsx)(r,{align:`center`,as:`p`,color:`muted`,variant:`body`,children:e(`setupPasskey.waiting`)})]})]}):z===`error`?(0,L.jsxs)(D,{children:[(0,L.jsx)(T,{subtitle:e(`setupPasskey.subtitle`),title:e(`setupPasskey.title`)}),(0,L.jsx)(E,{icon:b,type:`error`,children:V}),(0,L.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:[W&&(0,L.jsxs)(w,{className:`w-full gap-tinyrack-sm`,intent:`primary`,render:(0,L.jsx)(c,{search:y(o),to:`/setup/totp`}),uiSize:`lg`,children:[(0,L.jsx)(h,{"aria-hidden":!0,className:`size-tinyrack-xl`}),e(`setupPasskey.useTotp`)]}),(0,L.jsx)(a,{appearance:W?`outline`:`solid`,className:`w-full`,intent:W?`neutral`:`primary`,onClick:()=>{o.passkey_name?(B(`registering`),H(``),J.mutate({name:o.passkey_name})):B(`form`)},type:`button`,uiSize:`lg`,children:e(`setupPasskey.retry`)})]}),(0,L.jsx)(A,{children:(0,L.jsx)(k,{link:(0,L.jsx)(c,{search:y(o),to:`/login`,children:e(`setupPasskey.backToLogin`)})})})]}):(0,L.jsxs)(D,{children:[(0,L.jsx)(T,{subtitle:e(`setupPasskey.subtitle`),title:e(`setupPasskey.title`)}),(0,L.jsx)(E,{icon:h,type:`info`,children:e(`setupPasskey.required`)}),(0,L.jsx)(r,{align:`center`,as:`p`,color:`muted`,variant:`bodySm`,children:e(`setupPasskey.description`)}),(0,L.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-lg`,onSubmit:K(e=>{B(`registering`),H(``),J.mutate({name:e.name||void 0})}),children:[(0,L.jsx)(p,{error:q.name,hint:e(`setupPasskey.name.hint`),icon:F,id:`passkey-name`,label:e(`setupPasskey.name.label`),placeholder:e(`setupPasskey.name.placeholder`),...G(`name`),type:`text`}),(0,L.jsx)(a,{className:`w-full`,intent:`primary`,loading:J.isPending,loadingLabel:e(`setupPasskey.registering`),type:`submit`,uiSize:`lg`,children:e(`setupPasskey.continue`)})]}),(0,L.jsx)(A,{children:(0,L.jsx)(k,{link:(0,L.jsx)(c,{search:y(o),to:`/login`,children:e(`setupPasskey.backToLogin`)})})})]})}export{R as component};
|
|
2
|
-
//# sourceMappingURL=passkey-BE9JvJOP.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,U as t,Z as n,i as r,q as i,s as a}from"./createLucideIcon-BPpAIXR_.js";import{On as o,Sn as s,Sr as c,i as l,n as u,r as d,ur as f}from"./config-DTQCUlfZ.js";import{t as p}from"./useMutation-BWZ0G4Td.js";import{t as m}from"./useQuery-Ckxjmvtl.js";import{t as h}from"./fingerprint-pattern-DP62Vk8x.js";import{F as g,N as _,R as v,S as y,j as b,m as x,z as S}from"./index-CS23Ozt6.js";import{t as C}from"./auth-page-header-CIn2E4zI.js";import{t as w}from"./alert-leqyvHOp.js";import{t as T}from"./auth-layout-VtpryDof.js";import{t as E}from"./promise-OpBtq8tG.js";import{n as D,t as O}from"./auth-footer-Cz5ivsDc.js";import{t as k}from"./passkey-error-ZqqPQUta.js";import{t as A}from"./passkey-J1qnYp9A.js";var j=n(e()),M=f({queryKey:u.pendingSecondFactorMethods(),queryFn:async()=>l(await d.api.auth[`2fa`].methods.$get()),retry:!1}),N=i();function P(){let{t:e}=r(),n=o(),i=c(),l=x.useSearch(),[u,d]=(0,j.useState)(null),f=(0,j.useRef)(!1),P=m({...M,enabled:u!==null}).data?.methods.includes(`totp`)??!1,F=t=>{switch(t){case`unsupported`:return e(`verifyPasskey.error.unsupported`);case`not_allowed`:return e(`verifyPasskey.error.notAllowed`);case`expired`:return e(`verifyPasskey.error.expired`);case`user_mismatch`:return e(`verifyPasskey.error.userMismatch`);case`verification_failed`:return e(`verifyPasskey.error.failed`)}},I=p({...A,onSuccess:async e=>{e.user&&(i.setQueryData(y.queryKey,{user:e.user}),await E(),g(l)?window.location.href=b(l):n.navigate({to:`/profile`}))},onError:async e=>{let t=k(e);d({message:F(t),reason:t})},onSettled:()=>{i.invalidateQueries({queryKey:y.queryKey})}});return(0,j.useEffect)(()=>{f.current||(f.current=!0,I.mutate())},[I]),(0,N.jsxs)(T,{children:[(0,N.jsx)(C,{align:`center`,subtitle:e(`verifyPasskey.subtitle`),title:e(`verifyPasskey.title`)}),(0,N.jsxs)(`div`,{className:`flex flex-col items-center gap-tinyrack-lg`,children:[(0,N.jsx)(`div`,{className:`flex size-tinyrack-3xl items-center justify-center rounded-tinyrack-full bg-tinyrack-surface-muted`,children:(0,N.jsx)(h,{"aria-hidden":!0,className:`size-tinyrack-2xl text-tinyrack-text-muted`})}),I.isPending&&(0,N.jsxs)(`div`,{className:`flex flex-col items-center gap-tinyrack-sm`,children:[(0,N.jsx)(t,{uiSize:`md`}),(0,N.jsx)(`p`,{className:`text-center text-tinyrack-sm text-tinyrack-text-muted`,children:e(`verifyPasskey.waiting`)})]}),u&&(0,N.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-tinyrack-md`,children:[(0,N.jsx)(w,{className:`w-full`,icon:v,type:`error`,children:u.message}),P&&(0,N.jsx)(S,{className:`w-full`,intent:`primary`,render:(0,N.jsx)(s,{search:_(l),to:`/verify/totp`}),uiSize:`lg`,children:e(`verifyPasskey.useTotp`)}),(0,N.jsx)(a,{appearance:P?`outline`:`solid`,className:`w-full`,intent:P?`neutral`:`primary`,onClick:()=>{d(null),I.mutate()},type:`button`,uiSize:`lg`,children:e(`verifyPasskey.retry`)})]})]}),(0,N.jsx)(O,{children:(0,N.jsx)(D,{link:(0,N.jsx)(s,{search:l,to:`/login`,children:e(`verifyPasskey.backToLogin`)})})})]})}export{P as component};
|
|
2
|
-
//# sourceMappingURL=passkey-CynCz1Dt.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{i as e,n as t,r as n,ur as r}from"./config-DTQCUlfZ.js";import{t as i}from"./mutationOptions-DyYFUbyn.js";function a(e){let t=new Uint8Array(e),n=``;for(let e of t)n+=String.fromCharCode(e);return btoa(n).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}function o(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=(4-t.length%4)%4,r=t.padEnd(t.length+n,`=`),i=atob(r),a=new ArrayBuffer(i.length),o=new Uint8Array(a);for(let e=0;e<i.length;e++)o[e]=i.charCodeAt(e);return a}function s(){return c.stubThis(globalThis?.PublicKeyCredential!==void 0&&typeof globalThis.PublicKeyCredential==`function`)}var c={stubThis:e=>e};function l(e){let{id:t}=e;return{...e,id:o(t),transports:e.transports}}function u(e){return e===`localhost`||/^((xn--[a-z0-9-]+|[a-z0-9]+(-[a-z0-9]+)*)\.)+([a-z]{2,}|xn--[a-z0-9-]+)$/i.test(e)}var d=class extends Error{constructor({message:e,code:t,cause:n,name:r}){super(e,{cause:n}),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name=r??n.name,this.code=t}};function f({error:e,options:t}){let{publicKey:n}=t;if(!n)throw Error(`options was missing required publicKey property`);if(e.name===`AbortError`){if(t.signal instanceof AbortSignal)return new d({message:`Registration ceremony was sent an abort signal`,code:`ERROR_CEREMONY_ABORTED`,cause:e})}else if(e.name===`ConstraintError`){if(n.authenticatorSelection?.requireResidentKey===!0)return new d({message:`Discoverable credentials were required but no available authenticator supported it`,code:`ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT`,cause:e});if(t.mediation===`conditional`&&n.authenticatorSelection?.userVerification===`required`)return new d({message:`User verification was required during automatic registration but it could not be performed`,code:`ERROR_AUTO_REGISTER_USER_VERIFICATION_FAILURE`,cause:e});if(n.authenticatorSelection?.userVerification===`required`)return new d({message:`User verification was required but no available authenticator supported it`,code:`ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT`,cause:e})}else if(e.name===`InvalidStateError`)return new d({message:`The authenticator was previously registered`,code:`ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED`,cause:e});else if(e.name===`NotAllowedError`)return new d({message:e.message,code:`ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY`,cause:e});else if(e.name===`NotSupportedError`)return n.pubKeyCredParams.filter(e=>e.type===`public-key`).length===0?new d({message:`No entry in pubKeyCredParams was of type "public-key"`,code:`ERROR_MALFORMED_PUBKEYCREDPARAMS`,cause:e}):new d({message:`No available authenticator supported any of the specified pubKeyCredParams algorithms`,code:`ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG`,cause:e});else if(e.name===`SecurityError`){let t=globalThis.location.hostname;if(!u(t))return new d({message:`${globalThis.location.hostname} is an invalid domain`,code:`ERROR_INVALID_DOMAIN`,cause:e});if(n.rp.id!==t)return new d({message:`The RP ID "${n.rp.id}" is invalid for this domain`,code:`ERROR_INVALID_RP_ID`,cause:e})}else if(e.name===`TypeError`){if(n.user.id.byteLength<1||n.user.id.byteLength>64)return new d({message:`User ID was not between 1 and 64 characters`,code:`ERROR_INVALID_USER_ID_LENGTH`,cause:e})}else if(e.name===`UnknownError`)return new d({message:`The authenticator was unable to process the specified options, or could not create a new credential`,code:`ERROR_AUTHENTICATOR_GENERAL_ERROR`,cause:e});return e}var p=new class{constructor(){Object.defineProperty(this,"controller",{enumerable:!0,configurable:!0,writable:!0,value:void 0})}createNewAbortSignal(){if(this.controller){let e=Error(`Cancelling existing WebAuthn API call for new one`);e.name=`AbortError`,this.controller.abort(e)}let e=new AbortController;return this.controller=e,e.signal}cancelCeremony(){if(this.controller){let e=Error(`Manually cancelling existing WebAuthn API call`);e.name=`AbortError`,this.controller.abort(e),this.controller=void 0}}},m=[`cross-platform`,`platform`];function h(e){if(e&&!(m.indexOf(e)<0))return e}async function g(e){!e.optionsJSON&&e.challenge&&(console.warn(`startRegistration() was not called correctly. It will try to continue with the provided options, but this call should be refactored to use the expected call structure instead. See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge for more information.`),e={optionsJSON:e});let{optionsJSON:t,useAutoRegister:n=!1}=e;if(!s())throw Error(`WebAuthn is not supported in this browser`);let r={...t,challenge:o(t.challenge),user:{...t.user,id:o(t.user.id)},excludeCredentials:t.excludeCredentials?.map(l)},i={};n&&(i.mediation=`conditional`),i.publicKey=r,i.signal=p.createNewAbortSignal();let c;try{c=await navigator.credentials.create(i)}catch(e){throw f({error:e,options:i})}if(!c)throw Error(`Registration was not completed`);let{id:u,rawId:d,response:m,type:g}=c,v;typeof m.getTransports==`function`&&(v=m.getTransports());let y;if(typeof m.getPublicKeyAlgorithm==`function`)try{y=m.getPublicKeyAlgorithm()}catch(e){_(`getPublicKeyAlgorithm()`,e)}let b;if(typeof m.getPublicKey==`function`)try{let e=m.getPublicKey();e!==null&&(b=a(e))}catch(e){_(`getPublicKey()`,e)}let x;if(typeof m.getAuthenticatorData==`function`)try{x=a(m.getAuthenticatorData())}catch(e){_(`getAuthenticatorData()`,e)}return{id:u,rawId:a(d),response:{attestationObject:a(m.attestationObject),clientDataJSON:a(m.clientDataJSON),transports:v,publicKeyAlgorithm:y,publicKey:b,authenticatorData:x},type:g,clientExtensionResults:c.getClientExtensionResults(),authenticatorAttachment:h(c.authenticatorAttachment)}}function _(e,t){console.warn(`The browser extension that intercepted this WebAuthn API call incorrectly implemented ${e}. You should report this error to them.\n`,t)}function v(){if(!s())return y.stubThis(new Promise(e=>e(!1)));let e=globalThis.PublicKeyCredential;return e?.isConditionalMediationAvailable===void 0?y.stubThis(new Promise(e=>e(!1))):y.stubThis(e.isConditionalMediationAvailable())}var y={stubThis:e=>e};function b({error:e,options:t}){let{publicKey:n}=t;if(!n)throw Error(`options was missing required publicKey property`);if(e.name===`AbortError`){if(t.signal instanceof AbortSignal)return new d({message:`Authentication ceremony was sent an abort signal`,code:`ERROR_CEREMONY_ABORTED`,cause:e})}else if(e.name===`NotAllowedError`)return new d({message:e.message,code:`ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY`,cause:e});else if(e.name===`SecurityError`){let t=globalThis.location.hostname;if(!u(t))return new d({message:`${globalThis.location.hostname} is an invalid domain`,code:`ERROR_INVALID_DOMAIN`,cause:e});if(n.rpId!==t)return new d({message:`The RP ID "${n.rpId}" is invalid for this domain`,code:`ERROR_INVALID_RP_ID`,cause:e})}else if(e.name===`UnknownError`)return new d({message:`The authenticator was unable to process the specified options, or could not create a new assertion signature`,code:`ERROR_AUTHENTICATOR_GENERAL_ERROR`,cause:e});return e}async function x(e){!e.optionsJSON&&e.challenge&&(console.warn(`startAuthentication() was not called correctly. It will try to continue with the provided options, but this call should be refactored to use the expected call structure instead. See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge for more information.`),e={optionsJSON:e});let{optionsJSON:t,useBrowserAutofill:n=!1,verifyBrowserAutofillInput:r=!0}=e;if(!s())throw Error(`WebAuthn is not supported in this browser`);let i;t.allowCredentials?.length!==0&&(i=t.allowCredentials?.map(l));let c={...t,challenge:o(t.challenge),allowCredentials:i},u={};if(n){if(!await v())throw Error(`Browser does not support WebAuthn autofill`);if(document.querySelectorAll(`input[autocomplete$='webauthn']`).length<1&&r)throw Error('No <input> with "webauthn" as the only or last value in its `autocomplete` attribute was detected');u.mediation=`conditional`,c.allowCredentials=[]}u.publicKey=c,u.signal=p.createNewAbortSignal();let d;try{d=await navigator.credentials.get(u)}catch(e){throw b({error:e,options:u})}if(!d)throw Error(`Authentication was not completed`);let{id:f,rawId:m,response:g,type:_}=d,y;return g.userHandle&&(y=a(g.userHandle)),{id:f,rawId:a(m),response:{authenticatorData:a(g.authenticatorData),clientDataJSON:a(g.clientDataJSON),signature:a(g.signature),userHandle:y},type:_,clientExtensionResults:d.getClientExtensionResults(),authenticatorAttachment:h(d.authenticatorAttachment)}}var S=r({queryKey:t.passkeys(),queryFn:async()=>e(await n.api.user.passkeys.$get())}),C=i({mutationFn:async t=>{let{options:r}=await e(await n.api.user.passkeys.register.options.$post()),i=await g({optionsJSON:r});return e(await n.api.user.passkeys.register.verify.$post({json:{response:i,name:t.name}}))}}),w=i({mutationFn:async t=>e(await n.api.user.passkeys[`:id`].$delete({param:{id:t.id}}))}),T=i({mutationFn:async t=>e(await n.api.user.passkeys[`:id`].$patch({param:{id:t.id},json:{name:t.name}}))}),E=i({mutationFn:async()=>{let{options:t}=await e(await n.api.auth.passkey.options.$post()),r=await x({optionsJSON:t});return e(await n.api.auth.passkey.verify.$post({json:{response:{...r,clientExtensionResults:{...r.clientExtensionResults}}}}))}}),D=async(t,r)=>{try{let{options:i}=await e(await n.api.auth.passkey.options.$post({},{init:{signal:r}})),a=await x({optionsJSON:i,useBrowserAutofill:!0});t(await e(await n.api.auth.passkey.verify.$post({json:{response:{...a,clientExtensionResults:{...a.clientExtensionResults}}}},{init:{signal:r}})))}catch(e){e instanceof Error&&e.name}};export{T as a,C as i,w as n,D as o,S as r,E as t};
|
|
2
|
-
//# sourceMappingURL=passkey-J1qnYp9A.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"password-C5vUVgr_.js","names":["RouteErrorFallback","SplitErrorComponent","errorComponent"],"sources":["../../../frontend/src/routes/login/password/index.tsx?tsr-split=errorComponent"],"sourcesContent":["import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';\nimport {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from '@tanstack/react-query';\nimport { createFileRoute, Link, useRouter } from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { TRLink } from '@tinyrack/ui/components/link';\nimport { LockIcon, MailIcon } from 'lucide-react';\nimport { useCallback, useEffect, useMemo, useRef } 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 { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { AuthorizationContextBanner } from '#frontend/components/auth/authorization-context-banner.tsx';\nimport { RouteErrorFallback } from '#frontend/components/ui/route-error-fallback.tsx';\nimport { AuthLayout } from '#frontend/features/layout/auth-layout.tsx';\nimport {\n buildAuthenticatedAuthorizeUrl,\n extractOAuthParams,\n hasAuthorizationContext,\n isOAuthFlow,\n type OAuthSearch,\n OAuthSearchSchema,\n type SecondFactorMethod,\n} from '#frontend/libs/oauth-search.ts';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { getAuthorizationContextQueryOptions } from '#frontend/queries/authorization-context.ts';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { loginMutationOptions } from '#frontend/queries/login.ts';\nimport { startConditionalPasskeyAuth } from '#frontend/queries/passkey.ts';\nimport {\n type AuthResponse,\n getSessionQueryOptions,\n} from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema;\n\nexport const Route = createFileRoute('/login/password/')({\n component: LoginPassword,\n errorComponent: RouteErrorFallback,\n validateSearch: SearchSchema,\n loaderDeps: ({ search }) => ({\n search,\n }),\n loader: async ({ context, deps }) => {\n await context.queryClient.ensureQueryData(appConfigQueryOptions);\n if (hasAuthorizationContext(deps.search)) {\n await context.queryClient.ensureQueryData(\n getAuthorizationContextQueryOptions(deps.search),\n );\n }\n },\n});\n\nfunction LoginPassword() {\n const { t, i18n } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n const authorizeSearch: OAuthSearch =\n search.account_selection_state &&\n search.prompt?.split(' ').includes('login')\n ? { ...search, account_selected: 1 }\n : search;\n const lang = search.lang ?? i18n.language;\n\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n\n const implicitNotice =\n configData.registration.signup_notice?.[lang] ??\n configData.registration.signup_notice?.[configData.i18n.fallback_language];\n const isPasswordAuthEnabled = configData.auth.password.enabled;\n const isPasskeyEnabled = configData.auth.passkey.enabled;\n const hasMultipleLoginMethods =\n configData.identity_providers.length +\n (isPasswordAuthEnabled ? 1 : 0) +\n (isPasskeyEnabled ? 1 : 0) >\n 1;\n\n const loginSchema = useMemo(\n () =>\n z.object({\n email: z\n .string()\n .min(1, t('validation.email.required'))\n .pipe(z.email(t('validation.email.invalid'))),\n password: z.string().min(1, t('validation.password.required')),\n }),\n [t],\n );\n\n const loginMutation = useMutation({\n ...loginMutationOptions,\n onSuccess: async (data, params) => {\n const user = data.user;\n\n if (user.email_verification_required && !user.email_verified) {\n router.navigate({\n to: '/verify/email',\n search: {\n email: params.email,\n ...extractOAuthParams(search),\n },\n });\n return;\n }\n\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: user,\n });\n await tick();\n\n const registered_2fa_methods: SecondFactorMethod[] = [];\n if (configData.auth.password.totp.enabled && user.totp_registered) {\n registered_2fa_methods.push('totp');\n }\n if (configData.auth.passkey.enabled && user.passkey_count > 0) {\n registered_2fa_methods.push('passkey');\n }\n\n if (user.second_factor_required && registered_2fa_methods.length === 0) {\n if (configData.available_2fa_setup_methods.length > 1) {\n return router.navigate({\n to: '/setup/2fa',\n search: extractOAuthParams(search),\n });\n } else if (configData.available_2fa_setup_methods.length === 1) {\n const method = configData.available_2fa_setup_methods[0];\n if (method === 'totp') {\n return router.navigate({\n to: '/setup/totp',\n search: extractOAuthParams(search),\n });\n } else {\n return router.navigate({\n to: '/setup/passkey',\n search: {\n ...extractOAuthParams(search),\n passkey_name: 'default',\n },\n });\n }\n }\n }\n\n if (registered_2fa_methods.length > 1) {\n return router.navigate({\n to: '/verify/2fa',\n search: extractOAuthParams(search),\n });\n } else if (registered_2fa_methods.length === 1) {\n const method = registered_2fa_methods[0];\n if (method === 'totp') {\n return router.navigate({\n to: '/verify/totp',\n search: extractOAuthParams(search),\n });\n } else {\n return router.navigate({\n to: '/verify/passkey',\n search: extractOAuthParams(search),\n });\n }\n } else {\n if (isOAuthFlow(search)) {\n window.location.href =\n buildAuthenticatedAuthorizeUrl(authorizeSearch);\n } else {\n return router.navigate({ to: '/profile' });\n }\n }\n },\n onError: (_error) => {\n setError('email', {\n type: 'manual',\n message: t('login.error.failed'),\n });\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n const handlePasskeySuccess = useCallback(\n async (data: AuthResponse) => {\n if (data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, data);\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href =\n buildAuthenticatedAuthorizeUrl(authorizeSearch);\n } else {\n router.navigate({ to: '/profile' });\n }\n }\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n [queryClient, router, search, authorizeSearch],\n );\n\n // Conditional UI: Start passkey autofill on page load\n const abortControllerRef = useRef<AbortController | null>(null);\n\n useEffect(() => {\n if (!isPasskeyEnabled || !isPasswordAuthEnabled) {\n return;\n }\n\n abortControllerRef.current = new AbortController();\n startConditionalPasskeyAuth(\n handlePasskeySuccess,\n abortControllerRef.current.signal,\n );\n\n return () => {\n abortControllerRef.current?.abort();\n };\n }, [isPasskeyEnabled, isPasswordAuthEnabled, handlePasskeySuccess]);\n\n const {\n register,\n setError,\n handleSubmit,\n formState: { errors },\n } = useForm({\n defaultValues: {\n email: '',\n password: '',\n },\n resolver: standardSchemaResolver(loginSchema),\n });\n\n const onSubmit = async (values: z.infer<typeof loginSchema>) => {\n loginMutation.mutate(values);\n };\n\n return (\n <AuthLayout>\n {/* Branding lives in the layout's brand panel — see /login. */}\n <AuthPageHeader\n subtitle={t('login.selectMethod.subtitle') || undefined}\n title={t('login.title')}\n />\n\n <AuthorizationContextBanner search={search} />\n\n {isPasswordAuthEnabled && (\n <form\n className=\"flex flex-col gap-tinyrack-lg\"\n onSubmit={handleSubmit(onSubmit)}\n >\n <AuthField\n autoComplete=\"username webauthn\"\n error={errors.email}\n icon={MailIcon}\n label={t('login.email.label')}\n placeholder={t('login.email.placeholder')}\n {...register('email')}\n type=\"email\"\n />\n\n <AuthField\n autoComplete=\"current-password\"\n error={errors.password}\n icon={LockIcon}\n label={t('login.password.label')}\n /*\n * On the label row rather than under the field: it belongs to the\n * password, and putting it between the field and the submit button\n * separated the two things the user is actually trying to do.\n */\n labelAction={\n configData.email.enabled ? (\n <TRLink\n className=\"text-tinyrack-xs\"\n render={<Link to=\"/password/forgot\" />}\n >\n {t('login.link.forgotPassword')}\n </TRLink>\n ) : undefined\n }\n placeholder={t('login.password.placeholder')}\n {...register('password')}\n type=\"password\"\n />\n\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n loading={loginMutation.isPending}\n loadingLabel={t('login.submitting')}\n type=\"submit\"\n uiSize=\"lg\"\n >\n {t('login.submit')}\n </TRButton>\n </form>\n )}\n\n {implicitNotice && (\n <div\n className=\"prose prose-sm text-center text-tinyrack-text-muted text-tinyrack-xs! **:text-tinyrack-xs!\"\n dangerouslySetInnerHTML={{ __html: implicitNotice }}\n />\n )}\n\n {(configData.registration.public_registration ||\n hasMultipleLoginMethods) && (\n <AuthFooter>\n {configData.registration.public_registration && (\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/register\">\n {t('login.link.register')}\n </Link>\n }\n text={t('login.footer.noAccount')}\n />\n )}\n {hasMultipleLoginMethods && (\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/login\">\n {t('login.password.backToMethods')}\n </Link>\n }\n />\n )}\n </AuthFooter>\n )}\n </AuthLayout>\n );\n}\n"],"mappings":"wCAqBsF,IAAAC,EAA7ED"}
|
|
@@ -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{On as a,Sn as o,Sr as s,i as c,r as l,t as u}from"./config-DTQCUlfZ.js";import{t as d}from"./mutationOptions-DyYFUbyn.js";import{t as f}from"./useMutation-BWZ0G4Td.js";import{tt as p}from"./shell-header-bar-CjG5qvPg.js";import{t as m}from"./auth-field-DD8kvl--.js";import{t as h}from"./authorization-context-banner-SOuBHWIb.js";import{t as g}from"./lock-7NRyvXBS.js";import{t as _}from"./mail-D0B_1Dzd.js";import{c as v,i as y,o as b}from"./zod-C87S6Tec.js";import{F as x,N as S,S as C,j as w,s as T}from"./index-CS23Ozt6.js";import{t as E}from"./auth-page-header-CIn2E4zI.js";import{t as D}from"./auth-layout-VtpryDof.js";import{t as O}from"./promise-OpBtq8tG.js";import{t as k}from"./link-C-WdTj3F.js";import{n as A,t as j}from"./auth-footer-Cz5ivsDc.js";import{o as M}from"./passkey-J1qnYp9A.js";import{r as N,t as P}from"./standard-schema-e8gtSzGE.js";var F=t(e()),I=d({mutationFn:async e=>c(await l.api.auth.login.$post({json:e}))}),L=r();function R(){let{t:e,i18n:t}=n(),r=a(),c=s(),l=T.useSearch(),d=l.account_selection_state&&l.prompt?.split(` `).includes(`login`)?{...l,account_selected:1}:l,R=l.lang??t.language,{data:z}=p(u),B=z.registration.signup_notice?.[R]??z.registration.signup_notice?.[z.i18n.fallback_language],V=z.auth.password.enabled,H=z.auth.passkey.enabled,U=z.identity_providers.length+ +!!V+ +!!H>1,W=(0,F.useMemo)(()=>b({email:v().min(1,e(`validation.email.required`)).pipe(y(e(`validation.email.invalid`))),password:v().min(1,e(`validation.password.required`))}),[e]),G=f({...I,onSuccess:async(e,t)=>{let n=e.user;if(n.email_verification_required&&!n.email_verified){r.navigate({to:`/verify/email`,search:{email:t.email,...S(l)}});return}c.setQueryData(C.queryKey,{user:n}),await O();let i=[];if(z.auth.password.totp.enabled&&n.totp_registered&&i.push(`totp`),z.auth.passkey.enabled&&n.passkey_count>0&&i.push(`passkey`),n.second_factor_required&&i.length===0){if(z.available_2fa_setup_methods.length>1)return r.navigate({to:`/setup/2fa`,search:S(l)});if(z.available_2fa_setup_methods.length===1)return z.available_2fa_setup_methods[0]===`totp`?r.navigate({to:`/setup/totp`,search:S(l)}):r.navigate({to:`/setup/passkey`,search:{...S(l),passkey_name:`default`}})}if(i.length>1)return r.navigate({to:`/verify/2fa`,search:S(l)});if(i.length===1)return i[0]===`totp`?r.navigate({to:`/verify/totp`,search:S(l)}):r.navigate({to:`/verify/passkey`,search:S(l)});if(x(l))window.location.href=w(d);else return r.navigate({to:`/profile`})},onError:t=>{Y(`email`,{type:`manual`,message:e(`login.error.failed`)})},onSettled:()=>{c.invalidateQueries({queryKey:C.queryKey})}}),K=(0,F.useCallback)(async e=>{e.user&&(c.setQueryData(C.queryKey,e),await O(),x(l)?window.location.href=w(d):r.navigate({to:`/profile`})),c.invalidateQueries({queryKey:C.queryKey})},[c,r,l,d]),q=(0,F.useRef)(null);(0,F.useEffect)(()=>{if(!(!H||!V))return q.current=new AbortController,M(K,q.current.signal),()=>{q.current?.abort()}},[H,V,K]);let{register:J,setError:Y,handleSubmit:X,formState:{errors:Z}}=N({defaultValues:{email:``,password:``},resolver:P(W)});return(0,L.jsxs)(D,{children:[(0,L.jsx)(E,{subtitle:e(`login.selectMethod.subtitle`)||void 0,title:e(`login.title`)}),(0,L.jsx)(h,{search:l}),V&&(0,L.jsxs)(`form`,{className:`flex flex-col gap-tinyrack-lg`,onSubmit:X(async e=>{G.mutate(e)}),children:[(0,L.jsx)(m,{autoComplete:`username webauthn`,error:Z.email,icon:_,label:e(`login.email.label`),placeholder:e(`login.email.placeholder`),...J(`email`),type:`email`}),(0,L.jsx)(m,{autoComplete:`current-password`,error:Z.password,icon:g,label:e(`login.password.label`),labelAction:z.email.enabled?(0,L.jsx)(k,{className:`text-tinyrack-xs`,render:(0,L.jsx)(o,{to:`/password/forgot`}),children:e(`login.link.forgotPassword`)}):void 0,placeholder:e(`login.password.placeholder`),...J(`password`),type:`password`}),(0,L.jsx)(i,{className:`w-full`,intent:`primary`,loading:G.isPending,loadingLabel:e(`login.submitting`),type:`submit`,uiSize:`lg`,children:e(`login.submit`)})]}),B&&(0,L.jsx)(`div`,{className:`prose prose-sm text-center text-tinyrack-text-muted text-tinyrack-xs! **:text-tinyrack-xs!`,dangerouslySetInnerHTML:{__html:B}}),(z.registration.public_registration||U)&&(0,L.jsxs)(j,{children:[z.registration.public_registration&&(0,L.jsx)(A,{link:(0,L.jsx)(o,{search:S(l),to:`/register`,children:e(`login.link.register`)}),text:e(`login.footer.noAccount`)}),U&&(0,L.jsx)(A,{link:(0,L.jsx)(o,{search:S(l),to:`/login`,children:e(`login.password.backToMethods`)})})]})]})}export{R as component};
|
|
2
|
-
//# sourceMappingURL=password-RkUttbhD.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"password-RkUttbhD.js","names":["standardSchemaResolver","useMutation","useQueryClient","useSuspenseQuery","Link","useRouter","TRButton","TRLink","LockIcon","MailIcon","useCallback","useEffect","useMemo","useRef","useForm","useTranslation","z","AuthField","AuthFooter","AuthFooterLink","AuthPageHeader","AuthorizationContextBanner","AuthLayout","buildAuthenticatedAuthorizeUrl","extractOAuthParams","isOAuthFlow","tick","appConfigQueryOptions","loginMutationOptions","startConditionalPasskeyAuth","getSessionQueryOptions","Route","LoginPassword","t","i18n","router","queryClient","search","useSearch","authorizeSearch","OAuthSearch","account_selection_state","prompt","split","includes","account_selected","lang","language","data","configData","implicitNotice","registration","signup_notice","fallback_language","isPasswordAuthEnabled","auth","password","enabled","isPasskeyEnabled","passkey","hasMultipleLoginMethods","identity_providers","length","loginSchema","object","email","string","min","pipe","loginMutation","onSuccess","params","user","email_verification_required","email_verified","navigate","to","setQueryData","queryKey","registered_2fa_methods","SecondFactorMethod","totp","totp_registered","push","passkey_count","second_factor_required","available_2fa_setup_methods","method","passkey_name","window","location","href","onError","_error","setError","type","message","onSettled","invalidateQueries","handlePasskeySuccess","AuthResponse","abortControllerRef","AbortController","current","signal","abort","register","handleSubmit","formState","errors","defaultValues","resolver","onSubmit","values","infer","mutate","undefined","isPending","__html","public_registration","component"],"sources":["../../../frontend/src/queries/login.ts","../../../frontend/src/routes/login/password/index.tsx?tsr-split=component"],"sourcesContent":["import { mutationOptions } from '@tanstack/react-query';\nimport type { InferRequestType, InferResponseType } from 'hono/client';\nimport { client, jsonOk } from '#frontend/libs/api.ts';\n\nexport type LoginParams = InferRequestType<\n (typeof client.api.auth.login)['$post']\n>['json'];\n\nexport type LoginResponse = InferResponseType<\n (typeof client.api.auth.login)['$post'],\n 200\n>;\n\nexport const loginMutationOptions = mutationOptions({\n mutationFn: async (values: LoginParams) => {\n const res = await client.api.auth.login.$post({\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 { createFileRoute, Link, useRouter } from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { TRLink } from '@tinyrack/ui/components/link';\nimport { LockIcon, MailIcon } from 'lucide-react';\nimport { useCallback, useEffect, useMemo, useRef } 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 { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { AuthorizationContextBanner } from '#frontend/components/auth/authorization-context-banner.tsx';\nimport { RouteErrorFallback } from '#frontend/components/ui/route-error-fallback.tsx';\nimport { AuthLayout } from '#frontend/features/layout/auth-layout.tsx';\nimport {\n buildAuthenticatedAuthorizeUrl,\n extractOAuthParams,\n hasAuthorizationContext,\n isOAuthFlow,\n type OAuthSearch,\n OAuthSearchSchema,\n type SecondFactorMethod,\n} from '#frontend/libs/oauth-search.ts';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { getAuthorizationContextQueryOptions } from '#frontend/queries/authorization-context.ts';\nimport { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { loginMutationOptions } from '#frontend/queries/login.ts';\nimport { startConditionalPasskeyAuth } from '#frontend/queries/passkey.ts';\nimport {\n type AuthResponse,\n getSessionQueryOptions,\n} from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema;\n\nexport const Route = createFileRoute('/login/password/')({\n component: LoginPassword,\n errorComponent: RouteErrorFallback,\n validateSearch: SearchSchema,\n loaderDeps: ({ search }) => ({\n search,\n }),\n loader: async ({ context, deps }) => {\n await context.queryClient.ensureQueryData(appConfigQueryOptions);\n if (hasAuthorizationContext(deps.search)) {\n await context.queryClient.ensureQueryData(\n getAuthorizationContextQueryOptions(deps.search),\n );\n }\n },\n});\n\nfunction LoginPassword() {\n const { t, i18n } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n const authorizeSearch: OAuthSearch =\n search.account_selection_state &&\n search.prompt?.split(' ').includes('login')\n ? { ...search, account_selected: 1 }\n : search;\n const lang = search.lang ?? i18n.language;\n\n const { data: configData } = useSuspenseQuery(appConfigQueryOptions);\n\n const implicitNotice =\n configData.registration.signup_notice?.[lang] ??\n configData.registration.signup_notice?.[configData.i18n.fallback_language];\n const isPasswordAuthEnabled = configData.auth.password.enabled;\n const isPasskeyEnabled = configData.auth.passkey.enabled;\n const hasMultipleLoginMethods =\n configData.identity_providers.length +\n (isPasswordAuthEnabled ? 1 : 0) +\n (isPasskeyEnabled ? 1 : 0) >\n 1;\n\n const loginSchema = useMemo(\n () =>\n z.object({\n email: z\n .string()\n .min(1, t('validation.email.required'))\n .pipe(z.email(t('validation.email.invalid'))),\n password: z.string().min(1, t('validation.password.required')),\n }),\n [t],\n );\n\n const loginMutation = useMutation({\n ...loginMutationOptions,\n onSuccess: async (data, params) => {\n const user = data.user;\n\n if (user.email_verification_required && !user.email_verified) {\n router.navigate({\n to: '/verify/email',\n search: {\n email: params.email,\n ...extractOAuthParams(search),\n },\n });\n return;\n }\n\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: user,\n });\n await tick();\n\n const registered_2fa_methods: SecondFactorMethod[] = [];\n if (configData.auth.password.totp.enabled && user.totp_registered) {\n registered_2fa_methods.push('totp');\n }\n if (configData.auth.passkey.enabled && user.passkey_count > 0) {\n registered_2fa_methods.push('passkey');\n }\n\n if (user.second_factor_required && registered_2fa_methods.length === 0) {\n if (configData.available_2fa_setup_methods.length > 1) {\n return router.navigate({\n to: '/setup/2fa',\n search: extractOAuthParams(search),\n });\n } else if (configData.available_2fa_setup_methods.length === 1) {\n const method = configData.available_2fa_setup_methods[0];\n if (method === 'totp') {\n return router.navigate({\n to: '/setup/totp',\n search: extractOAuthParams(search),\n });\n } else {\n return router.navigate({\n to: '/setup/passkey',\n search: {\n ...extractOAuthParams(search),\n passkey_name: 'default',\n },\n });\n }\n }\n }\n\n if (registered_2fa_methods.length > 1) {\n return router.navigate({\n to: '/verify/2fa',\n search: extractOAuthParams(search),\n });\n } else if (registered_2fa_methods.length === 1) {\n const method = registered_2fa_methods[0];\n if (method === 'totp') {\n return router.navigate({\n to: '/verify/totp',\n search: extractOAuthParams(search),\n });\n } else {\n return router.navigate({\n to: '/verify/passkey',\n search: extractOAuthParams(search),\n });\n }\n } else {\n if (isOAuthFlow(search)) {\n window.location.href =\n buildAuthenticatedAuthorizeUrl(authorizeSearch);\n } else {\n return router.navigate({ to: '/profile' });\n }\n }\n },\n onError: (_error) => {\n setError('email', {\n type: 'manual',\n message: t('login.error.failed'),\n });\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n const handlePasskeySuccess = useCallback(\n async (data: AuthResponse) => {\n if (data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, data);\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href =\n buildAuthenticatedAuthorizeUrl(authorizeSearch);\n } else {\n router.navigate({ to: '/profile' });\n }\n }\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n [queryClient, router, search, authorizeSearch],\n );\n\n // Conditional UI: Start passkey autofill on page load\n const abortControllerRef = useRef<AbortController | null>(null);\n\n useEffect(() => {\n if (!isPasskeyEnabled || !isPasswordAuthEnabled) {\n return;\n }\n\n abortControllerRef.current = new AbortController();\n startConditionalPasskeyAuth(\n handlePasskeySuccess,\n abortControllerRef.current.signal,\n );\n\n return () => {\n abortControllerRef.current?.abort();\n };\n }, [isPasskeyEnabled, isPasswordAuthEnabled, handlePasskeySuccess]);\n\n const {\n register,\n setError,\n handleSubmit,\n formState: { errors },\n } = useForm({\n defaultValues: {\n email: '',\n password: '',\n },\n resolver: standardSchemaResolver(loginSchema),\n });\n\n const onSubmit = async (values: z.infer<typeof loginSchema>) => {\n loginMutation.mutate(values);\n };\n\n return (\n <AuthLayout>\n {/* Branding lives in the layout's brand panel — see /login. */}\n <AuthPageHeader\n subtitle={t('login.selectMethod.subtitle') || undefined}\n title={t('login.title')}\n />\n\n <AuthorizationContextBanner search={search} />\n\n {isPasswordAuthEnabled && (\n <form\n className=\"flex flex-col gap-tinyrack-lg\"\n onSubmit={handleSubmit(onSubmit)}\n >\n <AuthField\n autoComplete=\"username webauthn\"\n error={errors.email}\n icon={MailIcon}\n label={t('login.email.label')}\n placeholder={t('login.email.placeholder')}\n {...register('email')}\n type=\"email\"\n />\n\n <AuthField\n autoComplete=\"current-password\"\n error={errors.password}\n icon={LockIcon}\n label={t('login.password.label')}\n /*\n * On the label row rather than under the field: it belongs to the\n * password, and putting it between the field and the submit button\n * separated the two things the user is actually trying to do.\n */\n labelAction={\n configData.email.enabled ? (\n <TRLink\n className=\"text-tinyrack-xs\"\n render={<Link to=\"/password/forgot\" />}\n >\n {t('login.link.forgotPassword')}\n </TRLink>\n ) : undefined\n }\n placeholder={t('login.password.placeholder')}\n {...register('password')}\n type=\"password\"\n />\n\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n loading={loginMutation.isPending}\n loadingLabel={t('login.submitting')}\n type=\"submit\"\n uiSize=\"lg\"\n >\n {t('login.submit')}\n </TRButton>\n </form>\n )}\n\n {implicitNotice && (\n <div\n className=\"prose prose-sm text-center text-tinyrack-text-muted text-tinyrack-xs! **:text-tinyrack-xs!\"\n dangerouslySetInnerHTML={{ __html: implicitNotice }}\n />\n )}\n\n {(configData.registration.public_registration ||\n hasMultipleLoginMethods) && (\n <AuthFooter>\n {configData.registration.public_registration && (\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/register\">\n {t('login.link.register')}\n </Link>\n }\n text={t('login.footer.noAccount')}\n />\n )}\n {hasMultipleLoginMethods && (\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/login\">\n {t('login.password.backToMethods')}\n </Link>\n }\n />\n )}\n </AuthFooter>\n )}\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{i as e,r as t}from"./config-DTQCUlfZ.js";import{t as n}from"./mutationOptions-DyYFUbyn.js";var r=n({mutationFn:async n=>e(await t.api.auth.password.forgot.$post({json:n,header:{}}))}),i=n({mutationFn:async n=>e(await t.api.auth.password.reset.$post({json:n}))});export{i as n,r as t};
|
|
2
|
-
//# sourceMappingURL=password-reset-sU5KkBKi.js.map
|
|
@@ -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{On as o,Sn as s,Sr as c}from"./config-DTQCUlfZ.js";import{t as l}from"./useMutation-BWZ0G4Td.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-CS23Ozt6.js";import{t as v}from"./auth-page-header-CIn2E4zI.js";import{t as y}from"./alert-leqyvHOp.js";import{t as b}from"./auth-layout-VtpryDof.js";import{t as x}from"./promise-OpBtq8tG.js";import{t as S}from"./field-Cn4H1CUj.js";import{t as C}from"./input-CzQki7k6.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-BNZ904Zm.js";import{t as k}from"./labeled-separator-CV7nb0XW.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=c(),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=l({...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)(s,{search:p(P),to:`/login`,children:e(`verifyRecovery.backToLogin`)})})})]})}export{P as component};
|
|
2
|
-
//# sourceMappingURL=recovery-PnUATiUi.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{Sn as a,Sr as o,i as s,r as c,t as l}from"./config-DTQCUlfZ.js";import{t as u}from"./mutationOptions-DyYFUbyn.js";import{t as d}from"./useMutation-BWZ0G4Td.js";import{tt as f}from"./shell-header-bar-CjG5qvPg.js";import{t as p}from"./auth-field-DD8kvl--.js";import{t as m}from"./authorization-context-banner-SOuBHWIb.js";import{t as te}from"./lock-7NRyvXBS.js";import{t as h}from"./mail-D0B_1Dzd.js";import{a as g,c as _,i as v,o as y,r as b}from"./zod-C87S6Tec.js";import{E as x,F as S,N as C,S as w,V as ne,j as T,k as E}from"./index-CS23Ozt6.js";import{t as D}from"./auth-page-header-CIn2E4zI.js";import{t as O}from"./auth-layout-VtpryDof.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-BeSOu_Ga.js";import{t as F}from"./terms-checkbox-list-6jteUTIZ.js";import{t as I}from"./labeled-separator-CV7nb0XW.js";var L=t(e()),R=u({mutationFn:async e=>s(await c.api.auth.register.$post({json:e,header:{}}))}),z=r();function B(){let{t:e,i18n:t}=n(),r=ne(),s=o(),c=x.useSearch(),u=c.lang??t.language,B=(0,L.useDeferredValue)(u),{data:V}=f(l),{data:H}=f(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?.[u]??V.registration.signup_notice?.[V.i18n.fallback_language],Y=(0,L.useMemo)(()=>y({email:_().min(1,e(`validation.email.required`)).pipe(v(e(`validation.email.invalid`))),password:_().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:y(Object.fromEntries(K.map(t=>[t.id,t.required?g(!0,{message:e(`validation.terms.required`)}):b()])))}),[K,W.max_length,W.min_length,e]),X=d({...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,...C(c)}});if(s.setQueryData(w.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:C(c)}):r({to:`/setup/passkey`,search:{...C(c),passkey_name:`default`}}):r({to:`/setup/2fa`,search:C(c)})}S(c)?window.location.href=T(c):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 s.invalidateQueries({queryKey:w.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:c}),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:h,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:te,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)(a,{search:C(c),to:`/login`,children:e(`register.link.login`)}),text:e(`register.footer.haveAccount`)})})]})}export{B as component};
|
|
2
|
-
//# sourceMappingURL=register-DQXhru0_.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,q as r,s as i,t as a}from"./createLucideIcon-BPpAIXR_.js";import{Sn as o,t as s}from"./config-DTQCUlfZ.js";import{t as c}from"./useMutation-BWZ0G4Td.js";import{tt as l}from"./shell-header-bar-CjG5qvPg.js";import{t as u}from"./circle-check-6QTLhwM_.js";import{t as d}from"./auth-field-DD8kvl--.js";import{t as f}from"./key-round-CdvHb8vT.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-CS23Ozt6.js";import{t as b}from"./auth-page-header-CIn2E4zI.js";import{t as x}from"./alert-leqyvHOp.js";import{t as S}from"./auth-layout-VtpryDof.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-sU5KkBKi.js";import{t as O}from"./password-strength-BeSOu_Ga.js";var k=a(`lock-keyhole`,[[`circle`,{cx:`12`,cy:`16`,r:`1`,key:`1au0dj`}],[`rect`,{x:`3`,y:`10`,width:`18`,height:`12`,rx:`2`,key:`6s8ecr`}],[`path`,{d:`M7 10V7a5 5 0 0 1 10 0v3`,key:`1pqi11`}]]),A=t(e()),j=r();function M(){let{t:e}=n(),t=v(),{token:r}=y.useSearch(),[a,M]=(0,A.useState)(!1),{data:N}=l(s),P=N.auth.password.policy,F=(0,A.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=c({...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 a?(0,j.jsx)(S,{children:(0,j.jsx)(`div`,{"data-testid":`alert-success`,children:(0,j.jsx)(g,{description:(0,j.jsxs)(j.Fragment,{children:[e(`resetPassword.success.subtitle`),(0,j.jsx)(`br`,{}),e(`resetPassword.success.description`)]}),icon:u,title:e(`resetPassword.success.title`),tone:`success`,children:(0,j.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,j.jsxs)(S,{children:[(0,j.jsx)(b,{subtitle:e(`resetPassword.subtitle`),title:e(`resetPassword.title`)}),(0,j.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,j.jsx)(d,{error:V.token,icon:f,label:e(`resetPassword.token.label`),placeholder:e(`resetPassword.token.placeholder`),...L(`token`),type:`text`}),r&&V.token&&(0,j.jsx)(x,{"data-testid":`reset-password-token-error`,icon:_,type:`error`,children:V.token.message}),(0,j.jsxs)(`div`,{className:`flex flex-col gap-tinyrack-sm`,children:[(0,j.jsx)(d,{autoComplete:`new-password`,error:V.password,icon:p,label:e(`resetPassword.password.label`),placeholder:e(`resetPassword.password.placeholder`),...L(`password`),type:`password`}),(0,j.jsx)(O,{password:H,policy:P})]}),(0,j.jsx)(d,{autoComplete:`new-password`,error:V.confirmPassword,icon:k,label:e(`resetPassword.confirmPassword.label`),placeholder:e(`resetPassword.confirmPassword.placeholder`),...L(`confirmPassword`),type:`password`}),(0,j.jsx)(i,{className:`w-full`,intent:`primary`,loading:I.isPending,loadingLabel:e(`resetPassword.submitting`),type:`submit`,uiSize:`lg`,children:e(`resetPassword.submit`)})]}),(0,j.jsx)(w,{children:(0,j.jsx)(C,{link:(0,j.jsx)(o,{"data-testid":`reset-password-back-to-login`,to:`/login`,children:e(`resetPassword.backToLogin`)})})})]})}export{M as component};
|
|
2
|
-
//# sourceMappingURL=reset-CQgIa3yf.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reset-CQgIa3yf.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":["../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/lock-keyhole.mjs","../../../frontend/src/routes/password/reset/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 [\"circle\", { cx: \"12\", cy: \"16\", r: \"1\", key: \"1au0dj\" }],\n [\"rect\", { x: \"3\", y: \"10\", width: \"18\", height: \"12\", rx: \"2\", key: \"6s8ecr\" }],\n [\"path\", { d: \"M7 10V7a5 5 0 0 1 10 0v3\", key: \"1pqi11\" }]\n];\nconst LockKeyhole = createLucideIcon(\"lock-keyhole\", __iconNode);\n\nexport { __iconNode, LockKeyhole as default };\n//# sourceMappingURL=lock-keyhole.mjs.map\n","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"],"x_google_ignoreList":[0],"mappings":"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"}
|