refactor(ui): reorganize component structure and update imports for better clarity
ZhenYi committed
Modified view/auth/src/app/routing/router.tsx view/auth/src/app/routing/router.tsx +2 −12 View view/auth/src/app/routing/router.tsx
@@ -18,7 +18,7 @@
1818import { routes } from '@/shared/config'
1919import { t } from '@/shared/i18n'
2020import { navigate, usePath } from '@/shared/lib'
21import { Alert, Button, Heading } from '@/shared/ui'
21import { SessionCheck } from '@/shared/ui'
2222
2323function LoginEntry({ children }: { children: ReactNode }) {
2424 const [unauthenticated, setUnauthenticated] = useState(false)
@@ -27,17 +27,7 @@
2727 if (user) navigate(routes.account, true)
2828 }, [user])
2929 if (unauthenticated) return <>{children}</>
30 return (
31 <>
32 <Heading title={t('account.checking')} />
33 <Alert notice={task.notice} />
34 {!loading && task.notice && (
35 <Button type="button" onClick={() => location.reload()}>
36 {t('common.retry')}
37 </Button>
38 )}
39 </>
40 )
30 return <SessionCheck loading={loading} notice={task.notice} onRetry={() => location.reload()} />
4131}
4232
4333function useLoginComplete(): LoginComplete {
Modified view/auth/src/features/login-by-code/ui/login-code-form.tsx view/auth/src/features/login-by-code/ui/login-code-form.tsx +29 −37 View view/auth/src/features/login-by-code/ui/login-code-form.tsx
@@ -1,17 +1,17 @@
11import type { LoginByCodeModel } from '@/features/login-by-code'
22import { t } from '@/shared/i18n'
3import { Button, Field, Otp, ResendButton } from '@/shared/ui'
3import { AuthForm, EmailSummary, Field, Otp, ResendButton } from '@/shared/ui'
44
55export function LoginByCodeForm({ model }: { model: LoginByCodeModel }) {
66 const { email, setEmail, sentEmail, code, setCode, task, timer, retry, send, changeEmail, submit } = model
77 if (!sentEmail)
88 return (
9 <form
10 noValidate
11 onSubmit={(event) => {
12 event.preventDefault()
13 send()
14 }}
9 <AuthForm
10 onSubmit={send}
11 busy={task.busy}
12 submitDisabled={retry > 0}
13 submitClassName="mt-6"
14 submitLabel={t('loginCode.send')}
1515 >
1616 <Field
1717 name="email"
@@ -24,33 +24,30 @@
2424 error={task.errors.email}
2525 disabled={task.busy}
2626 />
27 <div className="mt-6">
28 <Button busy={task.busy} disabled={retry > 0}>
29 {t('loginCode.send')}
30 </Button>
31 </div>
32 </form>
27 </AuthForm>
3328 )
3429 return (
3530 <>
36 <div className="mb-6 flex flex-wrap items-center justify-center gap-2">
37 <span className="max-w-full font-latin text-sm font-medium wrap-anywhere">{sentEmail}</span>
38 <button
39 type="button"
40 disabled={task.busy}
41 className="min-h-11 px-1 text-xs text-accent-text hover:underline"
42 onClick={changeEmail}
43 >
44 {t('loginCode.changeEmail')}
45 </button>
46 </div>
47 <form
48 noValidate
49 aria-label={t('loginCode.form')}
50 onSubmit={(event) => {
51 event.preventDefault()
52 submit()
53 }}
31 <EmailSummary
32 email={sentEmail}
33 action={
34 <button
35 type="button"
36 disabled={task.busy}
37 className="min-h-11 px-1 text-xs text-accent-text hover:underline"
38 onClick={changeEmail}
39 >
40 {t('loginCode.changeEmail')}
41 </button>
42 }
43 />
44 <AuthForm
45 ariaLabel={t('loginCode.form')}
46 onSubmit={submit}
47 busy={task.busy}
48 submitDisabled={retry > 0 || !timer.expiry}
49 submitClassName="mt-6"
50 submitLabel={t('loginCode.submit')}
5451 >
5552 <Otp value={code} onInput={setCode} error={task.errors.code} />
5653 {timer.sent && timer.expiry === 0 && (
@@ -58,12 +55,7 @@
5855 {t('loginCode.expired')}
5956 </p>
6057 )}
61 <div className="mt-6">
62 <Button busy={task.busy} disabled={retry > 0 || !timer.expiry}>
63 {t('loginCode.submit')}
64 </Button>
65 </div>
66 </form>
58 </AuthForm>
6759 <ResendButton seconds={Math.max(timer.resend, retry)} busy={task.busy} onClick={send} />
6860 </>
6961 )
Modified view/auth/src/features/login-by-password/ui/login-form.tsx view/auth/src/features/login-by-password/ui/login-form.tsx +9 −13 View view/auth/src/features/login-by-password/ui/login-form.tsx
@@ -1,18 +1,18 @@
11import { routes } from '@/shared/config'
22import { t } from '@/shared/i18n'
3import { Button, Field, Link, RetryHint } from '@/shared/ui'
3import { AuthForm, Field, Link } from '@/shared/ui'
44import type { LoginByPasswordModel } from '../model/use-login-by-password'
55
66export function LoginByPasswordForm({ model }: { model: LoginByPasswordModel }) {
77 const { identity, setIdentity, password, setPassword, task, retry, submit } = model
88 return (
9 <form
10 noValidate
11 aria-label={t('login.form')}
12 onSubmit={(event) => {
13 event.preventDefault()
14 submit()
15 }}
9 <AuthForm
10 ariaLabel={t('login.form')}
11 onSubmit={submit}
12 busy={task.busy}
13 submitDisabled={retry > 0}
14 retry={retry}
15 submitLabel={task.busy ? t('login.busy') : t('login.submit')}
1616 >
1717 <div className="flex flex-col gap-4">
1818 <Field
@@ -42,10 +42,6 @@
4242 <Link to={routes.loginCode}>{t('login.codeLink')}</Link>
4343 <Link to={routes.forgotPassword}>{t('login.forgotLink')}</Link>
4444 </div>
45 <Button busy={task.busy} disabled={retry > 0}>
46 {task.busy ? t('login.busy') : t('login.submit')}
47 </Button>
48 <RetryHint seconds={retry} />
49 </form>
45 </AuthForm>
5046 )
5147}
Modified view/auth/src/features/register-account/ui/register-form.tsx view/auth/src/features/register-account/ui/register-form.tsx +11 −13 View view/auth/src/features/register-account/ui/register-form.tsx
@@ -1,6 +1,6 @@
11import { t } from '@/shared/i18n'
22import { normalizeEmail } from '@/shared/lib'
3import { Agreement, BirthDate, Button, Field, RetryHint } from '@/shared/ui'
3import { Agreement, AuthForm, BirthDate, Field } from '@/shared/ui'
44import type { RegisterAccountModel } from '../model/use-register-account'
55
66export function RegisterAccountForm({ model }: { model: RegisterAccountModel }) {
@@ -22,13 +22,15 @@
2222 submit,
2323 } = model
2424 return (
25 <form
26 noValidate
27 aria-label={t('register.form')}
28 onSubmit={(event) => {
29 event.preventDefault()
30 submit()
31 }}
25 <AuthForm
26 ariaLabel={t('register.form')}
27 onSubmit={submit}
28 busy={task.busy}
29 submitDisabled={retry > 0}
30 retry={retry}
31 submitLabel={
32 draft?.email === normalizeEmail(email) && timer.expiry ? t('register.submitContinue') : t('register.submit')
33 }
3234 >
3335 <div className="flex flex-col gap-4">
3436 <Field
@@ -72,10 +74,6 @@
7274 <BirthDate value={birth} onChange={setBirth} error={task.errors.birth} disabled={task.busy} />
7375 </div>
7476 <Agreement checked={agreed} onChange={setAgreed} error={task.errors.agreement} disabled={task.busy} />
75 <Button busy={task.busy} disabled={retry > 0}>
76 {draft?.email === normalizeEmail(email) && timer.expiry ? t('register.submitContinue') : t('register.submit')}
77 </Button>
78 <RetryHint seconds={retry} />
79 </form>
77 </AuthForm>
8078 )
8179}
Modified view/auth/src/features/register-account/ui/register-verify-form.tsx view/auth/src/features/register-account/ui/register-verify-form.tsx +8 −13 View view/auth/src/features/register-account/ui/register-verify-form.tsx
@@ -1,18 +1,18 @@
11import { routes } from '@/shared/config'
22import { t } from '@/shared/i18n'
3import { Button, Link, Otp, ResendButton } from '@/shared/ui'
3import { AuthForm, Link, Otp, ResendButton } from '@/shared/ui'
44import type { RegisterVerifyModel } from '../model/use-register-verify'
55
66export function RegisterVerifyForm({ model }: { model: RegisterVerifyModel }) {
77 const { code, setCode, task, timer, retry, submit, resend } = model
88 return (
99 <>
10 <form
11 noValidate
12 onSubmit={(event) => {
13 event.preventDefault()
14 submit()
15 }}
10 <AuthForm
11 onSubmit={submit}
12 busy={task.busy}
13 submitDisabled={retry > 0 || !timer.expiry}
14 submitClassName="mt-6"
15 submitLabel={t('registerVerify.submit')}
1616 >
1717 <Otp value={code} onInput={setCode} error={task.errors.code} />
1818 {timer.sent && !timer.expiry && (
@@ -20,12 +20,7 @@
2020 {t('registerVerify.expired')}
2121 </p>
2222 )}
23 <div className="mt-6">
24 <Button busy={task.busy} disabled={retry > 0 || !timer.expiry}>
25 {t('registerVerify.submit')}
26 </Button>
27 </div>
28 </form>
23 </AuthForm>
2924 {(task.errors.username || task.errors.email || task.errors.birth || task.errors.password) && (
3025 <div className="mt-3 text-center">
3126 <Link to={routes.register}>{t('registerVerify.backToForm')}</Link>
Modified view/auth/src/features/request-password-reset/ui/forgot-password-form.tsx view/auth/src/features/request-password-reset/ui/forgot-password-form.tsx +9 −14 View view/auth/src/features/request-password-reset/ui/forgot-password-form.tsx
@@ -1,16 +1,17 @@
11import { t } from '@/shared/i18n'
2import { Button, Field, RetryHint } from '@/shared/ui'
2import { AuthForm, Field } from '@/shared/ui'
33import type { RequestPasswordResetModel } from '../model/use-request-password-reset'
44
55export function ForgotPasswordForm({ model }: { model: RequestPasswordResetModel }) {
66 const { email, setEmail, task, retry, submit } = model
77 return (
8 <form
9 noValidate
10 onSubmit={(event) => {
11 event.preventDefault()
12 submit()
13 }}
8 <AuthForm
9 onSubmit={submit}
10 busy={task.busy}
11 submitDisabled={retry > 0}
12 retry={retry}
13 submitClassName="mt-6"
14 submitLabel={t('forgot.submit')}
1415 >
1516 <Field
1617 name="email"
@@ -23,12 +24,6 @@
2324 error={task.errors.email}
2425 disabled={task.busy}
2526 />
26 <div className="mt-6">
27 <Button busy={task.busy} disabled={retry > 0}>
28 {t('forgot.submit')}
29 </Button>
30 </div>
31 <RetryHint seconds={retry} />
32 </form>
27 </AuthForm>
3328 )
3429}
Modified view/auth/src/features/reset-password/ui/reset-password-form.tsx view/auth/src/features/reset-password/ui/reset-password-form.tsx +9 −14 View view/auth/src/features/reset-password/ui/reset-password-form.tsx
@@ -1,16 +1,17 @@
11import { t } from '@/shared/i18n'
2import { Button, Field, RetryHint } from '@/shared/ui'
2import { AuthForm, Field } from '@/shared/ui'
33import type { ResetPasswordModel } from '../model/use-reset-password'
44
55export function ResetPasswordForm({ model }: { model: ResetPasswordModel }) {
66 const { password, setPassword, confirmation, setConfirmation, task, retry, submit } = model
77 return (
8 <form
9 noValidate
10 onSubmit={(event) => {
11 event.preventDefault()
12 submit()
13 }}
8 <AuthForm
9 onSubmit={submit}
10 busy={task.busy}
11 submitDisabled={retry > 0}
12 retry={retry}
13 submitClassName="mt-6"
14 submitLabel={t('resetPassword.submit')}
1415 >
1516 <div className="flex flex-col gap-4">
1617 <Field
@@ -39,12 +40,6 @@
3940 disabled={task.busy}
4041 />
4142 </div>
42 <div className="mt-6">
43 <Button busy={task.busy} disabled={retry > 0}>
44 {t('resetPassword.submit')}
45 </Button>
46 </div>
47 <RetryHint seconds={retry} />
48 </form>
43 </AuthForm>
4944 )
5045}
Modified view/auth/src/features/verify-mfa/ui/mfa-form.tsx view/auth/src/features/verify-mfa/ui/mfa-form.tsx +9 −14 View view/auth/src/features/verify-mfa/ui/mfa-form.tsx
@@ -1,17 +1,18 @@
11import { t } from '@/shared/i18n'
2import { Button, Field, Otp, RetryHint } from '@/shared/ui'
2import { AuthForm, Field, Otp } from '@/shared/ui'
33import type { VerifyMfaModel } from '../model/use-verify-mfa'
44
55export function VerifyMfaForm({ model }: { model: VerifyMfaModel }) {
66 const { recovery, code, setCode, task, retry, toggleRecovery, submit } = model
77 return (
88 <>
9 <form
10 noValidate
11 onSubmit={(event) => {
12 event.preventDefault()
13 submit()
14 }}
9 <AuthForm
10 onSubmit={submit}
11 busy={task.busy}
12 submitDisabled={retry > 0}
13 retry={retry}
14 submitClassName="mt-6"
15 submitLabel={t('mfa.submit')}
1516 >
1617 {recovery ? (
1718 <Field
@@ -35,13 +36,7 @@
3536 helper={t('mfa.totpHelper')}
3637 />
3738 )}
38 <div className="mt-6">
39 <Button busy={task.busy} disabled={retry > 0}>
40 {t('mfa.submit')}
41 </Button>
42 </div>
43 <RetryHint seconds={retry} />
44 </form>
39 </AuthForm>
4540 <div className="mt-4 text-center">
4641 <button
4742 type="button"
Modified view/auth/src/pages/account/ui/account-page.tsx view/auth/src/pages/account/ui/account-page.tsx +2 −13 View view/auth/src/pages/account/ui/account-page.tsx
@@ -5,7 +5,7 @@
55import { routes } from '@/shared/config'
66import { t } from '@/shared/i18n'
77import { navigate } from '@/shared/lib'
8import { Alert, Button, Heading } from '@/shared/ui'
8import { Alert, Heading, SessionCheck } from '@/shared/ui'
99
1010const CALLBACK_REDIRECT_DELAY_MS = 1000
1111
@@ -21,18 +21,7 @@
2121 }, CALLBACK_REDIRECT_DELAY_MS)
2222 return () => clearTimeout(timer)
2323 }, [user])
24 if (loading || !user)
25 return (
26 <>
27 <Heading title={t('account.checking')} />
28 <Alert notice={task.notice} />
29 {!loading && task.notice && (
30 <Button type="button" onClick={() => location.reload()}>
31 {t('common.retry')}
32 </Button>
33 )}
34 </>
35 )
24 if (loading || !user) return <SessionCheck loading={loading} notice={task.notice} onRetry={() => location.reload()} />
3625 return (
3726 <>
3827 <Heading title={t('account.titleDone')} description={t('account.descriptionDone')} icon={CircleCheck} success />
Modified view/auth/src/pages/forgot-password/ui/forgot-password-page.tsx view/auth/src/pages/forgot-password/ui/forgot-password-page.tsx +8 −6 View view/auth/src/pages/forgot-password/ui/forgot-password-page.tsx
@@ -1,16 +1,18 @@
11import { KeyRound } from 'lucide-react'
22import { ForgotPasswordForm, useRequestPasswordReset } from '@/features/request-password-reset'
33import { t } from '@/shared/i18n'
4import { Alert, BackLink, Heading } from '@/shared/ui'
4import { BackLink, Heading } from '@/shared/ui'
5import { AuthPanel } from '@/widgets/auth-panel'
56
67export function ForgotPasswordPage({ onSent }: { onSent: () => void }) {
78 const model = useRequestPasswordReset(onSent)
89 return (
9 <>
10 <Heading title={t('forgot.title')} description={t('forgot.description')} icon={KeyRound} />
11 <Alert notice={model.task.notice} />
10 <AuthPanel
11 heading={<Heading title={t('forgot.title')} description={t('forgot.description')} icon={KeyRound} />}
12 notice={model.task.notice}
13 footer={<BackLink />}
14 >
1215 <ForgotPasswordForm model={model} />
13 <BackLink />
14 </>
16 </AuthPanel>
1517 )
1618}
Modified view/auth/src/pages/login/ui/login-page.tsx view/auth/src/pages/login/ui/login-page.tsx +8 −6 View view/auth/src/pages/login/ui/login-page.tsx
@@ -2,16 +2,18 @@
22import { LoginByPasswordForm, useLoginByPassword } from '@/features/login-by-password'
33import { routes } from '@/shared/config'
44import { t } from '@/shared/i18n'
5import { Alert, FormNavigation, Heading } from '@/shared/ui'
5import { FormNavigation, Heading } from '@/shared/ui'
6import { AuthPanel } from '@/widgets/auth-panel'
67
78export function LoginPage({ onComplete }: { onComplete: LoginComplete }) {
89 const model = useLoginByPassword(onComplete)
910 return (
10 <>
11 <Heading title={t('login.title')} description={t('login.description')} />
12 <Alert notice={model.task.notice} />
11 <AuthPanel
12 heading={<Heading title={t('login.title')} description={t('login.description')} />}
13 notice={model.task.notice}
14 footer={<FormNavigation prompt={t('login.prompt')} action={t('login.action')} to={routes.register} />}
15 >
1316 <LoginByPasswordForm model={model} />
14 <FormNavigation prompt={t('login.prompt')} action={t('login.action')} to={routes.register} />
15 </>
17 </AuthPanel>
1618 )
1719}
Modified view/auth/src/pages/login-code/ui/login-code-page.tsx view/auth/src/pages/login-code/ui/login-code-page.tsx +18 −10 View view/auth/src/pages/login-code/ui/login-code-page.tsx
@@ -1,20 +1,28 @@
11import type { LoginComplete } from '@/entities/session'
22import { LoginByCodeForm, useLoginByCode } from '@/features/login-by-code'
33import { t } from '@/shared/i18n'
4import { Alert, BackLink, Heading, RetryHint } from '@/shared/ui'
4import { BackLink, Heading, RetryHint } from '@/shared/ui'
5import { AuthPanel } from '@/widgets/auth-panel'
56
67export function LoginCodePage({ onComplete }: { onComplete: LoginComplete }) {
78 const model = useLoginByCode(onComplete)
89 return (
9 <>
10 <Heading
11 title={model.sentEmail ? t('loginCode.titleSent') : t('loginCode.title')}
12 description={model.sentEmail ? t('loginCode.descriptionSent') : t('loginCode.description')}
13 />
14 <Alert notice={model.task.notice} />
10 <AuthPanel
11 heading={
12 <Heading
13 title={model.sentEmail ? t('loginCode.titleSent') : t('loginCode.title')}
14 description={model.sentEmail ? t('loginCode.descriptionSent') : t('loginCode.description')}
15 />
16 }
17 notice={model.task.notice}
18 footer={
19 <>
20 <RetryHint seconds={model.retry} />
21 <BackLink>{t('loginCode.back')}</BackLink>
22 </>
23 }
24 >
1525 <LoginByCodeForm model={model} />
16 <RetryHint seconds={model.retry} />
17 <BackLink>{t('loginCode.back')}</BackLink>
18 </>
26 </AuthPanel>
1927 )
2028}
Modified view/auth/src/pages/login-verify/ui/login-verify-page.tsx view/auth/src/pages/login-verify/ui/login-verify-page.tsx +14 −10 View view/auth/src/pages/login-verify/ui/login-verify-page.tsx
@@ -4,7 +4,8 @@
44import { useVerifyMfa, VerifyMfaForm } from '@/features/verify-mfa'
55import { routes } from '@/shared/config'
66import { t } from '@/shared/i18n'
7import { Alert, BackLink, FlowRequired, Heading } from '@/shared/ui'
7import { BackLink, FlowRequired, Heading } from '@/shared/ui'
8import { AuthPanel } from '@/widgets/auth-panel'
89
910export function LoginVerifyPage({ onComplete }: { onComplete: LoginComplete }) {
1011 const challenge = useMfaChallenge()
@@ -25,15 +26,18 @@
2526function MfaVerification({ challenge, onComplete }: { challenge: string; onComplete: LoginComplete }) {
2627 const model = useVerifyMfa(challenge, onComplete)
2728 return (
28 <>
29 <Heading
30 title={t('mfa.title')}
31 description={model.recovery ? t('mfa.descriptionRecovery') : t('mfa.descriptionTotp')}
32 icon={ShieldCheck}
33 />
34 <Alert notice={model.task.notice} />
29 <AuthPanel
30 heading={
31 <Heading
32 title={t('mfa.title')}
33 description={model.recovery ? t('mfa.descriptionRecovery') : t('mfa.descriptionTotp')}
34 icon={ShieldCheck}
35 />
36 }
37 notice={model.task.notice}
38 footer={<BackLink>{t('mfa.back')}</BackLink>}
39 >
3540 <VerifyMfaForm model={model} />
36 <BackLink>{t('mfa.back')}</BackLink>
37 </>
41 </AuthPanel>
3842 )
3943}
Modified view/auth/src/pages/not-found/ui/not-found-page.tsx view/auth/src/pages/not-found/ui/not-found-page.tsx +3 −3 View view/auth/src/pages/not-found/ui/not-found-page.tsx
@@ -2,14 +2,14 @@
22import { t } from '@/shared/i18n'
33import { navigate } from '@/shared/lib'
44import { Button, Heading } from '@/shared/ui'
5import { AuthPanel } from '@/widgets/auth-panel'
56
67export function NotFoundPage() {
78 return (
8 <>
9 <Heading title={t('notFound.title')} description={t('notFound.description')} />
9 <AuthPanel heading={<Heading title={t('notFound.title')} description={t('notFound.description')} />}>
1010 <Button type="button" onClick={() => navigate(routes.login, true)}>
1111 {t('common.backToLogin')}
1212 </Button>
13 </>
13 </AuthPanel>
1414 )
1515}
Modified view/auth/src/pages/register/ui/register-page.tsx view/auth/src/pages/register/ui/register-page.tsx +10 −6 View view/auth/src/pages/register/ui/register-page.tsx
@@ -1,16 +1,20 @@
11import { RegisterAccountForm, useRegisterAccount } from '@/features/register-account'
22import { routes } from '@/shared/config'
33import { t } from '@/shared/i18n'
4import { Alert, FormNavigation, Heading } from '@/shared/ui'
4import { FormNavigation, Heading } from '@/shared/ui'
5import { AuthPanel } from '@/widgets/auth-panel'
56
67export function RegisterPage({ onSent }: { onSent: () => void }) {
78 const model = useRegisterAccount(onSent)
89 return (
9 <>
10 <Heading title={t('register.title')} step={t('register.step')} description={t('register.description')} />
11 <Alert notice={model.task.notice} />
10 <AuthPanel
11 heading={
12 <Heading title={t('register.title')} step={t('register.step')} description={t('register.description')} />
13 }
14 notice={model.task.notice}
15 footer={<FormNavigation prompt={t('register.prompt')} action={t('register.action')} to={routes.login} />}
16 >
1217 <RegisterAccountForm model={model} />
13 <FormNavigation prompt={t('register.prompt')} action={t('register.action')} to={routes.login} />
14 </>
18 </AuthPanel>
1519 )
1620}
Modified view/auth/src/pages/register-verify/ui/register-verify-page.tsx view/auth/src/pages/register-verify/ui/register-verify-page.tsx +18 −13 View view/auth/src/pages/register-verify/ui/register-verify-page.tsx
@@ -2,7 +2,8 @@
22import { RegisterVerifyForm, useRegisterVerify } from '@/features/register-account'
33import { routes } from '@/shared/config'
44import { t } from '@/shared/i18n'
5import { Alert, BackLink, FlowRequired, Heading, Link } from '@/shared/ui'
5import { BackLink, EmailSummary, FlowRequired, Heading, Link } from '@/shared/ui'
6import { AuthPanel } from '@/widgets/auth-panel'
67
78export function RegisterVerifyPage({ onComplete }: { onComplete: () => void }) {
89 const model = useRegisterVerify(onComplete)
@@ -18,19 +19,23 @@
1819 />
1920 )
2021 return (
21 <>
22 <Heading
23 title={t('registerVerify.title')}
24 step={t('registerVerify.step')}
25 description={t('registerVerify.description')}
22 <AuthPanel
23 heading={
24 <Heading
25 title={t('registerVerify.title')}
26 step={t('registerVerify.step')}
27 description={t('registerVerify.description')}
28 />
29 }
30 notice={model.task.notice}
31 footer={<BackLink to={routes.register}>{t('registerVerify.back')}</BackLink>}
32 >
33 <EmailSummary
34 className="mb-8"
35 email={model.draft.email}
36 action={<Link to={routes.register}>{t('registerVerify.changeEmail')}</Link>}
2637 />
27 <Alert notice={model.task.notice} />
28 <div className="mb-8 flex flex-wrap items-center justify-center gap-2">
29 <span className="max-w-full font-latin text-sm font-medium wrap-anywhere">{model.draft.email}</span>
30 <Link to={routes.register}>{t('registerVerify.changeEmail')}</Link>
31 </div>
3238 <RegisterVerifyForm model={model} />
33 <BackLink to={routes.register}>{t('registerVerify.back')}</BackLink>
34 </>
39 </AuthPanel>
3540 )
3641}
Modified view/auth/src/pages/reset-complete/ui/reset-complete-page.tsx view/auth/src/pages/reset-complete/ui/reset-complete-page.tsx +8 −4 View view/auth/src/pages/reset-complete/ui/reset-complete-page.tsx
@@ -4,6 +4,7 @@
44import { t } from '@/shared/i18n'
55import { navigate } from '@/shared/lib'
66import { Button, FlowRequired, Heading } from '@/shared/ui'
7import { AuthPanel } from '@/widgets/auth-panel'
78
89export function ResetCompletePage() {
910 const { completed } = usePasswordReset()
@@ -19,12 +20,15 @@
1920 />
2021 )
2122 return (
22 <>
23 <Heading title={t('resetComplete.title')} description={t('resetComplete.description')} icon={Check} success />
23 <AuthPanel
24 heading={
25 <Heading title={t('resetComplete.title')} description={t('resetComplete.description')} icon={Check} success />
26 }
27 footer={<p className="mt-4 text-center text-xs leading-[1.65] text-muted">{t('resetComplete.hint')}</p>}
28 >
2429 <Button type="button" onClick={() => navigate(routes.login)}>
2530 {t('common.backToLogin')}
2631 </Button>
27 <p className="mt-4 text-center text-xs leading-[1.65] text-muted">{t('resetComplete.hint')}</p>
28 </>
32 </AuthPanel>
2933 )
3034}
Modified view/auth/src/pages/reset-password/ui/reset-password-page.tsx view/auth/src/pages/reset-password/ui/reset-password-page.tsx +31 −20 View view/auth/src/pages/reset-password/ui/reset-password-page.tsx
@@ -4,24 +4,28 @@
44import { routes } from '@/shared/config'
55import { t } from '@/shared/i18n'
66import { navigate } from '@/shared/lib'
7import { Alert, BackLink, Button, Heading, Link } from '@/shared/ui'
7import { BackLink, Button, Heading, Link } from '@/shared/ui'
8import { AuthPanel } from '@/widgets/auth-panel'
89
910export function ResetPasswordPage({ onComplete }: { onComplete: () => void }) {
1011 const [token] = useState(() => new URLSearchParams(location.search).get('token') || '')
1112 if (!token)
1213 return (
13 <>
14 <Heading
15 title={t('resetPassword.invalidTitle')}
16 description={t('resetPassword.invalidDescription')}
17 icon={KeyRound}
18 />
19 <Alert notice={{ kind: 'error', text: t('resetPassword.missingAlert') }} />
14 <AuthPanel
15 heading={
16 <Heading
17 title={t('resetPassword.invalidTitle')}
18 description={t('resetPassword.invalidDescription')}
19 icon={KeyRound}
20 />
21 }
22 notice={{ kind: 'error', text: t('resetPassword.missingAlert') }}
23 footer={<BackLink />}
24 >
2025 <Button type="button" onClick={() => navigate(routes.forgotPassword)}>
2126 {t('resetPassword.invalidAction')}
2227 </Button>
23 <BackLink />
24 </>
28 </AuthPanel>
2529 )
2630 return <ResetPasswordSection token={token} onComplete={onComplete} />
2731}
@@ -29,16 +33,23 @@
2933function ResetPasswordSection({ token, onComplete }: { token: string; onComplete: () => void }) {
3034 const model = useResetPassword(token, onComplete)
3135 return (
32 <>
33 <Heading title={t('resetPassword.title')} description={t('resetPassword.description')} icon={LockKeyhole} />
34 <Alert notice={model.task.notice} />
36 <AuthPanel
37 heading={
38 <Heading title={t('resetPassword.title')} description={t('resetPassword.description')} icon={LockKeyhole} />
39 }
40 notice={model.task.notice}
41 footer={
42 <>
43 <BackLink />
44 {model.task.code === 'invalid_reset_token' && (
45 <div className="text-center">
46 <Link to={routes.forgotPassword}>{t('resetPassword.invalidAction')}</Link>
47 </div>
48 )}
49 </>
50 }
51 >
3552 <ResetPasswordForm model={model} />
36 <BackLink />
37 {model.task.code === 'invalid_reset_token' && (
38 <div className="text-center">
39 <Link to={routes.forgotPassword}>{t('resetPassword.invalidAction')}</Link>
40 </div>
41 )}
42 </>
53 </AuthPanel>
4354 )
4455}
Modified view/auth/src/pages/reset-sent/ui/reset-sent-page.tsx view/auth/src/pages/reset-sent/ui/reset-sent-page.tsx +13 −9 View view/auth/src/pages/reset-sent/ui/reset-sent-page.tsx
@@ -3,7 +3,8 @@
33import { routes } from '@/shared/config'
44import { t } from '@/shared/i18n'
55import { navigate } from '@/shared/lib'
6import { Alert, Button, FlowRequired, Heading, Link } from '@/shared/ui'
6import { Button, FlowRequired, Heading, Link } from '@/shared/ui'
7import { AuthPanel } from '@/widgets/auth-panel'
78
89export function ResetSentPage() {
910 const model = useResendResetEmail()
@@ -19,9 +20,16 @@
1920 />
2021 )
2122 return (
22 <>
23 <Heading title={t('resetSent.title')} description={t('resetSent.description')} icon={MailCheck} />
24 <Alert notice={model.task.notice} />
23 <AuthPanel
24 heading={<Heading title={t('resetSent.title')} description={t('resetSent.description')} icon={MailCheck} />}
25 notice={model.task.notice}
26 footer={
27 <div className="mt-6 flex items-center justify-center gap-1 text-xs">
28 <span className="text-muted">{t('resetSent.wrongEmail')}</span>
29 <Link to={routes.forgotPassword}>{t('resetSent.changeEmail')}</Link>
30 </div>
31 }
32 >
2533 <p className="mb-6 text-center font-latin text-sm font-medium wrap-anywhere">{model.email}</p>
2634 <p className="text-center text-xs leading-[1.65] text-muted">{t('resetSent.hint')}</p>
2735 <div className="mt-6">
@@ -30,10 +38,6 @@
3038 </Button>
3139 </div>
3240 <ResetSentActions model={model} />
33 <div className="mt-6 flex items-center justify-center gap-1 text-xs">
34 <span className="text-muted">{t('resetSent.wrongEmail')}</span>
35 <Link to={routes.forgotPassword}>{t('resetSent.changeEmail')}</Link>
36 </div>
37 </>
41 </AuthPanel>
3842 )
3943}
Renamed view/auth/src/shared/ui/button.tsx → view/auth/src/shared/ui/atoms/button.tsx view/auth/src/shared/ui/atoms/button.tsx +0 −0 View view/auth/src/shared/ui/atoms/button.tsx
No content changes.
Renamed view/auth/src/shared/ui/link.tsx → view/auth/src/shared/ui/atoms/link.tsx view/auth/src/shared/ui/atoms/link.tsx +0 −0 View view/auth/src/shared/ui/atoms/link.tsx
No content changes.
Renamed view/auth/src/shared/ui/retry-hint.tsx → view/auth/src/shared/ui/atoms/retry-hint.tsx view/auth/src/shared/ui/atoms/retry-hint.tsx +0 −0 View view/auth/src/shared/ui/atoms/retry-hint.tsx
No content changes.
Renamed view/auth/src/shared/ui/alert.tsx → view/auth/src/shared/ui/molecules/alert.tsx view/auth/src/shared/ui/molecules/alert.tsx +0 −0 View view/auth/src/shared/ui/molecules/alert.tsx
No content changes.
Renamed view/auth/src/shared/ui/back-link.tsx → view/auth/src/shared/ui/molecules/back-link.tsx view/auth/src/shared/ui/molecules/back-link.tsx +1 −1 View view/auth/src/shared/ui/molecules/back-link.tsx
@@ -2,7 +2,7 @@
22import type { ReactNode } from 'react'
33import { routes } from '@/shared/config'
44import { t } from '@/shared/i18n'
5import { Link } from './link'
5import { Link } from '../atoms/link'
66
77export function BackLink({
88 to = routes.login,
Renamed view/auth/src/shared/ui/birth-date.tsx → view/auth/src/shared/ui/molecules/birth-date.tsx view/auth/src/shared/ui/molecules/birth-date.tsx +0 −0 View view/auth/src/shared/ui/molecules/birth-date.tsx
No content changes.
Added view/auth/src/shared/ui/molecules/email-summary.tsx view/auth/src/shared/ui/molecules/email-summary.tsx +18 −0 View view/auth/src/shared/ui/molecules/email-summary.tsx
@@ -0,0 +1,18 @@
1import type { ReactNode } from 'react'
2
3export function EmailSummary({
4 email,
5 action,
6 className = 'mb-6',
7}: {
8 email: string
9 action?: ReactNode
10 className?: string
11}) {
12 return (
13 <div className={`${className} flex flex-wrap items-center justify-center gap-2`.trim()}>
14 <span className="max-w-full font-latin text-sm font-medium wrap-anywhere">{email}</span>
15 {action}
16 </div>
17 )
18}
Renamed view/auth/src/shared/ui/field.tsx → view/auth/src/shared/ui/molecules/field.tsx view/auth/src/shared/ui/molecules/field.tsx +0 −0 View view/auth/src/shared/ui/molecules/field.tsx
No content changes.
Renamed view/auth/src/shared/ui/form-navigation.tsx → view/auth/src/shared/ui/molecules/form-navigation.tsx view/auth/src/shared/ui/molecules/form-navigation.tsx +1 −1 View view/auth/src/shared/ui/molecules/form-navigation.tsx
@@ -1,4 +1,4 @@
1import { Link } from './link'
1import { Link } from '../atoms/link'
22
33export function FormNavigation({ prompt, action, to }: { prompt: string; action: string; to: string }) {
44 return (
Renamed view/auth/src/shared/ui/otp.tsx → view/auth/src/shared/ui/molecules/otp.tsx view/auth/src/shared/ui/molecules/otp.tsx +0 −0 View view/auth/src/shared/ui/molecules/otp.tsx
No content changes.
Renamed view/auth/src/shared/ui/resend-button.tsx → view/auth/src/shared/ui/molecules/resend-button.tsx view/auth/src/shared/ui/molecules/resend-button.tsx +0 −0 View view/auth/src/shared/ui/molecules/resend-button.tsx
No content changes.
Renamed view/auth/src/shared/ui/agreement.tsx → view/auth/src/shared/ui/organisms/agreement.tsx view/auth/src/shared/ui/organisms/agreement.tsx +0 −0 View view/auth/src/shared/ui/organisms/agreement.tsx
No content changes.
Added view/auth/src/shared/ui/organisms/auth-form.tsx view/auth/src/shared/ui/organisms/auth-form.tsx +42 −0 View view/auth/src/shared/ui/organisms/auth-form.tsx
@@ -0,0 +1,42 @@
1import type { ReactNode } from 'react'
2import { Button } from '../atoms/button'
3import { RetryHint } from '../atoms/retry-hint'
4
5export function AuthForm({
6 ariaLabel,
7 onSubmit,
8 busy,
9 submitLabel,
10 submitDisabled = false,
11 submitClassName = '',
12 retry = 0,
13 children,
14}: {
15 ariaLabel?: string
16 onSubmit: () => void
17 busy: boolean
18 submitLabel: ReactNode
19 submitDisabled?: boolean
20 submitClassName?: string
21 retry?: number
22 children: ReactNode
23}) {
24 return (
25 <form
26 noValidate
27 aria-label={ariaLabel}
28 onSubmit={(event) => {
29 event.preventDefault()
30 onSubmit()
31 }}
32 >
33 {children}
34 <div className={submitClassName}>
35 <Button busy={busy} disabled={retry > 0 || submitDisabled}>
36 {submitLabel}
37 </Button>
38 </div>
39 <RetryHint seconds={retry} />
40 </form>
41 )
42}
Renamed view/auth/src/shared/ui/flow-required.tsx → view/auth/src/shared/ui/organisms/flow-required.tsx view/auth/src/shared/ui/organisms/flow-required.tsx +1 −1 View view/auth/src/shared/ui/organisms/flow-required.tsx
@@ -1,6 +1,6 @@
11import type { LucideIcon } from 'lucide-react'
22import { navigate } from '@/shared/lib'
3import { Button } from './button'
3import { Button } from '../atoms/button'
44import { Heading } from './heading'
55
66export function FlowRequired({
Renamed view/auth/src/shared/ui/heading.tsx → view/auth/src/shared/ui/organisms/heading.tsx view/auth/src/shared/ui/organisms/heading.tsx +0 −0 View view/auth/src/shared/ui/organisms/heading.tsx
No content changes.
Renamed view/auth/src/shared/ui/legal-link.tsx → view/auth/src/shared/ui/organisms/legal-link.tsx view/auth/src/shared/ui/organisms/legal-link.tsx +1 −1 View view/auth/src/shared/ui/organisms/legal-link.tsx
@@ -1,6 +1,6 @@
11import { useRef } from 'react'
22import { t } from '@/shared/i18n'
3import { Button } from './button'
3import { Button } from '../atoms/button'
44
55export function LegalLink({ kind }: { kind: 'terms' | 'privacy' }) {
66 const ref = useRef<HTMLDialogElement>(null)
Added view/auth/src/shared/ui/organisms/session-check.tsx view/auth/src/shared/ui/organisms/session-check.tsx +19 −0 View view/auth/src/shared/ui/organisms/session-check.tsx
@@ -0,0 +1,19 @@
1import { t } from '@/shared/i18n'
2import type { Notice } from '@/shared/lib'
3import { Button } from '../atoms/button'
4import { Alert } from '../molecules/alert'
5import { Heading } from './heading'
6
7export function SessionCheck({ loading, notice, onRetry }: { loading: boolean; notice?: Notice; onRetry: () => void }) {
8 return (
9 <>
10 <Heading title={t('account.checking')} />
11 <Alert notice={notice} />
12 {!loading && notice && (
13 <Button type="button" onClick={onRetry}>
14 {t('common.retry')}
15 </Button>
16 )}
17 </>
18 )
19}
Modified view/auth/src/shared/ui/index.ts view/auth/src/shared/ui/index.ts +19 −16 View view/auth/src/shared/ui/index.ts
@@ -1,16 +1,19 @@
1export { Agreement } from './agreement'
2export { Alert } from './alert'
3export { BackLink } from './back-link'
4export type { BirthValue } from './birth-date'
5export { BirthDate, emptyBirth } from './birth-date'
6export { Button } from './button'
7export type { FieldProps } from './field'
8export { Field } from './field'
9export { FlowRequired } from './flow-required'
10export { FormNavigation } from './form-navigation'
11export { Heading } from './heading'
12export { LegalLink } from './legal-link'
13export { Link } from './link'
14export { Otp } from './otp'
15export { ResendButton } from './resend-button'
16export { RetryHint } from './retry-hint'
1export { Button } from './atoms/button'
2export { Link } from './atoms/link'
3export { RetryHint } from './atoms/retry-hint'
4export { Alert } from './molecules/alert'
5export { BackLink } from './molecules/back-link'
6export type { BirthValue } from './molecules/birth-date'
7export { BirthDate, emptyBirth } from './molecules/birth-date'
8export { EmailSummary } from './molecules/email-summary'
9export type { FieldProps } from './molecules/field'
10export { Field } from './molecules/field'
11export { FormNavigation } from './molecules/form-navigation'
12export { Otp } from './molecules/otp'
13export { ResendButton } from './molecules/resend-button'
14export { Agreement } from './organisms/agreement'
15export { AuthForm } from './organisms/auth-form'
16export { FlowRequired } from './organisms/flow-required'
17export { Heading } from './organisms/heading'
18export { LegalLink } from './organisms/legal-link'
19export { SessionCheck } from './organisms/session-check'
Added view/auth/src/widgets/auth-panel/ui/auth-panel.tsx view/auth/src/widgets/auth-panel/ui/auth-panel.tsx +24 −0 View view/auth/src/widgets/auth-panel/ui/auth-panel.tsx
@@ -0,0 +1,24 @@
1import type { ReactNode } from 'react'
2import type { Notice } from '@/shared/lib'
3import { Alert } from '@/shared/ui'
4
5export function AuthPanel({
6 heading,
7 notice,
8 children,
9 footer,
10}: {
11 heading: ReactNode
12 notice?: Notice
13 children: ReactNode
14 footer?: ReactNode
15}) {
16 return (
17 <>
18 {heading}
19 <Alert notice={notice} />
20 {children}
21 {footer}
22 </>
23 )
24}
Added view/auth/src/widgets/auth-panel/index.ts view/auth/src/widgets/auth-panel/index.ts +1 −0 View view/auth/src/widgets/auth-panel/index.ts
@@ -0,0 +1 @@
1export { AuthPanel } from './ui/auth-panel'
Modified Dockerfile Dockerfile +1 −1 View Dockerfile
@@ -30,7 +30,7 @@
3030COPY openapi.json ./
3131COPY scripts ./scripts
3232COPY vite.config.ts tsconfig.json tsconfig.app.json tsconfig.node.json \
33 orval.config.ts steiger.config.ts biome.json ./
33 orval.config.ts biome.json ./
3434# 契约闸门:生成客户端必须与提交的 packages/apiclient 一致。
3535RUN bash scripts/contract-check.sh --client-only
3636RUN pnpm build
Modified package.json package.json +0 −5 View package.json
@@ -7,9 +7,6 @@
77 "dev": "vite",
88 "build": "tsc -b && vite build",
99 "typecheck": "tsc -b",
10 "lint": "steiger view/auth/src",
11 "lint:fsd": "steiger view/auth/src",
12 "lint:fsd:strict": "steiger view/auth/src --fail-on-warnings",
1310 "preview": "vite preview",
1411 "format": "biome format --write .",
1512 "format:check": "biome format .",
@@ -26,7 +23,6 @@
2623 },
2724 "devDependencies": {
2825 "@biomejs/biome": "^2.5.15",
29 "@feature-sliced/steiger-plugin": "0.8.0",
3026 "@tailwindcss/vite": "^4.3.3",
3127 "@types/node": "^24.13.3",
3228 "@types/react": "^19.3.0",
@@ -34,7 +30,6 @@
3430 "@vitejs/plugin-react": "^6.1.2",
3531 "orval": "^8.43.0",
3632 "prettier": "^3.6.2",
37 "steiger": "0.7.0",
3833 "typescript": "~6.0.2",
3934 "vite": "^8.3.0"
4035 }
Modified pnpm-lock.yaml pnpm-lock.yaml +2 −525 View pnpm-lock.yaml
@@ -30,9 +30,6 @@
3030 '@biomejs/biome':
3131 specifier: ^2.5.15
3232 version: 2.5.15
33 '@feature-sliced/steiger-plugin':
34 specifier: 0.8.0
35 version: 0.8.0(typescript@6.0.3)
3633 '@tailwindcss/vite':
3734 specifier: ^4.3.3
3835 version: 4.3.3(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(yaml@2.9.1))
@@ -54,9 +51,6 @@
5451 prettier:
5552 specifier: ^3.6.2
5653 version: 3.9.10
57 steiger:
58 specifier: 0.7.0
59 version: 0.7.0(typescript@6.0.3)
6054 typescript:
6155 specifier: ~6.0.2
6256 version: 6.0.3
@@ -123,12 +117,6 @@
123117 cpu: [x64]
124118 os: [win32]
125119
126 '@clack/core@0.4.1':
127 resolution: {integrity: sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==}
128
129 '@clack/prompts@0.9.1':
130 resolution: {integrity: sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==}
131
132120 '@commander-js/extra-typings@15.0.0':
133121 resolution: {integrity: sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==}
134122 peerDependencies:
@@ -290,12 +278,6 @@
290278 cpu: [x64]
291279 os: [win32]
292280
293 '@feature-sliced/filesystem@3.1.1':
294 resolution: {integrity: sha512-P3WpHkOqdH4572ZhTfeg/Sbw0qkIuMw0QcLyTUygfwTZg1yd7hIv8QDYbhTddNTiFDgBRJTrYw/s6r2hnlo6Tw==}
295
296 '@feature-sliced/steiger-plugin@0.8.0':
297 resolution: {integrity: sha512-wACwEYLVxs6bziUDaZXlp6k43dantdU5MSBtO48MwonwrupdzYcLhs6+Ps9YoWDINccaAlqiMxlHmgLJubK5Ow==}
298
299281 '@fontsource-variable/geist@5.3.0':
300282 resolution: {integrity: sha512-j0m+vLQuG5XAYoHtGCVu0spvlGreR3EzpECUVzkFmI1mTVnAO38l/NEPDCFgZ177JxzYJCLSmTQibIiYPilGrA==}
301283
@@ -322,18 +304,6 @@
322304 resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==}
323305 engines: {node: '>= 20.19.0'}
324306
325 '@nodelib/fs.scandir@2.1.5':
326 resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
327 engines: {node: '>= 8'}
328
329 '@nodelib/fs.stat@2.0.5':
330 resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
331 engines: {node: '>= 8'}
332
333 '@nodelib/fs.walk@1.2.8':
334 resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
335 engines: {node: '>= 8'}
336
337307 '@orval/angular@8.43.0':
338308 resolution: {integrity: sha512-IxDrLrm2lORBsIQt01f4fDM8P/qXuDC8qB66FABxFy8znUXre+bNZBAIeB9IwwH0A4tnPgIKM67uqaXne8qahQ==}
339309
@@ -729,43 +699,13 @@
729699 ajv@8.20.0:
730700 resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==}
731701
732 ansi-regex@5.0.1:
733 resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
734 engines: {node: '>=8'}
735
736 ansi-styles@4.3.0:
737 resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
738 engines: {node: '>=8'}
739
740702 argparse@2.0.1:
741703 resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
742704
743 argparse@3.0.3:
744 resolution: {integrity: sha512-Sn98ftV3KfsO8xfLPHG6oT8y+b0yvbrLgZjgPDXsharNY15tTAjqIsIju4S32nl6/iEUNNE4v+yL2Zhm8ooP3w==}
745
746 braces@3.0.3:
747 resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
748 engines: {node: '>=8'}
749
750 chokidar@4.0.3:
751 resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
752 engines: {node: '>= 14.16.0'}
753
754705 chokidar@5.0.0:
755706 resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
756707 engines: {node: '>= 20.19.0'}
757708
758 cliui@8.0.1:
759 resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
760 engines: {node: '>=12'}
761
762 color-convert@2.0.1:
763 resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
764 engines: {node: '>=7.0.0'}
765
766 color-name@1.1.4:
767 resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
768
769709 commander@15.0.0:
770710 resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==}
771711 engines: {node: '>=22.12.0'}
@@ -773,10 +713,6 @@
773713 compare-versions@6.1.1:
774714 resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
775715
776 cosmiconfig@10.0.1:
777 resolution: {integrity: sha512-/zvGoYn0y27QTBmK+0B+oPdEPC4fKGUmJsMTQbDjqph00TrkqfVFW/M+C6ya54sYCgHC6QCwK/mI6djt8cEGHQ==}
778 engines: {node: ^22.18 || >= 24}
779
780716 cross-spawn@7.0.6:
781717 resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
782718 engines: {node: '>= 8'}
@@ -788,34 +724,15 @@
788724 resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
789725 engines: {node: '>=8'}
790726
791 effector@23.4.4:
792 resolution: {integrity: sha512-QkZboRN28K/iwxigDhlJcI3ux3aNbt8kYGGH/GkqWG0OlGeyuBhb7PdM89Iu+ogV8Lmz16xIlwnXR2UNWI6psg==}
793 engines: {node: '>=11.0.0'}
794
795 emoji-regex@8.0.0:
796 resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
797
798 empathic@1.1.0:
799 resolution: {integrity: sha512-rsPft6CK3eHtrlp9Y5ALBb+hfK+DWnA4WFebbazxjWyx8vSm3rZeoM3z9irsjcqO3PYRzlfv27XIB4tz2DV7RA==}
800 engines: {node: '>=14'}
801
802727 enhanced-resolve@5.26.0:
803728 resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==}
804729 engines: {node: '>=10.13.0'}
805730
806 env-paths@2.2.1:
807 resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
808 engines: {node: '>=6'}
809
810731 esbuild@0.28.2:
811732 resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==}
812733 engines: {node: '>=18'}
813734 hasBin: true
814735
815 escalade@3.2.0:
816 resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
817 engines: {node: '>=6'}
818
819736 esutils@2.0.3:
820737 resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
821738 engines: {node: '>=0.10.0'}
@@ -827,20 +744,9 @@
827744 fast-deep-equal@3.1.3:
828745 resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
829746
830 fast-glob@3.3.3:
831 resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
832 engines: {node: '>=8.6.0'}
833
834747 fast-uri@3.1.9:
835748 resolution: {integrity: sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==}
836749
837 fastest-levenshtein@1.0.16:
838 resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==}
839 engines: {node: '>= 4.9.1'}
840
841 fastq@1.20.3:
842 resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==}
843
844750 fdir@6.5.0:
845751 resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
846752 engines: {node: '>=12.0.0'}
@@ -854,19 +760,11 @@
854760 resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
855761 engines: {node: '>=18'}
856762
857 fill-range@7.1.1:
858 resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
859 engines: {node: '>=8'}
860
861763 fsevents@2.3.3:
862764 resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
863765 engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
864766 os: [darwin]
865767
866 get-caller-file@2.0.5:
867 resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
868 engines: {node: 6.* || 8.* || >= 10.*}
869
870768 get-stream@9.0.1:
871769 resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
872770 engines: {node: '>=18'}
@@ -874,14 +772,6 @@
874772 get-tsconfig@4.14.3:
875773 resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==}
876774
877 glob-parent@5.1.2:
878 resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
879 engines: {node: '>= 6'}
880
881 globby@16.2.4:
882 resolution: {integrity: sha512-c8B/VNLmxRcmqqenRA9t+9IyOjf9+V6lTxPaUJLqOCONdQkWZ0ETYgX0qbtJqPsgCNusT9MZ5Jeidw8Eb9tn2g==}
883 engines: {node: '>=20'}
884
885775 graceful-fs@4.2.11:
886776 resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
887777
@@ -889,33 +779,6 @@
889779 resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
890780 engines: {node: '>=18.18.0'}
891781
892 ignore@7.0.13:
893 resolution: {integrity: sha512-2E8Q6rh+1RRSq/YdaGsNfXsEZy9FVqv6BSSrkmZJP7BnaoPnRfKL+YaofPvP+5rzdk144qSm6i4+hvPgUcbV4Q==}
894 engines: {node: '>= 4'}
895
896 immer@10.2.0:
897 resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
898
899 is-extglob@2.1.1:
900 resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
901 engines: {node: '>=0.10.0'}
902
903 is-fullwidth-code-point@3.0.0:
904 resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
905 engines: {node: '>=8'}
906
907 is-glob@4.0.3:
908 resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
909 engines: {node: '>=0.10.0'}
910
911 is-number@7.0.0:
912 resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
913 engines: {node: '>=0.12.0'}
914
915 is-path-inside@4.0.0:
916 resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
917 engines: {node: '>=12'}
918
919782 is-plain-obj@4.1.0:
920783 resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
921784 engines: {node: '>=12'}
@@ -939,10 +802,6 @@
939802 resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==}
940803 hasBin: true
941804
942 js-yaml@5.5.0:
943 resolution: {integrity: sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg==}
944 hasBin: true
945
946805 jsesc@3.1.0:
947806 resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
948807 engines: {node: '>=6'}
@@ -1104,9 +963,6 @@
1104963 resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
1105964 engines: {node: '>= 12.0.0'}
1106965
1107 lodash-es@4.18.1:
1108 resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
1109
1110966 lucide-react@1.66.0:
1111967 resolution: {integrity: sha512-8zjbi/Us+ETXqfBwmXF/FHrWGIqOdE6zT1yUdRJLQVoptomSkB0zdFWVIM667t9K8djWDaXdkBkqi2qVTuDNiw==}
1112968 peerDependencies:
@@ -1119,14 +975,6 @@
1119975 magic-string@0.30.21:
1120976 resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
1121977
1122 merge2@1.4.1:
1123 resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
1124 engines: {node: '>= 8'}
1125
1126 micromatch@4.0.8:
1127 resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
1128 engines: {node: '>=8.6'}
1129
1130978 nanoid@3.3.20:
1131979 resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==}
1132980 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -1172,26 +1020,13 @@
11721020 pathe@2.0.3:
11731021 resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
11741022
1175 patronum@2.3.0:
1176 resolution: {integrity: sha512-BfKIOpoymVz6XnkOn8Fi5QZ1a3r/3lXdd8BcdHmYDbIXPTIRnD1EPFBFev/DheWnOge6/ZswEqgNF2ANLGOxLw==}
1177 peerDependencies:
1178 effector: ^23
1179
11801023 picocolors@1.1.1:
11811024 resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
11821025
1183 picomatch@2.3.2:
1184 resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
1185 engines: {node: '>=8.6'}
1186
11871026 picomatch@4.0.7:
11881027 resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==}
11891028 engines: {node: '>=12'}
11901029
1191 pluralize@8.0.0:
1192 resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
1193 engines: {node: '>=4'}
1194
11951030 postcss@8.5.31:
11961031 resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==}
11971032 engines: {node: ^10 || ^12 || >=14}
@@ -1205,13 +1040,6 @@
12051040 resolution: {integrity: sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==}
12061041 engines: {node: '>=18'}
12071042
1208 prexit@2.3.0:
1209 resolution: {integrity: sha512-mX+LIbtS0anKtl2PykYabxninwloblUQMRO6CubeSmjxb+kKlATuJoH9UeN8NLE4TgIEFWfBXw7V3GkWbBrSmg==}
1210 engines: {node: '>=12'}
1211
1212 queue-microtask@1.2.3:
1213 resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
1214
12151043 react-dom@19.3.1:
12161044 resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==}
12171045 peerDependencies:
@@ -1221,18 +1049,10 @@
12211049 resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==}
12221050 engines: {node: '>=0.10.0'}
12231051
1224 readdirp@4.1.2:
1225 resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
1226 engines: {node: '>= 14.18.0'}
1227
12281052 readdirp@5.1.1:
12291053 resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==}
12301054 engines: {node: '>= 20.19.0'}
12311055
1232 require-directory@2.1.1:
1233 resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
1234 engines: {node: '>=0.10.0'}
1235
12361056 require-from-string@2.0.2:
12371057 resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
12381058 engines: {node: '>=0.10.0'}
@@ -1240,18 +1060,11 @@
12401060 resolve-pkg-maps@1.0.0:
12411061 resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
12421062
1243 reusify@1.1.0:
1244 resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
1245 engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1246
12471063 rolldown@1.2.14:
12481064 resolution: {integrity: sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw==}
12491065 engines: {node: ^20.19.0 || >=22.12.0}
12501066 hasBin: true
12511067
1252 run-parallel@1.2.0:
1253 resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
1254
12551068 scheduler@0.28.0:
12561069 resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==}
12571070
@@ -1267,34 +1080,14 @@
12671080 resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
12681081 engines: {node: '>=14'}
12691082
1270 sisteransi@1.0.5:
1271 resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
1272
1273 slash@5.1.0:
1274 resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
1275 engines: {node: '>=14.16'}
1276
12771083 source-map-js@1.2.2:
12781084 resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==}
12791085 engines: {node: '>=0.10.0'}
12801086
1281 steiger@0.7.0:
1282 resolution: {integrity: sha512-KXqt/6LqQE5O9QhJ9ZsA4M/Nwys6pslryXk67PltNZ8UBzbV9X9PEwMqskEdOObgnHsb+hEOzPH1UbSGFMuRYg==}
1283 engines: {node: '>=22.18.0'}
1284 hasBin: true
1285
12861087 string-argv@0.3.2:
12871088 resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
12881089 engines: {node: '>=0.6.19'}
12891090
1290 string-width@4.2.3:
1291 resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
1292 engines: {node: '>=8'}
1293
1294 strip-ansi@6.0.1:
1295 resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
1296 engines: {node: '>=8'}
1297
12981091 strip-final-newline@4.0.0:
12991092 resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
13001093 engines: {node: '>=18'}
@@ -1314,30 +1107,10 @@
13141107 resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
13151108 engines: {node: '>=12.0.0'}
13161109
1317 to-regex-range@5.0.1:
1318 resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1319 engines: {node: '>=8.0'}
1320
1321 tsconfck@3.1.6:
1322 resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
1323 engines: {node: ^18 || >=20}
1324 deprecated: unmaintained
1325 hasBin: true
1326 peerDependencies:
1327 typescript: ^5.0.0
1328 peerDependenciesMeta:
1329 typescript:
1330 optional: true
1331
13321110 type-fest@5.10.0:
13331111 resolution: {integrity: sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==}
13341112 engines: {node: '>=20'}
13351113
1336 typescript@5.9.3:
1337 resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
1338 engines: {node: '>=14.17'}
1339 hasBin: true
1340
13411114 typescript@6.0.3:
13421115 resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
13431116 engines: {node: '>=14.17'}
@@ -1358,10 +1131,6 @@
13581131 resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
13591132 engines: {node: '>=18'}
13601133
1361 unicorn-magic@0.4.1:
1362 resolution: {integrity: sha512-lzlXPoVB0Uy/FvTaUgX39RbixYiSKoc3JSoSf01+0c2B6FR3qdYIPN7Qjo/AV7n6sqLCk0509cT3LRj1oSZ1+A==}
1363 engines: {node: '>=20'}
1364
13651134 vite@8.3.4:
13661135 resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==}
13671136 engines: {node: ^20.19.0 || >=22.12.0}
@@ -1405,59 +1174,20 @@
14051174 yaml:
14061175 optional: true
14071176
1408 vscode-jsonrpc@9.0.3:
1409 resolution: {integrity: sha512-qETYf9PCl1lVfwR+oBmMfc4vP2nqLNA35ABxorw3j06+xlKRgDVxbLgKm4Y/xPL0YWdeDjLoI4ImICIT3nB0zQ==}
1410 engines: {node: '>=14.0.0'}
1411
1412 vscode-languageserver-protocol@3.18.4:
1413 resolution: {integrity: sha512-CCXbyr99dafRJzJH/0Ryk7ly5T8XPmSR0//OuF2w4m+9JiOin7zcAT5iET8GRE7Z9taFBejb3GbM0a0mbjdbrg==}
1414
1415 vscode-languageserver-types@3.18.4:
1416 resolution: {integrity: sha512-nQsacoiijvl0fRf2q28uFDrAVwRhdCa3QveiF7/CX0r18mLR5FU/1WskSsCKOjmEbtteKUnY8x8Yzxop+k0zwg==}
1417
1418 vscode-languageserver@10.1.2:
1419 resolution: {integrity: sha512-pXPWde3RytdeBVEs6PulOOT5OpeXC5GkWRpcT11f5rNn41jviQsAYPyAqJ/0oVGETQLKPJtYbHNiMPlfLb0NTQ==}
1420 hasBin: true
1421
1422 web-tree-sitter@0.26.13:
1423 resolution: {integrity: sha512-5bUZ7vbQ1kcondet96wzP974+JfCZDeQ7bTpacICm2nnvHpa5cO0ByRsoMcAhUP+743vpkb4m0BFlVSm+Ye9VA==}
1424
14251177 which@2.0.2:
14261178 resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
14271179 engines: {node: '>= 8'}
14281180 hasBin: true
14291181
1430 wrap-ansi@7.0.0:
1431 resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
1432 engines: {node: '>=10'}
1433
1434 y18n@5.0.8:
1435 resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
1436 engines: {node: '>=10'}
1437
14381182 yaml@2.9.1:
14391183 resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==}
14401184 engines: {node: '>= 14.6'}
14411185 hasBin: true
14421186
1443 yargs-parser@21.1.1:
1444 resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
1445 engines: {node: '>=12'}
1446
1447 yargs@17.7.3:
1448 resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==}
1449 engines: {node: '>=12'}
1450
14511187 yoctocolors@2.2.0:
14521188 resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==}
14531189 engines: {node: '>=18'}
14541190
1455 zod-validation-error@3.5.4:
1456 resolution: {integrity: sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==}
1457 engines: {node: '>=18.0.0'}
1458 peerDependencies:
1459 zod: ^3.24.4
1460
14611191 zod@3.25.76:
14621192 resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
14631193
@@ -1501,17 +1231,6 @@
15011231 '@biomejs/cli-win32-x64@2.5.15':
15021232 optional: true
15031233
1504 '@clack/core@0.4.1':
1505 dependencies:
1506 picocolors: 1.1.1
1507 sisteransi: 1.0.5
1508
1509 '@clack/prompts@0.9.1':
1510 dependencies:
1511 '@clack/core': 0.4.1
1512 picocolors: 1.1.1
1513 sisteransi: 1.0.5
1514
15151234 '@commander-js/extra-typings@15.0.0(commander@15.0.0)':
15161235 dependencies:
15171236 commander: 15.0.0
@@ -1594,21 +1313,6 @@
15941313 '@esbuild/win32-x64@0.28.2':
15951314 optional: true
15961315
1597 '@feature-sliced/filesystem@3.1.1':
1598 dependencies:
1599 typescript: 5.9.3
1600
1601 '@feature-sliced/steiger-plugin@0.8.0(typescript@6.0.3)':
1602 dependencies:
1603 '@feature-sliced/filesystem': 3.1.1
1604 fastest-levenshtein: 1.0.16
1605 lodash-es: 4.18.1
1606 pluralize: 8.0.0
1607 tsconfck: 3.1.6(typescript@6.0.3)
1608 web-tree-sitter: 0.26.13
1609 transitivePeerDependencies:
1610 - typescript
1611
16121316 '@fontsource-variable/geist@5.3.0': {}
16131317
16141318 '@fontsource-variable/noto-sans-sc@5.3.1': {}
@@ -1634,18 +1338,6 @@
16341338
16351339 '@noble/hashes@2.4.0': {}
16361340
1637 '@nodelib/fs.scandir@2.1.5':
1638 dependencies:
1639 '@nodelib/fs.stat': 2.0.5
1640 run-parallel: 1.2.0
1641
1642 '@nodelib/fs.stat@2.0.5': {}
1643
1644 '@nodelib/fs.walk@1.2.8':
1645 dependencies:
1646 '@nodelib/fs.scandir': 2.1.5
1647 fastq: 1.20.3
1648
16491341 '@orval/angular@8.43.0':
16501342 dependencies:
16511343 '@orval/core': 8.43.0
@@ -1968,49 +1660,16 @@
19681660 json-schema-traverse: 1.0.0
19691661 require-from-string: 2.0.2
19701662
1971 ansi-regex@5.0.1: {}
1972
1973 ansi-styles@4.3.0:
1974 dependencies:
1975 color-convert: 2.0.1
1976
19771663 argparse@2.0.1: {}
19781664
1979 argparse@3.0.3: {}
1980
1981 braces@3.0.3:
1982 dependencies:
1983 fill-range: 7.1.1
1984
1985 chokidar@4.0.3:
1986 dependencies:
1987 readdirp: 4.1.2
1988
19891665 chokidar@5.0.0:
19901666 dependencies:
19911667 readdirp: 5.1.1
19921668
1993 cliui@8.0.1:
1994 dependencies:
1995 string-width: 4.2.3
1996 strip-ansi: 6.0.1
1997 wrap-ansi: 7.0.0
1998
1999 color-convert@2.0.1:
2000 dependencies:
2001 color-name: 1.1.4
2002
2003 color-name@1.1.4: {}
2004
20051669 commander@15.0.0: {}
20061670
20071671 compare-versions@6.1.1: {}
20081672
2009 cosmiconfig@10.0.1:
2010 dependencies:
2011 env-paths: 2.2.1
2012 js-yaml: 5.5.0
2013
20141673 cross-spawn@7.0.6:
20151674 dependencies:
20161675 path-key: 3.1.1
@@ -2021,19 +1680,11 @@
20211680
20221681 detect-libc@2.1.2: {}
20231682
2024 effector@23.4.4: {}
2025
2026 emoji-regex@8.0.0: {}
2027
2028 empathic@1.1.0: {}
2029
20301683 enhanced-resolve@5.26.0:
20311684 dependencies:
20321685 graceful-fs: 4.2.11
20331686 tapable: 2.3.3
20341687
2035 env-paths@2.2.1: {}
2036
20371688 esbuild@0.28.2:
20381689 optionalDependencies:
20391690 '@esbuild/aix-ppc64': 0.28.2
@@ -2063,8 +1714,6 @@
20631714 '@esbuild/win32-ia32': 0.28.2
20641715 '@esbuild/win32-x64': 0.28.2
20651716
2066 escalade@3.2.0: {}
2067
20681717 esutils@2.0.3: {}
20691718
20701719 execa@9.6.1:
@@ -2084,22 +1733,8 @@
20841733
20851734 fast-deep-equal@3.1.3: {}
20861735
2087 fast-glob@3.3.3:
2088 dependencies:
2089 '@nodelib/fs.stat': 2.0.5
2090 '@nodelib/fs.walk': 1.2.8
2091 glob-parent: 5.1.2
2092 merge2: 1.4.1
2093 micromatch: 4.0.8
2094
20951736 fast-uri@3.1.9: {}
20961737
2097 fastest-levenshtein@1.0.16: {}
2098
2099 fastq@1.20.3:
2100 dependencies:
2101 reusify: 1.1.0
2102
21031738 fdir@6.5.0(picomatch@4.0.7):
21041739 optionalDependencies:
21051740 picomatch: 4.0.7
@@ -2108,15 +1743,9 @@
21081743 dependencies:
21091744 is-unicode-supported: 2.1.0
21101745
2111 fill-range@7.1.1:
2112 dependencies:
2113 to-regex-range: 5.0.1
2114
21151746 fsevents@2.3.3:
21161747 optional: true
21171748
2118 get-caller-file@2.0.5: {}
2119
21201749 get-stream@9.0.1:
21211750 dependencies:
21221751 '@sec-ant/readable-stream': 0.4.1
@@ -2126,40 +1755,10 @@
21261755 dependencies:
21271756 resolve-pkg-maps: 1.0.0
21281757
2129 glob-parent@5.1.2:
2130 dependencies:
2131 is-glob: 4.0.3
2132
2133 globby@16.2.4:
2134 dependencies:
2135 '@sindresorhus/merge-streams': 4.0.0
2136 fast-glob: 3.3.3
2137 ignore: 7.0.13
2138 is-path-inside: 4.0.0
2139 micromatch: 4.0.8
2140 slash: 5.1.0
2141 unicorn-magic: 0.4.1
2142
21431758 graceful-fs@4.2.11: {}
21441759
21451760 human-signals@8.0.1: {}
21461761
2147 ignore@7.0.13: {}
2148
2149 immer@10.2.0: {}
2150
2151 is-extglob@2.1.1: {}
2152
2153 is-fullwidth-code-point@3.0.0: {}
2154
2155 is-glob@4.0.3:
2156 dependencies:
2157 is-extglob: 2.1.1
2158
2159 is-number@7.0.0: {}
2160
2161 is-path-inside@4.0.0: {}
2162
21631762 is-plain-obj@4.1.0: {}
21641763
21651764 is-stream@4.0.1: {}
@@ -2174,10 +1773,6 @@
21741773 dependencies:
21751774 argparse: 2.0.1
21761775
2177 js-yaml@5.5.0:
2178 dependencies:
2179 argparse: 3.0.3
2180
21811776 jsesc@3.1.0: {}
21821777
21831778 json-schema-traverse@1.0.0: {}
@@ -2282,8 +1877,6 @@
22821877 lightningcss-win32-arm64-msvc: 1.33.0
22831878 lightningcss-win32-x64-msvc: 1.33.0
22841879
2285 lodash-es@4.18.1: {}
2286
22871880 lucide-react@1.66.0(@types/react@19.3.0)(react@19.3.1):
22881881 dependencies:
22891882 react: 19.3.1
@@ -2294,13 +1887,6 @@
22941887 dependencies:
22951888 '@jridgewell/sourcemap-codec': 1.6.0
22961889
2297 merge2@1.4.1: {}
2298
2299 micromatch@4.0.8:
2300 dependencies:
2301 braces: 3.0.3
2302 picomatch: 2.3.2
2303
23041890 nanoid@3.3.20: {}
23051891
23061892 nanoid@5.1.16: {}
@@ -2361,19 +1947,11 @@
23611947 path-key@4.0.0: {}
23621948
23631949 pathe@2.0.3: {}
2364
2365 patronum@2.3.0(effector@23.4.4):
2366 dependencies:
2367 effector: 23.4.4
23681950
23691951 picocolors@1.1.1: {}
23701952
2371 picomatch@2.3.2: {}
2372
23731953 picomatch@4.0.7: {}
23741954
2375 pluralize@8.0.0: {}
2376
23771955 postcss@8.5.31:
23781956 dependencies:
23791957 nanoid: 3.3.20
@@ -2386,10 +1964,6 @@
23861964 dependencies:
23871965 parse-ms: 4.0.0
23881966
2389 prexit@2.3.0: {}
2390
2391 queue-microtask@1.2.3: {}
2392
23931967 react-dom@19.3.1(react@19.3.1):
23941968 dependencies:
23951969 react: 19.3.1
@@ -2397,18 +1971,12 @@
23971971
23981972 react@19.3.1: {}
23991973
2400 readdirp@4.1.2: {}
2401
24021974 readdirp@5.1.1: {}
24031975
2404 require-directory@2.1.1: {}
2405
24061976 require-from-string@2.0.2: {}
24071977
24081978 resolve-pkg-maps@1.0.0: {}
24091979
2410 reusify@1.1.0: {}
2411
24121980 rolldown@1.2.14:
24131981 dependencies:
24141982 '@oxc-project/types': 0.154.0
@@ -2430,10 +1998,6 @@
24301998 '@rolldown/binding-win32-arm64-msvc': 1.2.14
24311999 '@rolldown/binding-win32-x64-msvc': 1.2.14
24322000
2433 run-parallel@1.2.0:
2434 dependencies:
2435 queue-microtask: 1.2.3
2436
24372001 scheduler@0.28.0: {}
24382002
24392003 shebang-command@2.0.0:
@@ -2444,47 +2008,10 @@
24442008
24452009 signal-exit@4.1.0: {}
24462010
2447 sisteransi@1.0.5: {}
2448
2449 slash@5.1.0: {}
2450
24512011 source-map-js@1.2.2: {}
24522012
2453 steiger@0.7.0(typescript@6.0.3):
2454 dependencies:
2455 '@clack/prompts': 0.9.1
2456 '@feature-sliced/steiger-plugin': 0.8.0(typescript@6.0.3)
2457 chokidar: 4.0.3
2458 cosmiconfig: 10.0.1
2459 effector: 23.4.4
2460 empathic: 1.1.0
2461 fastest-levenshtein: 1.0.16
2462 globby: 16.2.4
2463 immer: 10.2.0
2464 lodash-es: 4.18.1
2465 micromatch: 4.0.8
2466 patronum: 2.3.0(effector@23.4.4)
2467 picocolors: 1.1.1
2468 prexit: 2.3.0
2469 vscode-languageserver: 10.1.2
2470 yargs: 17.7.3
2471 zod: 3.25.76
2472 zod-validation-error: 3.5.4(zod@3.25.76)
2473 transitivePeerDependencies:
2474 - typescript
2475
24762013 string-argv@0.3.2: {}
24772014
2478 string-width@4.2.3:
2479 dependencies:
2480 emoji-regex: 8.0.0
2481 is-fullwidth-code-point: 3.0.0
2482 strip-ansi: 6.0.1
2483
2484 strip-ansi@6.0.1:
2485 dependencies:
2486 ansi-regex: 5.0.1
2487
24882015 strip-final-newline@4.0.0: {}
24892016
24902017 tagged-tag@1.0.0: {}
@@ -2498,20 +2025,10 @@
24982025 fdir: 6.5.0(picomatch@4.0.7)
24992026 picomatch: 4.0.7
25002027
2501 to-regex-range@5.0.1:
2502 dependencies:
2503 is-number: 7.0.0
2504
2505 tsconfck@3.1.6(typescript@6.0.3):
2506 optionalDependencies:
2507 typescript: 6.0.3
2508
25092028 type-fest@5.10.0:
25102029 dependencies:
25112030 tagged-tag: 1.0.0
25122031
2513 typescript@5.9.3: {}
2514
25152032 typescript@6.0.3: {}
25162033
25172034 undici-types@7.24.6: {}
@@ -2522,8 +2039,6 @@
25222039
25232040 unicorn-magic@0.3.0: {}
25242041
2525 unicorn-magic@0.4.1: {}
2526
25272042 vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(yaml@2.9.1):
25282043 dependencies:
25292044 lightningcss: 1.33.0
@@ -2538,53 +2053,15 @@
25382053 jiti: 2.7.0
25392054 yaml: 2.9.1
25402055
2541 vscode-jsonrpc@9.0.3: {}
2542
2543 vscode-languageserver-protocol@3.18.4:
2544 dependencies:
2545 vscode-jsonrpc: 9.0.3
2546 vscode-languageserver-types: 3.18.4
2547
2548 vscode-languageserver-types@3.18.4: {}
2549
2550 vscode-languageserver@10.1.2:
2551 dependencies:
2552 vscode-languageserver-protocol: 3.18.4
2553
2554 web-tree-sitter@0.26.13: {}
2555
25562056 which@2.0.2:
25572057 dependencies:
25582058 isexe: 2.0.0
25592059
2560 wrap-ansi@7.0.0:
2561 dependencies:
2562 ansi-styles: 4.3.0
2563 string-width: 4.2.3
2564 strip-ansi: 6.0.1
2565
2566 y18n@5.0.8: {}
2567
25682060 yaml@2.9.1: {}
25692061
2570 yargs-parser@21.1.1: {}
2571
2572 yargs@17.7.3:
2573 dependencies:
2574 cliui: 8.0.1
2575 escalade: 3.2.0
2576 get-caller-file: 2.0.5
2577 require-directory: 2.1.1
2578 string-width: 4.2.3
2579 y18n: 5.0.8
2580 yargs-parser: 21.1.1
2581
25822062 yoctocolors@2.2.0: {}
25832063
2584 zod-validation-error@3.5.4(zod@3.25.76):
2585 dependencies:
2586 zod: 3.25.76
2587
2588 zod@3.25.76: {}
2064 zod@3.25.76:
2065 optional: true
25892066
25902067 zod@4.6.7: {}
Deleted PROJECT-CHECKPOINT.md PROJECT-CHECKPOINT.md +0 −18
@@ -1,18 +0,0 @@
1# Domain convergence checkpoint
2
3Goal: remove auth RPC, reorganize auth following 8fefadc, move SSH keys to user, unify identity HTTP, narrow domain capabilities, consolidate space access and cross-domain APIs, and centralize outbound delivery.
4
5Constraints: Git RPC implementation must not change. User authorized unlimited compilation and parallel agents. Preserve existing staged changes. No tests requested.
6
7| ID | Requirement | Priority | Status | Evidence |
8|---|---|---|---|---|
9| A | auth organization, RPC removal, SSH migration | P0 | COMPLETE | RPC implementations removed; Accounts replaces AuthApi; SSH lives in user; auth has no tonic/RPC references |
10| B | Single identity HTTP boundary | P0 | COMPLETE | Shared Router/State/ApiError; assets and middleware in webapi; Retry-After preserved through shared Envelope metadata |
11| C | Narrow services, concrete adapters, one read router | P1 | COMPLETE | No AppState in seven domain crates; Database/BlobStore/AuthApi traits removed; AppDatabase delegates DbConn; capabilities extracted |
12| D | Deep space policy, opaque handle | P1 | COMPLETE | Access/Space + Capability; shared permission kernel/cache; no domain access to space tables/errors |
13| E | Owner APIs across domains | P1 | COMPLETE | Issue label read API; repo ownership in Access; UserDto from export; chat-room-store owns room writes; Git facade uses concrete backend |
14| F | Deep outbound delivery | P1 | COMPLETE | events::emit; transactional Notifications; email helper; database-only Realtime |
15
16Latest check: `cargo check --workspace --target-dir target/auth-refactor` passed with 0 warnings. Targeted rustfmt check passed for auth/user/chat/issues/pulls/space/git/webapi/export/models. `git diff --check` passed. Git RPC files remain unchanged. No tests were run.
17
18Next: optional focused runtime/smoke verification in an environment with its dependencies.
Deleted steiger.config.ts steiger.config.ts +0 −14
@@ -1,14 +0,0 @@
1import fsd from '@feature-sliced/steiger-plugin'
2import { defineConfig } from 'steiger'
3
4export default defineConfig([
5 ...fsd.configs.recommended,
6 {
7 ignores: ['**/dist/**'],
8 },
9 {
10 rules: {
11 'fsd/insignificant-slice': 'off',
12 },
13 },
14])
Modified tsconfig.node.json tsconfig.node.json +1 −1 View tsconfig.node.json
@@ -19,5 +19,5 @@
1919 "erasableSyntaxOnly": true,
2020 "noFallthroughCasesInSwitch": true
2121 },
22 "include": ["vite.config.ts", "orval.config.ts", "steiger.config.ts"]
22 "include": ["vite.config.ts", "orval.config.ts"]
2323}