@notionx/core 0.1.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/admin/index.d.ts +137 -0
- package/dist/admin/index.js +206 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/index.d.ts +324 -0
- package/dist/admin/pages/index.js +827 -0
- package/dist/admin/pages/index.js.map +1 -0
- package/dist/auth/auth-pages/forgot-password.d.ts +20 -0
- package/dist/auth/auth-pages/forgot-password.js +70 -0
- package/dist/auth/auth-pages/forgot-password.js.map +1 -0
- package/dist/auth/auth-pages/index.d.ts +6 -0
- package/dist/auth/auth-pages/index.js +342 -0
- package/dist/auth/auth-pages/index.js.map +1 -0
- package/dist/auth/auth-pages/login.d.ts +30 -0
- package/dist/auth/auth-pages/login.js +125 -0
- package/dist/auth/auth-pages/login.js.map +1 -0
- package/dist/auth/auth-pages/register.d.ts +17 -0
- package/dist/auth/auth-pages/register.js +81 -0
- package/dist/auth/auth-pages/register.js.map +1 -0
- package/dist/auth/auth-pages/reset-password.d.ts +18 -0
- package/dist/auth/auth-pages/reset-password.js +72 -0
- package/dist/auth/auth-pages/reset-password.js.map +1 -0
- package/dist/auth/index.d.ts +72 -0
- package/dist/auth/index.js +1011 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/passwords.d.ts +6 -0
- package/dist/auth/passwords.js +79 -0
- package/dist/auth/passwords.js.map +1 -0
- package/dist/auth/rate-limit.d.ts +28 -0
- package/dist/auth/rate-limit.js +245 -0
- package/dist/auth/rate-limit.js.map +1 -0
- package/dist/auth/routes/google-callback.d.ts +6 -0
- package/dist/auth/routes/google-callback.js +404 -0
- package/dist/auth/routes/google-callback.js.map +1 -0
- package/dist/auth/routes/google.d.ts +6 -0
- package/dist/auth/routes/google.js +250 -0
- package/dist/auth/routes/google.js.map +1 -0
- package/dist/auth/routes/index.d.ts +22 -0
- package/dist/auth/routes/index.js +619 -0
- package/dist/auth/routes/index.js.map +1 -0
- package/dist/auth/routes/verify-email.d.ts +6 -0
- package/dist/auth/routes/verify-email.js +317 -0
- package/dist/auth/routes/verify-email.js.map +1 -0
- package/dist/auth/routes/viewer.d.ts +6 -0
- package/dist/auth/routes/viewer.js +372 -0
- package/dist/auth/routes/viewer.js.map +1 -0
- package/dist/auth/session.d.ts +9 -0
- package/dist/auth/session.js +1 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/turnstile.d.ts +20 -0
- package/dist/auth/turnstile.js +301 -0
- package/dist/auth/turnstile.js.map +1 -0
- package/dist/auth/user-session.d.ts +42 -0
- package/dist/auth/user-session.js +419 -0
- package/dist/auth/user-session.js.map +1 -0
- package/dist/auth/users.d.ts +112 -0
- package/dist/auth/users.js +558 -0
- package/dist/auth/users.js.map +1 -0
- package/dist/bootstrap-CN2g76M6.d.ts +67 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/index.js +47 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/content/admin-summary.d.ts +24 -0
- package/dist/content/admin-summary.js +36 -0
- package/dist/content/admin-summary.js.map +1 -0
- package/dist/content/index.d.ts +9 -0
- package/dist/content/index.js +473 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/models.d.ts +69 -0
- package/dist/content/models.js +24 -0
- package/dist/content/models.js.map +1 -0
- package/dist/content/prewarm.d.ts +28 -0
- package/dist/content/prewarm.js +56 -0
- package/dist/content/prewarm.js.map +1 -0
- package/dist/content/revalidate.d.ts +37 -0
- package/dist/content/revalidate.js +170 -0
- package/dist/content/revalidate.js.map +1 -0
- package/dist/content/search-index.d.ts +54 -0
- package/dist/content/search-index.js +172 -0
- package/dist/content/search-index.js.map +1 -0
- package/dist/content/search.d.ts +8 -0
- package/dist/content/search.js +57 -0
- package/dist/content/search.js.map +1 -0
- package/dist/doctor/cli.d.ts +1 -0
- package/dist/doctor/cli.js +360 -0
- package/dist/doctor/cli.js.map +1 -0
- package/dist/doctor/index.d.ts +139 -0
- package/dist/doctor/index.js +289 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/email/index.d.ts +38 -0
- package/dist/email/index.js +126 -0
- package/dist/email/index.js.map +1 -0
- package/dist/env-C5qu-0R-.d.ts +35 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/i18n/index.d.ts +26 -0
- package/dist/i18n/index.js +73 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1281 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/admin/index.d.ts +75 -0
- package/dist/internal/admin/index.js +365 -0
- package/dist/internal/admin/index.js.map +1 -0
- package/dist/media/index.d.ts +24 -0
- package/dist/media/index.js +86 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/routes/index.d.ts +1 -0
- package/dist/media/routes/index.js +585 -0
- package/dist/media/routes/index.js.map +1 -0
- package/dist/media/routes/notion-media.d.ts +19 -0
- package/dist/media/routes/notion-media.js +588 -0
- package/dist/media/routes/notion-media.js.map +1 -0
- package/dist/middleware.d.ts +95 -0
- package/dist/middleware.js +79 -0
- package/dist/middleware.js.map +1 -0
- package/dist/notion/block-text.d.ts +5 -0
- package/dist/notion/block-text.js +37 -0
- package/dist/notion/block-text.js.map +1 -0
- package/dist/notion/blocks.d.ts +24 -0
- package/dist/notion/blocks.js +46 -0
- package/dist/notion/blocks.js.map +1 -0
- package/dist/notion/client.d.ts +7 -0
- package/dist/notion/client.js +13 -0
- package/dist/notion/client.js.map +1 -0
- package/dist/notion/config.d.ts +25 -0
- package/dist/notion/config.js +147 -0
- package/dist/notion/config.js.map +1 -0
- package/dist/notion/content-cache.d.ts +45 -0
- package/dist/notion/content-cache.js +166 -0
- package/dist/notion/content-cache.js.map +1 -0
- package/dist/notion/generic-source.d.ts +61 -0
- package/dist/notion/generic-source.js +408 -0
- package/dist/notion/generic-source.js.map +1 -0
- package/dist/notion/index.d.ts +13 -0
- package/dist/notion/index.js +1278 -0
- package/dist/notion/index.js.map +1 -0
- package/dist/notion/mappers.d.ts +1 -0
- package/dist/notion/mappers.js +152 -0
- package/dist/notion/mappers.js.map +1 -0
- package/dist/notion/media.d.ts +22 -0
- package/dist/notion/media.js +209 -0
- package/dist/notion/media.js.map +1 -0
- package/dist/notion/property-mappers.d.ts +24 -0
- package/dist/notion/property-mappers.js +152 -0
- package/dist/notion/property-mappers.js.map +1 -0
- package/dist/notion/routes/index.d.ts +8 -0
- package/dist/notion/routes/index.js +428 -0
- package/dist/notion/routes/index.js.map +1 -0
- package/dist/notion/routes/webhook.d.ts +98 -0
- package/dist/notion/routes/webhook.js +428 -0
- package/dist/notion/routes/webhook.js.map +1 -0
- package/dist/notion/types.d.ts +152 -0
- package/dist/notion/types.js +1 -0
- package/dist/notion/types.js.map +1 -0
- package/dist/notion/webhook.d.ts +83 -0
- package/dist/notion/webhook.js +490 -0
- package/dist/notion/webhook.js.map +1 -0
- package/dist/platform/capabilities.d.ts +34 -0
- package/dist/platform/capabilities.js +42 -0
- package/dist/platform/capabilities.js.map +1 -0
- package/dist/platform/current.d.ts +13 -0
- package/dist/platform/current.js +181 -0
- package/dist/platform/current.js.map +1 -0
- package/dist/platform/index.d.ts +5 -0
- package/dist/platform/index.js +269 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/runtime.d.ts +118 -0
- package/dist/platform/runtime.js +160 -0
- package/dist/platform/runtime.js.map +1 -0
- package/dist/platform/selection.d.ts +10 -0
- package/dist/platform/selection.js +22 -0
- package/dist/platform/selection.js.map +1 -0
- package/dist/storage/index.d.ts +17 -0
- package/dist/storage/index.js +218 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/routes/cdn.d.ts +19 -0
- package/dist/storage/routes/cdn.js +289 -0
- package/dist/storage/routes/cdn.js.map +1 -0
- package/dist/storage/routes/files.d.ts +27 -0
- package/dist/storage/routes/files.js +216 -0
- package/dist/storage/routes/files.js.map +1 -0
- package/dist/storage/routes/index.d.ts +2 -0
- package/dist/storage/routes/index.js +352 -0
- package/dist/storage/routes/index.js.map +1 -0
- package/dist/types-BsAcZSNX.d.ts +94 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/util/index.d.ts +18 -0
- package/dist/util/index.js +48 -0
- package/dist/util/index.js.map +1 -0
- package/dist/worker/index.d.ts +6 -0
- package/dist/worker/index.js +1026 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/routes/content-prewarm.d.ts +34 -0
- package/dist/worker/routes/content-prewarm.js +38 -0
- package/dist/worker/routes/content-prewarm.js.map +1 -0
- package/dist/worker/routes/content-revalidate.d.ts +81 -0
- package/dist/worker/routes/content-revalidate.js +64 -0
- package/dist/worker/routes/content-revalidate.js.map +1 -0
- package/dist/worker/routes/health.d.ts +14 -0
- package/dist/worker/routes/health.js +278 -0
- package/dist/worker/routes/health.js.map +1 -0
- package/dist/worker/routes/index.d.ts +6 -0
- package/dist/worker/routes/index.js +373 -0
- package/dist/worker/routes/index.js.map +1 -0
- package/package.json +124 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/auth-pages/login.tsx","../../../src/auth/auth-pages/register.tsx","../../../src/auth/auth-pages/forgot-password.tsx","../../../src/auth/auth-pages/reset-password.tsx"],"sourcesContent":["// auth/auth-pages/login.tsx\n//\n// Login page. Renders the \"Sign in with Google\" button when OAuth is\n// configured plus the email/password form, with optional Turnstile\n// captcha. All UI primitives are passed in via the `ui` prop so the\n// package stays unopinionated about the design system.\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface LoginPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: {\n error?: string;\n loginError?: string;\n registered?: string;\n email?: string;\n verifyError?: string;\n resendSent?: string;\n resendError?: string;\n retry?: string;\n accountDeleted?: string;\n };\n emailLoginAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { emailLogin: infer F }\n ? F\n : never\n : never;\n resendVerificationAction?: AuthPageContext[\"actions\"] extends infer A\n ? A extends { resendVerification: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n getCurrentUser?: AuthPageContext[\"getCurrentUser\"];\n getGoogleOAuthConfig?: AuthPageContext[\"getGoogleOAuthConfig\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function LoginPage({\n ui,\n searchParams,\n emailLoginAction,\n resendVerificationAction,\n isAuthenticated,\n getCurrentUser,\n getGoogleOAuthConfig,\n redirectWhenAuthenticated = \"/admin\",\n}: LoginPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const {\n loginError,\n registered,\n email,\n verifyError,\n resendSent,\n resendError,\n retry,\n accountDeleted,\n } = searchParams;\n const user = getCurrentUser ? await getCurrentUser() : null;\n const googleCfg = getGoogleOAuthConfig ? await getGoogleOAuthConfig() : null;\n const googleEnabled = Boolean(googleCfg);\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Separator, Turnstile } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>后台登录</CardTitle>\n <CardDescription>多种方式登录管理面板</CardDescription>\n </CardHeader>\n <CardContent>\n {accountDeleted && (\n <div className=\"rounded-md bg-muted px-3 py-2 text-sm text-muted-foreground\">\n 账户已注销。如需再次使用,请重新注册。\n </div>\n )}\n {registered && (\n <div className=\"rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400\">\n 验证邮件已发送到 {email ?? \"你的邮箱\"},请先验证后再登录。\n </div>\n )}\n {verifyError && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 验证链接无效或已过期,请重新发送验证邮件。\n </div>\n )}\n {resendSent && (\n <div className=\"rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400\">\n 如果 {email ?? \"该邮箱\"} 有待验证账户,验证邮件已重新发送。\n </div>\n )}\n {resendError === \"verified\" && (\n <div className=\"rounded-md bg-amber-500/10 px-3 py-2 text-sm text-amber-700 dark:text-amber-400\">\n 该邮箱已验证,请直接登录。\n </div>\n )}\n {resendError === \"captcha\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 请完成人机验证后再重发邮件\n </div>\n )}\n {resendError === \"rate\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 重发过于频繁,请 {retry ?? \"900\"} 秒后再试\n </div>\n )}\n\n {googleEnabled ? (\n <Button asChild variant=\"outline\" className=\"w-full\" size=\"lg\">\n <a href=\"/api/auth/google\">使用 Google 登录</a>\n </Button>\n ) : (\n <div className=\"rounded-md border border-dashed p-3 text-xs text-muted-foreground\">\n Google 登录未启用(管理员可在 <a href=\"/admin/settings\" className=\"underline\">/admin/settings</a> 配置)\n </div>\n )}\n\n <Separator />\n\n <form action={emailLoginAction as unknown as (formData: FormData) => void}>\n <Label htmlFor=\"email\">邮箱</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n required\n />\n <Label htmlFor=\"email-password\">密码</Label>\n <Input\n id=\"email-password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"输入密码\"\n required\n />\n {loginError === \"rate\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 登录尝试过多,请 {retry ?? \"900\"} 秒后再试\n </div>\n )}\n {loginError === \"captcha\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 请完成人机验证后再试\n </div>\n )}\n {loginError === \"invalid\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 邮箱或密码错误\n </div>\n )}\n {loginError === \"unverified\" && (\n <div className=\"rounded-md bg-amber-500/10 px-3 py-2 text-sm text-amber-700 dark:text-amber-400\">\n 邮箱还没有验证,请先打开验证邮件中的链接。\n </div>\n )}\n {Turnstile && <Turnstile action=\"login\" />}\n <Button type=\"submit\" className=\"w-full\">使用邮箱登录</Button>\n </form>\n\n {loginError === \"unverified\" && email && resendVerificationAction && (\n <form action={resendVerificationAction as unknown as (formData: FormData) => void}>\n <input type=\"hidden\" name=\"email\" value={email} />\n {Turnstile && <Turnstile action=\"resend_verify\" />}\n <Button type=\"submit\" variant=\"outline\" size=\"sm\" className=\"w-full\">\n 重新发送验证邮件\n </Button>\n </form>\n )}\n\n <Button asChild variant=\"secondary\" className=\"w-full\">\n <a href=\"/register\">新用户注册</a>\n </Button>\n\n {user && (\n <p className=\"text-center text-xs text-muted-foreground\">\n 当前已登录:{user.email}\n </p>\n )}\n </CardContent>\n </Card>\n </main>\n );\n}\n","// auth/auth-pages/register.tsx\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface RegisterPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: { error?: string };\n registerAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { register: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function RegisterPage({\n ui,\n searchParams,\n registerAction,\n isAuthenticated,\n redirectWhenAuthenticated = \"/admin\",\n}: RegisterPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const { error } = searchParams;\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Turnstile } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>邮箱注册</CardTitle>\n <CardDescription>\n 注册后会发送验证邮件,验证完成即可进入后台。\n </CardDescription>\n </CardHeader>\n <CardContent>\n <form action={registerAction as unknown as (formData: FormData) => void}>\n <Label htmlFor=\"email\">邮箱</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n autoFocus\n required\n />\n <Label htmlFor=\"password\">密码</Label>\n <Input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"至少 8 位,包含字母和数字\"\n required\n />\n <Label htmlFor=\"confirmPassword\">确认密码</Label>\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n placeholder=\"再次输入密码\"\n required\n />\n {error && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n )}\n {Turnstile && <Turnstile action=\"register\" />}\n <Button type=\"submit\" className=\"w-full\">注册并发送验证邮件</Button>\n </form>\n\n <Button asChild variant=\"ghost\" className=\"w-full\">\n <a href=\"/login\">返回登录</a>\n </Button>\n </CardContent>\n </Card>\n </main>\n );\n}\n","// auth/auth-pages/forgot-password.tsx\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface ForgotPasswordPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: {\n sent?: string;\n email?: string;\n error?: string;\n retry?: string;\n };\n forgotPasswordAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { forgotPassword: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function ForgotPasswordPage({\n ui,\n searchParams,\n forgotPasswordAction,\n isAuthenticated,\n redirectWhenAuthenticated = \"/admin\",\n}: ForgotPasswordPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const { sent, email, error, retry } = searchParams;\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Turnstile } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>忘记密码</CardTitle>\n <CardDescription>\n 输入注册邮箱,我们会发送重置链接(1 小时内有效)。\n </CardDescription>\n </CardHeader>\n <CardContent>\n {sent && (\n <div className=\"rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400\">\n 如果 {email ?? \"该邮箱\"} 已注册且已验证,你会收到重置密码邮件。\n </div>\n )}\n {error === \"invalid\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 邮箱格式不正确\n </div>\n )}\n {error === \"captcha\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 请完成人机验证后再试\n </div>\n )}\n {error === \"rate\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 请求过于频繁,请 {retry ?? \"900\"} 秒后再试\n </div>\n )}\n\n <form action={forgotPasswordAction as unknown as (formData: FormData) => void}>\n <Label htmlFor=\"email\">邮箱</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n defaultValue={email ?? \"\"}\n required\n />\n {Turnstile && <Turnstile action=\"forgot_password\" />}\n <Button type=\"submit\" className=\"w-full\">发送重置链接</Button>\n </form>\n\n <Button asChild variant=\"ghost\" className=\"w-full\">\n <a href=\"/login\">返回登录</a>\n </Button>\n </CardContent>\n </Card>\n </main>\n );\n}\n","// auth/auth-pages/reset-password.tsx\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface ResetPasswordPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: {\n token?: string;\n error?: string;\n };\n resetPasswordAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { resetPassword: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function ResetPasswordPage({\n ui,\n searchParams,\n resetPasswordAction,\n isAuthenticated,\n redirectWhenAuthenticated = \"/admin\",\n}: ResetPasswordPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const { token, error } = searchParams;\n if (!token) {\n redirect(\"/forgot-password?error=missing\");\n }\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>设置新密码</CardTitle>\n <CardDescription>请输入新密码,提交后将自动登录。</CardDescription>\n </CardHeader>\n <CardContent>\n {error && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n )}\n\n <form action={resetPasswordAction as unknown as (formData: FormData) => void}>\n <input type=\"hidden\" name=\"token\" value={token} />\n <Label htmlFor=\"password\">新密码</Label>\n <Input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"至少 8 位,包含字母和数字\"\n required\n />\n <Label htmlFor=\"confirmPassword\">确认新密码</Label>\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n placeholder=\"再次输入新密码\"\n required\n />\n <Button type=\"submit\" className=\"w-full\">更新密码并登录</Button>\n </form>\n\n <Button asChild variant=\"ghost\" className=\"w-full\">\n <a href=\"/login\">返回登录</a>\n </Button>\n </CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":"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","names":["redirect","jsx","jsxs","redirect","jsx","jsxs","redirect","jsx","jsxs"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { A as AuthPageContext } from '../../types-BsAcZSNX.js';
|
|
3
|
+
|
|
4
|
+
interface LoginPageProps {
|
|
5
|
+
ui: AuthPageContext["ui"];
|
|
6
|
+
searchParams: {
|
|
7
|
+
error?: string;
|
|
8
|
+
loginError?: string;
|
|
9
|
+
registered?: string;
|
|
10
|
+
email?: string;
|
|
11
|
+
verifyError?: string;
|
|
12
|
+
resendSent?: string;
|
|
13
|
+
resendError?: string;
|
|
14
|
+
retry?: string;
|
|
15
|
+
accountDeleted?: string;
|
|
16
|
+
};
|
|
17
|
+
emailLoginAction: AuthPageContext["actions"] extends infer A ? A extends {
|
|
18
|
+
emailLogin: infer F;
|
|
19
|
+
} ? F : never : never;
|
|
20
|
+
resendVerificationAction?: AuthPageContext["actions"] extends infer A ? A extends {
|
|
21
|
+
resendVerification: infer F;
|
|
22
|
+
} ? F : never : never;
|
|
23
|
+
isAuthenticated?: AuthPageContext["isAuthenticated"];
|
|
24
|
+
getCurrentUser?: AuthPageContext["getCurrentUser"];
|
|
25
|
+
getGoogleOAuthConfig?: AuthPageContext["getGoogleOAuthConfig"];
|
|
26
|
+
redirectWhenAuthenticated?: string;
|
|
27
|
+
}
|
|
28
|
+
declare function LoginPage({ ui, searchParams, emailLoginAction, resendVerificationAction, isAuthenticated, getCurrentUser, getGoogleOAuthConfig, redirectWhenAuthenticated, }: LoginPageProps): Promise<react.JSX.Element>;
|
|
29
|
+
|
|
30
|
+
export { type LoginPageProps, LoginPage as default };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// src/auth/auth-pages/login.tsx
|
|
2
|
+
import { redirect } from "next/navigation";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
async function LoginPage({
|
|
5
|
+
ui,
|
|
6
|
+
searchParams,
|
|
7
|
+
emailLoginAction,
|
|
8
|
+
resendVerificationAction,
|
|
9
|
+
isAuthenticated,
|
|
10
|
+
getCurrentUser,
|
|
11
|
+
getGoogleOAuthConfig,
|
|
12
|
+
redirectWhenAuthenticated = "/admin"
|
|
13
|
+
}) {
|
|
14
|
+
if (isAuthenticated && await isAuthenticated()) {
|
|
15
|
+
redirect(redirectWhenAuthenticated);
|
|
16
|
+
}
|
|
17
|
+
const {
|
|
18
|
+
loginError,
|
|
19
|
+
registered,
|
|
20
|
+
email,
|
|
21
|
+
verifyError,
|
|
22
|
+
resendSent,
|
|
23
|
+
resendError,
|
|
24
|
+
retry,
|
|
25
|
+
accountDeleted
|
|
26
|
+
} = searchParams;
|
|
27
|
+
const user = getCurrentUser ? await getCurrentUser() : null;
|
|
28
|
+
const googleCfg = getGoogleOAuthConfig ? await getGoogleOAuthConfig() : null;
|
|
29
|
+
const googleEnabled = Boolean(googleCfg);
|
|
30
|
+
const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Separator, Turnstile } = ui;
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
"main",
|
|
33
|
+
{
|
|
34
|
+
style: {
|
|
35
|
+
minHeight: "100vh",
|
|
36
|
+
display: "flex",
|
|
37
|
+
alignItems: "center",
|
|
38
|
+
justifyContent: "center",
|
|
39
|
+
padding: "1rem",
|
|
40
|
+
background: "linear-gradient(to bottom right, var(--background), var(--muted))"
|
|
41
|
+
},
|
|
42
|
+
children: /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm", children: [
|
|
43
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
44
|
+
/* @__PURE__ */ jsx(CardTitle, { children: "\u540E\u53F0\u767B\u5F55" }),
|
|
45
|
+
/* @__PURE__ */ jsx(CardDescription, { children: "\u591A\u79CD\u65B9\u5F0F\u767B\u5F55\u7BA1\u7406\u9762\u677F" })
|
|
46
|
+
] }),
|
|
47
|
+
/* @__PURE__ */ jsxs(CardContent, { children: [
|
|
48
|
+
accountDeleted && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-muted px-3 py-2 text-sm text-muted-foreground", children: "\u8D26\u6237\u5DF2\u6CE8\u9500\u3002\u5982\u9700\u518D\u6B21\u4F7F\u7528\uFF0C\u8BF7\u91CD\u65B0\u6CE8\u518C\u3002" }),
|
|
49
|
+
registered && /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400", children: [
|
|
50
|
+
"\u9A8C\u8BC1\u90AE\u4EF6\u5DF2\u53D1\u9001\u5230 ",
|
|
51
|
+
email ?? "\u4F60\u7684\u90AE\u7BB1",
|
|
52
|
+
"\uFF0C\u8BF7\u5148\u9A8C\u8BC1\u540E\u518D\u767B\u5F55\u3002"
|
|
53
|
+
] }),
|
|
54
|
+
verifyError && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: "\u9A8C\u8BC1\u94FE\u63A5\u65E0\u6548\u6216\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u9A8C\u8BC1\u90AE\u4EF6\u3002" }),
|
|
55
|
+
resendSent && /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400", children: [
|
|
56
|
+
"\u5982\u679C ",
|
|
57
|
+
email ?? "\u8BE5\u90AE\u7BB1",
|
|
58
|
+
" \u6709\u5F85\u9A8C\u8BC1\u8D26\u6237\uFF0C\u9A8C\u8BC1\u90AE\u4EF6\u5DF2\u91CD\u65B0\u53D1\u9001\u3002"
|
|
59
|
+
] }),
|
|
60
|
+
resendError === "verified" && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-amber-500/10 px-3 py-2 text-sm text-amber-700 dark:text-amber-400", children: "\u8BE5\u90AE\u7BB1\u5DF2\u9A8C\u8BC1\uFF0C\u8BF7\u76F4\u63A5\u767B\u5F55\u3002" }),
|
|
61
|
+
resendError === "captcha" && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: "\u8BF7\u5B8C\u6210\u4EBA\u673A\u9A8C\u8BC1\u540E\u518D\u91CD\u53D1\u90AE\u4EF6" }),
|
|
62
|
+
resendError === "rate" && /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
63
|
+
"\u91CD\u53D1\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7 ",
|
|
64
|
+
retry ?? "900",
|
|
65
|
+
" \u79D2\u540E\u518D\u8BD5"
|
|
66
|
+
] }),
|
|
67
|
+
googleEnabled ? /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", className: "w-full", size: "lg", children: /* @__PURE__ */ jsx("a", { href: "/api/auth/google", children: "\u4F7F\u7528 Google \u767B\u5F55" }) }) : /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-dashed p-3 text-xs text-muted-foreground", children: [
|
|
68
|
+
"Google \u767B\u5F55\u672A\u542F\u7528\uFF08\u7BA1\u7406\u5458\u53EF\u5728 ",
|
|
69
|
+
/* @__PURE__ */ jsx("a", { href: "/admin/settings", className: "underline", children: "/admin/settings" }),
|
|
70
|
+
" \u914D\u7F6E\uFF09"
|
|
71
|
+
] }),
|
|
72
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
73
|
+
/* @__PURE__ */ jsxs("form", { action: emailLoginAction, children: [
|
|
74
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "\u90AE\u7BB1" }),
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
Input,
|
|
77
|
+
{
|
|
78
|
+
id: "email",
|
|
79
|
+
name: "email",
|
|
80
|
+
type: "email",
|
|
81
|
+
placeholder: "you@example.com",
|
|
82
|
+
required: true
|
|
83
|
+
}
|
|
84
|
+
),
|
|
85
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "email-password", children: "\u5BC6\u7801" }),
|
|
86
|
+
/* @__PURE__ */ jsx(
|
|
87
|
+
Input,
|
|
88
|
+
{
|
|
89
|
+
id: "email-password",
|
|
90
|
+
name: "password",
|
|
91
|
+
type: "password",
|
|
92
|
+
placeholder: "\u8F93\u5165\u5BC6\u7801",
|
|
93
|
+
required: true
|
|
94
|
+
}
|
|
95
|
+
),
|
|
96
|
+
loginError === "rate" && /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
97
|
+
"\u767B\u5F55\u5C1D\u8BD5\u8FC7\u591A\uFF0C\u8BF7 ",
|
|
98
|
+
retry ?? "900",
|
|
99
|
+
" \u79D2\u540E\u518D\u8BD5"
|
|
100
|
+
] }),
|
|
101
|
+
loginError === "captcha" && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: "\u8BF7\u5B8C\u6210\u4EBA\u673A\u9A8C\u8BC1\u540E\u518D\u8BD5" }),
|
|
102
|
+
loginError === "invalid" && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: "\u90AE\u7BB1\u6216\u5BC6\u7801\u9519\u8BEF" }),
|
|
103
|
+
loginError === "unverified" && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-amber-500/10 px-3 py-2 text-sm text-amber-700 dark:text-amber-400", children: "\u90AE\u7BB1\u8FD8\u6CA1\u6709\u9A8C\u8BC1\uFF0C\u8BF7\u5148\u6253\u5F00\u9A8C\u8BC1\u90AE\u4EF6\u4E2D\u7684\u94FE\u63A5\u3002" }),
|
|
104
|
+
Turnstile && /* @__PURE__ */ jsx(Turnstile, { action: "login" }),
|
|
105
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full", children: "\u4F7F\u7528\u90AE\u7BB1\u767B\u5F55" })
|
|
106
|
+
] }),
|
|
107
|
+
loginError === "unverified" && email && resendVerificationAction && /* @__PURE__ */ jsxs("form", { action: resendVerificationAction, children: [
|
|
108
|
+
/* @__PURE__ */ jsx("input", { type: "hidden", name: "email", value: email }),
|
|
109
|
+
Turnstile && /* @__PURE__ */ jsx(Turnstile, { action: "resend_verify" }),
|
|
110
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", variant: "outline", size: "sm", className: "w-full", children: "\u91CD\u65B0\u53D1\u9001\u9A8C\u8BC1\u90AE\u4EF6" })
|
|
111
|
+
] }),
|
|
112
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "secondary", className: "w-full", children: /* @__PURE__ */ jsx("a", { href: "/register", children: "\u65B0\u7528\u6237\u6CE8\u518C" }) }),
|
|
113
|
+
user && /* @__PURE__ */ jsxs("p", { className: "text-center text-xs text-muted-foreground", children: [
|
|
114
|
+
"\u5F53\u524D\u5DF2\u767B\u5F55\uFF1A",
|
|
115
|
+
user.email
|
|
116
|
+
] })
|
|
117
|
+
] })
|
|
118
|
+
] })
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
export {
|
|
123
|
+
LoginPage as default
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/auth-pages/login.tsx"],"sourcesContent":["// auth/auth-pages/login.tsx\n//\n// Login page. Renders the \"Sign in with Google\" button when OAuth is\n// configured plus the email/password form, with optional Turnstile\n// captcha. All UI primitives are passed in via the `ui` prop so the\n// package stays unopinionated about the design system.\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface LoginPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: {\n error?: string;\n loginError?: string;\n registered?: string;\n email?: string;\n verifyError?: string;\n resendSent?: string;\n resendError?: string;\n retry?: string;\n accountDeleted?: string;\n };\n emailLoginAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { emailLogin: infer F }\n ? F\n : never\n : never;\n resendVerificationAction?: AuthPageContext[\"actions\"] extends infer A\n ? A extends { resendVerification: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n getCurrentUser?: AuthPageContext[\"getCurrentUser\"];\n getGoogleOAuthConfig?: AuthPageContext[\"getGoogleOAuthConfig\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function LoginPage({\n ui,\n searchParams,\n emailLoginAction,\n resendVerificationAction,\n isAuthenticated,\n getCurrentUser,\n getGoogleOAuthConfig,\n redirectWhenAuthenticated = \"/admin\",\n}: LoginPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const {\n loginError,\n registered,\n email,\n verifyError,\n resendSent,\n resendError,\n retry,\n accountDeleted,\n } = searchParams;\n const user = getCurrentUser ? await getCurrentUser() : null;\n const googleCfg = getGoogleOAuthConfig ? await getGoogleOAuthConfig() : null;\n const googleEnabled = Boolean(googleCfg);\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Separator, Turnstile } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>后台登录</CardTitle>\n <CardDescription>多种方式登录管理面板</CardDescription>\n </CardHeader>\n <CardContent>\n {accountDeleted && (\n <div className=\"rounded-md bg-muted px-3 py-2 text-sm text-muted-foreground\">\n 账户已注销。如需再次使用,请重新注册。\n </div>\n )}\n {registered && (\n <div className=\"rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400\">\n 验证邮件已发送到 {email ?? \"你的邮箱\"},请先验证后再登录。\n </div>\n )}\n {verifyError && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 验证链接无效或已过期,请重新发送验证邮件。\n </div>\n )}\n {resendSent && (\n <div className=\"rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-400\">\n 如果 {email ?? \"该邮箱\"} 有待验证账户,验证邮件已重新发送。\n </div>\n )}\n {resendError === \"verified\" && (\n <div className=\"rounded-md bg-amber-500/10 px-3 py-2 text-sm text-amber-700 dark:text-amber-400\">\n 该邮箱已验证,请直接登录。\n </div>\n )}\n {resendError === \"captcha\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 请完成人机验证后再重发邮件\n </div>\n )}\n {resendError === \"rate\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 重发过于频繁,请 {retry ?? \"900\"} 秒后再试\n </div>\n )}\n\n {googleEnabled ? (\n <Button asChild variant=\"outline\" className=\"w-full\" size=\"lg\">\n <a href=\"/api/auth/google\">使用 Google 登录</a>\n </Button>\n ) : (\n <div className=\"rounded-md border border-dashed p-3 text-xs text-muted-foreground\">\n Google 登录未启用(管理员可在 <a href=\"/admin/settings\" className=\"underline\">/admin/settings</a> 配置)\n </div>\n )}\n\n <Separator />\n\n <form action={emailLoginAction as unknown as (formData: FormData) => void}>\n <Label htmlFor=\"email\">邮箱</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n required\n />\n <Label htmlFor=\"email-password\">密码</Label>\n <Input\n id=\"email-password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"输入密码\"\n required\n />\n {loginError === \"rate\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 登录尝试过多,请 {retry ?? \"900\"} 秒后再试\n </div>\n )}\n {loginError === \"captcha\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 请完成人机验证后再试\n </div>\n )}\n {loginError === \"invalid\" && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n 邮箱或密码错误\n </div>\n )}\n {loginError === \"unverified\" && (\n <div className=\"rounded-md bg-amber-500/10 px-3 py-2 text-sm text-amber-700 dark:text-amber-400\">\n 邮箱还没有验证,请先打开验证邮件中的链接。\n </div>\n )}\n {Turnstile && <Turnstile action=\"login\" />}\n <Button type=\"submit\" className=\"w-full\">使用邮箱登录</Button>\n </form>\n\n {loginError === \"unverified\" && email && resendVerificationAction && (\n <form action={resendVerificationAction as unknown as (formData: FormData) => void}>\n <input type=\"hidden\" name=\"email\" value={email} />\n {Turnstile && <Turnstile action=\"resend_verify\" />}\n <Button type=\"submit\" variant=\"outline\" size=\"sm\" className=\"w-full\">\n 重新发送验证邮件\n </Button>\n </form>\n )}\n\n <Button asChild variant=\"secondary\" className=\"w-full\">\n <a href=\"/register\">新用户注册</a>\n </Button>\n\n {user && (\n <p className=\"text-center text-xs text-muted-foreground\">\n 当前已登录:{user.email}\n </p>\n )}\n </CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { A as AuthPageContext } from '../../types-BsAcZSNX.js';
|
|
3
|
+
|
|
4
|
+
interface RegisterPageProps {
|
|
5
|
+
ui: AuthPageContext["ui"];
|
|
6
|
+
searchParams: {
|
|
7
|
+
error?: string;
|
|
8
|
+
};
|
|
9
|
+
registerAction: AuthPageContext["actions"] extends infer A ? A extends {
|
|
10
|
+
register: infer F;
|
|
11
|
+
} ? F : never : never;
|
|
12
|
+
isAuthenticated?: AuthPageContext["isAuthenticated"];
|
|
13
|
+
redirectWhenAuthenticated?: string;
|
|
14
|
+
}
|
|
15
|
+
declare function RegisterPage({ ui, searchParams, registerAction, isAuthenticated, redirectWhenAuthenticated, }: RegisterPageProps): Promise<react.JSX.Element>;
|
|
16
|
+
|
|
17
|
+
export { type RegisterPageProps, RegisterPage as default };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/auth/auth-pages/register.tsx
|
|
2
|
+
import { redirect } from "next/navigation";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
async function RegisterPage({
|
|
5
|
+
ui,
|
|
6
|
+
searchParams,
|
|
7
|
+
registerAction,
|
|
8
|
+
isAuthenticated,
|
|
9
|
+
redirectWhenAuthenticated = "/admin"
|
|
10
|
+
}) {
|
|
11
|
+
if (isAuthenticated && await isAuthenticated()) {
|
|
12
|
+
redirect(redirectWhenAuthenticated);
|
|
13
|
+
}
|
|
14
|
+
const { error } = searchParams;
|
|
15
|
+
const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Turnstile } = ui;
|
|
16
|
+
return /* @__PURE__ */ jsx(
|
|
17
|
+
"main",
|
|
18
|
+
{
|
|
19
|
+
style: {
|
|
20
|
+
minHeight: "100vh",
|
|
21
|
+
display: "flex",
|
|
22
|
+
alignItems: "center",
|
|
23
|
+
justifyContent: "center",
|
|
24
|
+
padding: "1rem",
|
|
25
|
+
background: "linear-gradient(to bottom right, var(--background), var(--muted))"
|
|
26
|
+
},
|
|
27
|
+
children: /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm", children: [
|
|
28
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
29
|
+
/* @__PURE__ */ jsx(CardTitle, { children: "\u90AE\u7BB1\u6CE8\u518C" }),
|
|
30
|
+
/* @__PURE__ */ jsx(CardDescription, { children: "\u6CE8\u518C\u540E\u4F1A\u53D1\u9001\u9A8C\u8BC1\u90AE\u4EF6\uFF0C\u9A8C\u8BC1\u5B8C\u6210\u5373\u53EF\u8FDB\u5165\u540E\u53F0\u3002" })
|
|
31
|
+
] }),
|
|
32
|
+
/* @__PURE__ */ jsxs(CardContent, { children: [
|
|
33
|
+
/* @__PURE__ */ jsxs("form", { action: registerAction, children: [
|
|
34
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "\u90AE\u7BB1" }),
|
|
35
|
+
/* @__PURE__ */ jsx(
|
|
36
|
+
Input,
|
|
37
|
+
{
|
|
38
|
+
id: "email",
|
|
39
|
+
name: "email",
|
|
40
|
+
type: "email",
|
|
41
|
+
placeholder: "you@example.com",
|
|
42
|
+
autoFocus: true,
|
|
43
|
+
required: true
|
|
44
|
+
}
|
|
45
|
+
),
|
|
46
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "password", children: "\u5BC6\u7801" }),
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
Input,
|
|
49
|
+
{
|
|
50
|
+
id: "password",
|
|
51
|
+
name: "password",
|
|
52
|
+
type: "password",
|
|
53
|
+
placeholder: "\u81F3\u5C11 8 \u4F4D\uFF0C\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
|
|
54
|
+
required: true
|
|
55
|
+
}
|
|
56
|
+
),
|
|
57
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "confirmPassword", children: "\u786E\u8BA4\u5BC6\u7801" }),
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
Input,
|
|
60
|
+
{
|
|
61
|
+
id: "confirmPassword",
|
|
62
|
+
name: "confirmPassword",
|
|
63
|
+
type: "password",
|
|
64
|
+
placeholder: "\u518D\u6B21\u8F93\u5165\u5BC6\u7801",
|
|
65
|
+
required: true
|
|
66
|
+
}
|
|
67
|
+
),
|
|
68
|
+
error && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error }),
|
|
69
|
+
Turnstile && /* @__PURE__ */ jsx(Turnstile, { action: "register" }),
|
|
70
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full", children: "\u6CE8\u518C\u5E76\u53D1\u9001\u9A8C\u8BC1\u90AE\u4EF6" })
|
|
71
|
+
] }),
|
|
72
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "ghost", className: "w-full", children: /* @__PURE__ */ jsx("a", { href: "/login", children: "\u8FD4\u56DE\u767B\u5F55" }) })
|
|
73
|
+
] })
|
|
74
|
+
] })
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
RegisterPage as default
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/auth-pages/register.tsx"],"sourcesContent":["// auth/auth-pages/register.tsx\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface RegisterPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: { error?: string };\n registerAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { register: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function RegisterPage({\n ui,\n searchParams,\n registerAction,\n isAuthenticated,\n redirectWhenAuthenticated = \"/admin\",\n}: RegisterPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const { error } = searchParams;\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent, Turnstile } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>邮箱注册</CardTitle>\n <CardDescription>\n 注册后会发送验证邮件,验证完成即可进入后台。\n </CardDescription>\n </CardHeader>\n <CardContent>\n <form action={registerAction as unknown as (formData: FormData) => void}>\n <Label htmlFor=\"email\">邮箱</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n autoFocus\n required\n />\n <Label htmlFor=\"password\">密码</Label>\n <Input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"至少 8 位,包含字母和数字\"\n required\n />\n <Label htmlFor=\"confirmPassword\">确认密码</Label>\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n placeholder=\"再次输入密码\"\n required\n />\n {error && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n )}\n {Turnstile && <Turnstile action=\"register\" />}\n <Button type=\"submit\" className=\"w-full\">注册并发送验证邮件</Button>\n </form>\n\n <Button asChild variant=\"ghost\" className=\"w-full\">\n <a href=\"/login\">返回登录</a>\n </Button>\n </CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AAwCjB,SACE,KADF;AAzBR,eAAO,aAAoC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,4BAA4B;AAC9B,GAAsB;AACpB,MAAI,mBAAoB,MAAM,gBAAgB,GAAI;AAChD,aAAS,yBAAyB;AAAA,EACpC;AACA,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,EAAE,QAAQ,OAAO,OAAO,MAAM,YAAY,WAAW,iBAAiB,aAAa,UAAU,IAAI;AAEvG,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,WAAW;AAAA,QACX,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,MAEA,+BAAC,QAAK,WAAU,mBACd;AAAA,6BAAC,cACC;AAAA,8BAAC,aAAU,sCAAI;AAAA,UACf,oBAAC,mBAAgB,kJAEjB;AAAA,WACF;AAAA,QACA,qBAAC,eACC;AAAA,+BAAC,UAAK,QAAQ,gBACZ;AAAA,gCAAC,SAAM,SAAQ,SAAQ,0BAAE;AAAA,YACzB;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,WAAS;AAAA,gBACT,UAAQ;AAAA;AAAA,YACV;AAAA,YACA,oBAAC,SAAM,SAAQ,YAAW,0BAAE;AAAA,YAC5B;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,UAAQ;AAAA;AAAA,YACV;AAAA,YACA,oBAAC,SAAM,SAAQ,mBAAkB,sCAAI;AAAA,YACrC;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,UAAQ;AAAA;AAAA,YACV;AAAA,YACC,SACC,oBAAC,SAAI,WAAU,mEACZ,iBACH;AAAA,YAED,aAAa,oBAAC,aAAU,QAAO,YAAW;AAAA,YAC3C,oBAAC,UAAO,MAAK,UAAS,WAAU,UAAS,oEAAS;AAAA,aACpD;AAAA,UAEA,oBAAC,UAAO,SAAO,MAAC,SAAQ,SAAQ,WAAU,UACxC,8BAAC,OAAE,MAAK,UAAS,sCAAI,GACvB;AAAA,WACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { A as AuthPageContext } from '../../types-BsAcZSNX.js';
|
|
3
|
+
|
|
4
|
+
interface ResetPasswordPageProps {
|
|
5
|
+
ui: AuthPageContext["ui"];
|
|
6
|
+
searchParams: {
|
|
7
|
+
token?: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
};
|
|
10
|
+
resetPasswordAction: AuthPageContext["actions"] extends infer A ? A extends {
|
|
11
|
+
resetPassword: infer F;
|
|
12
|
+
} ? F : never : never;
|
|
13
|
+
isAuthenticated?: AuthPageContext["isAuthenticated"];
|
|
14
|
+
redirectWhenAuthenticated?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function ResetPasswordPage({ ui, searchParams, resetPasswordAction, isAuthenticated, redirectWhenAuthenticated, }: ResetPasswordPageProps): Promise<react.JSX.Element>;
|
|
17
|
+
|
|
18
|
+
export { type ResetPasswordPageProps, ResetPasswordPage as default };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/auth/auth-pages/reset-password.tsx
|
|
2
|
+
import { redirect } from "next/navigation";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
async function ResetPasswordPage({
|
|
5
|
+
ui,
|
|
6
|
+
searchParams,
|
|
7
|
+
resetPasswordAction,
|
|
8
|
+
isAuthenticated,
|
|
9
|
+
redirectWhenAuthenticated = "/admin"
|
|
10
|
+
}) {
|
|
11
|
+
if (isAuthenticated && await isAuthenticated()) {
|
|
12
|
+
redirect(redirectWhenAuthenticated);
|
|
13
|
+
}
|
|
14
|
+
const { token, error } = searchParams;
|
|
15
|
+
if (!token) {
|
|
16
|
+
redirect("/forgot-password?error=missing");
|
|
17
|
+
}
|
|
18
|
+
const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent } = ui;
|
|
19
|
+
return /* @__PURE__ */ jsx(
|
|
20
|
+
"main",
|
|
21
|
+
{
|
|
22
|
+
style: {
|
|
23
|
+
minHeight: "100vh",
|
|
24
|
+
display: "flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
justifyContent: "center",
|
|
27
|
+
padding: "1rem",
|
|
28
|
+
background: "linear-gradient(to bottom right, var(--background), var(--muted))"
|
|
29
|
+
},
|
|
30
|
+
children: /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm", children: [
|
|
31
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
32
|
+
/* @__PURE__ */ jsx(CardTitle, { children: "\u8BBE\u7F6E\u65B0\u5BC6\u7801" }),
|
|
33
|
+
/* @__PURE__ */ jsx(CardDescription, { children: "\u8BF7\u8F93\u5165\u65B0\u5BC6\u7801\uFF0C\u63D0\u4EA4\u540E\u5C06\u81EA\u52A8\u767B\u5F55\u3002" })
|
|
34
|
+
] }),
|
|
35
|
+
/* @__PURE__ */ jsxs(CardContent, { children: [
|
|
36
|
+
error && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error }),
|
|
37
|
+
/* @__PURE__ */ jsxs("form", { action: resetPasswordAction, children: [
|
|
38
|
+
/* @__PURE__ */ jsx("input", { type: "hidden", name: "token", value: token }),
|
|
39
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "password", children: "\u65B0\u5BC6\u7801" }),
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
Input,
|
|
42
|
+
{
|
|
43
|
+
id: "password",
|
|
44
|
+
name: "password",
|
|
45
|
+
type: "password",
|
|
46
|
+
placeholder: "\u81F3\u5C11 8 \u4F4D\uFF0C\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
|
|
47
|
+
required: true
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "confirmPassword", children: "\u786E\u8BA4\u65B0\u5BC6\u7801" }),
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
Input,
|
|
53
|
+
{
|
|
54
|
+
id: "confirmPassword",
|
|
55
|
+
name: "confirmPassword",
|
|
56
|
+
type: "password",
|
|
57
|
+
placeholder: "\u518D\u6B21\u8F93\u5165\u65B0\u5BC6\u7801",
|
|
58
|
+
required: true
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full", children: "\u66F4\u65B0\u5BC6\u7801\u5E76\u767B\u5F55" })
|
|
62
|
+
] }),
|
|
63
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "ghost", className: "w-full", children: /* @__PURE__ */ jsx("a", { href: "/login", children: "\u8FD4\u56DE\u767B\u5F55" }) })
|
|
64
|
+
] })
|
|
65
|
+
] })
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
ResetPasswordPage as default
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=reset-password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/auth-pages/reset-password.tsx"],"sourcesContent":["// auth/auth-pages/reset-password.tsx\n\nimport { redirect } from \"next/navigation\";\nimport type { AuthPageContext } from \"./types\";\n\nexport interface ResetPasswordPageProps {\n ui: AuthPageContext[\"ui\"];\n searchParams: {\n token?: string;\n error?: string;\n };\n resetPasswordAction: AuthPageContext[\"actions\"] extends infer A\n ? A extends { resetPassword: infer F }\n ? F\n : never\n : never;\n isAuthenticated?: AuthPageContext[\"isAuthenticated\"];\n redirectWhenAuthenticated?: string;\n}\n\nexport default async function ResetPasswordPage({\n ui,\n searchParams,\n resetPasswordAction,\n isAuthenticated,\n redirectWhenAuthenticated = \"/admin\",\n}: ResetPasswordPageProps) {\n if (isAuthenticated && (await isAuthenticated())) {\n redirect(redirectWhenAuthenticated);\n }\n const { token, error } = searchParams;\n if (!token) {\n redirect(\"/forgot-password?error=missing\");\n }\n const { Button, Input, Label, Card, CardHeader, CardTitle, CardDescription, CardContent } = ui;\n\n return (\n <main\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"1rem\",\n background: \"linear-gradient(to bottom right, var(--background), var(--muted))\",\n }}\n >\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>设置新密码</CardTitle>\n <CardDescription>请输入新密码,提交后将自动登录。</CardDescription>\n </CardHeader>\n <CardContent>\n {error && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n )}\n\n <form action={resetPasswordAction as unknown as (formData: FormData) => void}>\n <input type=\"hidden\" name=\"token\" value={token} />\n <Label htmlFor=\"password\">新密码</Label>\n <Input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"至少 8 位,包含字母和数字\"\n required\n />\n <Label htmlFor=\"confirmPassword\">确认新密码</Label>\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n placeholder=\"再次输入新密码\"\n required\n />\n <Button type=\"submit\" className=\"w-full\">更新密码并登录</Button>\n </form>\n\n <Button asChild variant=\"ghost\" className=\"w-full\">\n <a href=\"/login\">返回登录</a>\n </Button>\n </CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AA8CjB,SACE,KADF;AA5BR,eAAO,kBAAyC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,4BAA4B;AAC9B,GAA2B;AACzB,MAAI,mBAAoB,MAAM,gBAAgB,GAAI;AAChD,aAAS,yBAAyB;AAAA,EACpC;AACA,QAAM,EAAE,OAAO,MAAM,IAAI;AACzB,MAAI,CAAC,OAAO;AACV,aAAS,gCAAgC;AAAA,EAC3C;AACA,QAAM,EAAE,QAAQ,OAAO,OAAO,MAAM,YAAY,WAAW,iBAAiB,YAAY,IAAI;AAE5F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,WAAW;AAAA,QACX,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,MAEA,+BAAC,QAAK,WAAU,mBACd;AAAA,6BAAC,cACC;AAAA,8BAAC,aAAU,4CAAK;AAAA,UAChB,oBAAC,mBAAgB,8GAAgB;AAAA,WACnC;AAAA,QACA,qBAAC,eACE;AAAA,mBACC,oBAAC,SAAI,WAAU,mEACZ,iBACH;AAAA,UAGF,qBAAC,UAAK,QAAQ,qBACZ;AAAA,gCAAC,WAAM,MAAK,UAAS,MAAK,SAAQ,OAAO,OAAO;AAAA,YAChD,oBAAC,SAAM,SAAQ,YAAW,gCAAG;AAAA,YAC7B;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,UAAQ;AAAA;AAAA,YACV;AAAA,YACA,oBAAC,SAAM,SAAQ,mBAAkB,4CAAK;AAAA,YACtC;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,UAAQ;AAAA;AAAA,YACV;AAAA,YACA,oBAAC,UAAO,MAAK,UAAS,WAAU,UAAS,wDAAO;AAAA,aAClD;AAAA,UAEA,oBAAC,UAAO,SAAO,MAAC,SAAQ,SAAQ,WAAU,UACxC,8BAAC,OAAE,MAAK,UAAS,sCAAI,GACvB;AAAA,WACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { AuthConfig } from '../types.js';
|
|
2
|
+
export { SessionUser } from './session.js';
|
|
3
|
+
export { ADMIN_COOKIE, AuthViewer, USER_COOKIE, checkPassword, clearSessionCookie, clearUserSessionCookie, getAuthViewer, getCurrentUser, isAuthenticated, setSessionCookie, setUserSessionCookie, signUserToken, verifyUserToken } from './user-session.js';
|
|
4
|
+
export { hashPassword, validatePasswordStrength, verifyPassword } from './passwords.js';
|
|
5
|
+
export { User, UserListItem, UserRole, authenticateEmailUser, changeUserPassword, createEmailUser, deleteUserAccount, getUserByEmail, getUserById, issuePasswordResetToken, issueVerificationToken, listUsers, listUsersWithPostCounts, normalizeUserRole, resetPasswordWithToken, revokeUserSessions, setUserRole, upsertGoogleUser, userToSession, verifyEmailUser } from './users.js';
|
|
6
|
+
export { AuthRateLimitKind, checkAuthRateLimit, clearAuthRateLimit, clearAuthRateLimits, enforceAuthRateLimits, recordAuthFailure, recordAuthFailures } from './rate-limit.js';
|
|
7
|
+
export { TurnstileRuntimeConfig, getTurnstileRuntimeConfig, verifyTurnstileFromForm, verifyTurnstileToken } from './turnstile.js';
|
|
8
|
+
import '../content/models.js';
|
|
9
|
+
import '../notion/types.js';
|
|
10
|
+
import '../platform/current.js';
|
|
11
|
+
import '../platform/runtime.js';
|
|
12
|
+
import '../env-C5qu-0R-.js';
|
|
13
|
+
import '../platform/selection.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal user shape. Expanded in Task 3.2 to mirror the full D1 row.
|
|
17
|
+
*/
|
|
18
|
+
interface AuthUser {
|
|
19
|
+
id: number;
|
|
20
|
+
email: string;
|
|
21
|
+
role: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Minimal viewer shape returned by `requireViewer` / `requireRole`.
|
|
25
|
+
* Expanded in Task 3.2 to include session info and role flags.
|
|
26
|
+
*/
|
|
27
|
+
interface AuthViewer {
|
|
28
|
+
id: number;
|
|
29
|
+
email: string;
|
|
30
|
+
role: string;
|
|
31
|
+
isAdmin: boolean;
|
|
32
|
+
isVip: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rate-limit verdict returned by `checkRateLimit`.
|
|
36
|
+
*/
|
|
37
|
+
type AuthRateLimitResult = {
|
|
38
|
+
ok: true;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
retryAfterSec: number;
|
|
42
|
+
scope: "email" | "ip";
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Aggregate auth surface returned by `createAuth`. Each method is bound
|
|
46
|
+
* to the configured database and cookie settings; consumers should not
|
|
47
|
+
* need to pass these in again.
|
|
48
|
+
*/
|
|
49
|
+
interface Auth {
|
|
50
|
+
requireViewer(request: Request): Promise<{
|
|
51
|
+
user: AuthViewer;
|
|
52
|
+
}>;
|
|
53
|
+
requireRole(request: Request, role: string): Promise<{
|
|
54
|
+
user: AuthViewer;
|
|
55
|
+
}>;
|
|
56
|
+
listUsers(): Promise<AuthUser[]>;
|
|
57
|
+
setUserRole(userId: number, role: string): Promise<void>;
|
|
58
|
+
checkRateLimit(key: string, limit: number, windowMs: number): Promise<AuthRateLimitResult>;
|
|
59
|
+
verifyTurnstile(token: string, ip: string | null): Promise<boolean>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build an `Auth` object bound to `config` and the current platform
|
|
63
|
+
* runtime. The returned methods share the same database/cookie context,
|
|
64
|
+
* removing the need for module-level singletons.
|
|
65
|
+
*
|
|
66
|
+
* Runtime/database validation is deferred to the first call so callers
|
|
67
|
+
* that only need the typed surface (e.g. tests) can still construct the
|
|
68
|
+
* factory in environments without a configured D1 binding.
|
|
69
|
+
*/
|
|
70
|
+
declare function createAuth(config: AuthConfig): Auth;
|
|
71
|
+
|
|
72
|
+
export { type Auth, type AuthRateLimitResult, type AuthUser, createAuth };
|