Skip to content

Conversation

@Dexploarer
Copy link
Owner

@Dexploarer Dexploarer commented Nov 27, 2025

This app will be decommissioned on Dec 1st. Please remove this app and install Qodo Git.

PR Type

Bug fix


Description

  • Fix CORS callback to return boolean instead of array per Elysia spec

  • Remove trailing slashes from API base URLs to prevent double-slash paths

  • Add origin validation logging for debugging CORS rejections

  • Format code with consistent quote style and semicolons


Diagram Walkthrough

flowchart LR
  A["CORS Request"] -->|"Check origin header"| B["Validate against allowed origins"]
  B -->|"Return boolean"| C["Elysia CORS Plugin"]
  D["API Base URL"] -->|"Remove trailing slash"| E["Prevent double-slash URLs"]
  E -->|"Construct request URL"| F["apiFetch utility"]
Loading

File Walkthrough

Relevant files
Bug fix
api-elysia.ts
Fix CORS callback to return boolean                                           

apps/core/server/api-elysia.ts

  • Changed CORS origin callback to return boolean instead of array
  • Extract incoming origin from request headers
  • Allow requests without origin header for same-origin/non-browser
    clients
  • Add detailed logging for rejected CORS requests with origin and
    allowed list
  • Validate incoming origin against allowed origins list before returning
+27/-5   
api-client.ts
Strip trailing slash from API base URL                                     

apps/core/src/lib/api-client.ts

  • Remove trailing slash from API base URL to prevent double-slash URLs
  • Store raw base URL and strip trailing slash if present
  • Improve debug logging formatting with proper line breaks
+10/-3   
api.ts
Remove trailing slash and format code                                       

apps/core/src/utils/api.ts

  • Remove trailing slash from API base URL in getApiBaseUrl function
  • Convert single quotes to double quotes for consistency
  • Add semicolons throughout for consistent code style
  • Improve code formatting with proper line breaks and indentation
+50/-40 

The managed version of the open source project PR-Agent is sunsetting on the 1st December 2025. The commercial version of this project will remain available and free to use as a hosted service. Install Qodo.

Summary by CodeRabbit

  • Bug Fixes

    • Stricter CORS origin validation with clearer warnings for missing or unauthorized origins
    • Normalized API base URL handling to prevent malformed URLs in development
  • New Features

    • Added a unified API fetch utility with timeout, retry, header normalization, and robust URL handling
  • Refactor

    • Improved API client internals for more consistent request construction and logging

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

…URLs

The VITE_API_URL env var can have a trailing slash which causes
double-slash URLs like //api/users/me when paths start with /.
This was causing requests to fail or go to incorrect endpoints.

Fixes both api.ts (apiFetch utility) and api-client.ts (Eden Treaty client).
The CORS origin callback was incorrectly returning an array of allowed
origins. According to Elysia CORS plugin documentation, the callback must
return a boolean indicating if the request's origin is allowed.

Changes:
- Get incoming origin from request.headers.get("origin")
- Compare against allowed origins list
- Return true/false (boolean) instead of string[]
- Add logging for rejected origins to aid debugging
- Allow requests without origin header (same-origin/non-browser)

This fixes CORS preflight failures where no Access-Control-Allow-Origin
header was being returned.
@coderabbitai
Copy link

coderabbitai bot commented Nov 27, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: fixing network errors related to user fetch by addressing CORS and API base URL issues across three core files.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50642f6 and 1ed10cd.

📒 Files selected for processing (1)
  • apps/core/server/api-elysia.ts (2 hunks)

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Dexploarer, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on enhancing the robustness and reliability of network communication within the application. It addresses potential network errors, particularly those related to user data fetching, by refining the server's Cross-Origin Resource Sharing (CORS) mechanism and standardizing the client-side API URL construction. These changes aim to ensure that API requests are correctly routed, authorized, and free from common URL-related issues.

