-
Notifications
You must be signed in to change notification settings - Fork 810
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
total glow-up: github MCP server (PR #434)
- Loading branch information
Showing
12 changed files
with
1,403 additions
and
1,522 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
export class GitHubError extends Error { | ||
constructor( | ||
message: string, | ||
public readonly status: number, | ||
public readonly response: unknown | ||
) { | ||
super(message); | ||
this.name = "GitHubError"; | ||
} | ||
} | ||
|
||
export class GitHubValidationError extends GitHubError { | ||
constructor(message: string, status: number, response: unknown) { | ||
super(message, status, response); | ||
this.name = "GitHubValidationError"; | ||
} | ||
} | ||
|
||
export class GitHubResourceNotFoundError extends GitHubError { | ||
constructor(resource: string) { | ||
super(`Resource not found: ${resource}`, 404, { message: `${resource} not found` }); | ||
this.name = "GitHubResourceNotFoundError"; | ||
} | ||
} | ||
|
||
export class GitHubAuthenticationError extends GitHubError { | ||
constructor(message = "Authentication failed") { | ||
super(message, 401, { message }); | ||
this.name = "GitHubAuthenticationError"; | ||
} | ||
} | ||
|
||
export class GitHubPermissionError extends GitHubError { | ||
constructor(message = "Insufficient permissions") { | ||
super(message, 403, { message }); | ||
this.name = "GitHubPermissionError"; | ||
} | ||
} | ||
|
||
export class GitHubRateLimitError extends GitHubError { | ||
constructor( | ||
message = "Rate limit exceeded", | ||
public readonly resetAt: Date | ||
) { | ||
super(message, 429, { message, reset_at: resetAt.toISOString() }); | ||
this.name = "GitHubRateLimitError"; | ||
} | ||
} | ||
|
||
export class GitHubConflictError extends GitHubError { | ||
constructor(message: string) { | ||
super(message, 409, { message }); | ||
this.name = "GitHubConflictError"; | ||
} | ||
} | ||
|
||
export function isGitHubError(error: unknown): error is GitHubError { | ||
return error instanceof GitHubError; | ||
} | ||
|
||
export function createGitHubError(status: number, response: any): GitHubError { | ||
switch (status) { | ||
case 401: | ||
return new GitHubAuthenticationError(response?.message); | ||
case 403: | ||
return new GitHubPermissionError(response?.message); | ||
case 404: | ||
return new GitHubResourceNotFoundError(response?.message || "Resource"); | ||
case 409: | ||
return new GitHubConflictError(response?.message || "Conflict occurred"); | ||
case 422: | ||
return new GitHubValidationError( | ||
response?.message || "Validation failed", | ||
status, | ||
response | ||
); | ||
case 429: | ||
return new GitHubRateLimitError( | ||
response?.message, | ||
new Date(response?.reset_at || Date.now() + 60000) | ||
); | ||
default: | ||
return new GitHubError( | ||
response?.message || "GitHub API error", | ||
status, | ||
response | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
import { z } from "zod"; | ||
|
||
// Base schemas for common types | ||
export const GitHubAuthorSchema = z.object({ | ||
name: z.string(), | ||
email: z.string(), | ||
date: z.string(), | ||
}); | ||
|
||
export const GitHubOwnerSchema = z.object({ | ||
login: z.string(), | ||
id: z.number(), | ||
node_id: z.string(), | ||
avatar_url: z.string(), | ||
url: z.string(), | ||
html_url: z.string(), | ||
type: z.string(), | ||
}); | ||
|
||
export const GitHubRepositorySchema = z.object({ | ||
id: z.number(), | ||
node_id: z.string(), | ||
name: z.string(), | ||
full_name: z.string(), | ||
private: z.boolean(), | ||
owner: GitHubOwnerSchema, | ||
html_url: z.string(), | ||
description: z.string().nullable(), | ||
fork: z.boolean(), | ||
url: z.string(), | ||
created_at: z.string(), | ||
updated_at: z.string(), | ||
pushed_at: z.string(), | ||
git_url: z.string(), | ||
ssh_url: z.string(), | ||
clone_url: z.string(), | ||
default_branch: z.string(), | ||
}); | ||
|
||
export const GithubFileContentLinks = z.object({ | ||
self: z.string(), | ||
git: z.string().nullable(), | ||
html: z.string().nullable() | ||
}); | ||
|
||
export const GitHubFileContentSchema = z.object({ | ||
name: z.string(), | ||
path: z.string(), | ||
sha: z.string(), | ||
size: z.number(), | ||
url: z.string(), | ||
html_url: z.string(), | ||
git_url: z.string(), | ||
download_url: z.string(), | ||
type: z.string(), | ||
content: z.string().optional(), | ||
encoding: z.string().optional(), | ||
_links: GithubFileContentLinks | ||
}); | ||
|
||
export const GitHubDirectoryContentSchema = z.object({ | ||
type: z.string(), | ||
size: z.number(), | ||
name: z.string(), | ||
path: z.string(), | ||
sha: z.string(), | ||
url: z.string(), | ||
git_url: z.string(), | ||
html_url: z.string(), | ||
download_url: z.string().nullable(), | ||
}); | ||
|
||
export const GitHubContentSchema = z.union([ | ||
GitHubFileContentSchema, | ||
z.array(GitHubDirectoryContentSchema), | ||
]); | ||
|
||
export const GitHubTreeEntrySchema = z.object({ | ||
path: z.string(), | ||
mode: z.enum(["100644", "100755", "040000", "160000", "120000"]), | ||
type: z.enum(["blob", "tree", "commit"]), | ||
size: z.number().optional(), | ||
sha: z.string(), | ||
url: z.string(), | ||
}); | ||
|
||
export const GitHubTreeSchema = z.object({ | ||
sha: z.string(), | ||
url: z.string(), | ||
tree: z.array(GitHubTreeEntrySchema), | ||
truncated: z.boolean(), | ||
}); | ||
|
||
export const GitHubCommitSchema = z.object({ | ||
sha: z.string(), | ||
node_id: z.string(), | ||
url: z.string(), | ||
author: GitHubAuthorSchema, | ||
committer: GitHubAuthorSchema, | ||
message: z.string(), | ||
tree: z.object({ | ||
sha: z.string(), | ||
url: z.string(), | ||
}), | ||
parents: z.array( | ||
z.object({ | ||
sha: z.string(), | ||
url: z.string(), | ||
}) | ||
), | ||
}); | ||
|
||
export const GitHubListCommitsSchema = z.array(z.object({ | ||
sha: z.string(), | ||
node_id: z.string(), | ||
commit: z.object({ | ||
author: GitHubAuthorSchema, | ||
committer: GitHubAuthorSchema, | ||
message: z.string(), | ||
tree: z.object({ | ||
sha: z.string(), | ||
url: z.string() | ||
}), | ||
url: z.string(), | ||
comment_count: z.number(), | ||
}), | ||
url: z.string(), | ||
html_url: z.string(), | ||
comments_url: z.string() | ||
})); | ||
|
||
export const GitHubReferenceSchema = z.object({ | ||
ref: z.string(), | ||
node_id: z.string(), | ||
url: z.string(), | ||
object: z.object({ | ||
sha: z.string(), | ||
type: z.string(), | ||
url: z.string(), | ||
}), | ||
}); | ||
|
||
// User and assignee schemas | ||
export const GitHubIssueAssigneeSchema = z.object({ | ||
login: z.string(), | ||
id: z.number(), | ||
avatar_url: z.string(), | ||
url: z.string(), | ||
html_url: z.string(), | ||
}); | ||
|
||
// Issue-related schemas | ||
export const GitHubLabelSchema = z.object({ | ||
id: z.number(), | ||
node_id: z.string(), | ||
url: z.string(), | ||
name: z.string(), | ||
color: z.string(), | ||
default: z.boolean(), | ||
description: z.string().optional(), | ||
}); | ||
|
||
export const GitHubMilestoneSchema = z.object({ | ||
url: z.string(), | ||
html_url: z.string(), | ||
labels_url: z.string(), | ||
id: z.number(), | ||
node_id: z.string(), | ||
number: z.number(), | ||
title: z.string(), | ||
description: z.string(), | ||
state: z.string(), | ||
}); | ||
|
||
export const GitHubIssueSchema = z.object({ | ||
url: z.string(), | ||
repository_url: z.string(), | ||
labels_url: z.string(), | ||
comments_url: z.string(), | ||
events_url: z.string(), | ||
html_url: z.string(), | ||
id: z.number(), | ||
node_id: z.string(), | ||
number: z.number(), | ||
title: z.string(), | ||
user: GitHubIssueAssigneeSchema, | ||
labels: z.array(GitHubLabelSchema), | ||
state: z.string(), | ||
locked: z.boolean(), | ||
assignee: GitHubIssueAssigneeSchema.nullable(), | ||
assignees: z.array(GitHubIssueAssigneeSchema), | ||
milestone: GitHubMilestoneSchema.nullable(), | ||
comments: z.number(), | ||
created_at: z.string(), | ||
updated_at: z.string(), | ||
closed_at: z.string().nullable(), | ||
body: z.string().nullable(), | ||
}); | ||
|
||
// Search-related schemas | ||
export const GitHubSearchResponseSchema = z.object({ | ||
total_count: z.number(), | ||
incomplete_results: z.boolean(), | ||
items: z.array(GitHubRepositorySchema), | ||
}); | ||
|
||
// Export types | ||
export type GitHubAuthor = z.infer<typeof GitHubAuthorSchema>; | ||
export type GitHubRepository = z.infer<typeof GitHubRepositorySchema>; | ||
export type GitHubFileContent = z.infer<typeof GitHubFileContentSchema>; | ||
export type GitHubDirectoryContent = z.infer<typeof GitHubDirectoryContentSchema>; | ||
export type GitHubContent = z.infer<typeof GitHubContentSchema>; | ||
export type GitHubTree = z.infer<typeof GitHubTreeSchema>; | ||
export type GitHubCommit = z.infer<typeof GitHubCommitSchema>; | ||
export type GitHubListCommits = z.infer<typeof GitHubListCommitsSchema>; | ||
export type GitHubReference = z.infer<typeof GitHubReferenceSchema>; | ||
export type GitHubIssueAssignee = z.infer<typeof GitHubIssueAssigneeSchema>; | ||
export type GitHubLabel = z.infer<typeof GitHubLabelSchema>; | ||
export type GitHubMilestone = z.infer<typeof GitHubMilestoneSchema>; | ||
export type GitHubIssue = z.infer<typeof GitHubIssueSchema>; | ||
export type GitHubSearchResponse = z.infer<typeof GitHubSearchResponseSchema>; |
Oops, something went wrong.