create-secra 0.1.11 → 1.0.2

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 (133) hide show
  1. package/README.md +15 -5
  2. package/README.zh-CN.md +15 -4
  3. package/antd-adapter-template/README.md +24 -0
  4. package/antd-adapter-template/index.html +16 -0
  5. package/antd-adapter-template/package-lock.json +3420 -0
  6. package/antd-adapter-template/package.json +20 -47
  7. package/antd-adapter-template/src/app/App.tsx +7 -0
  8. package/antd-adapter-template/src/app/layouts/AppLayout.tsx +163 -0
  9. package/antd-adapter-template/src/app/router.ts +26 -0
  10. package/antd-adapter-template/src/app/routes/RouteTitleSync.tsx +26 -0
  11. package/antd-adapter-template/src/app/routes/dynamic-routes.ts +52 -0
  12. package/antd-adapter-template/src/app/routes/route-modules.ts +4 -0
  13. package/antd-adapter-template/src/app/routes/static-routes.tsx +110 -0
  14. package/antd-adapter-template/src/app/routes/types.ts +9 -0
  15. package/antd-adapter-template/src/features/auth/api/auth-api.ts +61 -0
  16. package/antd-adapter-template/src/features/auth/auth-store.ts +125 -0
  17. package/antd-adapter-template/src/features/auth/auth-types.ts +29 -0
  18. package/antd-adapter-template/src/features/auth/authorization.ts +46 -0
  19. package/antd-adapter-template/src/features/auth/use-auth.ts +10 -0
  20. package/antd-adapter-template/src/main.tsx +79 -0
  21. package/antd-adapter-template/src/pages/dashboard/DashboardPage.tsx +105 -0
  22. package/antd-adapter-template/src/pages/errors/ForbiddenPage.tsx +36 -0
  23. package/antd-adapter-template/src/pages/errors/NotFoundPage.tsx +36 -0
  24. package/antd-adapter-template/src/pages/home/HomePage.tsx +129 -0
  25. package/antd-adapter-template/src/pages/login/LoginPage.tsx +128 -0
  26. package/antd-adapter-template/src/pages/permission-test/PermissionTestPage.tsx +55 -0
  27. package/antd-adapter-template/src/pages/restricted/RestrictedDemoPage.tsx +17 -0
  28. package/antd-adapter-template/src/shared/kernel/app-kernel.ts +10 -0
  29. package/antd-adapter-template/src/shared/request/client.ts +46 -0
  30. package/antd-adapter-template/src/shared/request/contracts.ts +6 -0
  31. package/antd-adapter-template/src/shared/request/kv-adapter.ts +14 -0
  32. package/antd-adapter-template/src/shared/request/kv-backend.ts +244 -0
  33. package/antd-adapter-template/src/shared/request/ky-browser-stub.ts +6 -0
  34. package/antd-adapter-template/src/shared/request/undici-browser-stub.ts +4 -0
  35. package/antd-adapter-template/src/styles/global.css +185 -0
  36. package/antd-adapter-template/src/vite-env.d.ts +2 -0
  37. package/antd-adapter-template/tsconfig.app.json +10 -13
  38. package/antd-adapter-template/tsconfig.json +7 -2
  39. package/antd-adapter-template/tsconfig.node.json +6 -16
  40. package/antd-adapter-template/vite.config.ts +24 -0
  41. package/bin/index.mjs +32 -14
  42. package/package.json +2 -2
  43. package/{antd-adapter-template/apps/core → template}/index.html +2 -3
  44. package/template/package.json +14 -46
  45. package/template/src/App.tsx +48 -0
  46. package/template/src/main.tsx +36 -0
  47. package/template/src/styles.css +163 -0
  48. package/template/src/vite-env.d.ts +1 -0
  49. package/template/tsconfig.app.json +0 -5
  50. package/template/tsconfig.node.json +0 -5
  51. package/template/vite.config.ts +6 -0
  52. package/antd-adapter-template/apps/core/package.json +0 -18
  53. package/antd-adapter-template/apps/core/public/favicon.ico +0 -1
  54. package/antd-adapter-template/apps/core/public/favicon.svg +0 -1
  55. package/antd-adapter-template/apps/core/public/logo.svg +0 -1
  56. package/antd-adapter-template/apps/core/src/api/auth.ts +0 -49
  57. package/antd-adapter-template/apps/core/src/assets/react.svg +0 -1
  58. package/antd-adapter-template/apps/core/src/components/AntdGlobalProvider.tsx +0 -87
  59. package/antd-adapter-template/apps/core/src/components/AntdRootLayout.tsx +0 -10
  60. package/antd-adapter-template/apps/core/src/components/layout.tsx +0 -387
  61. package/antd-adapter-template/apps/core/src/guards/auth-route-guard.ts +0 -45
  62. package/antd-adapter-template/apps/core/src/main.tsx +0 -65
  63. package/antd-adapter-template/apps/core/src/pages/auth/components/account-login-fields.tsx +0 -60
  64. package/antd-adapter-template/apps/core/src/pages/auth/components/phone-login-fields.tsx +0 -60
  65. package/antd-adapter-template/apps/core/src/pages/auth/login.tsx +0 -169
  66. package/antd-adapter-template/apps/core/src/pages/index.tsx +0 -156
  67. package/antd-adapter-template/apps/core/src/router.ts +0 -42
  68. package/antd-adapter-template/apps/core/src/shims/use-sync-external-store-shim.ts +0 -3
  69. package/antd-adapter-template/apps/core/src/theme/theme.css +0 -48
  70. package/antd-adapter-template/apps/core/src/types/crypto-js.d.ts +0 -5
  71. package/antd-adapter-template/apps/core/src/utils/index.ts +0 -12
  72. package/antd-adapter-template/apps/core/src/utils/md5.ts +0 -6
  73. package/antd-adapter-template/apps/core/tsconfig.app.json +0 -11
  74. package/antd-adapter-template/apps/core/tsconfig.json +0 -13
  75. package/antd-adapter-template/apps/core/tsconfig.node.json +0 -7
  76. package/antd-adapter-template/apps/core/vite.config.ts +0 -118
  77. package/antd-adapter-template/eslint.config.js +0 -23
  78. package/antd-adapter-template/packages/sdk/.swcrc +0 -18
  79. package/antd-adapter-template/packages/sdk/package.json +0 -52
  80. package/antd-adapter-template/packages/sdk/src/build/index.ts +0 -28
  81. package/antd-adapter-template/packages/sdk/src/build/plugins/auto-import.ts +0 -46
  82. package/antd-adapter-template/packages/sdk/src/build/plugins/bundle-analyzer.ts +0 -33
  83. package/antd-adapter-template/packages/sdk/src/build/plugins/remove-console.ts +0 -23
  84. package/antd-adapter-template/packages/sdk/src/build/plugins/unocss.ts +0 -202
  85. package/antd-adapter-template/packages/sdk/src/build/plugins/unplugin-icon.ts +0 -43
  86. package/antd-adapter-template/packages/sdk/src/components/i18n-switch-dropdown.tsx +0 -139
  87. package/antd-adapter-template/packages/sdk/src/components/index.ts +0 -2
  88. package/antd-adapter-template/packages/sdk/src/components/theme-switch-dropdown.tsx +0 -131
  89. package/antd-adapter-template/packages/sdk/src/hooks/auth/core.ts +0 -101
  90. package/antd-adapter-template/packages/sdk/src/hooks/auth/index.ts +0 -139
  91. package/antd-adapter-template/packages/sdk/src/hooks/auth/with-auth.tsx +0 -41
  92. package/antd-adapter-template/packages/sdk/src/hooks/index.ts +0 -1
  93. package/antd-adapter-template/packages/sdk/src/i18n/index.ts +0 -150
  94. package/antd-adapter-template/packages/sdk/src/index.ts +0 -11
  95. package/antd-adapter-template/packages/sdk/src/request/index.ts +0 -436
  96. package/antd-adapter-template/packages/sdk/src/storage/README.md +0 -30
  97. package/antd-adapter-template/packages/sdk/src/storage/index.ts +0 -57
  98. package/antd-adapter-template/packages/sdk/src/styles/reset.css +0 -111
  99. package/antd-adapter-template/packages/sdk/src/theme/index.ts +0 -466
  100. package/antd-adapter-template/packages/sdk/tsconfig.json +0 -16
  101. package/antd-adapter-template/pnpm-workspace.yaml +0 -3
  102. package/antd-adapter-template/turbo.json +0 -17
  103. package/template/apps/core/index.html +0 -13
  104. package/template/apps/core/package.json +0 -18
  105. package/template/apps/core/public/favicon.ico +0 -1
  106. package/template/apps/core/public/favicon.svg +0 -1
  107. package/template/apps/core/public/logo.svg +0 -1
  108. package/template/apps/core/src/assets/react.svg +0 -1
  109. package/template/apps/core/src/main.tsx +0 -14
  110. package/template/apps/core/src/pages/index.tsx +0 -84
  111. package/template/apps/core/src/router.ts +0 -19
  112. package/template/apps/core/src/types/auto-imports.d.ts +0 -130
  113. package/template/apps/core/tsconfig.app.json +0 -7
  114. package/template/apps/core/tsconfig.json +0 -7
  115. package/template/apps/core/tsconfig.node.json +0 -7
  116. package/template/apps/core/vite.config.ts +0 -86
  117. package/template/eslint.config.js +0 -23
  118. package/template/packages/sdk/.swcrc +0 -18
  119. package/template/packages/sdk/package-lock.json +0 -1621
  120. package/template/packages/sdk/package.json +0 -32
  121. package/template/packages/sdk/src/build/index.ts +0 -33
  122. package/template/packages/sdk/src/build/plugins/auto-import.ts +0 -47
  123. package/template/packages/sdk/src/build/plugins/bundle-analyzer.ts +0 -35
  124. package/template/packages/sdk/src/build/plugins/remove-console.ts +0 -21
  125. package/template/packages/sdk/src/build/plugins/unocss.ts +0 -113
  126. package/template/packages/sdk/src/build/plugins/unplugin-icon.ts +0 -43
  127. package/template/packages/sdk/src/index.ts +0 -1
  128. package/template/packages/sdk/src/request/index.ts +0 -341
  129. package/template/packages/sdk/src/styles/reset.css +0 -111
  130. package/template/packages/sdk/tsconfig.json +0 -16
  131. package/template/pnpm-lock.yaml +0 -8055
  132. package/template/pnpm-workspace.yaml +0 -3
  133. package/template/turbo.json +0 -17
@@ -1,131 +0,0 @@
1
- import {
2
- SunOutlined,
3
- DesktopOutlined,
4
- MoonOutlined,
5
- } from "@ant-design/icons";
6
- import { Button, Dropdown, Space, type MenuProps } from "antd";
7
- import { ThemeSwitch } from "@vlian/framework/components";
8
- import { useCallback, useEffect, useMemo } from "react";
9
- import { cache, type StorageStrategy } from "../storage/index.js";
10
- import { useThemeSwitch, type ThemeMode } from "../theme/index.js";
11
-
12
- const MODE_ICON: Record<ThemeMode, React.ReactNode> = {
13
- light: <SunOutlined />,
14
- dark: <MoonOutlined />,
15
- system: <DesktopOutlined />,
16
- };
17
-
18
- export interface ThemeSwitchDropdownProps {
19
- storageType?: StorageStrategy;
20
- storageKey?: string;
21
- }
22
-
23
- export const ThemeSwitchDropdown = ({
24
- storageType = "localstorage",
25
- storageKey = "theme-mode",
26
- }: ThemeSwitchDropdownProps) => {
27
- const { setThemeMode } = useThemeSwitch();
28
-
29
- useEffect(() => {
30
- if (storageType !== "indexeddb") {
31
- return;
32
- }
33
-
34
- let disposed = false;
35
-
36
- const restoreThemeMode = async () => {
37
- const nextMode = await cache.indexeddb.get<ThemeMode>(storageKey);
38
- if (disposed || !nextMode) {
39
- return;
40
- }
41
- if (nextMode === "light" || nextMode === "dark" || nextMode === "system") {
42
- setThemeMode(nextMode);
43
- }
44
- };
45
-
46
- void restoreThemeMode();
47
- return () => {
48
- disposed = true;
49
- };
50
- }, [setThemeMode, storageKey, storageType]);
51
-
52
- const persistence = useMemo(() => {
53
- if (typeof window === "undefined") {
54
- return { enabled: false, key: storageKey };
55
- }
56
-
57
- if (storageType === "localstorage") {
58
- return { key: storageKey, storage: window.localStorage };
59
- }
60
-
61
- if (storageType === "sessionStorage") {
62
- return { key: storageKey, storage: window.sessionStorage };
63
- }
64
-
65
- return { enabled: false, key: storageKey };
66
- }, [storageKey, storageType]);
67
-
68
- const handleChange = useCallback(
69
- (nextMode: ThemeMode) => {
70
- if (storageType === "indexeddb") {
71
- void cache.indexeddb.set(storageKey, nextMode, -1);
72
- }
73
- },
74
- [storageKey, storageType],
75
- );
76
-
77
- const renderDropdown = useCallback(
78
- ({
79
- mode,
80
- modes,
81
- labels,
82
- setMode,
83
- }: {
84
- mode: ThemeMode;
85
- modes: ThemeMode[];
86
- labels: Record<ThemeMode, string>;
87
- setMode: (nextMode: ThemeMode) => void;
88
- }) => {
89
- const menu: MenuProps = {
90
- selectedKeys: [mode],
91
- onClick: ({ key }) => {
92
- if (key !== "light" && key !== "dark" && key !== "system") {
93
- return;
94
- }
95
- setMode(key as ThemeMode);
96
- },
97
- items: modes.map((item) => ({
98
- key: item,
99
- label: (
100
- <Space size={8}>
101
- {MODE_ICON[item]}
102
- {labels[item]}
103
- </Space>
104
- ),
105
- })),
106
- };
107
-
108
- return (
109
- <Dropdown menu={menu} trigger={["click"]}>
110
- <Button type="text" size="small" shape={"circle"} aria-label="切换主题">
111
- {MODE_ICON[mode]}
112
- </Button>
113
- </Dropdown>
114
- );
115
- },
116
- [],
117
- );
118
-
119
- return (
120
- <ThemeSwitch
121
- labels={{
122
- light: "浅色",
123
- dark: "深色",
124
- system: "跟随系统",
125
- }}
126
- persistence={persistence}
127
- onChange={handleChange}
128
- render={renderDropdown}
129
- />
130
- );
131
- };
@@ -1,101 +0,0 @@
1
- import type { StorageStrategy } from "../../storage/index.js";
2
-
3
- /**
4
- * 默认 access token 存储键。
5
- * 业务方可通过 AuthTokenOptions.key 覆盖该键以复用同一套读写逻辑。
6
- */
7
- export const AUTH_TOKEN_KEY = "user:token";
8
-
9
- /**
10
- * 统一的 access token 存储键(业务登录场景)。
11
- */
12
- export const ACCESS_TOKEN_KEY = "auth-access-token";
13
-
14
- /**
15
- * 统一的 refresh token 存储键(业务登录场景)。
16
- */
17
- export const REFRESH_TOKEN_KEY = "auth-refresh-token";
18
-
19
- /**
20
- * 默认 token 存储介质。
21
- * 当前默认使用 localstorage,确保页面刷新后仍可读取。
22
- */
23
- export const AUTH_TOKEN_STORAGE: StorageStrategy = "localstorage";
24
-
25
- const SDK_STORAGE_PREFIX = "secra-admin-sdk";
26
-
27
- /**
28
- * Token 读写配置项。
29
- * - key: 自定义 token 对应的存储 key
30
- * - strategy: 存储策略(localstorage / sessionStorage / indexeddb)
31
- */
32
- export interface AuthTokenOptions {
33
- key?: string;
34
- strategy?: StorageStrategy;
35
- }
36
-
37
- /**
38
- * 归一化 token 配置,补齐默认值,避免调用方重复传参。
39
- */
40
- export const resolveAuthTokenOptions = (
41
- options?: AuthTokenOptions,
42
- ): Required<AuthTokenOptions> => ({
43
- key: options?.key || AUTH_TOKEN_KEY,
44
- strategy: options?.strategy || AUTH_TOKEN_STORAGE,
45
- });
46
-
47
- type SyncStorageStrategy = Exclude<StorageStrategy, "indexeddb">;
48
- type SerializedStoragePayload = {
49
- data?: unknown;
50
- exp?: number;
51
- sign?: string;
52
- };
53
-
54
- const getSyncStorageByStrategy = (strategy: SyncStorageStrategy): Storage | null => {
55
- if (typeof window === "undefined") {
56
- return null;
57
- }
58
- return strategy === "sessionStorage" ? window.sessionStorage : window.localStorage;
59
- };
60
-
61
- const resolveRawStoredValue = (storage: Storage, key: string): string | null => {
62
- const prefixedKey = `${SDK_STORAGE_PREFIX}:${key}`;
63
- return storage.getItem(prefixedKey) ?? storage.getItem(key);
64
- };
65
-
66
- const parseStoredToken = (rawValue: string): string | null => {
67
- try {
68
- const payload = JSON.parse(rawValue) as SerializedStoragePayload;
69
- const exp = payload.exp ?? -1;
70
- if (exp !== -1 && Date.now() > exp) {
71
- return null;
72
- }
73
- return typeof payload.data === "string" && payload.data ? payload.data : null;
74
- } catch {
75
- return rawValue || null;
76
- }
77
- };
78
-
79
- /**
80
- * 同步判断当前是否已登录。
81
- * 仅支持 localstorage / sessionStorage;indexeddb 回退为 false。
82
- */
83
- export const isAuthenticatedSync = (options?: AuthTokenOptions): boolean => {
84
- const { key, strategy } = resolveAuthTokenOptions(options);
85
- if (strategy === "indexeddb") {
86
- return false;
87
- }
88
-
89
- const storage = getSyncStorageByStrategy(strategy);
90
- if (!storage) {
91
- return false;
92
- }
93
-
94
- const rawValue = resolveRawStoredValue(storage, key);
95
- if (!rawValue) {
96
- return false;
97
- }
98
-
99
- return Boolean(parseStoredToken(rawValue));
100
- };
101
-
@@ -1,139 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react";
2
- import { cache } from "../../storage/index.js";
3
- import {
4
- ACCESS_TOKEN_KEY,
5
- AUTH_TOKEN_KEY,
6
- AUTH_TOKEN_STORAGE,
7
- REFRESH_TOKEN_KEY,
8
- type AuthTokenOptions,
9
- isAuthenticatedSync,
10
- resolveAuthTokenOptions,
11
- } from "./core.js";
12
-
13
- /**
14
- * 读取 token(非 hooks 模式)。
15
- *
16
- * @param options 可选配置:自定义 key 和存储策略。
17
- * @returns Promise<string | null> 返回 token 字符串;不存在时返回 null。
18
- */
19
- export const getToken = async (options?: AuthTokenOptions): Promise<string | null> => {
20
- const { key, strategy } = resolveAuthTokenOptions(options);
21
- return cache[strategy].get<string>(key);
22
- };
23
-
24
- /**
25
- * 写入 token(非 hooks 模式)。
26
- *
27
- * @param token 要持久化的 token 字符串。
28
- * @param options 可选配置:自定义 key 和存储策略。
29
- * @returns Promise<void>
30
- */
31
- export const setToken = async (token: string, options?: AuthTokenOptions): Promise<void> => {
32
- const { key, strategy } = resolveAuthTokenOptions(options);
33
- await cache[strategy].set<string>(key, token);
34
- };
35
-
36
- /**
37
- * 删除 token(非 hooks 模式)。
38
- *
39
- * @param options 可选配置:自定义 key 和存储策略。
40
- * @returns Promise<void>
41
- */
42
- export const removeToken = async (options?: AuthTokenOptions): Promise<void> => {
43
- const { key, strategy } = resolveAuthTokenOptions(options);
44
- await cache[strategy].remove(key);
45
- };
46
-
47
- /**
48
- * useToken 返回结果。
49
- * - token: 当前内存态 token
50
- * - loading: 首次加载或手动刷新时的读取状态
51
- * - getToken: 仅读取存储并同步到内存态
52
- * - setToken: 写入存储并同步到内存态
53
- * - removeToken: 删除存储并清空内存态
54
- * - refresh: 强制刷新 token,通常用于登录态恢复场景
55
- */
56
- export interface UseTokenResult {
57
- token: string | null;
58
- loading: boolean;
59
- getToken: () => Promise<string | null>;
60
- setToken: (value: string) => Promise<void>;
61
- removeToken: () => Promise<void>;
62
- refresh: () => Promise<string | null>;
63
- }
64
-
65
- /**
66
- * Token 管理 Hook(hooks 模式)。
67
- *
68
- * 提供 token 的读取、写入、删除与刷新能力,并维护组件内可响应的 token 状态。
69
- * 在组件挂载后会自动触发一次 refresh(),用于从持久化存储恢复 token。
70
- *
71
- * @param options 可选配置:自定义 key 和存储策略。
72
- * @returns UseTokenResult token 状态与一组可复用操作方法。
73
- */
74
- export const useToken = (options?: AuthTokenOptions): UseTokenResult => {
75
- const [token, setTokenState] = useState<string | null>(null);
76
- const [loading, setLoading] = useState(true);
77
- const resolvedOptions = useMemo(
78
- () => resolveAuthTokenOptions(options),
79
- [options?.key, options?.strategy],
80
- );
81
-
82
- /**
83
- * 从存储读取 token,并同步到 hook 内部状态。
84
- */
85
- const readToken = useCallback(async () => {
86
- const value = await cache[resolvedOptions.strategy].get<string>(resolvedOptions.key);
87
- setTokenState(value);
88
- return value;
89
- }, [resolvedOptions.key, resolvedOptions.strategy]);
90
-
91
- /**
92
- * 主动刷新 token:
93
- * 1. 设置 loading=true
94
- * 2. 读取并同步 token
95
- * 3. 结束后恢复 loading=false
96
- */
97
- const refresh = useCallback(async () => {
98
- setLoading(true);
99
- try {
100
- return await readToken();
101
- } finally {
102
- setLoading(false);
103
- }
104
- }, [readToken]);
105
-
106
- /**
107
- * 持久化写入 token,并立即更新内存态,避免界面等待下一次读取。
108
- */
109
- const persistToken = useCallback(
110
- async (value: string) => {
111
- await cache[resolvedOptions.strategy].set<string>(resolvedOptions.key, value);
112
- setTokenState(value);
113
- },
114
- [resolvedOptions.key, resolvedOptions.strategy],
115
- );
116
-
117
- /**
118
- * 删除持久化 token,并同步清空内存态。
119
- */
120
- const clearToken = useCallback(async () => {
121
- await cache[resolvedOptions.strategy].remove(resolvedOptions.key);
122
- setTokenState(null);
123
- }, [resolvedOptions.key, resolvedOptions.strategy]);
124
-
125
- useEffect(() => {
126
- void refresh();
127
- }, [refresh]);
128
-
129
- return {
130
- token,
131
- loading,
132
- getToken: readToken,
133
- setToken: persistToken,
134
- removeToken: clearToken,
135
- refresh,
136
- };
137
- };
138
- export * from "./core.js";
139
- export * from "./with-auth.js";
@@ -1,41 +0,0 @@
1
- import type { ComponentType, FC } from "react";
2
- import { Navigate } from "react-router-dom";
3
- import { logger } from "@vlian/framework/utils";
4
- import { ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY, isAuthenticatedSync, type AuthTokenOptions } from "./core.js";
5
-
6
- export interface WithAuthOptions {
7
- tokenOptions?: AuthTokenOptions;
8
- refreshTokenOptions?: AuthTokenOptions | false;
9
- }
10
-
11
- const DEFAULT_LOGIN_PATH = "/auth/login";
12
-
13
- export const withAuth = <P extends object>(
14
- WrappedComponent: ComponentType<P>,
15
- options?: WithAuthOptions,
16
- ): FC<P> => {
17
- const accessTokenOptions = options?.tokenOptions ?? { key: ACCESS_TOKEN_KEY };
18
- const refreshTokenOptions = options?.refreshTokenOptions ?? { key: REFRESH_TOKEN_KEY };
19
- const getNow =
20
- typeof performance !== "undefined" && typeof performance.now === "function"
21
- ? () => performance.now()
22
- : () => Date.now();
23
-
24
- const AuthenticatedComponent: FC<P> = (props) => {
25
- const start = getNow();
26
- const hasAccessToken = isAuthenticatedSync(accessTokenOptions);
27
- const hasRefreshToken =
28
- refreshTokenOptions === false ? false : isAuthenticatedSync(refreshTokenOptions);
29
- const end = getNow();
30
- logger.debug("[withAuth] isAuthenticatedSync cost(ms)", Number((end - start).toFixed(2)));
31
- const isLogin = hasAccessToken || hasRefreshToken;
32
- if (isLogin) {
33
- return <WrappedComponent {...props} />;
34
- }
35
- return <Navigate to={DEFAULT_LOGIN_PATH} />;
36
- };
37
-
38
- AuthenticatedComponent.displayName = `withAuth(${WrappedComponent.displayName || WrappedComponent.name || "Component"})`;
39
-
40
- return AuthenticatedComponent;
41
- };
@@ -1 +0,0 @@
1
- export * from "./auth/index.js";
@@ -1,150 +0,0 @@
1
- import { $t, setLang, setupI18n } from "@vlian/framework/library";
2
-
3
- export type SdkLang = "en-US" | "zh-CN";
4
-
5
- export const sdkLocales: Record<SdkLang, Record<string, unknown>> = {
6
- "en-US": {
7
- secraAdmin: {
8
- login: {
9
- subtitle: "Unified identity authentication and admin portal",
10
- otherLoginMethods: "Other login methods",
11
- accountTab: "Account Login",
12
- phoneTab: "Phone Login",
13
- autoLogin: "Remember me",
14
- forgotPassword: "Forgot password",
15
- usernamePlaceholder: "Username: admin or user",
16
- usernameRequired: "Please enter your username!",
17
- passwordPlaceholder: "Password: ant.design",
18
- passwordRequired: "Please enter your password!",
19
- passwordStrengthText:
20
- "Password should contain numbers, letters and special characters, at least 8 characters long.",
21
- passwordStrengthWeak: "Strength: Weak",
22
- passwordStrengthMedium: "Strength: Medium",
23
- passwordStrengthStrong: "Strength: Strong",
24
- mobilePlaceholder: "Phone number",
25
- mobileRequired: "Please enter your phone number!",
26
- mobileInvalid: "Invalid phone number format!",
27
- captchaPlaceholder: "Please enter verification code",
28
- captchaRequired: "Please enter verification code!",
29
- captchaButton: "Get code",
30
- captchaButtonTiming: "{{count}} Get code",
31
- captchaSuccess: "Code sent successfully! Verification code: 1234",
32
- phoneLoginNotReady: "Phone login is not connected to backend yet",
33
- loginSuccessTitle: "Login successful",
34
- loginWelcomeUser: "Welcome, {{username}}",
35
- loginFailedCheckCredentials: "Login failed, please check your username and password",
36
- },
37
- home: {
38
- title: "Theme sync between antd and @vlian/framework",
39
- currentMode: "Current mode",
40
- resolvedMode: "Resolved",
41
- modeSwitchTitle: "Mode switch",
42
- unifiedThemeTitle: "Unified theme (single primary color)",
43
- previewTitle: "Sync preview",
44
- currentUnifiedThemeTitle: "Current unified theme state",
45
- themePreset: "Theme preset",
46
- mode: {
47
- light: "Light",
48
- dark: "Dark",
49
- system: "System",
50
- },
51
- },
52
- },
53
- },
54
- "zh-CN": {
55
- secraAdmin: {
56
- login: {
57
- subtitle: "统一身份认证与后台管理入口",
58
- otherLoginMethods: "其他登录方式",
59
- accountTab: "账号密码登录",
60
- phoneTab: "手机号登录",
61
- autoLogin: "自动登录",
62
- forgotPassword: "忘记密码",
63
- usernamePlaceholder: "用户名: admin or user",
64
- usernameRequired: "请输入用户名!",
65
- passwordPlaceholder: "密码: ant.design",
66
- passwordRequired: "请输入密码!",
67
- passwordStrengthText:
68
- "Password should contain numbers, letters and special characters, at least 8 characters long.",
69
- passwordStrengthWeak: "强度:弱",
70
- passwordStrengthMedium: "强度:中",
71
- passwordStrengthStrong: "强度:强",
72
- mobilePlaceholder: "手机号",
73
- mobileRequired: "请输入手机号!",
74
- mobileInvalid: "手机号格式错误!",
75
- captchaPlaceholder: "请输入验证码",
76
- captchaRequired: "请输入验证码!",
77
- captchaButton: "获取验证码",
78
- captchaButtonTiming: "{{count}} 获取验证码",
79
- captchaSuccess: "获取验证码成功!验证码为:1234",
80
- phoneLoginNotReady: "手机号登录暂未接入后端",
81
- loginSuccessTitle: "登录成功",
82
- loginWelcomeUser: "欢迎,{{username}}",
83
- loginFailedCheckCredentials: "登录失败,请检查账号密码",
84
- },
85
- home: {
86
- title: "antd + @vlian/framework 主题联动",
87
- currentMode: "当前模式",
88
- resolvedMode: "解析后",
89
- modeSwitchTitle: "模式切换",
90
- unifiedThemeTitle: "统一主题(单一主色驱动)",
91
- previewTitle: "同步结果预览",
92
- currentUnifiedThemeTitle: "当前统一主题状态",
93
- themePreset: "主题预设",
94
- mode: {
95
- light: "浅色",
96
- dark: "深色",
97
- system: "跟随系统",
98
- },
99
- },
100
- },
101
- },
102
- };
103
-
104
- type SetupSdkI18nOptions = {
105
- lang?: SdkLang;
106
- locales?: Partial<Record<SdkLang, Record<string, unknown>>>;
107
- };
108
-
109
- const isPlainRecord = (value: unknown): value is Record<string, unknown> => {
110
- if (!value || typeof value !== "object") {
111
- return false;
112
- }
113
- return Object.prototype.toString.call(value) === "[object Object]";
114
- };
115
-
116
- const deepMergeLocale = (
117
- base: Record<string, unknown>,
118
- override: Record<string, unknown>,
119
- ): Record<string, unknown> => {
120
- const merged: Record<string, unknown> = { ...base };
121
- for (const [key, value] of Object.entries(override)) {
122
- const previous = merged[key];
123
- if (isPlainRecord(previous) && isPlainRecord(value)) {
124
- merged[key] = deepMergeLocale(previous, value);
125
- continue;
126
- }
127
- merged[key] = value;
128
- }
129
- return merged;
130
- };
131
-
132
- export function getSdkI18nLocales(locales: SetupSdkI18nOptions["locales"] = {}) {
133
- const enOverride = locales["en-US"] ?? {};
134
- const zhOverride = locales["zh-CN"] ?? {};
135
-
136
- return {
137
- "en-US": deepMergeLocale(sdkLocales["en-US"], enOverride),
138
- "zh-CN": deepMergeLocale(sdkLocales["zh-CN"], zhOverride),
139
- } as Record<SdkLang, Record<string, unknown>>;
140
- }
141
-
142
- export function setupSdkI18n(options: SetupSdkI18nOptions = {}) {
143
- const { lang = "zh-CN", locales = {} } = options;
144
-
145
- setupI18n(getSdkI18nLocales(locales));
146
-
147
- setLang(lang);
148
- }
149
-
150
- export { setLang as setSdkLang, $t as t };
@@ -1,11 +0,0 @@
1
- /**
2
- * 根入口只导出运行时通用能力(theme/components/storage/i18n/hooks)。
3
- * request/build 通过子路径导出,避免将构建时依赖耦合进运行时入口。
4
- * - @vlian/sdk/request
5
- * - @vlian/sdk/build
6
- */
7
- export * from "./theme/index.js";
8
- export * from "./components/index.js";
9
- export * from "./storage/index.js";
10
- export * from "./i18n/index.js";
11
- export * from "./hooks/index.js";