@quan-erp/shared-types 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Quan ERP Shared Types
2
+
3
+ The central contract repository for the Quan ERP system. This library defines the standardized interfaces, enums, and type aliases that provide type safety and structural consistency across the backend, frontend, and all modular plugins.
4
+
5
+ ---
6
+
7
+ ## 🔌 Plugin Architecture Contracts
8
+
9
+ These interfaces define how plugins interact with the core kernel during their lifecycle.
10
+
11
+ ### `IPlugin`
12
+ The primary interface for all backend plugins. It dictates the required hooks for installation, uninstallation, and readiness:
13
+ - **`onInstall`**: Triggered when the plugin is first added, receiving the `IAppInstance` bridge.
14
+ - **`onReady`**: Triggered once the plugin and all its dependencies are fully initialized.
15
+ - **`onMigrate`**: Handles versioned database schema transformations.
16
+ - **`getMigrations`**: Returns the list of `IDatabaseMigrationClass` to be executed.
17
+
18
+ ### `PluginMetadata`
19
+ Defines the structure of the mandatory `module.metadata.json` file.
20
+ - **`name`**: Unique identifier for the plugin.
21
+ - **`pluginDependencies`**: A map of required plugins and their semantic versions.
22
+ - **`requiredBasedVersion`**: The minimum kernel version required for compatibility.
23
+
24
+ ### `IAppInstance`
25
+ The "Bridge" provided by the kernel to a plugin during `onInstall`. It allows plugins to:
26
+ - Resolve services from the core container.
27
+ - Access data sources from other plugins.
28
+ - Check installation status of optional dependencies.
29
+
30
+ ---
31
+
32
+ ## 🎨 Frontend Orchestration Types
33
+
34
+ Standardizes the way frontend modules register their UI elements into the global ERP shell.
35
+
36
+ ### `AppRegistryState`
37
+ The contract for the global Zustand store managed by the frontend core. It includes:
38
+ - **`route.add()`**: For registering new page routes.
39
+ - **`menu.add()`**: For injecting items into the sidebar navigation.
40
+ - **`portal.add()`**: For injecting elements into global UI zones (e.g., header, status bar).
41
+ - **`report.add()`**: For registering items in the centralized reporting module.
42
+
43
+ ### Navigation Hierarchy
44
+ - **`Menu`**: Unified type for navigation items.
45
+ - **`GroupMenu`**: A parent item with nested `children`.
46
+ - **`SingleMenu`**: A terminal navigation item mapped to a specific path.
47
+
48
+ ---
49
+
50
+ ## 🏗️ Backend & Infrastructure Types
51
+
52
+ ### Database Migrations
53
+ - **`IDatabaseMigration`**: The contract for `up` and `down` database transformations.
54
+ - **`IDatabaseMigrationClass`**: Type alias for the constructor of a migration.
55
+
56
+ ### Cross-Plugin Features
57
+ - **`PluginExposedFeature`**: Defines how a plugin exposes its internal APIs to other modules in the system.
58
+
59
+ ---
60
+
61
+ ## 👤 Common Domain Entities
62
+
63
+ Basic structures shared across all layers of the ERP to ensure data consistency.
64
+
65
+ - **`UserInfo`**: Comprehensive user profile including role metadata and status.
66
+ - **`ApiPermission`**: Mapping of HTTP methods and URLs to formal system permissions.
67
+ - **`HttpMethod`**: Standardized string literal types for RESTful operations.
68
+
69
+ ---
70
+
71
+ ## 📜 Usage Guidelines
72
+
73
+ 1. **Strict Compliance**: All plugins MUST implement the `IPlugin` interface to be recognized by the `AppFactory`.
74
+ 2. **Metadata Accuracy**: Ensure `module.metadata.json` aligns with the `PluginMetadata` interface to prevent dependency resolution errors.
75
+ 3. **Cross-Plugin Safety**: Use the `PluginExposedFeature` types when interacting with APIs from other modules.
76
+
77
+ ---
78
+
79
+ > [!NOTE]
80
+ > This package should be considered a **stable contract**. Breaking changes here will require updates across the entire plugin ecosystem.
@@ -0,0 +1,66 @@
1
+ import { DataSource, QueryRunner } from 'typeorm';
2
+ export interface IAppInstance {
3
+ getAppId(): string;
4
+ getPlugin(name: string): PluginExposedFeature | undefined;
5
+ getPluginInfo(name: string): PluginMetadata | undefined;
6
+ getDetail(): BaseDetail;
7
+ getBuildin(): any;
8
+ getDataSource(pluginName: string, name: string): Promise<DataSource | undefined | null>;
9
+ getEntity(cls: any, pluginName: string, name: string): any | null;
10
+ checkIsInstalled(name: string): boolean;
11
+ findInstance<T>(cls: new (...args: any[]) => T, pluginName: string, name: string): T;
12
+ }
13
+ export type MobilePluginType = 'mobile-frontend';
14
+ export type WebPluginType = 'web-frontend';
15
+ export type DesktopPluginType = 'desktop-frontend';
16
+ export type BackendPluginType = 'backend' | 'middleware' | 'datasource' | 'assets';
17
+ export type PluginType = MobilePluginType | WebPluginType | DesktopPluginType | BackendPluginType;
18
+ export interface PluginMetadata {
19
+ name: string;
20
+ displayName?: string;
21
+ pluginVersion: string;
22
+ type: PluginType | string;
23
+ description: string;
24
+ moduleEntryObject: string;
25
+ requiredBasedVersion: string;
26
+ pluginDependencies: {
27
+ [key: string]: string;
28
+ };
29
+ }
30
+ export interface IDatabaseMigration {
31
+ getName(): string;
32
+ up(queryRunner: QueryRunner): Promise<void>;
33
+ down(queryRunner: QueryRunner): Promise<void>;
34
+ getSource(): {
35
+ plugin: string;
36
+ name: string;
37
+ };
38
+ }
39
+ export interface PluginExposedFeature {
40
+ getApi<T>(name: string): T;
41
+ info(): PluginMetadata;
42
+ }
43
+ export type IDatabaseMigrationClass = new () => IDatabaseMigration;
44
+ export type GetMigrationsType = (IDatabaseMigrationClass | IDatabaseMigrationClass[])[];
45
+ export interface IPlugin {
46
+ getName(): string;
47
+ getVersion(): string;
48
+ getAppModule(): PluginExposedFeature | undefined;
49
+ getRootModule(): any;
50
+ getMetadata(): PluginMetadata;
51
+ getMigrations(): GetMigrationsType;
52
+ onInstall(appContext: IAppInstance): void;
53
+ onUninstall(): Promise<void>;
54
+ onInstallError(err: any): void;
55
+ onUninstallError(err: any): void;
56
+ onMigrate(options: {
57
+ installedPluginVersion: number;
58
+ }): void;
59
+ onReady(): void;
60
+ isReady(): boolean;
61
+ isHealthy(): boolean;
62
+ }
63
+ export interface BaseDetail {
64
+ version: number;
65
+ name: string;
66
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './plugin.js';
2
+ export * from './backend-plugin-type.js';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './plugin.js';
2
+ export * from './backend-plugin-type.js';
@@ -0,0 +1,153 @@
1
+ import type { ReactElement } from "react";
2
+ import type { AxiosInstance } from 'axios';
3
+ import type { PluginMetadata } from "./backend-plugin-type.js";
4
+ import type { QueryClient } from "@tanstack/react-query";
5
+ export interface PluginModule {
6
+ register: (AppRegistry: any) => Promise<void> | void;
7
+ onAllPluginInstalled?: (AppRegistry: any) => Promise<void> | void;
8
+ onPluginInstalled?: (AppRegistry: any) => Promise<void> | void;
9
+ onBeforeInstall?: (AppRegistry: any) => Promise<void> | void;
10
+ pickFile?: () => Promise<string | string[]>;
11
+ }
12
+ export interface UserInfo {
13
+ username: string;
14
+ name: string;
15
+ roleId: number;
16
+ accessToken: string;
17
+ refreshToken: string;
18
+ isOwner: boolean;
19
+ createDate: string;
20
+ updateDate: string;
21
+ deleteDate: string | null;
22
+ version: number;
23
+ id: number;
24
+ }
25
+ export interface SettingComponents {
26
+ pluginName: string;
27
+ element: ReactElement;
28
+ routes?: {
29
+ path: string;
30
+ element: ReactElement;
31
+ }[];
32
+ }
33
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD';
34
+ export type ApiPermission = {
35
+ method: HttpMethod;
36
+ url: string;
37
+ };
38
+ export type WithApiMetadataFetchFn<T extends (...args: any[]) => any = (...args: any[]) => any> = {
39
+ api: ApiPermission;
40
+ fetchFn: T;
41
+ };
42
+ export declare function withApiMetadataFetchFn<T extends (...args: any[]) => any>(p: WithApiMetadataFetchFn<T>): WithApiMetadataFetchFn<T>;
43
+ export type Route = {
44
+ path: string;
45
+ element: ReactElement;
46
+ description?: string;
47
+ };
48
+ export type PageRoute = Route | Route[];
49
+ export type Component = string | ReactElement | ReactElement[];
50
+ export type SingleMenu = {
51
+ name: Component;
52
+ path: string;
53
+ pluginName?: string;
54
+ description?: string;
55
+ sortNumber?: number;
56
+ requiredApis?: ApiPermission | ApiPermission[] | (() => ApiPermission | ApiPermission[]) | WithApiMetadataFetchFn<any> | WithApiMetadataFetchFn<any>[] | (ApiPermission | WithApiMetadataFetchFn<any>)[];
57
+ };
58
+ export type GroupMenu = {
59
+ name: Component;
60
+ path?: string;
61
+ pluginName?: string;
62
+ description?: string;
63
+ sortNumber?: number;
64
+ requiredApis?: ApiPermission | ApiPermission[] | (() => ApiPermission | ApiPermission[]);
65
+ children: Menu[];
66
+ };
67
+ export type Menu = SingleMenu | GroupMenu;
68
+ export type RootRoute = {
69
+ path: string;
70
+ pluginName?: string;
71
+ element?: ReactElement;
72
+ children?: RootRoute[];
73
+ };
74
+ export type PagePermissionRouteStore = Record<string, Record<string, {
75
+ description: string;
76
+ }>>;
77
+ export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
78
+ export type NavMenuItem = {
79
+ pluginName: string;
80
+ element: ReactElement;
81
+ };
82
+ export type DashboardItems = {
83
+ id: string;
84
+ pluginName: string;
85
+ element: ReactElement;
86
+ };
87
+ export type Report = {
88
+ pluginName: string;
89
+ page: ReactElement;
90
+ };
91
+ export type PluginInfo = {
92
+ name: string;
93
+ displayName: string;
94
+ version: string;
95
+ };
96
+ export interface AppRegistryState {
97
+ locale: string;
98
+ setLocale: (locale: string) => void;
99
+ routes: PageRoute[];
100
+ route: {
101
+ add: (route: PageRoute) => void;
102
+ };
103
+ menus: Optional<Menu, 'pluginName'>[];
104
+ menuState: {
105
+ isMinimize: boolean;
106
+ allowSwipeToOpen: boolean;
107
+ };
108
+ menu: {
109
+ add: (menu: Menu) => void;
110
+ minimize(): void;
111
+ maximize(): void;
112
+ allowSwipeToOpen(allow: boolean): void;
113
+ };
114
+ queryClient: QueryClient;
115
+ rootRoutes: RootRoute[];
116
+ rootRoute: {
117
+ add: (route: RootRoute) => void;
118
+ };
119
+ userInfo: UserInfo | null;
120
+ user: {
121
+ getInfo: () => void;
122
+ getAccessToken: () => void;
123
+ isLogin: () => boolean;
124
+ setUser: (user: UserInfo) => void;
125
+ logout: () => void;
126
+ };
127
+ getAxiosClient: () => AxiosInstance;
128
+ plugins: PluginInfo[];
129
+ plugin: {
130
+ getInstalled: () => [];
131
+ install: (plugin: PluginInfo) => void;
132
+ isInstalled: (name: string) => boolean;
133
+ };
134
+ settings: SettingComponents[];
135
+ setting: {
136
+ add(setting: SettingComponents): void;
137
+ };
138
+ dashboards: DashboardItems[];
139
+ dashboard: {
140
+ add(item: DashboardItems): void;
141
+ };
142
+ portals: ReactElement[];
143
+ portal: {
144
+ add(element: ReactElement): void;
145
+ };
146
+ reports: Record<string, ReactElement>;
147
+ report: {
148
+ add(item: Report): void;
149
+ };
150
+ }
151
+ export type PluginMetadataInfo = PluginMetadata & {
152
+ installed: boolean;
153
+ };
package/dist/plugin.js ADDED
@@ -0,0 +1,3 @@
1
+ export function withApiMetadataFetchFn(p) {
2
+ return p;
3
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@quan-erp/shared-types",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "types/index.d.ts",
6
+ "types": "types/index.d.ts",
7
+ "scripts": {
8
+ "publish:registry": "npm run build && npm publish --tag beta",
9
+ "publish:npm-registry": "npm run build && npm publish --access public --tag beta --registry https://registry.npmjs.org/ --@quan-erp:registry=https://registry.npmjs.org/",
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "release:beta": "npm publish --tag beta",
12
+ "build": "tsc"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/index.js"
21
+ }
22
+ },
23
+ "keywords": [],
24
+ "author": "",
25
+ "license": "UNLICENSED",
26
+ "type": "module",
27
+ "devDependencies": {
28
+ "@types/node": "^24.10.1",
29
+ "@types/react": "^19.2.7",
30
+ "react": "19.2.6",
31
+ "@tanstack/react-query": "5.90.10"
32
+ },
33
+ "peerDependencies": {
34
+ "axios": "^1.13.2",
35
+ "react": "19.2.6",
36
+ "typeorm": "^0.3.27",
37
+ "@tanstack/react-query": "^5.90.10"
38
+ },
39
+ "dependencies": {}
40
+ }