diff --git a/apps/docs/app/(diffshub)/(view)/[...path]/page.tsx b/apps/docs/app/(diffshub)/(view)/[...path]/page.tsx
index 5dff5ee5a..f0518a603 100644
--- a/apps/docs/app/(diffshub)/(view)/[...path]/page.tsx
+++ b/apps/docs/app/(diffshub)/(view)/[...path]/page.tsx
@@ -2,6 +2,9 @@ import { redirect } from 'next/navigation';
import { ReviewUI } from '../_components/ReviewUI';
import { resolveDiffshubViewerRoute } from '../_components/utils';
+import { loadInitialDiffshubPatchResponse } from '@/lib/diffshubPatchResponse';
+
+export const dynamic = 'force-dynamic';
// Viewer route that mirrors the upstream path. GitHub is the public default,
// while hidden alternate domains can opt in through the `domain` query param.
@@ -19,11 +22,16 @@ export default async function DiffshubViewByPathPage({
if (route.kind === 'redirect') {
redirect(route.target);
}
+ const initialPatchResponse = loadInitialDiffshubPatchResponse({
+ domain: route.domain,
+ path: route.upstreamPath,
+ });
return (
diff --git a/apps/docs/app/(diffshub)/(view)/_components/ReviewUI.tsx b/apps/docs/app/(diffshub)/(view)/_components/ReviewUI.tsx
index 697f2191f..391041269 100644
--- a/apps/docs/app/(diffshub)/(view)/_components/ReviewUI.tsx
+++ b/apps/docs/app/(diffshub)/(view)/_components/ReviewUI.tsx
@@ -26,14 +26,21 @@ import {
removeSavedCommentSidebarEntry,
upsertSavedCommentSidebarEntry,
} from './utils';
+import type { InitialDiffshubPatchResponse } from '@/lib/diffshubPatchTypes';
interface ReviewUIProps {
domain?: string;
+ initialPatchResponse: Promise;
initialUrl: string;
path: string;
}
-export function ReviewUI({ domain, initialUrl, path }: ReviewUIProps) {
+export function ReviewUI({
+ domain,
+ initialPatchResponse,
+ initialUrl,
+ path,
+}: ReviewUIProps) {
useEffect(preloadAvatars, []);
const isWorkerPoolReadyOrDisable = useIsWorkerPoolReadyOrDisabled();
@@ -68,6 +75,7 @@ export function ReviewUI({ domain, initialUrl, path }: ReviewUIProps) {
} = usePatchLoader({
collapseMode,
domain,
+ initialPatchResponse,
onLoadStart: handlePatchLoadStart,
path,
viewerRef,
diff --git a/apps/docs/app/(diffshub)/(view)/_components/streamGitPatchFiles.ts b/apps/docs/app/(diffshub)/(view)/_components/streamGitPatchFiles.ts
index c5872d46d..feda0c809 100644
--- a/apps/docs/app/(diffshub)/(view)/_components/streamGitPatchFiles.ts
+++ b/apps/docs/app/(diffshub)/(view)/_components/streamGitPatchFiles.ts
@@ -6,22 +6,34 @@ const GIT_FILE_BOUNDARY_SCAN_OVERLAP =
GIT_FILE_BOUNDARY_WITH_NEWLINE.length - 1;
const NON_WHITESPACE_PATTERN = /\S/;
+export type GitPatchStream = ReadableStream;
+
export async function streamGitPatchFiles(
- body: ReadableStream,
- onFileText: (fileText: string) => Promise
+ body: GitPatchStream,
+ onFileText: (fileText: string) => Promise,
+ signal?: AbortSignal
): Promise {
const reader = body.getReader();
const decoder = new TextDecoder();
const parser = createGitPatchFileStreamParser();
+ const abortReader = () => {
+ void reader.cancel().catch(() => {});
+ };
+ signal?.addEventListener('abort', abortReader, { once: true });
try {
for (;;) {
+ if (signal?.aborted === true) {
+ return undefined;
+ }
+
const result = await reader.read();
if (result.done) {
break;
}
- if (result.value.byteLength > 0) {
- parser.push(decoder.decode(result.value, { stream: true }));
+ const text = decodeGitPatchStreamChunk(decoder, result.value);
+ if (text.length > 0) {
+ parser.push(text);
await consumeAvailableStreamedFiles(parser, onFileText);
}
}
@@ -41,10 +53,20 @@ export async function streamGitPatchFiles(
}
return result.fallbackPatchContent;
} finally {
+ signal?.removeEventListener('abort', abortReader);
reader.releaseLock();
}
}
+function decodeGitPatchStreamChunk(
+ decoder: TextDecoder,
+ chunk: string | Uint8Array
+): string {
+ return typeof chunk === 'string'
+ ? chunk
+ : decoder.decode(chunk, { stream: true });
+}
+
export function getStreamedPatchMetadata(fileText: string): string | undefined {
const diffBoundaryIndex = findNextGitFileBoundary(fileText, 0);
if (diffBoundaryIndex == null || diffBoundaryIndex <= 0) {
diff --git a/apps/docs/app/(diffshub)/(view)/_components/usePatchLoader.ts b/apps/docs/app/(diffshub)/(view)/_components/usePatchLoader.ts
index a07cee686..b43610cbe 100644
--- a/apps/docs/app/(diffshub)/(view)/_components/usePatchLoader.ts
+++ b/apps/docs/app/(diffshub)/(view)/_components/usePatchLoader.ts
@@ -34,6 +34,7 @@ import {
} from './lineHash';
import {
getStreamedPatchMetadata,
+ type GitPatchStream,
streamGitPatchFiles,
} from './streamGitPatchFiles';
import type {
@@ -44,6 +45,7 @@ import type {
CommentMetadata,
ViewerLoadState,
} from './types';
+import type { InitialDiffshubPatchResponse } from '@/lib/diffshubPatchTypes';
const STREAM_PUBLISH_INTERVAL_MS = 100;
const STREAM_INITIAL_PUBLISH_INTERVAL_MS = 500;
@@ -56,6 +58,7 @@ const GENERIC_PATCH_LOAD_ERROR_MESSAGE =
interface UsePatchLoaderOptions {
collapseMode: 'expanded' | 'collapsed';
domain?: string;
+ initialPatchResponse: Promise;
onLoadStart(): void;
path: string;
viewerRef: RefObject | null>;
@@ -80,6 +83,7 @@ interface UsePatchLoaderResult {
export function usePatchLoader({
collapseMode,
domain,
+ initialPatchResponse,
onLoadStart,
path,
viewerRef,
@@ -269,17 +273,20 @@ export function usePatchLoader({
}
console.time('-- request time');
- const response = await fetch(`/api/diff?${patchSearchParams}`, {
- cache: 'no-store',
- signal: controller.signal,
- });
+ const response =
+ loadAttempt === 0
+ ? await initialPatchResponse
+ : await fetch(`/api/diff?${patchSearchParams}`, {
+ cache: 'no-store',
+ signal: controller.signal,
+ });
console.timeEnd('-- request time');
// This only catches route setup errors. GitHub fetch failures are
// delivered while consuming the stream so the UI can enter the
// streaming state as soon as the local transport opens.
if (!response.ok) {
- const detail = (await response.text()).trim();
+ const detail = (await readPatchResponseText(response)).trim();
throw new Error(
detail.length > 0 ? detail : `Request failed (${response.status}).`
);
@@ -287,7 +294,7 @@ export function usePatchLoader({
if (response.body == null) {
console.time('-- reading patch');
- const patchContent = await response.text();
+ const patchContent = await readPatchResponseText(response);
console.timeEnd('-- reading patch');
await commitFullPatch(patchContent);
return;
@@ -402,6 +409,10 @@ export function usePatchLoader({
publishTreeSource();
};
const appendStreamedFile = async (fileText: string) => {
+ if (!isCurrentRequest()) {
+ return;
+ }
+
if (!hasReceivedFirstStreamedFile) {
hasReceivedFirstStreamedFile = true;
console.timeEnd('-- first streamed file');
@@ -454,7 +465,8 @@ export function usePatchLoader({
console.time('-- reading patch stream');
const fallbackPatchContent = await streamGitPatchFiles(
response.body,
- appendStreamedFile
+ appendStreamedFile,
+ controller.signal
);
console.timeEnd('-- reading patch stream');
if (!isCurrentRequest()) {
@@ -488,6 +500,7 @@ export function usePatchLoader({
};
}, [
domain,
+ initialPatchResponse,
loadAttempt,
onLoadStart,
path,
@@ -576,6 +589,43 @@ function getNextItemVersion(item: { version?: string | number }): number {
return typeof item.version === 'number' ? item.version + 1 : 1;
}
+type PatchResponseSource = Response | InitialDiffshubPatchResponse;
+
+async function readPatchResponseText(
+ response: PatchResponseSource
+): Promise {
+ if ('bodyText' in response) {
+ if (response.bodyText != null) {
+ return response.bodyText;
+ }
+ return response.body == null ? '' : await readStreamText(response.body);
+ }
+
+ return response.text();
+}
+
+async function readStreamText(body: GitPatchStream): Promise {
+ const reader = body.getReader();
+ const decoder = new TextDecoder();
+ let text = '';
+ try {
+ for (;;) {
+ const result = await reader.read();
+ if (result.done) {
+ break;
+ }
+ text +=
+ typeof result.value === 'string'
+ ? result.value
+ : decoder.decode(result.value, { stream: true });
+ }
+ text += decoder.decode();
+ return text;
+ } finally {
+ reader.releaseLock();
+ }
+}
+
function replaceLocationHash(hash: string | null): void {
const { pathname, search } = window.location;
const nextHash = hash ?? '';
diff --git a/apps/docs/app/(diffshub)/(view)/_components/utils.ts b/apps/docs/app/(diffshub)/(view)/_components/utils.ts
index 16b90bc8a..b0a63cfcf 100644
--- a/apps/docs/app/(diffshub)/(view)/_components/utils.ts
+++ b/apps/docs/app/(diffshub)/(view)/_components/utils.ts
@@ -93,7 +93,7 @@ export function getPatchViewerHref(input: string): string | undefined {
const githubPath = getGitHubPathFromURL(parsedURL);
if (githubPath != null) return githubPath;
if (parsedURL.pathname !== '/') {
- return `${parsedURL.pathname}?domain=${encodeURIComponent(parsedURL.hostname)}`;
+ return getAlternateDomainViewerHref(parsedURL);
}
return undefined;
} catch {
@@ -111,7 +111,7 @@ export function getPatchViewerHref(input: string): string | undefined {
const githubPath = getGitHubPathFromURL(parsedURL);
if (githubPath != null) return githubPath;
if (parsedURL.pathname !== '/') {
- return `${parsedURL.pathname}?domain=${encodeURIComponent(parsedURL.hostname)}`;
+ return getAlternateDomainViewerHref(parsedURL);
}
} catch {
// Not parseable even with https:// prefix.
@@ -175,6 +175,10 @@ export function resolveDiffshubViewerRoute(
};
}
+function getAlternateDomainViewerHref(parsedURL: URL): string {
+ return `${parsedURL.pathname}?domain=${encodeURIComponent(parsedURL.hostname)}`;
+}
+
function getGitHubPathFromURL(parsedURL: URL): string | undefined {
if (parsedURL.hostname === GITHUB_HOST) {
if (parsedURL.pathname === '/') {
diff --git a/apps/docs/app/api/diff/route.ts b/apps/docs/app/api/diff/route.ts
index 93d606b83..797fbf561 100644
--- a/apps/docs/app/api/diff/route.ts
+++ b/apps/docs/app/api/diff/route.ts
@@ -1,388 +1,18 @@
import { type NextRequest } from 'next/server';
-const CACHE_CONTROL = 'no-store';
-const EMPTY_PATCH_MESSAGE = 'GitHub returned an empty diff.';
-const GITHUB_HOST = 'github.com';
-const GITHUB_RAW_DIFF_HOST = 'patch-diff.githubusercontent.com';
-const NON_DIFF_RESPONSE_MESSAGE = 'GitHub did not return a diff for this URL.';
-const NON_WHITESPACE_PATTERN = /\S/;
-const RAW_GITHUB_DIFF_PATH_PATTERN =
- /^\/raw\/[^/]+\/[^/]+\/pull\/[^/]+\.(?:diff|patch)$/;
-const GITHUB_PULL_TAB_PATH_PATTERN =
- /^\/([^/]+)\/([^/]+)\/pull\/(\d+)\/(?:changes|files)$/;
-
-const CACHED_BLOBS = new Map([
- [
- '/nodejs/oven-sh/bun/pull/30412',
- 'https://diffshub.pierrecdn.com/patches/30412.diff',
- ],
- [
- '/nodejs/node/pull/59805',
- 'https://diffshub.pierrecdn.com/patches/59805.diff',
- ],
- [
- '/ghostty-org/ghostty/pull/12291',
- 'https://diffshub.pierrecdn.com/patches/12291.diff',
- ],
- [
- '/pierrecomputer/pierre/commit/0800fb',
- 'https://diffshub.pierrecdn.com/patches/0800fb.diff',
- ],
- [
- '/torvalds/linux/compare/v6.0...v7.0',
- 'https://diffshub.pierrecdn.com/patches/v6.0-v7.0.diff',
- ],
-]);
-
-const HIDDEN_PATCH_DOMAIN_RULES = [
- { domainRoot: 'tangled.org', defaultExtension: '.patch' },
-] as const;
-
-interface ResolvedPatchRequest {
- patchURL: string;
- sourceURL?: string;
-}
+import { createDiffshubPatchResponse } from '@/lib/diffshubPatchResponse';
// Validates the accepted path or URL, normalizes it to a raw diff URL, and
// returns a streaming proxy response so the client can render files as they
// arrive instead of waiting for the full patch text.
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
- const path = searchParams.get('path');
- const domain = searchParams.get('domain');
- const url = searchParams.get('url');
-
- if (path == null && url == null) {
- return createTextResponse('Path or URL parameter is required', {
- status: 400,
- });
- }
-
- try {
- // The client normally sends only the GitHub-relative path, but GitHub also
- // exposes raw PR diffs through patch-diff.githubusercontent.com. Tangled
- // paths use an explicit domain query parameter and are normalized to their
- // patch endpoint.
- const patchRequest = resolvePatchRequest(path, domain, url);
- if (patchRequest == null) {
- return createTextResponse('Invalid GitHub patch URL format', {
- status: 400,
- });
- }
-
- return await createPatchStreamResponse(
- patchRequest.patchURL,
- request.signal,
- {
- sourceURL: patchRequest.sourceURL ?? patchRequest.patchURL,
- }
- );
- } catch (error) {
- return createTextResponse(
- error instanceof Error ? error.message : 'Unknown error',
- { status: 500 }
- );
- }
-}
-
-// Resolves the accepted URL shapes to the exact upstream URL to fetch. Most
-// callers send a GitHub-relative path, but this also permits GitHub's raw PR
-// diff host and Tangled patch URLs without becoming a general URL fetcher.
-function resolvePatchRequest(
- path: string | null,
- domain: string | null,
- url: string | null
-): ResolvedPatchRequest | undefined {
- if (url != null) {
- return resolvePatchURLInput(url);
- }
-
- if (path == null) {
- return undefined;
- }
-
- if (domain != null) {
- const patchURL = resolveDomainPatchURL(domain, path);
- return patchURL == null ? undefined : { patchURL };
- }
-
- return resolvePatchURLInput(path);
-}
-
-function resolvePatchURLInput(input: string): ResolvedPatchRequest | undefined {
- if (input.startsWith('/')) {
- return resolveGitHubPatchRequest(input);
- }
-
- let parsedURL: URL;
- try {
- parsedURL = new URL(input);
- } catch {
- return undefined;
- }
-
- if (!isAllowedHTTPSURL(parsedURL)) {
- return undefined;
- }
-
- if (parsedURL.hostname === GITHUB_HOST) {
- return resolveGitHubPatchRequest(parsedURL.pathname);
- }
-
- if (
- parsedURL.hostname === GITHUB_RAW_DIFF_HOST &&
- RAW_GITHUB_DIFF_PATH_PATTERN.test(parsedURL.pathname)
- ) {
- return { patchURL: parsedURL.href };
- }
-
- const domainPatchURL = resolveDomainPatchURL(
- parsedURL.hostname,
- parsedURL.pathname
- );
- return domainPatchURL == null ? undefined : { patchURL: domainPatchURL };
-}
-
-function resolveGitHubPatchRequest(
- path: string
-): ResolvedPatchRequest | undefined {
- const patchURL = resolveGitHubPath(path);
- return patchURL == null ? undefined : { patchURL };
-}
-
-function resolveDomainPatchURL(
- domain: string,
- path: string
-): string | undefined {
- const domainRule = getHiddenPatchDomainRule(domain);
- if (domainRule == null) {
- return undefined;
- }
-
- const pathWithLeadingSlash = path.startsWith('/') ? path : `/${path}`;
- const url = new URL(`https://${domainRule.hostname}`);
- const normalizedPath = pathWithLeadingSlash.replace(/\/+$/, '');
- url.pathname = normalizedPath === '' ? '/' : normalizedPath;
- if (!url.pathname.endsWith(domainRule.defaultExtension)) {
- url.pathname += domainRule.defaultExtension;
- }
-
- return url.href;
-}
-
-function getHiddenPatchDomainRule(
- domain: string
-): { defaultExtension: string; hostname: string } | undefined {
- let hostname: string;
- try {
- hostname = new URL(`https://${domain}`).hostname;
- } catch {
- return undefined;
- }
-
- for (const domainRule of HIDDEN_PATCH_DOMAIN_RULES) {
- if (
- hostname === domainRule.domainRoot ||
- hostname.endsWith(`.${domainRule.domainRoot}`)
- ) {
- return { defaultExtension: domainRule.defaultExtension, hostname };
- }
- }
-
- return undefined;
-}
-
-function resolveGitHubPath(path: string): string | undefined {
- if (path === '/') {
- return undefined;
- }
-
- let patchPath = normalizeGitHubPath(path);
- if (patchPath === '') {
- return undefined;
- }
-
- const blobPatchURL = CACHED_BLOBS.get(removeDiffExtension(patchPath));
- if (blobPatchURL != null) {
- return blobPatchURL;
- }
-
- if (!patchPath.endsWith('.patch') && !patchPath.endsWith('.diff')) {
- patchPath += '.diff';
- }
-
- return `https://${GITHUB_HOST}${patchPath}`;
-}
-
-function removeDiffExtension(path: string): string {
- if (path.endsWith('.patch')) {
- return path.slice(0, -'.patch'.length);
- }
-
- if (path.endsWith('.diff')) {
- return path.slice(0, -'.diff'.length);
- }
-
- return path;
-}
-
-function normalizeGitHubPath(path: string): string {
- const trimmedPath = path.replace(/\/+$/, '');
- const pullTabMatch = GITHUB_PULL_TAB_PATH_PATTERN.exec(trimmedPath);
- if (pullTabMatch == null) {
- return trimmedPath;
- }
-
- return `/${pullTabMatch[1]}/${pullTabMatch[2]}/pull/${pullTabMatch[3]}`;
-}
-
-function isAllowedHTTPSURL(url: URL): boolean {
- return (
- url.protocol === 'https:' &&
- url.port === '' &&
- url.username === '' &&
- url.password === ''
- );
-}
-
-interface TextResponseOptions {
- status?: number;
- sourceURL?: string;
-}
-
-// Serves local patch fixtures through the same response path as GitHub data,
-// while rejecting empty files so the viewer does not enter a silent no-op
-// state.
-function createPatchTextResponse(
- patchText: string,
- options: Omit
-): Response {
- if (!NON_WHITESPACE_PATTERN.test(patchText)) {
- return createTextResponse(EMPTY_PATCH_MESSAGE, { status: 422 });
- }
-
- return createTextResponse(patchText, options);
-}
-
-// Validates the upstream response before opening the client-facing stream so
-// GitHub HTML pages and redirects become small text errors instead of Next.js
-// error documents.
-async function createPatchStreamResponse(
- patchURL: string,
- requestSignal: AbortSignal,
- options: Omit
-): Promise {
- const upstreamController = new AbortController();
- const abortUpstream = () => upstreamController.abort();
- requestSignal.addEventListener('abort', abortUpstream, { once: true });
-
- let response: Response;
- try {
- response = await fetch(patchURL, {
- cache: 'no-store',
- headers: { 'User-Agent': 'pierre-diffshub' },
- signal: upstreamController.signal,
- });
- } catch {
- requestSignal.removeEventListener('abort', abortUpstream);
- return createTextResponse('Failed to fetch patch.', { status: 502 });
- }
-
- if (!response.ok) {
- const status = response.status >= 400 ? response.status : 502;
- requestSignal.removeEventListener('abort', abortUpstream);
- return createTextResponse(
- `Failed to fetch patch: ${response.status} ${response.statusText}`,
- { status }
- );
- }
-
- const contentType = response.headers.get('Content-Type');
- if (contentType == null || !contentType.startsWith('text/plain')) {
- requestSignal.removeEventListener('abort', abortUpstream);
- return createTextResponse(NON_DIFF_RESPONSE_MESSAGE, { status: 415 });
- }
-
- if (response.headers.get('Content-Length') === '0') {
- requestSignal.removeEventListener('abort', abortUpstream);
- return createTextResponse(EMPTY_PATCH_MESSAGE, { status: 422 });
- }
-
- const responseBody = response.body;
- if (responseBody == null) {
- try {
- const patchText = await response.text();
- return createPatchTextResponse(patchText, options);
- } finally {
- requestSignal.removeEventListener('abort', abortUpstream);
- }
- }
-
- const stream = new ReadableStream({
- start(controller) {
- void pumpPatchBody(responseBody, controller).finally(() => {
- requestSignal.removeEventListener('abort', abortUpstream);
- });
+ return createDiffshubPatchResponse(
+ {
+ domain: searchParams.get('domain'),
+ path: searchParams.get('path'),
+ url: searchParams.get('url'),
},
- cancel() {
- abortUpstream();
- requestSignal.removeEventListener('abort', abortUpstream);
- },
- });
-
- return createTextResponse(stream, options);
-}
-
-// Forwards each validated upstream diff chunk into the client stream.
-async function pumpPatchBody(
- body: ReadableStream,
- controller: ReadableStreamDefaultController
-): Promise {
- try {
- const reader = body.getReader();
- let sawContent = false;
- try {
- for (;;) {
- const result = await reader.read();
- if (result.done) {
- break;
- }
-
- if (result.value.byteLength > 0) {
- sawContent = true;
- controller.enqueue(result.value);
- }
- }
- } finally {
- reader.releaseLock();
- }
-
- if (!sawContent) {
- throw new Error(EMPTY_PATCH_MESSAGE);
- }
-
- controller.close();
- } catch (error) {
- controller.error(error);
- }
-}
-
-// Centralizes text response headers for both stream and error bodies. Diff
-// responses are intentionally not cached in the browser because cached 100MB+
-// responses can replay poorly and delay the first useful diff bytes.
-function createTextResponse(
- body: string | ReadableStream,
- { status = 200, sourceURL }: TextResponseOptions = {}
-): Response {
- const headers = new Headers({
- 'Content-Type': 'text/plain; charset=utf-8',
- 'Cache-Control': CACHE_CONTROL,
- });
- if (sourceURL != null) {
- headers.set('X-Patch-Source', sourceURL);
- }
- return new Response(body, {
- status,
- headers,
- });
+ request.signal
+ );
}
diff --git a/apps/docs/lib/diffshubPatchResponse.ts b/apps/docs/lib/diffshubPatchResponse.ts
new file mode 100644
index 000000000..64c1e9ded
--- /dev/null
+++ b/apps/docs/lib/diffshubPatchResponse.ts
@@ -0,0 +1,469 @@
+import 'server-only';
+import type { InitialDiffshubPatchResponse } from './diffshubPatchTypes';
+
+const CACHE_CONTROL = 'no-store';
+const EMPTY_PATCH_MESSAGE = 'GitHub returned an empty diff.';
+const GITHUB_HOST = 'github.com';
+const GITHUB_RAW_DIFF_HOST = 'patch-diff.githubusercontent.com';
+const NON_DIFF_RESPONSE_MESSAGE = 'GitHub did not return a diff for this URL.';
+const NON_WHITESPACE_PATTERN = /\S/;
+const RAW_GITHUB_DIFF_PATH_PATTERN =
+ /^\/raw\/[^/]+\/[^/]+\/pull\/[^/]+\.(?:diff|patch)$/;
+const GITHUB_PULL_TAB_PATH_PATTERN =
+ /^\/([^/]+)\/([^/]+)\/pull\/(\d+)\/(?:changes|files)$/;
+
+const CACHED_BLOBS = new Map([
+ [
+ '/nodejs/oven-sh/bun/pull/30412',
+ 'https://diffshub.pierrecdn.com/patches/30412.diff',
+ ],
+ [
+ '/nodejs/node/pull/59805',
+ 'https://diffshub.pierrecdn.com/patches/59805.diff',
+ ],
+ [
+ '/ghostty-org/ghostty/pull/12291',
+ 'https://diffshub.pierrecdn.com/patches/12291.diff',
+ ],
+ [
+ '/pierrecomputer/pierre/commit/0800fb',
+ 'https://diffshub.pierrecdn.com/patches/0800fb.diff',
+ ],
+ [
+ '/torvalds/linux/compare/v6.0...v7.0',
+ 'https://diffshub.pierrecdn.com/patches/v6.0-v7.0.diff',
+ ],
+]);
+
+const HIDDEN_PATCH_DOMAIN_RULES = [
+ { domainRoot: 'tangled.org', defaultExtension: '.patch' },
+] as const;
+
+interface ResolvedPatchRequest {
+ patchURL: string;
+ sourceURL?: string;
+}
+
+export interface DiffshubPatchRequestInput {
+ domain?: string | null;
+ path?: string | null;
+ url?: string | null;
+}
+
+// Shared patch loader used by both the API route and the initial server render.
+// The API route returns the Response directly, while the page passes its body
+// stream through React Flight so the client can consume bytes earlier.
+export async function createDiffshubPatchResponse(
+ { domain = null, path = null, url = null }: DiffshubPatchRequestInput,
+ requestSignal: AbortSignal
+): Promise {
+ if (path == null && url == null) {
+ return createTextResponse('Path or URL parameter is required', {
+ status: 400,
+ });
+ }
+
+ try {
+ // The client normally sends only the GitHub-relative path, but GitHub also
+ // exposes raw PR diffs through patch-diff.githubusercontent.com. Tangled
+ // paths use an explicit domain query parameter and are normalized to their
+ // patch endpoint.
+ const patchRequest = resolvePatchRequest(path, domain, url);
+ if (patchRequest == null) {
+ return createTextResponse('Invalid GitHub patch URL format', {
+ status: 400,
+ });
+ }
+
+ return await createPatchStreamResponse(
+ patchRequest.patchURL,
+ requestSignal,
+ {
+ sourceURL: patchRequest.sourceURL ?? patchRequest.patchURL,
+ }
+ );
+ } catch (error) {
+ return createTextResponse(
+ error instanceof Error ? error.message : 'Unknown error',
+ { status: 500 }
+ );
+ }
+}
+
+export async function loadInitialDiffshubPatchResponse(
+ input: DiffshubPatchRequestInput
+): Promise {
+ try {
+ const response = await createDiffshubPatchResponse(
+ input,
+ new AbortController().signal
+ );
+
+ if (!response.ok || response.body == null) {
+ return {
+ body: null,
+ bodyText: await response.text(),
+ ok: response.ok,
+ status: response.status,
+ statusText: response.statusText,
+ };
+ }
+
+ return {
+ body: decodePatchBody(response.body),
+ bodyText: null,
+ ok: response.ok,
+ status: response.status,
+ statusText: response.statusText,
+ };
+ } catch (error) {
+ return {
+ body: null,
+ bodyText: error instanceof Error ? error.message : 'Unknown error',
+ ok: false,
+ status: 500,
+ statusText: 'Internal Server Error',
+ };
+ }
+}
+
+// React Flight's binary ReadableStream path currently trips over long patch
+// streams in dev. Decode on the server so the client receives text chunks via
+// the model stream path while preserving incremental delivery.
+function decodePatchBody(
+ body: ReadableStream
+): ReadableStream {
+ const decoder = new TextDecoder();
+ const reader = body.getReader();
+
+ return new ReadableStream({
+ async pull(controller) {
+ const result = await reader.read();
+ if (result.done) {
+ const finalText = decoder.decode();
+ if (finalText.length > 0) {
+ controller.enqueue(finalText);
+ }
+ controller.close();
+ reader.releaseLock();
+ return;
+ }
+
+ if (result.value.byteLength > 0) {
+ const text = decoder.decode(result.value, { stream: true });
+ if (text.length > 0) {
+ controller.enqueue(text);
+ }
+ }
+ },
+ async cancel(reason) {
+ try {
+ await reader.cancel(reason);
+ } finally {
+ reader.releaseLock();
+ }
+ },
+ });
+}
+
+// Resolves the accepted URL shapes to the exact upstream URL to fetch. Most
+// callers send a GitHub-relative path, but this also permits GitHub's raw PR
+// diff host and Tangled patch URLs without becoming a general URL fetcher.
+function resolvePatchRequest(
+ path: string | null,
+ domain: string | null,
+ url: string | null
+): ResolvedPatchRequest | undefined {
+ if (url != null) {
+ return resolvePatchURLInput(url);
+ }
+
+ if (path == null) {
+ return undefined;
+ }
+
+ if (domain != null) {
+ const patchURL = resolveDomainPatchURL(domain, path);
+ return patchURL == null ? undefined : { patchURL };
+ }
+
+ return resolvePatchURLInput(path);
+}
+
+function resolvePatchURLInput(input: string): ResolvedPatchRequest | undefined {
+ if (input.startsWith('/')) {
+ return resolveGitHubPatchRequest(input);
+ }
+
+ let parsedURL: URL;
+ try {
+ parsedURL = new URL(input);
+ } catch {
+ return undefined;
+ }
+
+ if (!isAllowedHTTPSURL(parsedURL)) {
+ return undefined;
+ }
+
+ if (parsedURL.hostname === GITHUB_HOST) {
+ return resolveGitHubPatchRequest(parsedURL.pathname);
+ }
+
+ if (
+ parsedURL.hostname === GITHUB_RAW_DIFF_HOST &&
+ RAW_GITHUB_DIFF_PATH_PATTERN.test(parsedURL.pathname)
+ ) {
+ return { patchURL: parsedURL.href };
+ }
+
+ const domainPatchURL = resolveDomainPatchURL(
+ parsedURL.hostname,
+ parsedURL.pathname
+ );
+ return domainPatchURL == null ? undefined : { patchURL: domainPatchURL };
+}
+
+function resolveGitHubPatchRequest(
+ path: string
+): ResolvedPatchRequest | undefined {
+ const patchURL = resolveGitHubPath(path);
+ return patchURL == null ? undefined : { patchURL };
+}
+
+function resolveDomainPatchURL(
+ domain: string,
+ path: string
+): string | undefined {
+ const domainRule = getHiddenPatchDomainRule(domain);
+ if (domainRule == null) {
+ return undefined;
+ }
+
+ const pathWithLeadingSlash = path.startsWith('/') ? path : `/${path}`;
+ const url = new URL(`https://${domainRule.hostname}`);
+ const normalizedPath = pathWithLeadingSlash.replace(/\/+$/, '');
+ url.pathname = normalizedPath === '' ? '/' : normalizedPath;
+ if (!url.pathname.endsWith(domainRule.defaultExtension)) {
+ url.pathname += domainRule.defaultExtension;
+ }
+
+ return url.href;
+}
+
+function getHiddenPatchDomainRule(
+ domain: string
+): { defaultExtension: string; hostname: string } | undefined {
+ let hostname: string;
+ try {
+ hostname = new URL(`https://${domain}`).hostname;
+ } catch {
+ return undefined;
+ }
+
+ for (const domainRule of HIDDEN_PATCH_DOMAIN_RULES) {
+ if (
+ hostname === domainRule.domainRoot ||
+ hostname.endsWith(`.${domainRule.domainRoot}`)
+ ) {
+ return { defaultExtension: domainRule.defaultExtension, hostname };
+ }
+ }
+
+ return undefined;
+}
+
+function resolveGitHubPath(path: string): string | undefined {
+ if (path === '/') {
+ return undefined;
+ }
+
+ let patchPath = normalizeGitHubPath(path);
+ if (patchPath === '') {
+ return undefined;
+ }
+
+ const blobPatchURL = CACHED_BLOBS.get(removeDiffExtension(patchPath));
+ if (blobPatchURL != null) {
+ return blobPatchURL;
+ }
+
+ if (!patchPath.endsWith('.patch') && !patchPath.endsWith('.diff')) {
+ patchPath += '.diff';
+ }
+
+ return `https://${GITHUB_HOST}${patchPath}`;
+}
+
+function removeDiffExtension(path: string): string {
+ if (path.endsWith('.patch')) {
+ return path.slice(0, -'.patch'.length);
+ }
+
+ if (path.endsWith('.diff')) {
+ return path.slice(0, -'.diff'.length);
+ }
+
+ return path;
+}
+
+function normalizeGitHubPath(path: string): string {
+ const trimmedPath = path.replace(/\/+$/, '');
+ const pullTabMatch = GITHUB_PULL_TAB_PATH_PATTERN.exec(trimmedPath);
+ if (pullTabMatch == null) {
+ return trimmedPath;
+ }
+
+ return `/${pullTabMatch[1]}/${pullTabMatch[2]}/pull/${pullTabMatch[3]}`;
+}
+
+function isAllowedHTTPSURL(url: URL): boolean {
+ return (
+ url.protocol === 'https:' &&
+ url.port === '' &&
+ url.username === '' &&
+ url.password === ''
+ );
+}
+
+interface TextResponseOptions {
+ status?: number;
+ sourceURL?: string;
+}
+
+// Serves local patch fixtures through the same response path as GitHub data,
+// while rejecting empty files so the viewer does not enter a silent no-op
+// state.
+function createPatchTextResponse(
+ patchText: string,
+ options: Omit
+): Response {
+ if (!NON_WHITESPACE_PATTERN.test(patchText)) {
+ return createTextResponse(EMPTY_PATCH_MESSAGE, { status: 422 });
+ }
+
+ return createTextResponse(patchText, options);
+}
+
+// Validates the upstream response before opening the client-facing stream so
+// GitHub HTML pages and redirects become small text errors instead of Next.js
+// error documents.
+async function createPatchStreamResponse(
+ patchURL: string,
+ requestSignal: AbortSignal,
+ options: Omit
+): Promise {
+ const upstreamController = new AbortController();
+ const abortUpstream = () => upstreamController.abort();
+ requestSignal.addEventListener('abort', abortUpstream, { once: true });
+
+ let response: Response;
+ try {
+ response = await fetch(patchURL, {
+ cache: 'no-store',
+ headers: { 'User-Agent': 'pierre-diffshub' },
+ signal: upstreamController.signal,
+ });
+ } catch {
+ requestSignal.removeEventListener('abort', abortUpstream);
+ return createTextResponse('Failed to fetch patch.', { status: 502 });
+ }
+
+ if (!response.ok) {
+ const status = response.status >= 400 ? response.status : 502;
+ requestSignal.removeEventListener('abort', abortUpstream);
+ return createTextResponse(
+ `Failed to fetch patch: ${response.status} ${response.statusText}`,
+ { status }
+ );
+ }
+
+ const contentType = response.headers.get('Content-Type');
+ if (contentType == null || !contentType.startsWith('text/plain')) {
+ requestSignal.removeEventListener('abort', abortUpstream);
+ return createTextResponse(NON_DIFF_RESPONSE_MESSAGE, { status: 415 });
+ }
+
+ if (response.headers.get('Content-Length') === '0') {
+ requestSignal.removeEventListener('abort', abortUpstream);
+ return createTextResponse(EMPTY_PATCH_MESSAGE, { status: 422 });
+ }
+
+ const responseBody = response.body;
+ if (responseBody == null) {
+ try {
+ const patchText = await response.text();
+ return createPatchTextResponse(patchText, options);
+ } finally {
+ requestSignal.removeEventListener('abort', abortUpstream);
+ }
+ }
+
+ const stream = new ReadableStream({
+ start(controller) {
+ void pumpPatchBody(responseBody, controller).finally(() => {
+ requestSignal.removeEventListener('abort', abortUpstream);
+ });
+ },
+ cancel() {
+ abortUpstream();
+ requestSignal.removeEventListener('abort', abortUpstream);
+ },
+ });
+
+ return createTextResponse(stream, options);
+}
+
+// Forwards each validated upstream diff chunk into the client stream.
+async function pumpPatchBody(
+ body: ReadableStream,
+ controller: ReadableStreamDefaultController
+): Promise {
+ try {
+ const reader = body.getReader();
+ let sawContent = false;
+ try {
+ for (;;) {
+ const result = await reader.read();
+ if (result.done) {
+ break;
+ }
+
+ if (result.value.byteLength > 0) {
+ sawContent = true;
+ controller.enqueue(result.value);
+ }
+ }
+ } finally {
+ reader.releaseLock();
+ }
+
+ if (!sawContent) {
+ throw new Error(EMPTY_PATCH_MESSAGE);
+ }
+
+ controller.close();
+ } catch (error) {
+ controller.error(error);
+ }
+}
+
+// Centralizes text response headers for both stream and error bodies. Diff
+// responses are intentionally not cached in the browser because cached 100MB+
+// responses can replay poorly and delay the first useful diff bytes.
+function createTextResponse(
+ body: string | ReadableStream,
+ { status = 200, sourceURL }: TextResponseOptions = {}
+): Response {
+ const headers = new Headers({
+ 'Content-Type': 'text/plain; charset=utf-8',
+ 'Cache-Control': CACHE_CONTROL,
+ });
+ if (sourceURL != null) {
+ headers.set('X-Patch-Source', sourceURL);
+ }
+ return new Response(body, {
+ status,
+ headers,
+ });
+}
diff --git a/apps/docs/lib/diffshubPatchTypes.ts b/apps/docs/lib/diffshubPatchTypes.ts
new file mode 100644
index 000000000..f8545558a
--- /dev/null
+++ b/apps/docs/lib/diffshubPatchTypes.ts
@@ -0,0 +1,7 @@
+export interface InitialDiffshubPatchResponse {
+ body: ReadableStream | null;
+ bodyText: string | null;
+ ok: boolean;
+ status: number;
+ statusText: string;
+}
diff --git a/apps/docs/test/getPatchViewerHref.test.ts b/apps/docs/test/getPatchViewerHref.test.ts
index 49eadec74..a7f33bbf2 100644
--- a/apps/docs/test/getPatchViewerHref.test.ts
+++ b/apps/docs/test/getPatchViewerHref.test.ts
@@ -71,6 +71,20 @@ describe('getPatchViewerHref', () => {
getPatchViewerHref('github.com/torvalds/linux/compare/v6.0...v7.0')
).toBe('/torvalds/linux/compare/v6.0...v7.0');
});
+
+ test('Tangled patch path preserves the host in the domain query', () => {
+ expect(getPatchViewerHref('tangled.org/@owner/repo/pulls/123')).toBe(
+ '/@owner/repo/pulls/123?domain=tangled.org'
+ );
+ });
+ });
+
+ describe('alternate domain URLs', () => {
+ test('Tangled URL preserves the host in the domain query', () => {
+ expect(
+ getPatchViewerHref('https://tangled.org/@owner/repo/pulls/123')
+ ).toBe('/@owner/repo/pulls/123?domain=tangled.org');
+ });
});
describe('bare GitHub paths (no domain)', () => {
diff --git a/apps/docs/test/resolveDiffshubViewerRoute.test.ts b/apps/docs/test/resolveDiffshubViewerRoute.test.ts
index 0aa905139..fa6dbd048 100644
--- a/apps/docs/test/resolveDiffshubViewerRoute.test.ts
+++ b/apps/docs/test/resolveDiffshubViewerRoute.test.ts
@@ -126,6 +126,20 @@ describe('resolveDiffshubViewerRoute', () => {
});
describe('alternate domain', () => {
+ test('renders Tangled paths against the requested host', () => {
+ expect(
+ resolveDiffshubViewerRoute(
+ ['@owner', 'repo', 'pulls', '123'],
+ 'tangled.org'
+ )
+ ).toEqual({
+ domain: 'tangled.org',
+ kind: 'render',
+ upstreamPath: '/@owner/repo/pulls/123',
+ url: 'https://tangled.org/@owner/repo/pulls/123',
+ });
+ });
+
test('renders against the requested host without rewriting', () => {
expect(
resolveDiffshubViewerRoute(