Skip to content

Commit 1d95e82

Browse files
chore(api): Changed the search api to return raw source (instead of base64 encoding) (#356)
This PR alters the behaviour of the search api (and all apis that depend on it) to return raw source code instead of a base64 encoding. Reasoning: we are decoding it on the client in multiple different places, so it would be beneficial to decode it in a single spot. **Note**: This is a **breaking change** to the API surface. However, since the API surface is still unofficial/unsupported, I will roll this as a patch version change. See #101
1 parent 22d548e commit 1d95e82

File tree

12 files changed

+25
-47
lines changed

12 files changed

+25
-47
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
<!-- @NOTE: this release includes a API change that affects the MCP package (@sourcebot/mcp). On release, bump the MCP package's version and delete this message. -->
11+
1012
### Fixed
1113
- Delete account join request when redeeming an invite. [#352](https://github.com/sourcebot-dev/sourcebot/pull/352)
1214
- Fix issue where a repository would not be included in a search context if the context was created before the repository. [#354](https://github.com/sourcebot-dev/sourcebot/pull/354)
1315

16+
### Changed
17+
- Changed search api (and all apis that depend on it) to return raw source code instead of base64 encoded string. ([356](https://github.com/sourcebot-dev/sourcebot/pull/356)).
18+
19+
1420
## [4.3.0] - 2025-06-11
1521

1622
### Added

packages/mcp/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- Updated API client to match the latest Sourcebot release. [#356](https://github.com/sourcebot-dev/sourcebot/pull/356)
12+
1013
## [1.0.2] - 2025-05-28
1114

1215
### Changed

packages/mcp/src/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { z } from 'zod';
88
import { listRepos, search, getFileSource } from './client.js';
99
import { env, numberSchema } from './env.js';
1010
import { TextContent } from './types.js';
11-
import { base64Decode, isServiceError } from './utils.js';
11+
import { isServiceError } from './utils.js';
1212

1313
// Create MCP server
1414
const server = new McpServer({
@@ -114,8 +114,7 @@ server.tool(
114114

115115
if (includeCodeSnippets) {
116116
const snippets = file.chunks.map(chunk => {
117-
const content = base64Decode(chunk.content);
118-
return `\`\`\`\n${content}\n\`\`\``
117+
return `\`\`\`\n${chunk.content}\n\`\`\``
119118
}).join('\n');
120119
text += `\n\n${snippets}`;
121120
}
@@ -201,7 +200,7 @@ server.tool(
201200

202201
const content: TextContent[] = [{
203202
type: "text",
204-
text: `file: ${fileName}\nrepository: ${repoId}\nlanguage: ${response.language}\nsource:\n${base64Decode(response.source)}`,
203+
text: `file: ${fileName}\nrepository: ${repoId}\nlanguage: ${response.language}\nsource:\n${response.source}`,
205204
}]
206205

207206
return {

packages/mcp/src/utils.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import { ServiceError } from "./types.js";
22

3-
// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
4-
export const base64Decode = (base64: string): string => {
5-
const binString = atob(base64);
6-
return Buffer.from(Uint8Array.from(binString, (m) => m.codePointAt(0)!).buffer).toString();
7-
}
83

94
export const isServiceError = (data: unknown): data is ServiceError => {
105
return typeof data === 'object' &&

packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { base64Decode, getCodeHostInfoForRepo, unwrapServiceError } from "@/lib/utils";
3+
import { getCodeHostInfoForRepo, unwrapServiceError } from "@/lib/utils";
44
import { useBrowseParams } from "@/app/[domain]/browse/hooks/useBrowseParams";
55
import { useQuery } from "@tanstack/react-query";
66
import { getFileSource } from "@/features/search/fileSourceApi";
@@ -88,7 +88,7 @@ export const CodePreviewPanel = () => {
8888
</div>
8989
<Separator />
9090
<PureCodePreviewPanel
91-
source={base64Decode(fileSourceResponse.source)}
91+
source={fileSourceResponse.source}
9292
language={fileSourceResponse.language}
9393
repoName={repoName}
9494
path={path}

packages/web/src/app/[domain]/search/components/codePreviewPanel/index.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { useDomain } from "@/hooks/useDomain";
77
import { SymbolIcon } from "@radix-ui/react-icons";
88
import { SetStateAction, Dispatch, useMemo } from "react";
99
import { getFileSource } from "@/features/search/fileSourceApi";
10-
import { base64Decode } from "@/lib/utils";
1110
import { unwrapServiceError } from "@/lib/utils";
1211

1312
interface CodePreviewPanelProps {
@@ -41,10 +40,8 @@ export const CodePreviewPanel = ({
4140
}, domain)
4241
),
4342
select: (data) => {
44-
const decodedSource = base64Decode(data.source);
45-
4643
return {
47-
content: decodedSource,
44+
content: data.source,
4845
filepath: previewedFile.fileName.text,
4946
matches: previewedFile.chunks,
5047
link: previewedFile.webUrl,

packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatch.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
'use client';
22

3-
import { useCallback, useMemo } from "react";
3+
import { useCallback } from "react";
44
import { SearchResultFile, SearchResultChunk } from "@/features/search/types";
5-
import { base64Decode } from "@/lib/utils";
65
import { LightweightCodeHighlighter } from "@/app/[domain]/components/lightweightCodeHighlighter";
76

87

@@ -17,17 +16,12 @@ export const FileMatch = ({
1716
file,
1817
onOpen: _onOpen,
1918
}: FileMatchProps) => {
20-
21-
const content = useMemo(() => {
22-
return base64Decode(match.content);
23-
}, [match.content]);
24-
2519
const onOpen = useCallback((isCtrlKeyPressed: boolean) => {
2620
const startLineNumber = match.contentStart.lineNumber;
27-
const endLineNumber = content.trimEnd().split('\n').length + startLineNumber - 1;
21+
const endLineNumber = match.content.trimEnd().split('\n').length + startLineNumber - 1;
2822

2923
_onOpen(startLineNumber, endLineNumber, isCtrlKeyPressed);
30-
}, [content, match.contentStart.lineNumber, _onOpen]);
24+
}, [match.content, match.contentStart.lineNumber, _onOpen]);
3125

3226
// If it's just the title, don't show a code preview
3327
if (match.matchRanges.length === 0) {
@@ -57,7 +51,7 @@ export const FileMatch = ({
5751
lineNumbersOffset={match.contentStart.lineNumber}
5852
renderWhitespace={true}
5953
>
60-
{content}
54+
{match.content}
6155
</LightweightCodeHighlighter>
6256
</div>
6357
);

packages/web/src/ee/features/codeNav/components/exploreMenu/referenceList.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { PathHeader } from "@/app/[domain]/components/pathHeader";
55
import { LightweightCodeHighlighter } from "@/app/[domain]/components/lightweightCodeHighlighter";
66
import { FindRelatedSymbolsResponse } from "@/features/codeNav/types";
77
import { RepositoryInfo, SourceRange } from "@/features/search/types";
8-
import { base64Decode } from "@/lib/utils";
98
import { useMemo, useRef } from "react";
109
import useCaptureEvent from "@/hooks/useCaptureEvent";
1110
import { useVirtualizer } from "@tanstack/react-virtual";
@@ -155,10 +154,6 @@ const ReferenceListItem = ({
155154
onClick,
156155
onMouseEnter,
157156
}: ReferenceListItemProps) => {
158-
const decodedLineContent = useMemo(() => {
159-
return base64Decode(lineContent);
160-
}, [lineContent]);
161-
162157
const highlightRanges = useMemo(() => [range], [range]);
163158

164159
return (
@@ -174,7 +169,7 @@ const ReferenceListItem = ({
174169
lineNumbersOffset={range.start.lineNumber}
175170
renderWhitespace={false}
176171
>
177-
{decodedLineContent}
172+
{lineContent}
178173
</LightweightCodeHighlighter>
179174
</div>
180175
)

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/symbolDefinitionPreview.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
33
import { LightweightCodeHighlighter } from "@/app/[domain]/components/lightweightCodeHighlighter";
44
import { useMemo } from "react";
55
import { SourceRange } from "@/features/search/types";
6-
import { base64Decode } from "@/lib/utils";
76

87
interface SymbolDefinitionPreviewProps {
98
symbolDefinition: {
@@ -21,10 +20,6 @@ export const SymbolDefinitionPreview = ({
2120
const { lineContent, language, range } = symbolDefinition;
2221
const highlightRanges = useMemo(() => [range], [range]);
2322

24-
const decodedLineContent = useMemo(() => {
25-
return base64Decode(lineContent);
26-
}, [lineContent]);
27-
2823
return (
2924
<div className="flex flex-col gap-2 mb-2">
3025
<Tooltip
@@ -55,7 +50,7 @@ export const SymbolDefinitionPreview = ({
5550
lineNumbersOffset={range.start.lineNumber}
5651
renderWhitespace={false}
5752
>
58-
{decodedLineContent}
53+
{lineContent}
5954
</LightweightCodeHighlighter>
6055
</div>
6156
)

packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { sourcebot_context, sourcebot_pr_payload } from "@/features/agents/review-agent/types";
22
import { getFileSource } from "@/features/search/fileSourceApi";
33
import { fileSourceResponseSchema } from "@/features/search/schemas";
4-
import { base64Decode } from "@/lib/utils";
54
import { isServiceError } from "@/lib/utils";
65
import { env } from "@/env.mjs";
76
import { createLogger } from "@sourcebot/logger";
@@ -24,7 +23,7 @@ export const fetchFileContent = async (pr_payload: sourcebot_pr_payload, filenam
2423
}
2524

2625
const fileSourceResponse = fileSourceResponseSchema.parse(response);
27-
const fileContent = base64Decode(fileSourceResponse.source);
26+
const fileContent = fileSourceResponse.source;
2827

2928
const fileContentContext: sourcebot_context = {
3029
type: "file_content",

0 commit comments

Comments
 (0)