@qlover/create-app 0.1.15 → 0.1.17
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 +39 -27
- package/bin/create-app.js +0 -0
- package/configs/_common/package.json.template +11 -1
- package/configs/react-app/eslint.config.js +70 -42
- package/dist/index.cjs +1 -3631
- package/dist/index.js +1 -3625
- package/package.json +8 -8
- package/templates/node-lib/package.json +1 -1
- package/templates/pack-app/package.json +1 -1
- package/templates/react-app/.env +1 -0
- package/templates/react-app/README.md +0 -1
- package/templates/react-app/config/ErrorIdentifier.ts +27 -0
- package/templates/react-app/config/app.router.json +9 -0
- package/templates/react-app/config/common.ts +12 -0
- package/templates/react-app/config/feapi.mock.json +15 -2
- package/templates/react-app/config/i18n.ts +3 -11
- package/templates/react-app/package.json +7 -4
- package/templates/react-app/public/locales/en/common.json +6 -2
- package/templates/react-app/public/locales/zh/common.json +6 -3
- package/templates/react-app/src/App.tsx +8 -8
- package/templates/react-app/src/base/apis/AiApi.ts +55 -0
- package/templates/react-app/src/base/apis/feApi/FeApi.ts +13 -44
- package/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +14 -0
- package/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +67 -0
- package/templates/react-app/src/base/apis/feApi/FeApiType.ts +2 -35
- package/templates/react-app/src/base/apis/userApi/UserApi.ts +64 -0
- package/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +14 -0
- package/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +75 -0
- package/templates/react-app/src/base/apis/userApi/UserApiType.ts +52 -0
- package/templates/react-app/src/base/cases/RequestLogger.ts +71 -0
- package/templates/react-app/src/base/cases/RequestStatusCatcher.ts +41 -0
- package/templates/react-app/src/base/cases/appError/AppError.ts +13 -0
- package/templates/react-app/{lib/router-loader/RouterLoader.ts → src/base/cases/router-loader/index.ts} +1 -1
- package/templates/react-app/src/base/port/ApiTransactionInterface.ts +7 -0
- package/templates/react-app/src/base/port/InversifyIocInterface.ts +1 -1
- package/templates/react-app/src/base/port/LoginInterface.ts +4 -0
- package/templates/react-app/src/base/port/RequestCatcherInterface.ts +12 -0
- package/templates/react-app/src/{services → base/services}/I18nService.ts +7 -2
- package/templates/react-app/src/{services/processer → base/services}/ProcesserService.ts +10 -11
- package/templates/react-app/src/base/types/Page.ts +1 -13
- package/templates/react-app/src/core/AppConfig.ts +14 -5
- package/templates/react-app/src/core/IOC.ts +77 -37
- package/templates/react-app/src/core/bootstrap.ts +38 -25
- package/templates/react-app/src/core/bootstraps/BootstrapApp.ts +7 -0
- package/templates/react-app/src/core/bootstraps/index.ts +12 -0
- package/templates/react-app/src/core/globals.ts +7 -10
- package/templates/react-app/src/core/registers/RegisterApi.ts +1 -52
- package/templates/react-app/src/core/registers/RegisterCommon.ts +44 -6
- package/templates/react-app/src/core/registers/RegisterControllers.ts +5 -34
- package/templates/react-app/src/core/registers/RegisterGlobals.ts +8 -2
- package/templates/react-app/src/core/registers/index.ts +2 -1
- package/templates/react-app/src/main.tsx +4 -1
- package/templates/react-app/src/pages/auth/Layout.tsx +4 -3
- package/templates/react-app/src/pages/auth/Login.tsx +5 -3
- package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +39 -0
- package/templates/react-app/src/pages/base/Executor.tsx +31 -10
- package/templates/react-app/src/pages/base/Home.tsx +58 -30
- package/templates/react-app/src/pages/base/JSONStorage.tsx +2 -4
- package/templates/react-app/src/pages/base/Request.tsx +318 -73
- package/templates/react-app/src/pages/base/components/BaseHeader.tsx +2 -2
- package/templates/react-app/src/{components → uikit/components}/RouterRenderComponent.tsx +1 -1
- package/templates/react-app/src/{components → uikit/components}/ThemeSwitcher.tsx +6 -6
- package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +6 -3
- package/templates/react-app/src/uikit/controllers/ExecutorController.ts +52 -22
- package/templates/react-app/src/uikit/controllers/JSONStorageController.ts +7 -3
- package/templates/react-app/src/uikit/controllers/RequestController.ts +65 -11
- package/templates/react-app/src/uikit/controllers/RouterController.ts +8 -7
- package/templates/react-app/src/uikit/controllers/UserController.ts +48 -54
- package/templates/react-app/src/uikit/hooks/useLanguageGuard.ts +1 -2
- package/templates/react-app/src/uikit/providers/ProcessProvider.tsx +4 -4
- package/templates/react-app/src/uikit/styles/css/index.css +1 -1
- package/templates/react-app/src/uikit/styles/css/page.css +1 -1
- package/templates/react-app/tailwind.config.js +2 -2
- package/templates/react-app/tsconfig.json +0 -1
- package/templates/react-app/tsconfig.node.json +1 -2
- package/templates/react-app/vite.config.ts +21 -26
- package/templates/react-app/.env.local +0 -24
- package/templates/react-app/lib/bootstrap/Bootstrap.ts +0 -36
- package/templates/react-app/lib/bootstrap/BootstrapExecutorPlugin.ts +0 -20
- package/templates/react-app/lib/bootstrap/IOCContainerInterface.ts +0 -33
- package/templates/react-app/lib/bootstrap/IOCManagerInterface.ts +0 -12
- package/templates/react-app/lib/bootstrap/index.ts +0 -7
- package/templates/react-app/lib/bootstrap/plugins/InjectEnv.ts +0 -61
- package/templates/react-app/lib/bootstrap/plugins/InjectGlobal.ts +0 -36
- package/templates/react-app/lib/bootstrap/plugins/InjectIOC.ts +0 -24
- package/templates/react-app/lib/env-config/injectPkgConfig.ts +0 -11
- package/templates/react-app/lib/fe-react-controller/FeController.ts +0 -19
- package/templates/react-app/lib/fe-react-controller/index.ts +0 -2
- package/templates/react-app/lib/fe-react-controller/useController.ts +0 -71
- package/templates/react-app/lib/fe-react-theme/ThemeController.ts +0 -40
- package/templates/react-app/lib/fe-react-theme/ThemeStateGetter.ts +0 -53
- package/templates/react-app/lib/fe-react-theme/index.ts +0 -3
- package/templates/react-app/lib/fe-react-theme/type.ts +0 -21
- package/templates/react-app/lib/openAiApi/OpenAIAuthPlugin.ts +0 -29
- package/templates/react-app/lib/openAiApi/OpenAIClient.ts +0 -51
- package/templates/react-app/lib/openAiApi/StreamProcessor.ts +0 -81
- package/templates/react-app/lib/openAiApi/index.ts +0 -3
- package/templates/react-app/lib/request-common-plugin/index.ts +0 -169
- package/templates/react-app/lib/router-loader/Page.ts +0 -68
- package/templates/react-app/lib/tw-root10px/index.css +0 -4
- package/templates/react-app/pnpm-lock.yaml +0 -5892
- package/templates/react-app/src/base/apis/feApi/FeApiMockPlugin.ts +0 -44
- package/templates/react-app/src/base/apis/feApi/index.ts +0 -2
- package/templates/react-app/src/base/cases/UserToken.ts +0 -47
- package/templates/react-app/src/base/consts/IOCIdentifier.ts +0 -16
- package/templates/react-app/src/base/port/IOCFunctionInterface.ts +0 -39
- package/templates/react-app/src/base/port/StorageTokenInterface.ts +0 -27
- package/templates/react-app/src/core/AppIOCContainer.ts +0 -30
- package/templates/react-app/src/uikit/utils/RequestLogger.ts +0 -37
- package/templates/react-app/src/uikit/utils/datetime.ts +0 -30
- package/templates/react-app/src/uikit/utils/thread.ts +0 -3
- /package/templates/react-app/lib/{tw-root10px/index.js → tailwind/root10px.js} +0 -0
- /package/templates/react-app/lib/{fe-react-theme/tw-generator.js → tailwind/theme-generator.js} +0 -0
- /package/templates/react-app/src/{components → uikit/components}/Loading.tsx +0 -0
- /package/templates/react-app/src/{components → uikit/components}/LocaleLink.tsx +0 -0
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { ExecutorContext } from '@qlover/fe-utils';
|
|
2
|
-
import type {
|
|
3
|
-
BootstrapArgs,
|
|
4
|
-
BootstrapExecutorPlugin
|
|
5
|
-
} from '../BootstrapExecutorPlugin';
|
|
6
|
-
|
|
7
|
-
export class InjectGlobal implements BootstrapExecutorPlugin {
|
|
8
|
-
readonly pluginName = 'InjectGlobal';
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
11
|
-
private sources: Record<string, unknown>,
|
|
12
|
-
private target?: string | Record<string, unknown>
|
|
13
|
-
) {}
|
|
14
|
-
|
|
15
|
-
onBefore(context: ExecutorContext<BootstrapArgs>): void {
|
|
16
|
-
// if target is provided, inject globals to target
|
|
17
|
-
if (typeof this.target === 'string') {
|
|
18
|
-
Object.assign(context.parameters.root!, {
|
|
19
|
-
[this.target]: Object.freeze(Object.assign({}, this.sources))
|
|
20
|
-
});
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const target = this.target || context.parameters.root;
|
|
25
|
-
|
|
26
|
-
if (typeof target !== 'object' || target === null) {
|
|
27
|
-
throw new Error('target must be an object');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// inject globals to root
|
|
31
|
-
for (const key in this.sources) {
|
|
32
|
-
const element = this.sources[key];
|
|
33
|
-
Object.assign(target, { [key]: element });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { IOCRegisterInterface } from '../IOCContainerInterface';
|
|
2
|
-
import type { IOCManagerInterface } from '../IOCManagerInterface';
|
|
3
|
-
import type {
|
|
4
|
-
BootstrapContext,
|
|
5
|
-
BootstrapExecutorPlugin
|
|
6
|
-
} from '../BootstrapExecutorPlugin';
|
|
7
|
-
import { Container } from 'inversify';
|
|
8
|
-
|
|
9
|
-
export class InjectIOC implements BootstrapExecutorPlugin {
|
|
10
|
-
readonly pluginName = 'InjectIOC';
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
private IOC: IOCManagerInterface,
|
|
14
|
-
private registeres: IOCRegisterInterface<Container>[]
|
|
15
|
-
) {}
|
|
16
|
-
|
|
17
|
-
onBefore(context: BootstrapContext): void {
|
|
18
|
-
const { ioc } = context.parameters;
|
|
19
|
-
this.IOC.implement(ioc);
|
|
20
|
-
|
|
21
|
-
// maybe runtimes configure
|
|
22
|
-
ioc.configure(this.registeres);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { SliceStore } from '@qlover/slice-store-react';
|
|
2
|
-
|
|
3
|
-
export class FeController<T> extends SliceStore<T> {
|
|
4
|
-
constructor(private stateFactory: () => T) {
|
|
5
|
-
super(stateFactory);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
getState(): T {
|
|
9
|
-
return this.state;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
setState(state: Partial<T>): void {
|
|
13
|
-
this.emit({ ...this.state, ...state });
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
reset(): void {
|
|
17
|
-
this.emit(this.stateFactory());
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { useSliceStore } from '@qlover/slice-store-react';
|
|
2
|
-
import { FeController } from './FeController';
|
|
3
|
-
import { useEffect, useRef, useState } from 'react';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Hook for managing controller instances and their state.
|
|
7
|
-
* Change controller to UIController
|
|
8
|
-
* @param createController Factory function that creates a controller instance or controller instance
|
|
9
|
-
* @returns Controller instance with precise type inference
|
|
10
|
-
*/
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
-
export function useController<C extends FeController<any>>(
|
|
13
|
-
createController: (() => C) | C
|
|
14
|
-
): C {
|
|
15
|
-
const controllerRef = useRef<C | null>(null);
|
|
16
|
-
const [, forceUpdate] = useState(0);
|
|
17
|
-
|
|
18
|
-
if (!controllerRef.current) {
|
|
19
|
-
controllerRef.current =
|
|
20
|
-
typeof createController === 'function'
|
|
21
|
-
? createController()
|
|
22
|
-
: createController;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
const controller = controllerRef.current!;
|
|
27
|
-
|
|
28
|
-
const unsubscribe = controller.observe(() => {
|
|
29
|
-
forceUpdate((prev) => prev + 1);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
return () => {
|
|
33
|
-
unsubscribe();
|
|
34
|
-
};
|
|
35
|
-
}, []);
|
|
36
|
-
|
|
37
|
-
return controllerRef.current;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Create a Controller instance and cache it to avoid repeated creation
|
|
42
|
-
*
|
|
43
|
-
* @see https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useCreation/index.ts
|
|
44
|
-
* @param Controller
|
|
45
|
-
* @param args
|
|
46
|
-
* @returns
|
|
47
|
-
*/
|
|
48
|
-
export function useCreateController<
|
|
49
|
-
T,
|
|
50
|
-
Ctrl extends FeController<T>,
|
|
51
|
-
Args extends unknown[]
|
|
52
|
-
>(Controller: new (...args: Args) => Ctrl, ...args: Args): Ctrl {
|
|
53
|
-
const { current } = useRef({
|
|
54
|
-
target: undefined as undefined | Ctrl,
|
|
55
|
-
initialized: false
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
if (!current.initialized) {
|
|
59
|
-
current.target = new Controller(...args);
|
|
60
|
-
current.initialized = true;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return current.target as Ctrl;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function useControllerState<T, S = T>(
|
|
67
|
-
controller: FeController<T>,
|
|
68
|
-
selector?: (state: T) => S
|
|
69
|
-
): S {
|
|
70
|
-
return useSliceStore(controller, selector);
|
|
71
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { FeController } from '@lib/fe-react-controller';
|
|
2
|
-
import { ThemeControllerProps, ThemeControllerState } from './type';
|
|
3
|
-
import { ThemeStateGetter } from './ThemeStateGetter';
|
|
4
|
-
|
|
5
|
-
export class ThemeController extends FeController<ThemeControllerState> {
|
|
6
|
-
constructor(private props: ThemeControllerProps) {
|
|
7
|
-
super(() => ThemeStateGetter.create(props));
|
|
8
|
-
|
|
9
|
-
this.bindToTheme();
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
getSupportedThemes(): string[] {
|
|
13
|
-
return this.props.supportedThemes;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
bindToTheme(): void {
|
|
17
|
-
const { theme } = this.getState();
|
|
18
|
-
|
|
19
|
-
const { domAttribute } = this.props;
|
|
20
|
-
|
|
21
|
-
if (domAttribute) {
|
|
22
|
-
document.documentElement.setAttribute(domAttribute, theme);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
changeTheme(theme: string): void {
|
|
27
|
-
if (theme === ThemeStateGetter.SYSTEM_THEME) {
|
|
28
|
-
theme = ThemeStateGetter.getSystemTheme();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
this.setState({ theme });
|
|
32
|
-
|
|
33
|
-
const { storage, storageKey } = this.props;
|
|
34
|
-
if (storage && storageKey) {
|
|
35
|
-
storage.setItem(storageKey, theme);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
this.bindToTheme();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import isString from 'lodash/isString';
|
|
2
|
-
import { ThemeControllerProps, ThemeControllerState } from './type';
|
|
3
|
-
|
|
4
|
-
export class ThemeStateGetter {
|
|
5
|
-
static SYSTEM_THEME = 'system';
|
|
6
|
-
|
|
7
|
-
static create(props: ThemeControllerProps): ThemeControllerState {
|
|
8
|
-
const theme = ThemeStateGetter.getDefaultTheme(props);
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
theme
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static getDefaultTheme(props: ThemeControllerProps): string {
|
|
16
|
-
const { storage, storageKey, defaultTheme } = props;
|
|
17
|
-
|
|
18
|
-
let theme;
|
|
19
|
-
|
|
20
|
-
// Trying to use local storage
|
|
21
|
-
if (storage && storageKey) {
|
|
22
|
-
theme = storage.getItem(storageKey);
|
|
23
|
-
|
|
24
|
-
if (isString(theme) && props.supportedThemes.includes(theme)) {
|
|
25
|
-
return theme;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (theme === ThemeStateGetter.SYSTEM_THEME) {
|
|
30
|
-
return ThemeStateGetter.getSystemTheme();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// if local storage does not have theme, use system theme
|
|
34
|
-
if (defaultTheme) {
|
|
35
|
-
if (defaultTheme === ThemeStateGetter.SYSTEM_THEME) {
|
|
36
|
-
return ThemeStateGetter.getSystemTheme();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return defaultTheme;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return ThemeStateGetter.getSystemTheme();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
static getSystemTheme(): 'dark' | 'light' {
|
|
46
|
-
// use window.matchMedia to detect prefers-color-scheme media query
|
|
47
|
-
const isDarkMode =
|
|
48
|
-
window.matchMedia &&
|
|
49
|
-
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
50
|
-
|
|
51
|
-
return isDarkMode ? 'dark' : 'light';
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { JSONStorage } from '@qlover/fe-utils';
|
|
2
|
-
|
|
3
|
-
export type ThemeControllerState = {
|
|
4
|
-
theme: string;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export type ThemeConfig = {
|
|
8
|
-
domAttribute: string;
|
|
9
|
-
defaultTheme: string;
|
|
10
|
-
target: string;
|
|
11
|
-
supportedThemes: string[];
|
|
12
|
-
storageKey: string;
|
|
13
|
-
styleThemeKeyTemplate: string;
|
|
14
|
-
styleKeyTemplate: string;
|
|
15
|
-
colorsValueTemplate: string;
|
|
16
|
-
colors: Record<string, unknown>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export interface ThemeControllerProps extends ThemeConfig {
|
|
20
|
-
storage?: JSONStorage;
|
|
21
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ExecutorContext,
|
|
3
|
-
ExecutorPlugin,
|
|
4
|
-
RequestAdapterFetchConfig,
|
|
5
|
-
RequestAdapterResponse
|
|
6
|
-
} from '@qlover/fe-utils';
|
|
7
|
-
import { StreamProcessor } from './StreamProcessor';
|
|
8
|
-
|
|
9
|
-
export class OpenAIAuthPlugin
|
|
10
|
-
implements ExecutorPlugin<RequestAdapterFetchConfig>
|
|
11
|
-
{
|
|
12
|
-
readonly pluginName = 'OpenAIAuthPlugin';
|
|
13
|
-
|
|
14
|
-
async onSuccess(
|
|
15
|
-
context: ExecutorContext<RequestAdapterFetchConfig>
|
|
16
|
-
): Promise<void> {
|
|
17
|
-
const adapterResponse = context.returnValue as RequestAdapterResponse<
|
|
18
|
-
Request,
|
|
19
|
-
Response
|
|
20
|
-
>;
|
|
21
|
-
|
|
22
|
-
if (adapterResponse.data.body instanceof ReadableStream) {
|
|
23
|
-
const processer = new StreamProcessor();
|
|
24
|
-
const data = await processer.processStream(adapterResponse.data.body);
|
|
25
|
-
// overried response data
|
|
26
|
-
context.returnValue = data;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RequestScheduler,
|
|
3
|
-
RequestAdapterConfig,
|
|
4
|
-
RequestAdapterFetch,
|
|
5
|
-
RequestAdapterFetchConfig,
|
|
6
|
-
FetchURLPlugin,
|
|
7
|
-
RequestAdapterResponse
|
|
8
|
-
} from '@qlover/fe-utils';
|
|
9
|
-
import { StreamResultType } from './StreamProcessor';
|
|
10
|
-
import { OpenAIAuthPlugin } from './OpenAIAuthPlugin';
|
|
11
|
-
import {
|
|
12
|
-
RequestCommonPlugin,
|
|
13
|
-
RequestCommonPluginConfig
|
|
14
|
-
} from '@lib/request-common-plugin';
|
|
15
|
-
export interface ApiMessage {
|
|
16
|
-
content: string;
|
|
17
|
-
role: 'user' | 'system' | 'assistant';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface OpenAIChatParmas {
|
|
21
|
-
model?: string;
|
|
22
|
-
messages: ApiMessage[];
|
|
23
|
-
stream?: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export type OpenAIAargs = {
|
|
27
|
-
commonPluginConfig: RequestCommonPluginConfig;
|
|
28
|
-
models: string[];
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export type OpenAIClientConfig = Partial<RequestAdapterFetchConfig> &
|
|
32
|
-
OpenAIAargs;
|
|
33
|
-
|
|
34
|
-
export class OpenAIClient extends RequestScheduler<RequestAdapterConfig> {
|
|
35
|
-
constructor(config: OpenAIClientConfig) {
|
|
36
|
-
const { commonPluginConfig, ...rest } = config;
|
|
37
|
-
super(new RequestAdapterFetch(rest));
|
|
38
|
-
|
|
39
|
-
this.usePlugin(new FetchURLPlugin());
|
|
40
|
-
this.usePlugin(new RequestCommonPlugin(commonPluginConfig));
|
|
41
|
-
this.usePlugin(new OpenAIAuthPlugin());
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async completion(
|
|
45
|
-
params: OpenAIChatParmas
|
|
46
|
-
): Promise<RequestAdapterResponse<StreamResultType>> {
|
|
47
|
-
return this.post('/chat/completions', {
|
|
48
|
-
data: params
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
export type StreamResultType = {
|
|
2
|
-
content: string;
|
|
3
|
-
};
|
|
4
|
-
|
|
5
|
-
export class StreamProcessor {
|
|
6
|
-
private decoder = new TextDecoder('utf-8');
|
|
7
|
-
private buffer = '';
|
|
8
|
-
|
|
9
|
-
async processStream(
|
|
10
|
-
readableStream: ReadableStream<Uint8Array>
|
|
11
|
-
): Promise<StreamResultType> {
|
|
12
|
-
let fullContent = '';
|
|
13
|
-
|
|
14
|
-
const reader = readableStream.getReader();
|
|
15
|
-
|
|
16
|
-
const shouldStop = (result: ReadableStreamReadResult<any>): boolean => {
|
|
17
|
-
return result.done;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
while (true) {
|
|
22
|
-
const readResult = await reader.read();
|
|
23
|
-
if (shouldStop(readResult)) break;
|
|
24
|
-
|
|
25
|
-
const decodedChunk = this.decoder.decode(readResult.value, {
|
|
26
|
-
stream: true
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const processLineResult = await this.processChunk(decodedChunk);
|
|
30
|
-
|
|
31
|
-
fullContent += processLineResult.value;
|
|
32
|
-
|
|
33
|
-
if (processLineResult.done) break;
|
|
34
|
-
}
|
|
35
|
-
} finally {
|
|
36
|
-
reader.releaseLock();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
content: fullContent
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
processLine(line: string) {
|
|
45
|
-
const data = line.startsWith('data:') ? line.slice(6).trim() : '';
|
|
46
|
-
|
|
47
|
-
if (data === '[DONE]') {
|
|
48
|
-
return { done: true, value: '' };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const value = data ? JSON.parse(data).choices[0]?.delta?.content : '';
|
|
52
|
-
|
|
53
|
-
return { done: false, value: value };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async processChunk(chunk: string) {
|
|
57
|
-
let processedContent = '';
|
|
58
|
-
this.buffer += chunk;
|
|
59
|
-
const lines = this.buffer.split('\n');
|
|
60
|
-
this.buffer = lines.pop() || '';
|
|
61
|
-
for (const line of lines) {
|
|
62
|
-
try {
|
|
63
|
-
const lineResult = this.processLine(line);
|
|
64
|
-
|
|
65
|
-
if (lineResult.done) {
|
|
66
|
-
return { value: processedContent, done: true };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!lineResult.value) {
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
processedContent += lineResult.value;
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.error('Parsing error:', error);
|
|
76
|
-
this.buffer = line + '\n' + this.buffer;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return { value: processedContent, done: false };
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { get, isUndefined, set } from 'lodash';
|
|
2
|
-
import {
|
|
3
|
-
ExecutorPlugin,
|
|
4
|
-
RequestAdapterConfig,
|
|
5
|
-
ExecutorContext,
|
|
6
|
-
RequestAdapterResponse
|
|
7
|
-
} from '@qlover/fe-utils';
|
|
8
|
-
|
|
9
|
-
export type RequestCommonPluginConfig = {
|
|
10
|
-
token?: string | (() => string | null);
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* token prefix.
|
|
14
|
-
*
|
|
15
|
-
* eg. `Bearer xxx`, `Token xxx`
|
|
16
|
-
*/
|
|
17
|
-
tokenPrefix?: string;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @default `Authorization`
|
|
21
|
-
*/
|
|
22
|
-
authKey?: string;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* default request headers
|
|
26
|
-
*/
|
|
27
|
-
defaultHeaders?: Record<string, string>;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Whether the token is required.
|
|
31
|
-
*
|
|
32
|
-
* if not token provided, throw error.
|
|
33
|
-
*
|
|
34
|
-
* @default `false`
|
|
35
|
-
*/
|
|
36
|
-
requiredToken?: boolean;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* defualt request data
|
|
40
|
-
*/
|
|
41
|
-
defaultRequestData?: Record<string, unknown>;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* transform request data before sending.
|
|
45
|
-
*
|
|
46
|
-
* @param data - request data
|
|
47
|
-
* @param context - executor context
|
|
48
|
-
* @returns - request data
|
|
49
|
-
*/
|
|
50
|
-
requestDataSerializer?: (
|
|
51
|
-
data: unknown,
|
|
52
|
-
context: ExecutorContext<RequestAdapterConfig>
|
|
53
|
-
) => unknown;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Represents a plugin for handling common request configurations and behaviors.
|
|
58
|
-
*
|
|
59
|
-
* The RequestCommonPlugin is designed to manage request headers, token handling,
|
|
60
|
-
* and data serialization before sending requests. It ensures that the necessary
|
|
61
|
-
* configurations are applied to each request, enhancing the flexibility and
|
|
62
|
-
* reusability of request handling in the application.
|
|
63
|
-
*
|
|
64
|
-
* Main functions include:
|
|
65
|
-
* - Appending default headers and token to requests.
|
|
66
|
-
* - Merging default request data with provided parameters.
|
|
67
|
-
* - Serializing request data before sending.
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* const plugin = new RequestCommonPlugin({
|
|
71
|
-
* token: 'your-token',
|
|
72
|
-
* tokenPrefix: 'Bearer',
|
|
73
|
-
* defaultHeaders: { 'Custom-Header': 'value' },
|
|
74
|
-
* requiredToken: true,
|
|
75
|
-
* });
|
|
76
|
-
*/
|
|
77
|
-
export class RequestCommonPlugin
|
|
78
|
-
implements ExecutorPlugin<RequestAdapterConfig>
|
|
79
|
-
{
|
|
80
|
-
readonly pluginName = 'RequestCommonPlugin';
|
|
81
|
-
|
|
82
|
-
constructor(readonly config: RequestCommonPluginConfig = {}) {
|
|
83
|
-
if (config.requiredToken && !config.token) {
|
|
84
|
-
throw new Error('Token is required!');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
onBefore(context: ExecutorContext<RequestAdapterConfig>): void {
|
|
89
|
-
const {
|
|
90
|
-
tokenPrefix,
|
|
91
|
-
defaultHeaders,
|
|
92
|
-
authKey = 'Authorization',
|
|
93
|
-
defaultRequestData,
|
|
94
|
-
requestDataSerializer
|
|
95
|
-
} = this.config;
|
|
96
|
-
const { parameters } = context;
|
|
97
|
-
|
|
98
|
-
// append default headers
|
|
99
|
-
parameters.headers = {
|
|
100
|
-
...defaultHeaders,
|
|
101
|
-
...parameters.headers
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// append content type header
|
|
105
|
-
if (
|
|
106
|
-
!parameters.headers['Content-Type'] &&
|
|
107
|
-
parameters.responseType === 'json'
|
|
108
|
-
) {
|
|
109
|
-
parameters.headers['Content-Type'] = 'application/json';
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// append token
|
|
113
|
-
if (authKey && !parameters.headers[authKey]) {
|
|
114
|
-
const authToken = this.getAuthToken();
|
|
115
|
-
const authValue = tokenPrefix ? `${tokenPrefix} ${authToken}` : authToken;
|
|
116
|
-
if (authValue) {
|
|
117
|
-
parameters.headers[authKey] = authValue;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// merge defaults request data
|
|
122
|
-
if (defaultRequestData) {
|
|
123
|
-
Object.entries(defaultRequestData).forEach(([key, value]) => {
|
|
124
|
-
const prevValue = get(parameters.data, key);
|
|
125
|
-
if (isUndefined(prevValue)) {
|
|
126
|
-
set(parameters.data as Record<string, unknown>, key, value);
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// serialize request data
|
|
132
|
-
if (requestDataSerializer && parameters.data) {
|
|
133
|
-
parameters.data = requestDataSerializer(parameters.data, context);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async onSuccess(
|
|
138
|
-
context: ExecutorContext<RequestAdapterConfig>
|
|
139
|
-
): Promise<void> {
|
|
140
|
-
const { parameters, returnValue } = context;
|
|
141
|
-
const response = (returnValue as RequestAdapterResponse<unknown, Response>)
|
|
142
|
-
.data;
|
|
143
|
-
|
|
144
|
-
if (response instanceof Response) {
|
|
145
|
-
switch (parameters.responseType) {
|
|
146
|
-
case 'json':
|
|
147
|
-
context.returnValue = await response.json();
|
|
148
|
-
break;
|
|
149
|
-
case 'text':
|
|
150
|
-
context.returnValue = await response.text();
|
|
151
|
-
break;
|
|
152
|
-
case 'blob':
|
|
153
|
-
context.returnValue = await response.blob();
|
|
154
|
-
break;
|
|
155
|
-
// FIXME: adapter support `arraybuffer`
|
|
156
|
-
// @ts-expect-error
|
|
157
|
-
case 'arrayBuffer':
|
|
158
|
-
case 'arraybuffer':
|
|
159
|
-
context.returnValue = await response.arrayBuffer();
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
getAuthToken(): string {
|
|
166
|
-
const { token } = this.config;
|
|
167
|
-
return typeof token === 'function' ? (token() ?? '') : (token ?? '');
|
|
168
|
-
}
|
|
169
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { LazyExoticComponent, PropsWithChildren } from 'react';
|
|
2
|
-
import { RouteObject } from 'react-router-dom';
|
|
3
|
-
|
|
4
|
-
import { TFunction } from 'i18next';
|
|
5
|
-
import { UseTranslationResponse } from 'react-i18next';
|
|
6
|
-
|
|
7
|
-
export interface BasePageProvider {
|
|
8
|
-
meta: RouteMeta;
|
|
9
|
-
i18n: UseTranslationResponse<string, string>;
|
|
10
|
-
t: TFunction<string, string>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type RouteCategory = 'main' | 'auth' | 'common';
|
|
14
|
-
|
|
15
|
-
export interface RouteMeta {
|
|
16
|
-
category?: RouteCategory;
|
|
17
|
-
/**
|
|
18
|
-
* from app.router.json
|
|
19
|
-
*/
|
|
20
|
-
title?: string;
|
|
21
|
-
icon?: string;
|
|
22
|
-
/**
|
|
23
|
-
* from app.router.json
|
|
24
|
-
*
|
|
25
|
-
* @default 'common'
|
|
26
|
-
*/
|
|
27
|
-
localNamespace?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type RouteType = RouteObject & {
|
|
31
|
-
meta?: RouteMeta;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export type RouteConfig = {
|
|
35
|
-
routes: RouteType[];
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type PagesMaps = Record<
|
|
39
|
-
string,
|
|
40
|
-
| (() => LazyExoticComponent<React.ComponentType<unknown>>)
|
|
41
|
-
| (() => React.ComponentType<unknown>)
|
|
42
|
-
>;
|
|
43
|
-
|
|
44
|
-
export type LoadProps = {
|
|
45
|
-
pagesMaps: PagesMaps;
|
|
46
|
-
componentPath: string;
|
|
47
|
-
route: RouteType;
|
|
48
|
-
Provider?: React.ComponentType<PropsWithChildren<RouteMeta>>;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
type ComponentValue =
|
|
52
|
-
| React.ComponentType<unknown>
|
|
53
|
-
| LazyExoticComponent<React.ComponentType<unknown>>;
|
|
54
|
-
|
|
55
|
-
export type ComponentMaps = {
|
|
56
|
-
/**
|
|
57
|
-
* key: ./xxx/bbb.(jsx,js,tsx,ts)
|
|
58
|
-
*/
|
|
59
|
-
[key: string]:
|
|
60
|
-
| ComponentValue
|
|
61
|
-
| (() => Promise<ComponentValue>)
|
|
62
|
-
| (() => ComponentValue);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// new RouterManager({
|
|
66
|
-
// routes: [],
|
|
67
|
-
// componentMaps:
|
|
68
|
-
// });
|