@qlover/create-app 0.1.15 → 0.1.16

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 (112) hide show
  1. package/CHANGELOG.md +33 -27
  2. package/bin/create-app.js +0 -0
  3. package/configs/_common/package.json.template +10 -0
  4. package/configs/react-app/eslint.config.js +70 -42
  5. package/dist/index.cjs +1 -3631
  6. package/dist/index.js +1 -3625
  7. package/package.json +7 -7
  8. package/templates/react-app/.env +1 -0
  9. package/templates/react-app/config/ErrorIdentifier.ts +27 -0
  10. package/templates/react-app/config/app.router.json +9 -0
  11. package/templates/react-app/config/common.ts +12 -0
  12. package/templates/react-app/config/feapi.mock.json +15 -2
  13. package/templates/react-app/config/i18n.ts +3 -11
  14. package/templates/react-app/package.json +7 -4
  15. package/templates/react-app/pnpm-lock.yaml +176 -25
  16. package/templates/react-app/public/locales/en/common.json +6 -2
  17. package/templates/react-app/public/locales/zh/common.json +6 -3
  18. package/templates/react-app/src/App.tsx +8 -8
  19. package/templates/react-app/src/base/apis/AiApi.ts +55 -0
  20. package/templates/react-app/src/base/apis/feApi/FeApi.ts +13 -44
  21. package/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +14 -0
  22. package/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +67 -0
  23. package/templates/react-app/src/base/apis/feApi/FeApiType.ts +2 -35
  24. package/templates/react-app/src/base/apis/userApi/UserApi.ts +64 -0
  25. package/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +14 -0
  26. package/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +75 -0
  27. package/templates/react-app/src/base/apis/userApi/UserApiType.ts +52 -0
  28. package/templates/react-app/src/base/cases/RequestLogger.ts +71 -0
  29. package/templates/react-app/src/base/cases/RequestStatusCatcher.ts +41 -0
  30. package/templates/react-app/src/base/cases/appError/AppError.ts +13 -0
  31. package/templates/react-app/{lib/router-loader/RouterLoader.ts → src/base/cases/router-loader/index.ts} +1 -1
  32. package/templates/react-app/src/base/port/ApiTransactionInterface.ts +7 -0
  33. package/templates/react-app/src/base/port/InversifyIocInterface.ts +1 -1
  34. package/templates/react-app/src/base/port/LoginInterface.ts +4 -0
  35. package/templates/react-app/src/base/port/RequestCatcherInterface.ts +12 -0
  36. package/templates/react-app/src/{services → base/services}/I18nService.ts +7 -2
  37. package/templates/react-app/src/{services/processer → base/services}/ProcesserService.ts +10 -11
  38. package/templates/react-app/src/base/types/Page.ts +1 -13
  39. package/templates/react-app/src/core/AppConfig.ts +14 -5
  40. package/templates/react-app/src/core/IOC.ts +77 -37
  41. package/templates/react-app/src/core/bootstrap.ts +38 -25
  42. package/templates/react-app/src/core/bootstraps/BootstrapApp.ts +7 -0
  43. package/templates/react-app/src/core/bootstraps/index.ts +12 -0
  44. package/templates/react-app/src/core/globals.ts +7 -10
  45. package/templates/react-app/src/core/registers/RegisterApi.ts +1 -52
  46. package/templates/react-app/src/core/registers/RegisterCommon.ts +44 -6
  47. package/templates/react-app/src/core/registers/RegisterControllers.ts +5 -34
  48. package/templates/react-app/src/core/registers/RegisterGlobals.ts +8 -2
  49. package/templates/react-app/src/core/registers/index.ts +2 -1
  50. package/templates/react-app/src/main.tsx +4 -1
  51. package/templates/react-app/src/pages/auth/Layout.tsx +4 -3
  52. package/templates/react-app/src/pages/auth/Login.tsx +5 -3
  53. package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +39 -0
  54. package/templates/react-app/src/pages/base/Executor.tsx +31 -10
  55. package/templates/react-app/src/pages/base/Home.tsx +58 -30
  56. package/templates/react-app/src/pages/base/JSONStorage.tsx +2 -4
  57. package/templates/react-app/src/pages/base/Request.tsx +318 -73
  58. package/templates/react-app/src/pages/base/components/BaseHeader.tsx +2 -2
  59. package/templates/react-app/src/{components → uikit/components}/RouterRenderComponent.tsx +1 -1
  60. package/templates/react-app/src/{components → uikit/components}/ThemeSwitcher.tsx +6 -6
  61. package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +6 -3
  62. package/templates/react-app/src/uikit/controllers/ExecutorController.ts +52 -22
  63. package/templates/react-app/src/uikit/controllers/JSONStorageController.ts +7 -3
  64. package/templates/react-app/src/uikit/controllers/RequestController.ts +65 -11
  65. package/templates/react-app/src/uikit/controllers/RouterController.ts +8 -7
  66. package/templates/react-app/src/uikit/controllers/UserController.ts +48 -54
  67. package/templates/react-app/src/uikit/hooks/useLanguageGuard.ts +1 -2
  68. package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +4 -4
  69. package/templates/react-app/src/uikit/styles/css/index.css +1 -1
  70. package/templates/react-app/src/uikit/styles/css/page.css +1 -1
  71. package/templates/react-app/tailwind.config.js +2 -2
  72. package/templates/react-app/tsconfig.json +0 -1
  73. package/templates/react-app/tsconfig.node.json +1 -2
  74. package/templates/react-app/vite.config.ts +21 -26
  75. package/templates/react-app/.env.local +0 -24
  76. package/templates/react-app/lib/bootstrap/Bootstrap.ts +0 -36
  77. package/templates/react-app/lib/bootstrap/BootstrapExecutorPlugin.ts +0 -20
  78. package/templates/react-app/lib/bootstrap/IOCContainerInterface.ts +0 -33
  79. package/templates/react-app/lib/bootstrap/IOCManagerInterface.ts +0 -12
  80. package/templates/react-app/lib/bootstrap/index.ts +0 -7
  81. package/templates/react-app/lib/bootstrap/plugins/InjectEnv.ts +0 -61
  82. package/templates/react-app/lib/bootstrap/plugins/InjectGlobal.ts +0 -36
  83. package/templates/react-app/lib/bootstrap/plugins/InjectIOC.ts +0 -24
  84. package/templates/react-app/lib/env-config/injectPkgConfig.ts +0 -11
  85. package/templates/react-app/lib/fe-react-controller/FeController.ts +0 -19
  86. package/templates/react-app/lib/fe-react-controller/index.ts +0 -2
  87. package/templates/react-app/lib/fe-react-controller/useController.ts +0 -71
  88. package/templates/react-app/lib/fe-react-theme/ThemeController.ts +0 -40
  89. package/templates/react-app/lib/fe-react-theme/ThemeStateGetter.ts +0 -53
  90. package/templates/react-app/lib/fe-react-theme/index.ts +0 -3
  91. package/templates/react-app/lib/fe-react-theme/type.ts +0 -21
  92. package/templates/react-app/lib/openAiApi/OpenAIAuthPlugin.ts +0 -29
  93. package/templates/react-app/lib/openAiApi/OpenAIClient.ts +0 -51
  94. package/templates/react-app/lib/openAiApi/StreamProcessor.ts +0 -81
  95. package/templates/react-app/lib/openAiApi/index.ts +0 -3
  96. package/templates/react-app/lib/request-common-plugin/index.ts +0 -169
  97. package/templates/react-app/lib/router-loader/Page.ts +0 -68
  98. package/templates/react-app/lib/tw-root10px/index.css +0 -4
  99. package/templates/react-app/src/base/apis/feApi/FeApiMockPlugin.ts +0 -44
  100. package/templates/react-app/src/base/apis/feApi/index.ts +0 -2
  101. package/templates/react-app/src/base/cases/UserToken.ts +0 -47
  102. package/templates/react-app/src/base/consts/IOCIdentifier.ts +0 -16
  103. package/templates/react-app/src/base/port/IOCFunctionInterface.ts +0 -39
  104. package/templates/react-app/src/base/port/StorageTokenInterface.ts +0 -27
  105. package/templates/react-app/src/core/AppIOCContainer.ts +0 -30
  106. package/templates/react-app/src/uikit/utils/RequestLogger.ts +0 -37
  107. package/templates/react-app/src/uikit/utils/datetime.ts +0 -30
  108. package/templates/react-app/src/uikit/utils/thread.ts +0 -3
  109. /package/templates/react-app/lib/{tw-root10px/index.js → tailwind/root10px.js} +0 -0
  110. /package/templates/react-app/lib/{fe-react-theme/tw-generator.js → tailwind/theme-generator.js} +0 -0
  111. /package/templates/react-app/src/{components → uikit/components}/Loading.tsx +0 -0
  112. /package/templates/react-app/src/{components → uikit/components}/LocaleLink.tsx +0 -0
