koishi-plugin-rocom 1.0.18 → 1.0.19

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.
Files changed (57) hide show
  1. package/lib/announcement-service.d.ts +21 -0
  2. package/lib/announcement-service.js +63 -0
  3. package/lib/async-control.d.ts +3 -0
  4. package/lib/async-control.js +48 -0
  5. package/lib/client.d.ts +48 -7
  6. package/lib/client.js +244 -125
  7. package/lib/commands/egg.js +66 -4
  8. package/lib/commands/merchant.js +144 -146
  9. package/lib/commands/query.js +148 -117
  10. package/lib/commands/ranking.d.ts +2 -0
  11. package/lib/commands/ranking.js +31 -0
  12. package/lib/commands/share-code.d.ts +2 -0
  13. package/lib/commands/share-code.js +66 -0
  14. package/lib/commands/tools.js +47 -59
  15. package/lib/egg-service.d.ts +82 -8
  16. package/lib/egg-service.js +235 -19
  17. package/lib/img//345/274/202/350/211/262.png +0 -0
  18. package/lib/img//347/202/253/345/275/251.png +0 -0
  19. package/lib/index.d.ts +5 -0
  20. package/lib/index.js +16 -3
  21. package/lib/merchant-clock.d.ts +22 -0
  22. package/lib/merchant-clock.js +95 -0
  23. package/lib/merchant-service.d.ts +24 -0
  24. package/lib/merchant-service.js +148 -0
  25. package/lib/permissions.d.ts +16 -0
  26. package/lib/permissions.js +66 -0
  27. package/lib/pet-data-service.js +7 -9
  28. package/lib/pet-size.d.ts +13 -0
  29. package/lib/pet-size.js +54 -0
  30. package/lib/player-service.d.ts +37 -0
  31. package/lib/player-service.js +201 -0
  32. package/lib/ranking-service.d.ts +46 -0
  33. package/lib/ranking-service.js +137 -0
  34. package/lib/render-templates/announcement/detail.html +8 -0
  35. package/lib/render-templates/announcement/list.html +5 -0
  36. package/lib/render-templates/announcement/style.css +1 -0
  37. package/lib/render-templates/pet-ranking/index.html +99 -0
  38. package/lib/render-templates/pet-ranking/style.css +338 -0
  39. package/lib/render-templates/player-search/index.html +7 -0
  40. package/lib/render-templates/searcheggs/index.html +1 -1
  41. package/lib/render-templates/searcheggs/size.html +70 -68
  42. package/lib/render-templates/share-code-team/index.html +105 -0
  43. package/lib/render-templates/share-code-team/style.css +345 -0
  44. package/lib/render.d.ts +15 -2
  45. package/lib/render.js +120 -37
  46. package/lib/send-image.d.ts +1 -1
  47. package/lib/send-image.js +12 -1
  48. package/lib/share-code-service.d.ts +32 -0
  49. package/lib/share-code-service.js +184 -0
  50. package/lib/subscription-runner.d.ts +6 -0
  51. package/lib/subscription-runner.js +21 -0
  52. package/lib/subscription-send.d.ts +4 -2
  53. package/lib/subscription-send.js +45 -20
  54. package/lib/types.d.ts +5 -0
  55. package/lib/user.d.ts +5 -0
  56. package/package.json +4 -1
  57. package/readme.md +145 -124
