@aalis/plugin-webui-server 0.14.1 → 0.16.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.
Files changed (118) hide show
  1. package/README.md +5 -1
  2. package/dist/admin-channel.d.ts +10 -0
  3. package/dist/admin-channel.d.ts.map +1 -0
  4. package/dist/admin-channel.js +57 -0
  5. package/dist/admin-channel.js.map +1 -0
  6. package/dist/attention.d.ts +36 -0
  7. package/dist/attention.d.ts.map +1 -0
  8. package/dist/attention.js +74 -0
  9. package/dist/attention.js.map +1 -0
  10. package/dist/auth.d.ts +32 -4
  11. package/dist/auth.d.ts.map +1 -1
  12. package/dist/auth.js +253 -79
  13. package/dist/auth.js.map +1 -1
  14. package/dist/client-discovery.d.ts +7 -3
  15. package/dist/client-discovery.d.ts.map +1 -1
  16. package/dist/client-discovery.js +9 -3
  17. package/dist/client-discovery.js.map +1 -1
  18. package/dist/client-switch-page.d.ts +26 -2
  19. package/dist/client-switch-page.d.ts.map +1 -1
  20. package/dist/client-switch-page.js +76 -45
  21. package/dist/client-switch-page.js.map +1 -1
  22. package/dist/gate.d.ts +3 -3
  23. package/dist/gate.d.ts.map +1 -1
  24. package/dist/gate.js +5 -4
  25. package/dist/gate.js.map +1 -1
  26. package/dist/html.d.ts +15 -0
  27. package/dist/html.d.ts.map +1 -0
  28. package/dist/html.js +38 -0
  29. package/dist/html.js.map +1 -0
  30. package/dist/index.d.ts +24 -26
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +627 -1102
  33. package/dist/index.js.map +1 -1
  34. package/dist/layout.d.ts +19 -0
  35. package/dist/layout.d.ts.map +1 -0
  36. package/dist/layout.js +200 -0
  37. package/dist/layout.js.map +1 -0
  38. package/dist/locales/en.d.ts +191 -0
  39. package/dist/locales/en.d.ts.map +1 -0
  40. package/dist/locales/en.js +191 -0
  41. package/dist/locales/en.js.map +1 -0
  42. package/dist/localize.d.ts +24 -0
  43. package/dist/localize.d.ts.map +1 -0
  44. package/dist/localize.js +68 -0
  45. package/dist/localize.js.map +1 -0
  46. package/dist/logs.d.ts +10 -0
  47. package/dist/logs.d.ts.map +1 -0
  48. package/dist/logs.js +50 -0
  49. package/dist/logs.js.map +1 -0
  50. package/dist/page-check.d.ts +56 -0
  51. package/dist/page-check.d.ts.map +1 -0
  52. package/dist/page-check.js +376 -0
  53. package/dist/page-check.js.map +1 -0
  54. package/dist/page-files.d.ts +13 -0
  55. package/dist/page-files.d.ts.map +1 -0
  56. package/dist/page-files.js +39 -0
  57. package/dist/page-files.js.map +1 -0
  58. package/dist/pages.d.ts +62 -0
  59. package/dist/pages.d.ts.map +1 -0
  60. package/dist/pages.js +486 -0
  61. package/dist/pages.js.map +1 -0
  62. package/dist/route.d.ts +14 -0
  63. package/dist/route.d.ts.map +1 -0
  64. package/dist/route.js +16 -0
  65. package/dist/route.js.map +1 -0
  66. package/dist/routes/files.d.ts +8 -9
  67. package/dist/routes/files.d.ts.map +1 -1
  68. package/dist/routes/files.js +33 -119
  69. package/dist/routes/files.js.map +1 -1
  70. package/dist/routes/frames.d.ts +4 -0
  71. package/dist/routes/frames.d.ts.map +1 -0
  72. package/dist/routes/frames.js +103 -0
  73. package/dist/routes/frames.js.map +1 -0
  74. package/dist/routes/i18n.d.ts +20 -0
  75. package/dist/routes/i18n.d.ts.map +1 -0
  76. package/dist/routes/i18n.js +78 -0
  77. package/dist/routes/i18n.js.map +1 -0
  78. package/dist/routes/marketplace.d.ts +46 -129
  79. package/dist/routes/marketplace.d.ts.map +1 -1
  80. package/dist/routes/marketplace.js +156 -106
  81. package/dist/routes/marketplace.js.map +1 -1
  82. package/dist/routes/media.d.ts +10 -0
  83. package/dist/routes/media.d.ts.map +1 -0
  84. package/dist/routes/media.js +66 -0
  85. package/dist/routes/media.js.map +1 -0
  86. package/dist/routes/pages.d.ts +22 -0
  87. package/dist/routes/pages.d.ts.map +1 -0
  88. package/dist/routes/pages.js +104 -0
  89. package/dist/routes/pages.js.map +1 -0
  90. package/dist/routes/pipe-to-response.d.ts +9 -0
  91. package/dist/routes/pipe-to-response.d.ts.map +1 -0
  92. package/dist/routes/pipe-to-response.js +16 -0
  93. package/dist/routes/pipe-to-response.js.map +1 -0
  94. package/dist/routes/plugins.d.ts +22 -28
  95. package/dist/routes/plugins.d.ts.map +1 -1
  96. package/dist/routes/plugins.js +339 -344
  97. package/dist/routes/plugins.js.map +1 -1
  98. package/dist/routes/proxy.d.ts +3 -2
  99. package/dist/routes/proxy.d.ts.map +1 -1
  100. package/dist/routes/proxy.js +64 -42
  101. package/dist/routes/proxy.js.map +1 -1
  102. package/dist/session-transport.d.ts +6 -0
  103. package/dist/session-transport.d.ts.map +1 -0
  104. package/dist/session-transport.js +32 -0
  105. package/dist/session-transport.js.map +1 -0
  106. package/dist/texts.d.ts +381 -0
  107. package/dist/texts.d.ts.map +1 -0
  108. package/dist/texts.js +194 -0
  109. package/dist/texts.js.map +1 -0
  110. package/package.json +38 -32
  111. package/dist/protocol.d.ts +0 -113
  112. package/dist/protocol.d.ts.map +0 -1
  113. package/dist/protocol.js +0 -59
  114. package/dist/protocol.js.map +0 -1
  115. package/dist/routes/uploaded-files.d.ts +0 -20
  116. package/dist/routes/uploaded-files.d.ts.map +0 -1
  117. package/dist/routes/uploaded-files.js +0 -161
  118. package/dist/routes/uploaded-files.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aalis/plugin-webui-server",
