@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.
Files changed (41) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +10 -2
  3. package/adapters/github/index.js +3 -36
  4. package/adapters/github/index.ts +3 -39
  5. package/agents/github/skills/github-account/handlers.ts +6 -6
  6. package/agents/github/skills/github-repository/handlers.js +1 -1
  7. package/agents/github/skills/github-repository/handlers.ts +7 -7
  8. package/agents/github/skills/github-subscriptions/handlers.ts +6 -6
  9. package/commands/github/endpoint/definition.js +0 -2
  10. package/commands/github/endpoint/definition.ts +0 -2
  11. package/lib/adapter.d.ts +19 -0
  12. package/lib/adapter.js +30 -0
  13. package/lib/client.d.ts +0 -35
  14. package/lib/client.js +1 -44
  15. package/lib/console-spec.d.ts +12 -0
  16. package/lib/console-spec.js +12 -0
  17. package/lib/console.d.ts +8 -0
  18. package/lib/console.js +13 -0
  19. package/lib/endpoint.d.ts +9 -12
  20. package/lib/endpoint.js +56 -31
  21. package/lib/gh-client.d.ts +27 -6
  22. package/lib/gh-client.js +74 -49
  23. package/lib/index.d.ts +2 -1
  24. package/lib/index.js +1 -1
  25. package/lib/webhook.d.ts +1 -1
  26. package/lib/webhook.js +3 -3
  27. package/package.json +28 -20
  28. package/pages/index/index.js +15 -0
  29. package/pages/index/index.ts +16 -0
  30. package/plugin.js +3 -4
  31. package/src/adapter.ts +32 -0
  32. package/src/client.ts +0 -61
  33. package/src/console-spec.ts +17 -0
  34. package/src/console.ts +18 -0
  35. package/src/endpoint.ts +52 -33
  36. package/src/gh-client.ts +90 -57
  37. package/src/index.ts +2 -1
  38. package/src/webhook.ts +4 -4
  39. package/lib/github-runtime-state.d.ts +0 -1
  40. package/lib/github-runtime-state.js +0 -6
  41. package/src/github-runtime-state.ts +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-github",
3
- "version": "1.1.17",
3
+ "version": "1.1.19",
4
4
  "description": "Zhin.js GitHub adapter for Plugin Runtime (App auth + webhook)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -39,25 +39,28 @@
39
39
  "directory": "plugins/adapters/github"
40
40
  },
41
41
  "dependencies": {
42
- "@zhin.js/adapter": "1.1.24",
43
- "@zhin.js/agent-feature": "1.1.10",
44
- "@zhin.js/core": "1.1.52",
45
- "@zhin.js/feature-kit": "1.1.9",
46
- "@zhin.js/host-http": "1.1.11",
47
- "@zhin.js/im-contract": "1.1.8",
42
+ "@zhin.js/adapter": "1.1.26",
43
+ "@zhin.js/agent-feature": "1.1.11",
44
+ "@zhin.js/client": "1.1.22",
45
+ "@zhin.js/console-contract": "1.1.3",
46
+ "@zhin.js/core": "1.1.54",
47
+ "@zhin.js/feature-kit": "1.1.10",
48
+ "@zhin.js/host-http": "1.1.12",
49
+ "@zhin.js/im-contract": "1.1.9",
48
50
  "@zhin.js/logger": "1.1.2",
49
- "@zhin.js/skill": "1.1.10",
50
- "@zhin.js/tool": "1.1.11"
51
+ "@zhin.js/page": "1.1.11",
52
+ "@zhin.js/skill": "1.1.11",
53
+ "@zhin.js/tool": "1.1.13"
51
54
  },
52
55
  "peerDependencies": {
53
56
  "zod": "^4.0.0",
54
- "@zhin.js/adapter": "^1.1.24",
55
- "@zhin.js/agent": "^1.1.43",
56
- "@zhin.js/command": "^1.1.11",
57
- "@zhin.js/core": "^1.1.52",
58
- "@zhin.js/host-http": "^1.1.11",
59
- "@zhin.js/prompt-section": "^1.1.9",
60
- "zhin.js": "^1.1.17"
57
+ "@zhin.js/adapter": "^1.1.26",
58
+ "@zhin.js/agent": "^1.1.45",
59
+ "@zhin.js/command": "^1.1.12",
60
+ "@zhin.js/core": "^1.1.54",
61
+ "@zhin.js/host-http": "^1.1.12",
62
+ "@zhin.js/prompt-section": "^1.1.10",
63
+ "zhin.js": "^1.1.19"
61
64
  },
