@qlover/create-app 1.0.1 → 1.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/index.cjs +9 -9
  3. package/dist/index.js +9 -9
  4. package/dist/templates/next-app/config/Identifier/api.ts +7 -0
  5. package/dist/templates/next-app/config/Identifier/pages/page.register.ts +8 -0
  6. package/dist/templates/next-app/config/common.ts +1 -1
  7. package/dist/templates/next-app/config/i18n/HomeI18n.ts +2 -0
  8. package/dist/templates/next-app/config/i18n/register18n.ts +2 -1
  9. package/dist/templates/next-app/config/route.ts +9 -0
  10. package/dist/templates/next-app/migrations/schema/UserSchema.ts +1 -1
  11. package/dist/templates/next-app/next.config.ts +5 -4
  12. package/dist/templates/next-app/package.json +7 -8
  13. package/dist/templates/next-app/public/locales/en.json +4 -1
  14. package/dist/templates/next-app/public/locales/zh.json +4 -1
  15. package/dist/templates/next-app/src/app/[locale]/auth/layout.tsx +18 -0
  16. package/dist/templates/next-app/src/app/[locale]/{login → auth/login}/LoginForm.tsx +2 -1
  17. package/dist/templates/next-app/src/app/[locale]/{login → auth/login}/page.tsx +4 -5
  18. package/dist/templates/next-app/src/app/[locale]/auth/page.tsx +8 -0
  19. package/dist/templates/next-app/src/app/[locale]/{register → auth/register}/RegisterForm.tsx +24 -3
  20. package/dist/templates/next-app/src/app/[locale]/{register → auth/register}/page.tsx +4 -5
  21. package/dist/templates/next-app/src/app/[locale]/page.tsx +18 -45
  22. package/dist/templates/next-app/src/app/api/ai/completions/route.ts +13 -13
  23. package/dist/templates/next-app/src/app/api/auth/callback/route.ts +11 -0
  24. package/dist/templates/next-app/src/app/api/callback/route.ts +49 -0
  25. package/dist/templates/next-app/src/base/cases/AppConfig.ts +2 -0
  26. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +3 -6
  27. package/dist/templates/next-app/src/base/cases/DialogHandler.ts +0 -1
  28. package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +13 -15
  29. package/dist/templates/next-app/src/base/cases/RouterService.ts +2 -7
  30. package/dist/templates/next-app/src/base/cases/StringEncryptor.ts +0 -6
  31. package/dist/templates/next-app/src/base/cases/TranslateI18nUtil.ts +53 -0
  32. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +0 -10
  33. package/dist/templates/next-app/src/base/port/AdminLayoutInterface.ts +0 -3
  34. package/dist/templates/next-app/src/base/port/AppUserApiInterface.ts +1 -1
  35. package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +0 -18
  36. package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +10 -5
  37. package/dist/templates/next-app/src/base/services/{appApi/AppApiRequester.ts → AppApiRequester.ts} +16 -11
  38. package/dist/templates/next-app/src/base/services/AppUserGateway.ts +110 -0
  39. package/dist/templates/next-app/src/base/services/I18nService.ts +1 -7
  40. package/dist/templates/next-app/src/base/services/ResourceService.ts +1 -4
  41. package/dist/templates/next-app/src/base/services/UserService.ts +28 -17
  42. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +5 -7
  43. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +4 -3
  44. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +24 -16
  45. package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +2 -5
  46. package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +15 -18
  47. package/dist/templates/next-app/src/core/clientIoc/ClientIOCRegister.ts +0 -5
  48. package/dist/templates/next-app/src/core/globals.ts +1 -0
  49. package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +2 -8
  50. package/dist/templates/next-app/src/i18n/routing.ts +8 -3
  51. package/dist/templates/next-app/src/lib/supabase/client.ts +8 -0
  52. package/dist/templates/next-app/src/lib/supabase/conts.ts +2 -0
  53. package/dist/templates/next-app/src/lib/supabase/proxy.ts +84 -0
  54. package/dist/templates/next-app/src/lib/supabase/server.ts +38 -0
  55. package/dist/templates/next-app/src/proxy.ts +8 -1
  56. package/dist/templates/next-app/src/server/AppPageRouteParams.ts +5 -2
  57. package/dist/templates/next-app/src/server/NextApiServer.ts +2 -9
  58. package/dist/templates/next-app/src/server/PagesRouteParams.ts +3 -4
  59. package/dist/templates/next-app/src/server/ServerAuth.ts +18 -12
  60. package/dist/templates/next-app/src/server/SupabaseBridge.ts +66 -59
  61. package/dist/templates/next-app/src/server/controllers/UserController.ts +7 -2
  62. package/dist/templates/next-app/src/server/port/ServerAuthInterface.ts +4 -0
  63. package/dist/templates/next-app/src/server/port/ServerInterface.ts +2 -1
  64. package/dist/templates/next-app/src/server/port/UserServiceInterface.ts +7 -1
  65. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +0 -3
  66. package/dist/templates/next-app/src/server/repositorys/UserRepository.ts +0 -3
  67. package/dist/templates/next-app/src/server/services/UserService.ts +71 -51
  68. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +0 -3
  69. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +0 -6
  70. package/dist/templates/next-app/src/server/validators/SignupVerifyValidator.ts +68 -0
  71. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -3
  72. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +0 -6
  73. package/dist/templates/next-app/src/uikit/components-app/AdminButton.tsx +29 -0
  74. package/dist/templates/next-app/src/uikit/components-app/AppRoutePage.tsx +21 -28
  75. package/dist/templates/next-app/src/uikit/components-app/AuthButton.tsx +20 -0
  76. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +2 -2
  77. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +3 -17
  78. package/dist/templates/next-app/src/uikit/utils/getHashParams.ts +8 -0
  79. package/dist/templates/next-app/src/uikit/utils/getHashVerifyEmailParams.ts +42 -0
  80. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +2 -0
  81. package/package.json +2 -2
  82. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +0 -25
  83. package/dist/templates/next-app/src/base/cases/UserServiceApi.ts +0 -78
  84. package/dist/templates/next-app/src/base/services/adminApi/AdminApiRequester.ts +0 -25
  85. package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +0 -78
  86. package/dist/templates/next-app/src/server/port/UserControllerInerface.ts +0 -8
