@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.
Files changed (96) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/LICENSE +21 -0
  3. package/README.md +667 -0
  4. package/SECURITY.md +498 -0
  5. package/dist/GitHubAppInternalContext.d.ts +44 -0
  6. package/dist/GitHubAppInternalContext.js +2 -0
  7. package/dist/GitHubAppPlugin.d.ts +45 -0
  8. package/dist/GitHubAppPlugin.js +367 -0
  9. package/dist/GitHubAppPluginContext.d.ts +242 -0
  10. package/dist/GitHubAppPluginContext.js +2 -0
  11. package/dist/GitHubAppPluginOptions.d.ts +369 -0
  12. package/dist/GitHubAppPluginOptions.js +2 -0
  13. package/dist/handlers/InitiateInstallation.d.ts +32 -0
  14. package/dist/handlers/InitiateInstallation.js +66 -0
  15. package/dist/handlers/InstallationCallback.d.ts +42 -0
  16. package/dist/handlers/InstallationCallback.js +248 -0
  17. package/dist/handlers/UninstallHandler.d.ts +37 -0
  18. package/dist/handlers/UninstallHandler.js +153 -0
  19. package/dist/handlers/WebhookHandler.d.ts +54 -0
  20. package/dist/handlers/WebhookHandler.js +157 -0
  21. package/dist/index.d.ts +19 -0
  22. package/dist/index.js +23 -0
  23. package/dist/repos/GitHubAppSessionRepo.d.ts +24 -0
  24. package/dist/repos/GitHubAppSessionRepo.js +32 -0
  25. package/dist/repos/GitHubInstallationRepo.d.ts +53 -0
  26. package/dist/repos/GitHubInstallationRepo.js +83 -0
  27. package/dist/repos/GitHubWebhookEventRepo.d.ts +29 -0
  28. package/dist/repos/GitHubWebhookEventRepo.js +42 -0
  29. package/dist/schemas/GitHubAppSession.d.ts +13 -0
  30. package/dist/schemas/GitHubAppSession.js +2 -0
  31. package/dist/schemas/GitHubInstallation.d.ts +28 -0
  32. package/dist/schemas/GitHubInstallation.js +2 -0
  33. package/dist/schemas/InstallationCallbackRequest.d.ts +10 -0
  34. package/dist/schemas/InstallationCallbackRequest.js +2 -0
  35. package/dist/schemas/WebhookEvent.d.ts +16 -0
  36. package/dist/schemas/WebhookEvent.js +2 -0
  37. package/dist/schemas/WebhookPayload.d.ts +35 -0
  38. package/dist/schemas/WebhookPayload.js +2 -0
  39. package/dist/services/GitHubAPIClient.d.ts +143 -0
  40. package/dist/services/GitHubAPIClient.js +167 -0
  41. package/dist/services/GitHubAuthService.d.ts +85 -0
  42. package/dist/services/GitHubAuthService.js +160 -0
  43. package/dist/services/WebhookValidator.d.ts +93 -0
  44. package/dist/services/WebhookValidator.js +123 -0
  45. package/dist/utils/error-utils.d.ts +67 -0
  46. package/dist/utils/error-utils.js +121 -0
  47. package/dist/utils/jwt-utils.d.ts +35 -0
  48. package/dist/utils/jwt-utils.js +67 -0
  49. package/dist/utils/state-utils.d.ts +38 -0
  50. package/dist/utils/state-utils.js +74 -0
  51. package/dist/utils/token-cache-utils.d.ts +47 -0
  52. package/dist/utils/token-cache-utils.js +74 -0
  53. package/dist/utils/webhook-signature-utils.d.ts +22 -0
  54. package/dist/utils/webhook-signature-utils.js +57 -0
  55. package/examples/basic-installation.ts +246 -0
  56. package/examples/create-issue.ts +392 -0
  57. package/examples/error-handling.ts +396 -0
  58. package/examples/multi-event-webhook.ts +367 -0
  59. package/examples/organization-installation.ts +316 -0
  60. package/examples/repository-access.ts +480 -0
  61. package/examples/webhook-handling.ts +343 -0
  62. package/examples/with-jwt-auth.ts +319 -0
  63. package/package.json +41 -0
  64. package/spec/core-utilities.spec.ts +243 -0
  65. package/spec/handlers.spec.ts +216 -0
  66. package/spec/helpers/reporter.ts +41 -0
  67. package/spec/integration-and-security.spec.ts +483 -0
  68. package/spec/plugin-core.spec.ts +258 -0
  69. package/spec/project-setup.spec.ts +56 -0
  70. package/spec/repos-and-schemas.spec.ts +288 -0
  71. package/spec/services.spec.ts +108 -0
  72. package/spec/support/jasmine.json +7 -0
  73. package/src/GitHubAppPlugin.ts +411 -0
  74. package/src/GitHubAppPluginContext.ts +254 -0
  75. package/src/GitHubAppPluginOptions.ts +412 -0
  76. package/src/handlers/InstallationCallback.ts +292 -0
  77. package/src/handlers/WebhookHandler.ts +179 -0
  78. package/src/index.ts +29 -0
  79. package/src/repos/GitHubAppSessionRepo.ts +36 -0
  80. package/src/repos/GitHubInstallationRepo.ts +95 -0
  81. package/src/repos/GitHubWebhookEventRepo.ts +48 -0
  82. package/src/schemas/GitHubAppSession.ts +13 -0
  83. package/src/schemas/GitHubInstallation.ts +28 -0
  84. package/src/schemas/InstallationCallbackRequest.ts +10 -0
  85. package/src/schemas/WebhookEvent.ts +16 -0
  86. package/src/schemas/WebhookPayload.ts +35 -0
  87. package/src/services/GitHubAPIClient.ts +244 -0
  88. package/src/services/GitHubAuthService.ts +188 -0
  89. package/src/services/WebhookValidator.ts +159 -0
  90. package/src/utils/error-utils.ts +148 -0
  91. package/src/utils/jwt-utils.ts +64 -0
  92. package/src/utils/state-utils.ts +72 -0
  93. package/src/utils/token-cache-utils.ts +89 -0
  94. package/src/utils/webhook-signature-utils.ts +57 -0
  95. package/tsconfig.dist.json +4 -0
  96. 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
+ }