-
Notifications
You must be signed in to change notification settings - Fork 218
feat(web): API & MCP improvements #795
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
a3e76a0
wip
brendan-kellam 0b13ee4
wip
brendan-kellam 96a64b0
change commits route to GET request with query params
brendan-kellam 493a2f6
paginated git api
brendan-kellam 4e2e14c
add param to list commits endpoint
brendan-kellam e7a9f37
wip
brendan-kellam ee14525
update file source api to be a GET request
brendan-kellam 3a4323f
case insensitive author search
brendan-kellam 41efac1
use paginated api for search suggestions
brendan-kellam 583fee2
rename webUrl to externalWebUrl for repos
brendan-kellam d35ab77
add line numbers to source output
brendan-kellam 3441ab7
case insensitive language filter
brendan-kellam 83b5c2d
wip: use external url for search as well
brendan-kellam cf35d04
changelog + fixed tests
brendan-kellam 2fea457
Merge branch 'main' into bkellam/repos-pagination
brendan-kellam d09d519
feedback
brendan-kellam 2ec0465
more feedback
brendan-kellam File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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 |
|---|---|---|
| @@ -1,72 +1,105 @@ | ||
| import { env } from './env.js'; | ||
| import { listRepositoriesResponseSchema, searchResponseSchema, fileSourceResponseSchema, searchCommitsResponseSchema } from './schemas.js'; | ||
| import { FileSourceRequest, FileSourceResponse, ListRepositoriesResponse, SearchRequest, SearchResponse, ServiceError, SearchCommitsRequest, SearchCommitsResponse } from './types.js'; | ||
| import { isServiceError } from './utils.js'; | ||
| import { listReposResponseSchema, searchResponseSchema, fileSourceResponseSchema, listCommitsResponseSchema } from './schemas.js'; | ||
| import { FileSourceRequest, ListReposQueryParams, SearchRequest, ListCommitsQueryParamsSchema } from './types.js'; | ||
| import { isServiceError, ServiceErrorException } from './utils.js'; | ||
| import { z } from 'zod'; | ||
|
|
||
| export const search = async (request: SearchRequest): Promise<SearchResponse | ServiceError> => { | ||
| const result = await fetch(`${env.SOURCEBOT_HOST}/api/search`, { | ||
| const parseResponse = async <T extends z.ZodTypeAny>( | ||
| response: Response, | ||
| schema: T | ||
| ): Promise<z.infer<T>> => { | ||
| const text = await response.text(); | ||
|
|
||
| let json: unknown; | ||
| try { | ||
| json = JSON.parse(text); | ||
| } catch { | ||
| throw new Error(`Invalid JSON response: ${text}`); | ||
| } | ||
|
|
||
| // Check if the response is already a service error from the API | ||
| if (isServiceError(json)) { | ||
| throw new ServiceErrorException(json); | ||
| } | ||
|
|
||
| const parsed = schema.safeParse(json); | ||
| if (!parsed.success) { | ||
| throw new Error(`Failed to parse response: ${parsed.error.message}`); | ||
| } | ||
|
|
||
| return parsed.data; | ||
| }; | ||
|
|
||
| export const search = async (request: SearchRequest) => { | ||
| const response = await fetch(`${env.SOURCEBOT_HOST}/api/search`, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) | ||
| }, | ||
| body: JSON.stringify(request) | ||
| }).then(response => response.json()); | ||
| }); | ||
|
|
||
| if (isServiceError(result)) { | ||
| return result; | ||
| } | ||
|
|
||
| return searchResponseSchema.parse(result); | ||
| return parseResponse(response, searchResponseSchema); | ||
| } | ||
|
|
||
| export const listRepos = async (): Promise<ListRepositoriesResponse | ServiceError> => { | ||
| const result = await fetch(`${env.SOURCEBOT_HOST}/api/repos`, { | ||
| export const listRepos = async (queryParams: ListReposQueryParams = {}) => { | ||
| const url = new URL(`${env.SOURCEBOT_HOST}/api/repos`); | ||
|
|
||
| for (const [key, value] of Object.entries(queryParams)) { | ||
| if (value) { | ||
| url.searchParams.set(key, value.toString()); | ||
| } | ||
| } | ||
|
|
||
| const response = await fetch(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) | ||
| }, | ||
| }).then(response => response.json()); | ||
|
|
||
| if (isServiceError(result)) { | ||
| return result; | ||
| } | ||
| }); | ||
|
|
||
| return listRepositoriesResponseSchema.parse(result); | ||
| const repos = await parseResponse(response, listReposResponseSchema); | ||
| const totalCount = parseInt(response.headers.get('X-Total-Count') ?? '0', 10); | ||
| return { repos, totalCount }; | ||
| } | ||
|
|
||
| export const getFileSource = async (request: FileSourceRequest): Promise<FileSourceResponse | ServiceError> => { | ||
| const result = await fetch(`${env.SOURCEBOT_HOST}/api/source`, { | ||
| method: 'POST', | ||
| export const getFileSource = async (request: FileSourceRequest) => { | ||
| const url = new URL(`${env.SOURCEBOT_HOST}/api/source`); | ||
| for (const [key, value] of Object.entries(request)) { | ||
| if (value) { | ||
| url.searchParams.set(key, value.toString()); | ||
| } | ||
| } | ||
|
|
||
| const response = await fetch(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) | ||
| }, | ||
| body: JSON.stringify(request) | ||
| }).then(response => response.json()); | ||
|
|
||
| if (isServiceError(result)) { | ||
| return result; | ||
| } | ||
| }); | ||
|
|
||
| return fileSourceResponseSchema.parse(result); | ||
| return parseResponse(response, fileSourceResponseSchema); | ||
| } | ||
|
|
||
| export const searchCommits = async (request: SearchCommitsRequest): Promise<SearchCommitsResponse | ServiceError> => { | ||
| const result = await fetch(`${env.SOURCEBOT_HOST}/api/commits`, { | ||
| method: 'POST', | ||
| export const listCommits = async (queryParams: ListCommitsQueryParamsSchema) => { | ||
| const url = new URL(`${env.SOURCEBOT_HOST}/api/commits`); | ||
| for (const [key, value] of Object.entries(queryParams)) { | ||
| if (value) { | ||
| url.searchParams.set(key, value.toString()); | ||
| } | ||
| } | ||
|
|
||
| const response = await fetch(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'X-Org-Domain': '~', | ||
| ...(env.SOURCEBOT_API_KEY ? { 'X-Sourcebot-Api-Key': env.SOURCEBOT_API_KEY } : {}) | ||
| }, | ||
| body: JSON.stringify(request) | ||
| }).then(response => response.json()); | ||
|
|
||
| if (isServiceError(result)) { | ||
| return result; | ||
| } | ||
| }); | ||
|
|
||
| return searchCommitsResponseSchema.parse(result); | ||
| const commits = await parseResponse(response, listCommitsResponseSchema); | ||
| const totalCount = parseInt(response.headers.get('X-Total-Count') ?? '0', 10); | ||
| return { commits, totalCount }; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.