@aalis/plugin-webui-server 0.4.1 → 0.5.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/dist/auth.d.ts CHANGED
@@ -3,38 +3,22 @@ import type { Logger } from '@aalis/core';
3
3
  import type { UserIdentity } from '@aalis/plugin-authority-api';
4
4
  import type { ProcessService } from '@aalis/plugin-process-api';
5
5
  import type { RequestHandler } from 'express';
6
- /**
7
- * 账户校验器 —— auth 系统对 authority 服务的最小依赖面。
8
- *
9
- * 以函数注入而非服务引用,调用方应惰性解析(authority 可能晚于 webui-server
10
- * 激活或被热替换)。
11
- */
12
- export interface AccountVerifier {
13
- /** 校验账户密码(无账户/不匹配均 false) */
14
- verify(username: string, password: string): boolean | Promise<boolean>;
15
- /** 是否存在任何可登录账户(决定登录页是否显示账户表单) */
16
- hasAccounts(): boolean;
17
- }
18
6
  export interface AuthSystem {
19
7
  /** Express 中间件:处理 ?token= 重定向、登录端点、未认证拦截、登录页 */
20
8
  middleware: RequestHandler;
21
9
  /** 校验 WebSocket 升级请求是否已认证(cookie 读取) */
22
10
  verifyWsClient(req: IncomingMessage): boolean;
23
- /**
24
- * 解析请求的调用者身份:账户 session → `webui:<username>`;
25
- * 单 token 模式 → `webui:console`(owner 级,单人模式语义);未认证 → undefined。
26
- */
11
+ /** 解析调用者身份:单 token 模式 → `webui:console`(owner 级,单人语义);未认证 → undefined。 */
27
12
  identify(req: Pick<IncomingMessage, 'headers'>): UserIdentity | undefined;
28
13
  }
29
14
  /**
30
- * 创建认证系统:账户 session + 单 token 双模式。
15
+ * 创建单 token 认证系统(单 owner)。
31
16
  *
32
- * - 账户登录(username/password)→ 服务端随机 session(内存表,重启失效),
33
- * cookie `aalis_webui_session`,身份为 `webui:<username>`
34
- * - token 登录(向后兼容的单人模式)→ cookie `aalis_webui_token`,身份 `webui:console`
35
- * - 两者并存时 session 身份优先
17
+ * - token 由调用方传入(参见 index.ts resolveAuthToken,支持 ephemeral / persist / fixed 三种模式)
18
+ * - HttpOnly + SameSite=Strict cookie;`?token=` 一键登录;同源 POST /api/auth/login 提交
19
+ * - 身份恒为 `webui:console`(owner 级,单人模式语义)
36
20
  */
