koishi-plugin-rocom 1.0.5 → 1.0.7
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.d.ts +4 -0
- package/lib/client.js +56 -1
- package/lib/commands/merchant.js +31 -11
- package/lib/commands/query.js +649 -13
- package/lib/render-templates/pet-panel/index.html +61 -0
- package/lib/render-templates/pet-panel/style.css +183 -0
- package/lib/render-templates/pet-panel-detail/index.html +123 -0
- package/lib/render-templates/pet-panel-detail/style.css +258 -0
- package/lib/render.d.ts +3 -3
- package/lib/render.js +33 -14
- package/lib/user.d.ts +1 -0
- package/package.json +1 -1
- package/readme.md +53 -509
package/lib/client.d.ts
CHANGED
|
@@ -4,11 +4,14 @@ export declare class RocomClient {
|
|
|
4
4
|
private apiKey;
|
|
5
5
|
private timeout;
|
|
6
6
|
private lastError;
|
|
7
|
+
private lastErrorBrief;
|
|
7
8
|
constructor(baseUrl: string, apiKey: string, timeout?: number);
|
|
8
9
|
private sanitizeUid;
|
|
9
10
|
private wegameHeaders;
|
|
10
11
|
private rocomHeaders;
|
|
11
12
|
private formatHttpError;
|
|
13
|
+
private simplifyErrorMessage;
|
|
14
|
+
private shouldRetryIngameWithApiKey;
|
|
12
15
|
private isSensitiveLogKey;
|
|
13
16
|
private maskSensitiveValue;
|
|
14
17
|
private sanitizeForLog;
|
|
@@ -32,6 +35,7 @@ export declare class RocomClient {
|
|
|
32
35
|
getRole(ctx: Context, fwToken: string, accountType?: number, userIdentifier?: string): Promise<any>;
|
|
33
36
|
getEvaluation(ctx: Context, fwToken: string, userIdentifier?: string): Promise<any>;
|
|
34
37
|
getLastError(defaultMessage?: string): string;
|
|
38
|
+
getLastErrorBrief(defaultMessage?: string): string;
|
|
35
39
|
private setLastError;
|
|
36
40
|
getPetSummary(ctx: Context, fwToken: string, userIdentifier?: string): Promise<any>;
|
|
37
41
|
getCollection(ctx: Context, fwToken: string, userIdentifier?: string): Promise<any>;
|
package/lib/client.js
CHANGED
|
@@ -8,6 +8,7 @@ class RocomClient {
|
|
|
8
8
|
apiKey;
|
|
9
9
|
timeout;
|
|
10
10
|
lastError = '接口异常';
|
|
11
|
+
lastErrorBrief = '接口异常';
|
|
11
12
|
constructor(baseUrl, apiKey, timeout = 15000) {
|
|
12
13
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
13
14
|
this.apiKey = apiKey;
|
|
@@ -53,6 +54,56 @@ class RocomClient {
|
|
|
53
54
|
}
|
|
54
55
|
return err?.message || String(e);
|
|
55
56
|
}
|
|
57
|
+
simplifyErrorMessage(message) {
|
|
58
|
+
const raw = String(message || '').replace(/\s+/g, ' ').trim();
|
|
59
|
+
if (!raw)
|
|
60
|
+
return '接口异常';
|
|
61
|
+
if (/ETIMEDOUT|request timeout|timeout/i.test(raw)) {
|
|
62
|
+
return '请求超时,请稍后重试';
|
|
63
|
+
}
|
|
64
|
+
if (/ENOTFOUND|EAI_AGAIN|ECONNRESET|ECONNREFUSED|socket hang up|fetch failed|network error/i.test(raw)) {
|
|
65
|
+
return '网络连接异常,请稍后重试';
|
|
66
|
+
}
|
|
67
|
+
if (/底层凭证已失效|WeGame 凭证已失效|凭证已失效|token expired|framework token/i.test(raw)) {
|
|
68
|
+
return '登录凭证已失效,请重新登录';
|
|
69
|
+
}
|
|
70
|
+
if (/HTTP\s*5\d\d/i.test(raw)) {
|
|
71
|
+
return '服务暂时不可用,请稍后重试';
|
|
72
|
+
}
|
|
73
|
+
if (/HTTP\s*401/i.test(raw)) {
|
|
74
|
+
return '登录状态失效,请重新登录';
|
|
75
|
+
}
|
|
76
|
+
if (/API[\s_-]*Key/i.test(raw) && /未声明|默认拒绝访问|not declared|not allowed/i.test(raw)) {
|
|
77
|
+
return '接口权限受限,请稍后重试';
|
|
78
|
+
}
|
|
79
|
+
if (/HTTP\s*403/i.test(raw) && !/凭证|登录|token/i.test(raw)) {
|
|
80
|
+
return '权限不足,暂时无法访问该接口';
|
|
81
|
+
}
|
|
82
|
+
const stripped = raw
|
|
83
|
+
.replace(/^HTTP\s*\d+\s*:\s*/i, '')
|
|
84
|
+
.replace(/^(Error|RequestError)\s*:\s*/i, '')
|
|
85
|
+
.trim();
|
|
86
|
+
if (!stripped)
|
|
87
|
+
return '接口异常';
|
|
88
|
+
return stripped.length > 120 ? `${stripped.slice(0, 117)}...` : stripped;
|
|
89
|
+
}
|
|
90
|
+
shouldRetryIngameWithApiKey(errorMessage) {
|
|
91
|
+
if (!this.apiKey)
|
|
92
|
+
return false;
|
|
93
|
+
const message = String(errorMessage || '').trim();
|
|
94
|
+
if (!message)
|
|
95
|
+
return true;
|
|
96
|
+
if (/未声明\s*API\s*Key\s*权限|默认拒绝访问|API\s*Key.*not declared|API\s*Key.*not allowed/i.test(message)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
if (/缺少\s*API\s*Key|API\s*Key.*required|missing\s+api\s*key/i.test(message)) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (/HTTP\s*(401|403)/i.test(message)) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
56
107
|
isSensitiveLogKey(key) {
|
|
57
108
|
return /api[-_]?key|authorization|cookie|framework[-_]?token|password|secret|ticket|token/i.test(key);
|
|
58
109
|
}
|
|
@@ -275,7 +326,7 @@ class RocomClient {
|
|
|
275
326
|
let result = await requestOnce(false, Boolean(this.apiKey));
|
|
276
327
|
if (result.status !== null)
|
|
277
328
|
return { ...result, usedApiKey: false };
|
|
278
|
-
if (this.
|
|
329
|
+
if (this.shouldRetryIngameWithApiKey(this.getLastError())) {
|
|
279
330
|
result = await requestOnce(true, false);
|
|
280
331
|
if (result.status !== null)
|
|
281
332
|
return { ...result, usedApiKey: true };
|
|
@@ -339,8 +390,12 @@ class RocomClient {
|
|
|
339
390
|
getLastError(defaultMessage = '接口异常') {
|
|
340
391
|
return this.lastError || defaultMessage;
|
|
341
392
|
}
|
|
393
|
+
getLastErrorBrief(defaultMessage = '接口异常') {
|
|
394
|
+
return this.lastErrorBrief || defaultMessage;
|
|
395
|
+
}
|
|
342
396
|
setLastError(message) {
|
|
343
397
|
this.lastError = message || '接口异常';
|
|
398
|
+
this.lastErrorBrief = this.simplifyErrorMessage(message);
|
|
344
399
|
}
|
|
345
400
|
async getPetSummary(ctx, fwToken, userIdentifier = '') {
|
|
346
401
|
return this.get(ctx, '/api/v1/games/rocom/profile/pet-summary', this.rocomHeaders(fwToken, userIdentifier));
|
package/lib/commands/merchant.js
CHANGED
|
@@ -103,11 +103,16 @@ function parseMerchantSubscriptionArgs(args, defaultItems) {
|
|
|
103
103
|
if (parts[0] === '1' || parts[0] === '0') {
|
|
104
104
|
mentionAll = parts.shift() === '1';
|
|
105
105
|
}
|
|
106
|
-
const
|
|
106
|
+
const matchAll = parts.length === 1 && parts[0] === '全部';
|
|
107
|
+
if (matchAll)
|
|
108
|
+
parts.shift();
|
|
109
|
+
const items = matchAll ? [] : (parts.length ? parts : defaultItems);
|
|
110
|
+
const source = matchAll ? '全部商品' : (parts.length ? TEXT.customSource : TEXT.defaultSource);
|
|
107
111
|
return {
|
|
108
112
|
mention_all: mentionAll,
|
|
113
|
+
match_all: matchAll,
|
|
109
114
|
items,
|
|
110
|
-
source
|
|
115
|
+
source,
|
|
111
116
|
};
|
|
112
117
|
}
|
|
113
118
|
function getSubscriptionTarget(session) {
|
|
@@ -158,13 +163,26 @@ async function checkMerchantSubscriptions(deps) {
|
|
|
158
163
|
let matchedCount = 0;
|
|
159
164
|
let pushedCount = 0;
|
|
160
165
|
for (const [key, sub] of Object.entries(subs)) {
|
|
161
|
-
const
|
|
162
|
-
|
|
166
|
+
const matchAll = !!sub.match_all;
|
|
167
|
+
const matched = matchAll
|
|
168
|
+
? productNames
|
|
169
|
+
: sub.items.filter((item) => productNames.some(n => n.includes(item)));
|
|
170
|
+
if (!matchAll && !matched.length)
|
|
163
171
|
continue;
|
|
164
|
-
|
|
165
|
-
if (sub.last_push_round === roundInfo.round_id && sameStringArray(matched, sub.last_matched_items || []))
|
|
172
|
+
if (matchAll && !products.length)
|
|
166
173
|
continue;
|
|
167
|
-
|
|
174
|
+
matchedCount++;
|
|
175
|
+
if (matchAll) {
|
|
176
|
+
if (sub.last_push_round === roundInfo.round_id)
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
if (sub.last_push_round === roundInfo.round_id && sameStringArray(matched, sub.last_matched_items || []))
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const msg = matchAll
|
|
184
|
+
? `\ud83d\udd14 \u8fdc\u884c\u5546\u4eba\u5237\u65b0\u63d0\u9192\n\u5f53\u524d\u5546\u54c1\uff1a${productNames.join('\u3001')}`
|
|
185
|
+
: `\ud83d\udd14 \u8fdc\u884c\u5546\u4eba\u5237\u65b0\u63d0\u9192\n\u5f53\u524d\u5546\u54c1\uff1a${productNames.join('\u3001')}\n\u5339\u914d\u8ba2\u9605\uff1a${matched.join('\u3001')}`;
|
|
168
186
|
const platform = sub.platform || ctx.bots[0]?.platform;
|
|
169
187
|
const channelId = sub.channel_id || sub.group_id || sub.user_id || key;
|
|
170
188
|
if (!platform || !channelId) {
|
|
@@ -195,7 +213,7 @@ function register(deps) {
|
|
|
195
213
|
.action(async ({ session }) => {
|
|
196
214
|
const res = await client.getMerchantInfo(ctx, true);
|
|
197
215
|
if (!res)
|
|
198
|
-
return
|
|
216
|
+
return `\u83b7\u53d6\u8fdc\u884c\u5546\u4eba\u6570\u636e\u5931\u8d25\uff1a${client.getLastErrorBrief()}`;
|
|
199
217
|
const { data, fallback } = buildMerchantRenderPayload(res);
|
|
200
218
|
const png = await deps.renderer.renderHtml(ctx, 'yuanxing-shangren', data);
|
|
201
219
|
await (0, send_image_1.sendImageWithFallback)(session, png, fallback, 'merchant:yuanxing-shangren', deps.config);
|
|
@@ -216,12 +234,13 @@ function register(deps) {
|
|
|
216
234
|
channel_id: target.channelId,
|
|
217
235
|
platform: target.platform,
|
|
218
236
|
items: parsed.items,
|
|
237
|
+
match_all: parsed.match_all,
|
|
219
238
|
mention_all: target.privateChat ? false : parsed.mention_all,
|
|
220
239
|
last_push_round: existing?.last_push_round ?? null,
|
|
221
240
|
last_matched_items: existing?.last_matched_items ?? [],
|
|
222
241
|
updated_by: session.userId,
|
|
223
242
|
});
|
|
224
|
-
return `\u2705 \u5df2\u8ba2\u9605\u8fdc\u884c\u5546\u4eba\u5546\u54c1\uff1a${parsed.items.join('\u3001')}\uff08${parsed.source}\uff09\uff1b${target.privateChat ? '个人订阅' : (parsed.mention_all ? '\u547d\u4e2d\u540e\u4f1a @\u5168\u4f53' : '\u547d\u4e2d\u540e\u4e0d @\u5168\u4f53')}`;
|
|
243
|
+
return `\u2705 \u5df2\u8ba2\u9605\u8fdc\u884c\u5546\u4eba\u5546\u54c1\uff1a${parsed.match_all ? '\u5168\u90e8\u5546\u54c1\uff08\u6bcf\u8f6e\u63a8\u9001\uff09' : parsed.items.join('\u3001')}\uff08${parsed.source}\uff09\uff1b${target.privateChat ? '个人订阅' : (parsed.mention_all ? '\u547d\u4e2d\u540e\u4f1a @\u5168\u4f53' : '\u547d\u4e2d\u540e\u4e0d @\u5168\u4f53')}`;
|
|
225
244
|
});
|
|
226
245
|
ctx.command(TEXT.viewSubscribe, '\u67e5\u770b\u5f53\u524d\u4f1a\u8bdd\u7684\u8fdc\u884c\u5546\u4eba\u8ba2\u9605')
|
|
227
246
|
.action(async ({ session }) => {
|
|
@@ -231,8 +250,9 @@ function register(deps) {
|
|
|
231
250
|
const sub = merchantSubMgr.get(target.key);
|
|
232
251
|
const scopeName = target.privateChat ? '你' : '当前群组';
|
|
233
252
|
if (!sub)
|
|
234
|
-
return `${scopeName}未订阅远行商人。\n用法:${TEXT.subscribe} [1/0] [商品名1] [商品名2]
|
|
235
|
-
|
|
253
|
+
return `${scopeName}未订阅远行商人。\n用法:${TEXT.subscribe} [1/0] [商品名1] [商品名2] ...\n或:${TEXT.subscribe} 全部(每轮直接推送整张商人图)`;
|
|
254
|
+
const itemsText = sub.match_all ? '全部商品(每轮推送)' : sub.items.join('、');
|
|
255
|
+
return `${scopeName}订阅商品:${itemsText}\n提醒方式:${target.privateChat ? '私聊提醒' : (sub.mention_all ? '@全体' : '普通提醒')}`;
|
|
236
256
|
});
|
|
237
257
|
ctx.command(TEXT.unsubscribe, '\u53d6\u6d88\u8fdc\u884c\u5546\u4eba\u8ba2\u9605')
|
|
238
258
|
.action(async ({ session }) => {
|