Compare commits

...

5 Commits

Author SHA1 Message Date
codegen-sh[bot] ae04635e42 fix: Correct TypeScript types for Logger calls in GitHub plugin
- Wrap unknown error objects in { error: err } for Logger.debug and Logger.warn calls
- Ensures compatibility with Logger's Extra type parameter requirements
- Fixes TypeScript compilation errors in CI
2025-09-04 02:04:41 +00:00
codegen-sh[bot] 2c7a365541 fix: Add proper TypeScript error handling for error.message access
- Add proper type checking for error.message access in catch block
- Ensures TypeScript strict mode compliance for error handling
2025-09-04 01:55:19 +00:00
codegen-sh[bot] 5ec0ed8fd5 fix: Correct Logger.debug usage for TypeScript compliance
- Add 'plugins' category as first argument to Logger.debug calls
- Fixes TypeScript compilation errors in GitHub plugin
- Maintains existing functionality while ensuring type safety
2025-09-04 01:49:44 +00:00
codegen-sh[bot] 308e7bc636 refactor: Use authenticated GitHub App client for public API fallback
- Use existing GitHub App authentication for higher rate limits (5,000/hour vs 60/hour)
- Leverage existing authenticateAsApp() method for minimal code changes
- Remove dependency on fetch utility, use Octokit client instead
- Improve error handling with proper type safety
- Fix linting issues with block scopes and unknown type handling

This provides the same functionality with significantly higher rate limits
while maintaining minimal changes to the existing codebase.
2025-09-04 01:40:06 +00:00
codegen-sh[bot] 926823f7c5 feat: Add public API fallback for GitHub link unfurling
- Implement fallback to GitHub's public API when no integration is found
- Enables unfurling for public repositories without requiring GitHub app installation
- Maintains existing functionality for integrated repositories
- Adds proper error handling for private repos and rate limits
- Uses server's fetch utility with proper user agent

Fixes unfurling for popular public repositories like microsoft/vscode, facebook/react, etc.
2025-09-04 01:29:00 +00:00
+90 -3
View File
@@ -15,6 +15,7 @@ import {
import Logger from "@server/logging/Logger";
import { Integration, User } from "@server/models";
import { UnfurlIssueOrPR, UnfurlSignature } from "@server/types";
import { GitHubUtils } from "../shared/GitHubUtils";
import env from "./env";
@@ -238,6 +239,21 @@ export class GitHub {
})) as Integration<IntegrationType.Embed>;
if (!integration) {
// Fallback: Try to fetch public repository data using GitHub's public API
try {
const appClient = GitHub.authenticateAsApp();
const publicData = await GitHub.fetchPublicResource(
resource,
appClient
);
if (publicData) {
return GitHub.transformData(publicData, resource.type);
}
} catch (err: unknown) {
Logger.debug("plugins", "Failed to fetch public resource from GitHub", {
error: err,
});
}
return;
}
@@ -252,12 +268,83 @@ export class GitHub {
}
return GitHub.transformData(res.data, resource.type);
} catch (err) {
Logger.warn("Failed to fetch resource from GitHub", err);
return { error: err.message || "Unknown error" };
} catch (err: unknown) {
Logger.warn("Failed to fetch resource from GitHub", { error: err });
return {
error:
err && typeof err === "object" && "message" in err
? (err.message as string) || "Unknown error"
: "Unknown error",
};
}
};
/**
* Fetches a GitHub resource using the public API with app authentication
* This is used as a fallback when no GitHub integration is available
*
* @param resource The parsed GitHub URL resource
* @param appClient The authenticated GitHub app client
* @returns The resource data or null if not found/not public
*/
private static async fetchPublicResource(
resource: NonNullable<ReturnType<typeof GitHub.parseUrl>>,
appClient: Octokit
): Promise<Issue | PR | null> {
try {
switch (resource.type) {
case UnfurlResourceType.Issue: {
const issueResponse = await appClient.request(
"GET /repos/{owner}/{repo}/issues/{issue_number}",
{
owner: resource.owner,
repo: resource.repo,
issue_number: resource.id,
headers: {
Accept: "application/vnd.github.text+json",
"X-GitHub-Api-Version": "2022-11-28",
},
}
);
return issueResponse.data;
}
case UnfurlResourceType.PR: {
const prResponse = await appClient.request(
"GET /repos/{owner}/{repo}/pulls/{pull_number}",
{
owner: resource.owner,
repo: resource.repo,
pull_number: resource.id,
headers: {
Accept: "application/vnd.github.text+json",
"X-GitHub-Api-Version": "2022-11-28",
},
}
);
return prResponse.data;
}
default:
return null;
}
} catch (err: unknown) {
// Handle common error cases
if (err && typeof err === "object" && "status" in err) {
if (err.status === 404) {
Logger.debug(
"plugins",
`GitHub resource not found or private: ${resource.owner}/${resource.repo}#${resource.id}`
);
} else if (err.status === 403) {
Logger.debug(
"plugins",
`GitHub API rate limit exceeded or access denied: ${resource.owner}/${resource.repo}#${resource.id}`
);
}
}
return null;
}
}
private static transformData(data: Issue | PR, type: UnfurlResourceType) {
if (type === UnfurlResourceType.Issue) {
const issue = data as Issue;