@@ -2,5 +2,9 @@
2
2
  "404.notComponent": "Component not found",
3
3
  "404.notPage": "Page not found",
4
4
  "500.title": "Server Error",
5
- "header.theme.label": "Switch Theme"
6
- }
5
+ "header.theme.label": "Switch Theme",
6
+ "err.ioc.not.implemented": "IOC not implemented",
7
+ "err.local.no.user.token": "Local no user token",
8
+ "err.global.no.window": "Global no window",
9
+ "err.within.page.provider": "Must be used in PageProvider"
10
+ }
@@ -2,6 +2,9 @@
2
2
  "404.notComponent": "组件不存在",
3
3
  "404.notPage": "页面不存在",
4
4
  "500.title": "服务器错误",
5
- "header.theme.label": "切换主题"
6
- }
7
-
5
+ "header.theme.label": "切换主题",
6
+ "err.ioc.not.implemented": "IOC 未实现",
7
+ "err.local.no.user.token": "本地未找到 user token",
8
+ "err.global.no.window": "全局未找到 window",
9
+ "err.within.page.provider": "必须在 PageProvider 中使用"
10
+ }
@@ -1,10 +1,10 @@
1
1
  import '@/uikit/styles/css/index.css';
2
2
  import { createBrowserRouter, RouterProvider } from 'react-router-dom';
