koishi-plugin-subscription 0.0.7 → 0.0.8

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.
@@ -0,0 +1,16 @@
1
+ import { Dict, Schema } from 'koishi';
2
+ export interface AppConfig {
3
+ alias: string[];
4
+ themeColor?: string;
5
+ allowedAccounts: {
6
+ id: string;
7
+ name: string;
8
+ alias: string;
9
+ }[];
10
+ }
11
+ export interface Config {
12
+ apps: Dict<AppConfig>;
13
+ minAuthority: number;
14
+ mode: 'noAdmin' | 'and' | 'or';
15
+ }
16
+ export declare const Config: Schema<Config>;
package/lib/index.d.ts CHANGED
@@ -1,77 +1,11 @@
1
- import { Context, Dict, Schema, Service, Fragment } from 'koishi';
2
- interface RecordsItem {
3
- app: string;
4
- id: string;
5
- createdAt: Date;
6
- }
7
- interface SubscriptionItem {
8
- id: number;
9
- app: string;
10
- account: string;
11
- groupId: string;
12
- createdAt: Date;
13
- }
14
- interface AppConfig {
15
- alias: string[];
16
- allowedAccounts: {
17
- id: string;
18
- name: string;
19
- alias: string;
20
- }[];
21
- }
22
- export interface Config {
23
- apps: Dict<AppConfig>;
24
- minAuthority: number;
25
- mode: "noAdmin" | "and" | "or";
26
- }
27
- export declare const Config: Schema<Config>;
1
+ import { Context } from 'koishi';
2
+ import { Config } from './config';
3
+ import type { Config as SubscriptionConfig } from './config';
4
+ export { Config };
5
+ export { SubscriptionService } from './service';
28
6
  export declare const name = "subscription";
29
7
  export declare const inject: {
30
8
  required: string[];
31
9
  optional: string[];
32
10
  };
33
- declare module 'koishi' {
34
- interface Context {
35
- subscription: SubscriptionService;
36
- }
37
- interface Tables {
38
- subscription_service: SubscriptionItem;
39
- subscription_records: RecordsItem;
40
- }
41
- }
42
- declare class SubscriptionService extends Service {
43
- readonly subTableName = "subscription_service";
44
- readonly recTableName = "subscription_records";
45
- subsConfig: Config;
46
- appMap: Map<string, string>;
47
- accountMap: Map<string, string>;
48
- constructor(ctx: Context, config: Config);
49
- initMap(): void;
50
- private getApp;
51
- checkExist(app: string, id: string): Promise<boolean>;
52
- getAccount(app: string, account: string): string;
53
- getName(app: string, account: string): string;
54
- getAvailableAccounts(app: string): string[];
55
- getSubscribedGroups(app: string, account: string): Promise<string[]>;
56
- broadcast(app: string, account: string, content: Fragment): Promise<void>;
57
- private getSelfIds;
58
- private getAssignedChannels;
59
- broadcastForward(app: string, account: string, content: Fragment): Promise<any[]>;
60
- addSubscription(app: string, account: string, groupId: string): Promise<{
61
- status: boolean;
62
- msg: string;
63
- }>;
64
- removeSubscription(app: string, account: string, groupId: string): Promise<boolean>;
65
- getGroupSubscriptions(groupId: string): Promise<SubscriptionItem[]>;
66
- getAllSubscriptions(): Promise<SubscriptionItem[]>;
67
- getSubscriptionStats(): Promise<{
68
- app: string;
69
- account: string;
70
- count: number;
71
- }[]>;
72
- private authCheck;
73
- private getChannelId;
74
- private registerCommands;
75
- }
76
- export declare function apply(ctx: Context, config: Config): void;
77
- export {};
11
+ export declare function apply(ctx: Context, config: SubscriptionConfig): void;
package/lib/index.js CHANGED
@@ -21,33 +21,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  Config: () => Config,
24
+ SubscriptionService: () => SubscriptionService,
24
25
  apply: () => apply,
25
26
  inject: () => inject,
26
27
  name: () => name
27
28
  });
28
29
  module.exports = __toCommonJS(src_exports);
29
- var import_koishi = require("koishi");
30
30
 