3
- "version": "0.14.1",
3
+ "version": "0.16.0",
4
4
  "license": "AGPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "url": "https://github.com/AalisLabs/Aalis/issues"
13
13
  },
14
14
  "homepage": "https://github.com/AalisLabs/Aalis#readme",
15
- "description": "Web 管理界面后端:对话/插件/服务/市场/文件",
15
+ "description": "Web 管理界面后端:会话连接、管理面推送、插件、服务与市场",
16
16
  "type": "module",
17
17
  "keywords": [
18
18
  "aalis",
@@ -24,61 +24,67 @@
24
24
  "dist"
25
25
  ],
26
26
  "dependencies": {
27
- "@aalis/api-agent": ">=0.9.0 <1.0.0",
28
- "@aalis/api-authority": ">=0.10.0 <1.0.0",
29
- "@aalis/api-commands": ">=0.7.0 <1.0.0",
30
- "@aalis/api-llm": ">=0.13.0 <1.0.0",
31
- "@aalis/api-persona": ">=0.8.0 <1.0.0",
32
- "@aalis/api-platform": ">=0.8.0 <1.0.0",
33
- "@aalis/api-process": ">=0.8.0 <1.0.0",
34
- "@aalis/api-session-confirm": ">=0.7.0 <1.0.0",
35
- "@aalis/api-storage": ">=0.7.0 <1.0.0",
36
- "@aalis/api-tools": ">=0.10.0 <1.0.0",
37
- "@aalis/api-webui": ">=0.11.0 <1.0.0",
38
- "@aalis/schema-config": ">=0.14.0 <1.0.0",
27
+ "@aalis/api-approval": ">=0.2.0 <1.0.0",
28
+ "@aalis/api-authority": ">=0.12.0 <1.0.0",
29
+ "@aalis/api-commands": ">=0.9.0 <1.0.0",
30
+ "@aalis/api-doctor": ">=0.9.0 <1.0.0",
31
+ "@aalis/api-i18n": ">=0.1.0 <1.0.0",
32
+ "@aalis/api-llm": ">=0.15.0 <1.0.0",
33
+ "@aalis/api-message-archive": ">=0.9.0 <1.0.0",
34
+ "@aalis/api-platform": ">=0.11.0 <1.0.0",
35
+ "@aalis/api-process": ">=0.10.0 <1.0.0",
36
+ "@aalis/api-session-manager": ">=0.12.0 <1.0.0",
37
+ "@aalis/api-session-protocol": ">=0.2.0 <1.0.0",
38
+ "@aalis/api-storage": ">=0.9.0 <1.0.0",
39
+ "@aalis/api-tools": ">=0.12.0 <1.0.0",
40
+ "@aalis/api-webui": ">=0.13.0 <1.0.0",
41
+ "@aalis/schema-config": ">=0.16.0 <1.0.0",
42
+ "@aalis/schema-i18n": ">=0.1.0 <1.0.0",
43
+ "@aalis/schema-message": ">=0.11.0 <1.0.0",
39
44
  "@aalis/util-dep-spec": ">=0.1.1 <1.0.0",
40
- "@aalis/util-network-guard": ">=0.6.2 <1.0.0",
45
+ "@aalis/util-file-signature": ">=0.1.0 <1.0.0",
46
+ "@aalis/util-network-guard": ">=0.7.0 <1.0.0",
41
47
  "express": "^5.1.0",
42
48
  "ws": "^8.18.0",
43
- "zod": "^3.25.76",
44
- "@aalis/schema-log": ">=0.2.0 <1.0.0",
45
- "@aalis/api-plugin-source": ">=0.1.0 <1.0.0",
46
- "@aalis/api-host-config": ">=0.1.0 <1.0.0",
47
- "@aalis/api-package-manager": ">=0.1.0 <1.0.0"
49
+ "@aalis/api-plugin-source": ">=0.2.0 <1.0.0",
50
+ "@aalis/api-host-config": ">=0.3.0 <1.0.0",
51
+ "@aalis/api-host-logs": ">=0.1.0 <1.0.0",
52
+ "@aalis/api-host-paths": ">=0.1.0 <1.0.0",
53
+ "@aalis/api-package-manager": ">=0.3.0 <1.0.0",
54
+ "@aalis/api-contributions": ">=0.2.0 <1.0.0"
48
55
  },
