@aalis/plugin-webui-server 0.14.0 → 0.15.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 +5 -1
- package/dist/admin-channel.d.ts +10 -0
- package/dist/admin-channel.d.ts.map +1 -0
- package/dist/admin-channel.js +57 -0
- package/dist/admin-channel.js.map +1 -0
- package/dist/attention.d.ts +36 -0
- package/dist/attention.d.ts.map +1 -0
- package/dist/attention.js +73 -0
- package/dist/attention.js.map +1 -0
- package/dist/auth.d.ts +22 -3
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +192 -68
- package/dist/auth.js.map +1 -1
- package/dist/client-discovery.d.ts +7 -3
- package/dist/client-discovery.d.ts.map +1 -1
- package/dist/client-discovery.js +9 -3
- package/dist/client-discovery.js.map +1 -1
- package/dist/client-switch-page.d.ts +2 -0
- package/dist/client-switch-page.d.ts.map +1 -1
- package/dist/client-switch-page.js +37 -36
- package/dist/client-switch-page.js.map +1 -1
- package/dist/gate.d.ts +3 -3
- package/dist/gate.js +3 -3
- package/dist/index.d.ts +21 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +577 -1018
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +18 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +198 -0
- package/dist/layout.js.map +1 -0
- package/dist/logs.d.ts +10 -0
- package/dist/logs.d.ts.map +1 -0
- package/dist/logs.js +50 -0
- package/dist/logs.js.map +1 -0
- package/dist/page-check.d.ts +56 -0
- package/dist/page-check.d.ts.map +1 -0
- package/dist/page-check.js +369 -0
- package/dist/page-check.js.map +1 -0
- package/dist/page-files.d.ts +13 -0
- package/dist/page-files.d.ts.map +1 -0
- package/dist/page-files.js +39 -0
- package/dist/page-files.js.map +1 -0
- package/dist/pages.d.ts +60 -0
- package/dist/pages.d.ts.map +1 -0
- package/dist/pages.js +470 -0
- package/dist/pages.js.map +1 -0
- package/dist/route.d.ts +11 -0
- package/dist/route.d.ts.map +1 -0
- package/dist/route.js +13 -0
- package/dist/route.js.map +1 -0
- package/dist/routes/files.d.ts +8 -9
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +32 -119
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/frames.d.ts +4 -0
- package/dist/routes/frames.d.ts.map +1 -0
- package/dist/routes/frames.js +103 -0
- package/dist/routes/frames.js.map +1 -0
- package/dist/routes/marketplace.d.ts +46 -129
- package/dist/routes/marketplace.d.ts.map +1 -1
- package/dist/routes/marketplace.js +138 -86
- package/dist/routes/marketplace.js.map +1 -1
- package/dist/routes/media.d.ts +7 -0
- package/dist/routes/media.d.ts.map +1 -0
- package/dist/routes/media.js +63 -0
- package/dist/routes/media.js.map +1 -0
- package/dist/routes/pages.d.ts +20 -0
- package/dist/routes/pages.d.ts.map +1 -0
- package/dist/routes/pages.js +86 -0
- package/dist/routes/pages.js.map +1 -0
- package/dist/routes/pipe-to-response.d.ts +9 -0
- package/dist/routes/pipe-to-response.d.ts.map +1 -0
- package/dist/routes/pipe-to-response.js +16 -0
- package/dist/routes/pipe-to-response.js.map +1 -0
- package/dist/routes/plugins.d.ts +22 -24
- package/dist/routes/plugins.d.ts.map +1 -1
- package/dist/routes/plugins.js +384 -361
- package/dist/routes/plugins.js.map +1 -1
- package/dist/routes/proxy.d.ts.map +1 -1
- package/dist/routes/proxy.js +2 -1
- package/dist/routes/proxy.js.map +1 -1
- package/dist/session-transport.d.ts +6 -0
- package/dist/session-transport.d.ts.map +1 -0
- package/dist/session-transport.js +32 -0
- package/dist/session-transport.js.map +1 -0
- package/package.json +34 -31
- package/dist/protocol.d.ts +0 -113
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -59
- package/dist/protocol.js.map +0 -1
- package/dist/routes/uploaded-files.d.ts +0 -20
- package/dist/routes/uploaded-files.d.ts.map +0 -1
- package/dist/routes/uploaded-files.js +0 -161
- package/dist/routes/uploaded-files.js.map +0 -1
package/dist/pages.js
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
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
|
+
//
|
|
11
|
+
// 插件前端页面登记时另从声明页面的模块往上找插件包根,核 webui/ 目录与入口文件,随机一个 token 记进登记条目:
|
|
12
|
+
// /frames/<token>/ 只托管这一次登记的 webui/(routes/frames.ts),页面撤回或重新登记后旧的 token 就找不到了。
|
|
13
|
+
// 它的数据源按名字分派,输入以 JSON 放在查询参数里,按声明的字段核;返回值要能转成 JSON。
|
|
14
|
+
// ============================================================
|
|
15
|
+
import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
16
|
+
import { dirname, join, sep } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { isStorageUri } from '@aalis/api-storage';
|
|
19
|
+
import { parseConfig, validateConfig } from '@aalis/schema-config';
|
|
20
|
+
import { checkNotice, checkPage, } from './page-check.js';
|
|
21
|
+
/** invalidate 的合并窗口:同一实例、页面、组件与会话一秒内最多推一次,窗口里再来的并成窗口结束时的一次 */
|
|
22
|
+
export const INVALIDATE_WINDOW_MS = 1000;
|
|
23
|
+
/** 会话面板的 applies 最多等这么久,超时按不适用处理 */
|
|
24
|
+
export const APPLIES_TIMEOUT_MS = 2000;
|
|
25
|
+
/** 闸门拒了这次调用:状态码与给人看的原因 */
|
|
26
|
+
class Refusal extends Error {
|
|
27
|
+
status;
|
|
28
|
+
issues;
|
|
29
|
+
constructor(status, message, issues) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.status = status;
|
|
32
|
+
this.issues = issues;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
36
|
+
const isText = (value) => typeof value === 'string' && value !== '';
|
|
37
|
+
const errorText = (err) => (err instanceof Error ? err.message : String(err));
|
|
38
|
+
/** 页面的先后:order 小的在前,没写 order 的排在后面,再按实例与 key */
|
|
39
|
+
const rank = (order) => order ?? Number.MAX_SAFE_INTEGER;
|
|
40
|
+
/** 路径的 realpath;不存在或取不了(含带空字符的路径)回 undefined */
|
|
41
|
+
function realpathOf(path) {
|
|
42
|
+
try {
|
|
43
|
+
return realpathSync(path);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** relative 按 realpath 落在 dir(本身是 realpath)之内时回它的 realpath;不存在或越界(含指向外面的符号链接)回 undefined */
|
|
50
|
+
export function realWithin(dir, relative) {
|
|
51
|
+
const real = realpathOf(join(dir, relative));
|
|
52
|
+
return real?.startsWith(dir + sep) ? real : undefined;
|
|
53
|
+
}
|
|
54
|
+
/** 从 from 往上找最近一个带 name 的 package.json(双格式构建里只写 type 的跳过),它的 name 要等于插件名 */
|
|
55
|
+
function packageRoot(from, plugin) {
|
|
56
|
+
for (let dir = from;; dir = dirname(dir)) {
|
|
57
|
+
const manifest = join(dir, 'package.json');
|
|
58
|
+
if (existsSync(manifest)) {
|
|
59
|
+
let name;
|
|
60
|
+
try {
|
|
61
|
+
name = JSON.parse(readFileSync(manifest, 'utf-8'))?.name;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return { problem: `frame.module:${manifest} 读不出来` };
|
|
65
|
+
}
|
|
66
|
+
if (name !== undefined) {
|
|
67
|
+
return name === plugin
|
|
68
|
+
? { root: dir }
|
|
69
|
+
: { problem: `frame.module:包根 ${dir} 的 package.json 名为 ${String(name)},不是插件名 ${plugin}` };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (dirname(dir) === dir)
|
|
73
|
+
return { problem: `frame.module:从 ${from} 往上找不到带 name 的 package.json` };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** 插件前端的 webui/ 目录(realpath):从声明页面的模块找到插件包根,核 webui/ 是目录、入口是它里面的文件 */
|
|
77
|
+
function frameDirOf(frame, instance) {
|
|
78
|
+
let from;
|
|
79
|
+
try {
|
|
80
|
+
from = dirname(fileURLToPath(frame.module));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { problem: 'frame.module:要是 file: 地址(写 import.meta.url)' };
|
|
84
|
+
}
|
|
85
|
+
// 插件名是实例 id 第一个「:」之前的部分
|
|
86
|
+
const found = packageRoot(from, instance.split(':')[0]);
|
|
87
|
+
if ('problem' in found)
|
|
88
|
+
return found;
|
|
89
|
+
const dir = realpathOf(join(found.root, 'webui'));
|
|
90
|
+
if (!dir || !statSync(dir).isDirectory())
|
|
91
|
+
return { problem: `frame.module:包根 ${found.root} 下没有 webui/ 目录` };
|
|
92
|
+
const entry = realWithin(dir, frame.entry);
|
|
93
|
+
if (!entry || !statSync(entry).isFile()) {
|
|
94
|
+
return { problem: `frame.entry:webui/${frame.entry} 不是 webui/ 里的文件` };
|
|
95
|
+
}
|
|
96
|
+
return { dir };
|
|
97
|
+
}
|
|
98
|
+
export function createPageRegistry(deps) {
|
|
99
|
+
const { logger } = deps;
|
|
100
|
+
const pages = new Map();
|
|
101
|
+
const notices = new Map();
|
|
102
|
+
const windows = new Map();
|
|
103
|
+
const keyOf = (instance, key) => JSON.stringify([instance, key]);
|
|
104
|
+
const sorted = () => [...pages.values()].sort((a, b) => rank(a.definition.order) - rank(b.definition.order) ||
|
|
105
|
+
a.instance.localeCompare(b.instance) ||
|
|
106
|
+
a.definition.key.localeCompare(b.definition.key));
|
|
107
|
+
function entryOf(instance, pageKey) {
|
|
108
|
+
const entry = pages.get(keyOf(instance, pageKey));
|
|
109
|
+
if (!entry)
|
|
110
|
+
throw new Refusal(404, `页面 ${pageKey}(${instance})不存在`);
|
|
111
|
+
return entry;
|
|
112
|
+
}
|
|
113
|
+
/** 只许这些键,多余的列出来拒掉 */
|
|
114
|
+
function onlyKeys(value, allowed) {
|
|
115
|
+
const extra = Object.keys(value).filter(key => !allowed.includes(key));
|
|
116
|
+
if (extra.length > 0)
|
|
117
|
+
throw new Refusal(400, `多余的参数:${extra.join('、')}`);
|
|
118
|
+
}
|
|
119
|
+
function requiredText(value, name) {
|
|
120
|
+
if (!isText(value))
|
|
121
|
+
throw new Refusal(400, `${name} 要是非空字符串`);
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
/** 调用上下文:会话面板核过会话存在,给规范化后的会话 id */
|
|
125
|
+
function contextOf(entry, sessionId, caller) {
|
|
126
|
+
if (entry.checked.placement !== 'session')
|
|
127
|
+
return { caller };
|
|
128
|
+
const session = sessionOf(requiredText(sessionId, 'sessionId'));
|
|
129
|
+
return { caller, sessionId: session.id };
|
|
130
|
+
}
|
|
131
|
+
function sessionOf(sessionId) {
|
|
132
|
+
if (!deps.sessions.present)
|
|
133
|
+
throw new Refusal(503, '会话管理服务不在,会话面板用不了');
|
|
134
|
+
const session = deps.sessions.use.getSession(sessionId);
|
|
135
|
+
if (!session)
|
|
136
|
+
throw new Refusal(404, `会话 ${sessionId} 不存在`);
|
|
137
|
+
return session;
|
|
138
|
+
}
|
|
139
|
+
/** 输入按声明的字段校验并解析:拒收多余的键,类型、必填与可选项不对的逐项列出 */
|
|
140
|
+
function inputOf(fields, value) {
|
|
141
|
+
const input = value ?? {};
|
|
142
|
+
if (!isRecord(input))
|
|
143
|
+
throw new Refusal(400, 'input 要是对象');
|
|
144
|
+
const extra = Object.keys(input).filter(key => !Object.hasOwn(fields, key));
|
|
145
|
+
if (extra.length > 0)
|
|
146
|
+
throw new Refusal(400, `input 里多余的键:${extra.join('、')}`);
|
|
147
|
+
const issues = validateConfig(fields, input);
|
|
148
|
+
if (issues.length > 0) {
|
|
149
|
+
throw new Refusal(400, `输入没过校验:${issues.map(i => `${i.path} ${i.message}`).join(';')}`, issues);
|
|
150
|
+
}
|
|
151
|
+
return parseConfig(fields, input);
|
|
152
|
+
}
|
|
153
|
+
/** 插件前端数据源的 input 查询参数:一个 JSON 字符串;没给时按空对象核 */
|
|
154
|
+
function queryInput(value) {
|
|
155
|
+
if (value === undefined)
|
|
156
|
+
return undefined;
|
|
157
|
+
if (typeof value !== 'string')
|
|
158
|
+
throw new Refusal(400, 'input 要是一个 JSON 字符串');
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(value);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
throw new Refusal(400, 'input 不是合法的 JSON');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** 插件前端的数据源返回的值要能转成 JSON,不能的按形状不对处理 */
|
|
167
|
+
function jsonData(entry, source, raw) {
|
|
168
|
+
let text;
|
|
169
|
+
try {
|
|
170
|
+
text = JSON.stringify(raw);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
throw breach(entry, source, `不能转成 JSON:${errorText(err)}`);
|
|
174
|
+
}
|
|
175
|
+
if (text === undefined)
|
|
176
|
+
throw breach(entry, source, '不能转成 JSON');
|
|
177
|
+
return raw;
|
|
178
|
+
}
|
|
179
|
+
/** 插件的数据源返回的形状不对:记告警,这一块显示出错 */
|
|
180
|
+
function breach(entry, componentId, problem) {
|
|
181
|
+
const message = `数据源 ${componentId} 返回的数据不对:${problem}`;
|
|
182
|
+
logger.warn(`页面 ${entry.definition.key}(${entry.instance})的${message}`);
|
|
183
|
+
return new Refusal(500, message);
|
|
184
|
+
}
|
|
185
|
+
/** 表格的行:核 rowKey 与 visibleWhen 指名的字段,图片列换成 /api/media 地址,文件列换成下载句柄 */
|
|
186
|
+
function rowsOf(entry, table, raw) {
|
|
187
|
+
if (!Array.isArray(raw))
|
|
188
|
+
throw breach(entry, table.id, '要返回行的数组');
|
|
189
|
+
const flags = (table.rowActions ?? []).flatMap(rowAction => rowAction.visibleWhen ?? []);
|
|
190
|
+
const media = table.columns.filter(column => column.kind === 'image' || column.kind === 'file');
|
|
191
|
+
const seen = new Set();
|
|
192
|
+
return raw.map((row, i) => {
|
|
193
|
+
if (!isRecord(row))
|
|
194
|
+
throw breach(entry, table.id, `第 ${i + 1} 行不是对象`);
|
|
195
|
+
const key = row[table.rowKey];
|
|
196
|
+
if (!isText(key) || seen.has(key)) {
|
|
197
|
+
throw breach(entry, table.id, `第 ${i + 1} 行的 ${table.rowKey} 要是不重复的非空字符串`);
|
|
198
|
+
}
|
|
199
|
+
seen.add(key);
|
|
200
|
+
for (const flag of flags) {
|
|
201
|
+
if (typeof row[flag] !== 'boolean')
|
|
202
|
+
throw breach(entry, table.id, `第 ${i + 1} 行的 ${flag} 要是布尔值`);
|
|
203
|
+
}
|
|
204
|
+
const out = { ...row };
|
|
205
|
+
for (const column of media) {
|
|
206
|
+
const uri = row[column.key];
|
|
207
|
+
if (uri === undefined || uri === null || uri === '')
|
|
208
|
+
continue;
|
|
209
|
+
if (typeof uri !== 'string' || !isStorageUri(uri)) {
|
|
210
|
+
throw breach(entry, table.id, `第 ${i + 1} 行的 ${column.key} 要是存储地址`);
|
|
211
|
+
}
|
|
212
|
+
if (column.kind === 'image')
|
|
213
|
+
out[column.key] = `/api/media?${new URLSearchParams({ uri })}`;
|
|
214
|
+
else {
|
|
215
|
+
const name = uri.slice(uri.lastIndexOf('/') + 1);
|
|
216
|
+
out[column.key] = { name, handle: deps.signFile(uri, name) };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/** 按组件种类核数据源返回的形状 */
|
|
223
|
+
function shaped(entry, source, raw) {
|
|
224
|
+
const component = source.component;
|
|
225
|
+
switch (component.type) {
|
|
226
|
+
case 'table':
|
|
227
|
+
return rowsOf(entry, component, raw);
|
|
228
|
+
case 'markdown':
|
|
229
|
+
if (typeof raw !== 'string')
|
|
230
|
+
throw breach(entry, component.id, '要返回字符串');
|
|
231
|
+
return raw;
|
|
232
|
+
case 'info':
|
|
233
|
+
if (!Array.isArray(raw) || !raw.every(item => isRecord(item) && typeof item.label === 'string')) {
|
|
234
|
+
throw breach(entry, component.id, '要返回 { label, value } 的数组');
|
|
235
|
+
}
|
|
236
|
+
return raw;
|
|
237
|
+
case 'graph': {
|
|
238
|
+
if (!isRecord(raw) || !Array.isArray(raw.nodes) || !Array.isArray(raw.edges)) {
|
|
239
|
+
throw breach(entry, component.id, '要返回 { nodes, edges }');
|
|
240
|
+
}
|
|
241
|
+
const ids = new Set();
|
|
242
|
+
for (const node of raw.nodes) {
|
|
243
|
+
if (!isRecord(node) || !isText(node.id) || ids.has(node.id) || typeof node.label !== 'string') {
|
|
244
|
+
throw breach(entry, component.id, '节点要有不重复的 id 与 label');
|
|
245
|
+
}
|
|
246
|
+
ids.add(node.id);
|
|
247
|
+
}
|
|
248
|
+
for (const edge of raw.edges) {
|
|
249
|
+
if (!isRecord(edge) || !ids.has(edge.source) || !ids.has(edge.target)) {
|
|
250
|
+
throw breach(entry, component.id, '边的两端要是节点 id');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return raw;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/** 跑一次调用:闸门拒的回它的状态码,插件抛的回 500 与原因 */
|
|
258
|
+
async function guarded(run) {
|
|
259
|
+
try {
|
|
260
|
+
return await run();
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
if (err instanceof Refusal) {
|
|
264
|
+
return {
|
|
265
|
+
status: err.status,
|
|
266
|
+
body: err.issues ? { error: err.message, issues: err.issues } : { error: err.message },
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return { status: 500, body: { error: errorText(err) } };
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function invalidate(instance, pageKey, componentId, sessionId) {
|
|
273
|
+
const key = JSON.stringify([instance, pageKey, componentId ?? null, sessionId ?? null]);
|
|
274
|
+
const open = windows.get(key);
|
|
275
|
+
if (open) {
|
|
276
|
+
open.again = true;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const event = { type: 'page.invalidate', instance, pageKey, componentId, sessionId };
|
|
280
|
+
deps.send(event);
|
|
281
|
+
const slot = {
|
|
282
|
+
again: false,
|
|
283
|
+
timer: setTimeout(function close() {
|
|
284
|
+
if (!slot.again) {
|
|
285
|
+
windows.delete(key);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
slot.again = false;
|
|
289
|
+
deps.send(event);
|
|
290
|
+
slot.timer = setTimeout(close, INVALIDATE_WINDOW_MS);
|
|
291
|
+
}, INVALIDATE_WINDOW_MS),
|
|
292
|
+
};
|
|
293
|
+
windows.set(key, slot);
|
|
294
|
+
}
|
|
295
|
+
/** 会话面板的 applies:抛错、超时或没回布尔值都按不适用,记一条告警 */
|
|
296
|
+
async function applies(entry, session) {
|
|
297
|
+
const { definition } = entry;
|
|
298
|
+
if (!definition.applies)
|
|
299
|
+
return true;
|
|
300
|
+
let timer;
|
|
301
|
+
try {
|
|
302
|
+
const verdict = await Promise.race([
|
|
303
|
+
Promise.resolve().then(() => definition.applies?.(session)),
|
|
304
|
+
new Promise((_, reject) => {
|
|
305
|
+
timer = setTimeout(() => reject(new Error(`超过 ${APPLIES_TIMEOUT_MS} 毫秒没有答复`)), APPLIES_TIMEOUT_MS);
|
|
306
|
+
}),
|
|
307
|
+
]);
|
|
308
|
+
if (typeof verdict !== 'boolean')
|
|
309
|
+
throw new Error('没有回布尔值');
|
|
310
|
+
return verdict;
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
logger.warn(`会话面板页面 ${entry.definition.key}(${entry.instance})的 applies 出错,按不适用处理: ${errorText(err)}`);
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
clearTimeout(timer);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
addPage(definition, instance) {
|
|
322
|
+
const refuse = (problems) => {
|
|
323
|
+
logger.error(`页面 ${String(definition?.key)}(${instance})没过登记校验,未登记:${problems.join(';')}`);
|
|
324
|
+
return () => { };
|
|
325
|
+
};
|
|
326
|
+
const result = checkPage(definition);
|
|
327
|
+
if (!result.ok)
|
|
328
|
+
return refuse(result.problems);
|
|
329
|
+
const key = keyOf(instance, definition.key);
|
|
330
|
+
const entry = { instance, definition, checked: result.page };
|
|
331
|
+
if (result.page.kind === 'frame') {
|
|
332
|
+
const { entry: path, host } = result.page.frame;
|
|
333
|
+
const hosted = frameDirOf(result.page.frame, instance);
|
|
334
|
+
if ('problem' in hosted)
|
|
335
|
+
return refuse([hosted.problem]);
|
|
336
|
+
const token = Buffer.from(crypto.getRandomValues(new Uint8Array(16))).toString('base64url');
|
|
337
|
+
const src = `/frames/${token}/${path.split('/').map(encodeURIComponent).join('/')}`;
|
|
338
|
+
entry.frame = { dir: hosted.dir, token, view: { src, host } };
|
|
339
|
+
}
|
|
340
|
+
pages.set(key, entry);
|
|
341
|
+
deps.send({ type: 'plugins.changed' });
|
|
342
|
+
// 插件重载时撤回与重新登记几乎同时,界面多半看不到页面不在的那一刻:打开着的这一页要换成新一次激活的数据
|
|
343
|
+
invalidate(instance, definition.key);
|
|
344
|
+
return () => {
|
|
345
|
+
if (pages.get(key) !== entry)
|
|
346
|
+
return;
|
|
347
|
+
pages.delete(key);
|
|
348
|
+
deps.send({ type: 'plugins.changed' });
|
|
349
|
+
};
|
|
350
|
+
},
|
|
351
|
+
addNotice(notice, instance) {
|
|
352
|
+
const problems = checkNotice(notice, pageKey => pages.get(keyOf(instance, pageKey))?.checked.placement);
|
|
353
|
+
if (problems.length > 0) {
|
|
354
|
+
logger.error(`提示 ${String(notice?.id)}(${instance})没过登记校验,未登记:${problems.join(';')}`);
|
|
355
|
+
return () => { };
|
|
356
|
+
}
|
|
357
|
+
const key = keyOf(instance, notice.id);
|
|
358
|
+
const entry = { instance, notice };
|
|
359
|
+
notices.set(key, entry);
|
|
360
|
+
deps.send({ type: 'attention.changed' });
|
|
361
|
+
return () => {
|
|
362
|
+
if (notices.get(key) !== entry)
|
|
363
|
+
return;
|
|
364
|
+
notices.delete(key);
|
|
365
|
+
deps.send({ type: 'attention.changed' });
|
|
366
|
+
};
|
|
367
|
+
},
|
|
368
|
+
/** 登记着的提示,带所属实例 */
|
|
369
|
+
notices: () => [...notices.values()].map(({ instance, notice }) => ({ instance, ...notice })),
|
|
370
|
+
invalidate,
|
|
371
|
+
/** 页面的位置;没登记的回 undefined */
|
|
372
|
+
placementOf: (ref) => pages.get(keyOf(ref.instance, ref.pageKey))?.checked.placement,
|
|
373
|
+
/** GET /api/pages:声明式页面的声明经 JSON 下发时函数随之去掉;插件前端页面按字段组装,不带模块、入口与数据源 */
|
|
374
|
+
views: () => sorted().map(({ instance, definition, checked, frame }) => frame
|
|
375
|
+
? {
|
|
376
|
+
instance,
|
|
377
|
+
key: definition.key,
|
|
378
|
+
title: definition.title,
|
|
379
|
+
icon: definition.icon,
|
|
380
|
+
placement: checked.placement,
|
|
381
|
+
order: definition.order,
|
|
382
|
+
...(checked.actions.size > 0 && { actions: Object.fromEntries(checked.actions) }),
|
|
383
|
+
frame: frame.view,
|
|
384
|
+
}
|
|
385
|
+
: {
|
|
386
|
+
...definition,
|
|
387
|
+
instance,
|
|
388
|
+
placement: checked.placement,
|
|
389
|
+
}),
|
|
390
|
+
/** 插件前端的 webui/ 目录:token 是这一次登记的;页面撤回或重新登记后旧的找不到 */
|
|
391
|
+
frameDir: (token) => [...pages.values()].find(entry => entry.frame?.token === token)?.frame?.dir,
|
|
392
|
+
/** 这个会话适用的会话面板页面,按页面的先后 */
|
|
393
|
+
panelPages: (sessionId) => guarded(async () => {
|
|
394
|
+
const session = sessionOf(requiredText(sessionId, 'sessionId'));
|
|
395
|
+
const target = { sessionId: session.id, kind: session.kind };
|
|
396
|
+
const candidates = sorted().filter(entry => entry.checked.placement === 'session');
|
|
397
|
+
const verdicts = await Promise.all(candidates.map(entry => applies(entry, target)));
|
|
398
|
+
const refs = candidates
|
|
399
|
+
.filter((_, i) => verdicts[i])
|
|
400
|
+
.map(entry => ({ instance: entry.instance, pageKey: entry.definition.key }));
|
|
401
|
+
return { status: 200, body: { pages: refs } };
|
|
402
|
+
}),
|
|
403
|
+
/**
|
|
404
|
+
* 取一个组件的数据;query 只收 sessionId(会话面板)与 rowKey(详情里的组件)。插件前端页面的 componentId 是数据源名,
|
|
405
|
+
* query 只收 sessionId(会话面板)与 input(声明了输入的数据源)
|
|
406
|
+
*/
|
|
407
|
+
data: (instance, pageKey, componentId, query, caller) => guarded(async () => {
|
|
408
|
+
const entry = entryOf(instance, pageKey);
|
|
409
|
+
const { checked } = entry;
|
|
410
|
+
if (checked.kind === 'frame') {
|
|
411
|
+
const source = checked.sources.get(componentId);
|
|
412
|
+
if (!source)
|
|
413
|
+
throw new Refusal(404, `页面 ${pageKey} 没有数据源 ${componentId}`);
|
|
414
|
+
onlyKeys(query, [
|
|
415
|
+
...(checked.placement === 'session' ? ['sessionId'] : []),
|
|
416
|
+
...(source.input ? ['input'] : []),
|
|
417
|
+
]);
|
|
418
|
+
const input = source.input ? inputOf(source.input, queryInput(query.input)) : undefined;
|
|
419
|
+
const ctx = contextOf(entry, query.sessionId, caller);
|
|
420
|
+
return { status: 200, body: { data: jsonData(entry, componentId, await source.data({ input, ctx })) } };
|
|
421
|
+
}
|
|
422
|
+
const source = checked.sources.get(componentId);
|
|
423
|
+
if (!source)
|
|
424
|
+
throw new Refusal(404, `页面 ${pageKey} 没有组件 ${componentId}`);
|
|
425
|
+
onlyKeys(query, [
|
|
426
|
+
...(entry.checked.placement === 'session' ? ['sessionId'] : []),
|
|
427
|
+
...(source.inDetail ? ['rowKey'] : []),
|
|
428
|
+
]);
|
|
429
|
+
const rowKey = source.inDetail ? requiredText(query.rowKey, 'rowKey') : undefined;
|
|
430
|
+
const ctx = contextOf(entry, query.sessionId, caller);
|
|
431
|
+
// 详情里的数据源另收 rowKey
|
|
432
|
+
const args = rowKey === undefined ? { ctx } : { ctx, rowKey };
|
|
433
|
+
const raw = await source.component.data(args);
|
|
434
|
+
return { status: 200, body: { data: shaped(entry, source, raw) } };
|
|
435
|
+
}),
|
|
436
|
+
/** 调一个动作;body 只收 sessionId(会话面板)、rowKey(行动作)与 input(声明了输入的动作) */
|
|
437
|
+
act: (instance, pageKey, name, body, caller, from) => guarded(async () => {
|
|
438
|
+
const entry = entryOf(instance, pageKey);
|
|
439
|
+
const action = entry.checked.actions.get(name);
|
|
440
|
+
if (!action)
|
|
441
|
+
throw new Refusal(404, `页面 ${pageKey} 没有动作 ${name}`);
|
|
442
|
+
if (!isRecord(body))
|
|
443
|
+
throw new Refusal(400, '请求体要是对象');
|
|
444
|
+
onlyKeys(body, [
|
|
445
|
+
...(entry.checked.placement === 'session' ? ['sessionId'] : []),
|
|
446
|
+
...(action.row ? ['rowKey'] : []),
|
|
447
|
+
...(action.input ? ['input'] : []),
|
|
448
|
+
]);
|
|
449
|
+
const rowKey = action.row ? requiredText(body.rowKey, 'rowKey') : undefined;
|
|
450
|
+
const input = action.input ? inputOf(action.input, body.input) : undefined;
|
|
451
|
+
const ctx = contextOf(entry, body.sessionId, caller);
|
|
452
|
+
if (action.effect !== 'read') {
|
|
453
|
+
logger.info(`页面动作 ${name}(${action.effect}):${instance} 的页面 ${pageKey},来自 ${from}`);
|
|
454
|
+
}
|
|
455
|
+
const result = await action.handler(rowKey === undefined ? { input, ctx } : { rowKey, input, ctx });
|
|
456
|
+
if (result !== undefined && typeof result !== 'string') {
|
|
457
|
+
logger.warn(`页面 ${pageKey}(${instance})的动作 ${name} 返回的不是一句话,按失败处理`);
|
|
458
|
+
throw new Refusal(500, `动作 ${name} 返回的不是一句话`);
|
|
459
|
+
}
|
|
460
|
+
return { status: 200, body: result === undefined ? {} : { message: result } };
|
|
461
|
+
}),
|
|
462
|
+
/** 停用时清掉合并窗口的计时器 */
|
|
463
|
+
dispose() {
|
|
464
|
+
for (const { timer } of windows.values())
|
|
465
|
+
clearTimeout(timer);
|
|
466
|
+
windows.clear();
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
//# sourceMappingURL=pages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../src/pages.ts"],"names":[],"mappings":"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"}
|
package/dist/route.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ErrorResponse, WebuiFileRoutes, WebuiRestResponse, WebuiRestRoutes } from '@aalis/api-webui';
|
|
2
|
+
import type express from 'express';
|
|
3
|
+
type RouteKey = keyof WebuiRestRoutes | keyof WebuiFileRoutes;
|
|
4
|
+
/** 处理函数能回的:JSON 路由是契约里的回应或失败,文件路由不限 */
|
|
5
|
+
type Reply<K extends RouteKey> = K extends keyof WebuiRestRoutes ? WebuiRestResponse<K> | ErrorResponse : unknown;
|
|
6
|
+
/** 路径里的 `:name` 参数,各是一段 */
|
|
7
|
+
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>;
|
|
8
|
+
type RouteHandler<K extends RouteKey> = (req: express.Request<Params<K>>, res: express.Response<Reply<K>>, next: express.NextFunction) => unknown;
|
|
9
|
+
export declare function route<K extends RouteKey>(app: express.Express, key: K, ...handlers: RouteHandler<K>[]): void;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC3G,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,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,aAAa,GAAG,OAAO,CAAC;AAElH,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,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,13 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// route.ts — 按契约登记路由
|
|
3
|
+
//
|
|
4
|
+
// 路由一律经这里登记,键是 api-webui 管理面 REST 路由表(rest.ts)里的键,方法与路径从键里拆出来交给 express。回 JSON 的
|
|
5
|
+
// 路由,处理函数只能回契约里的回应或 ErrorResponse,编译期就核;回文件的不限。都经这里登记由 test/architecture/webui-routes.test.ts
|
|
6
|
+
// 守住,实际登记的与路由表逐条对上由 test/plugins/webui-rest-contract.test.ts 守住
|
|
7
|
+
// ============================================================
|
|
8
|
+
export function route(app, key, ...handlers) {
|
|
9
|
+
const space = key.indexOf(' ');
|
|
10
|
+
const method = key.slice(0, space).toLowerCase();
|
|
11
|
+
app[method](key.slice(space + 1), ...handlers);
|
|
12
|
+
}
|
|
13
|
+
//# 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,8FAA8F;AAC9F,gEAAgE;AAChE,+DAA+D;AAuB/D,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"}
|
package/dist/routes/files.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type {
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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":"
|
|
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;AAIlD,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"}
|