37
- export declare function createAuthSystem(token: string, logger: Logger, accounts?: AccountVerifier, tokenLogin?: () => boolean): AuthSystem;
21
+ export declare function createAuthSystem(token: string, _logger: Logger): AuthSystem;
38
22
  /**
39
23
  * 跨平台打开默认浏览器到指定 URL(无外部依赖)
40
24
  * 失败静默;此为便利功能,不影响服务启动。
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAuG9C;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvE,iCAAiC;IACjC,WAAW,IAAI,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,gDAAgD;IAChD,UAAU,EAAE,cAAc,CAAC;IAC3B,wCAAwC;IACxC,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC;IAC9C;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,YAAY,GAAG,SAAS,CAAC;CAC3E;AAWD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,eAAe,EAC1B,UAAU,GAAE,MAAM,OAAoB,GACrC,UAAU,CAwJZ;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAenE"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA0E9C,MAAM,WAAW,UAAU;IACzB,gDAAgD;IAChD,UAAU,EAAE,cAAc,CAAC;IAC3B,wCAAwC;IACxC,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC;IAC9C,0EAA0E;IAC1E,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,YAAY,GAAG,SAAS,CAAC;CAC3E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CA+E3E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAenE"}
package/dist/auth.js CHANGED
@@ -1,5 +1,4 @@
1
1
  const TOKEN_COOKIE = 'aalis_webui_token';
2
- const SESSION_COOKIE = 'aalis_webui_session';
3
2
  function parseCookieValue(header, name) {
4
3
  if (!header)
5
4
  return undefined;
@@ -25,29 +24,9 @@ function buildSetCookie(name, value, maxAgeSec) {
25
24
  function buildClearCookie(name) {
26
25
  return `${name}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`;
27
26
  }
28
- /**
29
- * 登录页:自包含 HTML,不引入外部资源。
30
- *
31
- * 存在账户时默认显示「账户登录」表单(用户名+密码),token 登录折叠为次选
32
- * (tokenMode=disabled 时整体隐藏);无账户时只显示 token 表单(兜底,防锁死)。
33
- * 两种提交都打 POST /api/auth/login。
34
- */
35
- function loginPageHtml(hasAccounts, showToken, reason) {
27
+ /** 登录页:自包含 HTML,不引入外部资源;提交 POST /api/auth/login 后刷新到 / */
28
+ function loginPageHtml(reason) {
36
29
  const note = reason ? `<p class="note">${escapeHtml(reason)}</p>` : '';
37
- const tokenDetails = showToken
38
- ? `<details style="margin-top:14px"><summary>使用访问 token 登录</summary>
39
- <input id="t" type="password" autocomplete="off" placeholder="访问 token" style="margin-top:8px">
40
- <button type="button" id="tb" style="background:#2a3038">Token 登录</button>
41
- </details>`
42
- : '';
43
- const accountForm = hasAccounts
44
- ? `<input id="u" type="text" autocomplete="username" placeholder="用户名" autofocus required>
45
- <input id="p" type="password" autocomplete="current-password" placeholder="密码" required style="margin-top:8px">
46
- <button type="submit" id="b">登录</button>
47
- ${tokenDetails}`
48
- : `<p>请输入启动日志或 data/webui/access.txt 中显示的访问 token。</p>
49
- <input id="t" type="password" autocomplete="off" placeholder="访问 token" autofocus required>
50
- <button type="submit" id="b">登录</button>`;
51
30
  return `<!DOCTYPE html><html lang="zh-CN"><head>
52
31
  <meta charset="utf-8"><title>Aalis WebUI 登录</title>
53
32
  <meta name="viewport" content="width=device-width,initial-scale=1">
@@ -59,155 +38,68 @@ body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:c
59
38
  h1{margin:0 0 8px;font-size:22px;font-weight:600}
60
39
  p{margin:0 0 16px;color:#8b95a1;font-size:14px;line-height:1.5}
61
40
  p.note{color:#ffb300}
62
- summary{color:#8b95a1;font-size:13px;cursor:pointer}
63
41
  input{width:100%;padding:10px 12px;font-size:14px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;background:#0b0d10;color:#e6e8eb;border:1px solid #2a3038;border-radius:6px;outline:none}
64
42
  input:focus{border-color:#5b8def}
65
43
  button{width:100%;margin-top:12px;padding:10px;font-size:14px;font-weight:500;background:#5b8def;color:#fff;border:0;border-radius:6px;cursor:pointer}
66
- button:hover{filter:brightness(1.08)}
44
+ button:hover{background:#4a7de0}
67
45
  button:disabled{opacity:.5;cursor:wait}
68
46
  .err{margin-top:10px;color:#ff6b6b;font-size:13px;min-height:18px}
69
47
  </style></head>
70
48
  <body><form class="card" id="f">
71
49
  <h1>Aalis WebUI</h1>
50
+ <p>请输入启动日志或 data/webui/access.txt 中显示的访问 token。</p>
72
51
  ${note}
73
- ${accountForm}
52
+ <input id="t" type="password" autocomplete="off" placeholder="访问 token" autofocus required>
53
+ <button type="submit" id="b">登录</button>
74
54
  <div class="err" id="e"></div>
75
55
  </form>
76
56
  <script>
77
- const $=id=>document.getElementById(id);
78
- const f=$('f'),e=$('e');
79
- async function login(body,btn){
80
- e.textContent='';btn.disabled=true;
57
+ const f=document.getElementById('f'),t=document.getElementById('t'),b=document.getElementById('b'),e=document.getElementById('e');
58
+ f.addEventListener('submit',async ev=>{
59
+ ev.preventDefault();e.textContent='';b.disabled=true;
81
60
  try{
82
- const r=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
83
- if(r.ok){location.replace('/');}else{const j=await r.json().catch(()=>({}));e.textContent=j.error||'登录失败';btn.disabled=false;}
84
- }catch(err){e.textContent='网络错误';btn.disabled=false;}
85
- }
86
- f.addEventListener('submit',ev=>{
87
- ev.preventDefault();
88
- const u=$('u'),t=$('t');
89
- if(u&&u.value.trim()){login({username:u.value.trim(),password:$('p').value},$('b'));}
90
- else if(t&&t.value.trim()){login({token:t.value.trim()},$('b'));}
61
+ const r=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token:t.value.trim()})});
62
+ if(r.ok){location.replace('/');}else{const j=await r.json().catch(()=>({}));e.textContent=j.error||'token 不正确';b.disabled=false;t.select();}
63
+ }catch(err){e.textContent='网络错误';b.disabled=false;}
91
64
  });
92
- const tb=$('tb');
93
- if(tb)tb.addEventListener('click',()=>{const t=$('t');if(t.value.trim())login({token:t.value.trim()},tb);});
94
65
  </script></body></html>`;
95
66
  }
96
67
  function escapeHtml(s) {
97
68
  return s.replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]);
