koishi-plugin-githubsth 1.0.2 → 1.0.3-alpha.1

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.
@@ -7,6 +7,7 @@ declare module 'koishi' {
7
7
  }
8
8
  export declare class Notifier extends Service {
9
9
  config: Config;
10
+ static inject: string[];
10
11
  constructor(ctx: Context, config: Config);
11
12
  private registerListeners;
12
13
  private handleEvent;
@@ -11,16 +11,20 @@ class Notifier extends koishi_1.Service {
11
11
  this.registerListeners();
12
12
  }
13
13
  registerListeners() {
14
+ // adapter-github canonical event names
15
+ this.ctx.on('github/issue', (payload) => this.handleEvent('issues', payload));
16
+ this.ctx.on('github/issue-comment', (payload) => this.handleEvent('issue_comment', payload));
17
+ this.ctx.on('github/pull-request', (payload) => this.handleEvent('pull_request', payload));
18
+ this.ctx.on('github/workflow-run', (payload) => this.handleEvent('workflow_run', payload));
19
+ // Backward compatibility aliases
14
20
  this.ctx.on('github/push', (payload) => this.handleEvent('push', payload));
15
21
  this.ctx.on('github/issues', (payload) => this.handleEvent('issues', payload));
16
22
  this.ctx.on('github/pull_request', (payload) => this.handleEvent('pull_request', payload));
17
- this.ctx.on('github/pull-request', (payload) => this.handleEvent('pull_request', payload));
18
23
  this.ctx.on('github/star', (payload) => this.handleEvent('star', payload));
19
24
  this.ctx.on('github/fork', (payload) => this.handleEvent('fork', payload));
20
25
  this.ctx.on('github/release', (payload) => this.handleEvent('release', payload));
21
26
  this.ctx.on('github/discussion', (payload) => this.handleEvent('discussion', payload));
22
27
  this.ctx.on('github/workflow_run', (payload) => this.handleEvent('workflow_run', payload));
23
- this.ctx.on('github/workflow-run', (payload) => this.handleEvent('workflow_run', payload));
24
28
  this.ctx.on('github/issue_comment', (payload) => this.handleEvent('issue_comment', payload));
25
29
  this.ctx.on('github/issue-comment', (payload) => this.handleEvent('issue_comment', payload));
26
30
  this.ctx.on('github/pull-request-review', (payload) => this.handleEvent('pull_request_review', payload));
@@ -50,7 +54,7 @@ class Notifier extends koishi_1.Service {
50
54
  else if (realPayload.commits)
51
55
  eventType = 'push';
52
56
  else if (realPayload.starred_at !== undefined || (realPayload.action === 'started'))
53
- eventType = 'star'; // star event usually has action 'created' but check payload structure
57
+ eventType = 'star';
54
58
  else if (realPayload.forkee)
55
59
  eventType = 'fork';
56
60
  else if (realPayload.release)
@@ -59,7 +63,6 @@ class Notifier extends koishi_1.Service {
59
63
  eventType = 'discussion';
60
64
  else if (realPayload.workflow_run)
61
65
  eventType = 'workflow_run';
62
- // Handle raw star event if it has repository info directly
63
66
  else if (realPayload.repository && (realPayload.action === 'created' || realPayload.action === 'started'))
64
67
  eventType = 'star';
65
68
  if (eventType !== 'unknown') {
@@ -75,19 +78,15 @@ class Notifier extends koishi_1.Service {
75
78
  if (this.config.debug) {
76
79
  this.ctx.logger('githubsth').info(`Received event: ${event}`);
77
80
  }
78
- // Check if payload is nested in an 'event' object (common in some adapter versions)
79
- // or if the event data is directly in payload
80
81
  const realPayload = payload.payload || payload;
81
- // Extract sender from wrapper if available (adapter-github often puts it in 'actor')
82
82
  if (payload.actor && !realPayload.sender) {
83
- realPayload.sender = payload.actor;
83
+ const actorLogin = payload.actor.login || payload.actor.name || 'GitHub';
84
+ realPayload.sender = { ...payload.actor, login: actorLogin };
84
85
  }
85
- // Extract repository from wrapper if available
86
86
  if (payload.repository && !realPayload.repository) {
87
87
  realPayload.repository = payload.repository;
88
88
  }
89
89
  let repoName = realPayload.repository?.full_name;
90
- // Try to fallback if repoName is missing
91
90
  if (!repoName && realPayload.issue?.repository_url) {
92
91
  const parts = realPayload.issue.repository_url.split('/');
93
92
  if (parts.length >= 2) {
@@ -97,33 +96,38 @@ class Notifier extends koishi_1.Service {
97
96
  if (!repoName && realPayload.pull_request?.base?.repo?.full_name) {
98
97
  repoName = realPayload.pull_request.base.repo.full_name;
99
98
  }
100
- // Special handling for 'star' event (which might be 'watch' event with action 'started')
101
- // The payload might be missing repository info in the main object but have it in the original session payload
99
+ // adapter-github eventData fields
100
+ if (!repoName && typeof payload.repoKey === 'string' && payload.repoKey.includes('/')) {
101
+ repoName = payload.repoKey;
102
+ }
103
+ if (!repoName && typeof payload.owner === 'string' && typeof payload.repo === 'string') {
104
+ repoName = `${payload.owner}/${payload.repo}`;
105
+ }
106
+ if (!repoName && typeof payload.repo === 'string' && payload.repo.includes('/')) {
107
+ repoName = payload.repo;
108
+ }
102
109
  if (!repoName && event === 'star') {
103
- // Sometimes the repository info is at the root of the payload, not inside 'payload' property
104
110
  if (payload.repository?.full_name) {
105
111
  repoName = payload.repository.full_name;
106
112
  }
107
113
  }
114
+ if (!repoName && payload.repository?.full_name) {
115
+ repoName = payload.repository.full_name;
116
+ }
108
117
  if (!repoName) {
109
118
  if (this.config.debug) {
110
119
  this.ctx.logger('githubsth').warn(`Missing repo info for event: ${event}. Keys: ${Object.keys(realPayload).join(', ')}`);
111
120
  }
112
121
  else if (this.config.logUnhandledEvents) {
113
- // Log at warning level if repo info is missing and logUnhandledEvents is on
114
122
  this.ctx.logger('githubsth').warn(`Missing repo info for event: ${event}. Keys: ${Object.keys(realPayload).join(', ')}`);
115
123
  }
116
- // Do not return here, let patching logic handle it with defaultRepo
117
124
  }
118
- // Patch realPayload with extracted repo info if missing
119
- // This is crucial for formatter to work correctly as it expects repository object
120
125
  if (!realPayload.repository) {
121
126
  realPayload.repository = { full_name: repoName || 'Unknown/Repo' };
122
127
  }
123
128
  else if (!realPayload.repository.full_name) {
124
129
  realPayload.repository.full_name = repoName || 'Unknown/Repo';
125
130
  }
126
- // Patch realPayload with sender info if missing (e.g. issues event)
127
131
  if (!realPayload.sender) {
128
132
  if (realPayload.issue?.user) {
129
133
  realPayload.sender = realPayload.issue.user;
@@ -138,11 +142,9 @@ class Notifier extends koishi_1.Service {
138
142
  realPayload.sender = { login: realPayload.pusher.name || 'Pusher' };
139
143
  }
140
144
  else {
141
- // Fallback sender
142
145
  realPayload.sender = { login: 'GitHub' };
143
146
  }
144
147
  }
145
- // Comprehensive patching for specific events to prevent formatter crashes
146
148
  try {
147
149
  this.patchPayloadForEvent(event, realPayload, repoName || 'Unknown/Repo');
148
150
  }
@@ -154,10 +156,6 @@ class Notifier extends koishi_1.Service {
154
156
  this.ctx.logger('notifier').info(`Received event ${event} for ${repoName}`);
155
157
  this.ctx.logger('notifier').debug(JSON.stringify(realPayload, null, 2));
156
158
  }
157
- // Get rules from database
158
- // Try to match both exact name and lowercase name to handle case sensitivity
159
- // If repoName is missing (undefined), we can't query rules effectively by repo name
160
- // But we might want to support global subscriptions or handle it gracefully
161
159
  if (!repoName) {
162
160
  this.ctx.logger('githubsth').warn('Cannot query rules: repoName is missing');
163
161
  return;
@@ -169,8 +167,6 @@ class Notifier extends koishi_1.Service {
169
167
  const dbRules = await this.ctx.database.get('github_subscription', {
170
168
  repo: repoNames
171
169
  });
172
- // Combine with config rules (if any, for backward compatibility or static rules)
173
- // Also match config rules case-insensitively if needed
174
170
  const configRules = (this.config.rules || []).filter((r) => r.repo === repoName ||
175
171
  r.repo === repoName.toLowerCase() ||
176
172
  r.repo === '*');
@@ -179,7 +175,6 @@ class Notifier extends koishi_1.Service {
179
175
  ...configRules
180
176
  ];
181
177
  const matchedRules = allRules.filter(rule => {
182
- // Event match
183
178
  if (!rule.events.includes('*') && !rule.events.includes(event))
184
179
  return false;
185
180
  return true;
@@ -199,7 +194,6 @@ class Notifier extends koishi_1.Service {
199
194
  this.ctx.logger('notifier').debug(`Found ${matchedRules.length} matching rules for ${repoName}`);
200
195
  }
201
196
  let message = null;
202
- // Ensure formatter is loaded
203
197
  if (!this.ctx.githubsthFormatter) {
204
198
  this.ctx.logger('notifier').warn('Formatter service not available');
205
199
  return;
@@ -259,11 +253,9 @@ class Notifier extends koishi_1.Service {
259
253
  }
260
254
  }
261
255
  patchPayloadForEvent(event, payload, repoName) {
262
- // Ensure sender exists (handled before, but good for type safety)
263
256
  const defaultUser = { login: 'GitHub', id: 0, avatar_url: '' };
264
257
  if (!payload.sender)
265
258
  payload.sender = defaultUser;
266
- // Ensure repository exists (handled before, but good for type safety)
267
259
  const defaultRepo = { full_name: repoName, stargazers_count: 0, html_url: `https://github.com/${repoName}` };
268
260
  if (!payload.repository)
269
261
  payload.repository = defaultRepo;
@@ -277,7 +269,6 @@ class Notifier extends koishi_1.Service {
277
269
  payload.ref = 'refs/heads/unknown';
278
270
  if (!payload.compare)
279
271
  payload.compare = '';
280
- // Ensure author exists in commits
281
272
  if (payload.commits.length > 0) {
282
273
  payload.commits.forEach((c) => {
283
274
  if (!c.author)
@@ -294,7 +285,6 @@ class Notifier extends koishi_1.Service {
294
285
  payload.action = 'updated';
295
286
  if (!payload.issue)
296
287
  payload.issue = { number: 0, title: 'Unknown Issue', html_url: '', user: payload.sender };
297
- // Ensure user exists in issue
298
288
  if (!payload.issue.user)
299
289
  payload.issue.user = payload.sender;
300
290
  break;
@@ -309,6 +299,8 @@ class Notifier extends koishi_1.Service {
309
299
  case 'star':
310
300
  if (!payload.action)
311
301
  payload.action = 'created';
302
+ if (payload.action === 'started')
303
+ payload.action = 'created';
312
304
  if (payload.repository && payload.repository.stargazers_count === undefined) {
313
305
  payload.repository.stargazers_count = '?';
314
306
  }
@@ -360,11 +352,10 @@ class Notifier extends koishi_1.Service {
360
352
  }
361
353
  }
362
354
  async sendMessage(rule, message) {
363
- // Find suitable bots
364
355
  const bots = this.ctx.bots.filter(bot => {
365
356
  if (rule.platform)
366
357
  return bot.platform === rule.platform;
367
- return true; // If platform not specified, try all
358
+ return true;
368
359
  });
369
360
  if (bots.length === 0) {
370
361
  if (this.config.debug) {
@@ -380,7 +371,7 @@ class Notifier extends koishi_1.Service {
380
371
  if (this.config.debug) {
381
372
  this.ctx.logger('notifier').info(`Sent message to ${rule.channelId} via ${bot.platform}:${bot.selfId}`);
382
373
  }
383
- break; // Break on first success
374
+ break;
384
375
  }
385
376
  catch (e) {
386
377
  if (this.config.debug) {
@@ -394,3 +385,4 @@ class Notifier extends koishi_1.Service {
394
385
  }
395
386
  }
396
387
  exports.Notifier = Notifier;
388
+ Notifier.inject = ['githubsthFormatter'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-githubsth",
3
- "version": "1.0.2",
3
+ "version": "1.0.3-alpha.1",
4
4
  "description": "Github Subscriptions Notifications, push notifications for GitHub subscriptions For koishi",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",