49
56
  "devDependencies": {
50
57
  "@types/express": "^5.0.0",
51
58
  "@types/node": "^22.0.0",
52
59
  "@types/ws": "^8.5.0",
53
60
  "typescript": "^5.7.0",
54
- "@aalis/api-doctor": "0.7.0",
55
- "@aalis/core": "0.19.1",
56
- "@aalis/api-memory": "0.7.1",
57
- "@aalis/api-session-manager": "0.10.0",
58
- "@aalis/plugin-todo-list": "0.11.2",
59
- "@aalis/schema-message": "0.9.1"
61
+ "@aalis/core": "0.21.0"
60
62
  },
61
63
  "peerDependencies": {
62
- "@aalis/core": ">=0.19.0 <1.0.0"
64
+ "@aalis/core": ">=0.21.0 <1.0.0"
63
65
  },
64
66
  "aalis": {
65
67
  "service": {
66
68
  "optional": [
67
69
  "host-config",
70
+ "host-logs",
71
+ "host-paths",
68
72
  "app",
69
73
  "plugins",
70
74
  "storage",
71
- "authority",
72
75
  "commands",
73
76
  "platform",
74
77
  "process",
75
- "session-confirm",
78
+ "session-protocol",
79
+ "approvals",
80
+ "session-manager",
76
81
  "tools",
77
82
  "llm",
78
- "persona",
79
- "agent",
83
+ "message-archive",
80
84
  "plugin-source",
81
- "package-manager"
85
+ "package-manager",
86
+ "contributions",
87
+ "i18n"
82
88
  ],
83
89
  "provides": [
84
90
  "webui-server",
@@ -1,113 +0,0 @@
1
- /**
2
- * WebUI WebSocket 协议 — 入站消息 zod schema。
3
- *
4
- * 入站消息来自不受信的客户端(浏览器),必须运行时校验。
5
- * 出站消息由服务端构造,TS 类型即可保证形状,运行时不重复校验。
6
- */
7
- import { z } from 'zod';
8
- /**
9
- * 入站消息辨识联合。**所有 WebSocket 入站消息都必须通过此 schema 校验。**
10
- *
11
- * 用法:
12
- * ```ts
13
- * const parsed = WSIncomingSchema.safeParse(JSON.parse(raw));
14
- * if (!parsed.success) { logger.warn('协议违规', parsed.error.issues); return; }
15
- * const msg = parsed.data;
16
- * ```
17
- */
18
- export declare const WSIncomingSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
19
- type: z.ZodLiteral<"message">;
20
- content: z.ZodOptional<z.ZodString>;
21
- sessionId: z.ZodOptional<z.ZodString>;
22
- /** 统一附件列表(image/audio/video/file) */
23
- attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
24
- kind: z.ZodEnum<["image", "audio", "video", "file"]>;
25
- data: z.ZodString;
26
- mimeType: z.ZodOptional<z.ZodString>;
27
- name: z.ZodOptional<z.ZodString>;
28
- byteSize: z.ZodOptional<z.ZodNumber>;
29
- durationSec: z.ZodOptional<z.ZodNumber>;
30
- }, "strip", z.ZodTypeAny, {
31
- data: string;
32
- kind: "image" | "audio" | "video" | "file";
33
- name?: string | undefined;
34
- mimeType?: string | undefined;
35
- byteSize?: number | undefined;
36
- durationSec?: number | undefined;
37
- }, {
38
- data: string;
39
- kind: "image" | "audio" | "video" | "file";
40
- name?: string | undefined;
41
- mimeType?: string | undefined;
42
- byteSize?: number | undefined;
43
- durationSec?: number | undefined;
44
- }>, "many">>;
45
- }, "strip", z.ZodTypeAny, {
46
- type: "message";
47
- sessionId?: string | undefined;
48
- content?: string | undefined;
49
- attachments?: {
50
- data: string;
51
- kind: "image" | "audio" | "video" | "file";
52
- name?: string | undefined;
53
- mimeType?: string | undefined;
54
- byteSize?: number | undefined;
55
- durationSec?: number | undefined;
56
- }[] | undefined;
57
- }, {
58
- type: "message";
59
- sessionId?: string | undefined;
60
- content?: string | undefined;
61
- attachments?: {
62
- data: string;
63
- kind: "image" | "audio" | "video" | "file";
64
- name?: string | undefined;
65
- mimeType?: string | undefined;
66
- byteSize?: number | undefined;
67
- durationSec?: number | undefined;
68
- }[] | undefined;
69
- }>, z.ZodObject<{
70
- type: z.ZodLiteral<"subscribe_logs">;
71
- }, "strip", z.ZodTypeAny, {
72
- type: "subscribe_logs";
73
- }, {
74
- type: "subscribe_logs";
75
- }>, z.ZodObject<{
76
- type: z.ZodLiteral<"subscribe_session">;
77
- sessionId: z.ZodString;
78
- }, "strip", z.ZodTypeAny, {
79
- sessionId: string;
80
- type: "subscribe_session";
81
- }, {
82
- sessionId: string;
83
- type: "subscribe_session";
84
- }>, z.ZodObject<{
85
- type: z.ZodLiteral<"unsubscribe_session">;
86
- sessionId: z.ZodString;
87
- }, "strip", z.ZodTypeAny, {
88
- sessionId: string;
89
- type: "unsubscribe_session";
90
- }, {
91
- sessionId: string;
92
- type: "unsubscribe_session";
93
- }>, z.ZodObject<{
94
- type: z.ZodLiteral<"abort">;
95
- sessionId: z.ZodOptional<z.ZodString>;
96
- }, "strip", z.ZodTypeAny, {
97
- type: "abort";
98
- sessionId?: string | undefined;
99
- }, {
100
- type: "abort";
101
- sessionId?: string | undefined;
102
- }>, z.ZodObject<{
103
- type: z.ZodLiteral<"compress">;
104
- sessionId: z.ZodOptional<z.ZodString>;
105
- }, "strip", z.ZodTypeAny, {
106
- type: "compress";
107
- sessionId?: string | undefined;
108
- }, {
109
- type: "compress";
110
- sessionId?: string | undefined;
111
- }>]>;
112
- export type WSIncoming = z.infer<typeof WSIncomingSchema>;
113
- //# sourceMappingURL=protocol.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuCxB;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB;;;;IAhC3B,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuCrC,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
package/dist/protocol.js DELETED
@@ -1,59 +0,0 @@
1
- /**
2
- * WebUI WebSocket 协议 — 入站消息 zod schema。
3
- *
4
- * 入站消息来自不受信的客户端(浏览器),必须运行时校验。
5
- * 出站消息由服务端构造,TS 类型即可保证形状,运行时不重复校验。
6
- */
7
- import { z } from 'zod';
8
- // ----- 入站(客户端 → 服务端) -----
9
- const AttachmentSchema = z.object({
10
- kind: z.enum(['image', 'audio', 'video', 'file']),
11
- data: z.string(),
12
- mimeType: z.string().optional(),
13
- name: z.string().optional(),
14
- byteSize: z.number().optional(),
15
- durationSec: z.number().optional(),
16
- });
17
- const WSMessageSchema = z.object({
18
- type: z.literal('message'),
19
- content: z.string().optional(),
20
- sessionId: z.string().optional(),
21
- /** 统一附件列表(image/audio/video/file) */
22
- attachments: z.array(AttachmentSchema).optional(),
23
- });
24
- const WSSubscribeLogsSchema = z.object({ type: z.literal('subscribe_logs') });
25
- const WSSubscribeSessionSchema = z.object({
26
- type: z.literal('subscribe_session'),
27
- sessionId: z.string(),
28
- });
29
- const WSUnsubscribeSessionSchema = z.object({
30
- type: z.literal('unsubscribe_session'),
31
- sessionId: z.string(),
32
- });
33
- const WSAbortSchema = z.object({
34
- type: z.literal('abort'),
35
- sessionId: z.string().optional(),
36
- });
37
- const WSCompressSchema = z.object({
38
- type: z.literal('compress'),
39
- sessionId: z.string().optional(),
40
- });
41
- /**
42
- * 入站消息辨识联合。**所有 WebSocket 入站消息都必须通过此 schema 校验。**
43
- *
44
- * 用法:
45
- * ```ts
46
- * const parsed = WSIncomingSchema.safeParse(JSON.parse(raw));
47
- * if (!parsed.success) { logger.warn('协议违规', parsed.error.issues); return; }
48
- * const msg = parsed.data;
49
- * ```
50
- */
51
- export const WSIncomingSchema = z.discriminatedUnion('type', [
52
- WSMessageSchema,
53
- WSSubscribeLogsSchema,
54
- WSSubscribeSessionSchema,
55
- WSUnsubscribeSessionSchema,
56
- WSAbortSchema,
57
- WSCompressSchema,
58
- ]);
59
- //# sourceMappingURL=protocol.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4BAA4B;AAE5B,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACjD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,qCAAqC;IACrC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE;CAClD,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;AAC9E,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACpC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAC;AACH,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAC;AACH,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACxB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC3D,eAAe;IACf,qBAAqB;IACrB,wBAAwB;IACxB,0BAA0B;IAC1B,aAAa;IACb,gBAAgB;CACjB,CAAC,CAAC"}
@@ -1,20 +0,0 @@
1
- import type { StorageService } from '@aalis/api-storage';
2
- import type { Logger } from '@aalis/core';
3
- import type express from 'express';
4
- import type { RouteGate } from '../gate.js';
5
- /** file-reader 的内存索引维护面:删文件后要同步通知它,本包不反向依赖那个插件包,故只描述用到的一角 */
6
- interface FileIndex {
7
- deleteFile?: (id: string) => Promise<boolean>;
8
- }
9
- interface UploadedFilesRoutesOptions {
10
- /** storage 服务(必填)——传入的是 createStorageGateway 的返回值,恒为对象;
11
- * storage 服务缺席时 gateway 各方法内部 dispatch 抛错,而列表路由的内层 catch 会把它
12
- * 吞成空列表(前端看到「没有文件」而非「存储不可用」),download/delete 则落 404 */
13
- storage: StorageService;
14
- logger: Logger;
15
- /** 取当前 file-reader 提供者;每次现取,插件热重载后不留陈旧引用 */
16
- fileIndex(): FileIndex | undefined;
17
- }
18
- export declare function registerUploadedFilesRoutes(expressApp: express.Express, opts: UploadedFilesRoutesOptions, gate: RouteGate): void;
19
- export {};
20
- //# sourceMappingURL=uploaded-files.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"uploaded-files.d.ts","sourceRoot":"","sources":["../../src/routes/uploaded-files.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuB5C,6DAA6D;AAC7D,UAAU,SAAS;IACjB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,UAAU,0BAA0B;IAClC;;4DAEwD;IACxD,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,IAAI,SAAS,GAAG,SAAS,CAAC;CACpC;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,OAAO,CAAC,OAAO,EAC3B,IAAI,EAAE,0BAA0B,EAChC,IAAI,EAAE,SAAS,GACd,IAAI,CAiJN"}
@@ -1,161 +0,0 @@
1
- import path from 'node:path';
2
- const ROOT_PREFIX = 'pluginData:/file-reader';
3
- /** 会话目录名:与 plugin-file-reader 同一套替换(sessionId 含 `:` 时 Windows 文件名不收) */
4
- function sessionDir(sessionId) {
5
- return sessionId.replace(/[:/\\]/g, '_');
6
- }
7
- export function registerUploadedFilesRoutes(expressApp, opts, gate) {
8
- const { storage, logger, fileIndex } = opts;
9
- function isSafeSessionId(s) {
10
- return /^[A-Za-z0-9._:-]{1,128}$/.test(s);
11
- }
12
- function isSafeFileId(s) {
13
- return /^[A-Fa-f0-9]{8,64}$/.test(s);
14
- }
15
- /** 读会话目录下的 meta(数据文件与它同目录);不存在或损坏返回 null */
16
- async function readMeta(dir, fileId) {
17
- try {
18
- const raw = await storage.readFile(`${ROOT_PREFIX}/${dir}/${fileId}.meta.json`);
19
- const text = typeof raw === 'string' ? raw : raw.toString('utf-8');
20
- return JSON.parse(text);
21
- }
22
- catch {
23
- return null;
24
- }
25
- }
26
- /** 列出某 session 下的所有上传文件元信息(不传 sessionId 时列全部 session) */
27
- expressApp.get('/api/uploaded-files', gate(), async (req, res) => {
28
- const sessionId = req.query.sessionId ? String(req.query.sessionId) : undefined;
29
- if (sessionId !== undefined && !isSafeSessionId(sessionId)) {
30
- res.status(400).json({ error: 'sessionId 非法' });
31
- return;
32
- }
33
- try {
34
- const results = [];
35
- const sessions = [];
36
- if (sessionId) {
37
- sessions.push(sessionDir(sessionId));
38
- }
39
- else {
40
- try {
41
- const root = await storage.list(ROOT_PREFIX);
42
- for (const e of root.entries) {
43
- if (e.isDirectory)
44
- sessions.push(e.name);
45
- }
46
- }
47
- catch {
48
- /* 根目录不存在视为空 */
49
- }
50
- }
51
- for (const sid of sessions) {
52
- try {
53
- const list = await storage.list(`${ROOT_PREFIX}/${sid}`);
54
- for (const e of list.entries) {
55
- if (!e.name.endsWith('.meta.json'))
56
- continue;
57
- try {
58
- const raw = await storage.readFile(e.uri);
59
- const text = typeof raw === 'string' ? raw : raw.toString('utf-8');
60
- const meta = JSON.parse(text);
61
- // 不外泄全文缓存
62
- const { textCache: _tc, ...slim } = meta;
63
- results.push(slim);
64
- }
65
- catch (err) {
66
- logger.debug(`读取 meta 失败 ${e.uri}:`, err);
67
- }
68
- }
69
- }
70
- catch {
71
- /* session 目录不存在 */
72
- }
73
- }
74
- results.sort((a, b) => b.uploadedAt - a.uploadedAt);
75
- res.json({ files: results });
76
- }
77
- catch (err) {
78
- logger.warn('列出上传文件失败:', err);
79
- res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
80
- }
81
- });
82
- /** 下载文件 */
83
- expressApp.get('/api/uploaded-files/download', gate(), async (req, res) => {
84
- const sessionId = String(req.query.sessionId || '');
85
- const fileId = String(req.query.fileId || '');
86
- if (!isSafeSessionId(sessionId) || !isSafeFileId(fileId)) {
87
- res.status(400).json({ error: 'sessionId 或 fileId 非法' });
88
- return;
89
- }
90
- const dir = sessionDir(sessionId);
91
- const meta = await readMeta(dir, fileId);
92
- if (!meta) {
93
- res.status(404).json({ error: '文件不存在' });
94
- return;
95
- }
96
- const ext = path.extname(meta.name) || '';
97
- const dataUri = `${ROOT_PREFIX}/${dir}/${fileId}${ext}`;
98
- try {
99
- const result = await storage.createReadStream(dataUri);
100
- res.setHeader('Content-Type', meta.mimeType || 'application/octet-stream');
101
- res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodeURIComponent(meta.name)}`);
102
- res.setHeader('Content-Length', String(result.stat.size));
103
- // 客户端中断(取消下载/关标签页/断网)时 res 触发 'close',而 Node 的 pipe 只 unpipe、
104
- // 不 destroy 源流——fs.ReadStream 会停在 paused 态永不 end,fd 不回收。正常结束时
105
- // destroy 打在已 autoClose 的流上是 no-op,happy path 行为不变。
106
- res.on('close', () => result.stream.destroy());
107
- result.stream.pipe(res);
108
- }
109
- catch (err) {
110
- logger.warn('下载上传文件失败:', err);
111
- res.status(404).json({ error: err instanceof Error ? err.message : String(err) });
112
- }
113
- });
114
- /** 删除文件 */
115
- expressApp.post('/api/uploaded-files/delete', gate(), async (req, res) => {
116
- const body = (req.body ?? {});
117
- const sessionId = body.sessionId ?? '';
118
- const fileId = body.fileId ?? '';
119
- if (!isSafeSessionId(sessionId) || !isSafeFileId(fileId)) {
120
- res.status(400).json({ error: 'sessionId 或 fileId 非法' });
121
- return;
122
- }
123
- const dir = sessionDir(sessionId);
124
- const meta = await readMeta(dir, fileId);
125
- if (!meta) {
126
- res.status(404).json({ error: '文件不存在或已被删除' });
127
- return;
128
- }
129
- const ext = path.extname(meta.name) || '';
130
- const dataUri = `${ROOT_PREFIX}/${dir}/${fileId}${ext}`;
131
- const metaUri = `${ROOT_PREFIX}/${dir}/${fileId}.meta.json`;
132
- const errors = [];
133
- try {
134
- await storage.delete(dataUri);
135
- }
136
- catch (err) {
137
- errors.push(`数据文件: ${err instanceof Error ? err.message : String(err)}`);
138
- }
139
- try {
140
- await storage.delete(metaUri);
141
- }
142
- catch (err) {
143
- errors.push(`meta: ${err instanceof Error ? err.message : String(err)}`);
144
- }
145
- // 同步通知 file-reader 服务把内存索引也清掉
146
- try {
147
- const reader = fileIndex();
148
- if (reader?.deleteFile)
149
- await reader.deleteFile(fileId);
150
- }
151
- catch (err) {
152
- logger.debug('file-reader 索引同步失败:', err);
153
- }
154
- if (errors.length > 0) {
155
- res.status(500).json({ error: errors.join('; ') });
156
- return;
157
- }
158
- res.json({ ok: true, name: meta.name, id: fileId });
159
- });
160
- }
161
- //# sourceMappingURL=uploaded-files.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"uploaded-files.js","sourceRoot":"","sources":["../../src/routes/uploaded-files.ts"],"names":[],"mappings":"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"}