@zhin.js/adapter-github 1.1.17 → 1.1.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.
- package/CHANGELOG.md +65 -0
- package/README.md +10 -2
- package/adapters/github/index.js +3 -36
- package/adapters/github/index.ts +3 -39
- package/agents/github/skills/github-account/handlers.ts +6 -6
- package/agents/github/skills/github-repository/handlers.js +1 -1
- package/agents/github/skills/github-repository/handlers.ts +7 -7
- package/agents/github/skills/github-subscriptions/handlers.ts +6 -6
- package/commands/github/endpoint/definition.js +0 -2
- package/commands/github/endpoint/definition.ts +0 -2
- package/lib/adapter.d.ts +19 -0
- package/lib/adapter.js +30 -0
- package/lib/client.d.ts +0 -35
- package/lib/client.js +1 -44
- package/lib/console-spec.d.ts +12 -0
- package/lib/console-spec.js +12 -0
- package/lib/console.d.ts +8 -0
- package/lib/console.js +13 -0
- package/lib/endpoint.d.ts +9 -12
- package/lib/endpoint.js +56 -31
- package/lib/gh-client.d.ts +27 -6
- package/lib/gh-client.js +74 -49
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -1
- package/lib/webhook.d.ts +1 -1
- package/lib/webhook.js +3 -3
- package/package.json +28 -20
- package/pages/index/index.js +15 -0
- package/pages/index/index.ts +16 -0
- package/plugin.js +3 -4
- package/src/adapter.ts +32 -0
- package/src/client.ts +0 -61
- package/src/console-spec.ts +17 -0
- package/src/console.ts +18 -0
- package/src/endpoint.ts +52 -33
- package/src/gh-client.ts +90 -57
- package/src/index.ts +2 -1
- package/src/webhook.ts +4 -4
- package/lib/github-runtime-state.d.ts +0 -1
- package/lib/github-runtime-state.js +0 -6
- package/src/github-runtime-state.ts +0 -7
package/src/gh-client.ts
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { spawn } from 'node:child_process';
|
|
13
|
+
import { createEndpointOperation } from 'zhin.js/adapter';
|
|
14
|
+
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
13
15
|
import crypto from 'node:crypto';
|
|
14
16
|
import fs from 'node:fs';
|
|
15
17
|
|
|
@@ -35,6 +37,7 @@ export interface GitHubCommitAuthor {
|
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export interface GhClientOptions {
|
|
40
|
+
readonly signal?: AbortSignal;
|
|
38
41
|
/** GitHub Enterprise 主机名(默认 github.com) */
|
|
39
42
|
host?: string;
|
|
40
43
|
/** 覆盖 gh CLI 默认认证的 Personal Access Token / OAuth Token */
|
|
@@ -43,8 +46,27 @@ export interface GhClientOptions {
|
|
|
43
46
|
appAuth?: AppAuth;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
/** Per-request cancellation is independent of this account's execution lifetime. */
|
|
50
|
+
export interface GhRequestLifetime { readonly signal?: AbortSignal }
|
|
51
|
+
/** An API action and its transport inputs, retained together through authentication and subprocess IO. */
|
|
52
|
+
export interface GhApiRequest extends GhRequestLifetime {
|
|
53
|
+
readonly method: string;
|
|
54
|
+
readonly path: string;
|
|
55
|
+
readonly body?: unknown;
|
|
56
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
57
|
+
}
|
|
58
|
+
/** One comment publication, shared by issue and PR conversation sends. */
|
|
59
|
+
export interface GhCommentRequest extends GhRequestLifetime {
|
|
60
|
+
readonly repo: string;
|
|
61
|
+
readonly number: number;
|
|
62
|
+
readonly body: string;
|
|
63
|
+
}
|
|
64
|
+
interface GhCommandRequest extends GhRequestLifetime { readonly args: readonly string[]; readonly stdin?: string; readonly token?: string }
|
|
65
|
+
|
|
46
66
|
export class GhClient {
|
|
47
|
-
|
|
67
|
+
protected apiHost?: string;
|
|
68
|
+
protected executionSignal?: AbortSignal;
|
|
69
|
+
protected bindExecutionSignal(signal: AbortSignal): void { this.executionSignal = signal; }
|
|
48
70
|
private token?: string;
|
|
49
71
|
private _appAuth?: AppAuth;
|
|
50
72
|
private _resolvedKey?: string;
|
|
@@ -59,27 +81,34 @@ export class GhClient {
|
|
|
59
81
|
private _lastSyncTime = 0;
|
|
60
82
|
|
|
61
83
|
constructor(options: GhClientOptions = {}) {
|
|
62
|
-
this.
|
|
84
|
+
this.apiHost = options.host;
|
|
85
|
+
this.executionSignal = options.signal;
|
|
63
86
|
this.token = options.token;
|
|
64
87
|
this._appAuth = options.appAuth;
|
|
65
88
|
}
|
|
66
89
|
|
|
90
|
+
protected fetchNative(input: string, init?: RequestInit): Promise<Response> {
|
|
91
|
+
this.executionSignal?.throwIfAborted(); init?.signal?.throwIfAborted();
|
|
92
|
+
return fetch(input, { ...init, ...(this.executionSignal ? { signal: init?.signal ? AbortSignal.any([this.executionSignal, init.signal]) : this.executionSignal } : {}) });
|
|
93
|
+
}
|
|
94
|
+
|
|
67
95
|
/** 创建使用指定 token 的副本(共享 host 配置,不继承 App 认证) */
|
|
68
96
|
withToken(token: string): GhClient {
|
|
69
|
-
return new GhClient({ host: this.
|
|
97
|
+
return new GhClient({ host: this.apiHost, token, signal: this.executionSignal });
|
|
70
98
|
}
|
|
71
99
|
|
|
72
100
|
get authenticatedUser() { return this._user; }
|
|
73
101
|
|
|
74
102
|
// ── 底层执行 ──────────────────────────────────────────────────────
|
|
75
103
|
|
|
76
|
-
private exec(args
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
104
|
+
private exec({ args, stdin, token, signal = this.executionSignal }: GhCommandRequest): Promise<string> {
|
|
105
|
+
signal?.throwIfAborted();
|
|
106
|
+
const fullArgs = this.apiHost ? [...args, '--hostname', this.apiHost] : args;
|
|
107
|
+
const env = token
|
|
108
|
+
? { ...process.env, GH_TOKEN: token }
|
|
80
109
|
: undefined;
|
|
81
110
|
return new Promise((resolve, reject) => {
|
|
82
|
-
const proc = spawn('gh', fullArgs, { stdio: ['pipe', 'pipe', 'pipe'], env });
|
|
111
|
+
const proc = spawn('gh', fullArgs, { stdio: ['pipe', 'pipe', 'pipe'], env, signal });
|
|
83
112
|
let stdout = '';
|
|
84
113
|
let stderr = '';
|
|
85
114
|
proc.stdout.on('data', (d: Buffer) => (stdout += d.toString()));
|
|
@@ -110,8 +139,8 @@ export class GhClient {
|
|
|
110
139
|
* 确保 App 认证的 Installation Token 有效(自动按 repo 查找对应安装)
|
|
111
140
|
* @param repo 仓库全名(owner/repo),用于选择正确的 Installation
|
|
112
141
|
*/
|
|
113
|
-
private async ensureTokenForRepo(repo?: string): Promise<
|
|
114
|
-
if (!this._appAuth) return;
|
|
142
|
+
private async ensureTokenForRepo(repo?: string, signal?: AbortSignal): Promise<string | undefined> {
|
|
143
|
+
if (!this._appAuth) return this.token;
|
|
115
144
|
let installId: number | undefined;
|
|
116
145
|
if (repo) {
|
|
117
146
|
const key = repo.toLowerCase();
|
|
@@ -128,7 +157,7 @@ export class GhClient {
|
|
|
128
157
|
}
|
|
129
158
|
// 懒加载重新发现(5 分钟冷却)
|
|
130
159
|
if (!installId && Date.now() - this._lastSyncTime > 5 * 60_000) {
|
|
131
|
-
await this.syncInstallations();
|
|
160
|
+
await this.syncInstallations({ signal });
|
|
132
161
|
installId = this._repoToInstallation.get(key);
|
|
133
162
|
if (!installId) {
|
|
134
163
|
const owner = key.split('/')[0];
|
|
@@ -145,24 +174,21 @@ export class GhClient {
|
|
|
145
174
|
if (!installId && this._allInstallations.length) {
|
|
146
175
|
installId = this._allInstallations[0].id;
|
|
147
176
|
}
|
|
148
|
-
if (!installId) return;
|
|
177
|
+
if (!installId) return this.token;
|
|
149
178
|
const cached = this._installationTokens.get(installId);
|
|
150
179
|
if (cached && cached.expiresAt > Date.now() + 60_000) {
|
|
151
|
-
|
|
152
|
-
return;
|
|
180
|
+
return cached.token;
|
|
153
181
|
}
|
|
154
|
-
await this.refreshInstallationToken(installId);
|
|
182
|
+
await this.refreshInstallationToken(installId, { signal });
|
|
183
|
+
return this._installationTokens.get(installId)?.token;
|
|
155
184
|
}
|
|
156
185
|
|
|
157
|
-
async request<T = any>(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
body?: any,
|
|
161
|
-
headers?: Record<string, string>,
|
|
162
|
-
): Promise<{ ok: boolean; status: number; data: T }> {
|
|
186
|
+
async request<T = any>({ method, path, body, headers, signal }: GhApiRequest): Promise<{ ok: boolean; status: number; data: T }> {
|
|
187
|
+
const operationSignal = this.executionSignal && signal ? AbortSignal.any([this.executionSignal, signal]) : this.executionSignal ?? signal;
|
|
188
|
+
const operation = createEndpointOperation({ signal: operationSignal });
|
|
163
189
|
// 从路径自动检测 repo 以选择正确的 Installation Token
|
|
164
190
|
const repoMatch = path.match(/^\/repos\/([^/?]+\/[^/?]+)/);
|
|
165
|
-
await this.ensureTokenForRepo(repoMatch?.[1]);
|
|
191
|
+
const token = await operation.prepare(() => this.ensureTokenForRepo(repoMatch?.[1], operationSignal));
|
|
166
192
|
const args = ['api', path, '--method', method];
|
|
167
193
|
if (body) args.push('--input', '-');
|
|
168
194
|
if (headers) {
|
|
@@ -171,11 +197,13 @@ export class GhClient {
|
|
|
171
197
|
}
|
|
172
198
|
}
|
|
173
199
|
try {
|
|
174
|
-
const
|
|
200
|
+
const execute = () => this.exec({ args, stdin: body ? JSON.stringify(body) : undefined, token, signal: operationSignal });
|
|
201
|
+
const raw = await operation.run(execute);
|
|
175
202
|
let data: any;
|
|
176
203
|
try { data = raw ? JSON.parse(raw) : null; } catch { data = raw; }
|
|
177
204
|
return { ok: true, status: 200, data };
|
|
178
205
|
} catch (err: unknown) {
|
|
206
|
+
if (err instanceof EndpointDeliveryError) throw err;
|
|
179
207
|
let data: any;
|
|
180
208
|
const errObj = err instanceof Error ? err : new Error(String(err));
|
|
181
209
|
try { data = (err as any).stdout ? JSON.parse((err as any).stdout) : { message: errObj.message }; } catch {
|
|
@@ -185,11 +213,11 @@ export class GhClient {
|
|
|
185
213
|
}
|
|
186
214
|
}
|
|
187
215
|
|
|
188
|
-
private get<T = any>(path: string) { return this.request<T>('GET', path); }
|
|
189
|
-
private post<T = any>(path: string, body?: any) { return this.request<T>('POST', path, body); }
|
|
190
|
-
private patch<T = any>(path: string, body?: any) { return this.request<T>('PATCH', path, body); }
|
|
191
|
-
private put<T = any>(path: string, body?: any) { return this.request<T>('PUT', path, body); }
|
|
192
|
-
private del<T = any>(path: string, body?: any) { return this.request<T>('DELETE', path, body); }
|
|
216
|
+
private get<T = any>(path: string) { return this.request<T>({ method: 'GET', path }); }
|
|
217
|
+
private post<T = any>(path: string, body?: any) { return this.request<T>({ method: 'POST', path, body }); }
|
|
218
|
+
private patch<T = any>(path: string, body?: any) { return this.request<T>({ method: 'PATCH', path, body }); }
|
|
219
|
+
private put<T = any>(path: string, body?: any) { return this.request<T>({ method: 'PUT', path, body }); }
|
|
220
|
+
private del<T = any>(path: string, body?: any) { return this.request<T>({ method: 'DELETE', path, body }); }
|
|
193
221
|
|
|
194
222
|
// ── 认证验证 ──────────────────────────────────────────────────────
|
|
195
223
|
|
|
@@ -204,8 +232,8 @@ export class GhClient {
|
|
|
204
232
|
// 用 JWT 查询 App 信息(/app 端点只接受 JWT 认证,不能用 Installation Token)
|
|
205
233
|
const key = this.resolvePrivateKey();
|
|
206
234
|
const jwt = GhClient.createJWT(this._appAuth.appId, key);
|
|
207
|
-
const baseUrl = this.
|
|
208
|
-
const appRes = await
|
|
235
|
+
const baseUrl = this.apiHost ? `https://${this.apiHost}/api/v3` : 'https://api.github.com';
|
|
236
|
+
const appRes = await this.fetchNative(`${baseUrl}/app`, {
|
|
209
237
|
headers: { Authorization: `Bearer ${jwt}`, Accept: 'application/vnd.github+json' },
|
|
210
238
|
});
|
|
211
239
|
if (appRes.ok) {
|
|
@@ -235,8 +263,8 @@ export class GhClient {
|
|
|
235
263
|
}
|
|
236
264
|
return { ok: false, user: '', message: 'Token 无效' };
|
|
237
265
|
}
|
|
238
|
-
await this.exec(['auth', 'status']);
|
|
239
|
-
const raw = await this.exec(['api', '/user', '--jq', '.login']);
|
|
266
|
+
await this.exec({ args: ['auth', 'status'], token: this.token });
|
|
267
|
+
const raw = await this.exec({ args: ['api', '/user', '--jq', '.login'], token: this.token });
|
|
240
268
|
const login = raw.trim();
|
|
241
269
|
this._user = login;
|
|
242
270
|
return { ok: true, user: login, message: `gh CLI: ${login}` };
|
|
@@ -308,19 +336,18 @@ export class GhClient {
|
|
|
308
336
|
return this.patch(`/repos/${repo}/pulls/${number}`, { state: 'closed' });
|
|
309
337
|
}
|
|
310
338
|
|
|
311
|
-
async createIssueComment(repo
|
|
312
|
-
return this.
|
|
313
|
-
`/repos/${repo}/issues/${
|
|
314
|
-
|
|
315
|
-
);
|
|
339
|
+
async createIssueComment({ repo, number, body, signal }: GhCommentRequest) {
|
|
340
|
+
return this.request<{ id: number; html_url: string; message?: string }>({
|
|
341
|
+
method: 'POST', path: `/repos/${repo}/issues/${number}/comments`, body: { body }, signal,
|
|
342
|
+
});
|
|
316
343
|
}
|
|
317
344
|
|
|
318
345
|
async deleteIssueComment(repo: string, commentId: number) {
|
|
319
346
|
return this.del(`/repos/${repo}/issues/comments/${commentId}`);
|
|
320
347
|
}
|
|
321
348
|
|
|
322
|
-
async createPRComment(
|
|
323
|
-
return this.createIssueComment(
|
|
349
|
+
async createPRComment(request: GhCommentRequest) {
|
|
350
|
+
return this.createIssueComment(request);
|
|
324
351
|
}
|
|
325
352
|
|
|
326
353
|
async deletePRReviewComment(repo: string, commentId: number) {
|
|
@@ -409,7 +436,7 @@ export class GhClient {
|
|
|
409
436
|
}
|
|
410
437
|
|
|
411
438
|
buildCloneUrl(repo: string, token: string): string {
|
|
412
|
-
const host = this.
|
|
439
|
+
const host = this.apiHost || 'github.com';
|
|
413
440
|
return `https://x-access-token:${encodeURIComponent(token)}@${host}/${repo}.git`;
|
|
414
441
|
}
|
|
415
442
|
|
|
@@ -418,9 +445,9 @@ export class GhClient {
|
|
|
418
445
|
const slug = this._appSlug;
|
|
419
446
|
if (!slug) return null;
|
|
420
447
|
const login = `${slug}[bot]`;
|
|
421
|
-
const baseUrl = this.
|
|
448
|
+
const baseUrl = this.apiHost ? `https://${this.apiHost}/api/v3` : 'https://api.github.com';
|
|
422
449
|
try {
|
|
423
|
-
const res = await
|
|
450
|
+
const res = await this.fetchNative(`${baseUrl}/users/${encodeURIComponent(login)}`, {
|
|
424
451
|
headers: { Accept: 'application/vnd.github+json' },
|
|
425
452
|
});
|
|
426
453
|
if (!res.ok) return null;
|
|
@@ -446,7 +473,7 @@ export class GhClient {
|
|
|
446
473
|
}
|
|
447
474
|
|
|
448
475
|
async isStarred(repo: string): Promise<boolean> {
|
|
449
|
-
const r = await this.request('GET', `/user/starred/${repo}`);
|
|
476
|
+
const r = await this.request({ method: 'GET', path: `/user/starred/${repo}` });
|
|
450
477
|
return r.ok;
|
|
451
478
|
}
|
|
452
479
|
|
|
@@ -487,17 +514,18 @@ export class GhClient {
|
|
|
487
514
|
}
|
|
488
515
|
|
|
489
516
|
/** 使用 JWT 获取指定 Installation 的 Access Token(有效期 1 小时) */
|
|
490
|
-
async refreshInstallationToken(installationId: number): Promise<void> {
|
|
517
|
+
async refreshInstallationToken(installationId: number, { signal }: GhRequestLifetime = {}): Promise<void> {
|
|
518
|
+
signal?.throwIfAborted();
|
|
491
519
|
if (!this._appAuth) throw new Error('未配置 App 认证');
|
|
492
520
|
const key = this.resolvePrivateKey();
|
|
493
521
|
const jwt = GhClient.createJWT(this._appAuth.appId, key);
|
|
494
|
-
const baseUrl = this.
|
|
495
|
-
? `https://${this.
|
|
522
|
+
const baseUrl = this.apiHost
|
|
523
|
+
? `https://${this.apiHost}/api/v3`
|
|
496
524
|
: 'https://api.github.com';
|
|
497
|
-
const res = await
|
|
525
|
+
const res = await this.fetchNative(
|
|
498
526
|
`${baseUrl}/app/installations/${installationId}/access_tokens`,
|
|
499
527
|
{
|
|
500
|
-
method: 'POST',
|
|
528
|
+
method: 'POST', signal,
|
|
501
529
|
headers: {
|
|
502
530
|
Authorization: `Bearer ${jwt}`,
|
|
503
531
|
Accept: 'application/vnd.github+json',
|
|
@@ -509,6 +537,7 @@ export class GhClient {
|
|
|
509
537
|
throw new Error(`Installation Token 获取失败 (${res.status}): ${body}`);
|
|
510
538
|
}
|
|
511
539
|
const data = (await res.json()) as { token: string; expires_at: string };
|
|
540
|
+
signal?.throwIfAborted();
|
|
512
541
|
this.token = data.token;
|
|
513
542
|
this._installationTokens.set(installationId, {
|
|
514
543
|
token: data.token,
|
|
@@ -517,13 +546,14 @@ export class GhClient {
|
|
|
517
546
|
}
|
|
518
547
|
|
|
519
548
|
/** 发现所有 App 安装及其可访问的仓库 */
|
|
520
|
-
async syncInstallations(): Promise<void> {
|
|
549
|
+
async syncInstallations({ signal }: GhRequestLifetime = {}): Promise<void> {
|
|
550
|
+
signal?.throwIfAborted();
|
|
521
551
|
if (!this._appAuth) return;
|
|
522
552
|
const key = this.resolvePrivateKey();
|
|
523
553
|
const jwt = GhClient.createJWT(this._appAuth.appId, key);
|
|
524
|
-
const baseUrl = this.
|
|
525
|
-
const listRes = await
|
|
526
|
-
headers: { Authorization: `Bearer ${jwt}`, Accept: 'application/vnd.github+json' },
|
|
554
|
+
const baseUrl = this.apiHost ? `https://${this.apiHost}/api/v3` : 'https://api.github.com';
|
|
555
|
+
const listRes = await this.fetchNative(`${baseUrl}/app/installations`, {
|
|
556
|
+
headers: { Authorization: `Bearer ${jwt}`, Accept: 'application/vnd.github+json' }, signal,
|
|
527
557
|
});
|
|
528
558
|
if (!listRes.ok) {
|
|
529
559
|
const errBody = await listRes.text();
|
|
@@ -532,23 +562,26 @@ export class GhClient {
|
|
|
532
562
|
const installations = (await listRes.json()) as Array<{
|
|
533
563
|
id: number; account: { login: string; type: string }; target_type: string;
|
|
534
564
|
}>;
|
|
565
|
+
signal?.throwIfAborted();
|
|
535
566
|
this._allInstallations = installations;
|
|
536
567
|
this._repoToInstallation.clear();
|
|
537
568
|
for (const inst of installations) {
|
|
538
569
|
try {
|
|
539
|
-
await this.refreshInstallationToken(inst.id);
|
|
570
|
+
await this.refreshInstallationToken(inst.id, { signal });
|
|
540
571
|
const cached = this._installationTokens.get(inst.id);
|
|
541
572
|
if (!cached) continue;
|
|
542
|
-
const repoRes = await
|
|
543
|
-
headers: { Authorization: `Bearer ${cached.token}`, Accept: 'application/vnd.github+json' },
|
|
573
|
+
const repoRes = await this.fetchNative(`${baseUrl}/installation/repositories?per_page=100`, {
|
|
574
|
+
headers: { Authorization: `Bearer ${cached.token}`, Accept: 'application/vnd.github+json' }, signal,
|
|
544
575
|
});
|
|
545
576
|
if (repoRes.ok) {
|
|
546
577
|
const data = (await repoRes.json()) as { repositories: Array<{ full_name: string }> };
|
|
578
|
+
signal?.throwIfAborted();
|
|
547
579
|
for (const repo of data.repositories) {
|
|
548
580
|
this._repoToInstallation.set(repo.full_name.toLowerCase(), inst.id);
|
|
549
581
|
}
|
|
550
582
|
}
|
|
551
583
|
} catch {
|
|
584
|
+
signal?.throwIfAborted(); this.executionSignal?.throwIfAborted();
|
|
552
585
|
// 单个安装失败不影响其他
|
|
553
586
|
}
|
|
554
587
|
}
|
|
@@ -588,11 +621,11 @@ export class GhClient {
|
|
|
588
621
|
repo: string,
|
|
589
622
|
etag?: string,
|
|
590
623
|
): Promise<{ events: any[]; etag: string | null }> {
|
|
591
|
-
await this.ensureTokenForRepo(repo);
|
|
624
|
+
const token = await this.ensureTokenForRepo(repo);
|
|
592
625
|
const args = ['api', `/repos/${repo}/events?per_page=30`, '--method', 'GET', '--include'];
|
|
593
626
|
if (etag) args.push('-H', `If-None-Match: ${etag}`);
|
|
594
627
|
try {
|
|
595
|
-
const raw = await this.exec(args);
|
|
628
|
+
const raw = await this.exec({ args, token });
|
|
596
629
|
// --include 输出包含 HTTP 头 + 空行 + body
|
|
597
630
|
const sepIdx = raw.indexOf('\r\n\r\n');
|
|
598
631
|
const headerPart = sepIdx >= 0 ? raw.slice(0, sepIdx) : '';
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,7 @@ export {
|
|
|
21
21
|
export * from './types.js';
|
|
22
22
|
|
|
23
23
|
export { GhClient } from './gh-client.js';
|
|
24
|
-
export {
|
|
24
|
+
export type { GithubClientEventMap } from './client.js';
|
|
25
25
|
export { WorkspaceManager } from './workspace-manager.js';
|
|
26
26
|
export {
|
|
27
27
|
parseMessageChannel,
|
|
@@ -49,3 +49,4 @@ export {
|
|
|
49
49
|
dispatchGithubWebhookPayload,
|
|
50
50
|
type GithubWebhookHandler,
|
|
51
51
|
} from './webhook.js';
|
|
52
|
+
export { GithubAdapter } from './adapter.js';
|
package/src/webhook.ts
CHANGED
|
@@ -23,7 +23,7 @@ const logger = getLogger('github');
|
|
|
23
23
|
export interface GithubWebhookHandler {
|
|
24
24
|
readonly config: ResolvedGithubConfig;
|
|
25
25
|
admitPlatform(name: string, event: unknown): void;
|
|
26
|
-
admit(comment: GithubInboundComment): void;
|
|
26
|
+
admit(comment: GithubInboundComment, nativeEvent?: unknown): void;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function registerGithubWebhookRoutes(
|
|
@@ -114,17 +114,17 @@ export async function dispatchGithubWebhookPayload(
|
|
|
114
114
|
|
|
115
115
|
if (event === 'issue_comment') {
|
|
116
116
|
const inbound = parseIssueCommentInbound(payload as IssueCommentPayload);
|
|
117
|
-
if (inbound) handler.admit(inbound);
|
|
117
|
+
if (inbound) handler.admit(inbound, payload);
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
120
|
if (event === 'pull_request_review_comment') {
|
|
121
121
|
const inbound = parsePrReviewCommentInbound(payload as PRReviewCommentPayload);
|
|
122
|
-
if (inbound) handler.admit(inbound);
|
|
122
|
+
if (inbound) handler.admit(inbound, payload);
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
if (event === 'pull_request_review') {
|
|
126
126
|
const inbound = parsePrReviewInbound(payload as PRReviewPayload);
|
|
127
|
-
if (inbound) handler.admit(inbound);
|
|
127
|
+
if (inbound) handler.admit(inbound, payload);
|
|
128
128
|
}
|
|
129
129
|
// Cross-adapter subscription fan-out deferred (needs multi-adapter send in Runtime).
|
|
130
130
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const githubRuntimeStateToken: import("zhin.js").Token<import("@zhin.js/adapter").EndpointRuntimeState>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `github endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
export const githubRuntimeStateToken = defineEndpointRuntimeStateToken('github');
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `github endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
|
|
7
|
-
export const githubRuntimeStateToken = defineEndpointRuntimeStateToken('github');
|