@qlover/create-app 0.6.1 → 0.6.3

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 (68) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/react-app/README.en.md +257 -0
  5. package/dist/templates/react-app/README.md +29 -231
  6. package/dist/templates/react-app/config/IOCIdentifier.ts +13 -0
  7. package/dist/templates/react-app/docs/en/bootstrap.md +562 -0
  8. package/dist/templates/react-app/docs/en/development-guide.md +523 -0
  9. package/dist/templates/react-app/docs/en/env.md +482 -0
  10. package/dist/templates/react-app/docs/en/global.md +509 -0
  11. package/dist/templates/react-app/docs/en/i18n.md +268 -0
  12. package/dist/templates/react-app/docs/en/index.md +173 -0
  13. package/dist/templates/react-app/docs/en/ioc.md +424 -0
  14. package/dist/templates/react-app/docs/en/project-structure.md +434 -0
  15. package/dist/templates/react-app/docs/en/request.md +425 -0
  16. package/dist/templates/react-app/docs/en/router.md +404 -0
  17. package/dist/templates/react-app/docs/en/store.md +321 -0
  18. package/dist/templates/react-app/docs/en/theme.md +424 -0
  19. package/dist/templates/react-app/docs/en/typescript-guide.md +473 -0
  20. package/dist/templates/react-app/docs/zh/bootstrap.md +562 -0
  21. package/dist/templates/react-app/docs/zh/development-guide.md +523 -0
  22. package/dist/templates/react-app/docs/zh/env.md +479 -0
  23. package/dist/templates/react-app/docs/zh/global.md +511 -0
  24. package/dist/templates/react-app/docs/zh/i18n.md +268 -0
  25. package/dist/templates/react-app/docs/zh/index.md +173 -0
  26. package/dist/templates/react-app/docs/zh/ioc.md +422 -0
  27. package/dist/templates/react-app/docs/zh/project-structure.md +434 -0
  28. package/dist/templates/react-app/docs/zh/request.md +429 -0
  29. package/dist/templates/react-app/docs/zh/router.md +408 -0
  30. package/dist/templates/react-app/docs/zh/store.md +321 -0
  31. package/dist/templates/react-app/docs/zh/theme.md +424 -0
  32. package/dist/templates/react-app/docs/zh/typescript-guide.md +473 -0
  33. package/dist/templates/react-app/package.json +2 -2
  34. package/dist/templates/react-app/src/base/apis/AiApi.ts +10 -5
  35. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  36. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +1 -1
  37. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +10 -17
  38. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  39. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +2 -1
  40. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +7 -5
  41. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -2
  42. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +33 -0
  43. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +1 -1
  44. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +2 -2
  45. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +1 -1
  46. package/dist/templates/react-app/src/base/services/RouteService.ts +5 -2
  47. package/dist/templates/react-app/src/base/services/UserService.ts +8 -10
  48. package/dist/templates/react-app/src/core/IOC.ts +73 -83
  49. package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +52 -4
  50. package/dist/templates/react-app/src/core/bootstraps/{index.ts → BootstrapsRegistry.ts} +2 -3
  51. package/dist/templates/react-app/src/core/registers/IocRegisterImpl.ts +25 -0
  52. package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +11 -17
  53. package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +10 -4
  54. package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +6 -15
  55. package/dist/templates/react-app/src/main.tsx +2 -5
  56. package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +3 -1
  57. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +1 -1
  58. package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +6 -1
  59. package/dist/templates/react-app/src/styles/css/page.css +1 -1
  60. package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +1 -1
  61. package/dist/templates/react-app/tsconfig.app.json +2 -1
  62. package/dist/templates/react-app/tsconfig.node.json +2 -1
  63. package/package.json +2 -2
  64. package/dist/templates/react-app/src/base/port/ApiTransactionInterface.ts +0 -7
  65. package/dist/templates/react-app/src/base/port/RequestCatcherInterface.ts +0 -12
  66. package/dist/templates/react-app/src/core/bootstrap.ts +0 -58
  67. package/dist/templates/react-app/src/core/registers/RegisterApi.ts +0 -5
  68. package/dist/templates/react-app/src/core/registers/index.ts +0 -32