98
69
  }
99
- const MAX_FAILURES = 5;
100
- const LOCK_MS = 60_000;
101
70
  /**
102
- * 创建认证系统:账户 session + 单 token 双模式。
71
+ * 创建单 token 认证系统(单 owner)。
103
72
  *
104
- * - 账户登录(username/password)→ 服务端随机 session(内存表,重启失效),
105
- * cookie `aalis_webui_session`,身份为 `webui:<username>`
106
- * - token 登录(向后兼容的单人模式)→ cookie `aalis_webui_token`,身份 `webui:console`
107
- * - 两者并存时 session 身份优先
73
+ * - token 由调用方传入(参见 index.ts resolveAuthToken,支持 ephemeral / persist / fixed 三种模式)
74
+ * - HttpOnly + SameSite=Strict cookie;`?token=` 一键登录;同源 POST /api/auth/login 提交
75
+ * - 身份恒为 `webui:console`(owner 级,单人模式语义)
108
76
  */
109
- export function createAuthSystem(token, logger, accounts, tokenLogin = () => true) {
110
- const cookieMaxAge = 30 * 24 * 3600; // 30d;进程重启 token 轮换/session 表清空后无效
111
- const sessions = new Map();
112
- const failures = new Map();
113
- /** token 登录是否可用:宿主开关(tokenMode!=disabled)|| 无账户兜底(防锁死) */
114
- function tokenAllowed() {
115
- return tokenLogin() || !(accounts?.hasAccounts() ?? false);
116
- }
117
- function newSession(username) {
118
- // 顺带清扫过期 session(登录是低频操作,无需独立 timer——审计 MEDIUM #10)
119
- const now = Date.now();
120
- for (const [id, s] of sessions)
121
- if (s.expiresAt <= now)
122
- sessions.delete(id);
123
- const id = Buffer.from(crypto.getRandomValues(new Uint8Array(24))).toString('hex');
124
- sessions.set(id, { username, expiresAt: now + cookieMaxAge * 1000 });
125
- return id;
126
- }
127
- function sessionUser(req) {
128
- const id = parseCookieValue(req.headers.cookie, SESSION_COOKIE);
129
- if (!id)
130
- return undefined;
131
- const s = sessions.get(id);
132
- if (!s)
133
- return undefined;
134
- if (s.expiresAt <= Date.now()) {
135
- sessions.delete(id);
136
- return undefined;
137
- }
138
- return s.username;
139
- }
77
+ export function createAuthSystem(token, _logger) {
78
+ const cookieMaxAge = 30 * 24 * 3600; // 30d;进程重启 token 轮换后无效
140
79
  function tokenAuthed(req) {
141
- if (!tokenAllowed())
142
- return false;
143
80
  const cookieToken = parseCookieValue(req.headers.cookie, TOKEN_COOKIE);
144
81
  return !!cookieToken && cookieToken === token;
145
82
  }
146
83
  function identify(req) {
147
- const username = sessionUser(req);
148
- if (username)
149
- return { platform: 'webui', userId: username };
150
- if (tokenAuthed(req))
151
- return { platform: 'webui', userId: 'console' };
152
- return undefined;
153
- }
154
- function checkLocked(username) {
155
- const rec = failures.get(username);
156
- return !!rec && rec.count >= MAX_FAILURES && rec.lockedUntil > Date.now();
157
- }
158
- function recordFailure(username) {
159
- const rec = failures.get(username);
160
- if (rec && rec.lockedUntil > Date.now()) {
161
- rec.count += 1;
162
- rec.lockedUntil = Date.now() + LOCK_MS;
163
- }
164
- else {
165
- failures.set(username, { count: 1, lockedUntil: Date.now() + LOCK_MS });
166
- }
84
+ return tokenAuthed(req) ? { platform: 'webui', userId: 'console' } : undefined;
167
85
  }
168
- const middleware = async (req, res, next) => {
86
+ const middleware = (req, res, next) => {
169
87
  const url = req.path;
170
88
  const qToken = typeof req.query?.token === 'string' ? req.query.token : undefined;
171
- const hasAccounts = accounts?.hasAccounts() ?? false;
172
89
  // 1. ?token= 命中 → 设置 cookie → 302 到不带 query 的同路径
173
- if (req.method === 'GET' && qToken && tokenAllowed()) {
90
+ if (req.method === 'GET' && qToken) {
174
91
  if (qToken === token) {
175
92
  res.setHeader('Set-Cookie', buildSetCookie(TOKEN_COOKIE, token, cookieMaxAge));
176
93
  res.redirect(302, url);
177
94
  return;
178
95
  }
179
- // ?token 错误:落到登录页(不向 next 透)
180
- res
181
- .status(401)
182
- .type('html')
183
- .send(loginPageHtml(hasAccounts, true, 'URL 中的 token 不正确,请手动输入。'));
96
+ res.status(401).type('html').send(loginPageHtml('URL 中的 token 不正确,请手动输入。'));
184
97
  return;
185
98
  }
186
- // 2. 登录端点:{username, password}(账户)或 {token}(单人模式)
99
+ // 2. 登录端点:{token}
187
100
  if (url === '/api/auth/login' && req.method === 'POST') {
188
101
  const body = req.body ?? {};
189
- if (typeof body.username === 'string' && typeof body.password === 'string') {
190
- const username = body.username.trim();
191
- if (checkLocked(username)) {
192
- res.status(429).json({ ok: false, error: '尝试次数过多,请稍后再试' });
193
- return;
194
- }
195
- if (username && (await accounts?.verify(username, body.password))) {
196
- failures.delete(username);
197
- res.setHeader('Set-Cookie', buildSetCookie(SESSION_COOKIE, newSession(username), cookieMaxAge));
198
- logger.info(`账户登录: webui:${username}`);
199
- res.json({ ok: true, identity: { platform: 'webui', userId: username } });
200
- }
201
- else {
202
- recordFailure(username);
203
- res.status(401).json({ ok: false, error: '用户名或密码不正确' });
204
- }
205
- return;
206
- }
207
- if (typeof body.token === 'string' && !tokenAllowed()) {
208
- res.status(401).json({ ok: false, error: 'token 登录已禁用,请使用账户密码' });
209
- }
210
- else if (typeof body.token === 'string' && body.token === token) {
102
+ if (typeof body.token === 'string' && body.token === token) {
211
103
  res.setHeader('Set-Cookie', buildSetCookie(TOKEN_COOKIE, token, cookieMaxAge));
212
104
  res.json({ ok: true, identity: { platform: 'webui', userId: 'console' } });
213
105
  }
@@ -222,17 +114,14 @@ export function createAuthSystem(token, logger, accounts, tokenLogin = () => tru
222
114
  res.json({ authed: !!identity, identity });
223
115
  return;
224
116
  }
225
- // 4. 注销:清 session 记录与两种 cookie
117
+ // 4. 注销:清 token cookie
226
118
  if (url === '/api/auth/logout' && req.method === 'POST') {
227
- const sid = parseCookieValue(req.headers.cookie, SESSION_COOKIE);
228
- if (sid)
229
- sessions.delete(sid);
230
- res.setHeader('Set-Cookie', [buildClearCookie(SESSION_COOKIE), buildClearCookie(TOKEN_COOKIE)]);
119
+ res.setHeader('Set-Cookie', buildClearCookie(TOKEN_COOKIE));
231
120
  res.json({ ok: true });
232
121
  return;
233
122
  }
234
123
  // 5. 已认证 → 放行
235
- if (identify(req)) {
124
+ if (tokenAuthed(req)) {
236
125
  next();
237
126
  return;
238
127
  }
@@ -243,13 +132,13 @@ export function createAuthSystem(token, logger, accounts, tokenLogin = () => tru
243
132
  }
244
133
  // 7. 未认证 GET:返回内联登录页(覆盖 SPA shell,不暴露任何静态资源)
245
134
  if (req.method === 'GET') {
246
- res.status(401).type('html').send(loginPageHtml(hasAccounts, tokenAllowed()));
135
+ res.status(401).type('html').send(loginPageHtml());
247
136
  return;
248
137
  }
249
138
  res.status(401).end();
250
139
  };
251
140
  function verifyWsClient(req) {
252
- return !!identify(req);
141
+ return tokenAuthed(req);
253
142
  }
254
143
  return { middleware, verifyWsClient, identify };
255
144
  }
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ interface ClientCandidate {
2
+ id: string;
3
+ label: string;
4
+ dir: string;
5
+ }
6
+ export interface DiscoveryEnv {
7
+ existsSync: (p: string) => boolean;
8
+ /** 读目录子项;不可读返回 [] */
9
+ readdirSync: (p: string) => string[];
10
+ /** 读 + parse JSON;失败返回 undefined */
11
+ readJson: (p: string) => unknown;
12
+ join: (...parts: string[]) => string;
13
+ dirname: (p: string) => string;
14
+ /** 把 deps 包名解析到其 package.json 路径;失败返回 undefined */
15
+ resolvePkgJson: (id: string) => string | undefined;
16
+ }
17
+ /**
18
+ * 发现所有前端包:在 scanDirs 各目录下逐子目录、以及 depIds(项目根 deps)里,收录 package.json
19
+ * 标了 `aalis.client:true` 且其 `dist/index.html` 存在的包。按包名去重,再按 id 排序(确定性输出)。
20
+ * 默认活跃前端由调用方按 config 或「排序后第一个」决定——本函数不做偏好判断、不认任何具体名字。
21
+ */
22
+ export declare function discoverClients(scanDirs: string[], depIds: string[], env: DiscoveryEnv): ClientCandidate[];
23
+ /**
24
+ * 扫描本地物理存在的包 → `name → 依赖名[]`(与 discoverClients 共用 scanDirs/env)。
25
+ * 两用,一次扫盘:① keys 即「本地已装包名」,补市场已装判定(require.resolve 在 pnpm 工作区
26
+ * 从仓库根解析不到未提升的工作区包);② values 即各包 `dependencies/peer/optional` 的并集名单,
27
+ * 供依赖图(谁依赖谁)。**只取依赖名、不看版本区间**(`workspace:^`/`^1.0.0` 一律按名),故无需 semver。
28
+ * scope 无关(不挑 @aalis)。纯函数便于单测。
29
+ */
30
+ export declare function collectLocalPackageDeps(scanDirs: string[], env: Pick<DiscoveryEnv, 'existsSync' | 'readdirSync' | 'readJson' | 'join'>): Map<string, string[]>;
31
+ export {};
32
+ //# sourceMappingURL=client-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-discovery.d.ts","sourceRoot":"","sources":["../src/client-discovery.ts"],"names":[],"mappings":"AAMA,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,qBAAqB;IACrB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACrC,oCAAoC;IACpC,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACjC,IAAI,EAAE,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,mDAAmD;IACnD,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CACpD;AASD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,YAAY,GAAG,eAAe,EAAE,CA2B1G;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAAE,EAClB,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,aAAa,GAAG,UAAU,GAAG,MAAM,CAAC,GAC1E,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAuBvB"}
@@ -0,0 +1,67 @@
1
+ // 全动态前端发现(纯逻辑,注入 fs/path 便于单测)。
2
+ //
3
+ // 按 `aalis.client:true` 标记 + 存在 `dist/index.html` 收录前端候选——**不硬编码任何前端包名**,
4
+ // 与 runtime 加载器的 marker 驱动一致(忒修斯之船:任意第三方前端,带标记+dist 即被发现)。
5
+ // 覆盖三种拓扑:monorepo(扫 packages 同级目录)/ 独立项目(扫 node_modules/@aalis 作用域 + 根 deps)。
6
+ /**
7
+ * 发现所有前端包:在 scanDirs 各目录下逐子目录、以及 depIds(项目根 deps)里,收录 package.json
8
+ * 标了 `aalis.client:true` 且其 `dist/index.html` 存在的包。按包名去重,再按 id 排序(确定性输出)。
9
+ * 默认活跃前端由调用方按 config 或「排序后第一个」决定——本函数不做偏好判断、不认任何具体名字。
10
+ */
11
+ export function discoverClients(scanDirs, depIds, env) {
12
+ const out = [];
13
+ const seen = new Set();
14
+ const consider = (pkgJsonPath) => {
15
+ if (!pkgJsonPath || !env.existsSync(pkgJsonPath))
16
+ return;
17
+ const pkg = env.readJson(pkgJsonPath);
18
+ if (!pkg || pkg.aalis?.client !== true || typeof pkg.name !== 'string' || seen.has(pkg.name))
19
+ return;
20
+ const dir = env.join(env.dirname(pkgJsonPath), 'dist');
21
+ if (!env.existsSync(env.join(dir, 'index.html')))
22
+ return;
23
+ seen.add(pkg.name);
24
+ const label = (typeof pkg.displayName === 'string' && pkg.displayName) ||
25
+ (typeof pkg.description === 'string' && pkg.description) ||
26
+ pkg.name;
27
+ out.push({ id: pkg.name, label, dir });
28
+ };
29
+ // ① 扫描目录:monorepo 的 packages 同级目录 / 独立项目的 node_modules/@aalis 作用域
30
+ for (const base of scanDirs) {
31
+ if (!env.existsSync(base))
32
+ continue;
33
+ for (const entry of env.readdirSync(base))
34
+ consider(env.join(base, entry, 'package.json'));
35
+ }
36
+ // ② 第三方前端:项目根 deps 里按包名解析(覆盖独立项目把第三方 client 列为 dep 的情形)
37
+ for (const id of depIds)
38
+ consider(env.resolvePkgJson(id));
39
+ return out.sort((a, b) => a.id.localeCompare(b.id));
40
+ }
41
+ /**
42
+ * 扫描本地物理存在的包 → `name → 依赖名[]`(与 discoverClients 共用 scanDirs/env)。
43
+ * 两用,一次扫盘:① keys 即「本地已装包名」,补市场已装判定(require.resolve 在 pnpm 工作区
44
+ * 从仓库根解析不到未提升的工作区包);② values 即各包 `dependencies/peer/optional` 的并集名单,
45
+ * 供依赖图(谁依赖谁)。**只取依赖名、不看版本区间**(`workspace:^`/`^1.0.0` 一律按名),故无需 semver。
46
+ * scope 无关(不挑 @aalis)。纯函数便于单测。
47
+ */
48
+ export function collectLocalPackageDeps(scanDirs, env) {
49
+ const out = new Map();
50
+ for (const base of scanDirs) {
51
+ if (!env.existsSync(base))
52
+ continue;
53
+ for (const entry of env.readdirSync(base)) {
54
+ const pkg = env.readJson(env.join(base, entry, 'package.json'));
55
+ if (!pkg || typeof pkg.name !== 'string')
56
+ continue;
57
+ const deps = new Set([
58
+ ...Object.keys(pkg.dependencies ?? {}),
59
+ ...Object.keys(pkg.peerDependencies ?? {}),
60
+ ...Object.keys(pkg.optionalDependencies ?? {}),
61
+ ]);
62
+ out.set(pkg.name, [...deps]);
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+ //# sourceMappingURL=client-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-discovery.js","sourceRoot":"","sources":["../src/client-discovery.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,0EAA0E;AAC1E,2DAA2D;AAC3D,8EAA8E;AA2B9E;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAkB,EAAE,MAAgB,EAAE,GAAiB;IACrF,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,MAAM,QAAQ,GAAG,CAAC,WAA+B,EAAQ,EAAE;QACzD,IAAI,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO;QACzD,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAwB,CAAC;QAC7D,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QACrG,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;QACvD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAAE,OAAO;QACzD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,MAAM,KAAK,GACT,CAAC,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC;YACxD,CAAC,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC;QACX,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;IAEF,kEAAkE;IAClE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACpC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;IAC7F,CAAC;IACD,wDAAwD;IACxD,KAAK,MAAM,EAAE,IAAI,MAAM;QAAE,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC;IAE1D,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAAkB,EAClB,GAA2E;IAE3E,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACpC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,CAAC,CAOjD,CAAC;YACd,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;gBAAE,SAAS;YACnD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS;gBAC3B,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;gBACtC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;gBAC1C,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;aAC/C,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** 渲染前端切换恢复页的完整 HTML 文档(无运行时入参,数据由页面自身 fetch)。 */
2
+ export declare function renderClientSwitchPage(): string;
3
+ //# sourceMappingURL=client-switch-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-switch-page.d.ts","sourceRoot":"","sources":["../src/client-switch-page.ts"],"names":[],"mappings":"AAYA,kDAAkD;AAClD,wBAAgB,sBAAsB,IAAI,MAAM,CA4F/C"}
@@ -0,0 +1,106 @@
1
+ // 前端切换「逃生页」——由 webui-server 直出的极简恢复页,独立于任何「可被切换的前端」。
2
+ //
3
+ // 背景:前端切换统一走「服务偏好」下拉框,而该下拉框住在前端里。一旦切到不含该 UI 的极简
4
+ // 前端(如第三方裸前端),就没有切回去的入口(只能改 aalis.config.yaml + 重启)。本页由
5
+ // webui-server 直接托管在 `/__clients`,无论当前活跃前端多裸都可达,是「永不卡死」的恢复入口。
6
+ //
7
+ // 零新增后端逻辑:纯静态 HTML + 同源 fetch 复用既有接口(同源 cookie 自动鉴权)——
8
+ // · 列表:GET /api/services (取 webui-client 服务的 providers + preferred)
9
+ // · 切换:POST /api/services/webui-client/prefer (owner 闸,body {contextId})
10
+ // 全局 auth 中间件已要求登录方可到达本路由(未认证 GET 直接回登录页),故本页无需自加 gate;
11
+ // 切换动作仍受既有 owner 闸约束。抽成纯函数仅为便于单测——route 只 res.type('html').send(它)。
12
+ /** 渲染前端切换恢复页的完整 HTML 文档(无运行时入参,数据由页面自身 fetch)。 */
13
+ export function renderClientSwitchPage() {
14
+ return `<!doctype html>
15
+ <html lang="zh-CN">
16
+ <head>
17
+ <meta charset="utf-8" />
18
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
19
+ <title>切换前端 · Aalis</title>
20
+ <style>
21
+ :root { color-scheme: light dark; }
22
+ body { font: 15px/1.6 system-ui, -apple-system, sans-serif; max-width: 32rem; margin: 8vh auto; padding: 0 1.2rem; }
23
+ h1 { font-size: 1.25rem; margin: 0 0 .25rem; }
24
+ p.hint { color: #888; margin: .25rem 0 1.25rem; }
25
+ label { display: block; font-weight: 600; margin-bottom: .4rem; }
26
+ select, button { font: inherit; padding: .55rem .7rem; border-radius: .5rem; }
27
+ select { width: 100%; box-sizing: border-box; }
28
+ button { margin-top: 1rem; cursor: pointer; border: 1px solid currentColor; background: transparent; }
29
+ button:disabled { opacity: .5; cursor: default; }
30
+ #msg { margin-top: 1rem; min-height: 1.4em; }
31
+ #msg.err { color: #c0392b; }
32
+ #msg.ok { color: #2e7d32; }
33
+ code { font-family: ui-monospace, monospace; }
34
+ </style>
35
+ </head>
36
+ <body>
37
+ <h1>切换前端</h1>
38
+ <p class="hint">这是 Aalis 的前端恢复入口,由 webui-server 直接提供、独立于当前前端——即使当前前端没有切换界面,你也能在这里切回去。</p>
39
+ <label for="client">可用前端(webui-client)</label>
40
+ <select id="client"><option>加载中…</option></select>
41
+ <button id="go" type="button">切换并刷新</button>
42
+ <div id="msg"></div>
43
+ <p class="hint">切回原来的前端:在上面选中它,再点「切换并刷新」。</p>
44
+ <script>
45
+ (function () {
46
+ var SVC = 'webui-client';
47
+ var PREFER = '/api/services/' + SVC + '/prefer';
48
+ var sel = document.getElementById('client');
49
+ var btn = document.getElementById('go');
50
+ var msg = document.getElementById('msg');
51
+ function setMsg(t, err) { msg.textContent = t; msg.className = err ? 'err' : 'ok'; }
52
+ function load() {
53
+ fetch('/api/services', { headers: { Accept: 'application/json' } })
54
+ .then(function (r) {
55
+ if (!r.ok) throw new Error('读取服务列表失败(HTTP ' + r.status + ')');
56
+ return r.json();
57
+ })
58
+ .then(function (data) {
59
+ var svc = data && data.services && data.services[SVC];
60
+ var providers = (svc && svc.providers) || [];
61
+ if (!providers.length) {
62
+ setMsg('未发现任何前端(webui-client provider)。请先安装一个 aalis.client 包。', true);
63
+ btn.disabled = true;
64
+ sel.innerHTML = '';
65
+ return;
66
+ }
67
+ var active = (svc && svc.preferred) || providers[0].contextId;
68
+ sel.innerHTML = '';
69
+ providers.forEach(function (p) {
70
+ var o = document.createElement('option');
71
+ o.value = p.contextId;
72
+ o.textContent = (p.displayName || p.label || p.contextId) + (p.contextId === active ? '(当前)' : '');
73
+ if (p.contextId === active) o.selected = true;
74
+ sel.appendChild(o);
75
+ });
76
+ })
77
+ .catch(function (e) { setMsg(String((e && e.message) || e), true); });
78
+ }
79
+ btn.addEventListener('click', function () {
80
+ var contextId = sel.value;
81
+ if (!contextId) return;
82
+ btn.disabled = true;
83
+ setMsg('切换中…', false);
84
+ fetch(PREFER, {
85
+ method: 'POST',
86
+ headers: { 'Content-Type': 'application/json' },
87
+ body: JSON.stringify({ contextId: contextId })
88
+ })
89
+ .then(function (r) {
90
+ if (r.ok) { setMsg('已切换,正在跳转…', false); location.href = '/'; return; }
91
+ return r.json().catch(function () { return {}; }).then(function (j) {
92
+ var detail = (j && j.error) || ('HTTP ' + r.status);
93
+ var hint = (r.status === 401 || r.status === 403) ? '(需要 owner 权限:请用一键登录链接打开 WebUI 后再试)' : '';
94
+ setMsg('切换失败:' + detail + hint, true);
95
+ btn.disabled = false;
96
+ });
97
+ })
98
+ .catch(function (e) { setMsg('切换请求出错:' + String((e && e.message) || e), true); btn.disabled = false; });
99
+ });
100
+ load();
101
+ })();
102
+ </script>
103
+ </body>
104
+ </html>`;
105
+ }
106
+ //# sourceMappingURL=client-switch-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-switch-page.js","sourceRoot":"","sources":["../src/client-switch-page.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,gDAAgD;AAChD,wDAAwD;AACxD,8DAA8D;AAC9D,EAAE;AACF,uDAAuD;AACvD,6FAA6F;AAC7F,8EAA8E;AAC9E,wDAAwD;AACxD,oEAAoE;AAEpE,kDAAkD;AAClD,MAAM,UAAU,sBAAsB;IACpC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA0FD,CAAC;AACT,CAAC"}
package/dist/gate.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type { Context } from '@aalis/core';
2
- import type { CapabilityVisibility, UserIdentity } from '@aalis/plugin-authority-api';
1
+ import type { UserIdentity } from '@aalis/plugin-authority-api';
3
2
  /** 从请求解析调用者身份(auth.ts 的 AuthSystem.identify) */
4
3
  type IdentifyFn = (req: {
5
4
  headers: {
@@ -18,22 +17,17 @@ interface GateResponse {
18
17
  }
19
18
  type GateMiddleware = (req: GateRequest, res: GateResponse, next: () => void) => void;
20
19
  /**
21
- * REST 路由能力闸工厂。
20
+ * REST 路由 owner 闸工厂(单 owner 终态)。
22
21
  *
23
- * 连接级认证(auth middleware)只回答"是否登录";本闸回答"该身份能否做这件事"——
24
- * 每条 REST 路由声明一个 capability 与默认可见性,过 authorize 统一闸
25
- * (deny > owner(*) > public > granted)。owner 拥有一切;可对单账户 grant 某条
26
- * restricted capability(如 `webui:files:read`)做细粒度委托。
22
+ * 单 token 模式下「持 token ⟺ webui:console ⟺ owner」,故连接级认证(auth.middleware
23
+ * 校验 token,未认证一律 401)即等价于 owner 鉴权。本闸是 REST 层的显式 owner 复核
24
+ * (防御纵深,与 auth.middleware 同义):身份解析得到即放行,否则 403。
27
25
  *
28
- * 可见性约定(颗粒度由 capability 字符串本身承载,owner 之外的细分靠委托 grant):
29
- * - 'public':公共读(status / pages / 模型列表等,聊天面板可用即可)。
30
- * - 'restricted':管理读(插件清单含原始配置、日志、文件浏览——可能含密钥)与
31
- * 一切变更操作(配置写、插件启停装卸、服务偏好、文件删改);默认禁,须 owner /
32
- * 被委托授予。
33
- *
34
- * authority 服务缺席时:public 放行、restricted 503(fail-closed,不在权限服务缺位时裸奔)。
26
+ * 多账户 / 能力委托已剥离,故不再有 per-route capability 与档位裁决——所有需登录的
27
+ * REST 路由统一是 owner-only。页面/状态等只读路由同样在 auth.middleware 之后,对
28
+ * owner 无区别。
35
29
  */
36
- export declare function createRouteGate(ctx: Context, identify: IdentifyFn): (capability: string, visibility: CapabilityVisibility) => GateMiddleware;
30
+ export declare function createRouteGate(identify: IdentifyFn): () => GateMiddleware;
37
31
  /** createRouteGate 返回的闸生成函数类型(传给各 routes/ 注册器) */
38
32
  export type RouteGate = ReturnType<typeof createRouteGate>;
39
33
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAoB,oBAAoB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAExG,gDAAgD;AAChD,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE;IAAE,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,KAAK,YAAY,GAAG,SAAS,CAAC;AAKtF,UAAU,WAAW;IACnB,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AACD,UAAU,YAAY;IACpB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAC;CACxD;AACD,KAAK,cAAc,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAEtF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,IACxD,YAAY,MAAM,EAAE,YAAY,oBAAoB,KAAG,cAAc,CAqB9E;AAED,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,gDAAgD;AAChD,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE;IAAE,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,KAAK,YAAY,GAAG,SAAS,CAAC;AAKtF,UAAU,WAAW;IACnB,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AACD,UAAU,YAAY;IACpB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAC;CACxD;AACD,KAAK,cAAc,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAEtF;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,UAAU,SACvC,cAAc,CAO1B;AAED,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}