Skip to content

Conversation

@luxass
Copy link
Member

@luxass luxass commented Jan 11, 2026

🔗 Linked issue

📚 Description

Summary by CodeRabbit

Release Notes

  • Refactor
    • Consolidated file and directory response handling into unified utilities for improved consistency across the API.
    • Enhanced HTTP response mechanisms for serving files and directory listings with better header management and reliability.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Jan 11, 2026

⚠️ No Changeset found

Latest commit: 0b4f7e6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This pull request centralizes HTTP response handling for file and directory operations by introducing new utility functions in a shared library. These utilities replace duplicated inline logic across multiple route handlers for constructing response headers, determining file types, and handling file/directory responses.

Changes

Cohort / File(s) Summary
File Response Utilities Library
apps/api/src/lib/files.ts
Adds 9 new public functions and 2 interfaces: buildDirectoryHeaders(), buildFileHeaders(), handleFileResponse(), handleDirectoryResponse(), determineFileExtension(), isHtmlFile(), isDirectoryListing(), plus FileResponseOptions and DirectoryResponseOptions interfaces. Includes logic for constructing stat-like headers, handling HEAD requests, and detecting directory listings.
V1 Files Route Refactoring
apps/api/src/routes/v1_files/$wildcard.ts
Replaces ~40 lines of inline header construction and response handling with calls to new centralized utilities (handleDirectoryResponse(), handleFileResponse(), determineFileExtension(), isDirectoryListing()). Simplifies control flow and eliminates duplicated logic.
UCD Store Files Route Refactoring
apps/api/src/ucd-store/routes/files.ts
Removes imports of UCD stat header constants and replaces inline file extension/type detection with new utility functions. Delegates directory and file response handling to centralized handleDirectoryResponse() and handleFileResponse() functions, eliminating custom header assembly logic.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

pkg: env

Poem

🐰 With whiskers twitching, I delegate with cheer,
Files and dirs now handled without fear,
No more headers scattered, tangled about,
One shared library sorts it all out!
Hops of refactoring, cleaner and bright,

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99c61d8 and 0b4f7e6.

📒 Files selected for processing (3)
  • apps/api/src/lib/files.ts
  • apps/api/src/routes/v1_files/$wildcard.ts
  • apps/api/src/ucd-store/routes/files.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added pkg: cli Changes related to the CLI package. pkg: ucd-store Changes related to the UCD Store package. apps: api Changes related to the API. pkg: fs-bridge Changes related to the FS Bridge package. pkg: test-utils Changes related to the test-utils package. labels Jan 11, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 11, 2026

🌏 Preview Deployments

Application Status Preview URL
API ⏳ In Progress N/A
Website ⏳ In Progress N/A

Built from commit: 0b4f7e6e792946f72f84bea26b768651fb4793e4


🤖 This comment will be updated automatically when you push new commits to this PR.

@luxass luxass force-pushed the feat/align-store-files-edp branch from c21c43c to a874554 Compare January 11, 2026 12:03
Refactor file and directory response logic by introducing dedicated handlers `handleFileResponse` and `handleDirectoryResponse`. This improves code organization and readability. Additionally, utility functions for determining file extensions and checking directory listings have been added.
@luxass luxass force-pushed the feat/align-store-files-edp branch from a874554 to 3ef4be8 Compare January 11, 2026 12:04
@luxass luxass marked this pull request as ready for review January 11, 2026 12:06
Copilot AI review requested due to automatic review settings January 11, 2026 12:06
@luxass luxass merged commit ef98d58 into main Jan 11, 2026
18 of 21 checks passed
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@luxass luxass deleted the feat/align-store-files-edp branch January 11, 2026 12:06
@github-actions github-actions bot removed pkg: cli Changes related to the CLI package. pkg: ucd-store Changes related to the UCD Store package. pkg: fs-bridge Changes related to the FS Bridge package. pkg: test-utils Changes related to the test-utils package. labels Jan 11, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request refactors file handling logic by extracting common functionality from the wildcard and ucd-store routes into shared utility functions. This reduces code duplication and improves maintainability.

Changes:

  • Extracted file and directory response handling logic into shared utility functions in apps/api/src/lib/files.ts
  • Removed duplicated code from both route handlers ($wildcard.ts and files.ts)
  • Cleaned up console logging statements and eslint-disable directives

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
apps/api/src/lib/files.ts Added new utility functions: buildDirectoryHeaders, buildFileHeaders, handleFileResponse, handleDirectoryResponse, determineFileExtension, isHtmlFile, and isDirectoryListing to centralize file handling logic
apps/api/src/routes/v1_files/$wildcard.ts Removed duplicated helper functions and replaced with calls to shared utilities; removed unused Entry type import
apps/api/src/ucd-store/routes/files.ts Replaced inline file handling logic with shared utility function calls; removed route-specific console logging

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

export async function handleFileResponse(
c: any,
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter c has type any which bypasses type checking. Consider using Context<HonoEnv> imported from "hono" for better type safety.

Copilot uses AI. Check for mistakes.
}

export function handleDirectoryResponse(
c: any,
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter c has type any which bypasses type checking. Consider using Context<HonoEnv> imported from "hono" for better type safety.

Copilot uses AI. Check for mistakes.
Comment on lines +184 to +197
console.log(`[file-handler]: HEAD request, calculated size: ${actualSize}`);
return c.newResponse(null, 200, headers);
}

const headers: Record<string, string> = {
"Content-Type": contentType,
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "file",
};

const cd = response.headers.get("Content-Disposition");
if (cd) headers["Content-Disposition"] = cd;