@@ -167,3 +167,11 @@ export const PAGE_REGISTER_LOGIN_LINK = 'page_register:login_link';
167
167
  * @localEn Please agree to the Terms of Service and Privacy Policy
168
168
  */
169
169
  export const PAGE_REGISTER_TERMS_REQUIRED = 'page_register:terms_required';
170
+
171
+ /**
172
+ * @description 注册后需要验证邮箱
173
+ * @localZh 请查收邮箱完成账号注册
174
+ * @localEn Please check your email to complete the registration
175
+ */
176
+ export const PAGE_REGISTER_EMAIL_VERIFY_TITLE =
177
+ 'page_register:email_verify_title';
@@ -26,7 +26,7 @@ export const useLocaleRoutes = true;
26
26
  * - true: 使用API获取本地化数据,可以在 /admin/locales 页面中对他进行修改
27
27
  * - false: 不使用API获取本地化数据,直接使用 `@brain-toolkit/ts2locales` 生成的json数据
28
28
  */
29
- export const useApiLocales = true;
29
+ export const useApiLocales = false;
30
30
 
31
31
  /**
32
32
  * 是否在在 useWarnTranslations 中警告缺失的翻译,而不是抛出错误
@@ -8,6 +8,8 @@ import * as i18nKeys from '../Identifier/pages/page.home';
8
8
  */
9
9
  export type HomeI18nInterface = typeof homeI18n;
10
10
 
