@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/dist/pages.js ADDED
@@ -0,0 +1,486 @@
1
+ // ============================================================
2
+ // pages.ts — 页面与提示的登记表,以及数据源与动作的服务端闸门
3
+ //
4
+ // 页面与提示按插件实例登记、按条目撤回,页面表变了推 plugins.changed,提示变了推 attention.changed(「需要处理」,见
5
+ // attention.ts);invalidate 按实例、页面、组件与会话合并短时间内的连发;会话面板按会话一次算完
6
+ // 适用的页面。数据源与动作只许调页面声明过的,参数按声明核过再交给插件:会话面板的会话 id 是宿主单独设的字段,调用前
7
+ // 经会话管理核过会话存在;行动作只收 rowKey,插件按它重新查;输入按声明的字段校验类型、必填与可选项,拒收多余的键。
8
+ // 确认框只是界面上的交互,这里的闸门是 owner 身份(路由的 gate)加改状态请求的来源校验(auth.ts)。
9
+ // 路由(routes/pages.ts)只把请求交给这里、把结果写回。插件交来的文字可以是文字对象,由回应的渲染按读者语言换掉
10
+ // (localize.ts):Markdown 正文的字符串参数要转义,插件前端的数据是原样 JSON、不进渲染,这两样随结果交给路由。
11
+ //
12
+ // 插件前端页面登记时另从声明页面的模块往上找插件包根,核 webui/ 目录与入口文件,随机一个 token 记进登记条目:
13
+ // /frames/<token>/ 只托管这一次登记的 webui/(routes/frames.ts),页面撤回或重新登记后旧的 token 就找不到了。
14
+ // 它的数据源按名字分派,输入以 JSON 放在查询参数里,按声明的字段核;返回值要能转成 JSON。
15
+ // ============================================================
16
+ import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
17
+ import { dirname, join, sep } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { isStorageUri } from '@aalis/api-storage';
20
+ import { parseConfig, validateConfig } from '@aalis/schema-config';
21
+ import { isTextError, isTextRef, textClauses, textOf, toSource } from '@aalis/schema-i18n';
22
+ import { checkNotice, checkPage, } from './page-check.js';
23
+ import { issueViews } from './route.js';
24
+ import { t } from './texts.js';
25
+ /** invalidate 的合并窗口:同一实例、页面、组件与会话一秒内最多推一次,窗口里再来的并成窗口结束时的一次 */
26
+ export const INVALIDATE_WINDOW_MS = 1000;
27
+ /** 会话面板的 applies 最多等这么久,超时按不适用处理 */
28
+ export const APPLIES_TIMEOUT_MS = 2000;
29
+ /** Markdown 正文:文字对象的字符串参数按 Markdown 转义 */
30
+ const MARKDOWN = { escape: 'markdown' };
31
+ /** 插件前端的数据是原样 JSON:里面形如文字对象的值不换 */
32
+ const RAW = { skip: () => true };
33
+ /** 闸门拒了这次调用:状态码与给人看的原因 */
34
+ class Refusal extends Error {
35
+ status;
36
+ reason;
37
+ issues;
38
+ constructor(status, reason, issues) {
39
+ super(reason.source);
40
+ this.status = status;
41
+ this.reason = reason;
42
+ this.issues = issues;
43
+ }
44
+ }
45
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
46
+ /** 标识(rowKey、会话 id、节点 id):非空字符串 */
47
+ const isName = (value) => typeof value === 'string' && value !== '';
48
+ /** 给人看的文字:字符串或文字对象 */
49
+ const isText = (value) => typeof value === 'string' || isTextRef(value);
50
+ /** 页面的先后:order 小的在前,没写 order 的排在后面,再按实例与 key */
51
+ const rank = (order) => order ?? Number.MAX_SAFE_INTEGER;
52
+ /** 路径的 realpath;不存在或取不了(含带空字符的路径)回 undefined */
53
+ function realpathOf(path) {
54
+ try {
55
+ return realpathSync(path);
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ /** relative 按 realpath 落在 dir(本身是 realpath)之内时回它的 realpath;不存在或越界(含指向外面的符号链接)回 undefined */
62
+ export function realWithin(dir, relative) {
63
+ const real = realpathOf(join(dir, relative));
64
+ return real?.startsWith(dir + sep) ? real : undefined;
65
+ }
66
+ /** 从 from 往上找最近一个带 name 的 package.json(双格式构建里只写 type 的跳过),它的 name 要等于插件名 */
67
+ function packageRoot(from, plugin) {
68
+ for (let dir = from;; dir = dirname(dir)) {
69
+ const manifest = join(dir, 'package.json');
70
+ if (existsSync(manifest)) {
71
+ let name;
72
+ try {
73
+ name = JSON.parse(readFileSync(manifest, 'utf-8'))?.name;
74
+ }
75
+ catch {
76
+ return { problem: `frame.module:${manifest} 读不出来` };
77
+ }
78
+ if (name !== undefined) {
79
+ return name === plugin
80
+ ? { root: dir }
81
+ : { problem: `frame.module:包根 ${dir} 的 package.json 名为 ${String(name)},不是插件名 ${plugin}` };
82
+ }
83
+ }
84
+ if (dirname(dir) === dir)
85
+ return { problem: `frame.module:从 ${from} 往上找不到带 name 的 package.json` };
86
+ }
87
+ }
88
+ /** 插件前端的 webui/ 目录(realpath):从声明页面的模块找到插件包根,核 webui/ 是目录、入口是它里面的文件 */
89
+ function frameDirOf(frame, instance) {
90
+ let from;
91
+ try {
92
+ from = dirname(fileURLToPath(frame.module));
93
+ }
94
+ catch {
95
+ return { problem: 'frame.module:要是 file: 地址(写 import.meta.url)' };
96
+ }
97
+ // 插件名是实例 id 第一个「:」之前的部分
98
+ const found = packageRoot(from, instance.split(':')[0]);
99
+ if ('problem' in found)
100
+ return found;
101
+ const dir = realpathOf(join(found.root, 'webui'));
102
+ if (!dir || !statSync(dir).isDirectory())
103
+ return { problem: `frame.module:包根 ${found.root} 下没有 webui/ 目录` };
104
+ const entry = realWithin(dir, frame.entry);
105
+ if (!entry || !statSync(entry).isFile()) {
106
+ return { problem: `frame.entry:webui/${frame.entry} 不是 webui/ 里的文件` };
107
+ }
108
+ return { dir };
109
+ }
110
+ export function createPageRegistry(deps) {
111
+ const { logger } = deps;
112
+ const pages = new Map();
113
+ const notices = new Map();
114
+ const windows = new Map();
115
+ const keyOf = (instance, key) => JSON.stringify([instance, key]);
116
+ const sorted = () => [...pages.values()].sort((a, b) => rank(a.definition.order) - rank(b.definition.order) ||
117
+ a.instance.localeCompare(b.instance) ||
118
+ a.definition.key.localeCompare(b.definition.key));
119
+ function entryOf(instance, pageKey) {
120
+ const entry = pages.get(keyOf(instance, pageKey));
121
+ if (!entry)
122
+ throw new Refusal(404, t('pageMissing', { page: pageKey, instance }));
123
+ return entry;
124
+ }
125
+ /** 只许这些键,多余的列出来拒掉 */
126
+ function onlyKeys(value, allowed) {
127
+ const extra = Object.keys(value).filter(key => !allowed.includes(key));
128
+ if (extra.length > 0)
129
+ throw new Refusal(400, t('extraParams', { keys: extra }));
130
+ }
131
+ function requiredName(value, name) {
132
+ if (!isName(value))
133
+ throw new Refusal(400, t('nameRequired', { name }));
134
+ return value;
135
+ }
136
+ /** 调用上下文:会话面板核过会话存在,另给规范化后的会话 id */
137
+ function contextOf(entry, sessionId, ctx) {
138
+ if (entry.checked.placement !== 'session')
139
+ return ctx;
140
+ const session = sessionOf(requiredName(sessionId, 'sessionId'));
141
+ return { ...ctx, sessionId: session.id };
142
+ }
143
+ function sessionOf(sessionId) {
144
+ if (!deps.sessions.present)
145
+ throw new Refusal(503, t('noSessionManager'));
146
+ const session = deps.sessions.use.getSession(sessionId);
147
+ if (!session)
148
+ throw new Refusal(404, t('sessionMissing', { session: sessionId }));
149
+ return session;
150
+ }
151
+ /** 输入按声明的字段校验并解析:拒收多余的键,类型、必填与可选项不对的逐项列出 */
152
+ function inputOf(fields, value) {
153
+ const input = value ?? {};
154
+ if (!isRecord(input))
155
+ throw new Refusal(400, t('inputNotObject'));
156
+ const extra = Object.keys(input).filter(key => !Object.hasOwn(fields, key));
157
+ if (extra.length > 0)
158
+ throw new Refusal(400, t('inputExtraKeys', { keys: extra }));
159
+ const issues = validateConfig(fields, input);
160
+ if (issues.length > 0) {
161
+ const reasons = issues.map(issue => t('inputIssue', { path: issue.path, reason: issue.text }));
162
+ throw new Refusal(400, t('inputInvalid', { issues: textClauses(reasons) }), issues);
163
+ }
164
+ return parseConfig(fields, input);
165
+ }
166
+ /** 插件前端数据源的 input 查询参数:一个 JSON 字符串;没给时按空对象核 */
167
+ function queryInput(value) {
168
+ if (value === undefined)
169
+ return undefined;
170
+ if (typeof value !== 'string')
171
+ throw new Refusal(400, t('inputNotJsonString'));
172
+ try {
173
+ return JSON.parse(value);
174
+ }
175
+ catch {
176
+ throw new Refusal(400, t('inputBadJson'));
177
+ }
178
+ }
179
+ /** 插件前端的数据源返回的值要能转成 JSON,不能的按形状不对处理 */
180
+ function jsonData(entry, source, raw) {
181
+ let text;
182
+ try {
183
+ text = JSON.stringify(raw);
184
+ }
185
+ catch (err) {
186
+ throw breach(entry, source, t('notJson', { error: textOf(err) }));
187
+ }
188
+ if (text === undefined)
189
+ throw breach(entry, source, t('notJsonValue'));
190
+ return raw;
191
+ }
192
+ /** 插件的数据源返回的形状不对:记告警,这一块显示出错 */
193
+ function breach(entry, componentId, problem) {
194
+ const message = t('breach', { source: componentId, problem });
195
+ logger.warn(`页面 ${entry.definition.key}(${entry.instance})的${message.source}`);
196
+ return new Refusal(500, message);
197
+ }
198
+ /** 表格的行:核 rowKey 与 visibleWhen 指名的字段,图片列换成 /api/media 地址,文件列换成下载句柄 */
199
+ function rowsOf(entry, table, raw) {
200
+ if (!Array.isArray(raw))
201
+ throw breach(entry, table.id, t('wantRows'));
202
+ const flags = (table.rowActions ?? []).flatMap(rowAction => rowAction.visibleWhen ?? []);
203
+ const media = table.columns.filter(column => column.kind === 'image' || column.kind === 'file');
204
+ const seen = new Set();
205
+ return raw.map((row, i) => {
206
+ if (!isRecord(row))
207
+ throw breach(entry, table.id, t('rowNotObject', { row: i + 1 }));
208
+ const key = row[table.rowKey];
209
+ if (!isName(key) || seen.has(key)) {
210
+ throw breach(entry, table.id, t('rowKeyInvalid', { row: i + 1, key: table.rowKey }));
211
+ }
212
+ seen.add(key);
213
+ for (const flag of flags) {
214
+ if (typeof row[flag] !== 'boolean')
215
+ throw breach(entry, table.id, t('rowFlagInvalid', { row: i + 1, key: flag }));
216
+ }
217
+ const out = { ...row };
218
+ for (const column of media) {
219
+ const uri = row[column.key];
220
+ if (uri === undefined || uri === null || uri === '')
221
+ continue;
222
+ if (typeof uri !== 'string' || !isStorageUri(uri)) {
223
+ throw breach(entry, table.id, t('rowUriInvalid', { row: i + 1, key: column.key }));
224
+ }
225
+ if (column.kind === 'image')
226
+ out[column.key] = `/api/media?${new URLSearchParams({ uri })}`;
227
+ else {
228
+ const name = uri.slice(uri.lastIndexOf('/') + 1);
229
+ out[column.key] = { name, handle: deps.signFile(uri, name) };
230
+ }
231
+ }
232
+ return out;
233
+ });
234
+ }
235
+ /** 按组件种类核数据源返回的形状 */
236
+ function shaped(entry, source, raw) {
237
+ const component = source.component;
238
+ switch (component.type) {
239
+ case 'table':
240
+ return rowsOf(entry, component, raw);
241
+ case 'markdown':
242
+ if (!isText(raw))
243
+ throw breach(entry, component.id, t('wantText'));
244
+ return raw;
245
+ case 'info':
246
+ if (!Array.isArray(raw) || !raw.every(item => isRecord(item) && isText(item.label))) {
247
+ throw breach(entry, component.id, t('wantInfo'));
248
+ }
249
+ return raw;
250
+ case 'graph': {
251
+ if (!isRecord(raw) || !Array.isArray(raw.nodes) || !Array.isArray(raw.edges)) {
252
+ throw breach(entry, component.id, t('wantGraph'));
253
+ }
254
+ const ids = new Set();
255
+ for (const node of raw.nodes) {
256
+ if (!isRecord(node) || !isName(node.id) || ids.has(node.id) || !isText(node.label)) {
257
+ throw breach(entry, component.id, t('nodeInvalid'));
258
+ }
259
+ ids.add(node.id);
260
+ }
261
+ for (const edge of raw.edges) {
262
+ if (!isRecord(edge) || !ids.has(edge.source) || !ids.has(edge.target)) {
263
+ throw breach(entry, component.id, t('edgeInvalid'));
264
+ }
265
+ }
266
+ return raw;
267
+ }
268
+ }
269
+ }
270
+ /** 跑一次调用:闸门拒的回它的状态码;插件抛的回 500 与原因,挂着文字对象且 status 在 400–599 的(TextError)用它的 status */
271
+ async function guarded(run) {
272
+ try {
273
+ return await run();
274
+ }
275
+ catch (err) {
276
+ if (err instanceof Refusal) {
277
+ return {
278
+ status: err.status,
279
+ body: err.issues ? { error: err.reason, issues: issueViews(err.issues) } : { error: err.reason },
280
+ };
281
+ }
282
+ const status = isTextError(err) ? err.status : undefined;
283
+ const code = typeof status === 'number' && status >= 400 && status < 600 ? status : 500;
284
+ return { status: code, body: { error: textOf(err) } };
285
+ }
286
+ }
287
+ function invalidate(instance, pageKey, componentId, sessionId) {
288
+ const key = JSON.stringify([instance, pageKey, componentId ?? null, sessionId ?? null]);
289
+ const open = windows.get(key);
290
+ if (open) {
291
+ open.again = true;
292
+ return;
293
+ }
294
+ const event = { type: 'page.invalidate', instance, pageKey, componentId, sessionId };
295
+ deps.send(event);
296
+ const slot = {
297
+ again: false,
298
+ timer: setTimeout(function close() {
299
+ if (!slot.again) {
300
+ windows.delete(key);
301
+ return;
302
+ }
303
+ slot.again = false;
304
+ deps.send(event);
305
+ slot.timer = setTimeout(close, INVALIDATE_WINDOW_MS);
306
+ }, INVALIDATE_WINDOW_MS),
307
+ };
308
+ windows.set(key, slot);
309
+ }
310
+ /** 会话面板的 applies:抛错、超时或没回布尔值都按不适用,记一条告警 */
311
+ async function applies(entry, session) {
312
+ const { definition } = entry;
313
+ if (!definition.applies)
314
+ return true;
315
+ let timer;
316
+ try {
317
+ const verdict = await Promise.race([
318
+ Promise.resolve().then(() => definition.applies?.(session)),
319
+ new Promise((_, reject) => {
320
+ timer = setTimeout(() => reject(new Error(`超过 ${APPLIES_TIMEOUT_MS} 毫秒没有答复`)), APPLIES_TIMEOUT_MS);
321
+ }),
322
+ ]);
323
+ if (typeof verdict !== 'boolean')
324
+ throw new Error('没有回布尔值');
325
+ return verdict;
326
+ }
327
+ catch (err) {
328
+ logger.warn(`会话面板页面 ${entry.definition.key}(${entry.instance})的 applies 出错,按不适用处理: ${toSource(textOf(err))}`);
329
+ return false;
330
+ }
331
+ finally {
332
+ clearTimeout(timer);
333
+ }
334
+ }
335
+ return {
336
+ addPage(definition, instance) {
337
+ const refuse = (problems) => {
338
+ logger.error(`页面 ${String(definition?.key)}(${instance})没过登记校验,未登记:${problems.join(';')}`);
339
+ return () => { };
340
+ };
341
+ const result = checkPage(definition);
342
+ if (!result.ok)
343
+ return refuse(result.problems);
344
+ const key = keyOf(instance, definition.key);
345
+ const entry = { instance, definition, checked: result.page };
346
+ if (result.page.kind === 'frame') {
347
+ const { entry: path, host } = result.page.frame;
348
+ const hosted = frameDirOf(result.page.frame, instance);
349
+ if ('problem' in hosted)
350
+ return refuse([hosted.problem]);
351
+ const token = Buffer.from(crypto.getRandomValues(new Uint8Array(16))).toString('base64url');
352
+ const src = `/frames/${token}/${path.split('/').map(encodeURIComponent).join('/')}`;
353
+ entry.frame = { dir: hosted.dir, token, view: { src, host } };
354
+ }
355
+ pages.set(key, entry);
356
+ deps.send({ type: 'plugins.changed' });
357
+ // 插件重载时撤回与重新登记几乎同时,界面多半看不到页面不在的那一刻:打开着的这一页要换成新一次激活的数据
358
+ invalidate(instance, definition.key);
359
+ return () => {
360
+ if (pages.get(key) !== entry)
361
+ return;
362
+ pages.delete(key);
363
+ deps.send({ type: 'plugins.changed' });
364
+ };
365
+ },
366
+ addNotice(notice, instance) {
367
+ const problems = checkNotice(notice, pageKey => pages.get(keyOf(instance, pageKey))?.checked.placement);
368
+ if (problems.length > 0) {
369
+ logger.error(`提示 ${String(notice?.id)}(${instance})没过登记校验,未登记:${problems.join(';')}`);
370
+ return () => { };
371
+ }
372
+ const key = keyOf(instance, notice.id);
373
+ const entry = { instance, notice };
374
+ notices.set(key, entry);
375
+ deps.send({ type: 'attention.changed' });
376
+ return () => {
377
+ if (notices.get(key) !== entry)
378
+ return;
379
+ notices.delete(key);
380
+ deps.send({ type: 'attention.changed' });
381
+ };
382
+ },
383
+ /** 登记着的提示,带所属实例 */
384
+ notices: () => [...notices.values()].map(({ instance, notice }) => ({ instance, ...notice })),
385
+ invalidate,
386
+ /** 页面的位置;没登记的回 undefined */
387
+ placementOf: (ref) => pages.get(keyOf(ref.instance, ref.pageKey))?.checked.placement,
388
+ /** GET /api/pages:声明式页面的声明经 JSON 下发时函数随之去掉;插件前端页面按字段组装,不带模块、入口与数据源 */
389
+ views: () => sorted().map(({ instance, definition, checked, frame }) => frame
390
+ ? {
391
+ instance,
392
+ key: definition.key,
393
+ title: definition.title,
394
+ icon: definition.icon,
395
+ placement: checked.placement,
396
+ order: definition.order,
397
+ ...(checked.actions.size > 0 && { actions: Object.fromEntries(checked.actions) }),
398
+ frame: frame.view,
399
+ }
400
+ : {
401
+ ...definition,
402
+ instance,
403
+ placement: checked.placement,
404
+ }),
405
+ /** 插件前端的 webui/ 目录:token 是这一次登记的;页面撤回或重新登记后旧的找不到 */
406
+ frameDir: (token) => [...pages.values()].find(entry => entry.frame?.token === token)?.frame?.dir,
407
+ /** 这个会话适用的会话面板页面,按页面的先后 */
408
+ panelPages: (sessionId) => guarded(async () => {
409
+ const session = sessionOf(requiredName(sessionId, 'sessionId'));
410
+ const target = { sessionId: session.id, kind: session.kind };
411
+ const candidates = sorted().filter(entry => entry.checked.placement === 'session');
412
+ const verdicts = await Promise.all(candidates.map(entry => applies(entry, target)));
413
+ const refs = candidates
414
+ .filter((_, i) => verdicts[i])
415
+ .map(entry => ({ instance: entry.instance, pageKey: entry.definition.key }));
416
+ return { status: 200, body: { pages: refs } };
417
+ }),
418
+ /**
419
+ * 取一个组件的数据;query 只收 sessionId(会话面板)与 rowKey(详情里的组件)。插件前端页面的 componentId 是数据源名,
420
+ * query 只收 sessionId(会话面板)与 input(声明了输入的数据源)
421
+ */
422
+ data: (instance, pageKey, componentId, query, base) => guarded(async () => {
423
+ const entry = entryOf(instance, pageKey);
424
+ const { checked } = entry;
425
+ if (checked.kind === 'frame') {
426
+ const source = checked.sources.get(componentId);
427
+ if (!source)
428
+ throw new Refusal(404, t('noSource', { page: pageKey, source: componentId }));
429
+ onlyKeys(query, [
430
+ ...(checked.placement === 'session' ? ['sessionId'] : []),
431
+ ...(source.input ? ['input'] : []),
432
+ ]);
433
+ const input = source.input ? inputOf(source.input, queryInput(query.input)) : undefined;
434
+ const ctx = contextOf(entry, query.sessionId, base);
435
+ const data = jsonData(entry, componentId, await source.data({ input, ctx }));
436
+ return { status: 200, body: { data }, render: RAW };
437
+ }
438
+ const source = checked.sources.get(componentId);
439
+ if (!source)
440
+ throw new Refusal(404, t('noComponent', { page: pageKey, component: componentId }));
441
+ onlyKeys(query, [
442
+ ...(entry.checked.placement === 'session' ? ['sessionId'] : []),
443
+ ...(source.inDetail ? ['rowKey'] : []),
444
+ ]);
445
+ const rowKey = source.inDetail ? requiredName(query.rowKey, 'rowKey') : undefined;
446
+ const ctx = contextOf(entry, query.sessionId, base);
447
+ // 详情里的数据源另收 rowKey
448
+ const args = rowKey === undefined ? { ctx } : { ctx, rowKey };
449
+ const body = { data: shaped(entry, source, await source.component.data(args)) };
450
+ return source.component.type === 'markdown' ? { status: 200, body, render: MARKDOWN } : { status: 200, body };
451
+ }),
452
+ /** 调一个动作;body 只收 sessionId(会话面板)、rowKey(行动作)与 input(声明了输入的动作) */
453
+ act: (instance, pageKey, name, body, base, from) => guarded(async () => {
454
+ const entry = entryOf(instance, pageKey);
455
+ const action = entry.checked.actions.get(name);
456
+ if (!action)
457
+ throw new Refusal(404, t('noAction', { page: pageKey, action: name }));
458
+ if (!isRecord(body))
459
+ throw new Refusal(400, t('requestNotObject'));
460
+ onlyKeys(body, [
461
+ ...(entry.checked.placement === 'session' ? ['sessionId'] : []),
462
+ ...(action.row ? ['rowKey'] : []),
463
+ ...(action.input ? ['input'] : []),
464
+ ]);
465
+ const rowKey = action.row ? requiredName(body.rowKey, 'rowKey') : undefined;
466
+ const input = action.input ? inputOf(action.input, body.input) : undefined;
467
+ const ctx = contextOf(entry, body.sessionId, base);
468
+ if (action.effect !== 'read') {
469
+ logger.info(`页面动作 ${name}(${action.effect}):${instance} 的页面 ${pageKey},来自 ${from}`);
470
+ }
471
+ const result = await action.handler(rowKey === undefined ? { input, ctx } : { rowKey, input, ctx });
472
+ if (result !== undefined && !isText(result)) {
473
+ logger.warn(`页面 ${pageKey}(${instance})的动作 ${name} 返回的不是一句话,按失败处理`);
474
+ throw new Refusal(500, t('notASentence', { action: name }));
475
+ }
476
+ return { status: 200, body: result === undefined ? {} : { message: result } };
477
+ }),
478
+ /** 停用时清掉合并窗口的计时器 */
479
+ dispose() {
480
+ for (const { timer } of windows.values())
481
+ clearTimeout(timer);
482
+ windows.clear();
483
+ },
484
+ };
485
+ }
486
+ //# sourceMappingURL=pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../src/pages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ErrorResponse, WebuiFileRoutes, WebuiRestRoutes } from '@aalis/api-webui';
2
+ import type { SchemaIssue } from '@aalis/schema-config';
3
+ import type express from 'express';
4
+ type RouteKey = keyof WebuiRestRoutes | keyof WebuiFileRoutes;
5
+ /** 处理函数能回的:JSON 路由是契约里的回应或失败,文件路由不限 */
6
+ type Reply<K extends RouteKey> = K extends keyof WebuiRestRoutes ? WebuiRestRoutes[K]['response'] | ErrorResponse : unknown;
7
+ /** 路径里的 `:name` 参数,各是一段 */
8
+ type Params<S extends string> = S extends `${string}:${infer Name}/${infer Rest}` ? Record<Name, string> & Params<Rest> : S extends `${string}:${infer Name}` ? Record<Name, string> : Record<never, never>;
9
+ type RouteHandler<K extends RouteKey> = (req: express.Request<Params<K>>, res: express.Response<Reply<K>>, next: express.NextFunction) => unknown;
10
+ /** 校验问题交到 ErrorResponse 里的样子:说明只在 message 一处,取这一项的文字对象,由出口按读者渲染 */
11
+ export declare const issueViews: (issues: readonly SchemaIssue[]) => NonNullable<ErrorResponse["issues"]>;
12
+ export declare function route<K extends RouteKey>(app: express.Express, key: K, ...handlers: RouteHandler<K>[]): void;
13
+ export {};
14
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,KAAK,QAAQ,GAAG,MAAM,eAAe,GAAG,MAAM,eAAe,CAAC;AAE9D,uCAAuC;AACvC,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,SAAS,MAAM,eAAe,GAC5D,eAAe,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,aAAa,GAC9C,OAAO,CAAC;AAEZ,2BAA2B;AAC3B,KAAK,MAAM,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,EAAE,GAC7E,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GACnC,CAAC,SAAS,GAAG,MAAM,IAAI,MAAM,IAAI,EAAE,GACjC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GACpB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3B,KAAK,YAAY,CAAC,CAAC,SAAS,QAAQ,IAAI,CACtC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAC/B,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAC/B,IAAI,EAAE,OAAO,CAAC,YAAY,KACvB,OAAO,CAAC;AAEb,mEAAmE;AACnE,eAAO,MAAM,UAAU,GAAI,QAAQ,SAAS,WAAW,EAAE,KAAG,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CACZ,CAAC;AAEpF,wBAAgB,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAI5G"}
package/dist/route.js ADDED
@@ -0,0 +1,16 @@
1
+ // ============================================================
2
+ // route.ts — 按契约登记路由
3
+ //
4
+ // 路由一律经这里登记,键是 api-webui 管理面 REST 路由表(rest.ts)里的键,方法与路径从键里拆出来交给 express。回 JSON 的
5
+ // 路由,处理函数只能回契约里的回应或 ErrorResponse(服务端交出的形状,文字可以是文字对象,发出前由 localize.ts 渲染),
6
+ // 编译期就核;回文件的不限。都经这里登记由 test/architecture/webui-routes.test.ts 守住,实际登记的与路由表逐条对上由
7
+ // test/plugins/webui-rest-contract.test.ts 守住
8
+ // ============================================================
9
+ /** 校验问题交到 ErrorResponse 里的样子:说明只在 message 一处,取这一项的文字对象,由出口按读者渲染 */
10
+ export const issueViews = (issues) => issues.map(({ path, kind, code, text }) => ({ path, kind, code, message: text }));
11
+ export function route(app, key, ...handlers) {
12
+ const space = key.indexOf(' ');
13
+ const method = key.slice(0, space).toLowerCase();
14
+ app[method](key.slice(space + 1), ...handlers);
15
+ }
16
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,qBAAqB;AACrB,EAAE;AACF,iFAAiF;AACjF,2EAA2E;AAC3E,gFAAgF;AAChF,8CAA8C;AAC9C,+DAA+D;AA0B/D,mEAAmE;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAA8B,EAAwC,EAAE,CACjG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAEpF,MAAM,UAAU,KAAK,CAAqB,GAAoB,EAAE,GAAM,EAAE,GAAG,QAA2B;IACpG,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,EAAuC,CAAC;IACtF,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,GAAI,QAAqC,CAAC,CAAC;AAC/E,CAAC"}
@@ -1,12 +1,11 @@
1
- import type { StorageService } from '@aalis/api-storage';
1
+ import type { SessionProtocolService } from '@aalis/api-session-protocol';
2
+ import { type StorageService } from '@aalis/api-storage';
3
+ import type { Logger, ServiceSelection } from '@aalis/core';
2
4
  import type express from 'express';
3
5
  import type { RouteGate } from '../gate.js';
4
- export interface FileRoutesOptions {
5
- /** storage 服务(必填) */
6
- storage: StorageService;
7
- /** storage 根 ID,默认 workspace */
8
- fileRoot: string;
9
- }
10
- /** 注册文件管理相关 REST 路由 */
11
- export declare function registerFileRoutes(expressApp: express.Express, opts: FileRoutesOptions, gate: RouteGate): void;
6
+ import type { PageFiles } from '../page-files.js';
7
+ export declare function registerFileRoutes(expressApp: express.Express, storage: StorageService, issuers: {
8
+ sessions: Pick<ServiceSelection<SessionProtocolService>, 'present' | 'use'>;
9
+ pages: PageFiles;
10
+ }, logger: Logger, gate: RouteGate): void;
12
11
  //# sourceMappingURL=files.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/routes/files.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAC;IACxB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,uBAAuB;AACvB,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CA2H9G"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/routes/files.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAKlD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,OAAO,CAAC,OAAO,EAC3B,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE;IAAE,QAAQ,EAAE,IAAI,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,EAC1G,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,GACd,IAAI,CAyCN"}