Highlights

  • CORS Origin Handling Enhancement: The server-side CORS configuration has been updated to explicitly validate incoming request origins. It now correctly handles requests without an 'Origin' header (treating them as same-origin) and provides detailed logging for any unauthorized cross-origin requests, improving security and debuggability.
  • API Base URL Normalization: Logic has been introduced in both the API client and utility functions to ensure that API base URLs do not end with a trailing slash. This prevents the creation of malformed URLs (e.g., //api/users/me) which could lead to network errors when fetching resources.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Comment on lines 252 to 266
.use(securityHeaders)
.use(
cors({
origin: (request) => {
origin: ({ request }) => {
// Get the incoming origin from the request
const incomingOrigin = request.headers.get("origin");

// No origin header means same-origin request or non-browser client
if (!incomingOrigin) {
return true;
}

// Build allowed origins list
const allowedOrigins: string[] = [];

Choose a reason for hiding this comment

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

Security/Logic Issue:
The allowed origins list is rebuilt for every request, and the check for allowed origins uses strict equality (allowedOrigins.includes(incomingOrigin)). This may not account for subdomains or protocol variations, potentially causing legitimate requests to be rejected. Consider using a more flexible matching strategy, such as pattern matching or regular expressions, to allow for subdomains or protocol differences if required.

Recommended Solution:
Replace strict equality with a more robust check, for example:

const isAllowed = allowedOrigins.some(origin => incomingOrigin === origin || incomingOrigin.endsWith('.' + origin));

Or use a library for CORS origin matching if complex rules are needed.

Comment on lines 288 to 294
if (allowedOrigins.length === 0) {
logger.warn(
{ context: "cors" },
"No CORS origins configured - rejecting cross-origin requests",
{ context: "cors", origin: incomingOrigin },
"No CORS origins configured - rejecting cross-origin request",
);
return false;
}

Choose a reason for hiding this comment

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

Error Handling/UX Issue:
When no allowed origins are configured in production, the code logs a warning and returns false, but does not provide a clear error response to the client. This could lead to silent failures for cross-origin requests.

Recommended Solution:
Consider returning a more informative error response or status code to the client when CORS is misconfigured, to aid debugging and improve developer experience. For example, you could throw an error or return a custom message indicating that CORS is not configured.

signal: signal ?? controller.signal
})
return response
signal: signal ?? controller.signal,

Choose a reason for hiding this comment

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

Potential Timeout Bypass Due to Signal Precedence

The code uses signal: signal ?? controller.signal, which means if a caller provides a signal, the internal timeout logic using controller.signal will be ignored. This can result in requests not being aborted after the specified timeout, potentially causing resource leaks or hanging requests.

Recommended Solution:
Consider always using the internal controller.signal for timeout, and if an external signal is provided, listen for its abort event and propagate it to the controller:

if (signal) {
  signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });
}

Then always pass controller.signal to fetch.

Comment on lines +51 to 68
const headers: Record<string, string> = {};

if (rest.headers) {
if (rest.headers instanceof Headers) {
// Headers object - iterate over entries
rest.headers.forEach((value, key) => {
headers[key] = value
})
headers[key] = value;
});
} else if (Array.isArray(rest.headers)) {
// Array of [key, value] tuples
rest.headers.forEach(([key, value]) => {
headers[key] = value
})
headers[key] = value;
});
} else {
// Plain object
Object.assign(headers, rest.headers)
Object.assign(headers, rest.headers);
}
}

Choose a reason for hiding this comment

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

Header Key Case Sensitivity and Overwrite Risk

The header merging logic does not normalize header keys to a consistent case, which can result in duplicate headers (e.g., both 'Authorization' and 'authorization') or missed overwrites. This can lead to security issues if the intended header is not set or is overridden unexpectedly.

Recommended Solution:
Normalize all header keys to a consistent case (e.g., lowercase) when merging, and check for the presence of the authorization header in a case-insensitive manner:

const normalizedHeaders = Object.fromEntries(
  Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v])
);

Then check for 'authorization' only.

@codiumai-pr-agent-free
Copy link
Contributor

codiumai-pr-agent-free bot commented Nov 27, 2025

This app will be decommissioned on Dec 1st. Please remove this app and install Qodo Git.

PR Compliance Guide 🔍

(Compliance updated until commit 1ed10cd)

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit 72df026
Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