11
+ export const homeI18nNamespace = 'page_home';
12
+
11
13
  export const homeI18n = Object.freeze({
12
14
  // basic meta properties
13
15
  title: i18nKeys.PAGE_HOME_TITLE,
@@ -39,5 +39,6 @@ export const register18n = Object.freeze({
39
39
  have_account: i18nKeys.PAGE_REGISTER_HAVE_ACCOUNT,
40
40
  confirm_password: i18nKeys.PAGE_REGISTER_CONFIRM_PASSWORD,
41
41
  terms_required: i18nKeys.PAGE_REGISTER_TERMS_REQUIRED,
42
- login_link: i18nKeys.PAGE_REGISTER_LOGIN_LINK
42
+ login_link: i18nKeys.PAGE_REGISTER_LOGIN_LINK,
43
+ email_verify: i18nKeys.PAGE_REGISTER_EMAIL_VERIFY_TITLE
43
44
  });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 登录页面路由地址
3
+ */
4
+ export const ROUTE_LOGIN = '/auth/login' as const;
5
+
6
+ /**
7
+ * 注册页面路由地址
8
+ */
9
+ export const ROUTE_REGISTER = '/auth/register' as const;
@@ -9,7 +9,7 @@ export const UserRole = {
9
9
  export type UserRoleType = (typeof UserRole)[keyof typeof UserRole];
10
10
 
11
11
  export const userSchema = z.object({
12
- id: z.number(),
12
+ id: z.string(),
13
13
  role: z.nativeEnum(UserRole),
14
14
  email: z.string().email(),
15
15
  password: z.string(),
@@ -12,10 +12,11 @@ generateLocales().catch((error) => {
12
12
  const nextConfig: NextConfig = {
13
13
  // reactStrictMode: false,
14
14
  // turbopack 在接下本地 file: 依赖时支持还不够好
15
- // turbopack: {
16
- // root: __dirname // 明确指定根目录
17
- // },
18
- transpilePackages: ['@qlover/corekit-bridge', '@qlover/fe-corekit'],
15
+ turbopack: {
16
+ root: __dirname // 明确指定根目录
17
+ },
18
+ // pages 路由需要
19
+ transpilePackages: ['@qlover/fe-corekit', '@qlover/corekit-bridge'],
19
20
  env: {
20
21
  APP_ENV: process.env.APP_ENV
21
22
  }
@@ -22,13 +22,12 @@
22
22
  "@ant-design/icons": "^6.0.0",
23
23
  "@ant-design/nextjs-registry": "^1.3.0",
24
24
  "@ant-design/v5-patch-for-react-19": "^1.0.3",
25
- "@brain-toolkit/antd-blocks": "^0.0.1",
25
+ "@brain-toolkit/antd-blocks": "^0.1.2",
26
26
  "@brain-toolkit/antd-theme-override": "^0.0.3",
27
- "@brain-toolkit/bridge": "^0.0.1",
28
- "@brain-toolkit/react-kit": "^0.1.0",
29
- "@qlover/corekit-bridge": "latest",
30
- "@qlover/fe-corekit": "latest",
31
- "@qlover/logger": "latest",
27
+ "@brain-toolkit/react-kit": "^0.2.2",
28
+ "@qlover/corekit-bridge": "^2.1.1",
29
+ "@qlover/fe-corekit": "^3.1.1",
30
+ "@qlover/logger": "^1.0.0",
32
31
  "@qlover/slice-store-react": "^1.4.1",
33
32
  "@supabase/postgrest-js": "^2.87.1",
34
33
  "@supabase/ssr": "^0.7.0",
@@ -41,7 +40,7 @@
41
40
  "inversify": "^7.8.1",
42
41
  "jsonwebtoken": "^9.0.2",
43
42
  "lodash": "^4.17.21",
44
- "next": "^16.0.3",
43
+ "next": "^16.1.6",
45
44
  "next-intl": "^4.5.8",
46
45
  "next-themes": "^0.4.6",
47
46
  "openai": "^5.23.0",
@@ -55,7 +54,7 @@
55
54
  "@brain-toolkit/ts2locales": "^0.2.3",
56
55
  "@eslint/eslintrc": "^3",
57
56
  "@qlover/env-loader": "^0.3.0",
58
- "@qlover/eslint-plugin": "latest",
57
+ "@qlover/eslint-plugin": "^2.0.0",
59
58
  "@tailwindcss/postcss": "^4",
60
59
  "@types/lodash": "^4.17.20",
61
60
  "@types/ms": "^2.1.0",
@@ -175,5 +175,8 @@
175
175
  "page_register:privacy_link": "Privacy Policy",
176
176
  "page_register:have_account": "Already have an account?",
177
177
  "page_register:login_link": "Sign in",
178
- "page_register:terms_required": "Please agree to the Terms of Service and Privacy Policy"
178
+ "page_register:terms_required": "Please agree to the Terms of Service and Privacy Policy",
179
+ "api:user__not_verfified": "User not verified",
180
+ "page_register:email_verify_title": "Please check your email to complete the registration",
181
+ "page_home:welcome_with_user": "Welcome {email} to the homepage"
179
182
  }
@@ -175,5 +175,8 @@
175
175
  "page_register:privacy_link": "隐私政策",
176
176
  "page_register:have_account": "已有账号?",
177
177
  "page_register:login_link": "登录",
178
- "page_register:terms_required": "请同意服务条款和隐私政策"
178
+ "page_register:terms_required": "请同意服务条款和隐私政策",
179
+ "api:user__not_verfified": "用户未验证",
180
+ "page_register:email_verify_title": "请查收邮箱完成账号注册",
181
+ "page_home:welcome_with_user": "欢迎 {email} 来到主页"
179
182
  }
@@ -0,0 +1,18 @@
1
+ import type { PageLayoutProps } from '@/base/types/AppPageRouter';
2
+ import { bootstrapServer } from '@/core/bootstraps/BootstrapServer';
3
+ import { redirect } from '@/i18n/routing';
4
+ import { AppPageRouteParams } from '@/server/AppPageRouteParams';
5
+ import { ServerAuth } from '@/server/ServerAuth';
6
+
7
+ export default async function AuthRootPage(props: PageLayoutProps) {
8
+ const pageParams = new AppPageRouteParams(await props.params!);
9
+ const locale = pageParams.getLocale();
10
+
11
+ if (await bootstrapServer.getIOC(ServerAuth).hasAuth()) {
12
+ console.info('> User already logged in, redirecting to home page');
13
+
14
+ return redirect({ href: '/', locale: locale });
15
+ }
16
+
17
+ return <>{props.children}</>;
18
+ }
@@ -9,6 +9,7 @@ import { useIOC } from '@/uikit/hook/useIOC';
9
9
  import { useWarnTranslations } from '@/uikit/hook/useWarnTranslations';
10
10
  import type { LoginI18nInterface } from '@config/i18n/loginI18n';
11
11
  import { I } from '@config/IOCIdentifier';
12
+ import { ROUTE_REGISTER } from '@config/route';
12
13
 
13
14
  interface LoginFormData {
14
15
  email: string;
@@ -116,7 +117,7 @@ export function LoginForm(props: { tt: LoginI18nInterface }) {
116
117
 
117
118
  <div className="text-center mt-6">
118
119
  <span className="text-text-tertiary">{tt.noAccount} </span>
119
- <LocaleLink href="/register" title={tt.createAccountTitle}>
120
+ <LocaleLink href={ROUTE_REGISTER} title={tt.createAccountTitle}>
120
121
  {tt.createAccount}
121
122
  </LocaleLink>
122
123
  </div>
@@ -1,6 +1,6 @@
1
1
  import { notFound } from 'next/navigation';
2
2
  import type { PageParamsProps } from '@/base/types/AppPageRouter';
3
- import { BootstrapServer } from '@/core/bootstraps/BootstrapServer';
3
+ import { bootstrapServer } from '@/core/bootstraps/BootstrapServer';
4
4
  import { redirect } from '@/i18n/routing';
5
5
  import {
6
6
  AppPageRouteParams,
@@ -11,6 +11,7 @@ import { FeatureItem } from '@/uikit/components/FeatureItem';
11
11
  import { AppRoutePage } from '@/uikit/components-app/AppRoutePage';
12
12
  import { loginI18n, i18nConfig, NS_PAGE_LOGIN } from '@config/i18n';
13
13
  import { COMMON_ADMIN_TITLE } from '@config/Identifier';
14
+ import { ROUTE_LOGIN } from '@config/route';
14
15
  import { LoginForm } from './LoginForm';
15
16
  import type { Metadata } from 'next';
16
17
 
@@ -45,9 +46,7 @@ export default async function LoginPage(props: PageParamsProps) {
45
46
  const params = await props.params;
46
47
  const pageParams = new AppPageRouteParams(params);
47
48
 
48
- const server = new BootstrapServer();
49
-
50
- if (await server.getIOC(ServerAuth).hasAuth()) {
49
+ if (await bootstrapServer.getIOC(ServerAuth).hasAuth()) {
51
50
  return redirect({ href: '/', locale: params.locale! });
52
51
  }
53
52
 
@@ -63,7 +62,7 @@ export default async function LoginPage(props: PageParamsProps) {
63
62
  title: tt.title,
64
63
  adminTitle: tt.adminTitle
65
64
  }}
66
- headerHref="/login"
65
+ headerHref={ROUTE_LOGIN}
67
66
  mainProps={{
68
67
  className: 'text-xs1 bg-primary flex min-h-screen'
69
68
  }}
@@ -0,0 +1,8 @@
1
+ import { redirect } from 'next/navigation';
2
+ import { ROUTE_LOGIN } from '@config/route';
3
+
4
+ export default async function AuthRootPage() {
5
+ console.log('AuthRootPage redirect to login page');
6
+
7
+ redirect(ROUTE_LOGIN);
8
+ }
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { LockOutlined, MailOutlined, UserOutlined } from '@ant-design/icons';
4
+ import { useStore } from '@brain-toolkit/react-kit';
4
5
  import { Button, Checkbox, Form, Input } from 'antd';
5
6
  import { useState } from 'react';
6
7
  import { useIOC } from '@/uikit/hook/useIOC';
@@ -13,12 +14,20 @@ export function RegisterForm(props: { tt: RegisterI18nInterface }) {
13
14
  const logger = useIOC(I.Logger);
14
15
  const routerService = useIOC(I.RouterServiceInterface);
15
16
  const [loading, setLoading] = useState(false);
17
+ const result = useStore(userService.getUIStore(), (state) => state.result);
16
18
 
17
- const handleRegister = async (values: unknown) => {
19
+ const handleRegister = async (values: {
20
+ username: string;
21
+ email: string;
22
+ password: string;
23
+ }) => {
18
24
  try {
19
25
  setLoading(true);
20
- await userService.register(values);
21
- routerService.gotoLogin();
26
+ await userService.register({
27
+ username: values.username,
28
+ email: values.email,
29
+ password: values.password
30
+ });
22
31
  } catch (error) {
23
32
  logger.error(error);
24
33
  } finally {
@@ -39,7 +48,19 @@ export function RegisterForm(props: { tt: RegisterI18nInterface }) {
39
48
  layout="vertical"
40
49
  className="space-y-4"
41
50
  validateTrigger="onSubmit"
51
+ disabled={!!result}
52
+ initialValues={{
53
+ username: 'myused@sina.com',
54
+ email: 'myused@sina.com',
55
+ password: 'q1234566',
56
+ confirmPassword: 'q1234566',
57
+ agreeToTerms: true
58
+ }}
42
59
  >
60
+ {result && result.email_confirmed_at == null ? (
61
+ <div className="text-xl text-red-500">{tt.email_verify}</div>
62
+ ) : null}
63
+
43
64
  <Form.Item
44
65
  name="username"
45
66
  rules={[
@@ -1,6 +1,6 @@
1
1
  import { notFound } from 'next/navigation';
2
2
  import type { PageParamsProps } from '@/base/types/AppPageRouter';
3
- import { BootstrapServer } from '@/core/bootstraps/BootstrapServer';
3
+ import { bootstrapServer } from '@/core/bootstraps/BootstrapServer';
4
4
  import { redirect } from '@/i18n/routing';
5
5
  import {
6
6
  AppPageRouteParams,
@@ -45,9 +45,7 @@ export default async function LoginPage(props: PageParamsProps) {
45
45
  const params = await props.params;
46
46
  const pageParams = new AppPageRouteParams(params);
47
47
 
48
- const server = new BootstrapServer();
49
-
50
- if (await server.getIOC(ServerAuth).hasAuth()) {
48
+ if (await bootstrapServer.getIOC(ServerAuth).hasAuth()) {
51
49
  return redirect({ href: '/', locale: params.locale! });
52
50
  }
53
51
 
@@ -63,7 +61,8 @@ export default async function LoginPage(props: PageParamsProps) {
63
61
  title: tt.title,
64
62
  adminTitle: tt.adminTitle
65
63
  }}
66
- headerHref="/login"
64
+ showAuthButton={false}
65
+ headerHref=""
67
66
  mainProps={{
68
67
  className: 'text-xs1 bg-primary flex min-h-screen'
69
68
  }}
@@ -1,14 +1,13 @@
1
1
  import { Button } from 'antd';
2
2
  import type { PageParamsProps } from '@/base/types/AppPageRouter';
3
- import { BootstrapServer } from '@/core/bootstraps/BootstrapServer';
4
- import { redirect } from '@/i18n/routing';
3
+ import { bootstrapServer } from '@/core/bootstraps/BootstrapServer';
5
4
  import {
6
5
  AppPageRouteParams,
7
6
  type PageParamsType
8
7
  } from '@/server/AppPageRouteParams';
9
8
  import { ServerAuth } from '@/server/ServerAuth';
10
9
  import { AppRoutePage } from '@/uikit/components-app/AppRoutePage';
11
- import { i18nConfig, homeI18n } from '@config/i18n';
10
+ import { i18nConfig, homeI18n, homeI18nNamespace } from '@config/i18n';
12
11
  import { COMMON_ADMIN_TITLE } from '@config/Identifier';
13
12
  import type { Metadata } from 'next';
14
13
 
@@ -43,27 +42,27 @@ export async function generateMetadata({
43
42
  }
44
43
 
45
44
  export default async function Home({ params }: PageParamsProps) {
46
- const server = new BootstrapServer();
47
45
  const pageParams = new AppPageRouteParams(await params!);
48
- const locale = pageParams.getLocale();
49
- const tt = await pageParams.getI18nInterface({
50
- ...homeI18n,
51
- adminTitle: COMMON_ADMIN_TITLE
52
- });
46
+ const user = await bootstrapServer.getIOC(ServerAuth).getUser();
53
47
 
54
- if (!(await server.getIOC(ServerAuth).hasAuth())) {
55
- return redirect({ href: '/login', locale });
56
- }
48
+ // const locale = pageParams.getLocale();
49
+ const tt = await pageParams.getI18nInterface(
50
+ {
51
+ ...homeI18n,
52
+ adminTitle: COMMON_ADMIN_TITLE
53
+ },
54
+ homeI18nNamespace
55
+ );
57
56
 
58
57
  return (
59
58
  <AppRoutePage
60
59
  data-testid="AppRoute-HomePage"
61
- showLogoutButton
62
- showAdminButton
63
60
  tt={{
64
61
  title: tt.title,
65
62
  adminTitle: tt.adminTitle
66
63
  }}
64
+ showAdminButton
65
+ showAuthButton
67
66
  >
68
67
  {/* Hero Section */}
69
68
  <section className="py-16 px-4">
@@ -71,41 +70,15 @@ export default async function Home({ params }: PageParamsProps) {
71
70
  <h1 className="text-4xl md:text-5xl font-bold mb-6 text-text">
72
71
  {tt.welcome}
73
72
  </h1>
73
+ {!!user ? (
74
+ <p data-testid="AuthUserEmail" className="text-lg text-text">
75
+ {user.email}
76
+ </p>
77
+ ) : null}
74
78
  <p className="text-xl text-text-secondary mb-8">{tt.description}</p>
75
79
  </div>
76
80
  </section>
77
81
 
78
- {/* Navigation Grid */}
79
- <section className="max-w-6xl mx-auto px-4 py-12">
80
- <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
81
- {/* {navigationItems.map((item) => (
82
- <LocaleLink
83
- data-testid={`HomePage-navigation-${item.href}`}
84
- key={item.href}
85
- title={item.titleKey}
86
- className={clsx(
87
- href={item.href}
88
- 'block rounded-lg p-6',
89
- 'bg-secondary',
90
- 'border border-border',
91
- 'hover:bg-elevated',
92
- 'transition-colors duration-200'
93
- )}
94
- >
95
- <h3 className={`text-xl font-semibold mb-3 text-text`}>
96
- {t(item.titleKey)}
97
- </h3>
98
- <p className="text-text-secondary mb-4">
99
- {t(item.descriptionKey)}
100
- </p>
101
- <Button type="primary" className="w-full">
102
- {t(i18nKeys.HOME_EXPLORE)}
103
- </Button>
104
- </LocaleLink>
105
- ))} */}
106
- </div>
107
- </section>
108
-
109
82
  {/* Call to Action Section */}
110
83
  <section className="py-16 px-4 bg-elevated">
111
84
  <div className="max-w-4xl mx-auto text-center">
@@ -1,25 +1,25 @@
1
1
  import { ExecutorError } from '@qlover/fe-corekit';
2
2
  import { NextResponse } from 'next/server';
3
- import { BootstrapServer } from '@/core/bootstraps/BootstrapServer';
3
+ import { bootstrapServer } from '@/core/bootstraps/BootstrapServer';
4
4
  import { AppErrorApi } from '@/server/AppErrorApi';
5
5
  import { AppSuccessApi } from '@/server/AppSuccessApi';
6
6
  import { AIService } from '@/server/services/AIService';
7
7
 
8
8
  export async function GET() {
9
- const server = new BootstrapServer();
9
+ const result = await bootstrapServer.execNoError(
10
+ async ({ parameters: { IOC } }) => {
11
+ // const requestBody = await req.json();
10
12
 
11
- const result = await server.execNoError(async ({ parameters: { IOC } }) => {
12
- // const requestBody = await req.json();
13
+ const result = await IOC(AIService).completions([
14
+ {
15
+ role: 'user',
16
+ content: 'hello'
17
+ }
18
+ ]);
13
19
 
14
- const result = await IOC(AIService).completions([
15
- {
16
- role: 'user',
17
- content: 'hello'
18
- }
19
- ]);
20
-
21
- return result;
22
- });
20
+ return result;
21
+ }
22
+ );
23
23
 
24
24
  if (result instanceof ExecutorError) {
25
25
  console.log(result);
@@ -0,0 +1,11 @@
1
+ import { NextResponse } from 'next/server';
2
+ import type { NextRequest } from 'next/server';
3
+
4
+ export function GET(req: NextRequest) {
5
+ return NextResponse.json({
6
+ message: 'Hello World',
7
+ hash: req.nextUrl.hash,
8
+ url: req.url,
9
+ href: req.nextUrl.href
10
+ });
11
+ }
@@ -0,0 +1,49 @@
1
+ import { type NextRequest, NextResponse } from 'next/server';
2
+ import { createClient } from '@/lib/supabase/server';
3
+
4
+ export async function GET(request: NextRequest) {
5
+ const requestUrl = new URL(request.url);
6
+ const code = requestUrl.searchParams.get('code');
7
+
8
+ if (code) {
9
+ console.log('api/callback code', code);
10
+ try {
11
+ const supabase = await createClient();
12
+ // 使用 code 交换 session
13
+ const { error } = await supabase.auth.exchangeCodeForSession(code);
14
+
15
+ if (error) {
16
+ console.error('验证失败:', error.message);
17
+ // 重定向到错误页面
18
+ return NextResponse.redirect(
19
+ new URL('/auth/error?error=verification_failed', request.url)
20
+ );
21
+ }
22
+
23
+ // 获取用户信息
24
+ const {
25
+ data: { user }
26
+ } = await supabase.auth.getUser();
27
+
28
+ // 检查邮箱是否已验证
29
+ if (user && user.email_confirmed_at) {
30
+ console.log('✅ 邮箱已验证成功');
31
+ // 重定向到成功页面
32
+ return NextResponse.redirect(new URL('/', request.url));
33
+ } else {
34
+ console.log('⏳ 邮箱验证中...');
35
+ // 重定向到验证提醒页面
36
+ return NextResponse.redirect(
37
+ new URL('/auth/verify-email', request.url)
38
+ );
39
+ }
40
+ } catch (error) {
41
+ console.error('回调处理错误:', error);
42
+ return NextResponse.redirect(new URL('/auth/error', request.url));
43
+ }
44
+ }
45
+
46
+ // 如果没有 code 参
47
+ // 数,重定向到登录页
48
+ return NextResponse.redirect(new URL('/auth/login', request.url));
49
+ }
@@ -35,4 +35,6 @@ export class AppConfig implements EnvConfigInterface {
35
35
 
36
36
  public readonly openaiBaseUrl: string = process.env.CEREBRAS_BASE_URL!;
37
37
  public readonly openaiApiKey: string = process.env.CEREBRAS_API_KEY!;
38
+
39
+ public readonly isProduction: boolean = this.env === 'production';
38
40
  }
@@ -13,9 +13,9 @@ import type { I18nServiceInterface } from '../port/I18nServiceInterface';
13
13
  import type { UIDialogInterface } from '@qlover/corekit-bridge';
14
14
 
15
15
  @injectable()
16
- export class DialogErrorPlugin
17
- implements LifecyclePluginInterface<ExecutorContextInterface<unknown>>
18
- {
16
+ export class DialogErrorPlugin implements LifecyclePluginInterface<
17
+ ExecutorContextInterface<unknown>
18
+ > {
19
19
  public readonly pluginName = 'DialogErrorPlugin';
20
20
 
21
21
  constructor(
@@ -51,9 +51,6 @@ export class DialogErrorPlugin
51
51
  }
52
52
  }
53
53
 
54
- /**
55
- * @override
56
- */
57
54
  protected isI18nMessage(message: string): boolean {
58
55
  return i18nKeySchema.safeParse(message).success;
59
56
  }
@@ -69,7 +69,6 @@ export class DialogHandler
69
69
  /**
70
70
  * Formats error message from various error types
71
71
 
72
- * @override
73
72
  */
74
73
  protected formatErrorMessage(error: unknown): string {
75
74
  if (error instanceof Error) return error.message;
@@ -6,8 +6,9 @@ import type {
6
6
  EncryptorInterface
7
7
  } from '@qlover/fe-corekit';
8
8
 
9
- export interface RequestEncryptPluginProps<Request = unknown>
10
- extends RequestAdapterConfig<Request> {
9
+ export interface RequestEncryptPluginProps<
10
+ Request = unknown
11
+ > extends RequestAdapterConfig<Request> {
11
12
  /**
12
13
  * 加密密码在 HTTP 请求中
13
14
  *
@@ -18,12 +19,9 @@ export interface RequestEncryptPluginProps<Request = unknown>
18
19
  encryptProps?: string[] | string;
19
20
  }
20
21
 
21
- export class RequestEncryptPlugin
22
- implements
23
- LifecyclePluginInterface<
24
- ExecutorContextInterface<RequestEncryptPluginProps>
25
- >
26
- {
22
+ export class RequestEncryptPlugin implements LifecyclePluginInterface<
23
+ ExecutorContextInterface<RequestEncryptPluginProps>
24
+ > {
27
25
  public readonly pluginName = 'RequestEncryptPlugin';
28
26
 
29
27
  constructor(protected encryptor: EncryptorInterface<string, string>) {}
@@ -41,16 +39,16 @@ export class RequestEncryptPlugin
41
39
  isObject(context.parameters.data) &&
42
40
  encryptProps
43
41
  ) {
44
- context.parameters.data = this.encryptData(
45
- clone(context.parameters.data),
46
- encryptProps
47
- );
42
+ context.setParameters({
43
+ ...context.parameters,
44
+ data: {
45
+ ...context.parameters.data,
46
+ ...this.encryptData(clone(context.parameters.data), encryptProps)
47
+ }
48
+ });
48
49
  }
49
50
  }
50
51
 
51
- /**
52
- * @override
53
- */
54
52
  protected encryptData<T extends object>(
55
53
  data: T,
56
54
  encryptProps?: string | string[]
@@ -1,4 +1,5 @@
1
1
  import { inject, injectable } from 'inversify';
2
+ import { ROUTE_LOGIN } from '@config/route';
2
3
  import { NavigateBridge } from './NavigateBridge';
3
4
  import type { RouterInterface, RouterPathname } from '../port/RouterInterface';
4
5
  import type { UIBridgeInterface } from '@qlover/corekit-bridge';
@@ -27,16 +28,10 @@ export class RouterService implements RouterInterface {
27
28
  this.goto('/');
28
29
  }
29
30
 
30
- /**
31
- * @override
32
- */
33
31
  public gotoLogin(): void {
34
- this.goto('/login');
32
+ this.goto(ROUTE_LOGIN);
35
33
  }
36
34
 
37
- /**
38
- * @override
39
- */
40
35
  public replaceHome(): void {
41
36
  this.uiBridge.getUIBridge()?.replace('/');
42
37
  }
@@ -18,9 +18,6 @@ export class StringEncryptor implements EncryptorInterface<string, string> {
18
18
  this.key = appConfig.stringEncryptorKey;
19
19
  }
20
20
 
21
- /**
22
- * @override
23
- */
24
21
  protected encryptWithKey(str: string, key: string): string {
25
22
  const result = [];
26
23
  for (let i = 0; i < str.length; i++) {
@@ -34,9 +31,6 @@ export class StringEncryptor implements EncryptorInterface<string, string> {
34
31
  return result.join('');
35
32
  }
36
33
 
37
- /**
38
- * @override
39
- */
40
34
  protected decryptWithKey(str: string, key: string): string {
41
35
  const result = [];
42
36
  for (let i = 0; i < str.length; i++) {