@flink-app/github-app-plugin 0.12.1-alpha.38
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 +209 -0
- package/LICENSE +21 -0
- package/README.md +667 -0
- package/SECURITY.md +498 -0
- package/dist/GitHubAppInternalContext.d.ts +44 -0
- package/dist/GitHubAppInternalContext.js +2 -0
- package/dist/GitHubAppPlugin.d.ts +45 -0
- package/dist/GitHubAppPlugin.js +367 -0
- package/dist/GitHubAppPluginContext.d.ts +242 -0
- package/dist/GitHubAppPluginContext.js +2 -0
- package/dist/GitHubAppPluginOptions.d.ts +369 -0
- package/dist/GitHubAppPluginOptions.js +2 -0
- package/dist/handlers/InitiateInstallation.d.ts +32 -0
- package/dist/handlers/InitiateInstallation.js +66 -0
- package/dist/handlers/InstallationCallback.d.ts +42 -0
- package/dist/handlers/InstallationCallback.js +248 -0
- package/dist/handlers/UninstallHandler.d.ts +37 -0
- package/dist/handlers/UninstallHandler.js +153 -0
- package/dist/handlers/WebhookHandler.d.ts +54 -0
- package/dist/handlers/WebhookHandler.js +157 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +23 -0
- package/dist/repos/GitHubAppSessionRepo.d.ts +24 -0
- package/dist/repos/GitHubAppSessionRepo.js +32 -0
- package/dist/repos/GitHubInstallationRepo.d.ts +53 -0
- package/dist/repos/GitHubInstallationRepo.js +83 -0
- package/dist/repos/GitHubWebhookEventRepo.d.ts +29 -0
- package/dist/repos/GitHubWebhookEventRepo.js +42 -0
- package/dist/schemas/GitHubAppSession.d.ts +13 -0
- package/dist/schemas/GitHubAppSession.js +2 -0
- package/dist/schemas/GitHubInstallation.d.ts +28 -0
- package/dist/schemas/GitHubInstallation.js +2 -0
- package/dist/schemas/InstallationCallbackRequest.d.ts +10 -0
- package/dist/schemas/InstallationCallbackRequest.js +2 -0
- package/dist/schemas/WebhookEvent.d.ts +16 -0
- package/dist/schemas/WebhookEvent.js +2 -0
- package/dist/schemas/WebhookPayload.d.ts +35 -0
- package/dist/schemas/WebhookPayload.js +2 -0
- package/dist/services/GitHubAPIClient.d.ts +143 -0
- package/dist/services/GitHubAPIClient.js +167 -0
- package/dist/services/GitHubAuthService.d.ts +85 -0
- package/dist/services/GitHubAuthService.js +160 -0
- package/dist/services/WebhookValidator.d.ts +93 -0
- package/dist/services/WebhookValidator.js +123 -0
- package/dist/utils/error-utils.d.ts +67 -0
- package/dist/utils/error-utils.js +121 -0
- package/dist/utils/jwt-utils.d.ts +35 -0
- package/dist/utils/jwt-utils.js +67 -0
- package/dist/utils/state-utils.d.ts +38 -0
- package/dist/utils/state-utils.js +74 -0
- package/dist/utils/token-cache-utils.d.ts +47 -0
- package/dist/utils/token-cache-utils.js +74 -0
- package/dist/utils/webhook-signature-utils.d.ts +22 -0
- package/dist/utils/webhook-signature-utils.js +57 -0
- package/examples/basic-installation.ts +246 -0
- package/examples/create-issue.ts +392 -0
- package/examples/error-handling.ts +396 -0
- package/examples/multi-event-webhook.ts +367 -0
- package/examples/organization-installation.ts +316 -0
- package/examples/repository-access.ts +480 -0
- package/examples/webhook-handling.ts +343 -0
- package/examples/with-jwt-auth.ts +319 -0
- package/package.json +41 -0
- package/spec/core-utilities.spec.ts +243 -0
- package/spec/handlers.spec.ts +216 -0
- package/spec/helpers/reporter.ts +41 -0
- package/spec/integration-and-security.spec.ts +483 -0
- package/spec/plugin-core.spec.ts +258 -0
- package/spec/project-setup.spec.ts +56 -0
- package/spec/repos-and-schemas.spec.ts +288 -0
- package/spec/services.spec.ts +108 -0
- package/spec/support/jasmine.json +7 -0
- package/src/GitHubAppPlugin.ts +411 -0
- package/src/GitHubAppPluginContext.ts +254 -0
- package/src/GitHubAppPluginOptions.ts +412 -0
- package/src/handlers/InstallationCallback.ts +292 -0
- package/src/handlers/WebhookHandler.ts +179 -0
- package/src/index.ts +29 -0
- package/src/repos/GitHubAppSessionRepo.ts +36 -0
- package/src/repos/GitHubInstallationRepo.ts +95 -0
- package/src/repos/GitHubWebhookEventRepo.ts +48 -0
- package/src/schemas/GitHubAppSession.ts +13 -0
- package/src/schemas/GitHubInstallation.ts +28 -0
- package/src/schemas/InstallationCallbackRequest.ts +10 -0
- package/src/schemas/WebhookEvent.ts +16 -0
- package/src/schemas/WebhookPayload.ts +35 -0
- package/src/services/GitHubAPIClient.ts +244 -0
- package/src/services/GitHubAuthService.ts +188 -0
- package/src/services/WebhookValidator.ts +159 -0
- package/src/utils/error-utils.ts +148 -0
- package/src/utils/jwt-utils.ts +64 -0
- package/src/utils/state-utils.ts +72 -0
- package/src/utils/token-cache-utils.ts +89 -0
- package/src/utils/webhook-signature-utils.ts +57 -0
- package/tsconfig.dist.json +4 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { GitHubAPIClient } from "./services/GitHubAPIClient";
|
|
2
|
+
import GitHubInstallation from "./schemas/GitHubInstallation";
|
|
3
|
+
import { GitHubAppPluginOptions } from "./GitHubAppPluginOptions";
|
|
4
|
+
import { GitHubAuthService } from "./services/GitHubAuthService";
|
|
5
|
+
import { WebhookValidator } from "./services/WebhookValidator";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Public context interface exposed via ctx.plugins.githubApp
|
|
9
|
+
*
|
|
10
|
+
* Provides methods for interacting with GitHub App installations,
|
|
11
|
+
* managing installation access, and creating authenticated API clients.
|
|
12
|
+
*/
|
|
13
|
+
export interface GitHubAppPluginContext {
|
|
14
|
+
githubApp: {
|
|
15
|
+
/**
|
|
16
|
+
* Initiates GitHub App installation flow
|
|
17
|
+
*
|
|
18
|
+
* Creates a session with CSRF protection and returns the installation URL.
|
|
19
|
+
* Call this from your own handler with your own auth logic.
|
|
20
|
+
*
|
|
21
|
+
* @param params - Installation parameters
|
|
22
|
+
* @param params.userId - Application user ID to link installation to
|
|
23
|
+
* @param params.redirectUrl - Optional URL to redirect to after installation (deprecated, use onInstallationSuccess callback)
|
|
24
|
+
* @param params.metadata - Optional metadata to store in session
|
|
25
|
+
* @returns Installation flow details
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // In your custom handler
|
|
30
|
+
* export default async function InitiateGitHubInstall({ ctx }: GetHandlerParams) {
|
|
31
|
+
* const userId = ctx.auth.tokenData.userId;
|
|
32
|
+
*
|
|
33
|
+
* const { redirectUrl } = await ctx.plugins.githubApp.initiateInstallation({
|
|
34
|
+
* userId,
|
|
35
|
+
* metadata: { source: 'settings' }
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* return {
|
|
39
|
+
* status: 302,
|
|
40
|
+
* headers: { Location: redirectUrl }
|
|
41
|
+
* };
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
initiateInstallation(params: {
|
|
46
|
+
userId: string;
|
|
47
|
+
redirectUrl?: string;
|
|
48
|
+
metadata?: Record<string, any>;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
redirectUrl: string;
|
|
51
|
+
state: string;
|
|
52
|
+
sessionId: string;
|
|
53
|
+
}>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Uninstalls GitHub App for a user
|
|
57
|
+
*
|
|
58
|
+
* Removes installation from database and clears cached token.
|
|
59
|
+
* Call this from your own handler with your own auth logic.
|
|
60
|
+
*
|
|
61
|
+
* @param params - Uninstall parameters
|
|
62
|
+
* @param params.userId - Application user ID requesting uninstall
|
|
63
|
+
* @param params.installationId - GitHub installation ID to uninstall
|
|
64
|
+
* @returns Uninstall result
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* // In your custom handler
|
|
69
|
+
* export default async function UninstallGitHub({ ctx, params }: DeleteHandlerParams) {
|
|
70
|
+
* const userId = ctx.auth.tokenData.userId;
|
|
71
|
+
*
|
|
72
|
+
* const result = await ctx.plugins.githubApp.uninstall({
|
|
73
|
+
* userId,
|
|
74
|
+
* installationId: params.installationId
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* if (!result.success) {
|
|
78
|
+
* return badRequest(result.error);
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* return { status: 204 };
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
uninstall(params: {
|
|
86
|
+
userId: string;
|
|
87
|
+
installationId: number;
|
|
88
|
+
}): Promise<{
|
|
89
|
+
success: boolean;
|
|
90
|
+
error?: string;
|
|
91
|
+
}>;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get GitHub API client for an installation
|
|
95
|
+
*
|
|
96
|
+
* Creates an authenticated API client with automatic token injection.
|
|
97
|
+
* The client handles token caching, refresh, and retry logic.
|
|
98
|
+
*
|
|
99
|
+
* @param installationId - GitHub installation ID
|
|
100
|
+
* @returns GitHub API client instance
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const client = await ctx.plugins.githubApp.getClient(12345);
|
|
105
|
+
* const repos = await client.getRepositories();
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
getClient(installationId: number): Promise<GitHubAPIClient>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get installation for a user
|
|
112
|
+
*
|
|
113
|
+
* Returns the first installation found for the user.
|
|
114
|
+
* Use getInstallations() if a user may have multiple installations.
|
|
115
|
+
*
|
|
116
|
+
* @param userId - Application user ID
|
|
117
|
+
* @returns Installation if found, null otherwise
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const installation = await ctx.plugins.githubApp.getInstallation('user-123');
|
|
122
|
+
* if (installation) {
|
|
123
|
+
* console.log('Installed on:', installation.accountLogin);
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
getInstallation(userId: string): Promise<GitHubInstallation | null>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get all installations for a user
|
|
131
|
+
*
|
|
132
|
+
* Returns all GitHub App installations linked to the user.
|
|
133
|
+
* Users can install the app on multiple accounts (personal + organizations).
|
|
134
|
+
*
|
|
135
|
+
* @param userId - Application user ID
|
|
136
|
+
* @returns Array of installations
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* const installations = await ctx.plugins.githubApp.getInstallations('user-123');
|
|
141
|
+
* installations.forEach(installation => {
|
|
142
|
+
* console.log(`Installed on ${installation.accountLogin} (${installation.accountType})`);
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
getInstallations(userId: string): Promise<GitHubInstallation[]>;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Delete installation
|
|
150
|
+
*
|
|
151
|
+
* Removes an installation from the database and clears its cached token.
|
|
152
|
+
* Verifies the user owns the installation before deletion.
|
|
153
|
+
*
|
|
154
|
+
* @param userId - Application user ID
|
|
155
|
+
* @param installationId - GitHub installation ID
|
|
156
|
+
* @throws Error if user doesn't own installation
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* await ctx.plugins.githubApp.deleteInstallation('user-123', 12345);
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
deleteInstallation(userId: string, installationId: number): Promise<void>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check if user has access to specific repository
|
|
167
|
+
*
|
|
168
|
+
* Verifies that the user has an installation with access to the
|
|
169
|
+
* specified repository. Useful for authorization checks.
|
|
170
|
+
*
|
|
171
|
+
* @param userId - Application user ID
|
|
172
|
+
* @param owner - Repository owner (username or org)
|
|
173
|
+
* @param repo - Repository name
|
|
174
|
+
* @returns true if user has access, false otherwise
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const hasAccess = await ctx.plugins.githubApp.hasRepositoryAccess(
|
|
179
|
+
* 'user-123',
|
|
180
|
+
* 'facebook',
|
|
181
|
+
* 'react'
|
|
182
|
+
* );
|
|
183
|
+
*
|
|
184
|
+
* if (!hasAccess) {
|
|
185
|
+
* return forbidden('You do not have access to this repository');
|
|
186
|
+
* }
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
hasRepositoryAccess(userId: string, owner: string, repo: string): Promise<boolean>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get installation access token (for advanced usage)
|
|
193
|
+
*
|
|
194
|
+
* Returns a raw installation access token. Tokens are cached
|
|
195
|
+
* and automatically refreshed when expired.
|
|
196
|
+
*
|
|
197
|
+
* Most users should use getClient() instead, which handles
|
|
198
|
+
* token injection automatically.
|
|
199
|
+
*
|
|
200
|
+
* @param installationId - GitHub installation ID
|
|
201
|
+
* @returns Installation access token
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* const token = await ctx.plugins.githubApp.getInstallationToken(12345);
|
|
206
|
+
* // Make custom API call with token
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
getInstallationToken(installationId: number): Promise<string>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Clear token cache
|
|
213
|
+
*
|
|
214
|
+
* Removes all cached installation tokens. Next API call will
|
|
215
|
+
* fetch fresh tokens from GitHub.
|
|
216
|
+
*
|
|
217
|
+
* Useful for testing, forcing token refresh, or plugin shutdown.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* ctx.plugins.githubApp.clearTokenCache();
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
clearTokenCache(): void;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Plugin configuration (read-only)
|
|
228
|
+
*
|
|
229
|
+
* Provides access to plugin options for custom logic.
|
|
230
|
+
* Object is frozen to prevent modifications.
|
|
231
|
+
*/
|
|
232
|
+
options: Readonly<GitHubAppPluginOptions>;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* GitHub Authentication Service
|
|
236
|
+
*
|
|
237
|
+
* @internal
|
|
238
|
+
* Used internally by plugin handlers. Most applications should not need to access this directly.
|
|
239
|
+
*
|
|
240
|
+
* Provides JWT generation and installation token management.
|
|
241
|
+
*/
|
|
242
|
+
authService: GitHubAuthService;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Webhook Validator
|
|
246
|
+
*
|
|
247
|
+
* @internal
|
|
248
|
+
* Used internally by plugin handlers. Most applications should not need to access this directly.
|
|
249
|
+
*
|
|
250
|
+
* Validates webhook signatures and parses webhook payloads.
|
|
251
|
+
*/
|
|
252
|
+
webhookValidator: WebhookValidator;
|
|
253
|
+
};
|
|
254
|
+
}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installation success callback parameters
|
|
3
|
+
*
|
|
4
|
+
* Provided to the onInstallationSuccess callback when a user successfully
|
|
5
|
+
* installs the GitHub App and grants access to repositories.
|
|
6
|
+
*/
|
|
7
|
+
export interface InstallationSuccessParams {
|
|
8
|
+
/** GitHub installation ID */
|
|
9
|
+
installationId: number;
|
|
10
|
+
|
|
11
|
+
/** GitHub account (user or organization) where app was installed */
|
|
12
|
+
account: {
|
|
13
|
+
/** Account ID on GitHub */
|
|
14
|
+
id: number;
|
|
15
|
+
/** Account username or organization name */
|
|
16
|
+
login: string;
|
|
17
|
+
/** Account type */
|
|
18
|
+
type: "User" | "Organization";
|
|
19
|
+
/** Profile picture URL */
|
|
20
|
+
avatarUrl?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Repositories the user granted access to */
|
|
24
|
+
repositories: {
|
|
25
|
+
/** Repository ID on GitHub */
|
|
26
|
+
id: number;
|
|
27
|
+
/** Repository name (without owner) */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Full repository name (owner/repo) */
|
|
30
|
+
fullName: string;
|
|
31
|
+
/** Whether repository is private */
|
|
32
|
+
private: boolean;
|
|
33
|
+
}[];
|
|
34
|
+
|
|
35
|
+
/** Permissions granted to the app (e.g., { contents: 'read', issues: 'write' }) */
|
|
36
|
+
permissions: Record<string, string>;
|
|
37
|
+
|
|
38
|
+
/** Webhook events the app is subscribed to */
|
|
39
|
+
events: string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Installation success callback response
|
|
44
|
+
*
|
|
45
|
+
* Return this from onInstallationSuccess to link the installation
|
|
46
|
+
* to a user in your application and redirect the user.
|
|
47
|
+
*/
|
|
48
|
+
export interface InstallationSuccessResponse {
|
|
49
|
+
/**
|
|
50
|
+
* User ID in your application to link this installation to
|
|
51
|
+
*
|
|
52
|
+
* The plugin stores this mapping to enable repository access checks.
|
|
53
|
+
* Get this from your authentication system (session, JWT, etc.)
|
|
54
|
+
*/
|
|
55
|
+
userId: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Optional URL to redirect user after installation
|
|
59
|
+
*
|
|
60
|
+
* If not provided, a default success page will be shown.
|
|
61
|
+
* Use this to redirect users to your dashboard or specific page.
|
|
62
|
+
*
|
|
63
|
+
* @example "/dashboard/github"
|
|
64
|
+
* @example "/repos?installation=success"
|
|
65
|
+
*/
|
|
66
|
+
redirectUrl?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Installation error callback parameters
|
|
71
|
+
*
|
|
72
|
+
* Provided to the onInstallationError callback when installation fails.
|
|
73
|
+
*/
|
|
74
|
+
export interface InstallationErrorParams {
|
|
75
|
+
/** Error information */
|
|
76
|
+
error: {
|
|
77
|
+
/** Error code in kebab-case (e.g., 'invalid-state', 'session-expired') */
|
|
78
|
+
code: string;
|
|
79
|
+
/** User-friendly error message */
|
|
80
|
+
message: string;
|
|
81
|
+
/** Additional error details for debugging */
|
|
82
|
+
details?: any;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** Installation ID if available (may be undefined if error occurred before installation) */
|
|
86
|
+
installationId?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Installation error callback response
|
|
91
|
+
*
|
|
92
|
+
* Return this from onInstallationError to redirect the user
|
|
93
|
+
* to an error page or retry flow.
|
|
94
|
+
*/
|
|
95
|
+
export interface InstallationErrorResponse {
|
|
96
|
+
/**
|
|
97
|
+
* Optional URL to redirect user after error
|
|
98
|
+
*
|
|
99
|
+
* Use this to show error messages or allow retry.
|
|
100
|
+
*
|
|
101
|
+
* @example "/error?message=installation-failed"
|
|
102
|
+
* @example "/github/install?retry=true"
|
|
103
|
+
*/
|
|
104
|
+
redirectUrl?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Webhook event callback parameters
|
|
109
|
+
*
|
|
110
|
+
* Provided to the onWebhookEvent callback when a webhook event is received
|
|
111
|
+
* from GitHub. The plugin validates the webhook signature before calling this.
|
|
112
|
+
*/
|
|
113
|
+
export interface WebhookEventParams {
|
|
114
|
+
/**
|
|
115
|
+
* GitHub event type
|
|
116
|
+
*
|
|
117
|
+
* Common events: 'push', 'pull_request', 'issues', 'installation',
|
|
118
|
+
* 'pull_request_review', 'issue_comment', 'release', etc.
|
|
119
|
+
*/
|
|
120
|
+
event: string;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Event action (if applicable)
|
|
124
|
+
*
|
|
125
|
+
* Examples: 'opened', 'closed', 'reopened', 'created', 'deleted', etc.
|
|
126
|
+
* Not all events have actions.
|
|
127
|
+
*/
|
|
128
|
+
action?: string;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Full webhook payload from GitHub
|
|
132
|
+
*
|
|
133
|
+
* Structure varies by event type. See GitHub webhook documentation
|
|
134
|
+
* for payload schemas.
|
|
135
|
+
*/
|
|
136
|
+
payload: Record<string, any>;
|
|
137
|
+
|
|
138
|
+
/** Installation ID that triggered the webhook */
|
|
139
|
+
installationId: number;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Unique delivery ID from GitHub (X-GitHub-Delivery header)
|
|
143
|
+
*
|
|
144
|
+
* Use this for debugging and tracking webhook deliveries.
|
|
145
|
+
*/
|
|
146
|
+
deliveryId: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Configuration options for GitHub App Plugin
|
|
151
|
+
*
|
|
152
|
+
* Configure the plugin with your GitHub App credentials, callbacks,
|
|
153
|
+
* and optional settings for database, caching, and features.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* githubAppPlugin({
|
|
158
|
+
* // Required: GitHub App credentials
|
|
159
|
+
* appId: process.env.GITHUB_APP_ID!,
|
|
160
|
+
* privateKey: process.env.GITHUB_APP_PRIVATE_KEY_BASE64!, // Base64 encoded
|
|
161
|
+
* webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
|
|
162
|
+
* clientId: process.env.GITHUB_APP_CLIENT_ID!,
|
|
163
|
+
* clientSecret: process.env.GITHUB_APP_CLIENT_SECRET!,
|
|
164
|
+
*
|
|
165
|
+
* // Required: Installation success callback
|
|
166
|
+
* onInstallationSuccess: async ({ installationId, repositories }, ctx) => {
|
|
167
|
+
* const userId = getUserId(ctx); // Your auth system
|
|
168
|
+
* return { userId, redirectUrl: '/dashboard' };
|
|
169
|
+
* },
|
|
170
|
+
*
|
|
171
|
+
* // Optional: Handle webhook events
|
|
172
|
+
* onWebhookEvent: async ({ event, payload }, ctx) => {
|
|
173
|
+
* if (event === 'push') {
|
|
174
|
+
* console.log('Push event received');
|
|
175
|
+
* }
|
|
176
|
+
* }
|
|
177
|
+
* })
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
export interface GitHubAppPluginOptions {
|
|
181
|
+
// GitHub App Credentials (Required)
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* GitHub App ID
|
|
185
|
+
*
|
|
186
|
+
* Found in your GitHub App settings page.
|
|
187
|
+
*
|
|
188
|
+
* @example "123456"
|
|
189
|
+
*/
|
|
190
|
+
appId: string;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* GitHub App private key (Base64 encoded PEM format)
|
|
194
|
+
*
|
|
195
|
+
* Download the private key from GitHub App settings, then base64 encode it.
|
|
196
|
+
* This format plays nicely with environment variables (no line break issues).
|
|
197
|
+
* Supports both PKCS#1 and PKCS#8 formats (auto-detected after decoding).
|
|
198
|
+
*
|
|
199
|
+
* To encode your private key:
|
|
200
|
+
* ```bash
|
|
201
|
+
* # On macOS/Linux:
|
|
202
|
+
* base64 -i private-key.pem | tr -d '\n'
|
|
203
|
+
*
|
|
204
|
+
* # On Windows (PowerShell):
|
|
205
|
+
* [Convert]::ToBase64String([IO.File]::ReadAllBytes("private-key.pem"))
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @example "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0..."
|
|
209
|
+
*/
|
|
210
|
+
privateKey: string;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Webhook secret for signature validation
|
|
214
|
+
*
|
|
215
|
+
* Set in GitHub App settings. Used to validate webhook signatures
|
|
216
|
+
* using HMAC-SHA256. Generate a strong random string.
|
|
217
|
+
*
|
|
218
|
+
* @example "your-webhook-secret-here"
|
|
219
|
+
*/
|
|
220
|
+
webhookSecret: string;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* GitHub App client ID
|
|
224
|
+
*
|
|
225
|
+
* Found in your GitHub App settings page.
|
|
226
|
+
*
|
|
227
|
+
* @example "Iv1.abc123def456"
|
|
228
|
+
*/
|
|
229
|
+
clientId: string;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* GitHub App client secret
|
|
233
|
+
*
|
|
234
|
+
* Generate in GitHub App settings. Store in environment variables.
|
|
235
|
+
*
|
|
236
|
+
* @example "your-client-secret-here"
|
|
237
|
+
*/
|
|
238
|
+
clientSecret: string;
|
|
239
|
+
|
|
240
|
+
// Optional Configuration
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* GitHub App slug (optional)
|
|
244
|
+
*
|
|
245
|
+
* Used in installation URL. Auto-detected if not provided.
|
|
246
|
+
* Found in your GitHub App settings page.
|
|
247
|
+
*
|
|
248
|
+
* @default Auto-detected from GitHub API
|
|
249
|
+
* @example "my-flink-app"
|
|
250
|
+
*/
|
|
251
|
+
appSlug?: string;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* GitHub API base URL (optional)
|
|
255
|
+
*
|
|
256
|
+
* Use for GitHub Enterprise Server installations.
|
|
257
|
+
* For github.com, use the default.
|
|
258
|
+
*
|
|
259
|
+
* @default "https://api.github.com"
|
|
260
|
+
* @example "https://github.mycompany.com/api/v3"
|
|
261
|
+
*/
|
|
262
|
+
baseUrl?: string;
|
|
263
|
+
|
|
264
|
+
// Callbacks
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Callback invoked after successful installation
|
|
268
|
+
*
|
|
269
|
+
* REQUIRED. Called when user completes GitHub App installation.
|
|
270
|
+
* Return userId to link installation and optional redirectUrl.
|
|
271
|
+
*
|
|
272
|
+
* @param params - Installation data from GitHub
|
|
273
|
+
* @param ctx - Flink context with repos and plugins
|
|
274
|
+
* @returns Object with userId and optional redirectUrl
|
|
275
|
+
*
|
|
276
|
+
* @throws Should not throw - errors are caught and passed to onInstallationError
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```typescript
|
|
280
|
+
* async ({ installationId, repositories, account }, ctx) => {
|
|
281
|
+
* const userId = ctx.auth?.tokenData?.userId || 'anonymous';
|
|
282
|
+
* return {
|
|
283
|
+
* userId,
|
|
284
|
+
* redirectUrl: '/dashboard/github'
|
|
285
|
+
* };
|
|
286
|
+
* }
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
onInstallationSuccess: (params: InstallationSuccessParams, ctx: any) => Promise<InstallationSuccessResponse>;
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Callback invoked when installation fails (optional)
|
|
293
|
+
*
|
|
294
|
+
* Called when installation encounters an error (invalid state,
|
|
295
|
+
* expired session, GitHub API failure, etc.)
|
|
296
|
+
*
|
|
297
|
+
* @param params - Error information
|
|
298
|
+
* @returns Object with optional redirectUrl
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```typescript
|
|
302
|
+
* async ({ error, installationId }) => {
|
|
303
|
+
* console.error('Installation error:', error);
|
|
304
|
+
* return {
|
|
305
|
+
* redirectUrl: `/error?code=${error.code}`
|
|
306
|
+
* };
|
|
307
|
+
* }
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
onInstallationError?: (params: InstallationErrorParams) => Promise<InstallationErrorResponse>;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Callback invoked when webhook event is received (optional)
|
|
314
|
+
*
|
|
315
|
+
* Called for each webhook event after signature validation.
|
|
316
|
+
* Process events asynchronously. Don't throw errors to prevent
|
|
317
|
+
* GitHub from retrying.
|
|
318
|
+
*
|
|
319
|
+
* @param params - Webhook event data
|
|
320
|
+
* @param ctx - Flink context with repos and plugins
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```typescript
|
|
324
|
+
* async ({ event, action, payload, installationId }, ctx) => {
|
|
325
|
+
* if (event === 'push') {
|
|
326
|
+
* console.log('Push to', payload.repository.full_name);
|
|
327
|
+
* }
|
|
328
|
+
* if (event === 'pull_request' && action === 'opened') {
|
|
329
|
+
* const client = await ctx.plugins.githubApp.getClient(installationId);
|
|
330
|
+
* await client.createIssue(...);
|
|
331
|
+
* }
|
|
332
|
+
* }
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
onWebhookEvent?: (params: WebhookEventParams, ctx: any) => Promise<void>;
|
|
336
|
+
|
|
337
|
+
// Database Configuration
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* MongoDB collection name for sessions (optional)
|
|
341
|
+
*
|
|
342
|
+
* Used for CSRF protection during installation flow.
|
|
343
|
+
*
|
|
344
|
+
* @default "github_app_sessions"
|
|
345
|
+
*/
|
|
346
|
+
sessionsCollectionName?: string;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* MongoDB collection name for installations (optional)
|
|
350
|
+
*
|
|
351
|
+
* Stores installation-to-user mappings and repository access info.
|
|
352
|
+
*
|
|
353
|
+
* @default "github_installations"
|
|
354
|
+
*/
|
|
355
|
+
installationsCollectionName?: string;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* MongoDB collection name for webhook events (optional)
|
|
359
|
+
*
|
|
360
|
+
* Only used if logWebhookEvents is enabled.
|
|
361
|
+
*
|
|
362
|
+
* @default "github_webhook_events"
|
|
363
|
+
*/
|
|
364
|
+
webhookEventsCollectionName?: string;
|
|
365
|
+
|
|
366
|
+
// Cache Configuration
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Installation token cache TTL in seconds (optional)
|
|
370
|
+
*
|
|
371
|
+
* How long to cache installation access tokens in memory.
|
|
372
|
+
* Tokens expire after 60 minutes. Set to 55 minutes (3300 seconds)
|
|
373
|
+
* for 5-minute safety margin.
|
|
374
|
+
*
|
|
375
|
+
* @default 3300 (55 minutes)
|
|
376
|
+
* @example 3000 (50 minutes)
|
|
377
|
+
*/
|
|
378
|
+
tokenCacheTTL?: number;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Session TTL in seconds (optional)
|
|
382
|
+
*
|
|
383
|
+
* How long CSRF protection sessions are valid.
|
|
384
|
+
* Sessions are automatically deleted via MongoDB TTL index.
|
|
385
|
+
*
|
|
386
|
+
* @default 600 (10 minutes)
|
|
387
|
+
* @example 300 (5 minutes)
|
|
388
|
+
*/
|
|
389
|
+
sessionTTL?: number;
|
|
390
|
+
|
|
391
|
+
// Feature Flags
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Register HTTP handlers automatically (optional)
|
|
395
|
+
*
|
|
396
|
+
* If true, registers installation and webhook handlers.
|
|
397
|
+
* Set to false if you want to implement custom handlers.
|
|
398
|
+
*
|
|
399
|
+
* @default true
|
|
400
|
+
*/
|
|
401
|
+
registerRoutes?: boolean;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Log webhook events to MongoDB (optional)
|
|
405
|
+
*
|
|
406
|
+
* If true, stores all webhook events in database for debugging.
|
|
407
|
+
* Useful for development but may consume storage in production.
|
|
408
|
+
*
|
|
409
|
+
* @default false
|
|
410
|
+
*/
|
|
411
|
+
logWebhookEvents?: boolean;
|
|
412
|
+
}
|