@zhin.js/client 1.0.17 → 1.0.18

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 (76) hide show
  1. package/client/app.ts +228 -0
  2. package/client/index.ts +42 -14
  3. package/client/websocket/hooks.ts +218 -510
  4. package/client/websocket/index.ts +6 -43
  5. package/client/websocket/instance.ts +10 -32
  6. package/client/websocket/manager.ts +173 -390
  7. package/client/websocket/types.ts +58 -222
  8. package/dist/app.d.ts +95 -0
  9. package/dist/app.d.ts.map +1 -0
  10. package/dist/app.js +147 -0
  11. package/dist/app.js.map +1 -0
  12. package/dist/index.d.ts +7 -7
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +10 -14
  15. package/dist/index.js.map +1 -1
  16. package/dist/websocket/hooks.d.ts +35 -58
  17. package/dist/websocket/hooks.d.ts.map +1 -1
  18. package/dist/websocket/hooks.js +134 -410
  19. package/dist/websocket/hooks.js.map +1 -1
  20. package/dist/websocket/index.d.ts +5 -10
  21. package/dist/websocket/index.d.ts.map +1 -1
  22. package/dist/websocket/index.js +5 -25
  23. package/dist/websocket/index.js.map +1 -1
  24. package/dist/websocket/instance.d.ts +1 -14
  25. package/dist/websocket/instance.d.ts.map +1 -1
  26. package/dist/websocket/instance.js +2 -20
  27. package/dist/websocket/instance.js.map +1 -1
  28. package/dist/websocket/manager.d.ts +23 -93
  29. package/dist/websocket/manager.d.ts.map +1 -1
  30. package/dist/websocket/manager.js +87 -227
  31. package/dist/websocket/manager.js.map +1 -1
  32. package/dist/websocket/types.d.ts +35 -122
  33. package/dist/websocket/types.d.ts.map +1 -1
  34. package/dist/websocket/types.js +4 -13
  35. package/dist/websocket/types.js.map +1 -1
  36. package/package.json +12 -11
  37. package/client/router/index.tsx +0 -54
  38. package/client/store/index.ts +0 -132
  39. package/client/store/reducers/config.ts +0 -135
  40. package/client/store/reducers/index.ts +0 -19
  41. package/client/store/reducers/route.ts +0 -126
  42. package/client/store/reducers/script.ts +0 -109
  43. package/client/store/reducers/ui.ts +0 -31
  44. package/client/websocket/messageHandler.ts +0 -208
  45. package/dist/router/index.d.ts +0 -25
  46. package/dist/router/index.d.ts.map +0 -1
  47. package/dist/router/index.js +0 -48
  48. package/dist/router/index.js.map +0 -1
  49. package/dist/store/index.d.ts +0 -19
  50. package/dist/store/index.d.ts.map +0 -1
  51. package/dist/store/index.js +0 -67
  52. package/dist/store/index.js.map +0 -1
  53. package/dist/store/reducers/config.d.ts +0 -54
  54. package/dist/store/reducers/config.d.ts.map +0 -1
  55. package/dist/store/reducers/config.js +0 -78
  56. package/dist/store/reducers/config.js.map +0 -1
  57. package/dist/store/reducers/index.d.ts +0 -13
  58. package/dist/store/reducers/index.d.ts.map +0 -1
  59. package/dist/store/reducers/index.js +0 -11
  60. package/dist/store/reducers/index.js.map +0 -1
  61. package/dist/store/reducers/route.d.ts +0 -30
  62. package/dist/store/reducers/route.d.ts.map +0 -1
  63. package/dist/store/reducers/route.js +0 -85
  64. package/dist/store/reducers/route.js.map +0 -1
  65. package/dist/store/reducers/script.d.ts +0 -13
  66. package/dist/store/reducers/script.d.ts.map +0 -1
  67. package/dist/store/reducers/script.js +0 -78
  68. package/dist/store/reducers/script.js.map +0 -1
  69. package/dist/store/reducers/ui.d.ts +0 -8
  70. package/dist/store/reducers/ui.d.ts.map +0 -1
  71. package/dist/store/reducers/ui.js +0 -23
  72. package/dist/store/reducers/ui.js.map +0 -1
  73. package/dist/websocket/messageHandler.d.ts +0 -58
  74. package/dist/websocket/messageHandler.d.ts.map +0 -1
  75. package/dist/websocket/messageHandler.js +0 -174
  76. package/dist/websocket/messageHandler.js.map +0 -1