@@ -0,0 +1,473 @@
1
+ # TypeScript 开发指南
2
+
3
+ ## 概述
4
+
5
+ 本指南介绍项目中 TypeScript 的使用规范,重点强调三种编程范式:
6
+
7
+ - 面向对象编程(OOP)
8
+ - 面向接口编程(Interface-based)
9
+ - 面向配置编程(Configuration-based)
10
+
11
+ ## 编程范式
12
+
13
+ ### 1. 面向对象编程(OOP)
14
+
15
+ 在项目中,我们大量使用面向对象的思想来组织代码,主要体现在:
16
+
17
+ #### 类的设计
18
+
19
+ ```typescript
20
+ // 基类设计
21
+ abstract class StoreInterface<T extends StoreStateInterface> {
22
+ protected state: T;
23
+
24
+ constructor(initialState: T) {
25
+ this.state = initialState;
26
+ }
27
+
28
+ abstract setState(state: Partial<T>): void;
29
+
30
+ getState(): T {
31
+ return this.state;
32
+ }
33
+ }
34
+
35
+ // 具体实现
36
+ @injectable()
37
+ class UserStore extends StoreInterface<UserState> {
38
+ constructor() {
39
+ super({
40
+ user: null,
41
+ loading: false
42
+ });
43
+ }
44
+
45
+ setState(state: Partial<UserState>): void {
46
+ this.state = { ...this.state, ...state };
47
+ this.notify();
48
+ }
49
+
50
+ private notify(): void {
51
+ // 通知观察者
52
+ }
53
+ }
54
+ ```
55
+
56
+ #### 继承和多态
57
+
58
+ ```typescript
59
+ // 基础服务接口
60
+ interface ServiceInterface {
61
+ initialize(): Promise<void>;
62
+ destroy(): void;
63
+ }
64
+
65
+ // 抽象基类
66
+ abstract class BaseService implements ServiceInterface {
67
+ abstract initialize(): Promise<void>;
68
+
69
+ destroy(): void {
70
+ // 通用清理逻辑
71
+ }
72
+ }
73
+
74
+ // 具体服务实现
75
+ class UserService extends BaseService {
76
+ async initialize(): Promise<void> {
77
+ // 用户服务初始化逻辑
78
+ }
79
+
80
+ // 扩展特定方法
81
+ async login(): Promise<void> {
82
+ // 登录逻辑
83
+ }
84
+ }
85
+ ```
86
+
87
+ ### 2. 面向接口编程
88
+
89
+ 项目强调使用接口来定义契约,实现松耦合:
90
+
91
+ #### 接口定义
92
+
93
+ ```typescript
94
+ // 定义接口契约
95
+ interface StorageInterface<T> {
96
+ get(key: string): T | null;
97
+ set(key: string, value: T): void;
98
+ remove(key: string): void;
99
+ clear(): void;
100
+ }
101
+
102
+ // 实现接口
103
+ class LocalStorage<T> implements StorageInterface<T> {
104
+ get(key: string): T | null {
105
+ const value = localStorage.getItem(key);
106
+ return value ? JSON.parse(value) : null;
107
+ }
108
+
109
+ set(key: string, value: T): void {
110
+ localStorage.setItem(key, JSON.stringify(value));
111
+ }
112
+
113
+ remove(key: string): void {
114
+ localStorage.removeItem(key);
115
+ }
116
+
117
+ clear(): void {
118
+ localStorage.clear();
119
+ }
120
+ }
121
+ ```
122
+
123
+ #### 依赖注入
124
+
125
+ ```typescript
126
+ // 服务接口
127
+ interface UserServiceInterface {
128
+ getCurrentUser(): User | null;
129
+ updateProfile(data: UserProfile): Promise<void>;
130
+ }
131
+
132
+ // 服务实现
133
+ @injectable()
134
+ class UserService implements UserServiceInterface {
135
+ constructor(
136
+ @inject('StorageService') private storage: StorageInterface<User>,
137
+ @inject('ApiService') private api: ApiInterface
138
+ ) {}
139
+
140
+ getCurrentUser(): User | null {
141
+ return this.storage.get('currentUser');
142
+ }
143
+
144
+ async updateProfile(data: UserProfile): Promise<void> {
145
+ await this.api.put('/user/profile', data);
146
+ }
147
+ }
148
+ ```
149
+
150
+ ### 3. 面向配置编程
151
+
152
+ 项目采用配置驱动的方式来管理功能特性:
153
+
154
+ #### 配置定义
155
+
156
+ ```typescript
157
+ // 配置接口
158
+ interface AppConfig {
159
+ api: {
160
+ baseUrl: string;
161
+ timeout: number;
162
+ retries: number;
163
+ };
164
+ auth: {
165
+ tokenKey: string;
166
+ tokenPrefix: string;
167
+ expiresIn: number;
168
+ };
169
+ theme: {
170
+ defaultTheme: 'light' | 'dark';
171
+ enableUserTheme: boolean;
172
+ };
173
+ }
174
+
175
+ // 配置实现
176
+ const appConfig: AppConfig = {
177
+ api: {
178
+ baseUrl: process.env.API_BASE_URL || '/api',
179
+ timeout: 5000,
180
+ retries: 3
181
+ },
182
+ auth: {
183
+ tokenKey: 'auth_token',
184
+ tokenPrefix: 'Bearer',
185
+ expiresIn: 7200
186
+ },
187
+ theme: {
188
+ defaultTheme: 'light',
189
+ enableUserTheme: true
190
+ }
191
+ };
192
+ ```
193
+
194
+ #### 配置驱动
195
+
196
+ ```typescript
197
+ // 配置驱动的功能实现
198
+ @injectable()
199
+ class ApiService {
200
+ constructor(
201
+ @inject('AppConfig') private config: AppConfig,
202
+ @inject('HttpClient') private http: HttpClient
203
+ ) {
204
+ // 使用配置初始化服务
205
+ this.http.setBaseUrl(config.api.baseUrl);
206
+ this.http.setTimeout(config.api.timeout);
207
+ }
208
+
209
+ async request<T>(options: RequestOptions): Promise<T> {
210
+ let retries = this.config.api.retries;
211
+
212
+ while (retries > 0) {
213
+ try {
214
+ return await this.http.request(options);
215
+ } catch (error) {
216
+ retries--;
217
+ if (retries === 0) throw error;
218
+ }
219
+ }
220
+ }
221
+ }
222
+ ```
223
+
224
+ ## 类型系统使用
225
+
226
+ ### 1. 泛型
227
+
228
+ ```typescript
229
+ // 泛型接口
230
+ interface Repository<T> {
231
+ findById(id: string): Promise<T>;
232
+ findAll(): Promise<T[]>;
233
+ create(data: Omit<T, 'id'>): Promise<T>;
234
+ update(id: string, data: Partial<T>): Promise<T>;
235
+ }
236
+
237
+ // 泛型类
238
+ class ApiRepository<T> implements Repository<T> {
239
+ constructor(private endpoint: string) {}
240
+
241
+ async findById(id: string): Promise<T> {
242
+ return api.get(`${this.endpoint}/${id}`);
243
+ }
244
+
245
+ // ... 其他方法实现
246
+ }
247
+ ```
248
+
249
+ ### 2. 类型工具
250
+
251
+ ```typescript
252
+ // 类型映射
253
+ type Nullable<T> = { [P in keyof T]: T[P] | null };
254
+
255
+ // 条件类型
256
+ type ArrayType<T> = T extends Array<infer U> ? U : never;
257
+
258
+ // 工具类型
259
+ type PartialDeep<T> = {
260
+ [P in keyof T]?: T[P] extends object ? PartialDeep<T[P]> : T[P];
261
+ };
262
+ ```
263
+
264
+ ### 3. 装饰器
265
+
266
+ ```typescript
267
+ // 方法装饰器
268
+ function Cached(ttl: number = 3600) {
269
+ return function (
270
+ target: any,
271
+ propertyKey: string,
272
+ descriptor: PropertyDescriptor
273
+ ) {
274
+ const original = descriptor.value;
275
+ const cache = new Map();
276
+
277
+ descriptor.value = async function (...args: any[]) {
278
+ const key = JSON.stringify(args);
279
+ if (cache.has(key)) {
280
+ const { value, timestamp } = cache.get(key);
281
+ if (Date.now() - timestamp < ttl * 1000) {
282
+ return value;
283
+ }
284
+ }
285
+
286
+ const result = await original.apply(this, args);
287
+ cache.set(key, { value: result, timestamp: Date.now() });
288
+ return result;
289
+ };
290
+ };
291
+ }
292
+
293
+ // 使用装饰器
294
+ class UserService {
295
+ @Cached(1800)
296
+ async getUserProfile(id: string): Promise<UserProfile> {
297
+ return this.api.get(`/users/${id}`);
298
+ }
299
+ }
300
+ ```
301
+
302
+ ## 最佳实践
303
+
304
+ ### 1. 类型定义
305
+
306
+ - 使用 interface 定义对象结构
307
+ - 使用 type 定义联合类型和工具类型
308
+ - 优先使用 readonly 确保不可变性
309
+ - 合理使用可选属性
310
+
311
+ ```typescript
312
+ // 好的实践
313
+ interface UserProfile {
314
+ readonly id: string;
315
+ name: string;
316
+ email: string;
317
+ avatar?: string;
318
+ preferences: Readonly<UserPreferences>;
319
+ }
320
+
321
+ // 避免的实践
322
+ interface BadUserProfile {
323
+ [key: string]: any; // 避免使用索引签名
324
+ data: any; // 避免使用 any
325
+ }
326
+ ```
327
+
328
+ ### 2. 错误处理
329
+
330
+ ```typescript
331
+ // 自定义错误类
332
+ class ApiError extends Error {
333
+ constructor(
334
+ public code: string,
335
+ message: string,
336
+ public data?: any
337
+ ) {
338
+ super(message);
339
+ this.name = 'ApiError';
340
+ }
341
+ }
342
+
343
+ // 类型守卫
344
+ function isApiError(error: unknown): error is ApiError {
345
+ return error instanceof ApiError;
346
+ }
347
+
348
+ // 错误处理
349
+ try {
350
+ await api.request();
351
+ } catch (error) {
352
+ if (isApiError(error)) {
353
+ handleApiError(error);
354
+ } else {
355
+ handleUnknownError(error);
356
+ }
357
+ }
358
+ ```
359
+
360
+ ### 3. 异步处理
361
+
362
+ ```typescript
363
+ // 异步结果类型
364
+ interface AsyncResult<T, E = Error> {
365
+ data: T | null;
366
+ error: E | null;
367
+ loading: boolean;
368
+ }
369
+
370
+ // 异步操作包装器
371
+ async function asyncWrapper<T, E = Error>(
372
+ promise: Promise<T>
373
+ ): Promise<AsyncResult<T, E>> {
374
+ try {
375
+ const data = await promise;
376
+ return { data, error: null, loading: false };
377
+ } catch (error) {
378
+ return { data: null, error: error as E, loading: false };
379
+ }
380
+ }
381
+ ```
382
+
383
+ ## 开发工具配置
384
+
385
+ ### 1. TSConfig 配置
386
+
387
+ ```json
388
+ {
389
+ "compilerOptions": {
390
+ "target": "ES2020",
391
+ "module": "ESNext",
392
+ "strict": true,
393
+ "esModuleInterop": true,
394
+ "skipLibCheck": true,
395
+ "forceConsistentCasingInFileNames": true,
396
+ "experimentalDecorators": true,
397
+ "emitDecoratorMetadata": true
398
+ }
399
+ }
400
+ ```
401
+
402
+ ### 2. ESLint 配置
403
+
404
+ ```json
405
+ {
406
+ "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
407
+ "rules": {
408
+ "@typescript-eslint/explicit-function-return-type": "error",
409
+ "@typescript-eslint/no-explicit-any": "error",
410
+ "@typescript-eslint/no-unused-vars": "error"
411
+ }
412
+ }
413
+ ```
414
+
415
+ ## 调试技巧
416
+
417
+ ### 1. 类型断言
418
+
419
+ ```typescript
420
+ // 类型断言
421
+ function processValue(value: unknown) {
422
+ if (typeof value === 'string') {
423
+ return value.toUpperCase();
424
+ }
425
+ return String(value);
426
+ }
427
+
428
+ // 类型收窄
429
+ function isString(value: unknown): value is string {
430
+ return typeof value === 'string';
431
+ }
432
+ ```
433
+
434
+ ### 2. 调试工具
435
+
436
+ ```typescript
437
+ // 类型检查
438
+ type Debug<T> = {
439
+ [P in keyof T]: T[P];
440
+ };
441
+
442
+ // 运行时类型检查
443
+ function assertType<T>(value: unknown, message?: string): asserts value is T {
444
+ if (!isValidType<T>(value)) {
445
+ throw new TypeError(message || 'Type assertion failed');
446
+ }
447
+ }
448
+ ```
449
+
450
+ ## 性能优化
451
+
452
+ ### 1. 类型优化
453
+
454
+ ```typescript
455
+ // 使用类型缓存
456
+ type CachedType<T> = T extends Function ? T : Readonly<T>;
457
+
458
+ // 避免过度使用泛型
459
+ type SimpleType = string | number;
460
+ type ComplexType<T> = T extends SimpleType ? T : never;
461
+ ```
462
+
463
+ ### 2. 编译优化
464
+
465
+ - 使用 project references
466
+ - 启用增量编译
467
+ - 优化类型导入
468
+
469
+ ## 参考资源
470
+
471
+ - [TypeScript 官方文档](https://www.typescriptlang.org/docs/)
472
+ - [TypeScript 设计模式](https://refactoring.guru/design-patterns/typescript)
473
+ - [Clean Code TypeScript](https://github.com/labs42io/clean-code-typescript)
@@ -46,9 +46,9 @@
46
46
  "dev": "vite --mode localhost",
47
47
  "dev:staging": "vite --mode staging",
48
48
  "dev:prod": "vite --mode production",
49
- "build": "vite build",
49
+ "build": "npm run lint && vite build",
50
50
  "lint": "tsc -b --noEmit && eslint ./src --fix",
51
- "prettier": "prettier --write ./src",
51
+ "prettier": "prettier --write ./src ./docs ./config",
52
52
  "preview": "vite preview",
53
53
  "test": "vitest run"
54
54
  },
@@ -8,11 +8,11 @@ import {
8
8
  RequestCommonPlugin
9
9
  } from '@qlover/corekit-bridge';
10
10
  import { RequestLogger } from '../cases/RequestLogger';
11
- import { IOCIdentifier } from '@/core/IOC';
12
- import { appConfig } from '@/core/globals';
11
+ import { IOCIdentifier } from '@config/IOCIdentifier';
12
+ import type { AppConfig } from '../cases/AppConfig';
13
13
 
14
14
  const apiApiAdapter = new RequestAdapterFetch({
15
- baseURL: appConfig.aiApiBaseUrl
15
+ responseType: 'json'
16
16
  });
17
17
 
18
18
  // 使用 RequestScheduler
@@ -24,6 +24,11 @@ const apiApi = new RequestScheduler(apiApiAdapter);
24
24
  export const AiApiBootstarp: BootstrapExecutorPlugin = {
25
25
  pluginName: 'AiApiBootstarp',
26
26
  onBefore({ parameters: { ioc } }) {
27
+ const appConfig = ioc.get<AppConfig>(IOCIdentifier.AppConfig);
28
+
29
+ // dynamic set baseURL
30
+ apiApiAdapter.config.baseURL = appConfig.aiApiBaseUrl;
31
+
27
32
  apiApiAdapter.usePlugin(new FetchURLPlugin());
28
33
  apiApiAdapter.usePlugin(
29
34
  new RequestCommonPlugin({
@@ -40,13 +45,13 @@ export function aiHello(data: {
40
45
  messages: { role: string; content: string }[];
41
46
  }) {
42
47
  return apiApi.request<
43
- typeof data,
44
48
  {
45
49
  id: string;
46
50
  object: string;
47
51
  created: number;
48
52
  choices: { message: { role: string; content: string } }[];
49
- }
53
+ },
54
+ typeof data
50
55
  >({
51
56
  url: '/chat/completions',
52
57
  method: 'POST',
@@ -1,5 +1,5 @@
1
1
  import type { AppConfig } from '@/base/cases/AppConfig';
2
- import { IOCIdentifier } from '@/core/IOC';
2
+ import { IOCIdentifier } from '@config/IOCIdentifier';
3
3
  import { RequestAdapterFetch } from '@qlover/fe-corekit';
4
4
  import { inject, injectable } from 'inversify';
5
5
 
@@ -11,7 +11,7 @@ import {
11
11
  ApiPickDataPlugin
12
12
  } from '@qlover/corekit-bridge';
13
13
  import { FeApi } from './FeApi';
14
- import { IOCIdentifier } from '@/core/IOC';
14
+ import { IOCIdentifier } from '@config/IOCIdentifier';
15
15
  import { RequestLogger } from '@/base/cases/RequestLogger';
16
16
 
17
17
  /**
@@ -7,26 +7,21 @@ import {
7
7
  GetIpInfoTransaction,
8
8
  UserApiGetUserInfoTransaction,
9
9
  UserApiLoginTransaction,
10
- UserApiTestApiCatchResultTransaction
10
+ UserApiTestApiCatchResultTransaction,
11
+ UserInfo
11
12
  } from './UserApiType';
12
13
  import { inject, injectable } from 'inversify';
13
14
  import { UserApiAdapter } from './UserApiAdapter';
14
15
  import { UserApiConfig } from './UserApiBootstarp';
15
- import {
16
+ import type {
16
17
  LoginResponseData,
17
18
  UserAuthApiInterface,
18
- UserAuthStoreInterface,
19
- UserAuthState
19
+ UserAuthStoreInterface
20
20
  } from '@qlover/corekit-bridge';
21
- import {
22
- RegisterFormData,
23
- UserServiceUserInfo
24
- } from '@/base/services/UserService';
21
+ import { RegisterFormData } from '@/base/services/UserService';
25
22
  import { RES_NO_TOKEN } from '@config/Identifier';
26
23
  import { AppError } from '@/base/cases/AppError';
27
24
 
28
- export type UserApiState = UserAuthState<UserServiceUserInfo>;
29
-
30
25
  /**
31
26
  * UserApi
32
27
  *
@@ -37,9 +32,9 @@ export type UserApiState = UserAuthState<UserServiceUserInfo>;
37
32
  @injectable()
38
33
  export class UserApi
39
34
  extends RequestTransaction<UserApiConfig>
40
- implements UserAuthApiInterface<UserApiState>
35
+ implements UserAuthApiInterface<UserInfo>
41
36
  {
42
- protected store: UserAuthStoreInterface<UserApiState> | null = null;
37
+ protected store: UserAuthStoreInterface<UserInfo> | null = null;
43
38
 
44
39
  constructor(
45
40
  @inject(FetchAbortPlugin) private abortPlugin: FetchAbortPlugin,
@@ -48,7 +43,7 @@ export class UserApi
48
43
  super(adapter);
49
44
  }
50
45
 
51
- getStore(): UserAuthStoreInterface<UserApiState> | null {
46
+ getStore(): UserAuthStoreInterface<UserInfo> | null {
52
47
  return this.store;
53
48
  }
54
49
 
@@ -56,7 +51,7 @@ export class UserApi
56
51
  * @override
57
52
  * @param store
58
53
  */
59
- setStore(store: UserAuthStoreInterface<UserApiState>): void {
54
+ setStore(store: UserAuthStoreInterface<UserInfo>): void {
60
55
  this.store = store;
61
56
  }
62
57
 
@@ -130,9 +125,7 @@ export class UserApi
130
125
  * @override
131
126
  * @returns
132
127
  */
133
- async getUserInfo(): Promise<
134
- UserApiGetUserInfoTransaction['response']['data']
135
- > {
128
+ async getUserInfo(): Promise<UserInfo> {
136
129
  const response =
137
130
  await this.get<UserApiGetUserInfoTransaction>('/api/userinfo');
138
131
 
@@ -1,5 +1,5 @@
1
1
  import type { AppConfig } from '@/base/cases/AppConfig';
2
- import { IOCIdentifier } from '@/core/IOC';
2
+ import { IOCIdentifier } from '@config/IOCIdentifier';
3
3
  import { RequestAdapterFetch } from '@qlover/fe-corekit';
4
4
  import { inject, injectable } from 'inversify';
5
5
 
@@ -4,7 +4,8 @@ import {
4
4
  RequestAdapterResponse,
5
5
  RequestTransactionInterface
6
6
  } from '@qlover/fe-corekit';
7
- import { IOC, IOCIdentifier } from '@/core/IOC';
7
+ import { IOC } from '@/core/IOC';
8
+ import { IOCIdentifier } from '@config/IOCIdentifier';
8
9
  import { RequestLogger } from '@/base/cases/RequestLogger';
9
10
  import { FetchURLPlugin } from '@qlover/fe-corekit';
10
11
  import {
@@ -1,5 +1,11 @@
1
1
  import { UserApiTransaction } from './UserApiBootstarp';
2
2
 
3
+ export type UserInfo = {
4
+ name: string;
5
+ email: string;
6
+ picture: string;
7
+ };
8
+
3
9
  export type GetIpInfoTransaction = UserApiTransaction<
4
10
  undefined,
5
11
  {
@@ -35,11 +41,7 @@ export type UserApiGetRandomUser = UserApiTransaction<
35
41
 
36
42
  export type UserApiGetUserInfoTransaction = UserApiTransaction<
37
43
  string,
38
- {
39
- name: string;
40
- email: string;
41
- picture: string;
42
- }
44
+ UserInfo
43
45
  >;
44
46
 
45
47
  export type UserApiLoginTransaction = UserApiTransaction<
@@ -1,14 +1,15 @@
1
1
  import type { ExecutorContext, ExecutorPlugin } from '@qlover/fe-corekit';
2
2
  import type { LoggerInterface } from '@qlover/logger';
3
- import { inject } from 'inversify';
3
+ import { inject, injectable } from 'inversify';
4
4
  import { I18nService } from '../services/I18nService';
5
- import { IOCIdentifier } from '@/core/IOC';
5
+ import { IOCIdentifier } from '@config/IOCIdentifier';
6
6
 
7
7
  /**
8
8
  * When throw error, it will be converted to i18n key
9
9
  *
10
10
  * If the error thrown is an i18n key, it will be converted to the corresponding text
11
11
  */
12
+ @injectable()
12
13
  export class I18nKeyErrorPlugin implements ExecutorPlugin {
13
14
  readonly pluginName = 'I18nKeyErrorPlugin';
14
15