@zhin.js/console 1.0.8 → 1.0.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/client/index.html +16 -0
  3. package/client/src/components/PluginConfigForm/BasicFieldRenderers.tsx +6 -7
  4. package/client/src/components/PluginConfigForm/CollectionFieldRenderers.tsx +8 -8
  5. package/client/src/components/PluginConfigForm/CompositeFieldRenderers.tsx +3 -3
  6. package/client/src/components/PluginConfigForm/index.tsx +8 -7
  7. package/client/src/components/ThemeToggle.tsx +3 -3
  8. package/client/src/layouts/dashboard.tsx +14 -15
  9. package/client/src/main.tsx +60 -59
  10. package/client/src/pages/dashboard-plugin-detail.tsx +17 -17
  11. package/client/src/pages/dashboard-plugins.tsx +8 -8
  12. package/client/tsconfig.json +5 -6
  13. package/dist/_commonjsHelpers-C6fGbg64.js +6 -0
  14. package/dist/client.js +9 -0
  15. package/dist/index.html +31 -0
  16. package/dist/index.js +15 -0
  17. package/dist/lucide-react.js +28876 -0
  18. package/dist/radix-ui-themes.js +9321 -0
  19. package/dist/radix-ui.js +11213 -0
  20. package/dist/react-dom-client.js +10042 -0
  21. package/dist/react-dom.js +180 -0
  22. package/dist/react-jsx-dev-runtime.js +51 -0
  23. package/dist/react-jsx-runtime.js +68 -0
  24. package/dist/react-router.js +8141 -0
  25. package/dist/react.js +421 -0
  26. package/dist/style.css +2 -0
  27. package/lib/bin.d.ts.map +1 -1
  28. package/lib/bin.js +2 -26
  29. package/lib/bin.js.map +1 -1
  30. package/lib/build.d.ts +2 -32
  31. package/lib/build.d.ts.map +1 -1
  32. package/lib/build.js +67 -144
  33. package/lib/build.js.map +1 -1
  34. package/lib/dev.d.ts.map +1 -1
  35. package/lib/dev.js +2 -1
  36. package/lib/dev.js.map +1 -1
  37. package/lib/index.d.ts.map +1 -1
  38. package/lib/index.js +0 -1
  39. package/lib/index.js.map +1 -1
  40. package/lib/websocket.d.ts.map +1 -1
  41. package/lib/websocket.js.map +1 -1
  42. package/package.json +29 -13
  43. package/app/bin.ts +0 -52
  44. package/app/build.ts +0 -211
  45. package/app/dev.ts +0 -83
  46. package/app/index.ts +0 -193
  47. package/app/websocket.ts +0 -109
  48. package/client/public/vendor/react-dom.production.min.js +0 -1
  49. package/client/public/vendor/react.production.min.js +0 -1
package/app/build.ts DELETED
@@ -1,211 +0,0 @@
1
- import { build, searchForWorkspaceRoot } from "vite";
2
- import react from "@vitejs/plugin-react";
3
- import tailwindcss from "@tailwindcss/vite";
4
- import path from "path";
5
- import fs from "fs";
6
-
7
- export interface BuildOptions {
8
- /** 插件根目录 */
9
- pluginRoot: string;
10
- /** 输出目录,默认为 pluginRoot/dist */
11
- outDir?: string;
12
- /** 是否启用 tailwindcss,默认 true */
13
- enableTailwind?: boolean;
14
- }
15
-
16
- export interface ConsoleBuildOptions {
17
- /** Console 插件根目录 */
18
- consoleRoot: string;
19
- /** 输出目录,默认为 consoleRoot/dist */
20
- outDir?: string;
21
- }
22
-
23
- /**
24
- * 查找插件的客户端入口文件
25
- * @param pluginRoot 插件根目录
26
- * @returns 入口文件路径,如果不存在则返回 null
27
- */
28
- function findClientEntry(pluginRoot: string): string | null {
29
- const possibleEntries = [
30
- path.join(pluginRoot, "client/index.tsx"),
31
- path.join(pluginRoot, "client/index.ts"),
32
- path.join(pluginRoot, "src/main.tsx"),
33
- path.join(pluginRoot, "src/main.ts"),
34
- ];
35
-
36
- for (const entry of possibleEntries) {
37
- if (fs.existsSync(entry)) {
38
- return entry;
39
- }
40
- }
41
-
42
- return null;
43
- }
44
-
45
- /**
46
- * 验证构建环境
47
- * @param pluginRoot 插件根目录
48
- * @throws 如果环境不满足构建要求
49
- */
50
- function validateBuildEnvironment(pluginRoot: string): void {
51
- if (!fs.existsSync(pluginRoot)) {
52
- throw new Error(`Plugin root directory does not exist: ${pluginRoot}`);
53
- }
54
-
55
- const entry = findClientEntry(pluginRoot);
56
- if (!entry) {
57
- throw new Error(
58
- `No client entry file found in ${pluginRoot}. Looking for: client/index.tsx, client/index.ts, src/main.tsx, or src/main.ts`
59
- );
60
- }
61
- }
62
-
63
- /**
64
- * 构建插件的客户端代码(单文件模式)
65
- * 用于构建普通插件的 client/index.tsx 文件
66
- *
67
- * 策略:将公共依赖配置为 external,运行时从 console 加载的 vendor chunks 中复用
68
- * @param options 构建选项
69
- */
70
- export async function buildPluginClient(options: BuildOptions): Promise<void> {
71
- const {
72
- pluginRoot,
73
- outDir = path.join(pluginRoot, "dist"),
74
- enableTailwind = true,
75
- } = options;
76
-
77
- // 验证构建环境
78
- validateBuildEnvironment(pluginRoot);
79
-
80
- const entry = findClientEntry(pluginRoot);
81
- if (!entry) {
82
- throw new Error(`No client entry file found in ${pluginRoot}`);
83
- }
84
-
85
- const plugins = [react()];
86
- if (enableTailwind) {
87
- plugins.push(tailwindcss());
88
- }
89
-
90
- // 构建配置 - 库模式
91
- const clientRoot = path.dirname(entry);
92
-
93
- await build({
94
- root: clientRoot,
95
- plugins,
96
- build: {
97
- outDir,
98
- emptyOutDir: true,
99
- lib: {
100
- entry,
101
- formats: ["es"],
102
- fileName: "index",
103
- },
104
- rollupOptions: {
105
- makeAbsoluteExternalsRelative: true,
106
- external:[
107
- 'react',
108
- 'react-dom',
109
- 'react/jsx-runtime',
110
- 'clsx',
111
- 'tailwind-merge',
112
- 'lucide-react',
113
- '@radix-ui/themes'
114
- ],
115
- },
116
- },
117
- resolve:{
118
- dedupe: [
119
- "react",
120
- "react-dom",
121
- "clsx",
122
- "tailwind-merge",
123
- ],
124
- alias: {
125
- "@": path.resolve(pluginRoot, "client/src"),
126
- },
127
- }
128
- });
129
-
130
- console.log(`✅ Plugin client code built successfully: ${outDir}`);
131
- console.log(`📦 External dependencies will be loaded from console vendor chunks`);
132
- }
133
-
134
- /**
135
- * 构建 Console 插件的客户端代码(SPA 应用模式)
136
- * Console 有完整的 index.html 和 src 目录结构
137
- * @param options Console 构建选项
138
- */
139
- export async function buildConsoleClient(
140
- options: ConsoleBuildOptions
141
- ): Promise<void> {
142
- const { consoleRoot, outDir = path.join(consoleRoot, "dist") } = options;
143
-
144
- const clientRoot = path.join(consoleRoot, "client");
145
-
146
- // 检查 client 目录是否存在
147
- if (!fs.existsSync(clientRoot)) {
148
- throw new Error(`Console client directory does not exist: ${clientRoot}`);
149
- }
150
-
151
- // 检查 index.html 是否存在
152
- const indexHtml = path.join(clientRoot, "index.html");
153
- if (!fs.existsSync(indexHtml)) {
154
- throw new Error(`index.html not found in: ${clientRoot}`);
155
- }
156
-
157
- const workspaceRoot = searchForWorkspaceRoot(consoleRoot);
158
- const consoleClientRoot=path.resolve(workspaceRoot, "plugins/client/client")
159
- const plugins = [react(), tailwindcss()];
160
-
161
- await build({
162
- root: clientRoot,
163
- plugins,
164
- build: {
165
- outDir,
166
- emptyOutDir: true,
167
- // 设置最小 chunk 大小,避免过度分割
168
- chunkSizeWarningLimit: 1000,
169
- // SPA 应用模式,不是库模式
170
- rollupOptions: {
171
- input: indexHtml,
172
- // 保留导出签名
173
- preserveEntrySignatures: 'strict',
174
- output: {
175
- // 确保文件名稳定,不使用哈希,方便插件引用
176
- chunkFileNames: '[name].js',
177
- entryFileNames: '[name].js',
178
- assetFileNames: '[name].[ext]',
179
- },
180
- },
181
- },
182
- resolve: {
183
- dedupe: [
184
- "react",
185
- "react-dom",
186
- "clsx",
187
- "tailwind-merge",
188
- "@reduxjs/toolkit",
189
- "react-router",
190
- "react-redux",
191
- "redux-persist",
192
- ],
193
- alias: {
194
- "@zhin.js/client": consoleClientRoot,
195
- "@": path.resolve(clientRoot, "src"),
196
- },
197
- },
198
- });
199
-
200
- console.log(`✅ Console client built successfully: ${outDir}`);
201
- }
202
-
203
- /**
204
- * 构建当前目录的插件客户端代码
205
- */
206
- export async function buildCurrentPlugin(): Promise<void> {
207
- const currentDir = process.cwd();
208
- await buildPluginClient({
209
- pluginRoot: currentDir,
210
- });
211
- }
package/app/dev.ts DELETED
@@ -1,83 +0,0 @@
1
- import { ViteDevServer, createServer, searchForWorkspaceRoot } from "vite";
2
- import react from "@vitejs/plugin-react";
3
- import tailwindcss from "@tailwindcss/vite";
4
- import path from "path";
5
-
6
- export interface DevServerOptions {
7
- /** 客户端代码根目录 */
8
- root: string;
9
- /** 基础路径,默认 /vite/ */
10
- base?: string;
11
- /** 是否启用 tailwindcss,默认 true */
12
- enableTailwind?: boolean;
13
- }
14
-
15
- /**
16
- * 创建 Vite 开发服务器
17
- * @param options 开发服务器选项
18
- * @returns Vite 开发服务器实例
19
- */
20
- export async function createViteDevServer(
21
- options: DevServerOptions
22
- ): Promise<ViteDevServer> {
23
- const { root, base = "/vite/", enableTailwind = true } = options;
24
-
25
- const plugins = [react()];
26
- if (enableTailwind) {
27
- plugins.push(tailwindcss());
28
- }
29
-
30
- return await await createServer({
31
- root,
32
- base,
33
- plugins: [react(), tailwindcss()],
34
- server: {
35
- middlewareMode: true,
36
- fs: {
37
- strict: false,
38
- // 添加文件访问过滤,避免访问特殊文件
39
- allow: [
40
- // 允许访问的目录
41
- root,
42
- searchForWorkspaceRoot(root),
43
- path.resolve(process.cwd(), 'node_modules'),
44
- path.resolve(process.cwd(), 'client'),
45
- path.resolve(process.cwd(), 'src'),
46
- ],
47
- // 拒绝访问某些文件模式
48
- deny: [
49
- '**/.git/**',
50
- '**/node_modules/.cache/**',
51
- '**/*.socket',
52
- '**/*.pipe',
53
- '**/Dockerfile*',
54
- '**/.env*',
55
- ],
56
- },
57
- },
58
- resolve: {
59
- dedupe: [
60
- "react",
61
- "react-dom",
62
- "clsx",
63
- "tailwind-merge",
64
- "@reduxjs/toolkit",
65
- "react-router",
66
- "react-redux",
67
- "redux-persist",
68
- ],
69
- alias: {
70
- "@zhin.js/client": path.resolve(root, "../../client/client"),
71
- "@": path.resolve(root, "../client/src"),
72
- },
73
- },
74
- optimizeDeps: {
75
- include: ["react", "react-dom"],
76
- },
77
- build: {
78
- rollupOptions: {
79
- input: root + "/index.html",
80
- },
81
- },
82
- });
83
- }
package/app/index.ts DELETED
@@ -1,193 +0,0 @@
1
- import { register, useContext,useLogger } from "@zhin.js/core";
2
- import { WebSocketServer } from "ws";
3
- import { ViteDevServer } from "vite";
4
- import mime from "mime";
5
- import connect from "koa-connect";
6
- import * as fs from "fs";
7
- import * as path from "path";
8
- import { createViteDevServer } from "./dev.js";
9
- import { setupWebSocket,notifyDataUpdate } from "./websocket.js";
10
-
11
- declare module "@zhin.js/types" {
12
- interface GlobalContext {
13
- web: WebServer;
14
- }
15
- }
16
- export type WebEntry =
17
- | string
18
- | {
19
- production: string;
20
- development: string;
21
- };
22
- export type WebServer = {
23
- vite?: ViteDevServer;
24
- addEntry(entry: WebEntry): () => void;
25
- entries: Record<string, string>;
26
- ws: WebSocketServer;
27
- };
28
- const logger=useLogger()
29
- const createSyncMsg = (key: string, value: any) => {
30
- return {
31
- type: "sync",
32
- data: {
33
- key,
34
- value,
35
- },
36
- };
37
- };
38
- const createAddMsg = (key: string, value: any) => {
39
- return {
40
- type: "add",
41
- data: {
42
- key,
43
- value,
44
- },
45
- };
46
- };
47
- const createDeleteMsg = (key: string, value: any) => {
48
- return {
49
- type: "delete",
50
- data: {
51
- key,
52
- value,
53
- },
54
- };
55
- };
56
- useContext("router", async (router) => {
57
- const base = "/vite/";
58
-
59
- const webServer: WebServer = {
60
- entries: {},
61
- addEntry(entry) {
62
- const hash =
63
- Date.now().toString(16) + Math.random().toString(16).slice(2, 8);
64
- const entryFile =
65
- typeof entry === "string"
66
- ? entry
67
- : entry[
68
- (process.env.NODE_ENV as "development" | "production") ||
69
- "development"
70
- ];
71
- this.entries[hash] = `/vite/@fs/${entryFile}`
72
- for (const ws of this.ws.clients || []) {
73
- ws.send(JSON.stringify(createAddMsg("entries", this.entries[hash])));
74
- }
75
- return () => {
76
- for (const ws of this.ws.clients || []) {
77
- ws.send(
78
- JSON.stringify(createDeleteMsg("entries", this.entries[hash]))
79
- );
80
- }
81
- delete this.entries[hash];
82
- };
83
- },
84
- ws: router.ws("/server"),
85
- };
86
- const isDev = process.env.NODE_ENV === "development";
87
- const root = isDev
88
- ? path.join(import.meta.dirname, "../client")
89
- : path.join(import.meta.dirname, "../dist");
90
- logger.info({isDev,root})
91
- if (isDev) {
92
- webServer.vite = await await createViteDevServer({
93
- root,
94
- base,
95
- enableTailwind: true,
96
- });
97
- // Vite 中间件 - 必须在其他路由之前
98
- router.use((ctx, next) => {
99
- if (ctx.request.originalUrl.startsWith("/api")) return next();
100
- return connect(webServer.vite!.middlewares)(ctx, next);
101
- });
102
- }else{
103
- router.use((ctx, next) => {
104
- if (ctx.request.originalUrl.startsWith("/api")) return next();
105
- if(!ctx.path.startsWith('/vite/@fs/')) return next();
106
- const filename=ctx.path.replace(`/vite/@fs/`,'')
107
- if(!fs.existsSync(filename)) return next();
108
- ctx.type = mime.getType(filename) || path.extname(filename);
109
- ctx.body = fs.createReadStream(filename);
110
- });
111
- }
112
-
113
- // SPA 回退路由 - 处理所有未匹配的路由
114
- router.all("*all", async (ctx, next) => {
115
- const url = ctx.request.originalUrl.replace(base, "");
116
- const name = isDev ? ctx.path.slice(1) : ctx.path.slice(1);
117
- const sendFile = (filename: string) => {
118
- console.log(`发送文件: ${filename}`);
119
- // 安全检查:确保是常规文件
120
- try {
121
- const stat = fs.statSync(filename);
122
- if (!stat.isFile()) {
123
- ctx.status = 404;
124
- return;
125
- }
126
- } catch (error) {
127
- ctx.status = 404;
128
- return;
129
- }
130
-
131
- ctx.type = path.extname(filename);
132
- ctx.type = mime.getType(filename) || ctx.type;
133
- return (ctx.body = fs.createReadStream(filename));
134
- };
135
-
136
- // 1. 检查是否是动态入口
137
- if (Object.keys(webServer.entries).includes(name)) {
138
- return sendFile(path.resolve(process.cwd(), webServer.entries[name]));
139
- }
140
-
141
- // 2. 检查是否是静态文件
142
- const filename = path.resolve(root, name);
143
- if (filename.startsWith(root) || filename.includes("node_modules")) {
144
- try {
145
- if (fs.existsSync(filename)) {
146
- const fileState = fs.statSync(filename);
147
- // 只处理常规文件,忽略目录、socket、符号链接等
148
- if (
149
- fileState.isFile() &&
150
- !fileState.isSocket() &&
151
- !fileState.isFIFO()
152
- ) {
153
- return sendFile(filename);
154
- }
155
- }
156
- } catch (error) {
157
- // 忽略文件系统错误,继续处理
158
- console.warn(`文件访问错误: ${filename}`, (error as Error).message);
159
- }
160
- } else {
161
- // 安全检查:路径不在允许范围内
162
- return (ctx.status = 403);
163
- }
164
-
165
- // 3. 所有其他路径(包括 SPA 路由)都返回 index.html
166
- // 这样前端路由可以正确处理
167
- const indexFile = path.resolve(root, "index.html");
168
- if(!isDev) return sendFile(indexFile);
169
- const template = fs.readFileSync(indexFile, "utf8");
170
- ctx.type = "html";
171
- ctx.body = await webServer.vite!.transformIndexHtml(url, template);
172
- });
173
- // 定时通知客户端更新数据
174
- const dataUpdateInterval = setInterval(() => {
175
- notifyDataUpdate(webServer);
176
- }, 5000); // 每5秒通知一次更新
177
- setupWebSocket(webServer);
178
- // 插件卸载时清理定时器
179
- process.on("exit", () => {
180
- clearInterval(dataUpdateInterval);
181
- });
182
- register({
183
- name: "web",
184
- description: "web服务",
185
- async mounted() {
186
- return webServer;
187
- },
188
- async dispose(server) {
189
- await server.vite?.close();
190
- server.ws.close();
191
- },
192
- });
193
- });
package/app/websocket.ts DELETED
@@ -1,109 +0,0 @@
1
- import WebSocket from "ws";
2
- import type { WebServer } from "./index.js";
3
-
4
- /**
5
- * 设置 WebSocket 连接处理
6
- */
7
- export function setupWebSocket(webServer: WebServer) {
8
- webServer.ws.on("connection", (ws: WebSocket) => {
9
- // 发送初始数据同步
10
- ws.send(
11
- JSON.stringify({
12
- type: "sync",
13
- data: {
14
- key: "entries",
15
- value: Object.values(webServer.entries),
16
- },
17
- })
18
- );
19
-
20
- // 通知客户端进行数据初始化
21
- ws.send(
22
- JSON.stringify({
23
- type: "init-data",
24
- timestamp: Date.now(),
25
- })
26
- );
27
-
28
- // 处理客户端消息
29
- ws.on("message", async (data) => {
30
- try {
31
- const message = JSON.parse(data.toString());
32
- await handleWebSocketMessage(ws, message, webServer);
33
- } catch (error) {
34
- console.error("WebSocket 消息处理错误:", error);
35
- ws.send(
36
- JSON.stringify({
37
- error: "Invalid message format",
38
- })
39
- );
40
- }
41
- });
42
-
43
- ws.on("close", () => {
44
- // 连接关闭时的清理工作
45
- });
46
-
47
- ws.on("error", (error) => {
48
- console.error("WebSocket 错误:", error);
49
- });
50
- });
51
- }
52
-
53
- /**
54
- * 处理 WebSocket 消息
55
- */
56
- async function handleWebSocketMessage(
57
- ws: WebSocket,
58
- message: any,
59
- webServer: WebServer
60
- ) {
61
- const { type, requestId } = message;
62
-
63
- switch (type) {
64
- case "ping":
65
- // 心跳检测
66
- ws.send(JSON.stringify({ type: "pong", requestId }));
67
- break;
68
-
69
- case "entries:get":
70
- // 获取所有入口文件
71
- ws.send(
72
- JSON.stringify({
73
- requestId,
74
- data: Object.values(webServer.entries),
75
- })
76
- );
77
- break;
78
-
79
- default:
80
- // 未知消息类型
81
- ws.send(
82
- JSON.stringify({
83
- requestId,
84
- error: `Unknown message type: ${type}`,
85
- })
86
- );
87
- }
88
- }
89
-
90
- /**
91
- * 广播消息给所有连接的客户端
92
- */
93
- export function broadcastToAll(webServer: WebServer, message: any) {
94
- for (const ws of webServer.ws.clients || []) {
95
- if (ws.readyState === WebSocket.OPEN) {
96
- ws.send(JSON.stringify(message));
97
- }
98
- }
99
- }
100
-
101
- /**
102
- * 通知数据更新
103
- */
104
- export function notifyDataUpdate(webServer: WebServer) {
105
- broadcastToAll(webServer, {
106
- type: "data-update",
107
- timestamp: Date.now(),
108
- });
109
- }
@@ -1 +0,0 @@
1
- Not found: /react-dom@19.2.0/umd/react-dom.production.min.js
@@ -1 +0,0 @@
1
- Not found: /react@19.2.0/umd/react.production.min.js