package/client/app.ts ADDED
@@ -0,0 +1,228 @@
1
+ import * as React from "react";
2
+
3
+ export type AddRouteInput = {
4
+ path: string;
5
+ name: string;
6
+ element: React.ReactNode;
7
+ parent?: string | null;
8
+ icon?: React.ReactNode | string;
9
+ requiredPermissions?: string[];
10
+ requiredRoles?: string[];
11
+ meta?: {
12
+ hideInMenu?: boolean;
13
+ order?: number;
14
+ group?: string;
15
+ fullWidth?: boolean;
16
+ };
17
+ };
18
+
19
+ export type AddToolInput = {
20
+ id?: string;
21
+ name: string;
22
+ icon?: React.ReactNode;
23
+ parent?: string | null;
24
+ path?: string;
25
+ };
26
+
27
+ export type ConsoleRouteRecord = {
28
+ path: string;
29
+ name: string;
30
+ element: React.ReactNode;
31
+ parent: string | null;
32
+ icon?: React.ReactNode | string;
33
+ requiredPermissions?: string[];
34
+ requiredRoles?: string[];
35
+ meta?: {
36
+ hideInMenu?: boolean;
37
+ order?: number;
38
+ group?: string;
39
+ fullWidth?: boolean;
40
+ };
41
+ };
42
+
43
+ export type InternalToolRecord = {
44
+ id: string;
45
+ name: string;
46
+ icon?: React.ReactNode;
47
+ parent: string | null;
48
+ path?: string;
49
+ };
50
+
51
+ export type RouteTreeNode = ConsoleRouteRecord & { children: RouteTreeNode[] };
52
+ export type ToolTreeNode = InternalToolRecord & { children: ToolTreeNode[] };
53
+
54
+ type SidebarRenderer = (options: { routes: RouteTreeNode[] }) => React.ReactNode;
55
+ type ToolbarRenderer = (options: { tools: ToolTreeNode[] }) => React.ReactNode;
56
+ export type ConsoleRouteRenderer = (route: ConsoleRouteRecord) => React.ReactNode;
57
+
58
+ const listeners = new Set<() => void>();
59
+ let version = 0;
60
+
61
+ function bump() {
62
+ version++;
63
+ for (const l of listeners) l();
64
+ }
65
+
66
+ function subscribe(listener: () => void) {
67
+ listeners.add(listener);
68
+ return () => listeners.delete(listener);
69
+ }
70
+
71
+ function getVersion() {
72
+ return version;
73
+ }
74
+
75
+ let routes: ConsoleRouteRecord[] = [];
76
+ let tools: InternalToolRecord[] = [];
77
+ let sidebarRenderer: SidebarRenderer | null = null;
78
+ let toolbarRenderer: ToolbarRenderer | null = null;
79
+ let routeRenderer: ConsoleRouteRenderer | null = null;
80
+
81
+ function slugId(name: string) {
82
+ return (
83
+ name
84
+ .toLowerCase()
85
+ .replace(/[^a-z0-9]+/g, "-")
86
+ .replace(/^-|-$/g, "") || "tool"
87
+ );
88
+ }
89
+
90
+ function buildRouteTree(flatRoutes: ConsoleRouteRecord[]): RouteTreeNode[] {
91
+ const nodes: RouteTreeNode[] = flatRoutes.map((r) => ({ ...r, children: [] }));
92
+ const roots: RouteTreeNode[] = [];
93
+
94
+ for (const node of nodes) {
95
+ if (!node.parent) {
96
+ roots.push(node);
97
+ } else {
98
+ const parent = nodes.find((n) => n.path === node.parent);
99
+ if (parent) {
100
+ parent.children.push(node);
101
+ } else {
102
+ roots.push(node);
103
+ }
104
+ }
105
+ }
106
+
107
+ const sortFn = (a: RouteTreeNode, b: RouteTreeNode) =>
108
+ (a.meta?.order ?? 999) - (b.meta?.order ?? 999);
109
+ roots.sort(sortFn);
110
+ for (const n of nodes) n.children.sort(sortFn);
111
+
112
+ return roots;
113
+ }
114
+
115
+ function buildToolTree(flatTools: InternalToolRecord[]): ToolTreeNode[] {
116
+ const nodes: ToolTreeNode[] = flatTools.map((t) => ({ ...t, children: [] }));
117
+ const roots: ToolTreeNode[] = [];
118
+
119
+ for (const node of nodes) {
120
+ if (!node.parent) {
121
+ roots.push(node);
122
+ } else {
123
+ const parent = nodes.find((n) => n.id === node.parent);
124
+ if (parent) {
125
+ parent.children.push(node);
126
+ } else {
127
+ roots.push(node);
128
+ }
129
+ }
130
+ }
131
+ return roots;
132
+ }
133
+
134
+ function renderRouteElement(route: ConsoleRouteRecord): React.ReactNode {
135
+ if (routeRenderer) return routeRenderer(route);
136
+ return route.element;
137
+ }
138
+
139
+ function createConsoleApp() {
140
+ return {
141
+ subscribe,
142
+ getVersion,
143
+
144
+ defineSidebar(render: SidebarRenderer) {
145
+ sidebarRenderer = render;
146
+ bump();
147
+ },
148
+
149
+ defineToolbar(render: ToolbarRenderer) {
150
+ toolbarRenderer = render;
151
+ bump();
152
+ },
153
+
154
+ defineRouter(render: ConsoleRouteRenderer) {
155
+ routeRenderer = render;
156
+ bump();
157
+ },
158
+
159
+ addRoute(input: AddRouteInput) {
160
+ const next = routes.filter((r) => r.path !== input.path);
161
+ next.push({
162
+ path: input.path,
163
+ name: input.name,
164
+ element: input.element,
165
+ parent: input.parent ?? null,
166
+ icon: input.icon,
167
+ requiredPermissions: input.requiredPermissions,
168
+ requiredRoles: input.requiredRoles,
169
+ meta: input.meta,
170
+ });
171
+ routes = next;
172
+ bump();
173
+ },
174
+
175
+ removeRoute(path: string) {
176
+ routes = routes.filter((r) => r.path !== path);
177
+ bump();
178
+ },
179
+
180
+ addTool(input: AddToolInput): string {
181
+ const id =
182
+ input.id ?? `${slugId(input.name)}-${Math.random().toString(36).slice(2, 8)}`;
183
+ if (tools.some((t) => t.id === id)) {
184
+ throw new Error(`[zhin-console] addTool: id already exists: ${id}`);
185
+ }
186
+ tools = [
187
+ ...tools,
188
+ {
189
+ id,
190
+ name: input.name,
191
+ icon: input.icon,
192
+ parent: input.parent ?? null,
193
+ path: input.path,
194
+ },
195
+ ];
196
+ bump();
197
+ return id;
198
+ },
199
+
200
+ getRouteTree(): RouteTreeNode[] {
201
+ return buildRouteTree(routes);
202
+ },
203
+
204
+ getToolTree(): ToolTreeNode[] {
205
+ return buildToolTree(tools);
206
+ },
207
+
208
+ _getRoutes(): readonly ConsoleRouteRecord[] {
209
+ return routes;
210
+ },
211
+
212
+ _getSidebarRenderer(): SidebarRenderer | null {
213
+ return sidebarRenderer;
214
+ },
215
+
216
+ _getToolbarRenderer(): ToolbarRenderer | null {
217
+ return toolbarRenderer;
218
+ },
219
+
220
+ _renderRouteElement(route: ConsoleRouteRecord): React.ReactNode {
221
+ return renderRouteElement(route);
222
+ },
223
+ };
224
+ }
225
+
226
+ export type ConsoleApp = ReturnType<typeof createConsoleApp>;
227
+
228
+ export const app = createConsoleApp();
package/client/index.ts CHANGED
@@ -1,20 +1,48 @@
1
- import { type ClassValue, clsx } from 'clsx'
2
- import { twMerge } from 'tailwind-merge'
3
1
  // Types
4
- export * from './types'
2
+ export * from "./types";
5
3
 
6
- // 媒体 URL(含 base64://)解析,供控制台 / 沙盒等
7
- export { resolveMediaSrc, pickMediaRawUrl, type MediaKind } from './mediaSrc'
4
+ // Media URL resolution
5
+ export { resolveMediaSrc, pickMediaRawUrl, type MediaKind } from "./mediaSrc";
8
6
 
9
- // Redux Store
10
- export * from './store'
7
+ // Console app singleton (page-manager style)
8
+ export {
9
+ app,
10
+ type ConsoleApp,
11
+ type AddRouteInput,
12
+ type AddToolInput,
13
+ type ConsoleRouteRecord,
14
+ type RouteTreeNode,
15
+ type ToolTreeNode,
16
+ type ConsoleRouteRenderer,
17
+ } from "./app";
11
18
 
12
- // Router
13
- export * from './router'
19
+ // WebSocket (business data only)
20
+ export * from "./websocket";
14
21
 
15
- // WebSocket
16
- export * from './websocket'
22
+ // Re-export console-types
23
+ export type {
24
+ PluginRegisterHostApi,
25
+ PluginAddRouteInput,
26
+ PluginAddToolInput,
27
+ ConsolePluginRegister,
28
+ ConsoleClientEntry,
29
+ ConsoleEntriesResponse,
30
+ ConsoleEntry,
31
+ ConsoleFileAddEntryInput,
32
+ RuntimeEnv,
33
+ } from "@zhin.js/console-types";
17
34
 
18
- export function cn(...inputs: ClassValue[]) {
19
- return twMerge(clsx(inputs))
20
- }
35
+ export {
36
+ DEFAULT_CONSOLE_BASE_PATH,
37
+ CONSOLE_HOST_REACT_NAMESPACE_KEY,
38
+ } from "@zhin.js/console-types";
39
+
40
+ // Re-export console-core browser utilities
41
+ export {
42
+ createRegistryStore,
43
+ useRegistry,
44
+ type RegistryStore,
45
+ configureConsole,
46
+ getRuntimeEnv,
47
+ cn,
48
+ } from "@zhin.js/console-core/browser";