3
3
  import { lazy, useMemo } from 'react';
4
- import { RouterLoader } from '@lib/router-loader/RouterLoader';
5
- import appConfig from '@config/app.router.json';
6
- import { RouterRenderComponent } from './components/RouterRenderComponent';
7
- import { PagesMaps } from './base/types/Page';
4
+ import { RouterRenderComponent } from './uikit/components/RouterRenderComponent';
5
+ import { IOC } from './core/IOC';
6
+ import { RouterController } from './uikit/controllers/RouterController';
7
+ import { RouterLoader, type ComponentValue } from '@/base/cases/router-loader';
8
8
 
9
9
  function getAllPages() {
10
10
  const modules = import.meta.glob('./pages/**/*.tsx');
@@ -17,7 +17,7 @@ function getAllPages() {
17
17
  }>
18
18
  );
19
19
  return acc;
20
- }, {} as PagesMaps);
20
+ }, {} as ComponentValue);
21
21
  }
22
22
 
23
23
  const routerLoader = new RouterLoader({
@@ -27,9 +27,9 @@ const routerLoader = new RouterLoader({
27
27
 
28
28
  function App() {
29
29
  const routerBase = useMemo(() => {
30
- const routes = appConfig.base.routes.map((route) =>
31
- routerLoader.toRoute(route)
32
- );
30
+ const routes = IOC(RouterController)
31
+ .getRoutes()
32
+ .map((route) => routerLoader.toRoute(route));
33
33
  const router = createBrowserRouter(routes);
34
34
  return router;
35
35
  }, []);
@@ -0,0 +1,55 @@
1
+ import AppConfig from '@/core/AppConfig';
2
+ import {
3
+ FetchURLPlugin,
4
+ RequestAdapterFetch,
5
+ RequestScheduler
6
+ } from '@qlover/fe-corekit';
7
+ import {
8
+ type BootstrapExecutorPlugin,
9
+ RequestCommonPlugin
10
+ } from '@qlover/corekit-bridge';
11
+ import { RequestLogger } from '../cases/RequestLogger';
12
+ import { IOCIdentifier } from '@/core/IOC';
13
+
14
+ const apiApiAdapter = new RequestAdapterFetch({
15
+ baseURL: AppConfig.aiApiBaseUrl
16
+ });
17
+
18
+ // 使用 RequestScheduler
19
+ const apiApi = new RequestScheduler(apiApiAdapter);
20
+
21
+ // 直接使用 adapter
22
+ // const apiApi = apiApiAdapter;
23
+
24
+ export const AiApiBootstarp: BootstrapExecutorPlugin = {
25
+ pluginName: 'AiApiBootstarp',
26
+ onBefore({ parameters: { ioc } }) {
27
+ apiApiAdapter.usePlugin(new FetchURLPlugin());
28
+ apiApiAdapter.usePlugin(
29
+ new RequestCommonPlugin({
30
+ tokenPrefix: AppConfig.aiApiTokenPrefix,
31
+ token: AppConfig.aiApiToken
32
+ })
33
+ );
34
+ apiApiAdapter.usePlugin(ioc.get(IOCIdentifier.ApiMockPlugin));
35
+ apiApiAdapter.usePlugin(ioc.get(RequestLogger));
36
+ }
37
+ };
38
+
39
+ export function aiHello(data: {
40
+ messages: { role: string; content: string }[];
41
+ }) {
42
+ return apiApi.request<
43
+ typeof data,
44
+ {
45
+ id: string;
46
+ object: string;
47
+ created: number;
48
+ choices: { message: { role: string; content: string } }[];
49
+ }
50
+ >({
51
+ url: '/chat/completions',
52
+ method: 'POST',
53
+ data
54
+ });
55
+ }
@@ -1,51 +1,20 @@
1
- import {
2
- RequestAdapterFetch,
3
- RequestAdapterConfig,
4
- RequestScheduler,
5
- FetchAbortPlugin,
6
- RequestAdapterFetchConfig
7
- } from '@qlover/fe-utils';
8
- import {
9
- FeApiGetIpInfo,
10
- FeApiGetRandomUser,
11
- FeApiGetUserInfo,
12
- FeApiLogin
13
- } from './FeApiType';
1
+ import { RequestAdapterFetch, RequestScheduler } from '@qlover/fe-corekit';
2
+ import { FeApiGetIpInfo } from './FeApiType';
3
+ import { inject, injectable } from 'inversify';
4
+ import { FeApiAdapter } from './FeApiAdapter';
5
+ import { FeApiConfig } from './FeApiBootstarp';
14
6
 
15
- export class FeApi extends RequestScheduler<RequestAdapterConfig> {
16
- private abortPlugin: FetchAbortPlugin;
17
-
18
- constructor({
19
- abortPlugin,
20
- config
21
- }: {
22
- abortPlugin: FetchAbortPlugin;
23
- config?: Partial<RequestAdapterFetchConfig>;
24
- }) {
25
- super(new RequestAdapterFetch(config));
26
- this.abortPlugin = abortPlugin;
7
+ @injectable()
8
+ export class FeApi extends RequestScheduler<FeApiConfig> {
9
+ constructor(@inject(FeApiAdapter) adapter: RequestAdapterFetch) {
10
+ super(adapter);
27
11
  }
28
12
 
29
- stop(config: RequestAdapterConfig): void {
30
- this.abortPlugin.abort(config);
31
- }
13
+ stop(_config: FeApiConfig): void {}
32
14
 
33
15
  async getIpInfo(): Promise<FeApiGetIpInfo['response']> {
34
- return this.get('http://ip-api.com/json/');
35
- }
36
-
37
- async getRandomUser(): Promise<FeApiGetRandomUser['response']> {
38
- return this.get('https://randomuser.me/api/');
39
- }
40
-
41
- async getUserInfo(): Promise<FeApiGetUserInfo['response']> {
42
- return this.get('/api/userinfo');
43
- }
44
-
45
- async login(params: FeApiLogin['request']): Promise<FeApiLogin['response']> {
46
- return this.post('/api/login', {
47
- // FIXME: RequestAdapterResponse response type error
48
- data: params as unknown as FeApiLogin['response']['data']
49
- });
16
+ return this.get('http://ip-api.com/json/') as unknown as Promise<
17
+ FeApiGetIpInfo['response']
18
+ >;
50
19
  }
51
20
  }
@@ -0,0 +1,14 @@
1
+ import { IOCIdentifier } from '@/core/IOC';
2
+ import { RequestAdapterFetch } from '@qlover/fe-corekit';
3
+ import { inject, injectable } from 'inversify';
4
+ import { AppConfigImpl } from '@/core/AppConfig';
5
+
6
+ @injectable()
7
+ export class FeApiAdapter extends RequestAdapterFetch {
8
+ constructor(@inject(IOCIdentifier.AppConfig) appConfig: AppConfigImpl) {
9
+ super({
10
+ responseType: 'json',
11
+ baseURL: appConfig.feApiBaseUrl
12
+ });
13
+ }
14
+ }
@@ -0,0 +1,67 @@
1
+ import type {
2
+ RequestAdapterConfig,
3
+ RequestAdapterResponse,
4
+ RequestTransactionInterface
5
+ } from '@qlover/fe-corekit';
6
+ import { FetchURLPlugin } from '@qlover/fe-corekit';
7
+ import {
8
+ type BootstrapContext,
9
+ type BootstrapExecutorPlugin,
10
+ type ApiMockPluginConfig,
11
+ ApiPickDataPlugin
12
+ } from '@qlover/corekit-bridge';
13
+ import { FeApi } from './FeApi';
14
+ import { IOCIdentifier } from '@/core/IOC';
15
+ import { RequestLogger } from '@/base/cases/RequestLogger';
16
+
17
+ /**
18
+ * FeApiConfig
19
+ *
20
+ * @description
21
+ * FeApiConfig is the config for the FeApi.
22
+ *
23
+ * extends:
24
+ */
25
+ export interface FeApiConfig<Request = unknown>
26
+ extends RequestAdapterConfig<Request>,
27
+ ApiMockPluginConfig {}
28
+
29
+ /**
30
+ * FeApiResponse
31
+ *
32
+ * @description
33
+ * FeApiResponse is the response for the FeApi.
34
+ *
35
+ * extends:
36
+ * - RequestAdapterResponse<Request, Response>
37
+ */
38
+ export interface FeApiResponse<Request = unknown, Response = unknown>
39
+ extends RequestAdapterResponse<Request, Response> {}
40
+
41
+ /**
42
+ * FeApi common transaction
43
+ *
44
+ * FIXME: maybe we can add data to RequestTransactionInterface
45
+ *
46
+ * add data property
47
+ */
48
+ export interface FeApiTransaction<Request = unknown, Response = unknown>
49
+ extends RequestTransactionInterface<
50
+ FeApiConfig<Request>,
51
+ FeApiResponse<Request, Response>['data']
52
+ > {
53
+ data: FeApiConfig<Request>['data'];
54
+ }
55
+
56
+ export class FeApiBootstarp implements BootstrapExecutorPlugin {
57
+ readonly pluginName = 'FeApiBootstarp';
58
+
59
+ onBefore({ parameters: { ioc } }: BootstrapContext): void {
60
+ ioc
61
+ .get<FeApi>(FeApi)
62
+ .usePlugin(new FetchURLPlugin())
63
+ .usePlugin(ioc.get(IOCIdentifier.FeApiCommonPlugin))
64
+ .usePlugin(ioc.get(RequestLogger))
65
+ .usePlugin(ioc.get(ApiPickDataPlugin));
66
+ }
67
+ }
@@ -1,10 +1,6 @@
1
- import { RequestAdapterResponse } from '@qlover/fe-utils';
1
+ import { FeApiTransaction } from './FeApiBootstarp';
2
2
 
3
- export type FeApiType<Request, Response> = {
4
- request: Request;
5
- response: RequestAdapterResponse<Request, Response>;
6
- };
7
- export type FeApiGetIpInfo = FeApiType<
3
+ export type FeApiGetIpInfo = FeApiTransaction<
8
4
  undefined,
9
5
  {
10
6
  status: string;
@@ -23,32 +19,3 @@ export type FeApiGetIpInfo = FeApiType<
23
19
  query: string;
24
20
  }
25
21
  >;
26
-
27
- export type FeApiGetRandomUser = FeApiType<
28
- undefined,
29
- {
30
- results: unknown[];
31
- info: {
32
- seed: string;
33
- results: number;
34
- page: number;
35
- version: string;
36
- };
37
- }
38
- >;
39
-
40
- export type FeApiGetUserInfo = FeApiType<
41
- string,
42
- {
43
- name: string;
44
- email: string;
45
- picture: string;
46
- }
47
- >;
48
-
49
- export type FeApiLogin = FeApiType<
50
- { username: string; password: string },
51
- {
52
- token: string;
53
- }
54
- >;
@@ -0,0 +1,64 @@
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
+
16
+ /**
17
+ * UserApi
18
+ *
19
+ * @description
20
+ * UserApi is a client for the user API.
21
+ *
22
+ */
23
+ @injectable()
24
+ export class UserApi extends RequestTransaction<UserApiConfig> {
25
+ constructor(
26
+ @inject(FetchAbortPlugin) private abortPlugin: FetchAbortPlugin,
27
+ @inject(UserApiAdapter) adapter: RequestAdapterFetch
28
+ ) {
29
+ super(adapter);
30
+ }
31
+
32
+ stop(request: UserApiConfig): Promise<void> | void {
33
+ this.abortPlugin.abort(request);
34
+ }
35
+
36
+ async getRandomUser(): Promise<GetIpInfoTransaction['response']> {
37
+ return this.request<GetIpInfoTransaction>({
38
+ url: 'https://randomuser.me/api/',
39
+ method: 'GET',
40
+ disabledMock: true
41
+ });
42
+ }
43
+
44
+ async testApiCatchResult(): Promise<
45
+ UserApiTestApiCatchResultTransaction['response']
46
+ > {
47
+ return this.request<UserApiTestApiCatchResultTransaction>({
48
+ url: 'https://randomuser.me/api/?_name=ApiCatchResult',
49
+ method: 'GET',
50
+ disabledMock: true,
51
+ openApiCatch: true
52
+ });
53
+ }
54
+
55
+ async getUserInfo(): Promise<UserApiGetUserInfoTransaction['response']> {
56
+ return this.get<UserApiGetUserInfoTransaction>('/api/userinfo');
57
+ }
58
+
59
+ async login(
60
+ params: UserApiLoginTransaction['data']
61
+ ): Promise<UserApiLoginTransaction['response']> {
62
+ return this.post<UserApiLoginTransaction>('/api/login', params);
63
+ }
64
+ }
@@ -0,0 +1,14 @@
1
+ import { IOCIdentifier } from '@/core/IOC';
2
+ import { RequestAdapterFetch } from '@qlover/fe-corekit';
3
+ import { inject, injectable } from 'inversify';
4
+ import { AppConfigImpl } from '@/core/AppConfig';
5
+
6
+ @injectable()
7
+ export class UserApiAdapter extends RequestAdapterFetch {
8
+ constructor(@inject(IOCIdentifier.AppConfig) appConfig: AppConfigImpl) {
9
+ super({
10
+ responseType: 'json',
11
+ baseURL: appConfig.feApiBaseUrl
12
+ });
13
+ }
14
+ }
@@ -0,0 +1,75 @@
1
+ import {
2
+ FetchAbortPlugin,
3
+ RequestAdapterConfig,
4
+ RequestAdapterResponse,
5
+ RequestTransactionInterface
6
+ } from '@qlover/fe-corekit';
7
+ import { IOC, IOCIdentifier } from '@/core/IOC';
8
+ import { RequestLogger } from '@/base/cases/RequestLogger';
9
+ import { FetchURLPlugin } from '@qlover/fe-corekit';
10
+ import {
11
+ type BootstrapContext,
12
+ type BootstrapExecutorPlugin,
13
+ type ApiMockPluginConfig,
14
+ type ApiCatchPluginConfig,
15
+ type ApiCatchPluginResponse
16
+ } from '@qlover/corekit-bridge';
17
+ import { UserApi } from './UserApi';
18
+
19
+ /**
20
+ * UserApiConfig
21
+ *
22
+ * @description
23
+ * UserApiConfig is the config for the UserApi.
24
+ *
25
+ * extends:
26
+ * - ApiMockPluginConfig
27
+ * - ApiCatchPluginConfig
28
+ */
29
+ export interface UserApiConfig<Request = unknown>
30
+ extends RequestAdapterConfig<Request>,
31
+ ApiMockPluginConfig,
32
+ ApiCatchPluginConfig {}
33
+
34
+ /**
35
+ * UserApiResponse
36
+ *
37
+ * @description
38
+ * UserApiResponse is the response for the UserApi.
39
+ *
40
+ * extends:
41
+ * - RequestAdapterResponse<Request, Response>
42
+ */
43
+ export interface UserApiResponse<Request = unknown, Response = unknown>
44
+ extends RequestAdapterResponse<Request, Response>,
45
+ ApiCatchPluginResponse {}
46
+
47
+ /**
48
+ * UserApi common transaction
49
+ *
50
+ * FIXME: maybe we can add data to RequestTransactionInterface
51
+ *
52
+ * add data property
53
+ */
54
+ export interface UserApiTransaction<Request = unknown, Response = unknown>
55
+ extends RequestTransactionInterface<
56
+ UserApiConfig<Request>,
57
+ UserApiResponse<Request, Response>
58
+ > {
59
+ data: UserApiConfig<Request>['data'];
60
+ }
61
+
62
+ export class UserApiBootstarp implements BootstrapExecutorPlugin {
63
+ readonly pluginName = 'UserApiBootstarp';
64
+
65
+ onBefore({ parameters: { ioc } }: BootstrapContext): void {
66
+ ioc
67
+ .get<UserApi>(UserApi)
68
+ .usePlugin(new FetchURLPlugin())
69
+ .usePlugin(IOC.get(IOCIdentifier.FeApiCommonPlugin))
70
+ .usePlugin(IOC.get(IOCIdentifier.ApiMockPlugin))
71
+ .usePlugin(IOC.get(RequestLogger))
72
+ .usePlugin(IOC.get(FetchAbortPlugin))
73
+ .usePlugin(IOC.get(IOCIdentifier.ApiCatchPlugin));
74
+ }
75
+ }
@@ -0,0 +1,52 @@
1
+ import { UserApiTransaction } from './UserApiBootstarp';
2
+
3
+ export type GetIpInfoTransaction = UserApiTransaction<
4
+ undefined,
5
+ {
6
+ status: string;
7
+ country: string;
8
+ countryCode: string;
9
+ region: string;
10
+ regionName: string;
11
+ city: string;
12
+ zip: string;
13
+ lat: number;
14
+ lon: number;
15
+ timezone: string;
16
+ isp: string;
17
+ org: string;
18
+ as: string;
19
+ query: string;
20
+ }
21
+ >;
22
+
23
+ export type UserApiGetRandomUser = UserApiTransaction<
24
+ undefined,
25
+ {
26
+ results: unknown[];
27
+ info: {
28
+ seed: string;
29
+ results: number;
30
+ page: number;
31
+ version: string;
32
+ };
33
+ }
34
+ >;
35
+
36
+ export type UserApiGetUserInfoTransaction = UserApiTransaction<
37
+ string,
38
+ {
39
+ name: string;
40
+ email: string;
41
+ picture: string;
42
+ }
43
+ >;
44
+
45
+ export type UserApiLoginTransaction = UserApiTransaction<
46
+ { username: string; password: string },
47
+ {
48
+ token: string;
49
+ }
50
+ >;
51
+
52
+ export type UserApiTestApiCatchResultTransaction = UserApiGetRandomUser;
@@ -0,0 +1,71 @@
1
+ import { IOCIdentifier } from '@/core/IOC';
2
+ import {
3
+ type ExecutorPlugin,
4
+ type ExecutorContext,
5
+ type RequestAdapterFetchConfig,
6
+ type RequestAdapterResponse,
7
+ Logger
8
+ } from '@qlover/fe-corekit';
9
+ import {
10
+ type ApiCatchPluginConfig,
11
+ type ApiCatchPluginResponse
12
+ } from '@qlover/corekit-bridge';
13
+ import { injectable, inject } from 'inversify';
14
+
15
+ @injectable()
16
+ export class RequestLogger
17
+ implements ExecutorPlugin<RequestAdapterFetchConfig>
18
+ {
19
+ readonly pluginName = 'RequestLogger';
20
+
21
+ constructor(@inject(IOCIdentifier.Logger) public logger: Logger) {}
22
+
23
+ onBefore(context: ExecutorContext<RequestAdapterFetchConfig<unknown>>): void {
24
+ this.logger.log(
25
+ `%c[Request before]%c [${new Date().toLocaleString()}] ${context.parameters.method} ${context.parameters.url}`,
26
+ 'color: #0ff;',
27
+ 'color: inherit;',
28
+ context.parameters
29
+ );
30
+ }
31
+
32
+ async onSuccess({
33
+ parameters,
34
+ returnValue
35
+ }: ExecutorContext<
36
+ RequestAdapterFetchConfig & ApiCatchPluginConfig
37
+ >): Promise<void> {
38
+ const _returnValue = returnValue as RequestAdapterResponse &
39
+ ApiCatchPluginResponse;
40
+
41
+ // If the apiCatchResult is not null, it means that the error has been caught
42
+ // from `ApiCatchPlugin`
43
+ if (_returnValue.apiCatchResult) {
44
+ this.loggerError(parameters, _returnValue.apiCatchResult);
45
+ return;
46
+ }
47
+
48
+ this.logger.log(
49
+ `%c[Request success]%c [${new Date().toLocaleString()}] ${parameters.method} ${parameters.url}`,
50
+ 'color: #0f0;',
51
+ 'color: inherit;',
52
+ _returnValue
53
+ );
54
+ }
55
+
56
+ onError({
57
+ parameters,
58
+ error
59
+ }: ExecutorContext<RequestAdapterFetchConfig>): void {
60
+ this.loggerError(parameters, error);
61
+ }
62
+
63
+ loggerError(config: RequestAdapterFetchConfig, error: unknown): void {
64
+ this.logger.log(
65
+ `%c[Request error]%c [${new Date().toLocaleString()}] ${config.method} ${config.url}`,
66
+ 'color: #f00;',
67
+ 'color: inherit;',
68
+ error
69
+ );
70
+ }
71
+ }
@@ -0,0 +1,41 @@
1
+ import type { RequestCatcherInterface } from '@/base/port/RequestCatcherInterface';
2
+ import { IOCIdentifier } from '@/core/IOC';
3
+ import type { Logger, RequestAdapterResponse } from '@qlover/fe-corekit';
4
+ import { inject, injectable } from 'inversify';
5
+
6
+ @injectable()
7
+ export class RequestStatusCatcher
8
+ implements RequestCatcherInterface<RequestAdapterResponse>
9
+ {
10
+ constructor(
11
+ @inject(IOCIdentifier.Logger)
12
+ private readonly logger: Logger
13
+ ) {}
14
+ /**
15
+ * default handler
16
+ * @override
17
+ */
18
+ default(context: RequestAdapterResponse<unknown, unknown>): void {
19
+ this.logger.warn(`RequestStatusCatcher default handler`, context);
20
+ }
21
+
22
+ /**
23
+ * handler
24
+ * @override
25
+ */
26
+ handler(context: RequestAdapterResponse<unknown, unknown>): void {
27
+ const { status } = context;
28
+
29
+ const _handler = this[`case${status}` as keyof RequestStatusCatcher];
30
+
31
+ if (typeof _handler === 'function') {
32
+ return _handler.call(this, context);
33
+ }
34
+
35
+ return this.default(context);
36
+ }
37
+
38
+ case200(_context: RequestAdapterResponse<unknown, unknown>): void {
39
+ // this.logger.info(`RequestStatusCatcher case200 handler`, context);
40
+ }
41
+ }
@@ -0,0 +1,13 @@
1
+ import { ExecutorError } from '@qlover/fe-corekit';
2
+
3
+ /**
4
+ * 统一当前项目中开发的错误
5
+ */
6
+ export class AppError extends ExecutorError {
7
+ constructor(
8
+ public readonly id: string,
9
+ public readonly source?: string | Error
10
+ ) {
11
+ super(id, source);
12
+ }
13
+ }
@@ -2,7 +2,7 @@ import { RouteObject } from 'react-router-dom';
2
2
  import isString from 'lodash/isString';
3
3
  import type { ComponentType, LazyExoticComponent, ReactNode } from 'react';
4
4
 
5
- type ComponentValue = Record<string, () => unknown>;
5
+ export type ComponentValue = Record<string, () => unknown>;
6
6
 
7
7
  type RouteComponentType<T = unknown> =
8
8
  | ComponentType<T>
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Use for describe the unified format of Api request
3
+ */
4
+ export interface ApiTransactionInterface<Request, Response> {
5
+ request: Request;
6
+ response: Response;
7
+ }
@@ -1,4 +1,4 @@
1
- import type { IOCRegisterInterface } from '@lib/bootstrap';
1
+ import type { IOCRegisterInterface } from '@qlover/corekit-bridge';
2
2
  import type { Container } from 'inversify';
3
3
 
4
4
  export type InversifyRegisterContainer = Container;
@@ -0,0 +1,4 @@
1
+ export interface LoginInterface {
2
+ login(params: { username: string; password: string }): Promise<unknown>;
3
+ logout(): void;
4
+ }