console.log(`[file-handler]: binary file, streaming without buffering`);
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log messages now use a generic [file-handler] prefix instead of route-specific prefixes like [v1_files] or [ucd-store]. This makes it harder to trace which route generated the log entry. Consider either passing a logger prefix/context as a parameter to these functions, or using the route-specific logging before calling these shared handlers.

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +226
export function buildDirectoryHeaders(
files: Entry[],
baseHeaders: Record<string, string>,
): Record<string, string> {
return {
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "directory",
[UCD_STAT_CHILDREN_HEADER]: `${files.length}`,
[UCD_STAT_CHILDREN_FILES_HEADER]: `${files.filter((f) => f.type === "file").length}`,
[UCD_STAT_CHILDREN_DIRS_HEADER]: `${files.filter((f) => f.type === "directory").length}`,
};
}

export function buildFileHeaders(
contentType: string,
baseHeaders: Record<string, string>,
response: Response,
actualContentLength: number,
): Record<string, string> {
const headers: Record<string, string> = {
"Content-Type": contentType,
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "file",
[UCD_STAT_SIZE_HEADER]: `${actualContentLength}`,
"Content-Length": `${actualContentLength}`,
};

const cd = response.headers.get("Content-Disposition");
if (cd) headers["Content-Disposition"] = cd;

return headers;
}

export interface FileResponseOptions {
contentType: string;
baseHeaders: Record<string, string>;
response: Response;
isHeadRequest: boolean;
}

export async function handleFileResponse(
c: any,
options: FileResponseOptions,
): Promise<Response> {
const { contentType, baseHeaders, response, isHeadRequest } = options;

if (isHeadRequest) {
const blob = await response.blob();
const actualSize = blob.size;
const headers = buildFileHeaders(contentType, baseHeaders, response, actualSize);
console.log(`[file-handler]: HEAD request, calculated size: ${actualSize}`);
return c.newResponse(null, 200, headers);
}

const headers: Record<string, string> = {
"Content-Type": contentType,
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "file",
};

const cd = response.headers.get("Content-Disposition");
if (cd) headers["Content-Disposition"] = cd;

console.log(`[file-handler]: binary file, streaming without buffering`);

return c.newResponse(response.body, 200, headers);
}

export interface DirectoryResponseOptions {
files: Entry[];
baseHeaders: Record<string, string>;
}

export function handleDirectoryResponse(
c: any,
options: DirectoryResponseOptions,
): Response {
const { files, baseHeaders } = options;
const headers = buildDirectoryHeaders(files, baseHeaders);
return c.json(files, 200, headers);
}

export function determineFileExtension(leaf: string): string {
return leaf.includes(".") ? leaf.split(".").pop()!.toLowerCase() : "";
}

export function isHtmlFile(extName: string): boolean {
return HTML_EXTENSIONS.includes(`.${extName}`);
}

export function isDirectoryListing(contentType: string, extName: string): boolean {
return contentType.includes("text/html") && !isHtmlFile(extName);
}
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly extracted functions handleFileResponse, handleDirectoryResponse, determineFileExtension, isHtmlFile, isDirectoryListing, buildDirectoryHeaders, and buildFileHeaders lack test coverage. Consider adding unit tests for these functions to ensure they behave correctly in isolation, especially for edge cases like empty file extensions, different content types, and header handling.

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +214
export function buildDirectoryHeaders(
files: Entry[],
baseHeaders: Record<string, string>,
): Record<string, string> {
return {
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "directory",
[UCD_STAT_CHILDREN_HEADER]: `${files.length}`,
[UCD_STAT_CHILDREN_FILES_HEADER]: `${files.filter((f) => f.type === "file").length}`,
[UCD_STAT_CHILDREN_DIRS_HEADER]: `${files.filter((f) => f.type === "directory").length}`,
};
}

export function buildFileHeaders(
contentType: string,
baseHeaders: Record<string, string>,
response: Response,
actualContentLength: number,
): Record<string, string> {
const headers: Record<string, string> = {
"Content-Type": contentType,
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "file",
[UCD_STAT_SIZE_HEADER]: `${actualContentLength}`,
"Content-Length": `${actualContentLength}`,
};

const cd = response.headers.get("Content-Disposition");
if (cd) headers["Content-Disposition"] = cd;

return headers;
}

export interface FileResponseOptions {
contentType: string;
baseHeaders: Record<string, string>;
response: Response;
isHeadRequest: boolean;
}

export async function handleFileResponse(
c: any,
options: FileResponseOptions,
): Promise<Response> {
const { contentType, baseHeaders, response, isHeadRequest } = options;

if (isHeadRequest) {
const blob = await response.blob();
const actualSize = blob.size;
const headers = buildFileHeaders(contentType, baseHeaders, response, actualSize);
console.log(`[file-handler]: HEAD request, calculated size: ${actualSize}`);
return c.newResponse(null, 200, headers);
}

const headers: Record<string, string> = {
"Content-Type": contentType,
...baseHeaders,
[UCD_STAT_TYPE_HEADER]: "file",
};

const cd = response.headers.get("Content-Disposition");
if (cd) headers["Content-Disposition"] = cd;

console.log(`[file-handler]: binary file, streaming without buffering`);

return c.newResponse(response.body, 200, headers);
}

export interface DirectoryResponseOptions {
files: Entry[];
baseHeaders: Record<string, string>;
}

export function handleDirectoryResponse(
c: any,
options: DirectoryResponseOptions,
): Response {
const { files, baseHeaders } = options;
const headers = buildDirectoryHeaders(files, baseHeaders);
return c.json(files, 200, headers);
}
Copy link

Copilot AI Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added utility functions lack documentation. Consider adding JSDoc comments to describe their purpose, parameters, return values, and usage examples, especially for handleFileResponse, handleDirectoryResponse, buildDirectoryHeaders, and buildFileHeaders which are public exports.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apps: api Changes related to the API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant