@tinyrack/issuary-server 0.26.0 → 0.27.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/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/terms.entity.js +4 -0
- package/dist/entities/terms.entity.js.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/entrypoints/app.d.ts +598 -3
- package/dist/entrypoints/app.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts +19 -16
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.js +133 -76
- package/dist/entrypoints/database/postgres/compiled-functions.js.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts +19 -16
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.js +133 -76
- package/dist/entrypoints/database/sqlite/compiled-functions.js.map +1 -1
- package/dist/lib/config/branding.d.ts +5 -0
- package/dist/lib/config/branding.d.ts.map +1 -1
- package/dist/lib/config/branding.js +23 -1
- package/dist/lib/config/branding.js.map +1 -1
- package/dist/lib/config/resolved.d.ts +3 -0
- package/dist/lib/config/resolved.d.ts.map +1 -1
- package/dist/lib/interpolate-html.d.ts +3 -3
- package/dist/lib/interpolate-html.js +3 -3
- package/dist/lib/interpolate-html.js.map +1 -1
- package/dist/migrations/postgres/Migration20260827090000_archive_terms.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260827090000_archive_terms.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260827090000_archive_terms.js +12 -0
- package/dist/migrations/postgres/Migration20260827090000_archive_terms.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/Migration20260827090000_archive_terms.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260827090000_archive_terms.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260827090000_archive_terms.js +12 -0
- package/dist/migrations/sqlite/Migration20260827090000_archive_terms.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/terms.repository.d.ts.map +1 -1
- package/dist/repositories/terms.repository.js +1 -1
- package/dist/repositories/terms.repository.js.map +1 -1
- package/dist/routes/api/admin/console/index.d.ts +523 -0
- package/dist/routes/api/admin/console/index.d.ts.map +1 -0
- package/dist/routes/api/admin/console/index.js +212 -0
- package/dist/routes/api/admin/console/index.js.map +1 -0
- package/dist/routes/api/admin/index.d.ts +584 -0
- package/dist/routes/api/admin/index.d.ts.map +1 -1
- package/dist/routes/api/admin/index.js +3 -1
- package/dist/routes/api/admin/index.js.map +1 -1
- package/dist/routes/api/admin/users/index.d.ts +64 -0
- package/dist/routes/api/admin/users/index.d.ts.map +1 -1
- package/dist/routes/api/admin/users/index.js +47 -0
- package/dist/routes/api/admin/users/index.js.map +1 -1
- package/dist/routes/api/config/get.d.ts +10 -3
- package/dist/routes/api/config/get.d.ts.map +1 -1
- package/dist/routes/api/config/get.js +3 -0
- package/dist/routes/api/config/get.js.map +1 -1
- package/dist/routes/api/config/index.d.ts +10 -3
- package/dist/routes/api/config/index.d.ts.map +1 -1
- package/dist/routes/api/index.d.ts +594 -3
- package/dist/routes/api/index.d.ts.map +1 -1
- package/dist/routes/index.d.ts +594 -3
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/schemas/response.d.ts +4 -1
- package/dist/schemas/response.d.ts.map +1 -1
- package/dist/schemas/response.js +11 -2
- package/dist/schemas/response.js.map +1 -1
- package/dist/services/admin-console.service.d.ts +407 -0
- package/dist/services/admin-console.service.d.ts.map +1 -0
- package/dist/services/admin-console.service.js +377 -0
- package/dist/services/admin-console.service.js.map +1 -0
- package/dist/services/container.d.ts +5 -0
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +3 -0
- package/dist/services/container.js.map +1 -1
- package/dist/services/user.service.d.ts +21 -0
- package/dist/services/user.service.d.ts.map +1 -1
- package/dist/services/user.service.js +65 -1
- package/dist/services/user.service.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/2fa-BowFczF7.js +2 -0
- package/public/assets/2fa-BowFczF7.js.map +1 -0
- package/public/assets/2fa-C_pA-n2i.js +2 -0
- package/public/assets/{2fa-DFTcWEMb.js.map → 2fa-C_pA-n2i.js.map} +1 -1
- package/public/assets/2fa-Cpfhakvn.js +2 -0
- package/public/assets/{2fa-huNZDYU9.js.map → 2fa-Cpfhakvn.js.map} +1 -1
- package/public/assets/2fa-o1a13VHx.js +2 -0
- package/public/assets/2fa-o1a13VHx.js.map +1 -0
- package/public/assets/FieldControl-ShLuCjvG.js +2 -0
- package/public/assets/FieldControl-ShLuCjvG.js.map +1 -0
- package/public/assets/Separator-C6MmGAmP.js +2 -0
- package/public/assets/Separator-C6MmGAmP.js.map +1 -0
- package/public/assets/admin-_jFLs8Ve.js +2 -0
- package/public/assets/admin-_jFLs8Ve.js.map +1 -0
- package/public/assets/admin-shell-B91U4-Ro.js +2 -0
- package/public/assets/admin-shell-B91U4-Ro.js.map +1 -0
- package/public/assets/alert-D3aaK-_3.js +2 -0
- package/public/assets/alert-D3aaK-_3.js.map +1 -0
- package/public/assets/alert-kRxM1xsM.js +2 -0
- package/public/assets/alert-kRxM1xsM.js.map +1 -0
- package/public/assets/auth-choice-row-h4heOMHs.js +2 -0
- package/public/assets/auth-choice-row-h4heOMHs.js.map +1 -0
- package/public/assets/auth-field-BpJ4AHtU.js +2 -0
- package/public/assets/{auth-field-CWyXGKoC.js.map → auth-field-BpJ4AHtU.js.map} +1 -1
- package/public/assets/auth-footer-Du6S-oDG.js +2 -0
- package/public/assets/auth-footer-Du6S-oDG.js.map +1 -0
- package/public/assets/auth-layout-BdRRr0vT.js +2 -0
- package/public/assets/auth-layout-BdRRr0vT.js.map +1 -0
- package/public/assets/auth-page-header-ChaCNNrn.js +2 -0
- package/public/assets/{auth-page-header-DgGAaIiP.js.map → auth-page-header-ChaCNNrn.js.map} +1 -1
- package/public/assets/authorization-context-banner-zVxGX5e8.js +2 -0
- package/public/assets/{authorization-context-banner-DznMDPOX.js.map → authorization-context-banner-zVxGX5e8.js.map} +1 -1
- package/public/assets/avatar-BxTPQIDp.js +2 -0
- package/public/assets/{avatar-D-FRGa1m.js.map → avatar-BxTPQIDp.js.map} +1 -1
- package/public/assets/badge-B8D0Q2qq.js +2 -0
- package/public/assets/{badge-CsOfUji0.js.map → badge-B8D0Q2qq.js.map} +1 -1
- package/public/assets/checkbox-DTPGfvmq.js +2 -0
- package/public/assets/{checkbox-C90dDDza.js.map → checkbox-DTPGfvmq.js.map} +1 -1
- package/public/assets/{circle-check-6QTLhwM_.js → circle-check-Cnzuu7xR.js} +2 -2
- package/public/assets/{circle-check-6QTLhwM_.js.map → circle-check-Cnzuu7xR.js.map} +1 -1
- package/public/assets/clients-DLqy7K3N.js +5 -0
- package/public/assets/clients-DLqy7K3N.js.map +1 -0
- package/public/assets/config-C18-l7z7.js +2 -0
- package/public/assets/config-C18-l7z7.js.map +1 -0
- package/public/assets/{consent-RtCi_85E.js → consent-BWniDzI3.js} +2 -2
- package/public/assets/{consent-RtCi_85E.js.map → consent-BWniDzI3.js.map} +1 -1
- package/public/assets/consent-r_tX8DTb.js +2 -0
- package/public/assets/{consent-B9sQEyO8.js.map → consent-r_tX8DTb.js.map} +1 -1
- package/public/assets/{createLucideIcon-BPpAIXR_.js → createLucideIcon-D-yizrWN.js} +2 -2
- package/public/assets/{createLucideIcon-BPpAIXR_.js.map → createLucideIcon-D-yizrWN.js.map} +1 -1
- package/public/assets/design-system-rich-text-B3NzIRoJ.js +2 -0
- package/public/assets/design-system-rich-text-B3NzIRoJ.js.map +1 -0
- package/public/assets/email-Bx9JlWp3.js +2 -0
- package/public/assets/email-Bx9JlWp3.js.map +1 -0
- package/public/assets/email-Cpfhakvn.js +2 -0
- package/public/assets/email-Cpfhakvn.js.map +1 -0
- package/public/assets/error-DDY8m_Px.js +2 -0
- package/public/assets/error-DDY8m_Px.js.map +1 -0
- package/public/assets/field-CsrUbl__.js +3 -0
- package/public/assets/field-CsrUbl__.js.map +1 -0
- package/public/assets/{fingerprint-pattern-DP62Vk8x.js → fingerprint-pattern-BwUoN1_w.js} +2 -2
- package/public/assets/{fingerprint-pattern-DP62Vk8x.js.map → fingerprint-pattern-BwUoN1_w.js.map} +1 -1
- package/public/assets/forgot-Cpfhakvn.js +2 -0
- package/public/assets/forgot-Cpfhakvn.js.map +1 -0
- package/public/assets/forgot-u52JMu6e.js +2 -0
- package/public/assets/forgot-u52JMu6e.js.map +1 -0
- package/public/assets/form-sJw-V9wb.js +2 -0
- package/public/assets/form-sJw-V9wb.js.map +1 -0
- package/public/assets/index-8mX6CKcW.css +2 -0
- package/public/assets/index-lTEyHSus.js +11 -0
- package/public/assets/index-lTEyHSus.js.map +1 -0
- package/public/assets/initial-avatar-WMjxW3Zz.js +2 -0
- package/public/assets/initial-avatar-WMjxW3Zz.js.map +1 -0
- package/public/assets/input-QvBxPgy5.js +2 -0
- package/public/assets/{input-CxVeC8Pn.js.map → input-QvBxPgy5.js.map} +1 -1
- package/public/assets/{key-round-CdvHb8vT.js → key-round-BxWppK6h.js} +2 -2
- package/public/assets/{key-round-CdvHb8vT.js.map → key-round-BxWppK6h.js.map} +1 -1
- package/public/assets/labeled-separator-DdkyYDWH.js +2 -0
- package/public/assets/labeled-separator-DdkyYDWH.js.map +1 -0
- package/public/assets/link-BHmn75Zo.js +2 -0
- package/public/assets/{link-C-WdTj3F.js.map → link-BHmn75Zo.js.map} +1 -1
- package/public/assets/{lock-7NRyvXBS.js → lock-8wpR2C78.js} +2 -2
- package/public/assets/{lock-7NRyvXBS.js.map → lock-8wpR2C78.js.map} +1 -1
- package/public/assets/login-Cpfhakvn.js +2 -0
- package/public/assets/login-Cpfhakvn.js.map +1 -0
- package/public/assets/login-DRcHjJ2-.js +2 -0
- package/public/assets/login-DRcHjJ2-.js.map +1 -0
- package/public/assets/logout-Dphj1d_0.js +2 -0
- package/public/assets/logout-Dphj1d_0.js.map +1 -0
- package/public/assets/{mail-D0B_1Dzd.js → mail-DVP_XMUi.js} +2 -2
- package/public/assets/{mail-D0B_1Dzd.js.map → mail-DVP_XMUi.js.map} +1 -1
- package/public/assets/modal-JuaLVSyx.js +2 -0
- package/public/assets/modal-JuaLVSyx.js.map +1 -0
- package/public/assets/mutationOptions-Cv_vJkJn.js +2 -0
- package/public/assets/{mutationOptions-DyYFUbyn.js.map → mutationOptions-Cv_vJkJn.js.map} +1 -1
- package/public/assets/passkey-CObBlfKK.js +2 -0
- package/public/assets/passkey-CObBlfKK.js.map +1 -0
- package/public/assets/{passkey-J1qnYp9A.js → passkey-CWTjw19S.js} +2 -2
- package/public/assets/{passkey-J1qnYp9A.js.map → passkey-CWTjw19S.js.map} +1 -1
- package/public/assets/passkey-CavITajY.js +2 -0
- package/public/assets/passkey-CavITajY.js.map +1 -0
- package/public/assets/passkey-Cpfhakvn.js +2 -0
- package/public/assets/passkey-Cpfhakvn.js.map +1 -0
- package/public/assets/{passkey-error-ZqqPQUta.js → passkey-error-CZ26Ss-I.js} +2 -2
- package/public/assets/{passkey-error-ZqqPQUta.js.map → passkey-error-CZ26Ss-I.js.map} +1 -1
- package/public/assets/password-Cpfhakvn.js +2 -0
- package/public/assets/password-Cpfhakvn.js.map +1 -0
- package/public/assets/password-Dk8PwtZN.js +2 -0
- package/public/assets/password-Dk8PwtZN.js.map +1 -0
- package/public/assets/password-reset-BcFpGOop.js +2 -0
- package/public/assets/{password-reset-sU5KkBKi.js.map → password-reset-BcFpGOop.js.map} +1 -1
- package/public/assets/password-strength-Bgvy7kz6.js +2 -0
- package/public/assets/{password-strength-BIPcWiM_.js.map → password-strength-Bgvy7kz6.js.map} +1 -1
- package/public/assets/pin-input-DhsRO4Ei.js +2 -0
- package/public/assets/{pin-input-CITrr-Yc.js.map → pin-input-DhsRO4Ei.js.map} +1 -1
- package/public/assets/profile-PjXEnzA-.js +2 -0
- package/public/assets/profile-PjXEnzA-.js.map +1 -0
- package/public/assets/profile-k66ruDWl.js +2 -0
- package/public/assets/{profile-BHPL9Px_.js.map → profile-k66ruDWl.js.map} +1 -1
- package/public/assets/provider-mark-CeYazOfu.js +2 -0
- package/public/assets/provider-mark-CeYazOfu.js.map +1 -0
- package/public/assets/recovery-hdRyezmb.js +2 -0
- package/public/assets/recovery-hdRyezmb.js.map +1 -0
- package/public/assets/register-Cpfhakvn.js +2 -0
- package/public/assets/register-Cpfhakvn.js.map +1 -0
- package/public/assets/register-DMgKT_fm.js +2 -0
- package/public/assets/register-DMgKT_fm.js.map +1 -0
- package/public/assets/reset-Cpfhakvn.js +2 -0
- package/public/assets/reset-Cpfhakvn.js.map +1 -0
- package/public/assets/reset-DBu3wYpE.js +2 -0
- package/public/assets/reset-DBu3wYpE.js.map +1 -0
- package/public/assets/select-5LheSsRl.js +2 -0
- package/public/assets/select-5LheSsRl.js.map +1 -0
- package/public/assets/select-Cpfhakvn.js +2 -0
- package/public/assets/{select-huNZDYU9.js.map → select-Cpfhakvn.js.map} +1 -1
- package/public/assets/separator-CMGc2Y1q.js +2 -0
- package/public/assets/separator-CMGc2Y1q.js.map +1 -0
- package/public/assets/settings-BVe4k3kJ.js +2 -0
- package/public/assets/settings-BVe4k3kJ.js.map +1 -0
- package/public/assets/shell-header-bar-CdOEWmCT.js +2 -0
- package/public/assets/shell-header-bar-CdOEWmCT.js.map +1 -0
- package/public/assets/{shield-check-D_p8H0ni.js → shield-check-DpYF8yeI.js} +2 -2
- package/public/assets/{shield-check-D_p8H0ni.js.map → shield-check-DpYF8yeI.js.map} +1 -1
- package/public/assets/standard-schema-C50nwAaQ.js +2 -0
- package/public/assets/{standard-schema-e8gtSzGE.js.map → standard-schema-C50nwAaQ.js.map} +1 -1
- package/public/assets/system-BoUqxc5h.js +2 -0
- package/public/assets/system-BoUqxc5h.js.map +1 -0
- package/public/assets/table-Dl89o43x.js +2 -0
- package/public/assets/table-Dl89o43x.js.map +1 -0
- package/public/assets/terms-B2wWfx1d.js +2 -0
- package/public/assets/terms-B2wWfx1d.js.map +1 -0
- package/public/assets/terms-COr3cDw5.js +2 -0
- package/public/assets/terms-COr3cDw5.js.map +1 -0
- package/public/assets/terms-checkbox-list-C9TkDC8Y.js +2 -0
- package/public/assets/terms-checkbox-list-C9TkDC8Y.js.map +1 -0
- package/public/assets/terms-k66ruDWl.js +2 -0
- package/public/assets/terms-k66ruDWl.js.map +1 -0
- package/public/assets/totp-BJycMMTC.js +2 -0
- package/public/assets/totp-BJycMMTC.js.map +1 -0
- package/public/assets/{totp-BNZ904Zm.js → totp-BhElob6P.js} +2 -2
- package/public/assets/{totp-BNZ904Zm.js.map → totp-BhElob6P.js.map} +1 -1
- package/public/assets/totp-C1ba10Is.js +2 -0
- package/public/assets/totp-C1ba10Is.js.map +1 -0
- package/public/assets/{trash-2-DZdKBLvC.js → trash-2-B3NVE8pR.js} +2 -2
- package/public/assets/{trash-2-DZdKBLvC.js.map → trash-2-B3NVE8pR.js.map} +1 -1
- package/public/assets/{triangle-alert-CqNn0kPs.js → triangle-alert-DATO9o3k.js} +2 -2
- package/public/assets/{triangle-alert-CqNn0kPs.js.map → triangle-alert-DATO9o3k.js.map} +1 -1
- package/public/assets/use-admin-selection-D2b7jnym.js +2 -0
- package/public/assets/use-admin-selection-D2b7jnym.js.map +1 -0
- package/public/assets/use-totp-setup-KOVNS2DC.js +3 -0
- package/public/assets/use-totp-setup-KOVNS2DC.js.map +1 -0
- package/public/assets/useAriaLabelledBy-CF3crxLc.js +2 -0
- package/public/assets/{useAriaLabelledBy-IIwdHUss.js.map → useAriaLabelledBy-CF3crxLc.js.map} +1 -1
- package/public/assets/useMutation-DqIIIiBW.js +2 -0
- package/public/assets/{useMutation-BWZ0G4Td.js.map → useMutation-DqIIIiBW.js.map} +1 -1
- package/public/assets/useQuery-CLr9TaKA.js +2 -0
- package/public/assets/{useQuery-Ccv_nzQl.js.map → useQuery-CLr9TaKA.js.map} +1 -1
- package/public/assets/users-BQQQm353.js +2 -0
- package/public/assets/users-BQQQm353.js.map +1 -0
- package/public/assets/{zod-C87S6Tec.js → zod-Dszyrytb.js} +2 -2
- package/public/assets/{zod-C87S6Tec.js.map → zod-Dszyrytb.js.map} +1 -1
- package/public/index.html +6 -6
- package/public/issuary-app-icon-512.png +0 -0
- package/public/issuary-app-icon.svg +8 -0
- package/public/assets/2fa-C9wUlSBS.js +0 -2
- package/public/assets/2fa-C9wUlSBS.js.map +0 -1
- package/public/assets/2fa-DFTcWEMb.js +0 -2
- package/public/assets/2fa-TtshNxXv.js +0 -2
- package/public/assets/2fa-TtshNxXv.js.map +0 -1
- package/public/assets/2fa-huNZDYU9.js +0 -2
- package/public/assets/DialogHandle-DICBMcjK.js +0 -2
- package/public/assets/DialogHandle-DICBMcjK.js.map +0 -1
- package/public/assets/FieldItemContext-BeNfhOsU.js +0 -2
- package/public/assets/FieldItemContext-BeNfhOsU.js.map +0 -1
- package/public/assets/admin-CFZaO1bM.js +0 -2
- package/public/assets/admin-CFZaO1bM.js.map +0 -1
- package/public/assets/admin-users-BK_BN8jm.js +0 -2
- package/public/assets/admin-users-BK_BN8jm.js.map +0 -1
- package/public/assets/alert-leqyvHOp.js +0 -2
- package/public/assets/alert-leqyvHOp.js.map +0 -1
- package/public/assets/auth-choice-row-CXuyJgkR.js +0 -2
- package/public/assets/auth-choice-row-CXuyJgkR.js.map +0 -1
- package/public/assets/auth-field-CWyXGKoC.js +0 -2
- package/public/assets/auth-footer-Cz5ivsDc.js +0 -2
- package/public/assets/auth-footer-Cz5ivsDc.js.map +0 -1
- package/public/assets/auth-layout-CiNn2-Nb.js +0 -2
- package/public/assets/auth-layout-CiNn2-Nb.js.map +0 -1
- package/public/assets/auth-page-header-DgGAaIiP.js +0 -2
- package/public/assets/authorization-context-banner-DznMDPOX.js +0 -2
- package/public/assets/avatar-D-FRGa1m.js +0 -2
- package/public/assets/badge-CsOfUji0.js +0 -2
- package/public/assets/checkbox-C90dDDza.js +0 -2
- package/public/assets/chevron-right-CN0jUyV0.js +0 -2
- package/public/assets/chevron-right-CN0jUyV0.js.map +0 -1
- package/public/assets/config-DTQCUlfZ.js +0 -2
- package/public/assets/config-DTQCUlfZ.js.map +0 -1
- package/public/assets/consent-B9sQEyO8.js +0 -2
- package/public/assets/email-8RKQzeig.js +0 -2
- package/public/assets/email-8RKQzeig.js.map +0 -1
- package/public/assets/email-huNZDYU9.js +0 -2
- package/public/assets/email-huNZDYU9.js.map +0 -1
- package/public/assets/error-BYe3gUMO.js +0 -2
- package/public/assets/error-BYe3gUMO.js.map +0 -1
- package/public/assets/field-BMT214_m.js +0 -3
- package/public/assets/field-BMT214_m.js.map +0 -1
- package/public/assets/forgot-BenoOUxC.js +0 -2
- package/public/assets/forgot-BenoOUxC.js.map +0 -1
- package/public/assets/forgot-huNZDYU9.js +0 -2
- package/public/assets/forgot-huNZDYU9.js.map +0 -1
- package/public/assets/index-CKpnrw9M.js +0 -11
- package/public/assets/index-CKpnrw9M.js.map +0 -1
- package/public/assets/index-Ct9o0oCZ.css +0 -2
- package/public/assets/initial-avatar-E5DK9Igm.js +0 -2
- package/public/assets/initial-avatar-E5DK9Igm.js.map +0 -1
- package/public/assets/input-CxVeC8Pn.js +0 -2
- package/public/assets/labeled-separator-CV7nb0XW.js +0 -2
- package/public/assets/labeled-separator-CV7nb0XW.js.map +0 -1
- package/public/assets/link-C-WdTj3F.js +0 -2
- package/public/assets/login-1YuiZD30.js +0 -2
- package/public/assets/login-1YuiZD30.js.map +0 -1
- package/public/assets/login-huNZDYU9.js +0 -2
- package/public/assets/login-huNZDYU9.js.map +0 -1
- package/public/assets/logout-B5T52P8u.js +0 -2
- package/public/assets/logout-B5T52P8u.js.map +0 -1
- package/public/assets/modal-tByFpy18.js +0 -2
- package/public/assets/modal-tByFpy18.js.map +0 -1
- package/public/assets/mutationOptions-DyYFUbyn.js +0 -2
- package/public/assets/passkey-CgAHaQ1p.js +0 -2
- package/public/assets/passkey-CgAHaQ1p.js.map +0 -1
- package/public/assets/passkey-huNZDYU9.js +0 -2
- package/public/assets/passkey-huNZDYU9.js.map +0 -1
- package/public/assets/passkey-v9Pzv-4A.js +0 -2
- package/public/assets/passkey-v9Pzv-4A.js.map +0 -1
- package/public/assets/password-Cuh9Hnjp.js +0 -2
- package/public/assets/password-Cuh9Hnjp.js.map +0 -1
- package/public/assets/password-huNZDYU9.js +0 -2
- package/public/assets/password-huNZDYU9.js.map +0 -1
- package/public/assets/password-reset-sU5KkBKi.js +0 -2
- package/public/assets/password-strength-BIPcWiM_.js +0 -2
- package/public/assets/pin-input-CITrr-Yc.js +0 -2
- package/public/assets/plus-DSBBSrgj.js +0 -2
- package/public/assets/plus-DSBBSrgj.js.map +0 -1
- package/public/assets/profile-BHPL9Px_.js +0 -2
- package/public/assets/profile-C8KaELVe.js +0 -2
- package/public/assets/profile-C8KaELVe.js.map +0 -1
- package/public/assets/provider-logos-u1YURWQr.js +0 -2
- package/public/assets/provider-logos-u1YURWQr.js.map +0 -1
- package/public/assets/recovery-CVROV9nj.js +0 -2
- package/public/assets/recovery-CVROV9nj.js.map +0 -1
- package/public/assets/register-cpxjX3qr.js +0 -2
- package/public/assets/register-cpxjX3qr.js.map +0 -1
- package/public/assets/register-huNZDYU9.js +0 -2
- package/public/assets/register-huNZDYU9.js.map +0 -1
- package/public/assets/reset-huNZDYU9.js +0 -2
- package/public/assets/reset-huNZDYU9.js.map +0 -1
- package/public/assets/reset-iNqYdsoa.js +0 -2
- package/public/assets/reset-iNqYdsoa.js.map +0 -1
- package/public/assets/select-DdjQtcLJ.js +0 -2
- package/public/assets/select-DdjQtcLJ.js.map +0 -1
- package/public/assets/select-huNZDYU9.js +0 -2
- package/public/assets/separator-B0Bvh1he.js +0 -2
- package/public/assets/separator-B0Bvh1he.js.map +0 -1
- package/public/assets/shell-header-bar-JcFhS7mb.js +0 -2
- package/public/assets/shell-header-bar-JcFhS7mb.js.map +0 -1
- package/public/assets/standard-schema-e8gtSzGE.js +0 -2
- package/public/assets/terms-BHPL9Px_.js +0 -2
- package/public/assets/terms-BHPL9Px_.js.map +0 -1
- package/public/assets/terms-BjwMWDFp.js +0 -2
- package/public/assets/terms-BjwMWDFp.js.map +0 -1
- package/public/assets/terms-checkbox-list-DNOq4Pb2.js +0 -2
- package/public/assets/terms-checkbox-list-DNOq4Pb2.js.map +0 -1
- package/public/assets/totp-D_EWG1h8.js +0 -2
- package/public/assets/totp-D_EWG1h8.js.map +0 -1
- package/public/assets/totp-DetFwOkk.js +0 -2
- package/public/assets/totp-DetFwOkk.js.map +0 -1
- package/public/assets/use-totp-setup-DtlgPUPJ.js +0 -3
- package/public/assets/use-totp-setup-DtlgPUPJ.js.map +0 -1
- package/public/assets/useAriaLabelledBy-IIwdHUss.js +0 -2
- package/public/assets/useMutation-BWZ0G4Td.js +0 -2
- package/public/assets/useQuery-Ccv_nzQl.js +0 -2
- package/public/assets/users-B1gvPM_x.js +0 -2
- package/public/assets/users-B1gvPM_x.js.map +0 -1
- package/public/vite.svg +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{q as e}from"./createLucideIcon-BPpAIXR_.js";import{t}from"./avatar-D-FRGa1m.js";var n=e(),r={sm:{"--tr-avatar-size":`2rem`,"--tr-avatar-font-size":`var(--tinyrack-text-sm)`},md:{"--tr-avatar-size":`3rem`,"--tr-avatar-font-size":`var(--tinyrack-text-xl)`},lg:{"--tr-avatar-size":`4rem`,"--tr-avatar-font-size":`var(--tinyrack-text-2xl)`}};function i({email:e,size:i=`md`}){let a=e.charAt(0).toUpperCase();return(0,n.jsx)(t.Root,{className:`shrink-0 font-tinyrack-bold`,shape:`circle`,style:{...r[i],"--tr-avatar-background":`var(--tinyrack-primary)`,"--tr-avatar-color":`var(--tinyrack-on-primary)`,"--tr-avatar-border":`transparent`},children:(0,n.jsx)(t.Fallback,{children:a})})}export{i as t};
|
|
2
|
-
//# sourceMappingURL=initial-avatar-E5DK9Igm.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"initial-avatar-E5DK9Igm.js","names":[],"sources":["../../../frontend/src/components/ui/initial-avatar.tsx"],"sourcesContent":["import { TRAvatar } from '@tinyrack/ui/components/avatar';\nimport type { CSSProperties } from 'react';\n\ntype InitialAvatarProps = {\n email: string;\n size?: 'sm' | 'md' | 'lg';\n};\n\n/**\n * Brand-colored initial avatar built on the design system's `TRAvatar`.\n * Size, font size and the primary color pair are applied through the\n * component's own `--tr-avatar-*` custom properties so it composes the\n * design system rather than re-implementing an avatar.\n */\nconst sizeVars: Record<\n NonNullable<InitialAvatarProps['size']>,\n CSSProperties\n> = {\n sm: {\n '--tr-avatar-size': '2rem',\n '--tr-avatar-font-size': 'var(--tinyrack-text-sm)',\n } as CSSProperties,\n md: {\n '--tr-avatar-size': '3rem',\n '--tr-avatar-font-size': 'var(--tinyrack-text-xl)',\n } as CSSProperties,\n lg: {\n '--tr-avatar-size': '4rem',\n '--tr-avatar-font-size': 'var(--tinyrack-text-2xl)',\n } as CSSProperties,\n};\n\nexport function InitialAvatar({ email, size = 'md' }: InitialAvatarProps) {\n const initial = email.charAt(0).toUpperCase();\n\n return (\n <TRAvatar.Root\n className=\"shrink-0 font-tinyrack-bold\"\n shape=\"circle\"\n style={\n {\n ...sizeVars[size],\n '--tr-avatar-background': 'var(--tinyrack-primary)',\n '--tr-avatar-color': 'var(--tinyrack-on-primary)',\n '--tr-avatar-border': 'transparent',\n } as CSSProperties\n }\n >\n <TRAvatar.Fallback>{initial}</TRAvatar.Fallback>\n </TRAvatar.Root>\n );\n}\n"],"mappings":"iGAcM,EAGF,CACF,GAAI,CACF,mBAAoB,OACpB,wBAAyB,yBAC3B,EACA,GAAI,CACF,mBAAoB,OACpB,wBAAyB,yBAC3B,EACA,GAAI,CACF,mBAAoB,OACpB,wBAAyB,0BAC3B,CACF,EAEA,SAAgB,EAAc,CAAE,QAAO,OAAO,MAA4B,CACxE,IAAM,EAAU,EAAM,OAAO,CAAC,CAAC,CAAC,YAAY,EAE5C,OACE,EAAA,EAAA,IAAA,CAAC,EAAS,KAAV,CACE,UAAU,8BACV,MAAM,SACN,MACE,CACE,GAAG,EAAS,GACZ,yBAA0B,0BAC1B,oBAAqB,6BACrB,qBAAsB,aACxB,YAGF,EAAA,EAAA,IAAA,CAAC,EAAS,SAAV,CAAA,SAAoB,CAA2B,CAAA,CAClC,CAAA,CAEnB"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{G as e,J as t,W as n,Z as r,q as i}from"./createLucideIcon-BPpAIXR_.js";import{xn as a}from"./config-DTQCUlfZ.js";import{n as o}from"./field-BMT214_m.js";var s=i(),c=r(t(),1),l=(0,c.createContext)(!1);function u(){return(0,c.useContext)(l)}var d=c.forwardRef(function(e,t){return(0,s.jsx)(o,{ref:t,...e})});function f({className:t,uiSize:n=`md`,appearance:r=`solid`,...i}){a();let o=u();return(0,s.jsx)(d,{...i,className:e(o?`tr-input tr-input-group-input`:`tr-input`,t),"data-appearance":r,"data-ui-size":n})}function p({className:e,type:t=`button`,...r}){return(0,s.jsx)(`button`,{...r,className:n(`tr-input-group-action`,e),type:t})}function m({className:e,side:t=`start`,...r}){return(0,s.jsx)(`span`,{...r,className:n(`tr-input-group-adornment`,e),"data-side":t})}function h({children:e,className:t,uiSize:r=`md`,...i}){return a(),(0,s.jsx)(`div`,{...i,className:n(`tr-input-group`,t),"data-ui-size":r,children:(0,s.jsx)(l,{value:!0,children:e})})}var g=Object.assign(f,{Group:h,Adornment:m,Action:p});export{g as t};
|
|
2
|
-
//# sourceMappingURL=input-CxVeC8Pn.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{n as e,q as t}from"./createLucideIcon-BPpAIXR_.js";import{t as n}from"./separator-B0Bvh1he.js";var r=t();function i({label:t,className:i=``}){return t?(0,r.jsxs)(`div`,{className:`flex items-center gap-tinyrack-md ${i}`,children:[(0,r.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,r.jsx)(n,{orientation:`horizontal`})}),(0,r.jsx)(e,{color:`muted`,variant:`caption`,children:t}),(0,r.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,r.jsx)(n,{orientation:`horizontal`})})]}):(0,r.jsx)(n,{className:i,orientation:`horizontal`})}export{i as t};
|
|
2
|
-
//# sourceMappingURL=labeled-separator-CV7nb0XW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"labeled-separator-CV7nb0XW.js","names":[],"sources":["../../../frontend/src/components/ui/labeled-separator.tsx"],"sourcesContent":["import { TRSeparator } from '@tinyrack/ui/components/separator';\nimport { TRText } from '@tinyrack/ui/components/text';\n\ntype LabeledSeparatorProps = {\n /** Omit for a plain rule. */\n label?: string;\n className?: string;\n};\n\n/**\n * A rule that can carry a centred label (\"or\", \"Terms\").\n *\n * Two separators flank the label so the line reads as continuous. Replaces\n * the old `Divider` plus two hand-rolled copies of the same markup in the\n * register and terms screens.\n */\nexport function LabeledSeparator({\n label,\n className = '',\n}: LabeledSeparatorProps) {\n if (!label) {\n return <TRSeparator className={className} orientation=\"horizontal\" />;\n }\n\n return (\n <div className={`flex items-center gap-tinyrack-md ${className}`}>\n {/*\n The rules are wrapped rather than flexed directly: TRSeparator sets its\n own `inline-size`, which a width utility on the element does not\n override, so each rule would demand the full container width and the\n row would overflow as soon as the label is more than a word or two.\n */}\n <div className=\"min-w-0 flex-1\">\n <TRSeparator orientation=\"horizontal\" />\n </div>\n <TRText color=\"muted\" variant=\"caption\">\n {label}\n </TRText>\n <div className=\"min-w-0 flex-1\">\n <TRSeparator orientation=\"horizontal\" />\n </div>\n </div>\n );\n}\n"],"mappings":"gHAgBA,SAAgB,EAAiB,CAC/B,QACA,YAAY,IACY,CAKxB,OAJK,GAKH,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,qCAAqC,aAArD,EAOE,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,YAAY,YAAc,CAAA,CACpC,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,MAAM,QAAQ,QAAQ,mBAC3B,CACK,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,2BACb,EAAA,EAAA,IAAA,CAAC,EAAD,CAAa,YAAY,YAAc,CAAA,CACpC,CAAA,CACF,KApBE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAwB,YAAW,YAAY,YAAc,CAAA,CAsBxE"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,W as t,Z as n,o as r}from"./createLucideIcon-BPpAIXR_.js";var i=n(e(),1);function a({className:e,disabled:n=!1,href:a,onClick:o,onKeyDown:s,ref:c,render:l,underline:u=`hover`,variant:d=`default`,...f}){let p=n&&(0,i.isValidElement)(l)?(0,i.cloneElement)(l,{href:void 0}):l;return r({defaultTagName:`a`,props:{...f,"aria-disabled":n||void 0,className:t(`tr-link`,e),"data-disabled":n?``:void 0,"data-underline":u,"data-variant":d,href:n?void 0:a,onClick(e){if(n){e.preventDefault(),e.stopPropagation();return}o?.(e)},onKeyDown(e){if(n&&(e.key===`Enter`||e.key===` `)){e.preventDefault(),e.stopPropagation();return}s?.(e)},tabIndex:n?-1:f.tabIndex},ref:c,render:p})}export{a as t};
|
|
2
|
-
//# sourceMappingURL=link-C-WdTj3F.js.map
|
|
@@ -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{nt as u}from"./shell-header-bar-JcFhS7mb.js";import{t as d}from"./fingerprint-pattern-DP62Vk8x.js";import{t as f}from"./authorization-context-banner-DznMDPOX.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-CKpnrw9M.js";import{t as T}from"./auth-page-header-DgGAaIiP.js";import{t as E}from"./alert-leqyvHOp.js";import{t as D}from"./auth-layout-CiNn2-Nb.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-1YuiZD30.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-1YuiZD30.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":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-huNZDYU9.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{t as e}from"./createLucideIcon-BPpAIXR_.js";import{i as t,r as n}from"./config-DTQCUlfZ.js";import{t as r}from"./mutationOptions-DyYFUbyn.js";var i=e(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),a=r({mutationFn:async()=>t(await n.api.auth.logout.$post())});export{i as n,a as t};
|
|
2
|
-
//# sourceMappingURL=logout-B5T52P8u.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logout-B5T52P8u.js","names":[],"sources":["../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/log-out.mjs","../../../frontend/src/queries/logout.ts"],"sourcesContent":["/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m16 17 5-5-5-5\", key: \"1bji2h\" }],\n [\"path\", { d: \"M21 12H9\", key: \"dn1m92\" }],\n [\"path\", { d: \"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\", key: \"1uf3rs\" }]\n];\nconst LogOut = createLucideIcon(\"log-out\", __iconNode);\n\nexport { __iconNode, LogOut as default };\n//# sourceMappingURL=log-out.mjs.map\n","import { mutationOptions } from '@tanstack/react-query';\nimport { client, jsonOk } from '#frontend/libs/api.ts';\n\nexport const logoutMutationOptions = mutationOptions({\n mutationFn: async () => {\n const res = await client.api.auth.logout.$post();\n return jsonOk(res);\n },\n});\n"],"x_google_ignoreList":[0],"mappings":"qJAcA,IAAM,EAAS,EAAiB,UAAW,CAJzC,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAS,CAAC,EAC/C,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,0CAA2C,IAAK,QAAS,CAAC,CAE/B,CAAU,ECXxC,EAAwB,EAAgB,CACnD,WAAY,SAEH,EAAO,MADI,EAAO,IAAI,KAAK,OAAO,MAAM,CAC9B,CAErB,CAAC"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{G as e,J as t,Z as n,c as r,q as i}from"./createLucideIcon-BPpAIXR_.js";import{_ as a,bn as o,pt as s}from"./config-DTQCUlfZ.js";import{B as c,H as l,P as u,tt as d,u as f}from"./shell-header-bar-JcFhS7mb.js";import{a as p,c as m,d as h,f as g,i as _,l as v,n as y,o as b,r as x,s as S,u as C}from"./DialogHandle-DICBMcjK.js";var w=n(t(),1),T=w.forwardRef(function(e,t){let{render:n,className:i,style:o,forceRender:s=!1,...c}=e,l=g(),u=l.useState(`open`),d=l.useState(`nested`),f=l.useState(`mounted`);return r(`div`,e,{state:{open:u,transitionStatus:l.useState(`transitionStatus`)},ref:[l.context.backdropRef,t],stateAttributesMapping:a,props:[{role:`presentation`,hidden:!f,style:{userSelect:`none`,WebkitUserSelect:`none`}},c],enabled:s||!d})}),E=i(),D=w.forwardRef(function(e,t){let{render:n,className:i,style:a,finalFocus:o,initialFocus:u,...p}=e,m=g(),h=m.useState(`descriptionElementId`),y=m.useState(`disablePointerDismissal`),b=m.useState(`floatingRootContext`),x=m.useState(`popupProps`),S=m.useState(`modal`),C=m.useState(`mounted`),w=m.useState(`nested`),T=m.useState(`nestedOpenDialogCount`),D=m.useState(`open`),O=m.useState(`openMethod`),k=m.useState(`titleElementId`),A=m.useState(`transitionStatus`),j=m.useState(`role`),M=b.useState(`floatingId`);v(),s({open:D,ref:m.context.popupRef,onComplete(){D&&m.context.onOpenChangeComplete?.(!0)}});let N=u===void 0?l(m.context.popupRef):u,P=T>0,F=m.useStateSetter(`popupElement`),I=r(`div`,e,{state:{open:D,nested:w,transitionStatus:A,nestedDialogOpen:P},props:[x,{id:M,"aria-labelledby":k,"aria-describedby":h,role:j,...c,hidden:!C,onKeyDown(e){f.has(e.key)&&e.stopPropagation()},style:{"--nested-dialogs":T}},p],ref:[t,m.context.popupRef,F],stateAttributesMapping:_});return(0,E.jsx)(d,{context:b,openInteractionType:O,disabled:!C,closeOnFocusOut:!y,initialFocus:N,returnFocus:o,modal:S!==!1,restoreFocus:`popup`,children:I})});function O(e){return S(`dialog`,e)}var k=o(T,`tr-layer-backdrop tr-dialog-backdrop`),A=o(h,`tr-dialog-close`),j=o(C,`tr-dialog-description`);function M(){return y()}function N({className:t,placement:n=`middle`,...r}){return(0,E.jsx)(D,{...r,className:e(`tr-dialog tr-dialog-box`,t),"data-placement":n})}var P=o(m);function F(e){return(0,E.jsx)(O,{...e})}var I=o(b,`tr-dialog-title`),L=o(p,`tr-dialog-trigger`),R={Backdrop:k,Close:A,Description:j,Popup:N,Portal:P,Root:F,Viewport:o(x,`tr-layer-viewport tr-dialog-viewport`),Title:I,Trigger:L,createHandle:M},z={sm:`[--tr-dialog-box-max-width:var(--tinyrack-overlay-width-sm)]`,md:`[--tr-dialog-box-max-width:var(--tinyrack-overlay-width-md)]`,lg:`[--tr-dialog-box-max-width:var(--tinyrack-overlay-width-md)]`},B={default:`bg-tinyrack-surface-muted text-tinyrack-text`,destructive:`bg-tinyrack-danger-surface text-tinyrack-danger-foreground`};function V({isOpen:e,onClose:t,title:n,description:r,children:i,size:a=`md`,preventClose:o=!1,icon:s,variant:c=`default`}){return(0,w.useEffect)(()=>{if(!e||o)return;let n=e=>{e.key===`Escape`&&t()};return document.addEventListener(`keydown`,n),()=>document.removeEventListener(`keydown`,n)},[e,o,t]),e?(0,E.jsx)(R.Root,{defaultOpen:!0,disablePointerDismissal:o,onOpenChange:e=>{!e&&!o&&t()},children:(0,E.jsx)(R.Portal,{children:(0,E.jsxs)(R.Viewport,{children:[(0,E.jsx)(R.Backdrop,{}),(0,E.jsxs)(R.Popup,{className:z[a],children:[(0,E.jsxs)(`div`,{className:`flex items-start gap-tinyrack-md`,children:[s&&(0,E.jsx)(`div`,{className:`flex size-tinyrack-2xl shrink-0 items-center justify-center rounded-tinyrack-full ${B[c]}`,children:(0,E.jsx)(s,{"aria-hidden":!0,className:`size-tinyrack-lg`})}),(0,E.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-tinyrack-3xs`,children:[(0,E.jsx)(R.Title,{children:n}),r&&(0,E.jsx)(R.Description,{className:`text-tinyrack-text-muted text-tinyrack-xs`,children:r})]}),!o&&(0,E.jsx)(R.Close,{"aria-label":`Close`,className:`shrink-0`,"data-testid":`modal-close`,children:(0,E.jsx)(u,{"aria-hidden":!0,className:`size-tinyrack-lg`})})]}),i]})]})})}):null}function H({children:e}){return(0,E.jsx)(`div`,{className:`flex justify-end gap-tinyrack-sm pt-tinyrack-lg`,children:e})}export{H as n,V as t};
|
|
2
|
-
//# sourceMappingURL=modal-tByFpy18.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modal-tByFpy18.js","names":["Dialog.Backdrop","Dialog.Close","Dialog.Description","Dialog.createHandle","Dialog.Popup","Dialog.Portal","Dialog.Root","Dialog.Title","Dialog.Trigger","Dialog.Viewport"],"sources":["../../../../node_modules/.pnpm/@base-ui+react@1.7.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7/node_modules/@base-ui/react/dialog/backdrop/DialogBackdrop.mjs","../../../../node_modules/.pnpm/@base-ui+react@1.7.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7/node_modules/@base-ui/react/dialog/popup/DialogPopup.mjs","../../../../node_modules/.pnpm/@base-ui+react@1.7.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7/node_modules/@base-ui/react/dialog/root/DialogRoot.mjs","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-backdrop.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-close.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-description.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-handle.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-popup.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-portal.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-root.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-title.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-trigger.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/dialog-viewport.js","../../../../node_modules/.pnpm/@tinyrack+ui@0.29.0_@types+react@19.2.17_react-dom@19.2.7_react@19.2.7__react@19.2.7_shiki@4.4.2_tailwindcss@4.3.2/node_modules/@tinyrack/ui/dist/components/dialog/index.js","../../../frontend/src/components/ui/modal.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useDialogRootContext } from \"../root/DialogRootContext.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\nimport { popupTransitionStateMapping } from \"../../utils/popupStateMapping.mjs\";\n\n/**\n * An overlay displayed beneath the popup.\n * Renders a `<div>` element.\n *\n * Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)\n */\nexport const DialogBackdrop = /*#__PURE__*/React.forwardRef(function DialogBackdrop(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n forceRender = false,\n ...elementProps\n } = componentProps;\n const store = useDialogRootContext();\n const open = store.useState('open');\n const nested = store.useState('nested');\n const mounted = store.useState('mounted');\n const transitionStatus = store.useState('transitionStatus');\n const state = {\n open,\n transitionStatus\n };\n return useRenderElement('div', componentProps, {\n state,\n ref: [store.context.backdropRef, forwardedRef],\n stateAttributesMapping: popupTransitionStateMapping,\n props: [{\n role: 'presentation',\n hidden: !mounted,\n style: {\n userSelect: 'none',\n WebkitUserSelect: 'none'\n }\n }, elementProps],\n enabled: forceRender || !nested\n });\n});\nif (process.env.NODE_ENV !== \"production\") DialogBackdrop.displayName = \"DialogBackdrop\";","'use client';\n\nimport * as React from 'react';\nimport { FloatingFocusManager } from \"../../floating-ui-react/index.mjs\";\nimport { useDialogRootContext } from \"../root/DialogRootContext.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\nimport { useDialogPortalContext } from \"../portal/DialogPortalContext.mjs\";\nimport { useOpenChangeComplete } from \"../../internals/useOpenChangeComplete.mjs\";\nimport { COMPOSITE_KEYS } from \"../../internals/composite/composite.mjs\";\nimport { FOCUSABLE_POPUP_PROPS, createDefaultInitialFocus } from \"../../utils/popups/index.mjs\";\nimport { dialogStateAttributesMapping } from \"../utils/stateAttributesMapping.mjs\";\n\n/**\n * A container for the dialog contents.\n * Renders a `<div>` element.\n *\n * Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)\n */\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport const DialogPopup = /*#__PURE__*/React.forwardRef(function DialogPopup(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n finalFocus,\n initialFocus,\n ...elementProps\n } = componentProps;\n const store = useDialogRootContext();\n const descriptionElementId = store.useState('descriptionElementId');\n const disablePointerDismissal = store.useState('disablePointerDismissal');\n const floatingRootContext = store.useState('floatingRootContext');\n const rootPopupProps = store.useState('popupProps');\n const modal = store.useState('modal');\n const mounted = store.useState('mounted');\n const nested = store.useState('nested');\n const nestedOpenDialogCount = store.useState('nestedOpenDialogCount');\n const open = store.useState('open');\n const openMethod = store.useState('openMethod');\n const titleElementId = store.useState('titleElementId');\n const transitionStatus = store.useState('transitionStatus');\n const role = store.useState('role');\n const floatingId = floatingRootContext.useState('floatingId');\n useDialogPortalContext();\n useOpenChangeComplete({\n open,\n ref: store.context.popupRef,\n onComplete() {\n if (open) {\n store.context.onOpenChangeComplete?.(true);\n }\n }\n });\n const resolvedInitialFocus = initialFocus === undefined ? createDefaultInitialFocus(store.context.popupRef) : initialFocus;\n const nestedDialogOpen = nestedOpenDialogCount > 0;\n const setPopupElement = store.useStateSetter('popupElement');\n const state = {\n open,\n nested,\n transitionStatus,\n nestedDialogOpen\n };\n const element = useRenderElement('div', componentProps, {\n state,\n props: [rootPopupProps, {\n id: floatingId,\n 'aria-labelledby': titleElementId,\n 'aria-describedby': descriptionElementId,\n role,\n ...FOCUSABLE_POPUP_PROPS,\n hidden: !mounted,\n onKeyDown(event) {\n if (COMPOSITE_KEYS.has(event.key)) {\n event.stopPropagation();\n }\n },\n style: {\n '--nested-dialogs': nestedOpenDialogCount\n }\n }, elementProps],\n ref: [forwardedRef, store.context.popupRef, setPopupElement],\n stateAttributesMapping: dialogStateAttributesMapping\n });\n return /*#__PURE__*/_jsx(FloatingFocusManager, {\n context: floatingRootContext,\n openInteractionType: openMethod,\n disabled: !mounted,\n closeOnFocusOut: !disablePointerDismissal,\n initialFocus: resolvedInitialFocus,\n returnFocus: finalFocus,\n modal: modal !== false,\n restoreFocus: \"popup\",\n children: element\n });\n});\nif (process.env.NODE_ENV !== \"production\") DialogPopup.displayName = \"DialogPopup\";","'use client';\n\nimport { useRenderDialogRoot } from \"./useRenderDialogRoot.mjs\";\n\n/**\n * Groups all parts of the dialog.\n * Doesn't render its own HTML element.\n *\n * Documentation: [Base UI Dialog](https://base-ui.com/react/components/dialog)\n */\nexport function DialogRoot(props) {\n return useRenderDialogRoot('dialog', props);\n}","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-backdrop.tsx\nconst TRDialogBackdrop = createComponentPart(Dialog.Backdrop, \"tr-layer-backdrop tr-dialog-backdrop\");\n//#endregion\nexport { TRDialogBackdrop };\n\n//# sourceMappingURL=dialog-backdrop.js.map","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-close.tsx\nconst TRDialogClose = createComponentPart(Dialog.Close, \"tr-dialog-close\");\n//#endregion\nexport { TRDialogClose };\n\n//# sourceMappingURL=dialog-close.js.map","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-description.tsx\nconst TRDialogDescription = createComponentPart(Dialog.Description, \"tr-dialog-description\");\n//#endregion\nexport { TRDialogDescription };\n\n//# sourceMappingURL=dialog-description.js.map","\"use client\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-handle.ts\nfunction createDialogHandle() {\n\treturn Dialog.createHandle();\n}\n//#endregion\nexport { createDialogHandle };\n\n//# sourceMappingURL=dialog-handle.js.map","\"use client\";\nimport { mergeComponentClassName } from \"../../internal/component-class-name.js\";\nimport { jsx } from \"react/jsx-runtime\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-popup.tsx\nfunction TRDialogPopup({ className, placement = \"middle\", ...props }) {\n\treturn /* @__PURE__ */ jsx(Dialog.Popup, {\n\t\t...props,\n\t\tclassName: mergeComponentClassName(\"tr-dialog tr-dialog-box\", className),\n\t\t\"data-placement\": placement\n\t});\n}\n//#endregion\nexport { TRDialogPopup };\n\n//# sourceMappingURL=dialog-popup.js.map","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-portal.tsx\nconst TRDialogPortal = createComponentPart(Dialog.Portal);\n//#endregion\nexport { TRDialogPortal };\n\n//# sourceMappingURL=dialog-portal.js.map","\"use client\";\nimport { jsx } from \"react/jsx-runtime\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-root.tsx\nfunction TRDialogRoot(props) {\n\treturn /* @__PURE__ */ jsx(Dialog.Root, { ...props });\n}\n//#endregion\nexport { TRDialogRoot };\n\n//# sourceMappingURL=dialog-root.js.map","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-title.tsx\nconst TRDialogTitle = createComponentPart(Dialog.Title, \"tr-dialog-title\");\n//#endregion\nexport { TRDialogTitle };\n\n//# sourceMappingURL=dialog-title.js.map","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-trigger.tsx\nconst TRDialogTrigger = createComponentPart(Dialog.Trigger, \"tr-dialog-trigger\");\n//#endregion\nexport { TRDialogTrigger };\n\n//# sourceMappingURL=dialog-trigger.js.map","\"use client\";\nimport { createComponentPart } from \"../../internal/component-part.js\";\nimport { Dialog } from \"@base-ui/react/dialog\";\n//#region src/components/dialog/dialog-viewport.tsx\nconst TRDialogViewport = createComponentPart(Dialog.Viewport, \"tr-layer-viewport tr-dialog-viewport\");\n//#endregion\nexport { TRDialogViewport };\n\n//# sourceMappingURL=dialog-viewport.js.map","import { TRDialogBackdrop } from \"./dialog-backdrop.js\";\nimport { TRDialogClose } from \"./dialog-close.js\";\nimport { TRDialogDescription } from \"./dialog-description.js\";\nimport { createDialogHandle } from \"./dialog-handle.js\";\nimport { TRDialogPopup } from \"./dialog-popup.js\";\nimport { TRDialogPortal } from \"./dialog-portal.js\";\nimport { TRDialogRoot } from \"./dialog-root.js\";\nimport { TRDialogTitle } from \"./dialog-title.js\";\nimport { TRDialogTrigger } from \"./dialog-trigger.js\";\nimport { TRDialogViewport } from \"./dialog-viewport.js\";\n//#region src/components/dialog/index.tsx\nconst TRDialog = {\n\tBackdrop: TRDialogBackdrop,\n\tClose: TRDialogClose,\n\tDescription: TRDialogDescription,\n\tPopup: TRDialogPopup,\n\tPortal: TRDialogPortal,\n\tRoot: TRDialogRoot,\n\tViewport: TRDialogViewport,\n\tTitle: TRDialogTitle,\n\tTrigger: TRDialogTrigger,\n\tcreateHandle: createDialogHandle\n};\n//#endregion\nexport { TRDialog, TRDialogBackdrop, TRDialogClose, TRDialogDescription, TRDialogPopup, TRDialogPortal, TRDialogRoot, TRDialogTitle, TRDialogTrigger, TRDialogViewport, createDialogHandle };\n\n//# sourceMappingURL=index.js.map","import { TRDialog } from '@tinyrack/ui/components/dialog';\nimport type { LucideIcon } from 'lucide-react';\nimport { XIcon } from 'lucide-react';\nimport { type ReactNode, useEffect } from 'react';\n\ntype ModalVariant = 'default' | 'destructive';\n\ninterface ModalProps {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n description?: string;\n children: ReactNode;\n size?: 'sm' | 'md' | 'lg';\n preventClose?: boolean;\n icon?: LucideIcon;\n variant?: ModalVariant;\n}\n\n/*\n Set through `--tr-dialog-box-max-width`, the override hook `.tr-dialog-box`\n exposes, rather than a `max-w-*` utility. The box feeds that same custom\n property into its own `width: min(…)` calculation, so a utility would move\n the max-width while leaving the width computation on the old value.\n\n This is the current design system overlay scale (20/32rem), not Tailwind's\n width scale. The local `lg` compatibility option now resolves to the largest\n supported overlay token, and `md` remains the unstyled `TRDialog` default.\n*/\nconst sizeClasses = {\n sm: '[--tr-dialog-box-max-width:var(--tinyrack-overlay-width-sm)]',\n md: '[--tr-dialog-box-max-width:var(--tinyrack-overlay-width-md)]',\n lg: '[--tr-dialog-box-max-width:var(--tinyrack-overlay-width-md)]',\n} as const;\n\nconst iconVariantClasses: Record<ModalVariant, string> = {\n default: 'bg-tinyrack-surface-muted text-tinyrack-text',\n destructive: 'bg-tinyrack-danger-surface text-tinyrack-danger-foreground',\n};\n\nexport function Modal({\n isOpen,\n onClose,\n title,\n description,\n children,\n size = 'md',\n preventClose = false,\n icon: IconComponent,\n variant = 'default',\n}: ModalProps) {\n useEffect(() => {\n if (!isOpen) return;\n if (preventClose) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, preventClose, onClose]);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <TRDialog.Root\n defaultOpen\n disablePointerDismissal={preventClose}\n onOpenChange={(open) => {\n if (!open && !preventClose) {\n onClose();\n }\n }}\n >\n <TRDialog.Portal>\n <TRDialog.Viewport>\n <TRDialog.Backdrop />\n {/*\n No max-height here: `.tr-dialog-box` already clamps itself against\n `100dvh` minus the viewport gap, which is more correct than the\n `90vh`/`85vh` this used to override it with.\n */}\n <TRDialog.Popup className={sizeClasses[size]}>\n <div className=\"flex items-start gap-tinyrack-md\">\n {IconComponent && (\n <div\n className={`flex size-tinyrack-2xl shrink-0 items-center justify-center rounded-tinyrack-full ${iconVariantClasses[variant]}`}\n >\n <IconComponent aria-hidden className=\"size-tinyrack-lg\" />\n </div>\n )}\n <div className=\"flex min-w-0 flex-1 flex-col gap-tinyrack-3xs\">\n <TRDialog.Title>{title}</TRDialog.Title>\n {description && (\n <TRDialog.Description className=\"text-tinyrack-text-muted text-tinyrack-xs\">\n {description}\n </TRDialog.Description>\n )}\n </div>\n {!preventClose && (\n <TRDialog.Close\n aria-label=\"Close\"\n className=\"shrink-0\"\n data-testid=\"modal-close\"\n >\n <XIcon aria-hidden className=\"size-tinyrack-lg\" />\n </TRDialog.Close>\n )}\n </div>\n {children}\n </TRDialog.Popup>\n </TRDialog.Viewport>\n </TRDialog.Portal>\n </TRDialog.Root>\n );\n}\n\ninterface ModalActionsProps {\n children: ReactNode;\n}\n\nexport function ModalActions({ children }: ModalActionsProps) {\n return (\n <div className=\"flex justify-end gap-tinyrack-sm pt-tinyrack-lg\">\n {children}\n </div>\n );\n}\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"mappings":"4VAaa,EAA8B,EAAM,WAAW,SAAwB,EAAgB,EAAc,CAChH,GAAM,CACJ,SACA,YACA,QACA,cAAc,GACd,GAAG,GACD,EACE,EAAQ,EAAqB,EAC7B,EAAO,EAAM,SAAS,MAAM,EAC5B,EAAS,EAAM,SAAS,QAAQ,EAChC,EAAU,EAAM,SAAS,SAAS,EAMxC,OAAO,EAAiB,MAAO,EAAgB,CAC7C,MAAA,CAJA,OACA,iBAHuB,EAAM,SAAS,kBAGvB,CAGX,EACJ,IAAK,CAAC,EAAM,QAAQ,YAAa,CAAY,EAC7C,uBAAwB,EACxB,MAAO,CAAC,CACN,KAAM,eACN,OAAQ,CAAC,EACT,MAAO,CACL,WAAY,OACZ,iBAAkB,MACpB,CACF,EAAG,CAAY,EACf,QAAS,GAAe,CAAC,CAC3B,CAAC,CACH,CAAC,QCzBY,EAA2B,EAAM,WAAW,SAAqB,EAAgB,EAAc,CAC1G,GAAM,CACJ,SACA,YACA,QACA,aACA,eACA,GAAG,GACD,EACE,EAAQ,EAAqB,EAC7B,EAAuB,EAAM,SAAS,sBAAsB,EAC5D,EAA0B,EAAM,SAAS,yBAAyB,EAClE,EAAsB,EAAM,SAAS,qBAAqB,EAC1D,EAAiB,EAAM,SAAS,YAAY,EAC5C,EAAQ,EAAM,SAAS,OAAO,EAC9B,EAAU,EAAM,SAAS,SAAS,EAClC,EAAS,EAAM,SAAS,QAAQ,EAChC,EAAwB,EAAM,SAAS,uBAAuB,EAC9D,EAAO,EAAM,SAAS,MAAM,EAC5B,EAAa,EAAM,SAAS,YAAY,EACxC,EAAiB,EAAM,SAAS,gBAAgB,EAChD,EAAmB,EAAM,SAAS,kBAAkB,EACpD,EAAO,EAAM,SAAS,MAAM,EAC5B,EAAa,EAAoB,SAAS,YAAY,EAC5D,EAAuB,EACvB,EAAsB,CACpB,OACA,IAAK,EAAM,QAAQ,SACnB,YAAa,CACP,GACF,EAAM,QAAQ,uBAAuB,EAAI,CAE7C,CACF,CAAC,EACD,IAAM,EAAuB,IAAiB,IAAA,GAAY,EAA0B,EAAM,QAAQ,QAAQ,EAAI,EACxG,EAAmB,EAAwB,EAC3C,EAAkB,EAAM,eAAe,cAAc,EAOrD,EAAU,EAAiB,MAAO,EAAgB,CACtD,MAAA,CANA,OACA,SACA,mBACA,kBAGI,EACJ,MAAO,CAAC,EAAgB,CACtB,GAAI,EACJ,kBAAmB,EACnB,mBAAoB,EACpB,OACA,GAAG,EACH,OAAQ,CAAC,EACT,UAAU,EAAO,CACX,EAAe,IAAI,EAAM,GAAG,GAC9B,EAAM,gBAAgB,CAE1B,EACA,MAAO,CACL,mBAAoB,CACtB,CACF,EAAG,CAAY,EACf,IAAK,CAAC,EAAc,EAAM,QAAQ,SAAU,CAAe,EAC3D,uBAAwB,CAC1B,CAAC,EACD,OAAoB,EAAA,EAAA,IAAA,CAAK,EAAsB,CAC7C,QAAS,EACT,oBAAqB,EACrB,SAAU,CAAC,EACX,gBAAiB,CAAC,EAClB,aAAc,EACd,YAAa,EACb,MAAO,IAAU,GACjB,aAAc,QACd,SAAU,CACZ,CAAC,CACH,CAAC,ECpFD,SAAgB,EAAW,EAAO,CAChC,OAAO,EAAoB,SAAU,CAAK,CAC5C,CCRA,IAAM,EAAmB,EAAoBA,EAAiB,sCAAsC,ECA9F,EAAgB,EAAoBC,EAAc,iBAAiB,ECAnE,EAAsB,EAAoBC,EAAoB,uBAAuB,ECD3F,SAAS,GAAqB,CAC7B,OAAOC,EAAoB,CAC5B,CCAA,SAAS,EAAc,CAAE,YAAW,YAAY,SAAU,GAAG,GAAS,CACrE,OAAuB,EAAA,EAAA,IAAA,CAAIC,EAAc,CACxC,GAAG,EACH,UAAW,EAAwB,0BAA2B,CAAS,EACvE,iBAAkB,CACnB,CAAC,CACF,CCPA,IAAM,EAAiB,EAAoBC,CAAa,ECAxD,SAAS,EAAa,EAAO,CAC5B,OAAuB,EAAA,EAAA,IAAA,CAAIC,EAAa,CAAE,GAAG,CAAM,CAAC,CACrD,CCFA,IAAM,EAAgB,EAAoBC,EAAc,iBAAiB,ECAnE,EAAkB,EAAoBC,EAAgB,mBAAmB,EEOzE,EAAW,CAChB,SAAU,EACV,MAAO,EACP,YAAa,EACb,MAAO,EACP,OAAQ,EACR,KAAM,EACN,SDdwB,EAAoBC,EAAiB,sCCcnD,EACV,MAAO,EACP,QAAS,EACT,aAAc,CACf,ECOM,EAAc,CAClB,GAAI,+DACJ,GAAI,+DACJ,GAAI,8DACN,EAEM,EAAmD,CACvD,QAAS,+CACT,YAAa,4DACf,EAEA,SAAgB,EAAM,CACpB,SACA,UACA,QACA,cACA,WACA,OAAO,KACP,eAAe,GACf,KAAM,EACN,UAAU,WACG,CAiBb,OAhBA,EAAA,EAAA,UAAA,KAAgB,CAEd,GADI,CAAC,GACD,EAAc,OAClB,IAAM,EAAiB,GAAqB,CACtC,EAAE,MAAQ,UACZ,EAAQ,CAEZ,EAEA,OADA,SAAS,iBAAiB,UAAW,CAAa,MACrC,SAAS,oBAAoB,UAAW,CAAa,CACpE,EAAG,CAAC,EAAQ,EAAc,CAAO,CAAC,EAE7B,GAKH,EAAA,EAAA,IAAA,CAAC,EAAS,KAAV,CACE,YAAA,GACA,wBAAyB,EACzB,aAAe,GAAS,CAClB,CAAC,GAAQ,CAAC,GACZ,EAAQ,CAEZ,YAEA,EAAA,EAAA,IAAA,CAAC,EAAS,OAAV,CAAA,UACE,EAAA,EAAA,KAAA,CAAC,EAAS,SAAV,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAS,SAAV,CAAoB,CAAA,GAMpB,EAAA,EAAA,KAAA,CAAC,EAAS,MAAV,CAAgB,UAAW,EAAY,YAAvC,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,4CAAf,CACG,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAW,qFAAqF,EAAmB,eAEnH,EAAA,EAAA,IAAA,CAAC,EAAD,CAAe,cAAA,GAAY,UAAU,kBAAoB,CAAA,CACtD,CAAA,GAEP,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,yDAAf,EACE,EAAA,EAAA,IAAA,CAAC,EAAS,MAAV,CAAA,SAAiB,CAAsB,CAAA,EACtC,IACC,EAAA,EAAA,IAAA,CAAC,EAAS,YAAV,CAAsB,UAAU,qDAC7B,CACmB,CAAA,CAErB,IACJ,CAAC,IACA,EAAA,EAAA,IAAA,CAAC,EAAS,MAAV,CACE,aAAW,QACX,UAAU,WACV,cAAY,wBAEZ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAO,cAAA,GAAY,UAAU,kBAAoB,CAAA,CACnC,CAAA,CAEf,IACJ,CACa,GACC,CAAA,CAAA,CACJ,CAAA,CACJ,CAAA,EApDR,IAsDX,CAMA,SAAgB,EAAa,CAAE,YAA+B,CAC5D,OACE,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAU,kDACZ,UACE,CAAA,CAET"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{Er as e,Or as t,Tr as n}from"./config-DTQCUlfZ.js";var r=class extends n{#e;#t;#n;#r;constructor(e){super(),this.#e=e.client,this.mutationId=e.mutationId,this.#n=e.mutationCache,this.#t=[],this.state=e.state||i(),this.setOptions(e.options),this.scheduleGc()}setOptions(e){this.options=e,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(e){this.#t.includes(e)||(this.#t.push(e),this.clearGcTimeout(),this.#n.notify({type:`observerAdded`,mutation:this,observer:e}))}removeObserver(e){this.#t=this.#t.filter(t=>t!==e),this.scheduleGc(),this.#n.notify({type:`observerRemoved`,mutation:this,observer:e})}optionalRemove(){this.#t.length||(this.state.status===`pending`?this.scheduleGc():this.#n.remove(this))}continue(){return this.#r?.continue()??this.execute(this.state.variables)}async execute(t){let n=()=>{this.#i({type:`continue`})},r={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};this.#r=e({fn:()=>this.options.mutationFn?this.options.mutationFn(t,r):Promise.reject(Error(`No mutationFn found`)),onFail:(e,t)=>{this.#i({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#i({type:`pause`})},onContinue:n,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>this.#n.canRun(this)});let i=this.state.status===`pending`,a=!this.#r.canStart();try{if(i)n();else{this.#i({type:`pending`,variables:t,isPaused:a}),this.#n.config.onMutate&&await this.#n.config.onMutate(t,this,r);let e=await this.options.onMutate?.(t,r);e!==this.state.context&&this.#i({type:`pending`,context:e,variables:t,isPaused:a})}let e=await this.#r.start();return await this.#n.config.onSuccess?.(e,t,this.state.context,this,r),await this.options.onSuccess?.(e,t,this.state.context,r),await this.#n.config.onSettled?.(e,null,this.state.variables,this.state.context,this,r),await this.options.onSettled?.(e,null,t,this.state.context,r),this.#i({type:`success`,data:e}),e}catch(e){try{await this.#n.config.onError?.(e,t,this.state.context,this,r)}catch(e){Promise.reject(e)}try{await this.options.onError?.(e,t,this.state.context,r)}catch(e){Promise.reject(e)}try{await this.#n.config.onSettled?.(void 0,e,this.state.variables,this.state.context,this,r)}catch(e){Promise.reject(e)}try{await this.options.onSettled?.(void 0,e,t,this.state.context,r)}catch(e){Promise.reject(e)}throw this.#i({type:`error`,error:e}),e}finally{this.#n.runNext(this)}}#i(e){let n=t=>{switch(e.type){case`failed`:return{...t,failureCount:e.failureCount,failureReason:e.error};case`pause`:return{...t,isPaused:!0};case`continue`:return{...t,isPaused:!1};case`pending`:return{...t,context:e.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:e.isPaused,status:`pending`,variables:e.variables,submittedAt:Date.now()};case`success`:return{...t,data:e.data,failureCount:0,failureReason:null,error:null,status:`success`,isPaused:!1};case`error`:return{...t,data:void 0,error:e.error,failureCount:t.failureCount+1,failureReason:e.error,isPaused:!1,status:`error`}}};this.state=n(this.state),t.batch(()=>{this.#t.forEach(t=>{t.onMutationUpdate(e)}),this.#n.notify({mutation:this,type:`updated`,action:e})})}};function i(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:`idle`,variables:void 0,submittedAt:0}}function a(e){return e}export{r as n,i as r,a as t};
|
|
2
|
-
//# sourceMappingURL=mutationOptions-DyYFUbyn.js.map
|
|
@@ -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{nt as f}from"./shell-header-bar-JcFhS7mb.js";import{t as p}from"./auth-field-CWyXGKoC.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-CKpnrw9M.js";import{t as T}from"./auth-page-header-DgGAaIiP.js";import{t as E}from"./alert-leqyvHOp.js";import{t as D}from"./auth-layout-CiNn2-Nb.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-foreground`}),(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-CgAHaQ1p.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"passkey-CgAHaQ1p.js","names":["standardSchemaResolver","useMutation","useQueryClient","useSuspenseQuery","Link","useRouter","TRButton","TRLinkButton","TRText","CircleAlertIcon","FingerprintIcon","ShieldCheckIcon","TagIcon","useEffect","useMemo","useRef","useState","useForm","useTranslation","z","AuthField","AuthFooter","AuthFooterLink","AuthPageHeader","Alert","AuthLayout","buildAuthenticatedAuthorizeUrl","extractOAuthParams","isOAuthFlow","classifyPasskeyError","tick","appConfigQueryOptions","registerPasskeyMutationOptions","getSessionQueryOptions","Route","SetupStep","SetupPasskey","t","router","queryClient","search","useSearch","data","appConfig","step","setStep","passkey_name","errorMessage","setErrorMessage","autoRegisterCalledRef","canUseTotpSetup","auth","password","enabled","two_factor","enrollment_required","totp","formSchema","object","name","string","max","FormValues","infer","register","handleSubmit","formState","errors","defaultValues","resolver","registerMutation","onSuccess","second_factor_setup_completed","user","setQueryData","queryKey","window","location","href","navigate","to","invalidateQueries","onError","error","reason","onSettled","current","mutate","onSubmit","values","undefined","isPending","component"],"sources":["../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/tag.mjs","../../../frontend/src/routes/setup/passkey/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 [\n \"path\",\n {\n 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\",\n key: \"vktsd0\"\n }\n ],\n [\"circle\", { cx: \"7.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\", key: \"kqv944\" }]\n];\nconst Tag = createLucideIcon(\"tag\", __iconNode);\n\nexport { __iconNode, Tag as default };\n//# sourceMappingURL=tag.mjs.map\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 { TRLinkButton } from '@tinyrack/ui/components/link-button';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport {\n CircleAlertIcon,\n FingerprintIcon,\n ShieldCheckIcon,\n TagIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useRef, 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 { AuthPageHeader } from '#frontend/components/auth/auth-page-header.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 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 { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { registerPasskeyMutationOptions } from '#frontend/queries/passkey.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema.extend({\n passkey_name: z.string().optional(),\n});\n\nexport const Route = createFileRoute('/setup/passkey/')({\n component: SetupPasskey,\n errorComponent: RouteErrorFallback,\n loader: async ({ context }) => {\n await context.queryClient.ensureQueryData(appConfigQueryOptions);\n },\n validateSearch: SearchSchema,\n});\n\ntype SetupStep = 'form' | 'registering' | 'error';\n\nfunction SetupPasskey() {\n const { t } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n const { data: appConfig } = useSuspenseQuery(appConfigQueryOptions);\n\n const [step, setStep] = useState<SetupStep>(\n search.passkey_name ? 'registering' : 'form',\n );\n const [errorMessage, setErrorMessage] = useState<string>('');\n const autoRegisterCalledRef = useRef(false);\n const canUseTotpSetup =\n appConfig.auth.password.enabled &&\n appConfig.auth.password.two_factor.enrollment_required &&\n appConfig.auth.password.totp.enabled;\n\n const formSchema = useMemo(\n () =>\n z.object({\n name: z.string().max(100, t('validation.passkey.name.max')),\n }),\n [t],\n );\n\n type FormValues = z.infer<typeof formSchema>;\n\n const {\n register,\n handleSubmit,\n formState: { errors },\n } = useForm<FormValues>({\n defaultValues: { name: '' },\n resolver: standardSchemaResolver(formSchema),\n });\n\n const registerMutation = useMutation({\n ...registerPasskeyMutationOptions,\n onSuccess: async (data) => {\n if (data.second_factor_setup_completed && data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: data.user,\n });\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href = buildAuthenticatedAuthorizeUrl(search);\n } else {\n router.navigate({ to: '/profile' });\n }\n } else {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n router.navigate({ to: '/profile' });\n }\n },\n onError: (error) => {\n setStep('error');\n const reason = classifyPasskeyError(error);\n\n switch (reason) {\n case 'unsupported':\n setErrorMessage(t('setupPasskey.error.unsupported'));\n return;\n case 'not_allowed':\n setErrorMessage(t('setupPasskey.error.notAllowed'));\n return;\n case 'expired':\n setErrorMessage(t('setupPasskey.error.expired'));\n return;\n case 'user_mismatch':\n case 'verification_failed':\n setErrorMessage(t('setupPasskey.error.failed'));\n return;\n }\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n useEffect(() => {\n if (search.passkey_name && !autoRegisterCalledRef.current) {\n autoRegisterCalledRef.current = true;\n registerMutation.mutate({ name: search.passkey_name });\n }\n }, [registerMutation, search.passkey_name]);\n\n const onSubmit = (values: FormValues) => {\n setStep('registering');\n setErrorMessage('');\n registerMutation.mutate({ name: values.name || undefined });\n };\n\n // Registering state - waiting for WebAuthn\n if (step === 'registering') {\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('setupPasskey.subtitle')}\n title={t('setupPasskey.title')}\n />\n <div className=\"flex flex-col items-center gap-tinyrack-lg py-tinyrack-xl\">\n <FingerprintIcon\n aria-hidden\n className=\"size-tinyrack-3xl animate-pulse text-tinyrack-primary-foreground\"\n />\n <TRText align=\"center\" as=\"p\" color=\"muted\" variant=\"body\">\n {t('setupPasskey.waiting')}\n </TRText>\n </div>\n </AuthLayout>\n );\n }\n\n // Error state\n if (step === 'error') {\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('setupPasskey.subtitle')}\n title={t('setupPasskey.title')}\n />\n <Alert icon={CircleAlertIcon} type=\"error\">\n {errorMessage}\n </Alert>\n\n <div className=\"flex flex-col gap-tinyrack-sm\">\n {canUseTotpSetup && (\n <TRLinkButton\n className=\"w-full gap-tinyrack-sm\"\n intent=\"primary\"\n render={\n <Link search={extractOAuthParams(search)} to=\"/setup/totp\" />\n }\n uiSize=\"lg\"\n >\n <ShieldCheckIcon aria-hidden className=\"size-tinyrack-xl\" />\n {t('setupPasskey.useTotp')}\n </TRLinkButton>\n )}\n <TRButton\n appearance={canUseTotpSetup ? 'outline' : 'solid'}\n className=\"w-full\"\n intent={canUseTotpSetup ? 'neutral' : 'primary'}\n onClick={() => {\n if (search.passkey_name) {\n setStep('registering');\n setErrorMessage('');\n registerMutation.mutate({ name: search.passkey_name });\n } else {\n setStep('form');\n }\n }}\n type=\"button\"\n uiSize=\"lg\"\n >\n {t('setupPasskey.retry')}\n </TRButton>\n </div>\n\n <AuthFooter>\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/login\">\n {t('setupPasskey.backToLogin')}\n </Link>\n }\n />\n </AuthFooter>\n </AuthLayout>\n );\n }\n\n // Form state\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('setupPasskey.subtitle')}\n title={t('setupPasskey.title')}\n />\n\n <Alert icon={ShieldCheckIcon} type=\"info\">\n {t('setupPasskey.required')}\n </Alert>\n\n <TRText align=\"center\" as=\"p\" color=\"muted\" variant=\"bodySm\">\n {t('setupPasskey.description')}\n </TRText>\n\n <form\n className=\"flex flex-col gap-tinyrack-lg\"\n onSubmit={handleSubmit(onSubmit)}\n >\n <AuthField\n error={errors.name}\n hint={t('setupPasskey.name.hint')}\n icon={TagIcon}\n id=\"passkey-name\"\n label={t('setupPasskey.name.label')}\n placeholder={t('setupPasskey.name.placeholder')}\n {...register('name')}\n type=\"text\"\n />\n\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n loading={registerMutation.isPending}\n loadingLabel={t('setupPasskey.registering')}\n type=\"submit\"\n uiSize=\"lg\"\n >\n {t('setupPasskey.continue')}\n </TRButton>\n </form>\n\n <AuthFooter>\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/login\">\n {t('setupPasskey.backToLogin')}\n </Link>\n }\n />\n </AuthFooter>\n </AuthLayout>\n );\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"passkey-huNZDYU9.js","names":["RouteErrorFallback","SetupStep","SplitErrorComponent","errorComponent"],"sources":["../../../frontend/src/routes/setup/passkey/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 { TRLinkButton } from '@tinyrack/ui/components/link-button';\nimport { TRText } from '@tinyrack/ui/components/text';\nimport {\n CircleAlertIcon,\n FingerprintIcon,\n ShieldCheckIcon,\n TagIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useRef, 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 { AuthPageHeader } from '#frontend/components/auth/auth-page-header.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 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 { appConfigQueryOptions } from '#frontend/queries/config.ts';\nimport { registerPasskeyMutationOptions } from '#frontend/queries/passkey.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema.extend({\n passkey_name: z.string().optional(),\n});\n\nexport const Route = createFileRoute('/setup/passkey/')({\n component: SetupPasskey,\n errorComponent: RouteErrorFallback,\n loader: async ({ context }) => {\n await context.queryClient.ensureQueryData(appConfigQueryOptions);\n },\n validateSearch: SearchSchema,\n});\n\ntype SetupStep = 'form' | 'registering' | 'error';\n\nfunction SetupPasskey() {\n const { t } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n const { data: appConfig } = useSuspenseQuery(appConfigQueryOptions);\n\n const [step, setStep] = useState<SetupStep>(\n search.passkey_name ? 'registering' : 'form',\n );\n const [errorMessage, setErrorMessage] = useState<string>('');\n const autoRegisterCalledRef = useRef(false);\n const canUseTotpSetup =\n appConfig.auth.password.enabled &&\n appConfig.auth.password.two_factor.enrollment_required &&\n appConfig.auth.password.totp.enabled;\n\n const formSchema = useMemo(\n () =>\n z.object({\n name: z.string().max(100, t('validation.passkey.name.max')),\n }),\n [t],\n );\n\n type FormValues = z.infer<typeof formSchema>;\n\n const {\n register,\n handleSubmit,\n formState: { errors },\n } = useForm<FormValues>({\n defaultValues: { name: '' },\n resolver: standardSchemaResolver(formSchema),\n });\n\n const registerMutation = useMutation({\n ...registerPasskeyMutationOptions,\n onSuccess: async (data) => {\n if (data.second_factor_setup_completed && data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: data.user,\n });\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href = buildAuthenticatedAuthorizeUrl(search);\n } else {\n router.navigate({ to: '/profile' });\n }\n } else {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n router.navigate({ to: '/profile' });\n }\n },\n onError: (error) => {\n setStep('error');\n const reason = classifyPasskeyError(error);\n\n switch (reason) {\n case 'unsupported':\n setErrorMessage(t('setupPasskey.error.unsupported'));\n return;\n case 'not_allowed':\n setErrorMessage(t('setupPasskey.error.notAllowed'));\n return;\n case 'expired':\n setErrorMessage(t('setupPasskey.error.expired'));\n return;\n case 'user_mismatch':\n case 'verification_failed':\n setErrorMessage(t('setupPasskey.error.failed'));\n return;\n }\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n useEffect(() => {\n if (search.passkey_name && !autoRegisterCalledRef.current) {\n autoRegisterCalledRef.current = true;\n registerMutation.mutate({ name: search.passkey_name });\n }\n }, [registerMutation, search.passkey_name]);\n\n const onSubmit = (values: FormValues) => {\n setStep('registering');\n setErrorMessage('');\n registerMutation.mutate({ name: values.name || undefined });\n };\n\n // Registering state - waiting for WebAuthn\n if (step === 'registering') {\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('setupPasskey.subtitle')}\n title={t('setupPasskey.title')}\n />\n <div className=\"flex flex-col items-center gap-tinyrack-lg py-tinyrack-xl\">\n <FingerprintIcon\n aria-hidden\n className=\"size-tinyrack-3xl animate-pulse text-tinyrack-primary-foreground\"\n />\n <TRText align=\"center\" as=\"p\" color=\"muted\" variant=\"body\">\n {t('setupPasskey.waiting')}\n </TRText>\n </div>\n </AuthLayout>\n );\n }\n\n // Error state\n if (step === 'error') {\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('setupPasskey.subtitle')}\n title={t('setupPasskey.title')}\n />\n <Alert icon={CircleAlertIcon} type=\"error\">\n {errorMessage}\n </Alert>\n\n <div className=\"flex flex-col gap-tinyrack-sm\">\n {canUseTotpSetup && (\n <TRLinkButton\n className=\"w-full gap-tinyrack-sm\"\n intent=\"primary\"\n render={\n <Link search={extractOAuthParams(search)} to=\"/setup/totp\" />\n }\n uiSize=\"lg\"\n >\n <ShieldCheckIcon aria-hidden className=\"size-tinyrack-xl\" />\n {t('setupPasskey.useTotp')}\n </TRLinkButton>\n )}\n <TRButton\n appearance={canUseTotpSetup ? 'outline' : 'solid'}\n className=\"w-full\"\n intent={canUseTotpSetup ? 'neutral' : 'primary'}\n onClick={() => {\n if (search.passkey_name) {\n setStep('registering');\n setErrorMessage('');\n registerMutation.mutate({ name: search.passkey_name });\n } else {\n setStep('form');\n }\n }}\n type=\"button\"\n uiSize=\"lg\"\n >\n {t('setupPasskey.retry')}\n </TRButton>\n </div>\n\n <AuthFooter>\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/login\">\n {t('setupPasskey.backToLogin')}\n </Link>\n }\n />\n </AuthFooter>\n </AuthLayout>\n );\n }\n\n // Form state\n return (\n <AuthLayout>\n <AuthPageHeader\n subtitle={t('setupPasskey.subtitle')}\n title={t('setupPasskey.title')}\n />\n\n <Alert icon={ShieldCheckIcon} type=\"info\">\n {t('setupPasskey.required')}\n </Alert>\n\n <TRText align=\"center\" as=\"p\" color=\"muted\" variant=\"bodySm\">\n {t('setupPasskey.description')}\n </TRText>\n\n <form\n className=\"flex flex-col gap-tinyrack-lg\"\n onSubmit={handleSubmit(onSubmit)}\n >\n <AuthField\n error={errors.name}\n hint={t('setupPasskey.name.hint')}\n icon={TagIcon}\n id=\"passkey-name\"\n label={t('setupPasskey.name.label')}\n placeholder={t('setupPasskey.name.placeholder')}\n {...register('name')}\n type=\"text\"\n />\n\n <TRButton\n className=\"w-full\"\n intent=\"primary\"\n loading={registerMutation.isPending}\n loadingLabel={t('setupPasskey.registering')}\n type=\"submit\"\n uiSize=\"lg\"\n >\n {t('setupPasskey.continue')}\n </TRButton>\n </form>\n\n <AuthFooter>\n <AuthFooterLink\n link={\n <Link search={extractOAuthParams(search)} to=\"/login\">\n {t('setupPasskey.backToLogin')}\n </Link>\n }\n />\n </AuthFooter>\n </AuthLayout>\n );\n}\n"],"mappings":"wCAsDkD,IAAAE,EA3BzCF"}
|
|
@@ -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-Ccv_nzQl.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-CKpnrw9M.js";import{t as C}from"./auth-page-header-DgGAaIiP.js";import{t as w}from"./alert-leqyvHOp.js";import{t as T}from"./auth-layout-CiNn2-Nb.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-v9Pzv-4A.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"passkey-v9Pzv-4A.js","names":["useMutation","useQuery","useQueryClient","Link","useRouter","TRButton","TRLinkButton","TRSpinner","CircleAlertIcon","FingerprintIcon","useEffect","useRef","useState","useTranslation","AuthFooter","AuthFooterLink","AuthPageHeader","Alert","AuthLayout","buildAuthenticatedAuthorizeUrl","extractOAuthParams","isOAuthFlow","classifyPasskeyError","tick","authenticateWithPasskeyMutationOptions","getPendingSecondFactorMethodsQueryOptions","getSessionQueryOptions","Route","VerifyPasskey","t","router","queryClient","search","useSearch","error","setError","message","reason","PasskeyErrorReason","hasStarted","pendingMethodsQuery","enabled","canUseTotp","data","methods","includes","getErrorMessage","verifyMutation","onSuccess","user","setQueryData","queryKey","window","location","href","navigate","to","onError","err","onSettled","invalidateQueries","current","mutate","isPending","component"],"sources":["../../../frontend/src/queries/second-factor.ts","../../../frontend/src/routes/verify/passkey/index.tsx?tsr-split=component"],"sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport type { InferResponseType } from 'hono/client';\nimport { client, jsonOk } from '#frontend/libs/api.ts';\nimport { queryKeys } from './keys';\n\nexport type PendingSecondFactorMethodsResponse = InferResponseType<\n (typeof client.api.auth)['2fa']['methods']['$get'],\n 200\n>;\n\nexport const getPendingSecondFactorMethodsQueryOptions = queryOptions({\n queryKey: queryKeys.pendingSecondFactorMethods(),\n queryFn: async () => {\n const res = await client.api.auth['2fa'].methods.$get();\n return jsonOk(res);\n },\n retry: false,\n});\n","import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { createFileRoute, Link, useRouter } from '@tanstack/react-router';\nimport { TRButton } from '@tinyrack/ui/components/button';\nimport { TRLinkButton } from '@tinyrack/ui/components/link-button';\nimport { TRSpinner } from '@tinyrack/ui/components/spinner';\nimport { CircleAlertIcon, FingerprintIcon } from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n AuthFooter,\n AuthFooterLink,\n} from '#frontend/components/auth/auth-footer.tsx';\nimport { AuthPageHeader } from '#frontend/components/auth/auth-page-header.tsx';\nimport { Alert } from '#frontend/components/ui/alert.tsx';\nimport { AuthLayout } from '#frontend/features/layout/auth-layout.tsx';\nimport {\n buildAuthenticatedAuthorizeUrl,\n extractOAuthParams,\n isOAuthFlow,\n OAuthSearchSchema,\n} from '#frontend/libs/oauth-search.ts';\nimport {\n classifyPasskeyError,\n type PasskeyErrorReason,\n} from '#frontend/libs/passkey-error.ts';\nimport { tick } from '#frontend/libs/promise.ts';\nimport { authenticateWithPasskeyMutationOptions } from '#frontend/queries/passkey.ts';\nimport { getPendingSecondFactorMethodsQueryOptions } from '#frontend/queries/second-factor.ts';\nimport { getSessionQueryOptions } from '#frontend/queries/session.ts';\n\nconst SearchSchema = OAuthSearchSchema;\n\nexport const Route = createFileRoute('/verify/passkey/')({\n component: VerifyPasskey,\n validateSearch: SearchSchema,\n});\n\nfunction VerifyPasskey() {\n const { t } = useTranslation();\n const router = useRouter();\n const queryClient = useQueryClient();\n const search = Route.useSearch();\n const [error, setError] = useState<{\n message: string;\n reason: PasskeyErrorReason;\n } | null>(null);\n const hasStarted = useRef(false);\n const pendingMethodsQuery = useQuery({\n ...getPendingSecondFactorMethodsQueryOptions,\n enabled: error !== null,\n });\n const canUseTotp =\n pendingMethodsQuery.data?.methods.includes('totp') ?? false;\n\n const getErrorMessage = (reason: PasskeyErrorReason) => {\n switch (reason) {\n case 'unsupported':\n return t('verifyPasskey.error.unsupported');\n case 'not_allowed':\n return t('verifyPasskey.error.notAllowed');\n case 'expired':\n return t('verifyPasskey.error.expired');\n case 'user_mismatch':\n return t('verifyPasskey.error.userMismatch');\n case 'verification_failed':\n return t('verifyPasskey.error.failed');\n }\n };\n\n const verifyMutation = useMutation({\n ...authenticateWithPasskeyMutationOptions,\n onSuccess: async (data) => {\n if (data.user) {\n queryClient.setQueryData(getSessionQueryOptions.queryKey, {\n user: data.user,\n });\n await tick();\n\n if (isOAuthFlow(search)) {\n window.location.href = buildAuthenticatedAuthorizeUrl(search);\n } else {\n router.navigate({ to: '/profile' });\n }\n }\n },\n onError: async (err) => {\n const reason = classifyPasskeyError(err);\n setError({\n message: getErrorMessage(reason),\n reason,\n });\n },\n onSettled: () => {\n queryClient.invalidateQueries({\n queryKey: getSessionQueryOptions.queryKey,\n });\n },\n });\n\n // Auto-start passkey authentication on mount (with guard for StrictMode)\n useEffect(() => {\n if (hasStarted.current) return;\n hasStarted.current = true;\n verifyMutation.mutate();\n }, [verifyMutation]);\n\n return (\n <AuthLayout>\n {/*\n Centred: this screen has no form to scan, only a device prompt to wait\n on, so the eye has nothing to follow down a left edge.\n */}\n <AuthPageHeader\n align=\"center\"\n subtitle={t('verifyPasskey.subtitle')}\n title={t('verifyPasskey.title')}\n />\n\n <div className=\"flex flex-col items-center gap-tinyrack-lg\">\n <div className=\"flex size-tinyrack-3xl items-center justify-center rounded-tinyrack-full bg-tinyrack-surface-muted\">\n <FingerprintIcon\n aria-hidden\n className=\"size-tinyrack-2xl text-tinyrack-text-muted\"\n />\n </div>\n\n {verifyMutation.isPending && (\n <div className=\"flex flex-col items-center gap-tinyrack-sm\">\n <TRSpinner uiSize=\"md\" />\n <p className=\"text-center text-tinyrack-sm text-tinyrack-text-muted\">\n {t('verifyPasskey.waiting')}\n </p>\n </div>\n )}\n\n {error && (\n <div className=\"flex w-full flex-col items-center gap-tinyrack-md\">\n <Alert className=\"w-full\" icon={CircleAlertIcon} type=\"error\">\n {error.message}\n </Alert>\n {canUseTotp && (\n <TRLinkButton\n className=\"w-full\"\n intent=\"primary\"\n render={\n <Link search={extractOAuthParams(search)} to=\"/verify/totp\" />\n }\n uiSize=\"lg\"\n >\n {t('verifyPasskey.useTotp')}\n </TRLinkButton>\n )}\n <TRButton\n appearance={canUseTotp ? 'outline' : 'solid'}\n className=\"w-full\"\n intent={canUseTotp ? 'neutral' : 'primary'}\n onClick={() => {\n setError(null);\n verifyMutation.mutate();\n }}\n type=\"button\"\n uiSize=\"lg\"\n >\n {t('verifyPasskey.retry')}\n </TRButton>\n </div>\n )}\n </div>\n\n <AuthFooter>\n <AuthFooterLink\n link={\n <Link search={search} to=\"/login\">\n {t('verifyPasskey.backToLogin')}\n </Link>\n }\n />\n </AuthFooter>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{J as e,Z as t,i as n,q as r,s as i}from"./createLucideIcon-BPpAIXR_.js";import{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{nt as p}from"./shell-header-bar-JcFhS7mb.js";import{t as m}from"./auth-field-CWyXGKoC.js";import{t as h}from"./authorization-context-banner-DznMDPOX.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-CKpnrw9M.js";import{t as E}from"./auth-page-header-DgGAaIiP.js";import{t as D}from"./auth-layout-CiNn2-Nb.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-Cuh9Hnjp.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"password-Cuh9Hnjp.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":"27BAaA,EAAA,EAAA,CAAA,WAAA,KAAA,6CAME,CAAA,QC0CF,SAASgC,GAAgB,CACvB,GAAM,CAAEC,IAAGC,QAASnB,EAAe,EAC7BoB,EAAS9B,EAAU,EACnB+B,EAAclC,EAAe,EAC7BmC,EAASN,EAAMO,UAAU,EACzBC,EACJF,EAAOI,yBACPJ,EAAOK,QAAQC,MAAM,GAAG,CAAC,CAACC,SAAS,OAAO,EACtC,CAAE,GAAGP,EAAQQ,iBAAkB,CAAE,EACjCR,EACAS,EAAOT,EAAOS,MAAQZ,EAAKa,SAE3B,CAAEC,KAAMC,GAAe9C,EAAiBwB,CAAqB,EAE7DuB,EACJD,EAAWE,aAAaC,gBAAgBN,IACxCG,EAAWE,aAAaC,gBAAgBH,EAAWf,KAAKmB,mBACpDC,EAAwBL,EAAWM,KAAKC,SAASC,QACjDC,EAAmBT,EAAWM,KAAKI,QAAQF,QAC3CG,EACJX,EAAWY,mBAAmBC,QAC3BR,MACAI,KACH,EAEIK,GAAAA,EAAAA,EAAAA,QAAAA,KAEF/C,EAAS,CACPiD,MAAOjD,EACG,CAAC,CACRmD,IAAI,EAAGlC,EAAE,2BAA2B,CAAC,CAAC,CACtCmC,KAAKpD,EAAQiB,EAAE,0BAA0B,CAAC,CAAC,EAC9CuB,SAAUxC,EAAS,CAAC,CAACmD,IAAI,EAAGlC,EAAE,8BAA8B,CAAC,CAC/D,CAAC,EACH,CAACA,CAAC,CACJ,EAEMoC,EAAgBpE,EAAY,CAChC,GAAG2B,EACH0C,UAAW,MAAOtB,EAAMuB,IAAW,CACjC,IAAMC,EAAOxB,EAAKwB,KAElB,GAAIA,EAAKC,6BAA+B,CAACD,EAAKE,eAAgB,CAC5DvC,EAAOwC,SAAS,CACdC,GAAI,gBACJvC,OAAQ,CACN4B,MAAOM,EAAON,MACd,GAAGzC,EAAmBa,CAAM,CAC9B,CACF,CAAC,EACD,MACF,CAEAD,EAAYyC,aAAa/C,EAAuBgD,SAAU,CAClDN,MACR,CAAC,EACD,MAAM9C,EAAK,EAEX,IAAMqD,EAA+C,CAAA,EAQrD,GAPI9B,EAAWM,KAAKC,SAASyB,KAAKxB,SAAWe,EAAKU,iBAChDH,EAAuBI,KAAK,MAAM,EAEhClC,EAAWM,KAAKI,QAAQF,SAAWe,EAAKY,cAAgB,GAC1DL,EAAuBI,KAAK,SAAS,EAGnCX,EAAKa,wBAA0BN,EAAuBjB,SAAW,EACnE,IAAIb,EAAWqC,4BAA4BxB,OAAS,EAClD,OAAO3B,EAAOwC,SAAS,CACrBC,GAAI,aACJvC,OAAQb,EAAmBa,CAAM,CACnC,CAAC,EACI,GAAIY,EAAWqC,4BAA4BxB,SAAW,EAQzD,OAPab,EAAWqC,4BAA4B,KACvC,OACNnD,EAAOwC,SAAS,CACrBC,GAAI,cACJvC,OAAQb,EAAmBa,CAAM,CACnC,CAAC,EAEMF,EAAOwC,SAAS,CACrBC,GAAI,iBACJvC,OAAQ,CACN,GAAGb,EAAmBa,CAAM,EAC5BmD,aAAc,SAChB,CACF,CAAC,CAEL,CAGF,GAAIT,EAAuBjB,OAAS,EAClC,OAAO3B,EAAOwC,SAAS,CACrBC,GAAI,cACJvC,OAAQb,EAAmBa,CAAM,CACnC,CAAC,EACI,GAAI0C,EAAuBjB,SAAW,EAQzC,OAPaiB,EAAuB,KACvB,OACN5C,EAAOwC,SAAS,CACrBC,GAAI,eACJvC,OAAQb,EAAmBa,CAAM,CACnC,CAAC,EAEMF,EAAOwC,SAAS,CACrBC,GAAI,kBACJvC,OAAQb,EAAmBa,CAAM,CACnC,CAAC,EAGH,GAAIZ,EAAYY,CAAM,EACpBoD,OAAOC,SAASC,KACdpE,EAA+BgB,CAAe,OAEhD,OAAOJ,EAAOwC,SAAS,CAAEC,GAAI,UAAW,CAAC,CAG/C,EACAgB,QAAUC,GAAW,CACnBC,EAAS,QAAS,CAChBC,KAAM,SACNC,QAAS/D,EAAE,oBAAoB,CACjC,CAAC,CACH,EACAgE,cAAiB,CACf7D,EAAY8D,kBAAkB,CAC5BpB,SAAUhD,EAAuBgD,QACnC,CAAC,CACH,CACF,CAAC,EAEKqB,GAAAA,EAAAA,EAAAA,YAAAA,CACJ,KAAOnD,IAAuB,CACxBA,EAAKwB,OACPpC,EAAYyC,aAAa/C,EAAuBgD,SAAU9B,CAAI,EAC9D,MAAMtB,EAAK,EAEPD,EAAYY,CAAM,EACpBoD,OAAOC,SAASC,KACdpE,EAA+BgB,CAAe,EAEhDJ,EAAOwC,SAAS,CAAEC,GAAI,UAAW,CAAC,GAGtCxC,EAAY8D,kBAAkB,CAC5BpB,SAAUhD,EAAuBgD,QACnC,CAAC,CACH,EACA,CAAC1C,EAAaD,EAAQE,EAAQE,CAAe,CAC/C,EAGM8D,GAAAA,EAAAA,EAAAA,OAAAA,CAAoD,IAAI,GAE9D1F,EAAAA,EAAAA,UAAAA,KAAgB,CACV,MAAC+C,GAAoB,CAACJ,GAU1B,MANA+C,GAAmBE,QAAU,IAAID,gBACjCzE,EACEsE,EACAE,EAAmBE,QAAQC,MAC7B,MAEa,CACXH,EAAmBE,SAASE,MAAM,CACpC,CACF,EAAG,CAAC/C,EAAkBJ,EAAuB6C,CAAoB,CAAC,EAElE,GAAM,CACJO,WACAZ,WACAa,eACAC,UAAW,CAAEC,WACX/F,EAAQ,CACVgG,cAAe,CACb7C,MAAO,GACPT,SAAU,EACZ,EACAuD,SAAU/G,EAAuB+D,CAAW,CAC9C,CAAC,EAMD,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,EAEE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,SAAU9B,EAAE,6BAA6B,GAAKmF,IAAAA,GAC9C,MAAOnF,EAAE,aAAa,CAAE,CAAA,GAG1B,EAAA,EAAA,IAAA,CAAC,EAAD,CAAoCI,QAAO,CAAA,EAE1CiB,IACC,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAU,gCACV,SAAUqD,EAAaK,KAjBPC,IAAwC,CAC9D5C,EAAc8C,OAAOF,CAAM,CAC7B,CAeuC,WAFjC,EAIE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAa,oBACb,MAAOJ,EAAO5C,MACd,KAAMxD,EACN,MAAOwB,EAAE,mBAAmB,EAC5B,YAAaA,EAAE,yBAAyB,EACxC,GAAIyE,EAAS,OAAO,EACpB,KAAK,OAAO,CAAA,GAGd,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAa,mBACb,MAAOG,EAAOrD,SACd,KAAMhD,EACN,MAAOyB,EAAE,sBAAsB,EAM/B,YACEgB,EAAWgB,MAAMR,SACf,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAU,mBACV,QAAQ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,GAAG,kBAAkB,CAAA,WAElCxB,EAAE,2BAA2B,CACxB,CAAA,EACNmF,IAAAA,GAEN,YAAanF,EAAE,4BAA4B,EAC3C,GAAIyE,EAAS,UAAU,EACvB,KAAK,UAAU,CAAA,GAGjB,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAU,SACV,OAAO,UACP,QAASrC,EAAcgD,UACvB,aAAcpF,EAAE,kBAAkB,EAClC,KAAK,SACL,OAAO,cAENA,EAAE,cAAc,CACT,CAAA,CACN,IAGPiB,IACC,EAAA,EAAA,IAAA,CAAC,MAAD,CACE,UAAU,6FACV,wBAAyB,CAAEoE,OAAQpE,CAAe,CAAE,CAAA,GAItDD,EAAWE,aAAaoE,qBACxB3D,KACA,EAAA,EAAA,KAAA,CAAC,EAAD,CAAA,SAAA,CACGX,EAAWE,aAAaoE,sBACvB,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,OAAQ/F,EAAmBa,CAAM,EAAG,GAAG,qBAC1CJ,EAAE,qBAAqB,CACpB,CAAA,EAER,KAAMA,EAAE,wBAAwB,CAAE,CAAA,EAGrC2B,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,OAAQpC,EAAmBa,CAAM,EAAG,GAAG,kBAC1CJ,EAAE,8BAA8B,CAC7B,CAAA,CACP,CAAA,CAGK,CAAA,CAAA,CAEJ,CAAA,CAAA,CAEhB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"password-huNZDYU9.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{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{G as e,J as t,Z as n,c as r,i,n as a,q as o,v as s}from"./createLucideIcon-BPpAIXR_.js";import{bn as c,bt as l,st as u}from"./config-DTQCUlfZ.js";import{g as d}from"./shell-header-bar-JcFhS7mb.js";import{n as f,t as p}from"./valueToPercent-LgbY_prH.js";var m=n(t(),1),h=m.createContext(void 0);function g(){let e=m.useContext(h);if(e===void 0)throw Error(s(38));return e}var _=o(),v=m.forwardRef(function(e,t){let{format:n,getAriaValueText:i,locale:a,max:o=100,min:s=0,value:c,render:d,className:g,children:v,style:y,...b}=e,[x,S]=m.useState(),C=p(c,s,o),w=u(Number.isNaN(C)?0:C,0,100),T=u(Number.isNaN(c)?s:c,s,o),E=n?f(T,a,n):f(w/100,a,{style:`percent`}),D=E;i&&(D=i(E,c));let O={"aria-labelledby":x,"aria-valuemax":o,"aria-valuemin":s,"aria-valuenow":T,"aria-valuetext":D,role:`meter`,children:(0,_.jsxs)(m.Fragment,{children:[v,(0,_.jsx)(`span`,{role:`presentation`,style:l,children:`x`})]})},k=m.useMemo(()=>({formattedValue:E,percentageValue:w,setLabelId:S,value:c}),[E,w,S,c]),A=r(`div`,e,{ref:t,props:[O,b]});return(0,_.jsx)(h.Provider,{value:k,children:A})}),y=m.forwardRef(function(e,t){let{render:n,className:i,style:a,...o}=e;return r(`div`,e,{ref:t,props:o})}),b=m.forwardRef(function(e,t){let{render:n,className:i,style:a,...o}=e,{percentageValue:s}=g();return r(`div`,e,{ref:t,props:[{style:{insetInlineStart:0,height:`inherit`,width:`${s}%`}},o]})}),x=m.forwardRef(function(e,t){let{className:n,render:i,children:a,style:o,...s}=e,{value:c,formattedValue:l}=g();return r(`span`,e,{ref:t,props:[{"aria-hidden":!0,children:typeof a==`function`?a(l,c):l},s]})}),S=m.forwardRef(function(e,t){let{render:n,className:i,style:a,id:o,...s}=e,{setLabelId:c}=g();return r(`span`,e,{ref:t,props:[{id:d(o,c),role:`presentation`},s]})}),C=c(b,`tr-meter-indicator`),w=c(S,`tr-meter-label`);function T({className:t,max:n=100,min:r=0,value:i,variant:a=`neutral`,...o}){let s=Math.min(n,Math.max(r,Number.isNaN(i)?r:i));return(0,_.jsx)(v,{...o,className:e(`tr-meter`,t),"data-variant":a,max:n,min:r,value:s})}var E={Root:T,Track:c(y,`tr-meter-track`),Indicator:C,Value:c(x,`tr-meter-value`),Label:w},D=[`weak`,`fair`,`good`,`strong`],O={weak:`danger`,fair:`warning`,good:`info`,strong:`success`};function k(e,t){if(e.length===0)return 0;if(e.length<t.min_length)return 1;let n=[/[a-z]/,/[A-Z]/,/\d/,/[^a-zA-Z0-9]/].filter(t=>t.test(e)).length,r=e.length>=t.min_length+4;return n>=3&&r?4:n>=2&&r?3:2}function A({password:e,policy:t}){let{t:n}=i(),r=k(e,t);if(r===0)return null;let o=D[r-1];return(0,_.jsxs)(E.Root,{"aria-live":`polite`,className:`flex flex-col gap-tinyrack-xs`,max:4,min:0,value:r,variant:O[o],children:[(0,_.jsxs)(`div`,{className:`flex items-baseline justify-between gap-tinyrack-sm`,children:[(0,_.jsx)(E.Label,{render:(0,_.jsx)(a,{color:`muted`,variant:`caption`,children:n(`validation.password.strength.label`)})}),(0,_.jsx)(E.Value,{render:(0,_.jsx)(a,{color:`muted`,variant:`caption`,children:n(`validation.password.strength.${o}`)})})]}),(0,_.jsx)(E.Track,{children:(0,_.jsx)(E.Indicator,{})})]})}export{A as t};
|
|
2
|
-
//# sourceMappingURL=password-strength-BIPcWiM_.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{G as e,J as t,Z as n,_ as r,b as i,c as a,i as o,q as s,v as c,x as l}from"./createLucideIcon-BPpAIXR_.js";import{F as u,G as d,P as f,S as ee,U as p,Vt as m,W as h,Zt as te,bn as g,bt as ne,k as _,q as re,xt as v}from"./config-DTQCUlfZ.js";import{A as ie,C as ae,D as oe,T as se,b as ce,c as le,k as y,m as b,x as ue,y as de}from"./shell-header-bar-JcFhS7mb.js";import{t as x}from"./useAriaLabelledBy-IIwdHUss.js";import{t as S}from"./field-BMT214_m.js";import{t as C}from"./separator-B0Bvh1he.js";var w=n(t(),1),T=w.createContext(void 0);function fe(){let e=w.useContext(T);if(e===void 0)throw Error(c(98));return e}function E(e,t,n){return{...e,value:t,index:n,filled:t!==``}}var D={value:()=>null,length:()=>null,...y},O={value:()=>null,index:()=>null,...y},k={numeric:{slotPattern:`\\d{1}`,getRootPattern:e=>`\\d{${e}}`,regexp:/[^\d]/g,inputMode:`numeric`},alpha:{slotPattern:`[a-zA-Z]{1}`,getRootPattern:e=>`[a-zA-Z]{${e}}`,regexp:/[^a-zA-Z]/g,inputMode:`text`},alphanumeric:{slotPattern:`[a-zA-Z0-9]{1}`,getRootPattern:e=>`[a-zA-Z0-9]{${e}}`,regexp:/[^a-zA-Z0-9]/g,inputMode:`text`}};function A(e){return e===`none`?null:k[e]}function j(e){return(e??``).replace(/\s/g,``)}function pe(e,t){return t?e.replace(t.regexp,``):e}function M(e,t,n,r){let i=j(e),a=A(n),o=pe(i,a),s=i.length>o.length;if(r){let e=r(o);s||=o.length>e.length,o=pe(e,a),s||=e.length>o.length}let c=t<0?0:t,l=Array.from(o);return[l.slice(0,c).join(``),s||l.length>c]}function N(e,t,n,r){return M(e,t,n,r)[0]}function me(e,t,n,r,i,a){let o=N(n,r,i,a);return N(`${e.slice(0,t)}${o}${e.slice(t+o.length)}`,r,i,a)}function P(e,t){return t<0||t>=e.length?e:`${e.slice(0,t)}${e.slice(t+1)}`}var F=s(),I=w.forwardRef(function(e,t){let{"aria-describedby":n,"aria-labelledby":o,id:s,autoComplete:c=`one-time-code`,defaultValue:d,value:ee,onValueChange:p,onValueComplete:m,form:h,length:g,autoSubmit:re=!1,mask:le=!1,inputMode:y,validationType:S=`numeric`,normalizeValue:C,disabled:fe=!1,readOnly:E=!1,required:O=!1,name:k,onValueInvalid:j,render:pe,className:me,style:P,...I}=e,{setDirty:R,validityData:z,disabled:B,setFilled:V,invalid:H,name:he,state:ge,validation:U,validationMode:_e,setFocused:ve,setTouched:ye}=oe(),{clearErrors:be}=ce(),{getDescriptionProps:xe,labelId:Se}=ae(),W=B||fe,G=he??k,[Ce,we]=ie({controlled:ee,default:d,name:`OTPField`,state:`value`}),K=w.useRef(null),q=w.useRef([]),Te=w.useRef(null),J=w.useRef(null),Ee=w.useMemo(()=>({get current(){return q.current[0]??null}}),[]),Y=ue({id:s}),De=x(o,Se,Ee,!0,Y),Oe=o==null?De:void 0,ke=L(n,xe({})[`aria-describedby`]),Ae=A(S),je=Ae?.slotPattern,Me=Ae?.getRootPattern(g),Ne=y??Ae?.inputMode,Pe=Number.isInteger(g)&&g>0,X=N(Ce,g,S,C),Z=_(X),Q=X!==``,[Fe,Ie]=w.useState(0),[Le,Re]=w.useState(()=>Math.min(X.length,g-1)),[ze,Be]=w.useState(!1),Ve=ze?Math.min(Le,Math.max(g-1,0)):Math.min(X.length,g-1);i(()=>{V(Q)},[Q,V]),se(Ee,Y,X,void 0,!W,k);let $=l(e=>{let t=Math.min(Math.max(e,0),Math.max(q.current.length-1,0)),n=q.current[t];n?.focus(),n?.select()}),He=l((e,t)=>{Te.current={index:e,value:t}});function Ue(){let e=U.inputRef.current?.form??q.current[0]?.form??null;if(h){let t=r(K.current).getElementById(h);t?.tagName===`FORM`&&(e=t)}e&&typeof e.requestSubmit==`function`&&e.requestSubmit()}function We(e,t){m?.(e,t),re&&Ue()}de(X,()=>{be(G),R(X!==z.initialValue),U.change(X);let e=Te.current;e!=null&&(Te.current=null,e.value===X&&$(e.index));let t=J.current;t!=null&&(J.current=null,t.value===X&&We(X,t.eventDetails))});let Ge=l((e,t)=>{let n=N(e,g,S,C),r=(t.reason===`input-change`||t.reason===`input-paste`)&&n.length===g&&(Z.current.length!==g||t.reason===`input-paste`)?u(t.reason,t.event):null;return n===Z.current?(r!=null&&We(n,r),null):(p?.(n,t),t.isCanceled?null:(we(n),r==null?n.length!==g&&(J.current=null):J.current={value:n,eventDetails:r},n))}),Ke=l((e,t)=>{j?.(e,t)}),qe=l((e,t)=>{if(e>Z.current.length){$(Math.min(Z.current.length,g-1));return}Re(e),Be(!0),ve(!0),t.currentTarget.select()}),Je=l(e=>{te(K.current,e.relatedTarget)||(ye(!0),Be(!1),ve(!1),_e===`onBlur`&&U.commit(Z.current))}),Ye=w.useCallback(e=>{if(Y!=null)return e===0?Y:`${Y}-${e+1}`},[Y]),Xe=w.useMemo(()=>({...ge,complete:X.length===g,disabled:W,filled:Q,focused:ze,length:g,readOnly:E,required:O,value:X}),[W,ge,Q,ze,g,E,O,X]),Ze=w.useMemo(()=>({autoComplete:c,activeIndex:Ve,disabled:W,form:h,focusInput:$,queueFocusInput:He,getInputId:Ye,handleInputBlur:Je,handleInputFocus:qe,inputMode:Ne,inputAriaLabelledBy:Oe,invalid:H,length:g,mask:le,pattern:je,reportValueInvalid:Ke,readOnly:E,required:O,normalizeValue:C,setValue:Ge,state:Xe,validationType:S,value:X}),[Ve,c,W,$,h,Ye,Je,qe,Ne,Oe,H,g,le,je,He,E,Ke,O,C,Ge,Xe,S,X]),Qe=a(`div`,e,{ref:[t,K],state:Xe,props:[{role:`group`,"aria-describedby":ke,"aria-labelledby":De},I],stateAttributesMapping:D});return(0,F.jsx)(b,{elementsRef:q,onMapChange:e=>{Ie(e.size)},children:(0,F.jsxs)(T.Provider,{value:Ze,children:[Qe,Pe&&(0,F.jsx)(`input`,{...U.getValidationProps(W,{onFocus(){$(0)},onChange(e){if(e.nativeEvent.defaultPrevented||W||E)return;let t=e.currentTarget.value,[n,r]=M(t,g,S,C);r&&Ke(t,u(`input-change`,e.nativeEvent));let i=Ge(n,f(`input-change`,e.nativeEvent));i!=null&&i!==``&&He(i.length-1,i)}}),ref:U.inputRef,type:`text`,id:Y&&G==null?`${Y}-hidden-input`:void 0,form:h,name:G,value:X,autoComplete:c,inputMode:Ne,minLength:g,maxLength:g,pattern:Me,disabled:W,readOnly:E,required:O,"aria-hidden":!0,tabIndex:-1,style:G?v:ne})]})})});function L(...e){let t=e.flatMap(e=>e?.split(/\s+/).filter(Boolean)??[]);return t.length>0?Array.from(new Set(t)).join(` `):void 0}var R=g(w.forwardRef(function(e,t){let{"aria-label":n,"aria-labelledby":r,render:i,className:o,style:s,...c}=e,{activeIndex:l,autoComplete:te,disabled:g,form:ne,focusInput:_,queueFocusInput:v,getInputId:ie,handleInputBlur:ae,handleInputFocus:oe,inputMode:se,inputAriaLabelledBy:ce,invalid:y,length:b,mask:ue,pattern:de,reportValueInvalid:x,readOnly:S,required:C,normalizeValue:T,setValue:D,state:k,validationType:A,value:j}=fe(),{ref:pe,index:N}=le({guess:!0}),F=w.useRef(null),I=ee(),L=j[N]??``,R=E(k,L,N),z=n,B=r??ce,V=N===0?void 0:z,H={id:ie(N),value:L,type:ue?`password`:`text`,inputMode:se,autoComplete:N===0?te:`off`,autoCorrect:`off`,spellCheck:`false`,enterKeyHint:N===b-1?`done`:`next`,maxLength:N===0?b:void 0,tabIndex:l===N?0:-1,disabled:g,form:ne,pattern:de,readOnly:S,required:C,"aria-labelledby":V==null?B:void 0,"aria-invalid":!g&&y?!0:void 0,"aria-label":V,onMouseDown(e){e.defaultPrevented||g||(e.preventDefault(),_(N))},onFocus(e){e.defaultPrevented||g||oe(N,e)},onBlur(e){e.defaultPrevented||ae(e)},onChange(e){if(e.defaultPrevented||g||S)return;let t=e.currentTarget.value,[n,r]=M(t,b,A,T);if(r&&x(t,u(p,e.nativeEvent)),n===``){t===``?D(P(j,N),f(h,e.nativeEvent)):L!==``&&(e.currentTarget.value=L,e.currentTarget.select());return}let i=me(j,N,n,b,A,T),a=D(i,f(p,e.nativeEvent));if(a!=null){let e=Math.min(N+n.length,b-1);v(e,a)}},onKeyDown(e){if(e.defaultPrevented||g)return;let t=Math.max(b-1,0),n=Math.min(j.length,t),r=(e.ctrlKey||e.metaKey)&&!e.altKey,i=I===`rtl`,a=i?`ArrowRight`:`ArrowLeft`,o=i?`ArrowLeft`:`ArrowRight`;if(e.key===a){m(e),_(r?0:Math.max(0,N-1));return}if(e.key===o){m(e),_(r?n:Math.min(t,N+1));return}if(e.key===`Home`||e.key===`ArrowUp`){m(e),_(0);return}if(e.key===`End`||e.key===`ArrowDown`){m(e),_(n);return}if(S)return;function s(t,n){let r=D(t,f(re,e.nativeEvent));r!=null&&v(n,r)}if(e.key===`Backspace`&&r){m(e),s(``,0);return}if(e.key===`Delete`){m(e),s(P(j,N),N);return}let c=e.currentTarget.value,l=e.currentTarget.selectionStart===0&&e.currentTarget.selectionEnd===c.length;if(e.key.length===1&&l&&L===e.key){m(e),N<b-1&&_(N+1);return}if(e.key===`Backspace`){m(e);let t=Math.max(0,N-1);s(P(j,L===``?t:N),t)}},onPaste(e){if(e.defaultPrevented||g||S)return;let t=``;try{t=e.clipboardData?.getData(`text/plain`)??``}catch{return}e.preventDefault();let[n,r]=M(t,b,A,T);if(r&&x(t,u(d,e.nativeEvent)),n===``)return;let i=D(me(j,N,n,b,A,T),f(d,e.nativeEvent));if(i!=null){let e=Math.min(N+n.length,b-1);v(e,i)}}};return a(`input`,e,{ref:[t,pe,F],state:R,props:[H,c],stateAttributesMapping:O})}),`tr-otp-field-digit`,{tracksFocusModality:!0});function z({appearance:t=`solid`,className:n,layout:r=`compact`,uiSize:i=`md`,...a}){return(0,F.jsx)(I,{...a,className:e(`tr-otp-field`,n),"data-appearance":t,"data-layout":r,"data-ui-size":i})}function B({className:t,orientation:n=`vertical`,...r}){return(0,F.jsx)(C,{...r,className:e(`tr-otp-field-separator`,t),orientation:n})}var V={Root:z,Input:R,Separator:B},H=(0,w.forwardRef)(function({length:e=6,error:t,disabled:n=!1,onComplete:r,onChange:i,value:a,autoFocus:s=!1,className:c=``},l){let{t:u}=o(),d=(0,w.useId)(),f=(0,w.useRef)(null),[ee,p]=(0,w.useState)(a??``);(0,w.useEffect)(()=>{a!==void 0&&p(a)},[a]),(0,w.useImperativeHandle)(l,()=>({focus:()=>{(f.current?.querySelector(`input`))?.focus()},clear:()=>{p(``),(f.current?.querySelector(`input`))?.focus()}}),[]);let m=(0,w.useCallback)(e=>{p(e),i?.(e)},[i]),h=(0,w.useCallback)(e=>{r?.(e)},[r]);return(0,F.jsxs)(S.Root,{className:`w-full ${c}`,ref:f,children:[(0,F.jsx)(S.Label,{className:`sr-only`,htmlFor:d,children:u(`common.otp.label`)}),(0,F.jsx)(V.Root,{disabled:n,id:d,layout:`stretch`,length:e,onValueChange:m,onValueComplete:h,uiSize:`lg`,validationType:`numeric`,value:ee,children:Array.from({length:e},(t,n)=>(0,F.jsx)(V.Input,{"aria-label":n===0?void 0:u(`common.otp.digit`,{label:u(`common.otp.label`),position:n+1,total:e}),autoFocus:s&&n===0},n))}),t&&(0,F.jsx)(`p`,{className:`mt-tinyrack-sm text-center text-tinyrack-danger-foreground text-tinyrack-sm`,"data-testid":`pin-input-error`,children:t.message})]})});export{H as t};
|
|
2
|
-
//# sourceMappingURL=pin-input-CITrr-Yc.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plus-DSBBSrgj.js","names":[],"sources":["../../../../node_modules/.pnpm/lucide-react@1.25.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/plus.mjs"],"sourcesContent":["/**\n * @license lucide-react v1.25.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n];\nconst Plus = createLucideIcon(\"plus\", __iconNode);\n\nexport { __iconNode, Plus as default };\n//# sourceMappingURL=plus.mjs.map\n"],"x_google_ignoreList":[0],"mappings":"mDAaA,IAAM,EAAO,EAAiB,OAAQ,CAHpC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,CAEL,CAAU"}
|