The managed version of the open source project PR-Agent is sunsetting on the 1st December 2025. The commercial version of this project will remain available and free to use as a hosted service. Install Qodo.

@greptile-apps
Copy link

greptile-apps bot commented Nov 27, 2025

Greptile Overview

Greptile Summary

This PR fixes network errors affecting user authentication by addressing two critical issues. First, it corrects the CORS origin callback in the Elysia server to return boolean values instead of arrays, which was preventing legitimate cross-origin requests from being processed. Second, it removes trailing slashes from API base URLs across the frontend to prevent malformed double-slash paths (like //api/users/me) that would cause request failures. The changes also add detailed CORS logging for debugging and apply consistent code formatting throughout the affected files. These fixes address the root cause of user fetch errors by ensuring proper URL construction and CORS validation in the Asset-Forge platform's client-server communication layer.

Important Files Changed

Filename Score Overview
apps/core/server/api-elysia.ts 5/5 Fixed CORS callback to return boolean instead of array per Elysia spec and added origin validation logging
apps/core/src/lib/api-client.ts 5/5 Removed trailing slashes from API base URLs to prevent double-slash URL construction
apps/core/src/utils/api.ts 4/5 Applied URL normalization and consistent code formatting with double quotes and semicolons

Confidence score: 5/5

  • This PR is safe to merge with minimal risk as it addresses clear bug fixes for network connectivity issues
  • Score reflects straightforward bug fixes with well-defined problems (malformed URLs and incorrect CORS return types) that have clear solutions
  • No files require special attention - all changes are defensive improvements to URL handling and CORS validation

Sequence Diagram

sequenceDiagram
    participant User
    participant Frontend
    participant ElysiaCORS as "Elysia CORS Plugin"
    participant APIClient as "API Client"
    participant Server as "Elysia Server"

    User->>Frontend: "Triggers API request"
    Frontend->>APIClient: "Make API call"
    
    Note over APIClient: Remove trailing slash from base URL
    APIClient->>APIClient: "Strip trailing '/' to prevent double-slash URLs"
    
    APIClient->>ElysiaCORS: "Send request with Origin header"
    ElysiaCORS->>ElysiaCORS: "Extract origin from request headers"
    
    alt No origin header
        ElysiaCORS->>ElysiaCORS: "Allow same-origin/non-browser clients"
        ElysiaCORS->>Server: "Forward request (allowed)"
    else Origin header present
        ElysiaCORS->>ElysiaCORS: "Build allowed origins list"
        ElysiaCORS->>ElysiaCORS: "Check if origin is in allowed list"
        
        alt Origin allowed
            ElysiaCORS->>Server: "Forward request (allowed)"
        else Origin rejected
            ElysiaCORS->>ElysiaCORS: "Log rejection with origin and allowed list"
            ElysiaCORS->>APIClient: "Return CORS error (boolean false)"
        end
    end
    
    Server->>APIClient: "Return API response"
    APIClient->>Frontend: "Return formatted response"
    Frontend->>User: "Display result"
Loading

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.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@codiumai-pr-agent-free
Copy link
Contributor

codiumai-pr-agent-free bot commented Nov 27, 2025

PR Code Suggestions ✨

This app will be decommissioned on Dec 1st. Please remove this app and install Qodo Git.

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix potential double-slash in URLs
Suggestion Impact:The commit directly implemented the suggested code change to prevent double slashes when combining a base URL with a path that starts with a slash. The implementation extracts the base URL to a variable and uses conditional logic to properly join the base URL and input path.

code diff:

+  const baseUrl = getApiBaseUrl();
   const url =
     input.startsWith("http://") || input.startsWith("https://")
       ? input
-      : `${getApiBaseUrl()}${input.startsWith("/") ? input : `/${input}`}`;
+      : baseUrl && !input.startsWith("/")
+        ? `${baseUrl}/${input}`
+        : `${baseUrl}${input}`;

Refactor the URL construction logic to prevent creating double slashes when
combining a base URL (e.g., /api) with a path that starts with a slash (e.g.,
/users/me).

apps/core/src/utils/api.ts [33-36]

+const baseUrl = getApiBaseUrl();
 const url =
   input.startsWith("http://") || input.startsWith("https://")
     ? input
-    : `${getApiBaseUrl()}${input.startsWith("/") ? input : `/${input}`}`;
+    : baseUrl && !input.startsWith("/")
+      ? `${baseUrl}/${input}`
+      : `${baseUrl}${input}`;

[Suggestion processed]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a valid bug where combining a base URL from getApiBaseUrl() (which now removes trailing slashes) and a path starting with a slash can create a URL with double slashes (//), which is a critical issue to fix.

Medium
Prevent potential null value errors

Add a redundant null check for incomingOrigin before calling .includes() to make
the code more robust against future refactoring errors.

apps/core/server/api-elysia.ts [296-297]

 // Check if incoming origin is in allowed list
-const isAllowed = allowedOrigins.includes(incomingOrigin);
+const isAllowed = !!incomingOrigin && allowedOrigins.includes(incomingOrigin);

[Suggestion processed]

Suggestion importance[1-10]: 3

__

Why: The suggestion correctly identifies that incomingOrigin can be null, but the existing code already handles this case correctly with an early return. The proposed change is redundant and only serves as a defense against a hypothetical future refactoring error, offering a minor improvement in robustness.

Low
  • Update

The managed version of the open source project PR-Agent is sunsetting on the 1st December 2025. The commercial version of this project will remain available and free to use as a hosted service. Install Qodo.

@codiumai-pr-agent-free
Copy link
Contributor

codiumai-pr-agent-free bot commented Nov 27, 2025

CI Feedback 🧐

(Feedback updated until commit 72df026)

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: E2E Tests (Playwright) (firefox)

Failed stage: Run E2E tests [❌]

Failure summary:

The action failed because the specified project "firefox" was not found when running Playwright
tests. The command bunx playwright test --project=firefox failed because "firefox" is not a valid
project name. The available projects are: "desktop-1920", "desktop-1440", "tablet-portrait",
"tablet-landscape", "mobile-375", "mobile-414", "mobile-360".

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

510:  �[35menv�[39m: "development"
511:  [08:16:20 UTC] �[32mINFO�[39m: �[36m[Migrations] Running migrations...�[39m
512:  �[35menv�[39m: "development"
513:  [Migrations] ✓ Migrations completed successfully
514:  [08:16:21 UTC] �[32mINFO�[39m: �[36m[Migrations] ✓ Migrations completed successfully�[39m
515:  �[35menv�[39m: "development"
516:  ##[group]Run bunx playwright test --project=firefox
517:  �[36;1mbunx playwright test --project=firefox�[0m
518:  shell: /usr/bin/bash -e {0}
519:  env:
520:  BUN_VERSION: 1.3.2
521:  NODE_VERSION: 22.12.0
522:  DATABASE_URL: ***localhost:5432/asset_forge_test
523:  CI: true
524:  ##[endgroup]
525:  Error: Project(s) "firefox" not found. Available projects: "desktop-1920", "desktop-1440", "tablet-portrait", "tablet-landscape", "mobile-375", "mobile-414", "mobile-360"
526:  at filterProjects (/home/runner/work/hyper-forge/hyper-forge/node_modules/playwright/lib/runner/projectUtils.js:80:11)
527:  at runTests (/home/runner/work/hyper-forge/hyper-forge/node_modules/playwright/lib/program.js:217:42)
528:  at i.<anonymous> (/home/runner/work/hyper-forge/hyper-forge/node_modules/playwright/lib/program.js:71:7)
529:  ##[error]Process completed with exit code 1.
530:  ##[group]Run actions/upload-artifact@v4

Comment on lines +255 to +262
origin: ({ request }) => {
// Get the incoming origin from the request
const incomingOrigin = request.headers.get("origin");

// No origin header means same-origin request or non-browser client
if (!incomingOrigin) {
return true;
}
Copy link

Choose a reason for hiding this comment

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

Bug: The @elysiajs/cors origin callback incorrectly destructures ({ request }) instead of receiving the full Context object.
Severity: CRITICAL | Confidence: High

🔍 Detailed Analysis

The origin callback for @elysiajs/cors is incorrectly destructuring ({ request }) from its parameter. The callback expects a full Context object, not an object with a top-level request property. This causes request to be undefined, leading to a TypeError: Cannot read property 'headers' of undefined when request.headers.get("origin") is called, which will crash the server when processing CORS requests.

💡 Suggested Fix

Change the origin callback signature from ({ request }) => { ... } to (context) => { ... } and access the request via context.request.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/core/server/api-elysia.ts#L255-L262

Potential issue: The `origin` callback for `@elysiajs/cors` is incorrectly destructuring
`({ request })` from its parameter. The callback expects a full `Context` object, not an
object with a top-level `request` property. This causes `request` to be `undefined`,
leading to a `TypeError: Cannot read property 'headers' of undefined` when
`request.headers.get("origin")` is called, which will crash the server when processing
CORS requests.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 3979100

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces several improvements to fix a network error, primarily by enhancing the CORS handling on the server and making client-side URL construction more robust. The changes to the CORS logic add better logging and more explicit handling of different request types, which is a great improvement for security and debuggability. On the client side, removing trailing slashes from base URLs prevents potential issues with double slashes. I've identified one high-severity issue in the new CORS implementation where a mismatch in trailing slashes between the browser's Origin header and configured environment variables could lead to legitimate requests being blocked. My review includes a suggestion to address this.


return allowedOrigins;
// Check if incoming origin is in allowed list
const isAllowed = allowedOrigins.includes(incomingOrigin);
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The current check allowedOrigins.includes(incomingOrigin) is sensitive to trailing slashes. The Origin header from browsers typically does not include a trailing slash (e.g., https://example.com), but an origin configured in env.FRONTEND_URL or env.CORS_ALLOWED_ORIGINS might have one (e.g., https://example.com/). This discrepancy will cause the .includes() check to fail, incorrectly blocking valid cross-origin requests.

To make this check more robust, you should account for the potential trailing slash on the allowed origins during comparison.

        const isAllowed = allowedOrigins.some(allowedOrigin => allowedOrigin === incomingOrigin || (allowedOrigin.endsWith('/') && allowedOrigin.slice(0, -1) === incomingOrigin));

Co-authored-by: codiumai-pr-agent-free[bot] <138128286+codiumai-pr-agent-free[bot]@users.noreply.github.com>
Comment on lines +296 to +297
// Check if incoming origin is in allowed list
const isAllowed = allowedOrigins.includes(incomingOrigin);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: Prevent potential null value errors

Suggested change
// Check if incoming origin is in allowed list
const isAllowed = allowedOrigins.includes(incomingOrigin);
// Check if incoming origin is in allowed list
const isAllowed = !!incomingOrigin && allowedOrigins.includes(incomingOrigin);

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/core/src/lib/api-client.ts (2)

196-228: Naming conflict: Two apiFetch functions with different signatures.

This apiFetch returns { data, error } and auto-parses JSON, while apps/core/src/utils/api.ts exports an apiFetch that returns Promise<Response> with retry/timeout support. Both are public exports with the same name but incompatible contracts.

Consider:

  1. Rename one (e.g., apiFetchJson here vs apiFetchRaw in utils), or
  2. Consolidate into a single implementation with optional response handling

203-205: Redundant conditional: both branches are identical.

The ternary condition checks if API_BASE_URL starts with http, but both branches execute the same code. Simplify to remove the unnecessary conditional.

-    const url = API_BASE_URL.startsWith("http")
-      ? `${API_BASE_URL}${endpointPath}` // Absolute URL
-      : `${API_BASE_URL}${endpointPath}`; // Relative URL (Vite proxy handles it)
+    const url = `${API_BASE_URL}${endpointPath}`;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 257f9f7 and 72df026.

📒 Files selected for processing (3)
  • apps/core/server/api-elysia.ts (2 hunks)
  • apps/core/src/lib/api-client.ts (1 hunks)
  • apps/core/src/utils/api.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use bun <file> instead of node <file> in the Asset-Forge project
Use const over let, never use var
Use template literals for strings instead of string concatenation

Files:

  • apps/core/server/api-elysia.ts
  • apps/core/src/lib/api-client.ts
  • apps/core/src/utils/api.ts
apps/core/server/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

apps/core/server/**/*.ts: Research with Deepwiki before adding new endpoints in Elysia
Define API types in service file with TypeBox validation in Elysia endpoints
Implement business logic in service class for API endpoints
Create route handler with TypeBox validation for API endpoints
Add Swagger documentation to new API endpoints
Follow REST conventions for API endpoints

Files:

  • apps/core/server/api-elysia.ts
**/*.{ts,tsx,js,jsx,json,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Use 2-space indentation for all code

Files:

  • apps/core/server/api-elysia.ts
  • apps/core/src/lib/api-client.ts
  • apps/core/src/utils/api.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript strict mode everywhere
No any or unknown types in TypeScript code
Use explicit return types on public methods in TypeScript

Files:

  • apps/core/server/api-elysia.ts
  • apps/core/src/lib/api-client.ts
  • apps/core/src/utils/api.ts
🧬 Code graph analysis (1)
apps/core/src/utils/api.ts (2)
apps/core/src/lib/api-client.ts (1)
  • apiFetch (196-228)
apps/core/__tests__/helpers/auth.ts (1)
  • hasAuthHeader (126-129)
🪛 GitHub Actions: Test Suite
apps/core/server/api-elysia.ts

[error] 255-255: TS2339: Property 'request' does not exist on type 'Request'.

🔇 Additional comments (5)
apps/core/src/lib/api-client.ts (1)

23-29: LGTM! Good fix for trailing slash normalization.

This correctly prevents double-slash URLs (e.g., //api/users/me) by stripping trailing slashes from the base URL before concatenation.

apps/core/server/api-elysia.ts (2)

264-311: LGTM! CORS origin validation logic is well-structured.

Good implementation with:

  • Dynamic allowed origins from environment configuration
  • Development mode localhost fallbacks
  • Clear warning logs for debugging unauthorized origins
  • Correct early return for same-origin/non-browser requests

The logic is sound once the callback signature issue (above) is fixed.


255-262: The review comment is incorrect. The CORS origin callback signature is correct.

According to the official @elysiajs/cors documentation, the origin callback receives a Context object that should be destructured. The pattern origin: ({ request }) => { ... } is the correct and documented approach. The review comment's claim that this causes a TS2339 error is false, and the proposed "fix" would actually break the code.

The current code at lines 255-262 properly destructures the Context object to access the request property, which is exactly how the library is designed to be used.

apps/core/src/utils/api.ts (2)

19-22: LGTM! Consistent trailing slash normalization.

This mirrors the fix in api-client.ts, ensuring consistent URL handling across both API utilities.


24-104: Well-implemented fetch wrapper with proper timeout and retry handling.

Good patterns:

  • AbortController for request timeouts with proper cleanup in finally
  • Case-insensitive auth header check (lines 73-74)
  • Flexible header normalization supporting Headers, arrays, and plain objects
  • Clean retry integration with retryWithBackoff

Browser Origin headers never include trailing slashes, but environment
variables (FRONTEND_URL, CORS_ALLOWED_ORIGINS) might be configured with
them. This mismatch would cause legitimate requests to be rejected.

Added normalizeOrigin() helper to strip trailing slashes from configured
origins before comparison with the incoming request origin.
@Dexploarer Dexploarer merged commit 78507ad into main Nov 27, 2025
1 of 6 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
apps/core/src/utils/api.ts (2)

82-86: Timeout bypass when external signal is provided.

When the caller provides a signal, the internal timeout controller is bypassed due to signal ?? controller.signal. The request will not be aborted after timeoutMs, potentially causing hanging requests.

The previous review suggested combining both signals. Consider aborting the internal controller when the external signal aborts:

+    if (signal) {
+      signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });
+    }
+
     const response = await fetch(url, {
       ...rest,
       headers,
-      signal: signal ?? controller.signal,
+      signal: controller.signal,
     });

76-80: Partial fix for header case sensitivity.

The case-insensitive check for Authorization prevents duplicate auth headers from the token store. However, the broader header normalization suggested in a previous review (normalizing all header keys to consistent case) was not implemented. This is acceptable for now since the auth header is the critical case.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72df026 and 50642f6.

📒 Files selected for processing (1)
  • apps/core/src/utils/api.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use bun <file> instead of node <file> in the Asset-Forge project
Use const over let, never use var
Use template literals for strings instead of string concatenation

Files:

  • apps/core/src/utils/api.ts
**/*.{ts,tsx,js,jsx,json,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Use 2-space indentation for all code

Files:

  • apps/core/src/utils/api.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript strict mode everywhere
No any or unknown types in TypeScript code
Use explicit return types on public methods in TypeScript

Files:

  • apps/core/src/utils/api.ts
🧬 Code graph analysis (1)
apps/core/src/utils/api.ts (2)
apps/core/src/lib/api-client.ts (1)
  • apiFetch (196-228)
apps/core/__tests__/helpers/auth.ts (1)
  • hasAuthHeader (126-129)
🔇 Additional comments (4)
apps/core/src/utils/api.ts (4)

1-7: LGTM!

Imports and interface definition are clean. The RequestOptions extension of RequestInit properly types the additional options.


12-22: LGTM!

The trailing slash normalization correctly prevents double-slash URLs. The environment-based logic for dev vs. production is well-documented.


24-40: LGTM!

The URL construction logic correctly handles absolute URLs, relative paths with and without leading slashes, and avoids double-slash issues when combined with the normalized base URL.


93-107: LGTM!

The retry logic correctly handles both boolean and object configurations, returns the response on success, and throws an appropriate error after retries are exhausted.

Comment on lines +24 to +27
export async function apiFetch(
input: string,
init: RequestOptions = {},
): Promise<Response> {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find api-client.ts file
echo "=== Searching for api-client.ts ==="
find . -name "api-client.ts" -type f 2>/dev/null | head -20

# Find the specific file under review
echo -e "\n=== Searching for the api.ts file under review ==="
find . -path "*/core/src/utils/api.ts" -type f 2>/dev/null

Repository: Dexploarer/hyper-forge

Length of output: 216


🏁 Script executed:

#!/bin/bash
# Read the api-client.ts file to check for apiFetch export
echo "=== Content of api-client.ts ==="
cat -n ./apps/core/src/lib/api-client.ts

echo -e "\n=== Content of api.ts (first 50 lines) ==="
head -50 ./apps/core/src/utils/api.ts

# Search for imports of apiFetch across the codebase
echo -e "\n=== Imports of apiFetch in codebase ==="
rg -n "import.*apiFetch|from.*api" --type=ts --type=tsx -A1 -B1 | head -100

Repository: Dexploarer/hyper-forge

Length of output: 11868


🏁 Script executed:

#!/bin/bash
# Search for imports of apiFetch - fix the file type filter
echo "=== Imports of apiFetch in codebase ==="
rg -n "import.*apiFetch" --type=ts -B2 -A2

echo -e "\n=== Files that import from api-client ==="
rg -n "from.*['\"].*api-client" --type=ts

echo -e "\n=== Files that import from utils/api ==="
rg -n "from.*['\"].*utils/api" --type=ts

Repository: Dexploarer/hyper-forge

Length of output: 11685


Two apiFetch exports with incompatible signatures create real import confusion.

Verified: PromptService.ts and CDNAdminService.ts import apiFetch from @/lib/api-client (returns Promise<{ data: T | null; error: string | null }>), while 19+ other files import from @/utils/api (returns Promise<Response>). This inconsistency means developers could easily pick the wrong import. Consider renaming one function to clarify intent—e.g., apiFetchWrapped or apiFetchRaw.

🤖 Prompt for AI Agents
In apps/core/src/utils/api.ts around lines 24 to 27, there is an apiFetch
exported that returns Promise<Response>, which conflicts with another apiFetch
exported from @/lib/api-client (returns Promise<{ data: T | null; error: string
| null }>) causing import confusion; rename this function to a clear, distinct
name (for example apiFetchRaw or fetchResponse) and update its export and all
internal imports/usages accordingly to preserve the original Response-returning
behavior, leaving the wrapped api-client export untouched so callers explicitly
choose raw Response vs wrapped data/error form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants