@qlover/create-app 0.4.5 → 0.5.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 (163) hide show
  1. package/CHANGELOG.md +95 -35
  2. package/dist/index.cjs +11 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +10 -2418
  5. package/{templates → dist/templates}/node-lib/package.json +2 -2
  6. package/{templates → dist/templates}/react-app/README.md +6 -6
  7. package/{templates/react-app/config/Identifier/Error.ts → dist/templates/react-app/config/Identifier/common.error.ts} +8 -8
  8. package/dist/templates/react-app/config/Identifier/common.ts +62 -0
  9. package/dist/templates/react-app/config/Identifier/index.ts +10 -0
  10. package/dist/templates/react-app/config/Identifier/page.about.ts +181 -0
  11. package/dist/templates/react-app/config/Identifier/page.executor.ts +267 -0
  12. package/dist/templates/react-app/config/Identifier/page.home.ts +63 -0
  13. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +39 -0
  14. package/dist/templates/react-app/config/Identifier/page.jsonStorage.ts +70 -0
  15. package/dist/templates/react-app/config/Identifier/page.login.ts +152 -0
  16. package/dist/templates/react-app/config/Identifier/page.register.ts +147 -0
  17. package/dist/templates/react-app/config/Identifier/page.request.ts +179 -0
  18. package/dist/templates/react-app/config/app.router.ts +163 -0
  19. package/{templates → dist/templates}/react-app/config/feapi.mock.json +6 -0
  20. package/dist/templates/react-app/config/theme.ts +11 -0
  21. package/{templates → dist/templates}/react-app/package.json +2 -2
  22. package/{templates → dist/templates}/react-app/public/locales/en/common.json +97 -116
  23. package/{templates → dist/templates}/react-app/public/locales/zh/common.json +98 -117
  24. package/{templates → dist/templates}/react-app/src/App.tsx +6 -5
  25. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +142 -0
  26. package/{templates → dist/templates}/react-app/src/base/apis/userApi/UserApiType.ts +11 -0
  27. package/{templates → dist/templates}/react-app/src/base/cases/AppConfig.ts +11 -0
  28. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +36 -0
  29. package/{templates → dist/templates}/react-app/src/base/cases/RouterLoader.ts +2 -1
  30. package/{templates → dist/templates}/react-app/src/base/services/I18nService.ts +4 -4
  31. package/{templates/react-app/src/base/services/ProcesserService.ts → dist/templates/react-app/src/base/services/ProcesserExecutor.ts} +15 -5
  32. package/{templates → dist/templates}/react-app/src/base/services/RouteService.ts +11 -13
  33. package/dist/templates/react-app/src/base/services/UserService.ts +132 -0
  34. package/{templates → dist/templates}/react-app/src/base/types/Page.ts +12 -2
  35. package/{templates → dist/templates}/react-app/src/core/IOC.ts +11 -6
  36. package/{templates → dist/templates}/react-app/src/core/bootstrap.ts +2 -2
  37. package/{templates → dist/templates}/react-app/src/core/bootstraps/index.ts +3 -1
  38. package/{templates → dist/templates}/react-app/src/core/globals.ts +23 -7
  39. package/{templates → dist/templates}/react-app/src/core/registers/RegisterApi.ts +1 -1
  40. package/{templates → dist/templates}/react-app/src/core/registers/RegisterCommon.ts +14 -15
  41. package/{templates → dist/templates}/react-app/src/core/registers/RegisterControllers.ts +9 -4
  42. package/{templates → dist/templates}/react-app/src/core/registers/RegisterGlobals.ts +12 -4
  43. package/{templates → dist/templates}/react-app/src/pages/404.tsx +4 -1
  44. package/{templates → dist/templates}/react-app/src/pages/500.tsx +2 -1
  45. package/{templates → dist/templates}/react-app/src/pages/auth/Layout.tsx +2 -2
  46. package/{templates/react-app/src/pages/auth/Login.tsx → dist/templates/react-app/src/pages/auth/LoginPage.tsx} +2 -4
  47. package/{templates/react-app/src/pages/auth/Register.tsx → dist/templates/react-app/src/pages/auth/RegisterPage.tsx} +3 -6
  48. package/{templates/react-app/src/pages/base/About.tsx → dist/templates/react-app/src/pages/base/AboutPage.tsx} +4 -4
  49. package/{templates/react-app/src/pages/base/ErrorIdentifier.tsx → dist/templates/react-app/src/pages/base/ErrorIdentifierPage.tsx} +3 -3
  50. package/{templates/react-app/src/pages/base/Executor.tsx → dist/templates/react-app/src/pages/base/ExecutorPage.tsx} +3 -3
  51. package/{templates/react-app/src/pages/base/Home.tsx → dist/templates/react-app/src/pages/base/HomePage.tsx} +15 -45
  52. package/{templates/react-app/src/pages/base/JSONStorage.tsx → dist/templates/react-app/src/pages/base/JSONStoragePage.tsx} +3 -3
  53. package/{templates → dist/templates}/react-app/src/pages/base/Layout.tsx +4 -4
  54. package/{templates/react-app/src/pages/base/Request.tsx → dist/templates/react-app/src/pages/base/RequestPage.tsx} +2 -2
  55. package/{templates/react-app/src/pages/base → dist/templates/react-app/src/uikit}/components/LogoutButton.tsx +1 -1
  56. package/{templates → dist/templates}/react-app/src/uikit/components/ThemeSwitcher.tsx +5 -6
  57. package/{templates → dist/templates}/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
  58. package/{templates → dist/templates}/react-app/src/uikit/controllers/ExecutorController.ts +2 -2
  59. package/{templates → dist/templates}/react-app/src/uikit/controllers/JSONStorageController.ts +5 -5
  60. package/{templates → dist/templates}/react-app/src/uikit/controllers/RequestController.ts +1 -1
  61. package/{templates/react-app/src/uikit/hooks/useLanguageGuard.ts → dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts} +1 -1
  62. package/{templates → dist/templates}/react-app/src/uikit/hooks/useStore.ts +2 -2
  63. package/dist/templates/react-app/src/uikit/hooks/userRouterService.ts +12 -0
  64. package/{templates → dist/templates}/react-app/src/uikit/providers/BaseRouteProvider.tsx +1 -0
  65. package/dist/templates/react-app/src/uikit/providers/ProcessExecutorProvider.tsx +24 -0
  66. package/dist/templates/react-app/src/uikit/providers/UserAuthProvider.tsx +16 -0
  67. package/{templates → dist/templates}/react-app/vite.config.ts +2 -1
  68. package/package.json +4 -6
  69. package/templates/react-app/config/Identifier/Auth.ts +0 -13
  70. package/templates/react-app/config/Identifier/I18n.ts +0 -1366
  71. package/templates/react-app/config/app.router.json +0 -159
  72. package/templates/react-app/config/theme.json +0 -9
  73. package/templates/react-app/src/base/apis/userApi/UserApi.ts +0 -64
  74. package/templates/react-app/src/base/port/LoginInterface.ts +0 -12
  75. package/templates/react-app/src/base/port/StoreInterface.ts +0 -58
  76. package/templates/react-app/src/base/services/UserService.ts +0 -130
  77. package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +0 -45
  78. /package/{configs → dist/configs}/_common/.editorconfig +0 -0
  79. /package/{configs → dist/configs}/_common/.env.template +0 -0
  80. /package/{configs → dist/configs}/_common/.gitattributes +0 -0
  81. /package/{configs → dist/configs}/_common/.github/workflows/general-check.yml +0 -0
  82. /package/{configs → dist/configs}/_common/.github/workflows/release.yml +0 -0
  83. /package/{configs → dist/configs}/_common/.gitignore.template +0 -0
  84. /package/{configs → dist/configs}/_common/.husky/commit-msg +0 -0
  85. /package/{configs → dist/configs}/_common/.husky/pre-commit +0 -0
  86. /package/{configs → dist/configs}/_common/.prettierignore +0 -0
  87. /package/{configs → dist/configs}/_common/.prettierrc.js +0 -0
  88. /package/{configs → dist/configs}/_common/.vscode/extensions.json +0 -0
  89. /package/{configs → dist/configs}/_common/.vscode/react.code-snippets +0 -0
  90. /package/{configs → dist/configs}/_common/.vscode/settings.json +0 -0
  91. /package/{configs → dist/configs}/_common/commitlint.config.js +0 -0
  92. /package/{configs → dist/configs}/_common/package.json.template +0 -0
  93. /package/{configs → dist/configs}/node-lib/eslint.config.js +0 -0
  94. /package/{configs → dist/configs}/react-app/eslint.config.js +0 -0
  95. /package/{templates → dist/templates}/node-lib/__tests__/readJson.test.ts +0 -0
  96. /package/{templates → dist/templates}/node-lib/bin/test.js +0 -0
  97. /package/{templates → dist/templates}/node-lib/rollup.config.js +0 -0
  98. /package/{templates → dist/templates}/node-lib/src/index.ts +0 -0
  99. /package/{templates → dist/templates}/node-lib/src/readJson.ts +0 -0
  100. /package/{templates → dist/templates}/node-lib/tsconfig.json +0 -0
  101. /package/{templates → dist/templates}/pack-app/README.md +0 -0
  102. /package/{templates → dist/templates}/pack-app/eslint.config.js +0 -0
  103. /package/{templates → dist/templates}/pack-app/fe-config.json +0 -0
  104. /package/{templates → dist/templates}/pack-app/package.json +0 -0
  105. /package/{templates → dist/templates}/pack-app/pnpm-workspace.yaml +0 -0
  106. /package/{templates → dist/templates}/pack-app/tsconfig.json +0 -0
  107. /package/{templates → dist/templates}/pack-app/tsconfig.test.json +0 -0
  108. /package/{templates → dist/templates}/pack-app/vite.config.ts +0 -0
  109. /package/{templates → dist/templates}/react-app/.env.template +0 -0
  110. /package/{templates → dist/templates}/react-app/config/common.ts +0 -0
  111. /package/{templates → dist/templates}/react-app/config/i18n.ts +0 -0
  112. /package/{templates → dist/templates}/react-app/index.html +0 -0
  113. /package/{templates → dist/templates}/react-app/postcss.config.js +0 -0
  114. /package/{templates → dist/templates}/react-app/public/logo.svg +0 -0
  115. /package/{templates → dist/templates}/react-app/public/router-root/logo.svg +0 -0
  116. /package/{templates → dist/templates}/react-app/src/assets/react.svg +0 -0
  117. /package/{templates → dist/templates}/react-app/src/base/apis/AiApi.ts +0 -0
  118. /package/{templates → dist/templates}/react-app/src/base/apis/feApi/FeApi.ts +0 -0
  119. /package/{templates → dist/templates}/react-app/src/base/apis/feApi/FeApiAdapter.ts +0 -0
  120. /package/{templates → dist/templates}/react-app/src/base/apis/feApi/FeApiBootstarp.ts +0 -0
  121. /package/{templates → dist/templates}/react-app/src/base/apis/feApi/FeApiType.ts +0 -0
  122. /package/{templates → dist/templates}/react-app/src/base/apis/userApi/UserApiAdapter.ts +0 -0
  123. /package/{templates → dist/templates}/react-app/src/base/apis/userApi/UserApiBootstarp.ts +0 -0
  124. /package/{templates → dist/templates}/react-app/src/base/cases/AppError.ts +0 -0
  125. /package/{templates → dist/templates}/react-app/src/base/cases/DialogHandler.ts +0 -0
  126. /package/{templates → dist/templates}/react-app/src/base/cases/PublicAssetsPath.ts +0 -0
  127. /package/{templates → dist/templates}/react-app/src/base/cases/RequestLogger.ts +0 -0
  128. /package/{templates → dist/templates}/react-app/src/base/cases/RequestStatusCatcher.ts +0 -0
  129. /package/{templates → dist/templates}/react-app/src/base/port/ApiTransactionInterface.ts +0 -0
  130. /package/{templates → dist/templates}/react-app/src/base/port/InteractionHubInterface.ts +0 -0
  131. /package/{templates → dist/templates}/react-app/src/base/port/RequestCatcherInterface.ts +0 -0
  132. /package/{templates → dist/templates}/react-app/src/base/port/UIDependenciesInterface.ts +0 -0
  133. /package/{templates → dist/templates}/react-app/src/base/types/deprecated-antd.d.ts +0 -0
  134. /package/{templates → dist/templates}/react-app/src/base/types/global.d.ts +0 -0
  135. /package/{templates → dist/templates}/react-app/src/core/bootstraps/BootstrapApp.ts +0 -0
  136. /package/{templates → dist/templates}/react-app/src/core/bootstraps/PrintBootstrap.ts +0 -0
  137. /package/{templates → dist/templates}/react-app/src/core/registers/index.ts +0 -0
  138. /package/{templates → dist/templates}/react-app/src/main.tsx +0 -0
  139. /package/{templates → dist/templates}/react-app/src/pages/base/RedirectPathname.tsx +0 -0
  140. /package/{templates → dist/templates}/react-app/src/styles/css/antd-themes/_default.css +0 -0
  141. /package/{templates → dist/templates}/react-app/src/styles/css/antd-themes/dark.css +0 -0
  142. /package/{templates → dist/templates}/react-app/src/styles/css/antd-themes/index.css +0 -0
  143. /package/{templates → dist/templates}/react-app/src/styles/css/antd-themes/no-context.css +0 -0
  144. /package/{templates → dist/templates}/react-app/src/styles/css/antd-themes/pink.css +0 -0
  145. /package/{templates → dist/templates}/react-app/src/styles/css/index.css +0 -0
  146. /package/{templates → dist/templates}/react-app/src/styles/css/page.css +0 -0
  147. /package/{templates → dist/templates}/react-app/src/styles/css/tailwind.css +0 -0
  148. /package/{templates → dist/templates}/react-app/src/styles/css/themes/_default.css +0 -0
  149. /package/{templates → dist/templates}/react-app/src/styles/css/themes/dark.css +0 -0
  150. /package/{templates → dist/templates}/react-app/src/styles/css/themes/index.css +0 -0
  151. /package/{templates → dist/templates}/react-app/src/styles/css/themes/pink.css +0 -0
  152. /package/{templates/react-app/src/pages/base → dist/templates/react-app/src/uikit}/components/BaseHeader.tsx +0 -0
  153. /package/{templates → dist/templates}/react-app/src/uikit/components/LanguageSwitcher.tsx +0 -0
  154. /package/{templates → dist/templates}/react-app/src/uikit/components/Loading.tsx +0 -0
  155. /package/{templates → dist/templates}/react-app/src/uikit/components/LocaleLink.tsx +0 -0
  156. /package/{templates → dist/templates}/react-app/src/uikit/components/RouterRenderComponent.tsx +0 -0
  157. /package/{templates → dist/templates}/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -0
  158. /package/{templates → dist/templates}/react-app/src/uikit/hooks/useStrictEffect.ts +0 -0
  159. /package/{templates → dist/templates}/react-app/src/vite-env.d.ts +0 -0
  160. /package/{templates → dist/templates}/react-app/tailwind.config.js +0 -0
  161. /package/{templates → dist/templates}/react-app/tsconfig.app.json +0 -0
  162. /package/{templates → dist/templates}/react-app/tsconfig.json +0 -0
  163. /package/{templates → dist/templates}/react-app/tsconfig.node.json +0 -0
@@ -0,0 +1,142 @@
1
+ import {
2
+ FetchAbortPlugin,
3
+ RequestAdapterFetch,
4
+ RequestTransaction
5
+ } from '@qlover/fe-corekit';
6
+ import {
7
+ GetIpInfoTransaction,
8
+ UserApiGetUserInfoTransaction,
9
+ UserApiLoginTransaction,
10
+ UserApiTestApiCatchResultTransaction
11
+ } from './UserApiType';
12
+ import { inject, injectable } from 'inversify';
13
+ import { UserApiAdapter } from './UserApiAdapter';
14
+ import { UserApiConfig } from './UserApiBootstarp';
15
+ import {
16
+ LoginResponseData,
17
+ UserAuthApiInterface,
18
+ UserAuthStoreInterface
19
+ } from '@qlover/corekit-bridge';
20
+ import {
21
+ RegisterFormData,
22
+ UserServiceUserInfo
23
+ } from '@/base/services/UserService';
24
+ import { RES_NO_TOKEN } from '@config/Identifier';
25
+ import { AppError } from '@/base/cases/AppError';
26
+
27
+ /**
28
+ * UserApi
29
+ *
30
+ * @description
31
+ * UserApi is a client for the user API.
32
+ *
33
+ */
34
+ @injectable()
35
+ export class UserApi
36
+ extends RequestTransaction<UserApiConfig>
37
+ implements UserAuthApiInterface<UserServiceUserInfo>
38
+ {
39
+ protected store: UserAuthStoreInterface<UserServiceUserInfo> | null = null;
40
+
41
+ constructor(
42
+ @inject(FetchAbortPlugin) private abortPlugin: FetchAbortPlugin,
43
+ @inject(UserApiAdapter) adapter: RequestAdapterFetch
44
+ ) {
45
+ super(adapter);
46
+ }
47
+
48
+ getStore(): UserAuthStoreInterface<UserServiceUserInfo> | null {
49
+ return this.store;
50
+ }
51
+
52
+ /**
53
+ * @override
54
+ * @param store
55
+ */
56
+ setStore(store: UserAuthStoreInterface<UserServiceUserInfo>): void {
57
+ this.store = store;
58
+ }
59
+
60
+ stop(request: UserApiConfig): Promise<void> | void {
61
+ this.abortPlugin.abort(request);
62
+ }
63
+
64
+ async getRandomUser(): Promise<GetIpInfoTransaction['response']> {
65
+ return this.request<GetIpInfoTransaction>({
66
+ url: 'https://randomuser.me/api/',
67
+ method: 'GET',
68
+ disabledMock: true
69
+ });
70
+ }
71
+
72
+ async testApiCatchResult(): Promise<
73
+ UserApiTestApiCatchResultTransaction['response']
74
+ > {
75
+ return this.request<UserApiTestApiCatchResultTransaction>({
76
+ url: 'https://randomuser.me/api/?_name=ApiCatchResult',
77
+ method: 'GET',
78
+ disabledMock: true,
79
+ openApiCatch: true
80
+ });
81
+ }
82
+
83
+ /**
84
+ * @override
85
+ * @param params
86
+ * @returns
87
+ */
88
+ async login(
89
+ params: UserApiLoginTransaction['data']
90
+ ): Promise<LoginResponseData> {
91
+ const response = await this.post<UserApiLoginTransaction>(
92
+ '/api/login',
93
+ params
94
+ );
95
+
96
+ if (response.apiCatchResult) {
97
+ throw response.apiCatchResult;
98
+ }
99
+
100
+ if (!response.data.token) {
101
+ throw new AppError(RES_NO_TOKEN);
102
+ }
103
+
104
+ return response.data;
105
+ }
106
+
107
+ /**
108
+ * @override
109
+ * @param params
110
+ * @returns
111
+ */
112
+ register(
113
+ params: RegisterFormData
114
+ ): Promise<UserApiLoginTransaction['response']> {
115
+ return this.post<UserApiLoginTransaction>('/api/register', params);
116
+ }
117
+
118
+ /**
119
+ * @override
120
+ * @returns
121
+ */
122
+ logout(): Promise<void> {
123
+ return Promise.resolve();
124
+ }
125
+
126
+ /**
127
+ * @override
128
+ * @returns
129
+ */
130
+ async getUserInfo(): Promise<
131
+ UserApiGetUserInfoTransaction['response']['data']
132
+ > {
133
+ const response =
134
+ await this.get<UserApiGetUserInfoTransaction>('/api/userinfo');
135
+
136
+ if (response.apiCatchResult) {
137
+ throw response.apiCatchResult;
138
+ }
139
+
140
+ return response.data;
141
+ }
142
+ }
@@ -50,3 +50,14 @@ export type UserApiLoginTransaction = UserApiTransaction<
50
50
  >;
51
51
 
52
52
  export type UserApiTestApiCatchResultTransaction = UserApiGetRandomUser;
53
+
54
+ export type UserApiRegisterTransaction = UserApiTransaction<
55
+ {
56
+ username: string;
57
+ email: string;
58
+ password: string;
59
+ confirmPassword: string;
60
+ agreeToTerms: boolean;
61
+ },
62
+ UserApiTransaction['response']['data']
63
+ >;
@@ -55,6 +55,12 @@ export class AppConfig implements EnvConfigInterface {
55
55
  */
56
56
  readonly userTokenStorageKey = '__fe_user_token__';
57
57
 
58
+ /**
59
+ * Storage key for user information
60
+ * @description Injected from VITE_USER_INFO_STORAGE_KEY environment variable
61
+ */
62
+ readonly userInfoStorageKey = '__fe_user_info__';
63
+
58
64
  /**
59
65
  * Available OpenAI model configurations
60
66
  * @description List of supported OpenAI models for the application
@@ -102,4 +108,9 @@ export class AppConfig implements EnvConfigInterface {
102
108
 
103
109
  /** Flag indicating if AI service token is required */
104
110
  readonly aiApiRequireToken = true;
111
+
112
+ /**
113
+ * Project startup href, usually from window.location.href
114
+ */
115
+ readonly bootHref = '';
105
116
  }
@@ -0,0 +1,36 @@
1
+ import type { ExecutorContext, ExecutorPlugin } from '@qlover/fe-corekit';
2
+ import type { LoggerInterface } from '@qlover/logger';
3
+ import { inject } from 'inversify';
4
+ import { I18nService } from '../services/I18nService';
5
+ import { IOCIdentifier } from '@/core/IOC';
6
+
7
+ /**
8
+ * When throw error, it will be converted to i18n key
9
+ *
10
+ * If the error thrown is an i18n key, it will be converted to the corresponding text
11
+ */
12
+ export class I18nKeyErrorPlugin implements ExecutorPlugin {
13
+ readonly pluginName = 'I18nKeyErrorPlugin';
14
+
15
+ constructor(
16
+ @inject(IOCIdentifier.Logger) private logger: LoggerInterface,
17
+ @inject(I18nService) private i18nService: I18nService
18
+ ) {}
19
+
20
+ onError(context: ExecutorContext<unknown>): Error | void {
21
+ const { error } = context;
22
+
23
+ if (error instanceof Error) {
24
+ const i18nKey = error.message;
25
+
26
+ if (i18nKey && typeof i18nKey === 'string') {
27
+ const i18nText = this.i18nService.t(i18nKey);
28
+
29
+ if (i18nText && i18nText !== i18nKey) {
30
+ this.logger.debug('I18nKeyErrorPlugin Error:', i18nText);
31
+ return new Error(i18nText);
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
@@ -1,6 +1,7 @@
1
1
  import type { ComponentType, LazyExoticComponent, ReactNode } from 'react';
2
2
  import { RouteObject } from 'react-router-dom';
3
3
  import isString from 'lodash/isString';
4
+ import { RouteMeta } from '../types/Page';
4
5
 
5
6
  /**
6
7
  * Component mapping type for lazy-loaded components
@@ -38,7 +39,7 @@ export type RouteConfigValue = Omit<RouteObject, 'element' | 'children'> & {
38
39
  * Additional metadata for the route
39
40
  * @description Can store any route-specific data like permissions, titles, etc.
40
41
  */
41
- meta?: Record<string, unknown>;
42
+ meta?: RouteMeta;
42
43
  };
43
44
 
44
45
  /**
@@ -4,11 +4,11 @@ import LanguageDetector from 'i18next-browser-languagedetector';
4
4
  import HttpApi from 'i18next-http-backend';
5
5
  import merge from 'lodash/merge';
6
6
  import i18nConfig from '@config/i18n';
7
- import type { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
8
7
  import {
9
- StoreInterface,
10
- StoreStateInterface
11
- } from '@/base/port/StoreInterface';
8
+ type BootstrapExecutorPlugin,
9
+ type StoreStateInterface,
10
+ StoreInterface
11
+ } from '@qlover/corekit-bridge';
12
12
  const { supportedLngs, fallbackLng } = i18nConfig;
13
13
 
14
14
  export type I18nServiceLocale = (typeof supportedLngs)[number];
@@ -2,12 +2,15 @@ import { AsyncExecutor, ExecutorPlugin } from '@qlover/fe-corekit';
2
2
  import { IOCIdentifier } from '@/core/IOC';
3
3
  import { injectable, inject } from 'inversify';
4
4
  import type { LoggerInterface } from '@qlover/logger';
5
+ import { RouteService } from './RouteService';
5
6
 
6
7
  @injectable()
7
- export class ProcesserService {
8
+ export class ProcesserExecutor {
9
+ protected executor: AsyncExecutor = new AsyncExecutor();
10
+
8
11
  constructor(
9
12
  @inject(IOCIdentifier.Logger) private logger: LoggerInterface,
10
- @inject(AsyncExecutor) private executor: AsyncExecutor
13
+ @inject(RouteService) private routeService: RouteService
11
14
  ) {}
12
15
 
13
16
  use(plugin: ExecutorPlugin): this {
@@ -21,9 +24,16 @@ export class ProcesserService {
21
24
  });
22
25
  }
23
26
 
24
- init(): Promise<unknown> {
25
- return this.executor.exec(this.handler).catch((err) => {
27
+ async starup(): Promise<unknown> {
28
+ this.logger.info('PageProcesser startup');
29
+
30
+ try {
31
+ const result = await this.executor.exec(this.handler);
32
+ return result;
33
+ } catch (err) {
26
34
  this.logger.error('PageProcesser init failed', err);
27
- });
35
+
36
+ this.routeService.gotoLogin();
37
+ }
28
38
  }
29
39
  }
@@ -3,23 +3,23 @@ import type { NavigateFunction, NavigateOptions } from 'react-router-dom';
3
3
  import type { UIDependenciesInterface } from '@/base/port/UIDependenciesInterface';
4
4
  import type { LoggerInterface } from '@qlover/logger';
5
5
  import { I18nService } from '@/base/services/I18nService';
6
+ import { StoreInterface, StoreStateInterface } from '@qlover/corekit-bridge';
6
7
 
7
8
  export type RouterServiceDependencies = {
8
9
  navigate: NavigateFunction;
9
10
  };
10
11
 
11
12
  export type RouterServiceOptions = {
12
- config: {
13
- routes: RouteConfigValue[];
14
- };
13
+ routes: RouteConfigValue[];
15
14
  logger: LoggerInterface;
16
15
  };
17
16
 
18
- export type RouterServiceState = {
19
- routes: RouteConfigValue[];
20
- };
17
+ export class RouterServiceState implements StoreStateInterface {
18
+ constructor(public routes: RouteConfigValue[] = []) {}
19
+ }
21
20
 
22
21
  export class RouteService
22
+ extends StoreInterface<RouterServiceState>
23
23
  implements UIDependenciesInterface<RouterServiceDependencies>
24
24
  {
25
25
  /**
@@ -27,12 +27,8 @@ export class RouteService
27
27
  */
28
28
  dependencies?: RouterServiceDependencies;
29
29
 
30
- state: RouterServiceState;
31
-
32
30
  constructor(private options: RouterServiceOptions) {
33
- this.state = {
34
- routes: options.config.routes
35
- };
31
+ super(() => new RouterServiceState(options.routes));
36
32
  }
37
33
 
38
34
  get logger(): LoggerInterface {
@@ -43,7 +39,9 @@ export class RouteService
43
39
  const navigate = this.dependencies?.navigate;
44
40
 
45
41
  if (!navigate) {
46
- this.logger.debug('navigate is not set');
42
+ this.logger.debug(
43
+ 'Please use `RouterServiceProvider` to set dependencies'
44
+ );
47
45
  }
48
46
 
49
47
  return navigate;
@@ -69,7 +67,7 @@ export class RouteService
69
67
  }
70
68
 
71
69
  changeRoutes(routes: RouteConfigValue[]): void {
72
- this.state.routes = routes;
70
+ this.emit({ routes });
73
71
  }
74
72
 
75
73
  goto(path: string, options?: NavigateOptions): void {
@@ -0,0 +1,132 @@
1
+ import { ExecutorPlugin, type SyncStorageInterface } from '@qlover/fe-corekit';
2
+ import type {
3
+ UserApiGetUserInfoTransaction,
4
+ UserApiLoginTransaction
5
+ } from '@/base/apis/userApi/UserApiType';
6
+ import { RouteService } from './RouteService';
7
+ import {
8
+ LoginResponseData,
9
+ type UserAuthApiInterface,
10
+ UserAuthService,
11
+ UserAuthStore
12
+ } from '@qlover/corekit-bridge';
13
+ import { inject, injectable } from 'inversify';
14
+ import { UserApi } from '@/base/apis/userApi/UserApi';
15
+ import { AppError } from '@/base/cases/AppError';
16
+ import * as errKeys from '@config/Identifier/common.error';
17
+ import { IOCIdentifier } from '@/core/IOC';
18
+ import { AppConfig } from '../cases/AppConfig';
19
+
20
+ export type UserServiceUserInfo =
21
+ UserApiGetUserInfoTransaction['response']['data'];
22
+
23
+ export interface RegisterFormData {
24
+ username: string;
25
+ email: string;
26
+ password: string;
27
+ confirmPassword: string;
28
+ agreeToTerms: boolean;
29
+ }
30
+
31
+ @injectable()
32
+ export class UserService
33
+ extends UserAuthService<UserServiceUserInfo>
34
+ implements ExecutorPlugin
35
+ {
36
+ readonly pluginName = 'UserService';
37
+
38
+ constructor(
39
+ @inject(RouteService) protected routerService: RouteService,
40
+ @inject(UserApi) userApi: UserAuthApiInterface<UserServiceUserInfo>,
41
+ @inject(IOCIdentifier.AppConfig) appConfig: AppConfig,
42
+ @inject(IOCIdentifier.LocalStorageEncrypt)
43
+ storage: SyncStorageInterface<string, string>
44
+ ) {
45
+ super({
46
+ api: userApi,
47
+ userStorage: {
48
+ key: appConfig.userInfoStorageKey,
49
+ storage: storage
50
+ },
51
+ credentialStorage: {
52
+ key: appConfig.userTokenStorageKey,
53
+ storage: storage
54
+ }
55
+ });
56
+
57
+ // FIXME:
58
+ // load credential from storage
59
+ // this.store.setCredential(this.store.getCredentialStorage()?.get() ?? '');
60
+ }
61
+
62
+ /**
63
+ * @override
64
+ */
65
+ override get store(): UserAuthStore<UserServiceUserInfo> {
66
+ return super.store as UserAuthStore<UserServiceUserInfo>;
67
+ }
68
+
69
+ getToken(): string | null {
70
+ return this.store.getCredential();
71
+ }
72
+
73
+ /**
74
+ * @override
75
+ */
76
+ async onBefore(): Promise<void> {
77
+ if (this.isAuthenticated()) {
78
+ return;
79
+ }
80
+
81
+ const userToken = this.getToken();
82
+
83
+ if (!userToken) {
84
+ throw new AppError(errKeys.LOCAL_NO_USER_TOKEN);
85
+ }
86
+
87
+ if (userToken) {
88
+ this.store.authSuccess();
89
+ }
90
+
91
+ await this.userInfo();
92
+ this.store.authSuccess();
93
+ }
94
+
95
+ /**
96
+ * @override
97
+ */
98
+ onSuccess(): void {
99
+ // if (this.isAuthenticated()) {
100
+ // this.store.authSuccess();
101
+ // } else {
102
+ // this.logout();
103
+ // }
104
+ }
105
+
106
+ /**
107
+ * @override
108
+ */
109
+ override async logout(): Promise<void> {
110
+ await super.logout();
111
+
112
+ this.routerService.reset();
113
+ this.routerService.gotoLogin();
114
+ }
115
+
116
+ async register(params: RegisterFormData): Promise<LoginResponseData> {
117
+ const response = (await this.api.register(
118
+ params
119
+ )) as UserApiLoginTransaction['response'];
120
+
121
+ if (response.data?.token) {
122
+ try {
123
+ await this.userInfo({ token: response.data?.token });
124
+ this.store.authSuccess();
125
+ } catch (error) {
126
+ this.store.authFailed(error);
127
+ }
128
+ }
129
+
130
+ throw new AppError(errKeys.LOCAL_NO_USER_TOKEN);
131
+ }
132
+ }
@@ -10,12 +10,22 @@ export interface BasePageProvider {
10
10
  type RouteCategory = 'main' | 'auth' | 'common';
11
11
 
12
12
  export interface RouteMeta {
13
- category?: RouteCategory;
14
13
  /**
15
- * from app.router.json
14
+ * The title of the route
16
15
  */
17
16
  title?: string;
17
+
18
+ /**
19
+ * The description of the route
20
+ */
21
+ description?: string;
22
+
23
+ /**
24
+ * The icon of the route
25
+ */
18
26
  icon?: string;
27
+
28
+ category?: RouteCategory;
19
29
  /**
20
30
  * from app.router.json
21
31
  *
@@ -2,14 +2,15 @@
2
2
  import {
3
3
  ApiMockPlugin,
4
4
  EnvConfigInterface,
5
- StorageTokenInterface,
6
5
  RequestCommonPlugin,
7
6
  ApiCatchPlugin,
8
7
  IOCContainerInterface,
9
8
  createIOCFunction,
10
- ServiceIdentifier
9
+ ServiceIdentifier,
10
+ TokenStorage,
11
+ CookieStorage
11
12
  } from '@qlover/corekit-bridge';
12
- import type { JSONSerializer, JSONStorage } from '@qlover/fe-corekit';
13
+ import type { JSONSerializer, ObjectStorage } from '@qlover/fe-corekit';
13
14
  import type { LoggerInterface } from '@qlover/logger';
14
15
  import type { AppConfig } from '@/base/cases/AppConfig';
15
16
  import { Container } from 'inversify';
@@ -69,7 +70,9 @@ export class InversifyContainer implements IOCContainerInterface {
69
70
  */
70
71
  export const IOCIdentifier = Object.freeze({
71
72
  JSON: 'JSON',
72
- JSONStorage: 'JSONStorage',
73
+ LocalStorage: 'LocalStorage',
74
+ LocalStorageEncrypt: 'LocalStorageEncrypt',
75
+ CookieStorage: 'CookieStorage',
73
76
  Logger: 'Logger',
74
77
  FeApiToken: 'FeApiToken',
75
78
  FeApiCommonPlugin: 'FeApiCommonPlugin',
@@ -84,9 +87,11 @@ export const IOCIdentifier = Object.freeze({
84
87
  */
85
88
  export interface IOCIdentifierMap {
86
89
  [IOCIdentifier.JSON]: JSONSerializer;
87
- [IOCIdentifier.JSONStorage]: JSONStorage;
90
+ [IOCIdentifier.LocalStorage]: ObjectStorage<string, string>;
91
+ [IOCIdentifier.LocalStorageEncrypt]: ObjectStorage<string, string>;
92
+ [IOCIdentifier.CookieStorage]: CookieStorage;
88
93
  [IOCIdentifier.Logger]: LoggerInterface;
89
- [IOCIdentifier.FeApiToken]: StorageTokenInterface<string>;
94
+ [IOCIdentifier.FeApiToken]: TokenStorage<string>;
90
95
  [IOCIdentifier.FeApiCommonPlugin]: RequestCommonPlugin;
91
96
  [IOCIdentifier.AppConfig]: EnvConfigInterface;
92
97
  [IOCIdentifier.ApiMockPlugin]: ApiMockPlugin;
@@ -4,7 +4,7 @@ import { IOC } from './IOC';
4
4
  import * as globals from '@/core/globals';
5
5
  import { IocRegister } from './registers';
6
6
  import { BootstrapsRegistry } from './bootstraps';
7
- import { GLOBAL_NO_WINDOW } from '@config/Identifier/Error';
7
+ import { GLOBAL_NO_WINDOW } from '@config/Identifier/common.error';
8
8
 
9
9
  export default async function startup({
10
10
  root,
@@ -33,7 +33,7 @@ export default async function startup({
33
33
  },
34
34
  envOptions: {
35
35
  target: appConfig,
36
- source: envSource,
36
+ source: { ...envSource, [envPrefix + 'BOOT_HREF']: root.location.href },
37
37
  prefix: envPrefix,
38
38
  blackList: envBlackList
39
39
  },
@@ -11,6 +11,7 @@ import { AiApiBootstarp } from '@/base/apis/AiApi';
11
11
  import { printBootstrap } from './PrintBootstrap';
12
12
  import { IOCIdentifier, type IOCIdentifierMap } from '../IOC';
13
13
  import { I18nService } from '@/base/services/I18nService';
14
+ import { I18nKeyErrorPlugin } from '@/base/cases/I18nKeyErrorPlugin';
14
15
 
15
16
  export class BootstrapsRegistry {
16
17
  constructor(
@@ -29,7 +30,8 @@ export class BootstrapsRegistry {
29
30
  new UserApiBootstarp(),
30
31
  new FeApiBootstarp(),
31
32
  AiApiBootstarp,
32
- new BootstrapApp()
33
+ new BootstrapApp(),
34
+ IOC(I18nKeyErrorPlugin)
33
35
  ];
34
36
 
35
37
  if (this.appConfig.env !== 'production') {
@@ -1,6 +1,17 @@
1
1
  // ! global variables, don't import any dependencies and don't have side effects
2
- import { JSONStorage, JSONSerializer, SyncStorage } from '@qlover/fe-corekit';
3
- import { ColorFormatter, ConsoleHandler, Logger } from '@qlover/corekit-bridge';
2
+ import {
3
+ Base64Serializer,
4
+ JSONSerializer,
5
+ ObjectStorage,
6
+ SyncStorage,
7
+ SyncStorageInterface
8
+ } from '@qlover/fe-corekit';
9
+ import {
10
+ ColorFormatter,
11
+ ConsoleHandler,
12
+ CookieStorage,
13
+ Logger
14
+ } from '@qlover/corekit-bridge';
4
15
  import { DialogHandler } from '@/base/cases/DialogHandler';
5
16
  import { loggerStyles } from '@config/common';
6
17
  import { AppConfig } from '@/base/cases/AppConfig';
@@ -26,9 +37,14 @@ export const logger = new Logger({
26
37
  export const JSON = new JSONSerializer();
27
38
 
28
39
  /**
29
- * Override JSONStorage to use the global local storage
40
+ * Override localStorage to use the global local storage
30
41
  */
31
- export const localJsonStorage = new JSONStorage(
32
- localStorage as SyncStorage<string, string>,
33
- JSON
34
- );
42
+ export const localStorage = new SyncStorage(new ObjectStorage(), [
43
+ JSON,
44
+ new Base64Serializer(),
45
+ window.localStorage as unknown as SyncStorageInterface<string>
46
+ ]);
47
+
48
+ export const localStorageEncrypt = localStorage;
49
+
50
+ export const cookieStorage = new CookieStorage();
@@ -1,4 +1,4 @@
1
- import { InversifyContainer, InversifyRegisterInterface } from '../IOC';
1
+ import type { InversifyContainer, InversifyRegisterInterface } from '../IOC';
2
2
 
3
3
  export class RegisterApi implements InversifyRegisterInterface {
4
4
  register(_container: InversifyContainer): void {}