@@ -0,0 +1,21 @@
1
+ export type AnnouncementBlock = {
2
+ text: string;
3
+ image: string;
4
+ };
5
+ export declare function plainAnnouncementText(value: unknown): string;
6
+ export declare function buildAnnouncementView(data: any, baseUrl: string): {
7
+ title: string;
8
+ id: string;
9
+ publishedAt: string;
10
+ blocks: AnnouncementBlock[];
11
+ commandHint: string;
12
+ copyright: string;
13
+ };
14
+ export declare function announcementViewText(view: ReturnType<typeof buildAnnouncementView>): string;
15
+ export declare function buildAnnouncementListView(data: any, page: number): {
16
+ title: string;
17
+ page: number;
18
+ items: any;
19
+ commandHint: string;
20
+ copyright: string;
21
+ };
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.plainAnnouncementText = plainAnnouncementText;
4
+ exports.buildAnnouncementView = buildAnnouncementView;
5
+ exports.announcementViewText = announcementViewText;
6
+ exports.buildAnnouncementListView = buildAnnouncementListView;
7
+ const player_service_1 = require("./player-service");
8
+ function plainAnnouncementText(value) {
9
+ return String(value ?? '').replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, '')
10
+ .replace(/<br\s*\/?>|<\/(?:p|div|h[1-6]|li)>/gi, '\n')
11
+ .replace(/<[^>]*>/g, '').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&')
12
+ .replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"')
13
+ .replace(/\n{3,}/g, '\n\n').trim();
14
+ }
15
+ function buildAnnouncementView(data, baseUrl) {
16
+ const item = data?.detail || data?.announcement || data || {};
17
+ const content = typeof item.content === 'object' ? item.content?.text : item.content;
18
+ const html = String(content || item.text || item.summary || '')
19
+ .replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, '');
20
+ const blocks = [];
21
+ const images = new Set();
22
+ const addText = (value) => {
23
+ const text = plainAnnouncementText(value);
24
+ if (text)
25
+ blocks.push({ text, image: '' });
26
+ };
27
+ const addImage = (value) => {
28
+ const url = (0, player_service_1.resourceUrl)(value, baseUrl);
29
+ if (!/^https?:\/\//i.test(url) || images.has(url))
30
+ return;
31
+ images.add(url);
32
+ blocks.push({ text: '', image: url });
33
+ };
34
+ let offset = 0;
35
+ for (const match of html.matchAll(/<img\b[^>]*\bsrc\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))[^>]*>/gi)) {
36
+ addText(html.slice(offset, match.index));
37
+ addImage(match[1] || match[2] || match[3]);
38
+ offset = match.index + match[0].length;
39
+ }
40
+ addText(html.slice(offset));
41
+ for (const index of Array.isArray(item.content?.indexes) ? item.content.indexes : []) {
42
+ for (const image of Array.isArray(index?.imageUrl) ? index.imageUrl : [])
43
+ addImage(image);
44
+ }
45
+ return {
46
+ title: String(item.title || '洛克公告'), id: String(item.thread_id || item.id || ''),
47
+ publishedAt: String(item.publishAt || item.published_at || item.createdAt || ''),
48
+ blocks, commandHint: '洛克.公告详情 <公告ID>', copyright: 'Koishi · 洛克王国',
49
+ };
50
+ }
51
+ function announcementViewText(view) {
52
+ return [view.title, view.publishedAt, ...view.blocks.map(block => block.text || block.image)].filter(Boolean).join('\n');
53
+ }
54
+ function buildAnnouncementListView(data, page) {
55
+ const items = Array.isArray(data?.items) ? data.items : Array.isArray(data?.list) ? data.list : [];
56
+ return {
57
+ title: '洛克公告', page,
58
+ items: items.map((item) => ({ id: String(item.thread_id || item.id || ''),
59
+ title: String(item.title || '未命名公告'), summary: plainAnnouncementText(item.summary),
60
+ publishedAt: String(item.publishAt || item.published_at || item.createdAt || '') })),
61
+ commandHint: '洛克.公告 [页码] · 洛克.公告详情 <公告ID>', copyright: 'Koishi · 洛克王国',
62
+ };
63
+ }
@@ -0,0 +1,3 @@
1
+ /** A deadline cancels the underlying operation as well as the caller's wait. */
2
+ export declare function withDeadline<T>(timeoutMs: number, parent: AbortSignal | undefined, task: (signal: AbortSignal) => Promise<T>, onAbort?: () => void): Promise<T>;
3
+ export declare function delay(ms: number, signal?: AbortSignal): Promise<void>;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withDeadline = withDeadline;
4
+ exports.delay = delay;
5
+ /** A deadline cancels the underlying operation as well as the caller's wait. */
6
+ async function withDeadline(timeoutMs, parent, task, onAbort) {
7
+ const controller = new AbortController();
8
+ const forward = () => controller.abort(parent?.reason ?? new Error('操作已取消'));
9
+ if (parent?.aborted)
10
+ forward();
11
+ else
12
+ parent?.addEventListener('abort', forward, { once: true });
13
+ const timer = setTimeout(() => controller.abort(new Error('操作超时')), Math.max(1, timeoutMs));
14
+ let stop = () => { };
15
+ const cancelled = new Promise((_, reject) => {
16
+ stop = () => {
17
+ onAbort?.();
18
+ reject(controller.signal.reason);
19
+ };
20
+ if (controller.signal.aborted)
21
+ stop();
22
+ else
23
+ controller.signal.addEventListener('abort', stop, { once: true });
24
+ });
25
+ try {
26
+ return await Promise.race([cancelled, Promise.resolve().then(() => {
27
+ controller.signal.throwIfAborted();
28
+ return task(controller.signal);
29
+ })]);
30
+ }
31
+ finally {
32
+ clearTimeout(timer);
33
+ parent?.removeEventListener('abort', forward);
34
+ controller.signal.removeEventListener('abort', stop);
35
+ }
36
+ }
37
+ function delay(ms, signal) {
38
+ return new Promise((resolve, reject) => {
39
+ if (signal?.aborted)
40
+ return reject(signal.reason);
41
+ const cancel = () => { clearTimeout(timer); reject(signal?.reason); };
42
+ const timer = setTimeout(() => {
43
+ signal?.removeEventListener('abort', cancel);
44
+ resolve();
45
+ }, Math.max(0, ms));
46
+ signal?.addEventListener('abort', cancel, { once: true });
47
+ });
48
+ }
package/lib/client.d.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  import { Context } from 'koishi';
2
+ export type JsonObject = Record<string, unknown>;
3
+ export declare const isObject: (v: unknown) => v is JsonObject;
4
+ export declare function inheritGoodsMapping<T extends JsonObject>(parent: JsonObject, child: T): T & {
5
+ _goods_mapping?: unknown;
6
+ };
7
+ /** 传给 ingame 请求的可选授权上下文:指定 UID 查询时透传凭证,不自动替换为主账号。 */
8
+ export interface IngameAuthContext {
9
+ fwToken?: string;
10
+ userIdentifier?: string;
11
+ }
2
12
  export interface IngameTaskPollOptions {
3
13
  /** 服务端同步等待毫秒(long-poll),这段时间内服务端会尽量直接返回结果而不入队 */
4
14
  waitMs?: number;
@@ -8,6 +18,8 @@ export interface IngameTaskPollOptions {
8
18
  timeoutMs?: number;
9
19
  /** 任务进入排队(拿到 task_id)时回调一次,可用于向用户发送“排队中”提示 */
10
20
  onQueued?: (taskId: string) => void | Promise<void>;
21
+ /** 取消信号;插件卸载或调用方放弃时用于中止在途请求与轮询 */
22
+ signal?: AbortSignal;
11
23
  }
12
24
  export declare class RocomClient {
13
25
  private baseUrl;
@@ -17,6 +29,7 @@ export declare class RocomClient {
17
29
  private lastErrorBrief;
18
30
  constructor(baseUrl: string, apiKey: string, timeout?: number);
19
31
  private sanitizeUid;
32
+ private attachGoodsMapping;
20
33
  private wegameHeaders;
21
34
  private rocomHeaders;
22
35
  private formatHttpError;
@@ -38,9 +51,10 @@ export declare class RocomClient {
38
51
  private static normalizeTaskStatus;
39
52
  private static extractTaskId;
40
53
  private static isCompletedGatewayPayload;
41
- private static extractCompletedIngamePayload;
54
+ private static inspectIngamePayload;
42
55
  private static taskErrorMessage;
43
56
  private pollIngameTask;
57
+ private queuedQuery;
44
58
  qqQrLogin(ctx: Context, userIdentifier: string): Promise<any>;
45
59
  qqQrStatus(ctx: Context, fwToken: string, userIdentifier: string): Promise<any>;
46
60
  wechatQrLogin(ctx: Context, userIdentifier: string): Promise<any>;
@@ -61,12 +75,33 @@ export declare class RocomClient {
61
75
  getBattleOverview(ctx: Context, fwToken: string, userIdentifier?: string): Promise<any>;
62
76
  getBattleList(ctx: Context, fwToken: string, pageSize?: number, afterTime?: string, userIdentifier?: string): Promise<any>;
63
77
  private isIngamePlayerPayload;
64
- ingamePlayerSearch(ctx: Context, uid: string): Promise<any>;
78
+ ingamePlayerSearch(ctx: Context, uid: string, options?: IngameTaskPollOptions & {
79
+ auth?: IngameAuthContext;
80
+ }): Promise<any>;
81
+ ingamePlayerCard(ctx: Context, uid: string, options?: IngameTaskPollOptions & {
82
+ auth?: IngameAuthContext;
83
+ source?: string;
84
+ }): Promise<any>;
65
85
  getPets(ctx: Context, fwToken: string, petSubset?: number, pageNo?: number, pageSize?: number, userIdentifier?: string): Promise<any>;
66
86
  getLineupList(ctx: Context, fwToken: string, pageNo?: number, category?: string, userIdentifier?: string): Promise<any>;
67
87
  getExchangePosters(ctx: Context, fwToken: string, pageNo?: number, userIdentifier?: string): Promise<any>;
68
- getMerchantInfo(ctx: Context, refresh?: boolean): Promise<any>;
88
+ getMerchantInfo(ctx: Context, refresh?: boolean, options?: IngameTaskPollOptions & {
89
+ auth?: IngameAuthContext;
90
+ }): Promise<any>;
69
91
  queryPetSize(ctx: Context, diameter: number, weight: number, pool?: string, pageNo?: number, pageSize?: number, userIdentifier?: string): Promise<any>;
92
+ searchEggBySize(ctx: Context, heightMeters: number, weightKg: number, pageNo?: number, pageSize?: number, userIdentifier?: string): Promise<any>;
93
+ getPetCollectionRanking(ctx: Context, rankType: 'shining' | 'glass', limit?: number, uid?: string, options?: {
94
+ userIdentifier?: string;
95
+ }): Promise<any>;
96
+ parseShareCode(ctx: Context, shareCode: string, userIdentifier?: string): Promise<any>;
97
+ getShareCodeRecords(ctx: Context, options?: {
98
+ shareCode?: string;
99
+ hash?: string;
100
+ pageNo?: number;
101
+ pageSize?: number;
102
+ modeId?: number;
103
+ magicId?: number;
104
+ }, userIdentifier?: string): Promise<any>;
70
105
  getActivitiesInfo(ctx: Context, refresh?: boolean, userIdentifier?: string): Promise<any>;
71
106
  syncConfig(ctx: Context, userIdentifier?: string): Promise<any>;
72
107
  getAnnouncementList(ctx: Context, params?: {
@@ -78,7 +113,7 @@ export declare class RocomClient {
78
113
  getLatestAnnouncement(ctx: Context, params?: {
79
114
  category_id?: number | string;
80
115
  order?: string;
81
- }, userIdentifier?: string): Promise<any>;
116
+ }, userIdentifier?: string, signal?: AbortSignal): Promise<any>;
82
117
  getAnnouncementDetail(ctx: Context, threadId: number | string, userIdentifier?: string): Promise<any>;
83
118
  getEggGroups(ctx: Context, userIdentifier?: string): Promise<any>;
84
119
  getEggGroupPets(ctx: Context, groupIds: string | number[], matchMode?: 'any' | 'all', pageNo?: number, pageSize?: number, userIdentifier?: string): Promise<any>;
@@ -92,12 +127,18 @@ export declare class RocomClient {
92
127
  getEggExchangeSubscriptions(ctx: Context, userIdentifier?: string): Promise<any>;
93
128
  deleteEggExchangeSubscription(ctx: Context, subscriptionId: string | number, userIdentifier?: string): Promise<any>;
94
129
  getEggExchangeEvents(ctx: Context, subscriptionId: string | number, afterEventId?: string, limit?: number, userIdentifier?: string): Promise<any>;
95
- ingameHomeInfo(ctx: Context, uid: string, options?: IngameTaskPollOptions): Promise<any>;
96
- ingameMerchantInfo(ctx: Context, shopId: string | number): Promise<any>;
130
+ ingameHomeInfo(ctx: Context, uid: string, options?: IngameTaskPollOptions & {
131
+ auth?: IngameAuthContext;
132
+ }): Promise<any>;
133
+ ingameMerchantInfo(ctx: Context, shopId?: string | number | null, options?: IngameTaskPollOptions & {
134
+ auth?: IngameAuthContext;
135
+ }): Promise<any>;
97
136
  ingamePetData(ctx: Context, uid: string, extras?: {
98
137
  petGid?: string | number;
99
138
  npcId?: string | number;
100
- }, options?: IngameTaskPollOptions): Promise<any>;
139
+ }, options?: IngameTaskPollOptions & {
140
+ auth?: IngameAuthContext;
141
+ }): Promise<any>;
101
142
  getFriendship(ctx: Context, fwToken: string, userIds: string, userIdentifier?: string): Promise<any>;
102
143
  getStudentState(ctx: Context, fwToken: string, accountType?: number, userIdentifier?: string): Promise<any>;
103
144
  getStudentPerks(ctx: Context, fwToken: string, area?: number, accountType?: number, userIdentifier?: string): Promise<any>;