koishi-plugin-rocom 1.0.7 → 1.0.9

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/lib/client.js CHANGED
@@ -99,6 +99,9 @@ class RocomClient {
99
99
  if (/缺少\s*API\s*Key|API\s*Key.*required|missing\s+api\s*key/i.test(message)) {
100
100
  return true;
101
101
  }
102
+ if (/请提供有效的认证凭证|有效的?认证凭证|valid\s+credentials?\s+required|X-API-Key|Authorization\s*:\s*Bearer|X-Anonymous-Token/i.test(message)) {
103
+ return true;
104
+ }
102
105
  if (/HTTP\s*(401|403)/i.test(message)) {
103
106
  return true;
104
107
  }
@@ -280,7 +283,11 @@ class RocomClient {
280
283
  const status = Number(response?.status ?? response?.statusCode ?? 200);
281
284
  const body = response?.data !== undefined ? response.data : response;
282
285
  if (body?.code !== undefined && body.code !== 0) {
283
- this.setLastError(body.message || body.msg || '接口返回异常');
286
+ const rawMessage = body.message || body.msg || '接口返回异常';
287
+ const message = !acceptedStatuses.includes(status)
288
+ ? `HTTP ${status}: ${rawMessage}`
289
+ : rawMessage;
290
+ this.setLastError(message);
284
291
  if (!options.silentFailureDetails) {
285
292
  this.logRequestFailureDetails(method, path, headers, options.params, options.json, body);
286
293
  }
@@ -1,5 +1,5 @@
1
1
  import { PluginDeps } from '../types';
2
2
  export declare function getPrimaryToken(deps: PluginDeps, userId: string): Promise<string>;
3
3
  export declare function notLoggedInHint(): string;
4
- export declare function saveBindingWithRoleInfo(deps: PluginDeps, session: any, fwToken: string, loginType: string, userId: string): Promise<void>;
4
+ export declare function saveBindingWithRoleInfo(deps: PluginDeps, session: any, fwToken: string, loginType: string, userId: string, preMessageIds?: string[]): Promise<void>;
5
5
  export declare function register(deps: PluginDeps): void;
@@ -7,6 +7,21 @@ exports.register = register;
7
7
  const koishi_1 = require("koishi");
8
8
  const role_token_1 = require("../role-token");
9
9
  const send_image_1 = require("../send-image");
10
+ const logger = new koishi_1.Logger('rocom-account');
11
+ async function recallMessages(session, messageIds) {
12
+ if (!session?.bot?.deleteMessage || !session.channelId)
13
+ return;
14
+ for (const id of messageIds) {
15
+ if (!id)
16
+ continue;
17
+ try {
18
+ await session.bot.deleteMessage(session.channelId, id);
19
+ }
20
+ catch (err) {
21
+ logger.warn(`撤回消息 ${id} 失败:${err}`);
22
+ }
23
+ }
24
+ }
10
25
  async function getPrimaryToken(deps, userId) {
11
26
  const token = await (0, role_token_1.getRoleToken)(deps.ctx, userId);
12
27
  return token?.fwt || '';
@@ -29,16 +44,29 @@ function formatLoginType(loginType) {
29
44
  };
30
45
  return typeMap[loginType] || loginType || '未知';
31
46
  }
32
- async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId) {
47
+ async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId, preMessageIds = []) {
33
48
  const { ctx, client, userMgr } = deps;
34
- await session.send('登录成功,正在调用绑定接口...');
49
+ const intermediateMessageIds = [...preMessageIds];
50
+ const sendIntermediate = async (content) => {
51
+ const result = await session.send(content);
52
+ if (Array.isArray(result)) {
53
+ for (const id of result) {
54
+ if (id)
55
+ intermediateMessageIds.push(String(id));
56
+ }
57
+ }
58
+ else if (result) {
59
+ intermediateMessageIds.push(String(result));
60
+ }
61
+ };
62
+ await sendIntermediate('登录成功,正在调用绑定接口...');
35
63
  const bindRes = await client.createBinding(ctx, fwToken, userId);
36
64
  const bindingId = String(bindRes?.binding?.id || fwToken || '').trim();
37
65
  if (!bindRes?.binding || !bindingId) {
38
66
  await session.send('绑定接口调用失败,请稍后重试。');
39
67
  return;
40
68
  }
41
- await session.send('绑定成功,正在获取角色信息...');
69
+ await sendIntermediate('绑定成功,正在获取角色信息...');
42
70
  const roleRes = await client.getRole(ctx, fwToken, undefined, userId);
43
71
  if (!roleRes?.role) {
44
72
  await session.send('绑定成功,但获取角色信息失败,请尝试重新登录。');
@@ -61,6 +89,7 @@ async function saveBindingWithRoleInfo(deps, session, fwToken, loginType, userId
61
89
  roleId: binding.role_id,
62
90
  loginType,
63
91
  });
92
+ await recallMessages(session, intermediateMessageIds);
64
93
  await session.send(`绑定成功!当前账号:${binding.nickname} (ID: ${binding.role_id})`);
65
94
  }
66
95
  function register(deps) {
@@ -75,7 +104,10 @@ function register(deps) {
75
104
  const fwToken = qrData.frameworkToken;
76
105
  const qrB64 = qrData.qr_image;
77
106
  const imgData = qrB64.includes(',') ? qrB64.split(',')[1] : qrB64;
78
- await session.send((0, koishi_1.h)('message', {}, koishi_1.h.at(userId), koishi_1.h.text('\n请使用 QQ 扫描二维码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n'), koishi_1.h.image(`data:image/png;base64,${imgData}`)));
107
+ const qrSendResult = await session.send((0, koishi_1.h)('message', {}, koishi_1.h.at(userId), koishi_1.h.text('\n请使用 QQ 扫描二维码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n'), koishi_1.h.image(`data:image/png;base64,${imgData}`)));
108
+ const qrMessageIds = Array.isArray(qrSendResult)
109
+ ? qrSendResult.filter(Boolean).map(String)
110
+ : qrSendResult ? [String(qrSendResult)] : [];
79
111
  const startTime = Date.now();
80
112
  while (Date.now() - startTime < 115000) {
81
113
  await new Promise(r => setTimeout(r, 3000));
@@ -83,7 +115,7 @@ function register(deps) {
83
115
  if (!status)
84
116
  continue;
85
117
  if (status.status === 'done') {
86
- await saveBindingWithRoleInfo(deps, session, fwToken, 'qq', userId);
118
+ await saveBindingWithRoleInfo(deps, session, fwToken, 'qq', userId, qrMessageIds);
87
119
  return;
88
120
  }
89
121
  if (['expired', 'failed', 'canceled'].includes(status.status))
@@ -100,7 +132,10 @@ function register(deps) {
100
132
  return '获取微信登录链接失败。';
101
133
  const fwToken = qrData.frameworkToken;
102
134
  const qrUrl = qrData.qr_image;
103
- await session.send(`请使用微信打开以下链接扫码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n${qrUrl}`);
135
+ const qrSendResult = await session.send(`请使用微信打开以下链接扫码登录(有效时间 2 分钟)\n注意需要双设备扫码。\n${qrUrl}`);
136
+ const qrMessageIds = Array.isArray(qrSendResult)
137
+ ? qrSendResult.filter(Boolean).map(String)
138
+ : qrSendResult ? [String(qrSendResult)] : [];
104
139
  const startTime = Date.now();
105
140
  while (Date.now() - startTime < 115000) {
106
141
  await new Promise(r => setTimeout(r, 3000));
@@ -108,7 +143,7 @@ function register(deps) {
108
143
  if (!status)
109
144
  continue;
110
145
  if (status.status === 'done') {
111
- await saveBindingWithRoleInfo(deps, session, fwToken, 'wechat', userId);
146
+ await saveBindingWithRoleInfo(deps, session, fwToken, 'wechat', userId, qrMessageIds);
112
147
  return;
113
148
  }
114
149
  if (['expired', 'failed'].includes(status.status))
@@ -1058,12 +1058,6 @@ function buildPlayerSearchRenderData(payload, uid) {
1058
1058
  ['舒适度', playerField(parsed, 'home_comfort_level')],
1059
1059
  ['访客数量', playerField(parsed, 'visitor_num')],
1060
1060
  ]),
1061
- pack('名片信息', [
1062
- ['名片皮肤', playerField(parsed, 'card_skin_selected')],
1063
- ['名片头像', playerField(parsed, 'card_icon_selected')],
1064
- ['首标签', playerField(parsed, 'card_label_first_selected')],
1065
- ['尾标签', playerField(parsed, 'card_label_last_selected')],
1066
- ]),
1067
1061
  ].filter(Boolean);
1068
1062
  const summaryCards = [
1069
1063
  { label: '等级', value: parsed.level },
@@ -1076,7 +1070,6 @@ function buildPlayerSearchRenderData(payload, uid) {
1076
1070
  const signature = parsed.signature && parsed.signature !== '未设置' ? parsed.signature : '';
1077
1071
  return {
1078
1072
  title: '洛克玩家',
1079
- subtitle: parsed.title,
1080
1073
  heroTitle: '玩家信息',
1081
1074
  heroValue: parsed.nickname,
1082
1075
  heroSubvalue: `UID ${parsed.uid}`,
@@ -1334,7 +1327,6 @@ function register(deps) {
1334
1327
  if (!fwToken)
1335
1328
  return (0, account_1.notLoggedInHint)();
1336
1329
  const userIdentifier = session.userId;
1337
- await session.send('正在获取洛克王国数据...');
1338
1330
  const [roleRes, evalRes, sumRes, collRes, boRes, blRes] = await Promise.all([
1339
1331
  client.getRole(ctx, fwToken, undefined, userIdentifier),
1340
1332
  client.getEvaluation(ctx, fwToken, userIdentifier),
@@ -1781,7 +1773,6 @@ function register(deps) {
1781
1773
  return '请提供 UID,或先绑定账号后再使用 洛克.刷新面板。';
1782
1774
  if (!/^\d+$/.test(targetUid))
1783
1775
  return '请输入正确的 UID 格式。';
1784
- await session?.send?.(`正在刷新 UID ${targetUid} 的精灵面板,请稍候...`);
1785
1776
  const record = await refreshPanelPets(deps, targetUid, session?.userId || '');
1786
1777
  if (!record)
1787
1778
  return panelRefreshErrorHint(client);
package/lib/index.js CHANGED
@@ -96,7 +96,7 @@ function buildMenuFallbackText() {
96
96
  exports.Config = koishi_1.Schema.intersect([
97
97
  koishi_1.Schema.object({
98
98
  apiBaseUrl: koishi_1.Schema.string().default('https://wegame.shallow.ink').description('API 基础地址'),
99
- wegameApiKey: koishi_1.Schema.string().default('').description('WeGame API Key'),
99
+ wegameApiKey: koishi_1.Schema.string().default('').description('WeGame API Key(获取 key 查看 Github:https://github.com/Entropy-Increase-Team/koishi-plugin-rocom )'),
100
100
  qqLoginDebugMode: koishi_1.Schema.boolean().default(false).description('QQ 扫码登录调试模式,仅调试时开启'),
101
101
  adminUserIds: koishi_1.Schema.array(String).default([]).description('管理员用户 ID 列表'),
102
102
  autoRefreshEnabled: koishi_1.Schema.boolean().default(false).description('启用自动刷新凭证'),
@@ -1,60 +1,68 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=1200, initial-scale=1">
6
- <link rel="stylesheet" href="{{_res_path}}render/player-search/style.css">
7
- </head>
8
- <body>
9
- <div class="player-search-page player-page">
10
- <div class="page-header">
11
- <div class="page-title">{{title}}</div>
12
- <div class="page-subtitle">{{subtitle}}</div>
13
- </div>
14
-
15
- <div class="hero-card">
16
- <div class="hero-title">{{heroTitle}}</div>
17
- <div class="hero-value">{{heroValue}}</div>
18
- <div class="hero-subvalue">{{heroSubvalue}}</div>
19
- </div>
20
-
21
- <div class="summary-grid">
22
- {{each summaryCards item}}
23
- <div class="summary-card">
24
- <div class="summary-label">{{item.label}}</div>
25
- <div class="summary-value">{{item.value}}</div>
26
- </div>
27
- {{/each}}
28
- </div>
29
-
30
- {{if showSignature}}
31
- <div class="panel-card signature-panel">
32
- <div class="section-title">个性签名</div>
33
- <div class="signature-box">{{signature}}</div>
34
- </div>
35
- {{/if}}
36
-
37
- <div class="section-grid">
38
- {{each sections section}}
39
- <div class="panel-card info-panel">
40
- <div class="section-title">{{section.title}}</div>
41
- <div class="detail-card">
42
- {{each section["items"] item}}
43
- <div class="detail-row">
44
- <div class="detail-label">{{item.label}}</div>
45
- <div class="detail-value">{{item.value}}</div>
46
- </div>
47
- {{/each}}
48
- </div>
49
- </div>
50
- {{/each}}
51
- </div>
52
-
53
- {{if commandHint}}
54
- <div class="command-hint">{{commandHint}}</div>
55
- {{/if}}
56
-
57
- <div class="footer">{{copyright}}</div>
58
- </div>
59
- </body>
60
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=1280, initial-scale=1">
6
+ <link rel="stylesheet" href="{{_res_path}}render/player-search/style.css">
7
+ </head>
8
+ <body>
9
+ <div class="player-search-page player-page">
10
+ <div class="page-bg"></div>
11
+
12
+ <header class="page-header">
13
+ <div class="page-title">{{title}}</div>
14
+ <div class="page-title-ghost">ROCOM PLAYER</div>
15
+ </header>
16
+
17
+ <section class="profile-strip">
18
+ <div class="profile-main">
19
+ <div class="profile-name-row">
20
+ <span class="player-name">{{heroValue}}</span>
21
+ <span class="uid-pill">{{heroSubvalue}}</span>
22
+ </div>
23
+ </div>
24
+ </section>
25
+
26
+ <section class="summary-strip">
27
+ {{each summaryCards item}}
28
+ <div class="summary-item">
29
+ <div class="summary-label">{{item.label}}</div>
30
+ <div class="summary-value">{{item.value}}</div>
31
+ </div>
32
+ {{/each}}
33
+ </section>
34
+
35
+ {{if showSignature}}
36
+ <section class="signature-strip">
37
+ <div class="signature-label">个性签名</div>
38
+ <div class="signature-text">{{signature}}</div>
39
+ </section>
40
+ {{/if}}
41
+
42
+ <main class="content-grid">
43
+ {{each sections section}}
44
+ <section class="panel">
45
+ <div class="panel-head">
46
+ <h2>{{section.title}}</h2>
47
+ </div>
48
+ <div class="detail-list">
49
+ {{each section["items"] item}}
50
+ <div class="detail-row">
51
+ <span class="detail-label">{{item.label}}</span>
52
+ <span class="detail-value">{{item.value}}</span>
53
+ </div>
54
+ {{/each}}
55
+ </div>
56
+ </section>
57
+ {{/each}}
58
+ </main>
59
+
60
+ <footer class="page-footer">
61
+ {{if commandHint}}
62
+ <div class="command-hint">用法:{{commandHint}}</div>
63
+ {{/if}}
64
+ <div class="copyright">{{copyright}}</div>
65
+ </footer>
66
+ </div>
67
+ </body>
68
+ </html>