31
- // src/retry.ts
32
- async function retry(retries, fn, delay = 500) {
33
- try {
34
- return await fn();
35
- } catch (err) {
36
- console.log(`剩余${retries}次尝试`, err);
37
- if (retries <= 1) throw err;
38
- await new Promise((r) => setTimeout(r, delay));
39
- return retry(retries - 1, fn, delay * 2);
40
- }
41
- }
42
- __name(retry, "retry");
43
-
44
- // src/index.tsx
45
- var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
31
+ // src/config.ts
32
+ var import_koishi = require("koishi");
46
33
  var Config = import_koishi.Schema.intersect([
47
34
  import_koishi.Schema.object({
48
35
  apps: import_koishi.Schema.dict(
49
36
  import_koishi.Schema.object({
50
37
  alias: import_koishi.Schema.array(import_koishi.Schema.string()).role("table").description("应用别名,如果重复,后面会覆盖前面的"),
38
+ themeColor: import_koishi.Schema.string().role("color").description("应用主题色,用于订阅列表展示,建议使用十六进制颜色,如 #1d9bf0"),
51
39
  allowedAccounts: import_koishi.Schema.array(
52
40
  import_koishi.Schema.object({
53
41
  id: import_koishi.Schema.string().required().description("账号id"),
@@ -67,16 +55,386 @@ var Config = import_koishi.Schema.intersect([
67
55
  ]).default("or").role("radio").description("权限模式")
68
56
  }).description("权限配置")
69
57
  ]);
70
- var name = "subscription";
71
- var inject = {
72
- required: ["database"],
73
- optional: ["puppeteer"]
74
- };
75
- var SubscriptionService = class extends import_koishi.Service {
58
+
59
+ // src/service.tsx
60
+ var import_koishi2 = require("koishi");
61
+
62
+ // src/render.ts
63
+ function generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp, appThemeColors = {}, options = {}) {
64
+ const apps = createAppViews(availableAccounts, subscribedByApp, appThemeColors);
65
+ const showTitle = options.showTitle ?? true;
66
+ return `
67
+ <!DOCTYPE html>
68
+ <html lang="zh-CN">
69
+ <head>
70
+ <meta charset="UTF-8">
71
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
72
+ <title>订阅状态总览</title>
73
+ <style>
74
+ :root {
75
+ --bg: #f5f7fb;
76
+ --panel: #ffffff;
77
+ --text: #1f2328;
78
+ --muted: #69727f;
79
+ --soft: #f8fafc;
80
+ --line: #d9e0e8;
81
+ --line-soft: #e8edf3;
82
+ --ok: #157347;
83
+ --ok-bg: #e6f4ec;
84
+ --ok-line: #a8d8bd;
85
+ --off: #8a95a3;
86
+ --off-bg: #f2f4f7;
87
+ --accent: #315f8a;
88
+ --app-color: var(--accent);
89
+ --app-color-soft: rgba(49, 95, 138, 0.22);
90
+ --app-color-faint: rgba(49, 95, 138, 0.11);
91
+ --app-color-wash: rgba(49, 95, 138, 0.06);
92
+ --alias-bg: #fff5dc;
93
+ --alias-text: #745416;
94
+ --id-bg: #eef2f7;
95
+ --shadow: rgba(18, 27, 38, 0.05);
96
+ }
97
+ * {
98
+ box-sizing: border-box;
99
+ }
100
+ html,
101
+ body {
102
+ margin: 0;
103
+ min-height: 100%;
104
+ background: var(--bg);
105
+ color: var(--text);
106
+ font-family: Inter, "Segoe UI", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
107
+ }
108
+ body {
109
+ padding: 24px;
110
+ }
111
+ .page {
112
+ width: 1392px;
113
+ margin: 0 auto;
114
+ }
115
+ .title {
116
+ margin: 0 0 18px;
117
+ color: #17202b;
118
+ font-size: 32px;
119
+ line-height: 1.2;
120
+ font-weight: 820;
121
+ letter-spacing: 0;
122
+ }
123
+ .app {
124
+ margin-bottom: 22px;
125
+ overflow: hidden;
126
+ }
127
+ .app-head {
128
+ display: flex;
129
+ align-items: center;
130
+ min-height: 34px;
131
+ padding: 0 4px;
132
+ }
133
+ .app-name {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: 10px;
137
+ color: var(--app-color);
138
+ font-size: 26px;
139
+ line-height: 1.2;
140
+ font-weight: 820;
141
+ }
142
+ .app-name::before {
143
+ content: "";
144
+ width: 10px;
145
+ height: 10px;
146
+ border-radius: 999px;
147
+ background: var(--app-color);
148
+ box-shadow: 0 0 0 5px var(--app-color-faint);
149
+ }
150
+ .account-grid {
151
+ display: grid;
152
+ grid-template-columns: repeat(4, minmax(0, 1fr));
153
+ gap: 9px;
154
+ padding: 10px 0 0;
155
+ }
156
+ .account {
157
+ position: relative;
158
+ min-width: 0;
159
+ min-height: 78px;
160
+ padding: 10px 11px 9px 22px;
161
+ border-radius: 13px;
162
+ background: #ffffff;
163
+ display: grid;
164
+ grid-template-rows: auto auto;
165
+ gap: 6px;
166
+ box-shadow: 0 1px 1px var(--shadow);
167
+ }
168
+ .account::before {
169
+ content: "";
170
+ position: absolute;
171
+ inset: 10px auto 10px 8px;
172
+ width: 5px;
173
+ border-radius: 999px;
174
+ background: var(--off);
175
+ }
176
+ .account.subscribed::before {
177
+ background: var(--app-color);
178
+ }
179
+ .account.subscribed {
180
+ background: var(--app-color-wash);
181
+ }
182
+ .account.unsubscribed {
183
+ background: #ffffff;
184
+ color: #687280;
185
+ box-shadow: none;
186
+ }
187
+ .main-line {
188
+ min-width: 0;
189
+ display: grid;
190
+ grid-template-columns: minmax(0, 1fr) auto;
191
+ gap: 10px;
192
+ align-items: start;
193
+ }
194
+ .sub-line {
195
+ min-width: 0;
196
+ display: flex;
197
+ flex-wrap: wrap;
198
+ gap: 5px;
199
+ align-items: center;
200
+ }
201
+ .status {
202
+ display: inline-flex;
203
+ align-items: center;
204
+ justify-content: center;
205
+ width: 22px;
206
+ height: 22px;
207
+ }
208
+ .dot {
209
+ width: 8px;
210
+ height: 8px;
211
+ border-radius: 50%;
212
+ background: var(--off);
213
+ }
214
+ .subscribed .dot {
215
+ background: var(--app-color);
216
+ box-shadow: 0 0 0 3px var(--app-color-soft);
217
+ }
218
+ .subscribed .status {
219
+ color: var(--ok);
220
+ }
221
+ .unsubscribed .status {
222
+ color: var(--off);
223
+ }
224
+ .name {
225
+ min-width: 0;
226
+ overflow-wrap: anywhere;
227
+ display: -webkit-box;
228
+ overflow: hidden;
229
+ -webkit-line-clamp: 2;
230
+ -webkit-box-orient: vertical;
231
+ color: var(--text);
232
+ font-size: 18px;
233
+ line-height: 1.2;
234
+ font-weight: 780;
235
+ }
236
+ .unsubscribed .name {
237
+ color: #4f5b68;
238
+ font-weight: 700;
239
+ }
240
+ .id {
241
+ display: inline;
242
+ overflow-wrap: anywhere;
243
+ padding: 0;
244
+ border-radius: 0;
245
+ background: transparent;
246
+ color: #3f4b59;
247
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
248
+ font-size: 14px;
249
+ line-height: 1.3;
250
+ }
251
+ .id::before {
252
+ content: "@";
253
+ color: var(--app-color);
254
+ font-family: Inter, "Segoe UI", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
255
+ font-weight: 760;
256
+ }
257
+ .aliases {
258
+ display: flex;
259
+ flex-wrap: wrap;
260
+ gap: 5px;
261
+ }
262
+ .alias {
263
+ max-width: 100%;
264
+ overflow-wrap: anywhere;
265
+ padding: 0;
266
+ border-radius: 0;
267
+ background: transparent;
268
+ color: var(--app-color);
269
+ font-size: 13px;
270
+ line-height: 1.25;
271
+ font-weight: 720;
272
+ }
273
+ .alias::before {
274
+ content: "#";
275
+ opacity: 1;
276
+ }
277
+ .alias.empty {
278
+ background: transparent;
279
+ color: #9aa3af;
280
+ padding-left: 0;
281
+ font-weight: 520;
282
+ }
283
+ .alias.empty::before {
284
+ content: "";
285
+ }
286
+ .empty-row {
287
+ padding: 18px 4px;
288
+ color: var(--muted);
289
+ font-size: 18px;
290
+ }
291
+ </style>
292
+ </head>
293
+ <body>
294
+ <main class="page">
295
+ ${showTitle ? '<h1 class="title">当前群订阅</h1>' : ""}
296
+ ${apps.map(renderApp).join("")}
297
+ </main>
298
+ </body>
299
+ </html>
300
+ `;
301
+ }
302
+ __name(generateSubscriptionHTML, "generateSubscriptionHTML");
303
+ function createAppViews(availableAccounts, subscribedByApp, appThemeColors) {
304
+ return Object.entries(availableAccounts).map(([app, accounts]) => {
305
+ const subscribed = subscribedByApp[app] || /* @__PURE__ */ new Set();
306
+ return {
307
+ app,
308
+ theme: createTheme(appThemeColors[app], app),
309
+ accounts: accounts.map((account) => ({
310
+ ...account,
311
+ aliases: normalizeAliases(account.alias),
312
+ subscribed: subscribed.has(account.id)
313
+ })).sort((a, b) => Number(b.subscribed) - Number(a.subscribed))
314
+ };
315
+ });
316
+ }
317
+ __name(createAppViews, "createAppViews");
318
+ function normalizeAliases(aliases) {
319
+ return aliases.flatMap((alias) => alias.split(",")).map((alias) => alias.trim()).filter(Boolean);
320
+ }
321
+ __name(normalizeAliases, "normalizeAliases");
322
+ function renderApp(section) {
323
+ return `
324
+ <section class="app" style="${renderThemeStyle(section.theme)}">
325
+ <div class="app-head">
326
+ <div class="app-name">${escapeHtml(section.app)}</div>
327
+ </div>
328
+ ${section.accounts.length ? `<div class="account-grid">
329
+ ${section.accounts.map(renderAccount).join("")}
330
+ </div>` : '<div class="empty-row">暂无可用账号</div>'}
331
+ </section>
332
+ `;
333
+ }
334
+ __name(renderApp, "renderApp");
335
+ function createTheme(input, app) {
336
+ const color = normalizeColor(input, getDefaultThemeColor(app));
337
+ const rgb = hexToRgb(color);
338
+ return {
339
+ color,
340
+ soft: `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.22)`,
341
+ faint: `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.11)`,
342
+ wash: `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.06)`
343
+ };
344
+ }
345
+ __name(createTheme, "createTheme");
346
+ function getDefaultThemeColor(app) {
347
+ switch (app?.toLowerCase()) {
348
+ case "twitter":
349
+ return "#1d9bf0";
350
+ case "bilibili":
351
+ return "#fb7299";
352
+ case "instagram":
353
+ return "#c13584";
354
+ default:
355
+ return "#315f8a";
356
+ }
357
+ }
358
+ __name(getDefaultThemeColor, "getDefaultThemeColor");
359
+ function normalizeColor(input, fallback = "#315f8a") {
360
+ const value = input?.trim();
361
+ if (!value) return fallback;
362
+ if (/^#[0-9a-f]{3}$/i.test(value)) {
363
+ const [, r, g, b] = value;
364
+ return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
365
+ }
366
+ if (/^#[0-9a-f]{6}$/i.test(value)) {
367
+ return value.toLowerCase();
368
+ }
369
+ return fallback;
370
+ }
371
+ __name(normalizeColor, "normalizeColor");
372
+ function hexToRgb(hex) {
373
+ return {
374
+ r: Number.parseInt(hex.slice(1, 3), 16),
375
+ g: Number.parseInt(hex.slice(3, 5), 16),
376
+ b: Number.parseInt(hex.slice(5, 7), 16)
377
+ };
378
+ }
379
+ __name(hexToRgb, "hexToRgb");
380
+ function renderThemeStyle(theme) {
381
+ return [
382
+ `--app-color: ${theme.color}`,
383
+ `--app-color-soft: ${theme.soft}`,
384
+ `--app-color-faint: ${theme.faint}`,
385
+ `--app-color-wash: ${theme.wash}`
386
+ ].join("; ");
387
+ }
388
+ __name(renderThemeStyle, "renderThemeStyle");
389
+ function renderAccount(account) {
390
+ return `
391
+ <article class="account ${account.subscribed ? "subscribed" : "unsubscribed"}">
392
+ <div class="main-line">
393
+ <div class="name">${escapeHtml(account.name)}</div>
394
+ <span class="status"><span class="dot"></span></span>
395
+ </div>
396
+ <div class="sub-line">
397
+ <span class="id">${escapeHtml(account.id)}</span>
398
+ <span class="aliases">${renderAliases(account.aliases)}</span>
399
+ </div>
400
+ </article>
401
+ `;
402
+ }
403
+ __name(renderAccount, "renderAccount");
404
+ function renderAliases(aliases) {
405
+ return aliases.length ? aliases.map((alias) => `<span class="alias">${escapeHtml(alias)}</span>`).join("") : '<span class="alias empty">无别名</span>';
406
+ }
407
+ __name(renderAliases, "renderAliases");
408
+ function escapeHtml(value) {
409
+ return String(value ?? "").replace(/[&<>"']/g, (char) => ({
410
+ "&": "&amp;",
411
+ "<": "&lt;",
412
+ ">": "&gt;",
413
+ '"': "&quot;",
414
+ "'": "&#39;"
415
+ })[char]);
416
+ }
417
+ __name(escapeHtml, "escapeHtml");
418
+
419
+ // src/retry.ts
420
+ async function retry(retries, fn, delay = 500) {
421
+ try {
422
+ return await fn();
423
+ } catch (err) {
424
+ console.log(`剩余${retries}次尝试`, err);
425
+ if (retries <= 1) throw err;
426
+ await new Promise((r) => setTimeout(r, delay));
427
+ return retry(retries - 1, fn, delay * 2);
428
+ }
429
+ }
430
+ __name(retry, "retry");
431
+
432
+ // src/service.tsx
433
+ var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
434
+ var SubscriptionService = class extends import_koishi2.Service {
76
435
  static {
77
436
  __name(this, "SubscriptionService");
78
437
  }
79
- // 数据表名称
80
438
  subTableName = "subscription_service";
81
439
  recTableName = "subscription_records";
82
440
  subsConfig;
@@ -131,6 +489,7 @@ var SubscriptionService = class extends import_koishi.Service {
131
489
  }
132
490
  }
133
491
  getApp(app) {
492
+ if (!app) return;
134
493
  return this.appMap.get(app.toLowerCase());
135
494
  }
136
495
  async checkExist(app, id) {
@@ -146,19 +505,19 @@ var SubscriptionService = class extends import_koishi.Service {
146
505
  return false;
147
506
  }
148
507
  getAccount(app, account) {
508
+ if (!app || !account) return;
149
509
  return this.accountMap.get((app + account).toLowerCase());
150
510
  }
151
511
  getName(app, account) {
152
512
  app = this.getApp(app);
513
+ if (!app) return;
153
514
  return this.subsConfig.apps[app].allowedAccounts.find((item) => item.id === this.getAccount(app, account))?.name;
154
515
  }
155
- // 获取对应应用可以订阅的账号
156
516
  getAvailableAccounts(app) {
157
517
  app = this.getApp(app);
158
518
  const appConfig = this.subsConfig.apps[app];
159
519
  return appConfig ? appConfig.allowedAccounts.map((item) => item.id) : [];
160
520
  }
161
- // 根据应用和账号获取订阅了这个账号的所有群组
162
521
  async getSubscribedGroups(app, account) {
163
522
  app = this.getApp(app), account = this.getAccount(app, account);
164
523
  const subscriptions = await this.ctx.database.get(this.subTableName, {
@@ -199,6 +558,7 @@ var SubscriptionService = class extends import_koishi.Service {
199
558
  if (index < 0) continue;
200
559
  channels.splice(index, 1);
201
560
  }
561
+ ;
202
562
  ((assignMap[platform] ||= {})[assignee] ||= []).push(channel);
203
563
  }
204
564
  if (channels?.length) {
@@ -212,7 +572,7 @@ var SubscriptionService = class extends import_koishi.Service {
212
572
  type: "message",
213
573
  channel: {
214
574
  id: selfChannelId,
215
- type: import_koishi.Universal.Channel.Type.DIRECT
575
+ type: import_koishi2.Universal.Channel.Type.DIRECT
216
576
  },
217
577
  user: { id: bot.selfId }
218
578
  });
@@ -240,7 +600,7 @@ var SubscriptionService = class extends import_koishi.Service {
240
600
  const sessions = targets.map(({ id, guildId, locales }) => {
241
601
  const session2 = bot.session({
242
602
  type: "message",
243
- channel: { id, type: import_koishi.Universal.Channel.Type.TEXT },
603
+ channel: { id, type: import_koishi2.Universal.Channel.Type.TEXT },
244
604
  guild: { id: guildId }
245
605
  });
246
606
  session2.locales = locales;
@@ -253,13 +613,13 @@ var SubscriptionService = class extends import_koishi.Service {
253
613
  }
254
614
  }))).flat(1);
255
615
  }
256
- // 添加订阅
257
616
  async addSubscription(app, account, groupId) {
258
- app = this.getApp(app), account = this.getAccount(app, account);
259
- const appConfig = this.getAvailableAccounts(app);
260
- if (!appConfig) {
617
+ app = this.getApp(app);
618
+ if (!app) {
261
619
  return { status: false, msg: "应用不存在" };
262
620
  }
621
+ account = this.getAccount(app, account);
622
+ const appConfig = this.getAvailableAccounts(app);
263
623
  if (!appConfig.includes(account)) {
264
624
  return { status: false, msg: "账号不在白名单中" };
265
625
  }
@@ -279,9 +639,11 @@ var SubscriptionService = class extends import_koishi.Service {
279
639
  });
280
640
  return { status: true, msg: "订阅成功" };
281
641
  }
282
- // 删除订阅
283
642
  async removeSubscription(app, account, groupId) {
284
- app = this.appMap.get(app), account = this.getAccount(app, account);
643
+ app = this.getApp(app);
644
+ if (!app) return false;
645
+ account = this.getAccount(app, account);
646
+ if (!account) return false;
285
647
  const result = await this.ctx.database.remove(this.subTableName, {
286
648
  app,
287
649
  account,
@@ -289,15 +651,12 @@ var SubscriptionService = class extends import_koishi.Service {
289
651
  });
290
652
  return result.removed > 0;
291
653
  }
292
- // 获取群组的所有订阅
293
654
  async getGroupSubscriptions(groupId) {
294
655
  return await this.ctx.database.get(this.subTableName, { groupId });
295
656
  }
296
- // 获取所有订阅(用于管理)
297
657
  async getAllSubscriptions() {
298
658
  return await this.ctx.database.get(this.subTableName, {});
299
659
  }
300
- // 按应用获取订阅统计
301
660
  async getSubscriptionStats() {
302
661
  const subscriptions = await this.getAllSubscriptions();
303
662
  const stats = {};
@@ -328,50 +687,112 @@ var SubscriptionService = class extends import_koishi.Service {
328
687
  if (!channel) return;
329
688
  return `${channel.platform}:${channel.id}`;
330
689
  }
690
+ async getSubscriptionListView(app, groupId) {
691
+ const subscriptions = await this.getGroupSubscriptions(groupId);
692
+ const subscribedByApp = {};
693
+ subscriptions.forEach((sub) => {
694
+ if (!subscribedByApp[sub.app]) {
695
+ subscribedByApp[sub.app] = /* @__PURE__ */ new Set();
696
+ }
697
+ subscribedByApp[sub.app].add(sub.account);
698
+ });
699
+ const availableAccounts = {};
700
+ const appThemeColors = {};
701
+ const appConfig = this.subsConfig.apps;
702
+ const targetApp = app ? this.getApp(app) : void 0;
703
+ if (app && !targetApp) {
704
+ return `应用不存在:${app}
705
+ 请使用配置中的应用名或应用别名,例如:订阅列表 twitter`;
706
+ }
707
+ for (const appName in appConfig) {
708
+ if (targetApp && appName !== targetApp) continue;
709
+ appThemeColors[appName] = appConfig[appName].themeColor;
710
+ const subscribed = subscribedByApp[appName] || /* @__PURE__ */ new Set();
711
+ availableAccounts[appName] = appConfig[appName].allowedAccounts.filter((account) => targetApp || subscribed.has(account.id)).map((account) => ({
712
+ id: account.id,
713
+ name: account.name,
714
+ alias: account.alias ? account.alias.split(",") : []
715
+ }));
716
+ }
717
+ return {
718
+ targetApp,
719
+ subscribedByApp,
720
+ availableAccounts,
721
+ appThemeColors
722
+ };
723
+ }
724
+ renderSubscriptionListText(view) {
725
+ let result = ``;
726
+ for (const app in view.availableAccounts) {
727
+ result += `【${app}】
728
+ `;
729
+ const subscribed = view.subscribedByApp[app] || /* @__PURE__ */ new Set();
730
+ view.availableAccounts[app].forEach((account) => {
731
+ const isSubscribed = subscribed.has(account.id);
732
+ const status = isSubscribed ? "✅ 已订阅" : "❌ 未订阅";
733
+ const aliases = account.alias.length > 0 ? ` (${account.alias.join(", ")})` : "";
734
+ result += `${status} ${account.name} id:${account.id}
735
+ ${aliases}
736
+ `;
737
+ });
738
+ result += "\n";
739
+ }
740
+ return result;
741
+ }
331
742
  registerCommands(ctx, config) {
332
- const sub = ctx.command("subscription <app:string> [...accounts]", "添加订阅,账号可以使用 用户名 用户id 或是别名,格式:订阅 <应用名> <账号> [...更多账号]").alias("订阅").alias("添加订阅").userFields(["authority"]).example("推特订阅 爱美 伊藤彩沙").example("订阅 twitter aimi_sound").action(async ({ session, options }, app, ...accounts) => {
743
+ const screenshotWidth = 1440;
744
+ const screenshotDeviceScaleFactor = 2;
745
+ const screenshotQuality = 82;
746
+ const sub = ctx.command("subscription <app:string> [...accounts]", "为当前群添加账号订阅。账号可使用 ID、名称或别名,可一次添加多个。").alias("订阅").alias("添加订阅").userFields(["authority"]).example("订阅 twitter aimi_sound ayasa_ito").example("推特订阅 爱美 伊藤彩沙").action(async ({ session, options }, app, ...accounts) => {
333
747
  if (!await this.authCheck(session, config)) {
334
748
  return "权限不足";
335
749
  }
336
750
  if (!app || !accounts || accounts.length == 0) {
337
- return "请指定应用名和账号,格式:订阅 <应用名> <账号> [...更多账号]";
751
+ return "请指定应用名和账号。\n用法:订阅 <应用名> <账号> [...更多账号]\n示例:订阅 twitter aimi_sound ayasa_ito";
752
+ }
753
+ const appName = this.getApp(app);
754
+ if (!appName) {
755
+ return `应用不存在:${app}`;
338
756
  }
339
- accounts;
340
757
  const groupId = this.getChannelId(session.channel);
341
758
  if (!groupId) {
342
759
  return "请在群聊中使用当前指令";
343
760
  }
344
761
  let result = "";
345
762
  for (let account of accounts) {
346
- app = this.getApp(app), account = this.getName(app, account);
347
- const { status, msg } = await this.addSubscription(app, account, groupId);
763
+ const accountName = this.getName(appName, account) || account;
764
+ const { status, msg } = await this.addSubscription(appName, accountName, groupId);
348
765
  if (status) {
349
- result += `成功为群组 ${groupId} 添加订阅:${app} - ${account}
766
+ result += `成功为当前群添加订阅:${appName} - ${accountName}
350
767
  `;
351
768
  } else {
352
- result += `添加订阅 ${app} - ${account} 失败,${msg}
769
+ result += `添加订阅 ${appName} - ${accountName} 失败,${msg}
353
770
  `;
354
771
  }
355
772
  }
356
773
  return result;
357
774
  });
358
- const unsub = ctx.command("subscription.remove <app:string> <account:string>", "删除订阅").alias("删除订阅").alias("取消订阅").userFields(["authority"]).example("取消推特订阅 爱美").example("取消订阅 twitter aimi_sound").action(async ({ session, options }, app, account) => {
775
+ const unsub = ctx.command("subscription.remove <app:string> <account:string>", "从当前群删除一个账号订阅。账号可使用 ID、名称或别名。").alias("删除订阅").alias("取消订阅").userFields(["authority"]).example("取消订阅 twitter aimi_sound").example("取消推特订阅 爱美").action(async ({ session, options }, app, account) => {
359
776
  if (!await this.authCheck(session, config)) {
360
777
  return "权限不足";
361
778
  }
362
779
  if (!app || !account) {
363
- return "请指定应用名和账号,格式:取消订阅 <应用名> <账号>";
780
+ return "请指定应用名和账号。\n用法:取消订阅 <应用名> <账号>\n示例:取消订阅 twitter aimi_sound";
781
+ }
782
+ const appName = this.getApp(app);
783
+ if (!appName) {
784
+ return `应用不存在:${app}`;
364
785
  }
365
- app = this.getApp(app), account = this.getName(app, account);
786
+ const accountName = this.getName(appName, account) || account;
366
787
  const groupId = this.getChannelId(session.channel);
367
788
  if (!groupId) {
368
789
  return "请在群聊中使用当前指令";
369
790
  }
370
- const success = await this.removeSubscription(app, account, groupId);
791
+ const success = await this.removeSubscription(appName, accountName, groupId);
371
792
  if (success) {
372
- return `成功为群组 ${groupId} 删除订阅:${app} - ${account}`;
793
+ return `成功为当前群删除订阅:${appName} - ${accountName}`;
373
794
  } else {
374
- return `删除订阅失败,可能的原因:订阅不存在`;
795
+ return "删除订阅失败,可能的原因:订阅不存在";
375
796
  }
376
797
  });
377
798
  for (const app in config.apps) {
@@ -382,330 +803,50 @@ var SubscriptionService = class extends import_koishi.Service {
382
803
  unsub.alias(`取消${appAlias}订阅`, { args: [app] });
383
804
  }
384
805
  }
385
- ctx.command("subscription.list", "查看当前群组的订阅").alias("订阅列表").userFields(["authority"]).action(async ({ session, options }) => {
386
- if (!await this.authCheck(session, config)) {
806
+ ctx.command("subscription.list [app:string]", "查看当前群订阅。默认只显示已订阅账号;指定应用时显示该应用完整状态。").alias("订阅列表").userFields(["authority"]).example("订阅列表").example("订阅列表 twitter").example("订阅列表 推特").action(async ({ session, options }, app) => {
807
+ const passedAuth = await this.authCheck(session, config);
808
+ if (!passedAuth) {
387
809
  return "权限不足";
388
810
  }
389
811
  const groupId = this.getChannelId(session.channel);
390
812
  if (!groupId) {
391
813
  return "请在群聊中使用当前指令";
392
814
  }
393
- const subscriptions = await this.getGroupSubscriptions(groupId);
394
- const subscribedByApp = {};
395
- subscriptions.forEach((sub2) => {
396
- if (!subscribedByApp[sub2.app]) {
397
- subscribedByApp[sub2.app] = /* @__PURE__ */ new Set();
398
- }
399
- subscribedByApp[sub2.app].add(sub2.account);
400
- });
401
- const availableAccounts = {};
402
- const appConfig = this.subsConfig.apps;
403
- for (const app in appConfig) {
404
- availableAccounts[app] = appConfig[app].allowedAccounts.map((account) => ({
405
- id: account.id,
406
- name: account.name,
407
- alias: account.alias ? account.alias.split(",") : []
408
- }));
409
- }
815
+ const view = await this.getSubscriptionListView(app, groupId);
816
+ if (typeof view === "string") return view;
817
+ const textFallback = /* @__PURE__ */ __name(() => this.renderSubscriptionListText(view), "textFallback");
410
818
  if (!ctx.puppeteer) {
411
- let result = ``;
412
- for (const app in availableAccounts) {
413
- result += `【${app}】
414
- `;
415
- const subscribed = subscribedByApp[app] || /* @__PURE__ */ new Set();
416
- availableAccounts[app].forEach((account) => {
417
- const isSubscribed = subscribed.has(account.id);
418
- const status = isSubscribed ? "✅ 已订阅" : "❌ 未订阅";
419
- const aliases = account.alias.length > 0 ? ` (${account.alias.join(", ")})` : "";
420
- result += `${status} ${account.name} id:${account.id}
421
- ${aliases}
422
- `;
423
- });
424
- result += "\n";
425
- }
426
- return result;
819
+ return textFallback();
427
820
  }
428
- const html = generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp);
429
- const page = await ctx.puppeteer.page();
821
+ const html = generateSubscriptionHTML(groupId, view.availableAccounts, view.subscribedByApp, view.appThemeColors, {
822
+ showTitle: !view.targetApp
823
+ });
824
+ let page;
430
825
  try {
826
+ page = await ctx.puppeteer.page();
827
+ page.setDefaultTimeout?.(15e3);
431
828
  await page.setViewport({
432
- width: 1e3,
433
- height: 800
829
+ width: screenshotWidth,
830
+ height: 1,
831
+ deviceScaleFactor: screenshotDeviceScaleFactor
434
832
  });
435
833
  await page.setContent(html, {
436
- waitUntil: "networkidle0"
834
+ waitUntil: "load"
437
835
  });
438
836
  const image = await page.screenshot({
439
837
  type: "jpeg",
838
+ quality: screenshotQuality,
440
839
  fullPage: true
441
840
  });
442
- return `<image url="data:image/png;base64,${image.toString("base64")}" />`;
841
+ const base64 = image.toString("base64");
842
+ return `<image url="data:image/jpeg;base64,${base64}" />`;
843
+ } catch (error) {
844
+ return textFallback();
443
845
  } finally {
444
- await page.close();
846
+ await page?.close();
445
847
  }
446
848
  });
447
- function generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp) {
448
- return `
449
- <!DOCTYPE html>
450
- <html>
451
- <head>
452
- <meta charset="UTF-8">
453
- <style>
454
- * {
455
- margin: 0;
456
- padding: 0;
457
- box-sizing: border-box;
458
- }
459
- body {
460
- font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
461
- background: #f5f7fa;
462
- min-height: 100vh;
463
- padding: 20px;
464
- }
465
- .container {
466
- max-width: 1000px;
467
- margin: 0 auto;
468
- }
469
- .header {
470
- text-align: center;
471
- margin-bottom: 20px;
472
- color: #2c3e50;
473
- }
474
- .header h1 {
475
- font-size: 36px;
476
- margin-bottom: 12px;
477
- font-weight: 900;
478
- }
479
- .header .subtitle {
480
- font-size: 21px;
481
- color: #7f8c8d;
482
- }
483
- .apps-container {
484
- background: white;
485
- border-radius: 12px;
486
- box-shadow: 0 3px 18px rgba(0,0,0,0.08);
487
- overflow: hidden;
488
- }
489
- .app-section {
490
- border-bottom: 1px solid #eaeaea;
491
- }
492
- .app-section:last-child {
493
- border-bottom: none;
494
- }
495
- .app-title {
496
- font-size: 24px;
497
- font-weight: 600;
498
- color: #34495e;
499
- padding: 18px 24px;
500
- background: #f8f9fa;
501
- border-bottom: 1px solid #eaeaea;
502
- display: flex;
503
- align-items: center;
504
- gap: 12px;
505
- }
506
- .app-title::before {
507
- content: "▸";
508
- font-size: 21px;
509
- color: #3498db;
510
- }
511
- .grid {
512
- display: grid;
513
- grid-template-columns: repeat(2, 1fr);
514
- gap: 0;
515
- }
516
- .account-card {
517
- padding: 21px;
518
- border-right: 1px solid #f0f0f0;
519
- border-bottom: 1px solid #f0f0f0;
520
- transition: all 0.2s ease;
521
- position: relative;
522
- min-height: 120px;
523
- display: flex;
524
- flex-direction: column;
525
- }
526
- .account-card:nth-child(4n+1),
527
- .account-card:nth-child(4n+4) {
528
- background: #f8f9fa;
529
- }
530
- .account-card:nth-child(4n+2),
531
- .account-card:nth-child(4n+3) {
532
- background: #f0f2f5;
533
- }
534
- .account-card:hover {
535
- background: #e6f3ff !important;
536
- }
537
- .account-card:nth-child(2n) {
538
- border-right: none;
539
- }
540
- .account-card:last-child {
541
- border-right: none;
542
- }
543
- .name-id-container {
544
- display: flex;
545
- justify-content: space-between;
546
- align-items: center;
547
- margin-bottom: 12px;
548
- flex-wrap: wrap;
549
- }
550
- .name {
551
- font-size: 21px;
552
- font-weight: 900;
553
- color: #2c3e50;
554
- line-height: 1.3;
555
- max-width: 60%;
556
- overflow: hidden;
557
- text-overflow: ellipsis;
558
- white-space: nowrap;
559
- }
560
- .id {
561
- font-size: 21px;
562
- color: #5a6c7d;
563
- font-family: 'Courier New', monospace;
564
- background: #f8f9fa;
565
- padding: 4.5px 9px;
566
- border-radius: 4.5px;
567
- line-height: 1.3;
568
- max-width: 35%;
569
- overflow: hidden;
570
- text-overflow: ellipsis;
571
- white-space: nowrap;
572
- }
573
- .name-id-container.vertical {
574
- flex-direction: column;
575
- align-items: flex-start;
576
- }
577
- .name-id-container.vertical .name {
578
- max-width: 100%;
579
- margin-bottom: 6px;
580
- }
581
- .name-id-container.vertical .id {
582
- max-width: 100%;
583
- align-self: flex-end;
584
- }
585
- .alias-status-container {
586
- display: flex;
587
- justify-content: space-between;
588
- margin-top: 12px;
589
- flex-grow: 1;
590
- }
591
- .alias-container {
592
- flex: 1;
593
- max-width: calc(100% - 105px);
594
- align-self: flex-start;
595
- }
596
- .alias {
597
- font-size: 20px;
598
- color: #6c757d;
599
- display: flex;
600
- flex-wrap: wrap;
601
- gap: 6px;
602
- align-items: flex-start;
603
- }
604
- .alias-tag {
605
- background: #e8f4fd;
606
- color: #1971c2;
607
- padding: 3px 9px;
608
- border-radius: 15px;
609
- border: 1px solid #a5d8ff;
610
- white-space: nowrap;
611
- margin-bottom: 3px;
612
- }
613
- .no-alias {
614
- font-size: 20px;
615
- color: #adb5bd;
616
- font-style: italic;
617
- }
618
- .status-container {
619
- display: flex;
620
- align-items: flex-end;
621
- margin-left: 12px;
622
- }
623
- .status {
624
- display: inline-flex;
625
- align-items: center;
626
- gap: 9px;
627
- padding: 4.5px 15px;
628
- border-radius: 24px;
629
- font-size: 20px;
630
- font-weight: 900;
631
- white-space: nowrap;
632
- flex-shrink: 0;
633
- }
634
- .subscribed {
635
- background: #d4edda;
636
- color: #155724;
637
- border: 1px solid #c3e6cb;
638
- }
639
- .unsubscribed {
640
- background: #f8d7da;
641
- color: #721c24;
642
- border: 1px solid #f5c6cb;
643
- }
644
- .empty-state {
645
- text-align: center;
646
- color: #6c757d;
647
- font-style: italic;
648
- padding: 45px;
649
- background: #f8f9fa;
650
- grid-column: 1 / -1;
651
- }
652
- </style>
653
- </head>
654
- <body>
655
- <div class="container">
656
- <div class="header">
657
- <h1>订阅状态总览</h1>
658
- </div>
659
-
660
- <div class="apps-container">
661
- ${Object.entries(availableAccounts).map(([app, accounts]) => {
662
- const subscribed = subscribedByApp[app] || /* @__PURE__ */ new Set();
663
- return `
664
- <div class="app-section">
665
- <div class="app-title">${app}</div>
666
- <div class="grid">
667
- ${accounts.length > 0 ? accounts.map((account) => {
668
- const isSubscribed = subscribed.has(account.id);
669
- const needsVerticalLayout = account.name.length > 15 || account.id.length > 20;
670
- return `
671
- <div class="account-card">
672
- <div class="name-id-container ${needsVerticalLayout ? "vertical" : ""}">
673
- <div class="name">${account.name}</div>
674
- <div class="id">${account.id}</div>
675
- </div>
676
- <div class="alias-status-container">
677
- <div class="alias-container">
678
- ${account.alias.length > 0 ? `
679
- <div class="alias">
680
- ${account.alias.map((alias) => `<span class="alias-tag">${alias}</span>`).join("")}
681
- </div>
682
- ` : `<div class="no-alias">无别名</div>`}
683
- </div>
684
- <div class="status-container">
685
- <div class="status ${isSubscribed ? "subscribed" : "unsubscribed"}">
686
- ${isSubscribed ? "✅ 已订阅" : "❌ 未订阅"}
687
- </div>
688
- </div>
689
- </div>
690
- </div>
691
- `;
692
- }).join("") : `
693
- <div class="empty-state">
694
- 暂无可用账号
695
- </div>
696
- `}
697
- </div>
698
- </div>
699
- `;
700
- }).join("")}
701
- </div>
702
- </div>
703
- </body>
704
- </html>
705
- `;
706
- }
707
- __name(generateSubscriptionHTML, "generateSubscriptionHTML");
708
- ctx.command("subscription.clear", "删除群组的所有订阅").alias("清空订阅").userFields(["authority"]).action(async ({ session }) => {
849
+ ctx.command("subscription.clear [app:string]", "清空当前群订阅。可指定应用名或别名;不指定时清空全部。执行前会要求二次确认。").alias("清空订阅").userFields(["authority"]).example("清空订阅").example("清空订阅 twitter").example("清空订阅 推特").action(async ({ session }, app) => {
709
850
  if (!await this.authCheck(session, config)) {
710
851
  return "权限不足";
711
852
  }
@@ -713,12 +854,20 @@ var SubscriptionService = class extends import_koishi.Service {
713
854
  if (!groupId) {
714
855
  return "请在群聊中使用当前指令";
715
856
  }
716
- const subscriptions = await this.getGroupSubscriptions(groupId);
857
+ const targetApp = app ? this.getApp(app) : void 0;
858
+ if (app && !targetApp) {
859
+ return `应用不存在:${app}
860
+ 请使用配置中的应用名或应用别名,例如:清空订阅 twitter`;
861
+ }
862
+ const query = targetApp ? { groupId, app: targetApp } : { groupId };
863
+ const subscriptions = await ctx.database.get(this.subTableName, query);
864
+ const scopeText = targetApp ? `应用 ${targetApp}` : "所有应用";
717
865
  if (subscriptions.length === 0) {
718
- return `群组 ${groupId} 暂无订阅`;
866
+ return `当前群暂无${scopeText}的订阅`;
719
867
  }
720
- const confirm = await session.send(
721
- `确认要清空当前群聊的所有订阅吗?
868
+ await session.send(
869
+ `确认要清空当前群的${scopeText}订阅吗?
870
+ 将删除 ${subscriptions.length} 个订阅。
722
871
  请输入 "是" 或 "确认" 或 "yes" 来确认删除,输入其他内容取消。`
723
872
  );
724
873
  const response = await session.prompt(3e4);
@@ -726,13 +875,13 @@ var SubscriptionService = class extends import_koishi.Service {
726
875
  return "操作已取消(超时)。";
727
876
  }
728
877
  if (["是", "确认", "yes", "y"].includes(response.toLowerCase())) {
729
- await ctx.database.remove("subscription_service", { groupId });
730
- return `已删除群组 ${groupId} 的所有订阅(共 ${subscriptions.length} 个)`;
878
+ await ctx.database.remove(this.subTableName, query);
879
+ return `已删除当前群的${scopeText}订阅(共 ${subscriptions.length} 个)`;
731
880
  } else {
732
881
  return "操作已取消。";
733
882
  }
734
883
  });
735
- ctx.command("subscription.stats", "查看订阅统计", {
884
+ ctx.command("subscription.stats", "查看所有订阅的群组数量统计。", {
736
885
  permissions: [`authority:${config.minAuthority}`],
737
886
  hidden: true
738
887
  }).alias("订阅统计").userFields(["authority"]).action(async ({ session }) => {
@@ -748,6 +897,13 @@ ${statsList}`;
748
897
  });
749
898
  }
750
899
  };
900
+
901
+ // src/index.tsx
902
+ var name = "subscription";
903
+ var inject = {
904
+ required: ["database"],
905
+ optional: ["puppeteer"]
906
+ };
751
907
  function apply(ctx, config) {
752
908
  ctx.plugin(SubscriptionService, config);
753
909
  }
@@ -755,6 +911,7 @@ __name(apply, "apply");
755
911
  // Annotate the CommonJS export names for ESM import in node:
756
912
  0 && (module.exports = {
757
913
  Config,
914
+ SubscriptionService,
758
915
  apply,
759
916
  inject,
760
917
  name
@@ -0,0 +1,14 @@
1
+ import { Dict } from 'koishi';
2
+ interface AccountItem {
3
+ id: string;
4
+ name: string;
5
+ alias: string[];
6
+ }
7
+ interface ThemeInput {
8
+ [app: string]: string | undefined;
9
+ }
10
+ interface RenderOptions {
11
+ showTitle?: boolean;
12
+ }
13
+ export declare function generateSubscriptionHTML(groupId: string, availableAccounts: Dict<AccountItem[]>, subscribedByApp: Dict<Set<string>>, appThemeColors?: ThemeInput, options?: RenderOptions): string;
14
+ export {};
@@ -0,0 +1,60 @@
1
+ import { Context, Service, Fragment } from 'koishi';
2
+ import type { Config } from './config';
3
+ interface RecordsItem {
4
+ app: string;
5
+ id: string;
6
+ createdAt: Date;
7
+ }
8
+ interface SubscriptionItem {
9
+ id: number;
10
+ app: string;
11
+ account: string;
12
+ groupId: string;
13
+ createdAt: Date;
14
+ }
15
+ declare module 'koishi' {
16
+ interface Context {
17
+ subscription: SubscriptionService;
18
+ }
19
+ interface Tables {
20
+ subscription_service: SubscriptionItem;
21
+ subscription_records: RecordsItem;
22
+ }
23
+ }
24
+ export declare class SubscriptionService extends Service {
25
+ readonly subTableName = "subscription_service";
26
+ readonly recTableName = "subscription_records";
27
+ subsConfig: Config;
28
+ appMap: Map<string, string>;
29
+ accountMap: Map<string, string>;
30
+ constructor(ctx: Context, config: Config);
31
+ initMap(): void;
32
+ private getApp;
33
+ checkExist(app: string, id: string): Promise<boolean>;
34
+ getAccount(app: string, account: string): string;
35
+ getName(app: string, account: string): string;
36
+ getAvailableAccounts(app: string): string[];
37
+ getSubscribedGroups(app: string, account: string): Promise<string[]>;
38
+ broadcast(app: string, account: string, content: Fragment): Promise<void>;
39
+ private getSelfIds;
40
+ private getAssignedChannels;
41
+ broadcastForward(app: string, account: string, content: Fragment): Promise<any[]>;
42
+ addSubscription(app: string, account: string, groupId: string): Promise<{
43
+ status: boolean;
44
+ msg: string;
45
+ }>;
46
+ removeSubscription(app: string, account: string, groupId: string): Promise<boolean>;
47
+ getGroupSubscriptions(groupId: string): Promise<SubscriptionItem[]>;
48
+ getAllSubscriptions(): Promise<SubscriptionItem[]>;
49
+ getSubscriptionStats(): Promise<{
50
+ app: string;
51
+ account: string;
52
+ count: number;
53
+ }[]>;
54
+ private authCheck;
55
+ private getChannelId;
56
+ private getSubscriptionListView;
57
+ private renderSubscriptionListText;
58
+ private registerCommands;
59
+ }
60
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-subscription",
3
3
  "description": "给多个应用提供订阅群组管理",
4
- "version": "0.0.7",
4
+ "version": "0.0.8",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [