@qlover/create-app 0.7.9 → 0.7.10
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.
- package/CHANGELOG.md +110 -0
- package/dist/index.cjs +3 -3
- package/dist/index.js +3 -3
- package/dist/templates/next-app/.env.template +8 -4
- package/dist/templates/next-app/config/IOCIdentifier.ts +4 -1
- package/dist/templates/next-app/config/Identifier/api.ts +20 -0
- package/dist/templates/next-app/config/Identifier/index.ts +2 -0
- package/dist/templates/next-app/config/Identifier/page.login.ts +2 -2
- package/dist/templates/next-app/config/Identifier/page.register.ts +43 -22
- package/dist/templates/next-app/config/Identifier/validator.ts +34 -0
- package/dist/templates/next-app/config/i18n/index.ts +1 -0
- package/dist/templates/next-app/config/i18n/register18n.ts +44 -0
- package/dist/templates/next-app/migrations/schema/UserSchema.ts +13 -0
- package/dist/templates/next-app/migrations/sql/1694244000000.sql +10 -0
- package/dist/templates/next-app/package.json +11 -2
- package/dist/templates/next-app/public/locales/en.json +16 -2
- package/dist/templates/next-app/public/locales/zh.json +16 -2
- package/dist/templates/next-app/src/app/[locale]/admin/layout.tsx +21 -0
- package/dist/templates/next-app/src/app/[locale]/admin/page.tsx +10 -0
- package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +25 -5
- package/dist/templates/next-app/src/app/[locale]/login/page.tsx +6 -4
- package/dist/templates/next-app/src/app/[locale]/page.tsx +3 -3
- package/dist/templates/next-app/src/app/[locale]/register/RegisterForm.tsx +176 -0
- package/dist/templates/next-app/src/app/[locale]/register/page.tsx +79 -0
- package/dist/templates/next-app/src/app/api/user/login/route.ts +50 -0
- package/dist/templates/next-app/src/app/api/user/logout/route.ts +27 -0
- package/dist/templates/next-app/src/app/api/user/register/route.ts +50 -0
- package/dist/templates/next-app/src/base/cases/AppConfig.ts +19 -0
- package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +35 -0
- package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +70 -0
- package/dist/templates/next-app/src/base/cases/RouterService.ts +4 -0
- package/dist/templates/next-app/src/base/cases/StringEncryptor.ts +67 -0
- package/dist/templates/next-app/src/base/cases/UserServiceApi.ts +48 -0
- package/dist/templates/next-app/src/base/port/AppApiInterface.ts +14 -0
- package/dist/templates/next-app/src/base/port/AppUserApiInterface.ts +15 -0
- package/dist/templates/next-app/src/base/port/DBBridgeInterface.ts +18 -0
- package/dist/templates/next-app/src/base/port/DBMigrationInterface.ts +92 -0
- package/dist/templates/next-app/src/base/port/DBTableInterface.ts +3 -0
- package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +3 -2
- package/dist/templates/next-app/src/base/port/MigrationApiInterface.ts +3 -0
- package/dist/templates/next-app/src/base/port/ServerApiResponseInterface.ts +6 -0
- package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +3 -2
- package/dist/templates/next-app/src/base/services/I18nService.ts +9 -45
- package/dist/templates/next-app/src/base/services/UserService.ts +9 -8
- package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +63 -0
- package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +72 -0
- package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +48 -0
- package/dist/templates/next-app/src/base/services/appApi/AppUserType.ts +51 -0
- package/dist/templates/next-app/src/base/services/migrations/MigrationsApi.ts +43 -0
- package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +30 -5
- package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +4 -3
- package/dist/templates/next-app/src/server/AppErrorApi.ts +10 -0
- package/dist/templates/next-app/src/server/AppSuccessApi.ts +7 -0
- package/dist/templates/next-app/src/server/PasswordEncrypt.ts +12 -0
- package/dist/templates/next-app/src/server/ServerAuth.ts +50 -0
- package/dist/templates/next-app/src/server/SupabaseBridge.ts +124 -0
- package/dist/templates/next-app/src/server/UserCredentialToken.ts +49 -0
- package/dist/templates/next-app/src/server/port/CrentialTokenInterface.ts +5 -0
- package/dist/templates/next-app/src/server/port/ServerInterface.ts +22 -0
- package/dist/templates/next-app/src/server/port/UserAuthInterface.ts +9 -0
- package/dist/templates/next-app/src/server/port/UserRepositoryInterface.ts +15 -0
- package/dist/templates/next-app/src/server/port/UserServiceInterface.ts +8 -0
- package/dist/templates/next-app/src/server/port/ValidatorInterface.ts +23 -0
- package/dist/templates/next-app/src/server/repositorys/UserRepository.ts +63 -0
- package/dist/templates/next-app/src/server/services/UserService.ts +105 -0
- package/dist/templates/next-app/src/server/validators/LoginValidator.ts +79 -0
- package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +1 -1
- package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +8 -1
- package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +20 -10
- package/dist/templates/next-app/tsconfig.json +3 -1
- package/package.json +2 -2
- package/dist/templates/next-app/src/base/cases/ServerAuth.ts +0 -17
- package/dist/templates/next-app/src/base/port/ServerAuthInterface.ts +0 -3
- package/dist/templates/next-app/src/base/port/ServerInterface.ts +0 -12
- /package/dist/templates/next-app/src/{app/[locale]/login → uikit/components}/FeatureItem.tsx +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PostgrestSingleResponse } from '@supabase/supabase-js';
|
|
2
|
+
|
|
3
|
+
export type WhereOperation = '=' | '!=' | '>' | '<' | '>=' | '<=';
|
|
4
|
+
export type Where = [string, WhereOperation, string | number];
|
|
5
|
+
|
|
6
|
+
export interface BridgeEvent {
|
|
7
|
+
table: string;
|
|
8
|
+
fields?: string | string[];
|
|
9
|
+
where?: Where[];
|
|
10
|
+
data?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DBBridgeInterface {
|
|
14
|
+
add(event: BridgeEvent): Promise<PostgrestSingleResponse<unknown>>;
|
|
15
|
+
update(event: BridgeEvent): Promise<PostgrestSingleResponse<unknown>>;
|
|
16
|
+
delete(event: BridgeEvent): Promise<PostgrestSingleResponse<unknown>>;
|
|
17
|
+
get(event: BridgeEvent): Promise<PostgrestSingleResponse<unknown>>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export interface MigrationConfig {
|
|
2
|
+
/**
|
|
3
|
+
* Migration version number or identifier
|
|
4
|
+
*/
|
|
5
|
+
version: string | number;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Description of what this migration does
|
|
9
|
+
*/
|
|
10
|
+
description: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Timestamp when migration was created
|
|
14
|
+
*/
|
|
15
|
+
timestamp?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MigrationResult {
|
|
19
|
+
/**
|
|
20
|
+
* Whether the migration was successful
|
|
21
|
+
*/
|
|
22
|
+
success: boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Error message if migration failed
|
|
26
|
+
*/
|
|
27
|
+
error?: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Migration version that was executed
|
|
31
|
+
*/
|
|
32
|
+
version: string | number;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Time taken to execute the migration in milliseconds
|
|
36
|
+
*/
|
|
37
|
+
executionTime?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DBMigrationInterface {
|
|
41
|
+
/**
|
|
42
|
+
* Get current database version
|
|
43
|
+
*/
|
|
44
|
+
getCurrentVersion(): Promise<string | number>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get list of all applied migrations
|
|
48
|
+
*/
|
|
49
|
+
getAppliedMigrations(): Promise<MigrationConfig[]>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get list of pending migrations that need to be applied
|
|
53
|
+
*/
|
|
54
|
+
getPendingMigrations(): Promise<MigrationConfig[]>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Apply a specific migration
|
|
58
|
+
* @param migration Migration configuration
|
|
59
|
+
*/
|
|
60
|
+
applyMigration(migration: MigrationConfig): Promise<MigrationResult>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Rollback a specific migration
|
|
64
|
+
* @param migration Migration configuration
|
|
65
|
+
*/
|
|
66
|
+
rollbackMigration(migration: MigrationConfig): Promise<MigrationResult>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Apply all pending migrations
|
|
70
|
+
*/
|
|
71
|
+
migrateUp(): Promise<MigrationResult[]>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Rollback to a specific version
|
|
75
|
+
* @param targetVersion Version to rollback to
|
|
76
|
+
*/
|
|
77
|
+
migrateDown(targetVersion: string | number): Promise<MigrationResult[]>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create a new migration file/record
|
|
81
|
+
* @param name Name/description of the migration
|
|
82
|
+
*/
|
|
83
|
+
createMigration(name: string): Promise<MigrationConfig>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Validate migration history and database state
|
|
87
|
+
*/
|
|
88
|
+
validateMigrations(): Promise<{
|
|
89
|
+
valid: boolean;
|
|
90
|
+
errors?: string[];
|
|
91
|
+
}>;
|
|
92
|
+
}
|
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
StoreInterface,
|
|
3
3
|
type StoreStateInterface
|
|
4
4
|
} from '@qlover/corekit-bridge';
|
|
5
|
+
import type { Locale } from '@/i18n/routing';
|
|
5
6
|
import type { i18nConfig } from '@config/i18n';
|
|
6
7
|
|
|
7
8
|
export type SupportedLocale = (typeof i18nConfig.supportedLngs)[number];
|
|
8
9
|
export type SupportedNamespace = typeof i18nConfig.fallbackLng;
|
|
9
|
-
export type I18nServiceLocale =
|
|
10
|
+
export type I18nServiceLocale = Locale;
|
|
10
11
|
|
|
11
12
|
export class I18nServiceState implements StoreStateInterface {
|
|
12
13
|
loading: boolean = false;
|
|
@@ -16,7 +17,7 @@ export abstract class I18nServiceInterface
|
|
|
16
17
|
extends StoreInterface<I18nServiceState>
|
|
17
18
|
implements I18nServiceInterface
|
|
18
19
|
{
|
|
19
|
-
abstract t(key: string, params?: Record<string, unknown>):
|
|
20
|
+
abstract t(key: string, params?: Record<string, unknown>): string;
|
|
20
21
|
abstract changeLanguage(language: I18nServiceLocale): Promise<void>;
|
|
21
22
|
abstract changeLoading(loading: boolean): void;
|
|
22
23
|
abstract getCurrentLanguage(): Promise<I18nServiceLocale>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UserAuthService } from '@qlover/corekit-bridge';
|
|
2
|
+
import type { UserSchema } from '@migrations/schema/UserSchema';
|
|
2
3
|
import type { ExecutorPlugin } from '@qlover/fe-corekit';
|
|
3
4
|
|
|
4
5
|
export abstract class UserServiceInterface
|
|
5
|
-
extends
|
|
6
|
+
extends UserAuthService<UserSchema>
|
|
6
7
|
implements ExecutorPlugin
|
|
7
8
|
{
|
|
8
9
|
readonly pluginName = 'UserService';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useLocaleRoutes } from '@config/common';
|
|
2
1
|
import { i18nConfig } from '@config/i18n';
|
|
3
2
|
import {
|
|
4
3
|
I18nServiceInterface,
|
|
@@ -11,20 +10,13 @@ type TranslationFunction = ReturnType<typeof useTranslations>;
|
|
|
11
10
|
|
|
12
11
|
export class I18nService extends I18nServiceInterface {
|
|
13
12
|
readonly pluginName = 'I18nService';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
private translator: TranslationFunction | null = null;
|
|
13
|
+
protected pathname: string = '';
|
|
14
|
+
protected translator: TranslationFunction | null = null;
|
|
17
15
|
|
|
18
16
|
constructor() {
|
|
19
17
|
super(() => new I18nServiceState(i18nConfig.fallbackLng));
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
private async ensureInitialized(): Promise<void> {
|
|
23
|
-
if (!this.initialized) {
|
|
24
|
-
throw new Error('I18nService not initialized');
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
20
|
setPathname(pathname: string): void {
|
|
29
21
|
this.pathname = pathname;
|
|
30
22
|
}
|
|
@@ -36,44 +28,19 @@ export class I18nService extends I18nServiceInterface {
|
|
|
36
28
|
/**
|
|
37
29
|
* @override
|
|
38
30
|
*/
|
|
39
|
-
async onBefore(): Promise<void> {
|
|
40
|
-
if (this.initialized) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.initialized = true;
|
|
45
|
-
|
|
46
|
-
// 初始化语言状态
|
|
47
|
-
const currentLang = this.getCurrentLanguageFromPath();
|
|
48
|
-
if (this.isValidLanguage(currentLang)) {
|
|
49
|
-
this.emit({ ...this.state, language: currentLang });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private getCurrentLanguageFromPath(): string {
|
|
54
|
-
const paths = this.pathname.split('/');
|
|
55
|
-
|
|
56
|
-
for (const path of paths) {
|
|
57
|
-
if (this.isValidLanguage(path)) {
|
|
58
|
-
return path;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return i18nConfig.fallbackLng;
|
|
63
|
-
}
|
|
31
|
+
async onBefore(): Promise<void> {}
|
|
64
32
|
|
|
65
33
|
override async changeLanguage(language: I18nServiceLocale): Promise<void> {
|
|
66
34
|
try {
|
|
67
35
|
this.changeLoading(true);
|
|
68
|
-
await this.ensureInitialized();
|
|
69
36
|
|
|
70
37
|
// 在这里我们只需要更新状态,因为实际的语言切换会通过路由处理
|
|
71
38
|
this.emit({ ...this.state, language });
|
|
72
39
|
|
|
73
40
|
// 如果不使用本地化路由,则保存语言设置到本地存储
|
|
74
|
-
if (!useLocaleRoutes && typeof window !== 'undefined') {
|
|
75
|
-
|
|
76
|
-
}
|
|
41
|
+
// if (!useLocaleRoutes && typeof window !== 'undefined') {
|
|
42
|
+
// window.localStorage.setItem('i18nextLng', language);
|
|
43
|
+
// }
|
|
77
44
|
} finally {
|
|
78
45
|
this.changeLoading(false);
|
|
79
46
|
}
|
|
@@ -84,8 +51,7 @@ export class I18nService extends I18nServiceInterface {
|
|
|
84
51
|
}
|
|
85
52
|
|
|
86
53
|
override async getCurrentLanguage(): Promise<I18nServiceLocale> {
|
|
87
|
-
|
|
88
|
-
return this.getCurrentLanguageFromPath() as I18nServiceLocale;
|
|
54
|
+
return this.state.language;
|
|
89
55
|
}
|
|
90
56
|
|
|
91
57
|
override isValidLanguage(language: string): language is I18nServiceLocale {
|
|
@@ -96,12 +62,10 @@ export class I18nService extends I18nServiceInterface {
|
|
|
96
62
|
return [...i18nConfig.supportedLngs];
|
|
97
63
|
}
|
|
98
64
|
|
|
99
|
-
override
|
|
65
|
+
override t(
|
|
100
66
|
key: string,
|
|
101
67
|
params?: Record<string, string | number | Date>
|
|
102
|
-
):
|
|
103
|
-
await this.ensureInitialized();
|
|
104
|
-
|
|
68
|
+
): string {
|
|
105
69
|
if (!this.translator) {
|
|
106
70
|
return key;
|
|
107
71
|
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { CookieStorage } from '@qlover/corekit-bridge';
|
|
2
1
|
import { injectable, inject } from 'inversify';
|
|
3
2
|
import { AppConfig } from '../cases/AppConfig';
|
|
3
|
+
import { UserServiceApi } from '../cases/UserServiceApi';
|
|
4
4
|
import { UserServiceInterface } from '../port/UserServiceInterface';
|
|
5
|
+
import type { UserSchema } from '@migrations/schema/UserSchema';
|
|
6
|
+
import type { UserAuthApiInterface } from '@qlover/corekit-bridge';
|
|
5
7
|
|
|
6
8
|
@injectable()
|
|
7
9
|
export class UserService extends UserServiceInterface {
|
|
8
|
-
constructor(
|
|
9
|
-
|
|
10
|
+
constructor(
|
|
11
|
+
@inject(AppConfig) protected appConfig: AppConfig,
|
|
12
|
+
@inject(UserServiceApi) protected userApi: UserAuthApiInterface<UserSchema>
|
|
13
|
+
) {
|
|
14
|
+
super(userApi, {
|
|
10
15
|
credentialStorage: {
|
|
11
|
-
key: appConfig.userTokenKey
|
|
12
|
-
storage: new CookieStorage()
|
|
13
|
-
},
|
|
14
|
-
requestConfig: {
|
|
15
|
-
env: appConfig.env !== 'production' ? 'development' : 'production'
|
|
16
|
+
key: appConfig.userTokenKey
|
|
16
17
|
}
|
|
17
18
|
});
|
|
18
19
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExecutorError,
|
|
3
|
+
RequestError,
|
|
4
|
+
type ExecutorContext,
|
|
5
|
+
type ExecutorPlugin
|
|
6
|
+
} from '@qlover/fe-corekit';
|
|
7
|
+
import type { AppApiErrorInterface } from '@/base/port/AppApiInterface';
|
|
8
|
+
import type { UserApiConfig } from './AppUserType';
|
|
9
|
+
|
|
10
|
+
export class AppApiPlugin implements ExecutorPlugin {
|
|
11
|
+
readonly pluginName = 'AppApiPlugin';
|
|
12
|
+
|
|
13
|
+
isAppApiErrorInterface(value: unknown): value is AppApiErrorInterface {
|
|
14
|
+
return (
|
|
15
|
+
typeof value === 'object' &&
|
|
16
|
+
value !== null &&
|
|
17
|
+
'success' in value &&
|
|
18
|
+
value.success === false &&
|
|
19
|
+
'id' in value &&
|
|
20
|
+
typeof value.id === 'string'
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
onSuccess(context: ExecutorContext<unknown>): void | Promise<void> {
|
|
25
|
+
const response = context.returnValue;
|
|
26
|
+
|
|
27
|
+
if (this.isAppApiErrorInterface(response)) {
|
|
28
|
+
throw new Error(response.message || response.id);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async onError(
|
|
33
|
+
context: ExecutorContext<UserApiConfig>
|
|
34
|
+
): Promise<ExecutorError | void> {
|
|
35
|
+
const { error, parameters } = context;
|
|
36
|
+
|
|
37
|
+
if (error instanceof RequestError && parameters.responseType === 'json') {
|
|
38
|
+
// @ts-expect-error response is not defined in Error
|
|
39
|
+
let response = error?.response;
|
|
40
|
+
|
|
41
|
+
if (response instanceof Response) {
|
|
42
|
+
// clone the response to avoid mutating the original response
|
|
43
|
+
response = response.clone();
|
|
44
|
+
|
|
45
|
+
const json = await this.getResponseJson(response);
|
|
46
|
+
|
|
47
|
+
if (this.isAppApiErrorInterface(json)) {
|
|
48
|
+
const newError = new ExecutorError(json.message || json.id);
|
|
49
|
+
// context.error = newError;
|
|
50
|
+
return newError;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected async getResponseJson(response: Response): Promise<unknown> {
|
|
57
|
+
try {
|
|
58
|
+
return await response.json();
|
|
59
|
+
} catch {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FetchAbortPlugin,
|
|
3
|
+
RequestTransaction,
|
|
4
|
+
RequestAdapterFetch
|
|
5
|
+
} from '@qlover/fe-corekit';
|
|
6
|
+
import { inject, injectable } from 'inversify';
|
|
7
|
+
import type { AppApiResponse } from '@/base/port/AppApiInterface';
|
|
8
|
+
import type { AppUserApiInterface } from '@/base/port/AppUserApiInterface';
|
|
9
|
+
import type {
|
|
10
|
+
UserApiConfig,
|
|
11
|
+
UserApiLoginTransaction,
|
|
12
|
+
UserApiRegisterTransaction
|
|
13
|
+
} from './AppUserType';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* UserApi
|
|
17
|
+
*
|
|
18
|
+
* @description
|
|
19
|
+
* UserApi is a client for the user API.
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
@injectable()
|
|
23
|
+
export class AppUserApi
|
|
24
|
+
extends RequestTransaction<UserApiConfig>
|
|
25
|
+
implements AppUserApiInterface
|
|
26
|
+
{
|
|
27
|
+
constructor(
|
|
28
|
+
@inject(FetchAbortPlugin) protected abortPlugin: FetchAbortPlugin
|
|
29
|
+
) {
|
|
30
|
+
super(
|
|
31
|
+
new RequestAdapterFetch({
|
|
32
|
+
baseURL: '/api',
|
|
33
|
+
responseType: 'json'
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async login(
|
|
39
|
+
params: UserApiLoginTransaction['data']
|
|
40
|
+
): Promise<AppApiResponse<unknown>> {
|
|
41
|
+
const response = await this.request<UserApiLoginTransaction>({
|
|
42
|
+
url: '/user/login',
|
|
43
|
+
method: 'POST',
|
|
44
|
+
data: params,
|
|
45
|
+
encryptProps: 'password'
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return response.data;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async register(
|
|
52
|
+
params: UserApiRegisterTransaction['data']
|
|
53
|
+
): Promise<AppApiResponse<unknown>> {
|
|
54
|
+
const response = await this.request<UserApiRegisterTransaction>({
|
|
55
|
+
url: '/user/register',
|
|
56
|
+
method: 'POST',
|
|
57
|
+
data: params,
|
|
58
|
+
encryptProps: 'password'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return response.data;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async logout(): Promise<AppApiResponse<unknown>> {
|
|
65
|
+
const response = await this.request({
|
|
66
|
+
url: '/user/logout',
|
|
67
|
+
method: 'POST'
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return response.data as AppApiResponse<unknown>;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { RequestCommonPlugin } from '@qlover/corekit-bridge';
|
|
2
|
+
import { FetchURLPlugin } from '@qlover/fe-corekit';
|
|
3
|
+
import { DialogErrorPlugin } from '@/base/cases/DialogErrorPlugin';
|
|
4
|
+
import { RequestEncryptPlugin } from '@/base/cases/RequestEncryptPlugin';
|
|
5
|
+
import { StringEncryptor } from '@/base/cases/StringEncryptor';
|
|
6
|
+
import { AppApiPlugin } from './AppApiPlugin';
|
|
7
|
+
import { AppUserApi } from './AppUserApi';
|
|
8
|
+
import type { UserApiConfig } from './AppUserType';
|
|
9
|
+
import type {
|
|
10
|
+
BootstrapContext,
|
|
11
|
+
BootstrapExecutorPlugin
|
|
12
|
+
} from '@qlover/corekit-bridge';
|
|
13
|
+
import type { ExecutorContext, SerializerIneterface } from '@qlover/fe-corekit';
|
|
14
|
+
|
|
15
|
+
export class AppUserApiBootstrap implements BootstrapExecutorPlugin {
|
|
16
|
+
readonly pluginName = 'AppUserApiBootstrap';
|
|
17
|
+
|
|
18
|
+
constructor(protected serializer: SerializerIneterface) {}
|
|
19
|
+
|
|
20
|
+
onBefore({ parameters: { ioc } }: BootstrapContext): void | Promise<void> {
|
|
21
|
+
const appUserApi = ioc.get<AppUserApi>(AppUserApi);
|
|
22
|
+
|
|
23
|
+
appUserApi.usePlugin(new FetchURLPlugin());
|
|
24
|
+
appUserApi.usePlugin(new RequestEncryptPlugin(ioc.get(StringEncryptor)));
|
|
25
|
+
appUserApi.usePlugin(
|
|
26
|
+
new RequestCommonPlugin({
|
|
27
|
+
requestDataSerializer: this.requestDataSerializer.bind(this)
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
appUserApi.usePlugin(new AppApiPlugin());
|
|
31
|
+
appUserApi.usePlugin(ioc.get(DialogErrorPlugin));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected requestDataSerializer(
|
|
35
|
+
data: unknown,
|
|
36
|
+
context: ExecutorContext<UserApiConfig>
|
|
37
|
+
): unknown {
|
|
38
|
+
if (data instanceof FormData) {
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (context.parameters?.responseType === 'json') {
|
|
43
|
+
return this.serializer.serialize(data);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { RequestEncryptPluginProps } from '@/base/cases/RequestEncryptPlugin';
|
|
2
|
+
import type { AppApiResponse } from '@/base/port/AppApiInterface';
|
|
3
|
+
import type {
|
|
4
|
+
RequestAdapterConfig,
|
|
5
|
+
RequestAdapterResponse,
|
|
6
|
+
RequestTransactionInterface
|
|
7
|
+
} from '@qlover/fe-corekit';
|
|
8
|
+
|
|
9
|
+
export interface UserApiConfig<Request = unknown>
|
|
10
|
+
extends RequestAdapterConfig<Request>,
|
|
11
|
+
RequestEncryptPluginProps<Request> {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* UserApiResponse
|
|
15
|
+
*
|
|
16
|
+
* @description
|
|
17
|
+
* UserApiResponse is the response for the UserApi.
|
|
18
|
+
*
|
|
19
|
+
* extends:
|
|
20
|
+
* - RequestAdapterResponse<Request, Response>
|
|
21
|
+
*/
|
|
22
|
+
export type UserApiResponse<
|
|
23
|
+
Request = unknown,
|
|
24
|
+
Response = unknown
|
|
25
|
+
> = RequestAdapterResponse<Request, AppApiResponse<Response>>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* UserApi common transaction
|
|
29
|
+
*/
|
|
30
|
+
export interface UserApiTransaction<Request = unknown, Response = unknown>
|
|
31
|
+
extends RequestTransactionInterface<
|
|
32
|
+
UserApiConfig<Request>,
|
|
33
|
+
UserApiResponse<Request, Response>
|
|
34
|
+
> {
|
|
35
|
+
data: UserApiConfig<Request>['data'];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type UserApiLoginTransaction = UserApiTransaction<
|
|
39
|
+
{ email: string; password: string },
|
|
40
|
+
{
|
|
41
|
+
token: string;
|
|
42
|
+
}
|
|
43
|
+
>;
|
|
44
|
+
|
|
45
|
+
export type UserApiRegisterTransaction = UserApiTransaction<
|
|
46
|
+
{
|
|
47
|
+
email: string;
|
|
48
|
+
password: string;
|
|
49
|
+
},
|
|
50
|
+
UserApiTransaction['response']['data']
|
|
51
|
+
>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { RequestCommonPlugin } from '@qlover/corekit-bridge';
|
|
2
|
+
import {
|
|
3
|
+
FetchAbortPlugin,
|
|
4
|
+
RequestTransaction,
|
|
5
|
+
RequestAdapterFetch,
|
|
6
|
+
FetchURLPlugin
|
|
7
|
+
} from '@qlover/fe-corekit';
|
|
8
|
+
import { inject, injectable } from 'inversify';
|
|
9
|
+
import type { MigrationApiInterface } from '@/base/port/MigrationApiInterface';
|
|
10
|
+
import type { RequestAdapterConfig } from '@qlover/fe-corekit';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* UserApi
|
|
14
|
+
*
|
|
15
|
+
* @description
|
|
16
|
+
* UserApi is a client for the user API.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
@injectable()
|
|
20
|
+
export class MigrationsApi
|
|
21
|
+
extends RequestTransaction<RequestAdapterConfig>
|
|
22
|
+
implements MigrationApiInterface
|
|
23
|
+
{
|
|
24
|
+
constructor(
|
|
25
|
+
@inject(FetchAbortPlugin) protected abortPlugin: FetchAbortPlugin
|
|
26
|
+
) {
|
|
27
|
+
super(
|
|
28
|
+
new RequestAdapterFetch({
|
|
29
|
+
baseURL: '/api/admin/migrations',
|
|
30
|
+
responseType: 'json'
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
this.usePlugin(new FetchURLPlugin()).usePlugin(new RequestCommonPlugin());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async init(): Promise<unknown> {
|
|
38
|
+
return this.request({
|
|
39
|
+
url: '/init',
|
|
40
|
+
method: 'POST'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type ServiceIdentifier,
|
|
2
3
|
type BootstrapContextValue,
|
|
3
4
|
type BootstrapExecutorPlugin,
|
|
4
5
|
type IOCContainerInterface,
|
|
5
6
|
type IOCFunctionInterface,
|
|
6
7
|
type LoggerInterface
|
|
7
8
|
} from '@qlover/corekit-bridge';
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
AsyncExecutor,
|
|
11
|
+
type ExecutorError,
|
|
12
|
+
type PromiseTask,
|
|
13
|
+
type ExecutorPlugin
|
|
14
|
+
} from '@qlover/fe-corekit';
|
|
9
15
|
import { I, type IOCIdentifierMapServer } from '@config/IOCIdentifier';
|
|
10
|
-
import type { ServerInterface } from '@/
|
|
16
|
+
import type { ServerInterface } from '@/server/port/ServerInterface';
|
|
11
17
|
import { ServerIOC } from '../serverIoc/ServerIOC';
|
|
12
18
|
|
|
13
19
|
export interface BootstrapServerResult {
|
|
@@ -20,6 +26,12 @@ export interface BootstrapServerContextValue extends BootstrapContextValue {
|
|
|
20
26
|
messages: Record<string, string>;
|
|
21
27
|
}
|
|
22
28
|
|
|
29
|
+
interface BootstrapServerContext {
|
|
30
|
+
logger: LoggerInterface;
|
|
31
|
+
root: Record<string, unknown>;
|
|
32
|
+
IOC: IOCFunctionInterface<IOCIdentifierMapServer, IOCContainerInterface>;
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
export class BootstrapServer implements ServerInterface {
|
|
24
36
|
protected executor: AsyncExecutor;
|
|
25
37
|
protected root: Record<string, unknown> = {};
|
|
@@ -43,11 +55,12 @@ export class BootstrapServer implements ServerInterface {
|
|
|
43
55
|
getIOC<T extends keyof IOCIdentifierMapServer>(
|
|
44
56
|
identifier: T
|
|
45
57
|
): IOCIdentifierMapServer[T];
|
|
46
|
-
getIOC(
|
|
47
|
-
|
|
58
|
+
getIOC<T>(serviceIdentifier: ServiceIdentifier<T>): T;
|
|
59
|
+
getIOC<T extends keyof IOCIdentifierMapServer>(
|
|
60
|
+
identifier?: T
|
|
48
61
|
):
|
|
49
62
|
| IOCFunctionInterface<IOCIdentifierMapServer, IOCContainerInterface>
|
|
50
|
-
| IOCIdentifierMapServer[
|
|
63
|
+
| IOCIdentifierMapServer[T] {
|
|
51
64
|
if (identifier === undefined) {
|
|
52
65
|
return this.IOC;
|
|
53
66
|
}
|
|
@@ -75,4 +88,16 @@ export class BootstrapServer implements ServerInterface {
|
|
|
75
88
|
this.executor.use(plugin as ExecutorPlugin<unknown>);
|
|
76
89
|
return this;
|
|
77
90
|
}
|
|
91
|
+
|
|
92
|
+
execNoError<Result>(
|
|
93
|
+
task?: PromiseTask<Result, BootstrapServerContext>
|
|
94
|
+
): Promise<Result | ExecutorError> {
|
|
95
|
+
const context = {
|
|
96
|
+
logger: this.logger,
|
|
97
|
+
root: this.root,
|
|
98
|
+
IOC: this.IOC
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return this.executor.execNoError(context, task);
|
|
102
|
+
}
|
|
78
103
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
1
|
+
import { I, IOCIdentifier } from '@config/IOCIdentifier';
|
|
2
|
+
import { AppUserApiBootstrap } from '@/base/services/appApi/AppUserApiBootstrap';
|
|
2
3
|
import { IocIdentifierTest } from './IocIdentifierTest';
|
|
3
4
|
import { printBootstrap } from './PrintBootstrap';
|
|
4
5
|
import type { BootstrapAppArgs } from './BootstrapClient';
|
|
@@ -28,8 +29,8 @@ export class BootstrapsRegistry {
|
|
|
28
29
|
i18nService.setPathname(this.args.pathname);
|
|
29
30
|
|
|
30
31
|
const bootstrapList: BootstrapExecutorPlugin[] = [
|
|
31
|
-
i18nService
|
|
32
|
-
|
|
32
|
+
i18nService,
|
|
33
|
+
new AppUserApiBootstrap(IOC(I.JSONSerializer))
|
|
33
34
|
// new FeApiBootstarp(),
|
|
34
35
|
// AiApiBootstarp,
|
|
35
36
|
// IOC(IOCIdentifier.I18nKeyErrorPlugin)
|