62
65
  "peerDependenciesMeta": {
63
66
  "@zhin.js/agent": {
@@ -81,13 +84,14 @@
81
84
  "typescript": "^6.0.3",
82
85
  "vitest": "^4.1.10",
83
86
  "zod": "^4.4.3",
84
- "@zhin.js/agent": "1.1.43",
85
- "@zhin.js/prompt-section": "1.1.9",
86
- "zhin.js": "1.1.17"
87
+ "@zhin.js/agent": "1.1.45",
88
+ "@zhin.js/prompt-section": "1.1.10",
89
+ "zhin.js": "1.1.19"
87
90
  },
88
91
  "files": [
89
92
  "adapters",
90
93
  "commands",
94
+ "pages",
91
95
  "plugin.js",
92
96
  "schema.json",
93
97
  "src",
@@ -113,7 +117,7 @@
113
117
  "features": [
114
118
  {
115
119
  "package": "@zhin.js/adapter",
116
- "api": "^1.0.0"
120
+ "api": "^2.0.0"
117
121
  },
118
122
  {
119
123
  "package": "@zhin.js/command",
@@ -130,6 +134,10 @@
130
134
  {
131
135
  "package": "@zhin.js/agent-feature",
132
136
  "api": "^1.0.0"
137
+ },
138
+ {
139
+ "package": "@zhin.js/page",
140
+ "api": "^1.0.0"
133
141
  }
134
142
  ],
135
143
  "plugins": []
@@ -0,0 +1,15 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { definePage } from '@zhin.js/console-contract';
3
+ import { createAdapterConsolePage } from '@zhin.js/client';
4
+ export const meta = definePage({
5
+ title: 'GitHub',
6
+ titleI18n: { en: 'GitHub' },
7
+ icon: 'Github',
8
+ order: 63,
9
+ requiredPermissions: ['github:read'],
10
+ });
11
+ /**
12
+ * Convention page: `pages/index/index.ts` → `/github`(插件路径)。
13
+ * 连接状态、连接测试、endpoint 增删;登录待办来自 LoginAssist(ICQQ 等)。
14
+ */
15
+ export default createAdapterConsolePage('github');
@@ -0,0 +1,16 @@
1
+ import { definePage } from '@zhin.js/console-contract';
2
+ import { createAdapterConsolePage } from '@zhin.js/client';
3
+
4
+ export const meta = definePage({
5
+ title: 'GitHub',
6
+ titleI18n: { en: 'GitHub' },
7
+ icon: 'Github',
8
+ order: 63,
9
+ requiredPermissions: ['github:read'],
10
+ });
11
+
12
+ /**
13
+ * Convention page: `pages/index/index.ts` → `/github`(插件路径)。
14
+ * 连接状态、连接测试、endpoint 增删;登录待办来自 LoginAssist(ICQQ 等)。
15
+ */
16
+ export default createAdapterConsolePage('github');
package/plugin.js CHANGED
@@ -1,8 +1,7 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { createEndpointRuntimeState } from 'zhin.js/adapter';
3
- import { definePlugin, databaseHostToken } from 'zhin.js';
4
- import { githubRuntimeStateToken } from "./lib/github-runtime-state.js";
2
+ import { definePlugin, databaseHostToken, pluginConsoleRpcToken } from 'zhin.js';
5
3
  import { defineGithubOauthUsersTable } from "./lib/oauth-users.js";
4
+ import { createGithubConsoleRpc } from "./lib/console.js";
6
5
  /**
7
6
  * github_subscriptions — repo event subscriptions per chat channel
8
7
  * (used by github_subscriptions agent tool; schema is registered through DatabaseHost).
@@ -28,7 +27,7 @@ export default definePlugin({
28
27
  },
29
28
  setup(context) {
30
29
  // 运行中 endpoint 注册表(github endpoint list 的"运行中"数据源)
31
- context.resources.provide(githubRuntimeStateToken, createEndpointRuntimeState());
30
+ context.resources.provide(pluginConsoleRpcToken, createGithubConsoleRpc(context.resources, () => context.config.get()));
32
31
  if (context.resources.has(databaseHostToken)) {
33
32
  const host = context.resources.use(databaseHostToken);
34
33
  defineGithubOauthUsersTable(host);
package/src/adapter.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { GhClient } from './gh-client.js';
2
+ import { Adapter, type AdapterContext, type EndpointCreationContext } from 'zhin.js/adapter';
3
+ import { GithubEndpoint } from './endpoint.js';
4
+ import { resolveGithubConfig, type GithubEndpointConfig } from './protocol.js';
5
+ import type { GithubClientEventMap } from './client.js';
6
+ import { httpHostToken } from '@zhin.js/host-http';
7
+ import { databaseHostToken } from 'zhin.js';
8
+
9
+ export class GithubAdapter extends Adapter<GithubEndpoint, GithubEndpointConfig, GithubClientEventMap> {
10
+ readonly #context: AdapterContext<GithubEndpointConfig>;
11
+ constructor(context: AdapterContext<GithubEndpointConfig>) { super(); this.#context = context; }
12
+ override get configurationIdentityFields(): readonly string[] { return ['id', 'app_id', 'host']; }
13
+ override get configurationUpdateFields(): readonly string[] { return ['private_key', 'webhook_secret', 'webhook_path', 'auto_reply_repos', 'bot_login', 'workspace_root']; }
14
+ override get configurationIdentityProbeFields(): readonly string[] { return ['private_key']; }
15
+ protected override async identifyConfiguration(input: GithubEndpointConfig, signal: AbortSignal, _changed: readonly string[]): Promise<string | undefined> {
16
+ const config = resolveGithubConfig(input), client = new GhClient({ host: config.host, appAuth: { appId: config.appId, privateKey: config.privateKey }, signal });
17
+ const authenticated = await client.verifyAuth(); signal.throwIfAborted();
18
+ if (!authenticated.ok) throw new Error('GitHub application identity verification failed');
19
+ const identity = await client.getBotIdentity(); signal.throwIfAborted();
20
+ if (!identity?.userId) throw new Error('GitHub identity verification returned no bot userId');
21
+ return JSON.stringify(['github', config.host ?? 'github.com', identity.userId]);
22
+ }
23
+ protected override validateConfiguration(config: GithubEndpointConfig): void { resolveGithubConfig(config); }
24
+ protected createEndpoint(input: GithubEndpointConfig, execution: EndpointCreationContext): GithubEndpoint {
25
+ const config = resolveGithubConfig(input);
26
+ return new GithubEndpoint({ id: execution.canonicalId, config, ...(config.webhookSecret ? { http: this.#context.use(httpHostToken) } : {}), ...(this.#context.has?.(databaseHostToken) ? { database: this.#context.use(databaseHostToken) } : {}) });
27
+ }
28
+ }
29
+
30
+ declare module '@zhin.js/feature-kit' {
31
+ interface AdapterRegistry { readonly 'github': GithubAdapter; }
32
+ }
package/src/client.ts CHANGED
@@ -1,62 +1 @@
1
- import type { PluginDatabaseHost } from 'zhin.js';
2
- import { defineEndpointClient } from 'zhin.js/adapter';
3
- import { GhClient } from './gh-client.js';
4
- import { lookupGithubOauthAccessToken } from './oauth-users.js';
5
- import type { ResolvedGithubConfig } from './protocol.js';
6
- import { WorkspaceManager } from './workspace-manager.js';
7
-
8
- /** GitHub SDK surface exposed to plugin handlers and Agent tools. */
9
- export class GithubClient {
10
- #workspaceManager?: WorkspaceManager;
11
-
12
- constructor(
13
- readonly name: string,
14
- readonly api: GhClient,
15
- readonly config: ResolvedGithubConfig,
16
- readonly database?: PluginDatabaseHost,
17
- ) {}
18
-
19
- async getUserOrDefaultApi(platform?: string, platformUid?: string): Promise<GhClient> {
20
- if (platform && platformUid) {
21
- const token = await lookupGithubOauthAccessToken(this.database, platform, platformUid);
22
- if (token) return this.api.withToken(token);
23
- }
24
- return this.api;
25
- }
26
-
27
- get clientId(): string | null {
28
- return this.api.clientId || null;
29
- }
30
-
31
- get host(): string | undefined {
32
- return this.config.host;
33
- }
34
-
35
- get appSlug(): string | null {
36
- return this.api.appSlug || null;
37
- }
38
-
39
- get installations() {
40
- return this.api.installations || [];
41
- }
42
-
43
- get workspaceManager(): WorkspaceManager {
44
- if (!this.#workspaceManager) {
45
- this.#workspaceManager = new WorkspaceManager(this.api, this.config.workspaceRoot);
46
- }
47
- return this.#workspaceManager;
48
- }
49
- }
50
-
51
1
  export type GithubClientEventMap = Record<string, unknown>;
52
-
53
- declare module '@zhin.js/feature-kit' {
54
- interface AdapterClientRegistry {
55
- readonly github: {
56
- readonly client: GithubClient;
57
- readonly events: GithubClientEventMap;
58
- };
59
- }
60
- }
61
-
62
- export const githubClient = defineEndpointClient<GithubClient, GithubClientEventMap>('github');
@@ -0,0 +1,17 @@
1
+ /**
2
+ * GitHub Console 页面元数据(浏览器与服务端共享;不要在这里 import 服务端代码)。
3
+ */
4
+ import type { AdapterConsoleField } from 'zhin.js/adapter';
5
+
6
+ export const githubConsoleSpec = {
7
+ adapterKey: 'github',
8
+ adapterDisplayName: 'GitHub',
9
+ fields: [
10
+ { key: 'app_id', required: true, env: true, description: 'GitHub App ID' },
11
+ { key: 'private_key', required: true, secret: true, description: 'PEM 文件路径(推荐,如 ./data/xxx.pem)或 PEM 内容', descriptionI18n: { en: 'PEM file path (recommended) or PEM content' } },
12
+ { key: 'webhook_secret', env: true, description: 'webhook 签名密钥(不配则 API-only)', descriptionI18n: { en: 'Webhook signing secret (API-only when omitted)' } },
13
+ ] as readonly AdapterConsoleField[],
14
+ docsUrl: 'https://zhin.js.org/adapters/github',
15
+ readPermission: 'github:read',
16
+ writePermission: 'github:write',
17
+ } as const;
package/src/console.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GitHub Console RPC:运行状态 + endpoint 增删(原 `github endpoint` 聊天命令)。
3
+ *
4
+ * 页面绑定 `pages/index`,读取 / 写入分别要求 `<adapter>:read` / `<adapter>:write`。
5
+ */
6
+ import { createAdapterConsoleRpc, type AdapterConsoleResources } from 'zhin.js/adapter';
7
+ import type { PluginConsoleRpc } from 'zhin.js';
8
+ import { githubConsoleSpec } from './console-spec.js';
9
+
10
+ export function createGithubConsoleRpc(
11
+ _resources: AdapterConsoleResources,
12
+ getConfig: () => unknown,
13
+ ): PluginConsoleRpc {
14
+ return createAdapterConsoleRpc({
15
+ ...githubConsoleSpec,
16
+ getConfig,
17
+ });
18
+ }
package/src/endpoint.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { Endpoint } from 'zhin.js/adapter';
1
+ import { createEndpointSpecification, endpointSpec, type Endpoint, type EndpointSendRequest } from 'zhin.js/adapter';
2
2
  /**
3
3
  * GithubEndpoint — lifecycle, outbound send, inbound admit.
4
4
  */
5
- import { type EndpointSendRequest } from 'zhin.js/adapter';
6
5
  import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
7
6
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
8
7
  import type { CapabilityId, PluginDatabaseHost } from 'zhin.js';
@@ -17,98 +16,110 @@ import {
17
16
  type ResolvedGithubConfig,
18
17
  } from './protocol.js';
19
18
  import { registerGithubWebhookRoutes } from './webhook.js';
20
- import { GithubClient } from './client.js';
19
+ import { WorkspaceManager } from './workspace-manager.js';
20
+ import { lookupGithubOauthAccessToken } from './oauth-users.js';
21
21
 
22
22
  export interface GithubEndpointOptions {
23
23
  readonly id: CapabilityId;
24
24
  readonly http?: HttpHost;
25
25
  readonly database?: PluginDatabaseHost;
26
26
  readonly config: ResolvedGithubConfig;
27
- readonly createClient?: (config: ResolvedGithubConfig) => GhClient;
28
27
  }
29
28
 
30
29
  /**
31
30
  * GitHub 是代码协作面(issue/PR),无好友/群/频道等 IM 社交概念,
32
31
  * 不适用 EndpointManagement 语义端口;本 endpoint 不暴露该端口。
33
32
  */
34
- export class GithubEndpoint extends Endpoint<GithubClient> {
33
+ export class GithubEndpoint extends GhClient implements Endpoint {
34
+ readonly [endpointSpec] = createEndpointSpecification(this, {
35
+ start: signal => this.#startFramework(signal), open: () => this.#openFramework(), close: () => this.#closeFramework(),
36
+ stop: () => this.#stopFramework(), send: request => this.#sendFramework(request),
37
+ });
38
+ #workspaceManager?: WorkspaceManager;
39
+ get database() { return this.#options.database; }
40
+ get host(): string | undefined { return this.#options.config.host; }
41
+ async getUserOrDefaultApi(platform?: string, platformUid?: string): Promise<GhClient> {
42
+ if (platform && platformUid) { const token = await lookupGithubOauthAccessToken(this.database, platform, platformUid); if (token) return this.withToken(token); }
43
+ return this;
44
+ }
45
+ get workspaceManager(): WorkspaceManager { return this.#workspaceManager ??= new WorkspaceManager(this, this.config.workspaceRoot); }
35
46
  readonly #logger!: ReturnType<typeof getAdapterLogger>;
36
47
 
37
48
  readonly #options: GithubEndpointOptions;
38
- readonly client: GithubClient;
39
49
  #routeReleases: HttpRouteRegistration[] = [];
40
50
  #open = false;
41
51
  #started = false;
42
52
 
43
53
  constructor(options: GithubEndpointOptions) {
44
- super();
54
+ super({ host: options.config.host, appAuth: { appId: options.config.appId, privateKey: options.config.privateKey } });
45
55
  this.#logger = getAdapterLogger('github', options.config.id);
46
56
  this.#options = options;
47
- const api = options.createClient?.(options.config) ?? defaultCreateClient(options.config);
48
- this.client = new GithubClient(options.config.id, api, options.config, options.database);
57
+
49
58
  }
50
59
 
51
60
  get config(): ResolvedGithubConfig {
52
- return this.client.config;
61
+ return this.#options.config;
53
62
  }
54
63
 
55
- async start(): Promise<void> {
64
+ async #startFramework(signal: AbortSignal): Promise<void> {
65
+ this.bindExecutionSignal(signal); signal.throwIfAborted();
56
66
  if (this.#started) return;
57
67
  this.#started = true;
58
68
  try {
59
- const result = await this.client.api.verifyAuth();
69
+ const result = await this.verifyAuth();
70
+ signal.throwIfAborted();
60
71
  if (!result.ok) throw new Error(`GitHub 认证失败: ${result.message}`);
61
- if (this.client.config.webhookSecret) {
72
+ if (this.#options.config.webhookSecret) {
62
73
  if (!this.#options.http) {
63
74
  throw new TypeError('GitHub webhook_secret requires httpHostToken');
64
75
  }
65
76
  this.#routeReleases.push(...registerGithubWebhookRoutes(this.#options.http, this));
66
77
  this.#logger.debug(formatCompact({
67
- endpoint: this.client.name,
78
+ endpoint: this.#options.config.id,
68
79
  op: 'webhook',
69
- path: this.client.config.webhookPath,
80
+ path: this.#options.config.webhookPath,
70
81
  }));
71
82
  } else {
72
83
  this.#logger.debug(formatCompact({
73
- endpoint: this.client.name,
84
+ endpoint: this.#options.config.id,
74
85
  op: 'connect',
75
86
  mode: 'api-only',
76
- bot: this.client.api.authenticatedUser,
87
+ bot: this.authenticatedUser,
77
88
  }));
78
89
  }
79
90
  } catch (error) {
80
- await this.stop();
91
+ await this.#stopFramework();
81
92
  this.#logger.error('Failed to connect GitHub endpoint:', error);
82
93
  throw error;
83
94
  }
84
95
  }
85
96
 
86
- open(): void {
97
+ #openFramework(): void {
87
98
  this.#open = true;
88
99
  }
89
100
 
90
- close(): void {
101
+ #closeFramework(): void {
91
102
  this.#open = false;
92
103
  }
93
104
 
94
- async stop(): Promise<void> {
105
+ async #stopFramework(): Promise<void> {
95
106
  this.#open = false;
96
107
  for (const release of this.#routeReleases.splice(0)) release();
97
108
  this.#started = false;
98
109
  this.#logger.debug(formatCompact({ op: 'disconnect' }));
99
110
  }
100
111
 
101
- async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
112
+ async #sendFramework({ conversation, payload, signal }: EndpointSendRequest): Promise<string> {
102
113
  const parsed = parseChannelId(conversation.id);
103
114
  if (!parsed) throw new Error(`无效的 GitHub conversation ID: ${conversation.id}`);
104
115
  const text = formatOutboundBody(payload);
105
116
  const r = parsed.type === 'issue'
106
- ? await this.client.api.createIssueComment(parsed.repo, parsed.number, text)
107
- : await this.client.api.createPRComment(parsed.repo, parsed.number, text);
117
+ ? await this.createIssueComment({ repo: parsed.repo, number: parsed.number, body: text, signal })
118
+ : await this.createPRComment({ repo: parsed.repo, number: parsed.number, body: text, signal });
108
119
  if (!r.ok) throw new Error(`发送失败: ${JSON.stringify(r.data)}`);
109
120
  this.#logger.debug(formatCompact({
110
121
  op: 'github_send',
111
- endpoint: this.client.name,
122
+ endpoint: this.#options.config.id,
112
123
  target: `${conversation.kind}:${conversation.id}`,
113
124
  messageId: r.data.id,
114
125
  }));
@@ -116,25 +127,33 @@ export class GithubEndpoint extends Endpoint<GithubClient> {
116
127
  }
117
128
 
118
129
  /** Test / internal: admit a parsed comment when open. */
119
- admit(comment: GithubInboundComment): void {
130
+ admit(comment: GithubInboundComment, nativeEvent: unknown = comment): void {
131
+ if (!this.#open) return;
132
+ void this[endpointSpec].events.run(() => this.#admitComment(comment, nativeEvent)).catch(error => {
133
+ this.#logger.warn(formatCompact({ op: 'github_gateway_receive_failed', error: error instanceof Error ? error.message : String(error) }));
134
+ });
135
+ }
136
+
137
+ #admitComment(comment: GithubInboundComment, nativeEvent: unknown = comment): void {
120
138
  if (!this.#open) return;
121
- const botUser = this.client.config.botLogin
122
- || this.client.api.getBotLogin()
123
- || this.client.api.authenticatedUser;
139
+ const botUser = this.#options.config.botLogin
140
+ || this.getBotLogin()
141
+ || this.authenticatedUser;
124
142
  if (botUser && comment.sender === botUser) return;
125
143
  const conversation = githubInboundConversation(String(this.#options.id), comment);
126
144
  const content = enrichInboundContent(
127
145
  formatInboundContent(comment.content),
128
- this.client.config,
146
+ this.#options.config,
129
147
  botUser ?? undefined,
130
148
  comment.repo,
131
149
  );
132
- void this.emit('message.receive', {
150
+ void this[endpointSpec].events.emit('message.receive', {
151
+ event: nativeEvent,
133
152
  conversation,
134
153
  message: { conversation, id: comment.id },
135
154
  content,
136
155
  sender: { id: comment.sender, name: comment.sender },
137
- endpointId: this.client.name,
156
+ endpointId: this.#options.config.id,
138
157
  metadata: Object.freeze({
139
158
  repo: comment.repo,
140
159
  kind: comment.kind,
@@ -151,7 +170,7 @@ export class GithubEndpoint extends Endpoint<GithubClient> {
151
170
 
152
171
  admitPlatform(name: string, event: unknown): void {
153
172
  if (!this.#open) return;
154
- void this.emitPlatform(name, event).catch((error) => {
173
+ void this[endpointSpec].events.run(() => this[endpointSpec].events.platform(name, event)).catch((error) => {
155
174
  this.#logger.warn(formatCompact({
156
175
  op: 'github_platform_event_failed',
157
176
  event: name,