@flink-app/github-app-plugin 0.12.1-alpha.38 → 0.12.1-alpha.39

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/README.md CHANGED
@@ -82,6 +82,8 @@ The plugin requires MongoDB to store installation data and sessions.
82
82
 
83
83
  ## Quick Start
84
84
 
85
+ ### 1. Configure the Plugin
86
+
85
87
  ```typescript
86
88
  import { FlinkApp } from "@flink-app/flink";
87
89
  import { githubAppPlugin } from "@flink-app/github-app-plugin";
@@ -102,45 +104,13 @@ const app = new FlinkApp<Context>({
102
104
  webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
103
105
  clientId: process.env.GITHUB_APP_CLIENT_ID!,
104
106
  clientSecret: process.env.GITHUB_APP_CLIENT_SECRET!,
105
-
106
- // Optional: App slug for installation URL
107
107
  appSlug: "my-flink-app",
108
108
 
109
- // Required: Callback after successful installation
110
- onInstallationSuccess: async ({ installationId, repositories, account }, ctx) => {
111
- // Your app determines how to get userId
112
- // This could come from session, custom auth, or any other source
113
- const userId = getUserIdFromSession(); // Your implementation
114
-
115
- console.log(`User ${userId} installed app on ${account.login}`);
116
- console.log(`Granted access to ${repositories.length} repositories`);
117
-
118
- return {
119
- userId, // Link installation to this user
120
- redirectUrl: "/dashboard/repos", // Where to redirect after installation
121
- };
122
- },
123
-
124
109
  // Optional: Handle webhook events
125
110
  onWebhookEvent: async ({ event, action, payload, installationId }, ctx) => {
126
- console.log(`Received ${event} event for installation ${installationId}`);
127
-
128
- // Handle specific events
129
111
  if (event === "push") {
130
112
  console.log(`Push to ${payload.repository.full_name}`);
131
113
  }
132
-
133
- if (event === "pull_request" && action === "opened") {
134
- console.log(`New PR #${payload.pull_request.number}`);
135
- }
136
- },
137
-
138
- // Optional: Handle installation errors
139
- onInstallationError: async ({ error, installationId }) => {
140
- console.error(`Installation error:`, error);
141
- return {
142
- redirectUrl: "/error?message=installation-failed",
143
- };
144
114
  },
145
115
  }),
146
116
  ],
