koishi-plugin-rocom 1.0.2 → 1.0.3
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 +1 -0
- package/lib/client.js +75 -10
- package/lib/commands/query.js +9 -1
- package/lib/index.js +84 -11
- package/package.json +1 -1
package/lib/client.d.ts
CHANGED
package/lib/client.js
CHANGED
|
@@ -18,9 +18,9 @@ class RocomClient {
|
|
|
18
18
|
return '';
|
|
19
19
|
return uid.trim().replace(/[^a-zA-Z0-9_\- \u4e00-\u9fa5]/g, '').trim();
|
|
20
20
|
}
|
|
21
|
-
wegameHeaders(fwToken = '', userIdentifier = '', clientType = '', clientId = '') {
|
|
21
|
+
wegameHeaders(fwToken = '', userIdentifier = '', clientType = '', clientId = '', includeApiKey = true) {
|
|
22
22
|
const headers = {};
|
|
23
|
-
if (this.apiKey)
|
|
23
|
+
if (includeApiKey && this.apiKey)
|
|
24
24
|
headers['X-API-Key'] = this.apiKey;
|
|
25
25
|
if (fwToken)
|
|
26
26
|
headers['X-Framework-Token'] = fwToken;
|
|
@@ -99,6 +99,11 @@ class RocomClient {
|
|
|
99
99
|
return String(value);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
+
isApiKeyPermissionUndeclaredError(message) {
|
|
103
|
+
if (!message)
|
|
104
|
+
return false;
|
|
105
|
+
return /未声明\s*api\s*key\s*权限|api\s*key\s*permission|api key 权限/i.test(message);
|
|
106
|
+
}
|
|
102
107
|
logRequestFailureDetails(method, path, headers, params, body, errorOrResponse) {
|
|
103
108
|
const err = errorOrResponse;
|
|
104
109
|
const response = err?.response;
|
|
@@ -247,8 +252,8 @@ class RocomClient {
|
|
|
247
252
|
return { status: null, data: null };
|
|
248
253
|
}
|
|
249
254
|
}
|
|
250
|
-
async getIngameTask(ctx, taskId) {
|
|
251
|
-
return this.requestWithStatus(ctx, 'GET', `/api/v1/games/rocom/ingame/tasks/${taskId}`, this.wegameHeaders(), { acceptedStatuses: [200, 202] });
|
|
255
|
+
async getIngameTask(ctx, taskId, includeApiKey = true) {
|
|
256
|
+
return this.requestWithStatus(ctx, 'GET', `/api/v1/games/rocom/ingame/tasks/${taskId}`, this.wegameHeaders('', '', '', '', includeApiKey), { acceptedStatuses: [200, 202] });
|
|
252
257
|
}
|
|
253
258
|
async qqQrLogin(ctx, userIdentifier) {
|
|
254
259
|
const params = { client_type: 'bot', client_id: 'koishi', provider: 'rocom' };
|
|
@@ -338,7 +343,8 @@ class RocomClient {
|
|
|
338
343
|
return null;
|
|
339
344
|
}
|
|
340
345
|
const path = '/api/v1/games/rocom/ingame/player/search';
|
|
341
|
-
|
|
346
|
+
let includeApiKey = true;
|
|
347
|
+
let headers = this.wegameHeaders();
|
|
342
348
|
const payload = { uid: sanitizedUid, wait_ms: 5000 };
|
|
343
349
|
let { status, data } = await this.requestWithStatus(ctx, 'POST', path, headers, {
|
|
344
350
|
json: payload,
|
|
@@ -356,6 +362,29 @@ class RocomClient {
|
|
|
356
362
|
if (status === 200 && data && this.isIngamePlayerPayload(data))
|
|
357
363
|
return data;
|
|
358
364
|
}
|
|
365
|
+
if (status === null && includeApiKey && this.apiKey && this.isApiKeyPermissionUndeclaredError(this.getLastError(''))) {
|
|
366
|
+
logger.warn('ingame/player/search rejected X-API-Key, retrying without API key');
|
|
367
|
+
includeApiKey = false;
|
|
368
|
+
headers = this.wegameHeaders('', '', '', '', false);
|
|
369
|
+
const retry = await this.requestWithStatus(ctx, 'POST', path, headers, {
|
|
370
|
+
json: payload,
|
|
371
|
+
acceptedStatuses: [200, 202],
|
|
372
|
+
});
|
|
373
|
+
status = retry.status;
|
|
374
|
+
data = retry.data;
|
|
375
|
+
if (status === 200 && data && this.isIngamePlayerPayload(data))
|
|
376
|
+
return data;
|
|
377
|
+
if (status === null) {
|
|
378
|
+
const fallback = await this.requestWithStatus(ctx, 'GET', path, headers, {
|
|
379
|
+
params: payload,
|
|
380
|
+
acceptedStatuses: [200, 202],
|
|
381
|
+
});
|
|
382
|
+
status = fallback.status;
|
|
383
|
+
data = fallback.data;
|
|
384
|
+
if (status === 200 && data && this.isIngamePlayerPayload(data))
|
|
385
|
+
return data;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
359
388
|
if (!data)
|
|
360
389
|
return null;
|
|
361
390
|
if (this.isIngamePlayerPayload(data))
|
|
@@ -368,7 +397,7 @@ class RocomClient {
|
|
|
368
397
|
}
|
|
369
398
|
for (let i = 0; i < 8; i++) {
|
|
370
399
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
371
|
-
const task = await this.getIngameTask(ctx, taskId);
|
|
400
|
+
const task = await this.getIngameTask(ctx, taskId, includeApiKey);
|
|
372
401
|
if (task.status === 200)
|
|
373
402
|
return task.data;
|
|
374
403
|
if (task.status === null)
|
|
@@ -404,7 +433,8 @@ class RocomClient {
|
|
|
404
433
|
return null;
|
|
405
434
|
}
|
|
406
435
|
const path = '/api/v1/games/rocom/ingame/home/info';
|
|
407
|
-
|
|
436
|
+
let includeApiKey = true;
|
|
437
|
+
let headers = this.wegameHeaders();
|
|
408
438
|
const payload = { uid: sanitizedUid, wait_ms: waitMs };
|
|
409
439
|
let { status, data } = await this.requestWithStatus(ctx, 'POST', path, headers, {
|
|
410
440
|
json: payload,
|
|
@@ -422,6 +452,29 @@ class RocomClient {
|
|
|
422
452
|
if (status === 200 && data && !(data.task_id || data.taskId || data.taskID))
|
|
423
453
|
return data;
|
|
424
454
|
}
|
|
455
|
+
if (status === null && includeApiKey && this.apiKey && this.isApiKeyPermissionUndeclaredError(this.getLastError(''))) {
|
|
456
|
+
logger.warn('ingame/home/info rejected X-API-Key, retrying without API key');
|
|
457
|
+
includeApiKey = false;
|
|
458
|
+
headers = this.wegameHeaders('', '', '', '', false);
|
|
459
|
+
const retry = await this.requestWithStatus(ctx, 'POST', path, headers, {
|
|
460
|
+
json: payload,
|
|
461
|
+
acceptedStatuses: [200, 202],
|
|
462
|
+
});
|
|
463
|
+
status = retry.status;
|
|
464
|
+
data = retry.data;
|
|
465
|
+
if (status === 200 && data && !(data.task_id || data.taskId || data.taskID))
|
|
466
|
+
return data;
|
|
467
|
+
if (status === null) {
|
|
468
|
+
const fallback = await this.requestWithStatus(ctx, 'GET', path, headers, {
|
|
469
|
+
params: payload,
|
|
470
|
+
acceptedStatuses: [200, 202],
|
|
471
|
+
});
|
|
472
|
+
status = fallback.status;
|
|
473
|
+
data = fallback.data;
|
|
474
|
+
if (status === 200 && data && !(data.task_id || data.taskId || data.taskID))
|
|
475
|
+
return data;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
425
478
|
const taskId = data?.task_id || data?.taskId || data?.taskID;
|
|
426
479
|
if (!taskId) {
|
|
427
480
|
if (status === 202)
|
|
@@ -430,7 +483,7 @@ class RocomClient {
|
|
|
430
483
|
}
|
|
431
484
|
for (let i = 0; i < 10; i++) {
|
|
432
485
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
433
|
-
const task = await this.getIngameTask(ctx, taskId);
|
|
486
|
+
const task = await this.getIngameTask(ctx, taskId, includeApiKey);
|
|
434
487
|
if (task.status === 200)
|
|
435
488
|
return task.data;
|
|
436
489
|
if (task.status === null)
|
|
@@ -441,10 +494,22 @@ class RocomClient {
|
|
|
441
494
|
}
|
|
442
495
|
async ingameMerchantInfo(ctx, shopId) {
|
|
443
496
|
const params = { shop_id: shopId };
|
|
444
|
-
|
|
497
|
+
let headers = this.wegameHeaders();
|
|
498
|
+
const data = await this.get(ctx, '/api/v1/games/rocom/ingame/merchant/info', headers, params, { silentFailureDetails: true });
|
|
445
499
|
if (data)
|
|
446
500
|
return data;
|
|
447
|
-
|
|
501
|
+
const postData = await this.post(ctx, '/api/v1/games/rocom/ingame/merchant/info', headers, params);
|
|
502
|
+
if (postData)
|
|
503
|
+
return postData;
|
|
504
|
+
if (this.apiKey && this.isApiKeyPermissionUndeclaredError(this.getLastError(''))) {
|
|
505
|
+
logger.warn('ingame/merchant/info rejected X-API-Key, retrying without API key');
|
|
506
|
+
headers = this.wegameHeaders('', '', '', '', false);
|
|
507
|
+
const fallbackData = await this.get(ctx, '/api/v1/games/rocom/ingame/merchant/info', headers, params, { silentFailureDetails: true });
|
|
508
|
+
if (fallbackData)
|
|
509
|
+
return fallbackData;
|
|
510
|
+
return this.post(ctx, '/api/v1/games/rocom/ingame/merchant/info', headers, params);
|
|
511
|
+
}
|
|
512
|
+
return null;
|
|
448
513
|
}
|
|
449
514
|
async getFriendship(ctx, fwToken, userIds, userIdentifier = '') {
|
|
450
515
|
return this.get(ctx, '/api/v1/games/rocom/social/friendship', this.rocomHeaders(fwToken, userIdentifier), { user_ids: userIds });
|
package/lib/commands/query.js
CHANGED
|
@@ -373,10 +373,18 @@ function homePlantIcon(deps, iconId) {
|
|
|
373
373
|
return deps.renderer.resourceUrl(`render-templates/home/img/home_icon/${text}_2.png`);
|
|
374
374
|
}
|
|
375
375
|
let homePlantMapCache = null;
|
|
376
|
+
const HOME_PLANT_MAP_RELATIVE_PATH = node_path_1.default.join('render-templates', 'home', 'data', 'home_item_list.json');
|
|
377
|
+
function resolveHomePlantMapPath() {
|
|
378
|
+
const candidates = [
|
|
379
|
+
node_path_1.default.resolve(__dirname, '..', HOME_PLANT_MAP_RELATIVE_PATH),
|
|
380
|
+
node_path_1.default.resolve(__dirname, HOME_PLANT_MAP_RELATIVE_PATH),
|
|
381
|
+
];
|
|
382
|
+
return candidates.find(candidate => node_fs_1.default.existsSync(candidate)) || candidates[0];
|
|
383
|
+
}
|
|
376
384
|
function loadHomePlantMap() {
|
|
377
385
|
if (homePlantMapCache)
|
|
378
386
|
return homePlantMapCache;
|
|
379
|
-
const filePath =
|
|
387
|
+
const filePath = resolveHomePlantMapPath();
|
|
380
388
|
try {
|
|
381
389
|
const data = JSON.parse(node_fs_1.default.readFileSync(filePath, 'utf-8'));
|
|
382
390
|
homePlantMapCache = data && typeof data === 'object' ? data : {};
|
package/lib/index.js
CHANGED
|
@@ -59,9 +59,9 @@ var RocomClient = class {
|
|
|
59
59
|
if (!uid) return "";
|
|
60
60
|
return uid.trim().replace(/[^a-zA-Z0-9_\- \u4e00-\u9fa5]/g, "").trim();
|
|
61
61
|
}
|
|
62
|
-
wegameHeaders(fwToken = "", userIdentifier = "", clientType = "", clientId = "") {
|
|
62
|
+
wegameHeaders(fwToken = "", userIdentifier = "", clientType = "", clientId = "", includeApiKey = true) {
|
|
63
63
|
const headers = {};
|
|
64
|
-
if (this.apiKey) headers["X-API-Key"] = this.apiKey;
|
|
64
|
+
if (includeApiKey && this.apiKey) headers["X-API-Key"] = this.apiKey;
|
|
65
65
|
if (fwToken) headers["X-Framework-Token"] = fwToken;
|
|
66
66
|
if (userIdentifier) headers["X-User-Identifier"] = this.sanitizeUid(userIdentifier);
|
|
67
67
|
if (clientType) headers["X-Client-Type"] = clientType;
|
|
@@ -123,6 +123,10 @@ var RocomClient = class {
|
|
|
123
123
|
return String(value);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
+
isApiKeyPermissionUndeclaredError(message) {
|
|
127
|
+
if (!message) return false;
|
|
128
|
+
return /未声明\s*api\s*key\s*权限|api\s*key\s*permission|api key 权限/i.test(message);
|
|
129
|
+
}
|
|
126
130
|
logRequestFailureDetails(method, path6, headers, params, body, errorOrResponse) {
|
|
127
131
|
const err = errorOrResponse;
|
|
128
132
|
const response = err?.response;
|
|
@@ -265,12 +269,12 @@ ${this.stringifyForLog(details)}`);
|
|
|
265
269
|
return { status: null, data: null };
|
|
266
270
|
}
|
|
267
271
|
}
|
|
268
|
-
async getIngameTask(ctx, taskId) {
|
|
272
|
+
async getIngameTask(ctx, taskId, includeApiKey = true) {
|
|
269
273
|
return this.requestWithStatus(
|
|
270
274
|
ctx,
|
|
271
275
|
"GET",
|
|
272
276
|
`/api/v1/games/rocom/ingame/tasks/${taskId}`,
|
|
273
|
-
this.wegameHeaders(),
|
|
277
|
+
this.wegameHeaders("", "", "", "", includeApiKey),
|
|
274
278
|
{ acceptedStatuses: [200, 202] }
|
|
275
279
|
);
|
|
276
280
|
}
|
|
@@ -358,7 +362,8 @@ ${this.stringifyForLog(details)}`);
|
|
|
358
362
|
return null;
|
|
359
363
|
}
|
|
360
364
|
const path6 = "/api/v1/games/rocom/ingame/player/search";
|
|
361
|
-
|
|
365
|
+
let includeApiKey = true;
|
|
366
|
+
let headers = this.wegameHeaders();
|
|
362
367
|
const payload = { uid: sanitizedUid, wait_ms: 5e3 };
|
|
363
368
|
let { status, data } = await this.requestWithStatus(ctx, "POST", path6, headers, {
|
|
364
369
|
json: payload,
|
|
@@ -374,6 +379,27 @@ ${this.stringifyForLog(details)}`);
|
|
|
374
379
|
data = fallback.data;
|
|
375
380
|
if (status === 200 && data && this.isIngamePlayerPayload(data)) return data;
|
|
376
381
|
}
|
|
382
|
+
if (status === null && includeApiKey && this.apiKey && this.isApiKeyPermissionUndeclaredError(this.getLastError(""))) {
|
|
383
|
+
logger.warn("ingame/player/search rejected X-API-Key, retrying without API key");
|
|
384
|
+
includeApiKey = false;
|
|
385
|
+
headers = this.wegameHeaders("", "", "", "", false);
|
|
386
|
+
const retry = await this.requestWithStatus(ctx, "POST", path6, headers, {
|
|
387
|
+
json: payload,
|
|
388
|
+
acceptedStatuses: [200, 202]
|
|
389
|
+
});
|
|
390
|
+
status = retry.status;
|
|
391
|
+
data = retry.data;
|
|
392
|
+
if (status === 200 && data && this.isIngamePlayerPayload(data)) return data;
|
|
393
|
+
if (status === null) {
|
|
394
|
+
const fallback = await this.requestWithStatus(ctx, "GET", path6, headers, {
|
|
395
|
+
params: payload,
|
|
396
|
+
acceptedStatuses: [200, 202]
|
|
397
|
+
});
|
|
398
|
+
status = fallback.status;
|
|
399
|
+
data = fallback.data;
|
|
400
|
+
if (status === 200 && data && this.isIngamePlayerPayload(data)) return data;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
377
403
|
if (!data) return null;
|
|
378
404
|
if (this.isIngamePlayerPayload(data)) return data;
|
|
379
405
|
const taskId = data.task_id || data.taskId || data.taskID;
|
|
@@ -383,7 +409,7 @@ ${this.stringifyForLog(details)}`);
|
|
|
383
409
|
}
|
|
384
410
|
for (let i = 0; i < 8; i++) {
|
|
385
411
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
386
|
-
const task = await this.getIngameTask(ctx, taskId);
|
|
412
|
+
const task = await this.getIngameTask(ctx, taskId, includeApiKey);
|
|
387
413
|
if (task.status === 200) return task.data;
|
|
388
414
|
if (task.status === null) return null;
|
|
389
415
|
}
|
|
@@ -416,7 +442,8 @@ ${this.stringifyForLog(details)}`);
|
|
|
416
442
|
return null;
|
|
417
443
|
}
|
|
418
444
|
const path6 = "/api/v1/games/rocom/ingame/home/info";
|
|
419
|
-
|
|
445
|
+
let includeApiKey = true;
|
|
446
|
+
let headers = this.wegameHeaders();
|
|
420
447
|
const payload = { uid: sanitizedUid, wait_ms: waitMs };
|
|
421
448
|
let { status, data } = await this.requestWithStatus(ctx, "POST", path6, headers, {
|
|
422
449
|
json: payload,
|
|
@@ -432,6 +459,27 @@ ${this.stringifyForLog(details)}`);
|
|
|
432
459
|
data = fallback.data;
|
|
433
460
|
if (status === 200 && data && !(data.task_id || data.taskId || data.taskID)) return data;
|
|
434
461
|
}
|
|
462
|
+
if (status === null && includeApiKey && this.apiKey && this.isApiKeyPermissionUndeclaredError(this.getLastError(""))) {
|
|
463
|
+
logger.warn("ingame/home/info rejected X-API-Key, retrying without API key");
|
|
464
|
+
includeApiKey = false;
|
|
465
|
+
headers = this.wegameHeaders("", "", "", "", false);
|
|
466
|
+
const retry = await this.requestWithStatus(ctx, "POST", path6, headers, {
|
|
467
|
+
json: payload,
|
|
468
|
+
acceptedStatuses: [200, 202]
|
|
469
|
+
});
|
|
470
|
+
status = retry.status;
|
|
471
|
+
data = retry.data;
|
|
472
|
+
if (status === 200 && data && !(data.task_id || data.taskId || data.taskID)) return data;
|
|
473
|
+
if (status === null) {
|
|
474
|
+
const fallback = await this.requestWithStatus(ctx, "GET", path6, headers, {
|
|
475
|
+
params: payload,
|
|
476
|
+
acceptedStatuses: [200, 202]
|
|
477
|
+
});
|
|
478
|
+
status = fallback.status;
|
|
479
|
+
data = fallback.data;
|
|
480
|
+
if (status === 200 && data && !(data.task_id || data.taskId || data.taskID)) return data;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
435
483
|
const taskId = data?.task_id || data?.taskId || data?.taskID;
|
|
436
484
|
if (!taskId) {
|
|
437
485
|
if (status === 202) this.setLastError("家园查询任务已入队,但未返回 task_id");
|
|
@@ -439,7 +487,7 @@ ${this.stringifyForLog(details)}`);
|
|
|
439
487
|
}
|
|
440
488
|
for (let i = 0; i < 10; i++) {
|
|
441
489
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
442
|
-
const task = await this.getIngameTask(ctx, taskId);
|
|
490
|
+
const task = await this.getIngameTask(ctx, taskId, includeApiKey);
|
|
443
491
|
if (task.status === 200) return task.data;
|
|
444
492
|
if (task.status === null) return null;
|
|
445
493
|
}
|
|
@@ -448,15 +496,31 @@ ${this.stringifyForLog(details)}`);
|
|
|
448
496
|
}
|
|
449
497
|
async ingameMerchantInfo(ctx, shopId) {
|
|
450
498
|
const params = { shop_id: shopId };
|
|
499
|
+
let headers = this.wegameHeaders();
|
|
451
500
|
const data = await this.get(
|
|
452
501
|
ctx,
|
|
453
502
|
"/api/v1/games/rocom/ingame/merchant/info",
|
|
454
|
-
|
|
503
|
+
headers,
|
|
455
504
|
params,
|
|
456
505
|
{ silentFailureDetails: true }
|
|
457
506
|
);
|
|
458
507
|
if (data) return data;
|
|
459
|
-
|
|
508
|
+
const postData = await this.post(ctx, "/api/v1/games/rocom/ingame/merchant/info", headers, params);
|
|
509
|
+
if (postData) return postData;
|
|
510
|
+
if (this.apiKey && this.isApiKeyPermissionUndeclaredError(this.getLastError(""))) {
|
|
511
|
+
logger.warn("ingame/merchant/info rejected X-API-Key, retrying without API key");
|
|
512
|
+
headers = this.wegameHeaders("", "", "", "", false);
|
|
513
|
+
const fallbackData = await this.get(
|
|
514
|
+
ctx,
|
|
515
|
+
"/api/v1/games/rocom/ingame/merchant/info",
|
|
516
|
+
headers,
|
|
517
|
+
params,
|
|
518
|
+
{ silentFailureDetails: true }
|
|
519
|
+
);
|
|
520
|
+
if (fallbackData) return fallbackData;
|
|
521
|
+
return this.post(ctx, "/api/v1/games/rocom/ingame/merchant/info", headers, params);
|
|
522
|
+
}
|
|
523
|
+
return null;
|
|
460
524
|
}
|
|
461
525
|
async getFriendship(ctx, fwToken, userIds, userIdentifier = "") {
|
|
462
526
|
return this.get(
|
|
@@ -2323,9 +2387,18 @@ function homePlantIcon(deps, iconId) {
|
|
|
2323
2387
|
}
|
|
2324
2388
|
__name(homePlantIcon, "homePlantIcon");
|
|
2325
2389
|
var homePlantMapCache = null;
|
|
2390
|
+
var HOME_PLANT_MAP_RELATIVE_PATH = import_node_path4.default.join("render-templates", "home", "data", "home_item_list.json");
|
|
2391
|
+
function resolveHomePlantMapPath() {
|
|
2392
|
+
const candidates = [
|
|
2393
|
+
import_node_path4.default.resolve(__dirname, "..", HOME_PLANT_MAP_RELATIVE_PATH),
|
|
2394
|
+
import_node_path4.default.resolve(__dirname, HOME_PLANT_MAP_RELATIVE_PATH)
|
|
2395
|
+
];
|
|
2396
|
+
return candidates.find((candidate) => import_node_fs4.default.existsSync(candidate)) || candidates[0];
|
|
2397
|
+
}
|
|
2398
|
+
__name(resolveHomePlantMapPath, "resolveHomePlantMapPath");
|
|
2326
2399
|
function loadHomePlantMap() {
|
|
2327
2400
|
if (homePlantMapCache) return homePlantMapCache;
|
|
2328
|
-
const filePath =
|
|
2401
|
+
const filePath = resolveHomePlantMapPath();
|
|
2329
2402
|
try {
|
|
2330
2403
|
const data = JSON.parse(import_node_fs4.default.readFileSync(filePath, "utf-8"));
|
|
2331
2404
|
homePlantMapCache = data && typeof data === "object" ? data : {};
|