@@ -149,6 +119,54 @@ const app = new FlinkApp<Context>({
149
119
  await app.start();
150
120
  ```
151
121
 
122
+ ### 2. Implement Installation Callback Handler
123
+
124
+ The plugin does NOT include an opinionated installation callback handler. You must implement your own handler with your own authentication and authorization logic.
125
+
126
+ ```typescript
127
+ // src/handlers/github/GetGitHubInstallCallback.ts
128
+ import { GetHandler, unauthorized, badRequest, redirect } from "@flink-app/flink";
129
+ import { Context } from "../../Context";
130
+
131
+ export const Route = {
132
+ path: "/github/callback",
133
+ };
134
+
135
+ const GetGitHubInstallCallback: GetHandler<{}, {}, {}, { installation_id: string; state: string }> = async ({
136
+ ctx,
137
+ req,
138
+ }) => {
139
+ // 1. Check authentication (your way)
140
+ if (!ctx.auth?.tokenData?.userId) {
141
+ return unauthorized("Please log in to connect GitHub");
142
+ }
143
+
144
+ // 2. Parse query params
145
+ const { installation_id, state } = req.query;
146
+ if (!installation_id || !state) {
147
+ return badRequest("Missing required parameters");
148
+ }
149
+
150
+ // 3. Complete installation using plugin
151
+ const result = await ctx.plugins.githubApp.completeInstallation({
152
+ installationId: parseInt(installation_id, 10),
153
+ state,
154
+ userId: ctx.auth.tokenData.userId,
155
+ });
156
+
157
+ // 4. Handle response (your way)
158
+ if (!result.success) {
159
+ console.error("Installation failed:", result.error);
160
+ return redirect(`/settings/github?error=${result.error.code}`);
161
+ }
162
+
163
+ console.log("GitHub App installed:", result.installation);
164
+ return redirect("/settings/github?success=true");
165
+ };
166
+
167
+ export default GetGitHubInstallCallback;
168
+ ```
169
+
152
170
  ## Configuration
153
171
 
154
172
  ### GitHubAppPluginOptions
@@ -162,8 +180,6 @@ await app.start();
162
180
  | `clientSecret` | `string` | Yes | - | GitHub App client secret |
163
181
  | `appSlug` | `string` | No | Auto-detected | GitHub App slug (used in installation URL) |
164
182
  | `baseUrl` | `string` | No | `https://api.github.com` | GitHub API base URL (for GitHub Enterprise) |
165
- | `onInstallationSuccess` | `Function` | Yes | - | Callback after successful installation |
166
- | `onInstallationError` | `Function` | No | - | Callback on installation errors |
167
183
  | `onWebhookEvent` | `Function` | No | - | Callback for webhook events |
168
184
  | `sessionsCollectionName` | `string` | No | `github_app_sessions` | MongoDB collection for sessions |
169
185
  | `installationsCollectionName` | `string` | No | `github_installations` | MongoDB collection for installations |
@@ -175,73 +191,6 @@ await app.start();
175
191
 
176
192
  ### Callback Functions
177
193
 
178
- #### onInstallationSuccess (Required)
179
-
180
- Called when a user successfully installs the GitHub App.
181
-
182
- ```typescript
183
- onInstallationSuccess: async (
184
- params: {
185
- installationId: number;
186
- account: {
187
- id: number;
188
- login: string;
189
- type: "User" | "Organization";
190
- avatarUrl?: string;
191
- };
192
- repositories: {
193
- id: number;
194
- name: string;
195
- fullName: string;
196
- private: boolean;
197
- }[];
198
- permissions: Record<string, string>;
199
- events: string[];
200
- },
201
- ctx: Context
202
- ) =>
203
- Promise<{
204
- userId: string;
205
- redirectUrl?: string;
206
- }>;
207
- ```
208
-
209
- **Example:**
210
-
211
- ```typescript
212
- onInstallationSuccess: async ({ installationId, repositories, account }, ctx) => {
213
- // Get userId from your authentication system
214
- const userId = ctx.session?.userId || "anonymous";
215
-
216
- // Optionally notify user
217
- console.log(`Installation ${installationId} linked to user ${userId}`);
218
- console.log(`Access granted to ${repositories.length} repositories`);
219
-
220
- return {
221
- userId, // Required: Link installation to this user
222
- redirectUrl: "/dashboard", // Optional: Redirect after installation
223
- };
224
- };
225
- ```
226
-
227
- #### onInstallationError (Optional)
228
-
229
- Called when installation fails.
230
-
231
- ```typescript
232
- onInstallationError: async (params: {
233
- error: {
234
- code: string;
235
- message: string;
236
- details?: any;
237
- };
238
- installationId?: number;
239
- }) =>
240
- Promise<{
241
- redirectUrl?: string;
242
- }>;
243
- ```
244
-
245
194
  #### onWebhookEvent (Optional)
246
195
 
247
196
  Called when a webhook event is received.
@@ -411,6 +360,24 @@ if (!hasAccess) {
411
360
  }
412
361
  ```
413
362
 
363
+ ### completeInstallation(params)
364
+
365
+ Complete GitHub App installation after callback from GitHub.
366
+
367
+ ```typescript
368
+ const result = await ctx.plugins.githubApp.completeInstallation({
369
+ installationId: 12345,
370
+ state: "csrf-state-token",
371
+ userId: "user-123",
372
+ });
373
+
374
+ if (result.success) {
375
+ console.log("Installation completed:", result.installation);
376
+ } else {
377
+ console.error("Installation failed:", result.error);
378
+ }
379
+ ```
380
+
414
381
  ### getInstallationToken(installationId)
415
382
 
416
383
  Get raw installation access token (for advanced usage).
@@ -454,80 +421,56 @@ const issue = await client.createIssue("facebook", "react", {
454
421
  const response = await client.request("GET", "/rate_limit");
455
422
  ```
456
423
 
457
- ## Standalone Usage (No JWT Auth Plugin)
424
+ ## Authentication Integration
458
425
 
459
- This plugin is **standalone** and does NOT require the JWT Auth Plugin. It works with any authentication system.
426
+ This plugin is **auth-agnostic** and works with any authentication system. You implement your own installation callback handler with your own auth logic.
460
427
 
461
- ### Example with Custom Session-Based Auth
428
+ ### Example with Session-Based Auth
462
429
 
463
430
  ```typescript
464
- githubAppPlugin({
465
- // ... config
466
-
467
- onInstallationSuccess: async ({ installationId, repositories }, ctx) => {
468
- // Get userId from your custom session system
469
- const userId = ctx.req.session?.userId;
470
-
471
- if (!userId) {
472
- throw new Error("User not authenticated");
473
- }
474
-
475
- return {
476
- userId,
477
- redirectUrl: "/dashboard",
478
- };
479
- },
480
- });
481
- ```
431
+ // In your handler
432
+ const GetGitHubCallback: GetHandler = async ({ ctx, req }) => {
433
+ // Check session-based auth
434
+ const userId = ctx.req.session?.userId;
435
+ if (!userId) {
436
+ return unauthorized("Please log in");
437
+ }
482
438
 
483
- ### Example with Custom Token-Based Auth
439
+ const { installation_id, state } = req.query;
440
+ const result = await ctx.plugins.githubApp.completeInstallation({
441
+ installationId: parseInt(installation_id),
442
+ state,
443
+ userId,
444
+ });
484
445
 
485
- ```typescript
486
- githubAppPlugin({
487
- // ... config
488
-
489
- onInstallationSuccess: async ({ installationId, repositories }, ctx) => {
490
- // Get userId from your custom auth token
491
- const authHeader = ctx.req.headers.authorization;
492
- const userId = parseAuthToken(authHeader); // Your function
493
-
494
- return {
495
- userId,
496
- redirectUrl: "/dashboard",
497
- };
498
- },
499
- });
446
+ return result.success
447
+ ? redirect("/dashboard")
448
+ : redirect(`/error?code=${result.error.code}`);
449
+ };
500
450
  ```
501
451
 
502
- ## Integration with JWT Auth Plugin (Optional)
503
-
504
- While the plugin works standalone, you can optionally use it with the JWT Auth Plugin:
452
+ ### Example with JWT Auth Plugin
505
453
 
506
454
  ```typescript
507
- import { jwtAuthPlugin } from "@flink-app/jwt-auth-plugin";
508
-
509
- const app = new FlinkApp<Context>({
510
- auth: jwtAuthPlugin({
511
- secret: process.env.JWT_SECRET!,
512
- // ... JWT config
513
- }),
514
-
515
- plugins: [
516
- githubAppPlugin({
517
- // ... config
455
+ // In your handler with @flink-app/jwt-auth-plugin
456
+ const GetGitHubCallback: GetHandler = async ({ ctx, req }) => {
457
+ // Check JWT auth
458
+ const userId = ctx.auth?.tokenData?.userId;
459
+ if (!userId) {
460
+ return unauthorized("Please log in");
461
+ }
518
462
 
519
- onInstallationSuccess: async ({ installationId, repositories }, ctx) => {
520
- // Access JWT Auth Plugin context (if available)
521
- const userId = ctx.auth?.tokenData?.userId || "anonymous";
463
+ const { installation_id, state } = req.query;
464
+ const result = await ctx.plugins.githubApp.completeInstallation({
465
+ installationId: parseInt(installation_id),
466
+ state,
467
+ userId,
468
+ });
522
469
 
523
- return {
524
- userId,
525
- redirectUrl: "/dashboard",
526
- };
527
- },
528
- }),
529
- ],
530
- });
470
+ return result.success
471
+ ? redirect("/dashboard/github")
472
+ : redirect(`/error?code=${result.error.code}`);
473
+ };
531
474
  ```
532
475
 
533
476
  ## Security Considerations
@@ -1,44 +1,15 @@
1
1
  import { FlinkContext } from "@flink-app/flink";
2
- import { GitHubAuthService } from "./services/GitHubAuthService";
3
- import { WebhookValidator } from "./services/WebhookValidator";
2
+ import { GitHubAppPluginContext } from "./GitHubAppPluginContext";
4
3
  import GitHubAppSessionRepo from "./repos/GitHubAppSessionRepo";
5
4
  import GitHubInstallationRepo from "./repos/GitHubInstallationRepo";
6
5
  import GitHubWebhookEventRepo from "./repos/GitHubWebhookEventRepo";
7
- import { GitHubAppPluginOptions } from "./GitHubAppPluginOptions";
8
6
  /**
9
- * Internal context interface with private methods and services
10
- *
11
- * This interface extends the base FlinkContext with GitHub App Plugin-specific
12
- * repositories, services, and configuration. It's used internally by handlers,
13
- * services, and the plugin itself.
7
+ * Internal context used for plugin handlers.
14
8
  */
15
- export interface GitHubAppInternalContext extends FlinkContext {
16
- /**
17
- * GitHub App Session Repository
18
- * Manages temporary installation sessions for CSRF protection
19
- */
20
- repos: FlinkContext['repos'] & {
9
+ export interface GitHubAppInternalContext extends FlinkContext<GitHubAppPluginContext> {
10
+ repos: {
21
11
  githubAppSessionRepo: GitHubAppSessionRepo;
22
12
  githubInstallationRepo: GitHubInstallationRepo;
23
13
  githubWebhookEventRepo?: GitHubWebhookEventRepo;
24
14
  };
25
- /**
26
- * Internal plugin state and services
27
- */
28
- _githubAppInternal: {
29
- /**
30
- * GitHub Authentication Service
31
- * Handles JWT generation and installation token management
32
- */
33
- authService: GitHubAuthService;
34
- /**
35
- * Webhook Validator
36
- * Validates webhook signatures and parses payloads
37
- */
38
- webhookValidator: WebhookValidator;
39
- /**
40
- * Plugin configuration options
41
- */
42
- options: GitHubAppPluginOptions;
43
- };
44
15
  }
@@ -34,9 +34,9 @@ const GitHubWebhookEventRepo_1 = __importDefault(require("./repos/GitHubWebhookE
34
34
  const GitHubAuthService_1 = require("./services/GitHubAuthService");
35
35
  const GitHubAPIClient_1 = require("./services/GitHubAPIClient");
36
36
  const WebhookValidator_1 = require("./services/WebhookValidator");
37
+ const InstallationService_1 = require("./services/InstallationService");
37
38
  const error_utils_1 = require("./utils/error-utils");
38
39
  const state_utils_1 = require("./utils/state-utils");
39
- const InstallationCallback = __importStar(require("./handlers/InstallationCallback"));
40
40
  const WebhookHandler = __importStar(require("./handlers/WebhookHandler"));
41
41
  /**
42
42
  * GitHub App Plugin Factory Function
@@ -97,9 +97,6 @@ function githubAppPlugin(options) {
97
97
  if (!options.clientSecret) {
98
98
  throw new Error("GitHub App Plugin: clientSecret is required");
99
99
  }
100
- if (!options.onInstallationSuccess) {
101
- throw new Error("GitHub App Plugin: onInstallationSuccess callback is required");
102
- }
103
100
  // Determine configuration defaults
104
101
  const baseUrl = options.baseUrl || "https://api.github.com";
105
102
  const tokenCacheTTL = options.tokenCacheTTL || 3300; // 55 minutes
@@ -109,6 +106,7 @@ function githubAppPlugin(options) {
109
106
  let flinkApp;
110
107
  let authService;
111
108
  let webhookValidator;
109
+ let installationService;
112
110
  let sessionRepo;
113
111
  let installationRepo;
114
112
  let webhookEventRepo;
@@ -143,6 +141,8 @@ function githubAppPlugin(options) {
143
141
  // Add repositories to FlinkApp
144
142
  flinkApp.addRepo("githubAppSessionRepo", sessionRepo);
145
143
  flinkApp.addRepo("githubInstallationRepo", installationRepo);
144
+ // Initialize InstallationService
145
+ installationService = new InstallationService_1.InstallationService(authService, sessionRepo, installationRepo, baseUrl);
146
146
  // Conditionally initialize webhook event repo if logging is enabled
147
147
  if (logWebhookEvents) {
148
148
  webhookEventRepo = new GitHubWebhookEventRepo_1.default(flinkApp.ctx, db, webhookEventsCollectionName);
@@ -160,11 +160,10 @@ function githubAppPlugin(options) {
160
160
  await db.collection(webhookEventsCollectionName).createIndex({ createdAt: 1 }, { expireAfterSeconds: webhookEventTTL });
161
161
  flink_1.log.info(`GitHub App Plugin: Created TTL index on ${webhookEventsCollectionName} with ${webhookEventTTL}s expiration`);
162
162
  }
163
- // Conditionally register handlers (only GitHub-required handlers)
163
+ // Conditionally register handlers (only webhook handler)
164
164
  if (registerRoutes) {
165
- flinkApp.addHandler(InstallationCallback);
166
165
  flinkApp.addHandler(WebhookHandler);
167
- flink_1.log.info("GitHub App Plugin: Registered handlers (callback and webhook)");
166
+ flink_1.log.info("GitHub App Plugin: Registered webhook handler");
168
167
  }
169
168
  else {
170
169
  flink_1.log.info("GitHub App Plugin: Skipped handler registration (routes disabled)");
@@ -213,6 +212,15 @@ function githubAppPlugin(options) {
213
212
  sessionId,
214
213
  };
215
214
  }
215
+ /**
216
+ * Complete GitHub App installation
217
+ */
218
+ async function completeInstallation(params) {
219
+ if (!installationService) {
220
+ throw new Error("GitHub App Plugin: Plugin not initialized");
221
+ }
222
+ return installationService.completeInstallation(params);
223
+ }
216
224
  /**
217
225
  * Uninstalls GitHub App for a user
218
226
  */
@@ -343,6 +351,7 @@ function githubAppPlugin(options) {
343
351
  */
344
352
  const pluginCtx = {
345
353
  initiateInstallation,
354
+ completeInstallation,
346
355
  uninstall,
347
356
  getClient,
348
357
  getInstallation,
@@ -3,6 +3,7 @@ import GitHubInstallation from "./schemas/GitHubInstallation";
3
3
  import { GitHubAppPluginOptions } from "./GitHubAppPluginOptions";
4
4
  import { GitHubAuthService } from "./services/GitHubAuthService";
5
5
  import { WebhookValidator } from "./services/WebhookValidator";
6
+ import { CompleteInstallationResult } from "./services/InstallationService";
6
7
  /**
7
8
  * Public context interface exposed via ctx.plugins.githubApp
8
9
  *
@@ -50,6 +51,62 @@ export interface GitHubAppPluginContext {
50
51
  state: string;
51
52
  sessionId: string;
52
53
  }>;
54
+ /**
55
+ * Complete GitHub App installation
56
+ *
57
+ * Handles all the boilerplate of completing a GitHub App installation:
58
+ * 1. Validates the state parameter (CSRF protection)
59
+ * 2. Fetches installation details from GitHub API
60
+ * 3. Stores the installation in database
61
+ *
62
+ * The host application should:
63
+ * - Check if user is authenticated
64
+ * - Parse query parameters from the callback URL
65
+ * - Call this method with userId
66
+ * - Handle the response and redirect
67
+ *
68
+ * @param params - Installation completion parameters
69
+ * @param params.installationId - GitHub installation ID from query params
70
+ * @param params.state - State parameter from query params (CSRF protection)
71
+ * @param params.userId - Application user ID (from auth system)
72
+ * @returns Result with installation details or error
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * // In your custom callback handler
77
+ * export default async function GitHubCallback({ ctx, req }: GetHandlerParams) {
78
+ * // 1. Check authentication (your way)
79
+ * if (!ctx.auth?.tokenData?.userId) {
80
+ * return unauthorized('Please log in first');
81
+ * }
82
+ *
83
+ * // 2. Parse query params
84
+ * const { installation_id, state } = req.query;
85
+ * if (!installation_id || !state) {
86
+ * return badRequest('Missing required parameters');
87
+ * }
88
+ *
89
+ * // 3. Complete installation
90
+ * const result = await ctx.plugins.githubApp.completeInstallation({
91
+ * installationId: parseInt(installation_id),
92
+ * state,
93
+ * userId: ctx.auth.tokenData.userId
94
+ * });
95
+ *
96
+ * // 4. Handle response (your way)
97
+ * if (!result.success) {
98
+ * return redirect(`/error?code=${result.error.code}`);
99
+ * }
100
+ *
101
+ * return redirect('/dashboard/github');
102
+ * }
103
+ * ```
104
+ */
105
+ completeInstallation(params: {
106
+ installationId: number;
107
+ state: string;
108
+ userId: string;
109
+ }): Promise<CompleteInstallationResult>;
53
110
  /**
54
111
  * Uninstalls GitHub App for a user
55
112
  *
@@ -7,6 +7,8 @@
7
7
  export interface InstallationSuccessParams {
8
8
  /** GitHub installation ID */
9
9
  installationId: number;
10
+ /** Setup action type: 'install' for new installations, 'update' for repository selection updates */
11
+ setupAction: string;
10
12
  /** GitHub account (user or organization) where app was installed */
11
13
  account: {
12
14
  /** Account ID on GitHub */
@@ -134,8 +136,11 @@ export interface WebhookEventParams {
134
136
  /**
135
137
  * Configuration options for GitHub App Plugin
136
138
  *
137
- * Configure the plugin with your GitHub App credentials, callbacks,
138
- * and optional settings for database, caching, and features.
139
+ * Configure the plugin with your GitHub App credentials and optional settings
140
+ * for database, caching, and features.
141
+ *
142
+ * Note: Installation callback handler must be implemented by the host app.
143
+ * Use ctx.plugins.githubApp.completeInstallation() in your own handler.
139
144
  *
140
145
  * @example
141
146
  * ```typescript
@@ -146,12 +151,7 @@ export interface WebhookEventParams {
146
151
  * webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
147
152
  * clientId: process.env.GITHUB_APP_CLIENT_ID!,
148
153
  * clientSecret: process.env.GITHUB_APP_CLIENT_SECRET!,
149
- *
150
- * // Required: Installation success callback
151
- * onInstallationSuccess: async ({ installationId, repositories }, ctx) => {
152
- * const userId = getUserId(ctx); // Your auth system
153
- * return { userId, redirectUrl: '/dashboard' };
154
- * },
154
+ * appSlug: 'my-app',
155
155
  *
156
156
  * // Optional: Handle webhook events
157
157
  * onWebhookEvent: async ({ event, payload }, ctx) => {
@@ -235,50 +235,6 @@ export interface GitHubAppPluginOptions {
235
235
  * @example "https://github.mycompany.com/api/v3"
236
236
  */
237
237
  baseUrl?: string;
238
- /**
239
- * Callback invoked after successful installation
240
- *
241
- * REQUIRED. Called when user completes GitHub App installation.
242
- * Return userId to link installation and optional redirectUrl.
243
- *
244
- * @param params - Installation data from GitHub
245
- * @param ctx - Flink context with repos and plugins
246
- * @returns Object with userId and optional redirectUrl
247
- *
248
- * @throws Should not throw - errors are caught and passed to onInstallationError
249
- *
250
- * @example
251
- * ```typescript
252
- * async ({ installationId, repositories, account }, ctx) => {
253
- * const userId = ctx.auth?.tokenData?.userId || 'anonymous';
254
- * return {
255
- * userId,
256
- * redirectUrl: '/dashboard/github'
257
- * };
258
- * }
259
- * ```
260
- */
261
- onInstallationSuccess: (params: InstallationSuccessParams, ctx: any) => Promise<InstallationSuccessResponse>;
262
- /**
263
- * Callback invoked when installation fails (optional)
264
- *
265
- * Called when installation encounters an error (invalid state,
266
- * expired session, GitHub API failure, etc.)
267
- *
268
- * @param params - Error information
269
- * @returns Object with optional redirectUrl
270
- *
271
- * @example
272
- * ```typescript
273
- * async ({ error, installationId }) => {
274
- * console.error('Installation error:', error);
275
- * return {
276
- * redirectUrl: `/error?code=${error.code}`
277
- * };
278
- * }
279
- * ```
280
- */
281
- onInstallationError?: (params: InstallationErrorParams) => Promise<InstallationErrorResponse>;
282
238
  /**
283
239
  * Callback invoked when webhook event is received (optional)
284
240
  *
@@ -351,8 +307,9 @@ export interface GitHubAppPluginOptions {
351
307
  /**
352
308
  * Register HTTP handlers automatically (optional)
353
309
  *
354
- * If true, registers installation and webhook handlers.
310
+ * If true, registers the webhook handler.
355
311
  * Set to false if you want to implement custom handlers.
312
+ * Note: Installation callback handler must be implemented by the host app.
356
313
  *
357
314
  * @default true
358
315
  */
@@ -11,13 +11,7 @@
11
11
  * Route: GET /github-app/callback?installation_id=...&setup_action=...&state=...
12
12
  */
13
13
  import { RouteProps } from "@flink-app/flink";
14
- /**
15
- * Context with GitHub App Plugin
16
- *
17
- * Note: Using 'any' for simplicity. In a real-world scenario, you'd want to properly
18
- * type the context with both FlinkContext and GitHubAppPluginContext including the repos.
19
- */
20
- type InstallationCallbackContext = any;
14
+ import { GitHubAppInternalContext } from "../GitHubAppInternalContext";
21
15
  /**
22
16
  * Route configuration
23
17
  * Registered programmatically by the plugin if registerRoutes is enabled
@@ -30,12 +24,12 @@ export declare const Route: RouteProps;
30
24
  * details, calling the app's callback, and storing the installation.
31
25
  */
32
26
  declare const InstallationCallback: ({ ctx, req }: {
33
- ctx: InstallationCallbackContext;
27
+ ctx: GitHubAppInternalContext;
34
28
  req: any;
35
29
  }) => Promise<import("@flink-app/flink").FlinkResponse<undefined> | {
36
30
  status: number;
37
31
  headers: {
38
- Location: any;
32
+ Location: string;
39
33
  };
40
34
  data: {};
41
35
  }>;
@@ -10,15 +10,8 @@
10
10
  *
11
11
  * Route: POST /github-app/webhook
12
12
  */
13
- import { FlinkContext, RouteProps } from "@flink-app/flink";
14
- import { GitHubAppPluginContext } from "../GitHubAppPluginContext";
15
- /**
16
- * Context with GitHub App Plugin
17
- *
18
- * Note: Using 'any' for simplicity. In a real-world scenario, you'd want to properly
19
- * type the context with both FlinkContext and GitHubAppPluginContext including the repos.
20
- */
21
- type WebhookHandlerContext = FlinkContext<GitHubAppPluginContext>;
13
+ import { RouteProps } from "@flink-app/flink";
14
+ import { GitHubAppInternalContext } from "../GitHubAppInternalContext";
22
15
  /**
23
16
  * Route configuration
24
17
  * Registered programmatically by the plugin if registerRoutes is enabled
@@ -30,7 +23,7 @@ export declare const Route: RouteProps;
30
23
  * Validates webhook signatures and processes GitHub webhook events.
31
24
  */
32
25
  declare const WebhookHandler: ({ ctx, req }: {
33
- ctx: WebhookHandlerContext;
26
+ ctx: GitHubAppInternalContext;
34
27
  req: any;
35
28
  }) => Promise<{
36
29
  status: number;