Skip to content

feat: add proxy support for network-restricted environments - #144

Closed
evergood2025 wants to merge 1 commit into
ccusage:mainfrom
evergood2025:feat/add-proxy-support
Closed

feat: add proxy support for network-restricted environments#144
evergood2025 wants to merge 1 commit into
ccusage:mainfrom
evergood2025:feat/add-proxy-support

Conversation

@evergood2025

@evergood2025 evergood2025 commented Jun 22, 2025

Copy link
Copy Markdown

Summary

This PR adds automatic proxy support to resolve network connectivity issues in environments with restricted access to GitHub (such as mainland China).

Changes Made

  • Automatic proxy detection: Checks for http_proxy, https_proxy, HTTP_PROXY, and HTTPS_PROXY environment variables
  • Undici ProxyAgent integration: Uses undici's ProxyAgent for fetch requests when proxy is configured
  • Build-time support: Extends proxy support to macro execution during build process
  • Debug logging: Adds informative logging when proxy is detected and used

Files Modified

  • src/pricing-fetcher.ts: Added proxy detection and ProxyAgent usage in ensurePricingLoaded()
  • src/_macro.ts: Added proxy support for build-time pricing data fetching

Problem Solved

Fixes the issue where npx ccusage@latest fails in network-restricted environments due to inability to fetch pricing data from GitHub raw content. Users previously had to use --offline mode or clone the repository locally to work around this limitation.

Testing

Tested successfully with:

  • Local development environment with proxy
  • Published test package [email protected] via npx with proxy configuration
  • Verified proxy detection and usage logging

Usage

No changes required for existing users. The tool will automatically detect and use proxy settings from environment variables when available.

Example:

export https_proxy=http://127.0.0.1:8888
npx ccusage@latest daily  # Now works in restricted environments

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

Summary by CodeRabbit

  • New Features

    • Added support for routing pricing data fetch requests through a proxy if proxy environment variables are configured.
  • Chores

    • Improved logging to indicate when a proxy is being used for fetch operations.

@coderabbitai

coderabbitai Bot commented Jun 22, 2025

Copy link
Copy Markdown

Walkthrough

Proxy support was added to the fetch operations in both the prefetchClaudePricing function and the PricingFetcher class. The code now checks for proxy-related environment variables and, if present, uses the ProxyAgent from the undici library to route requests through the specified proxy.

Changes

File(s) Change Summary
src/_macro.ts Updated prefetchClaudePricing to detect proxy environment variables and use ProxyAgent for fetch requests.
src/pricing-fetcher.ts Modified fetch logic in PricingFetcher to support proxy usage via environment variables and ProxyAgent.

Poem

In tunnels of code, a proxy appears,
Fetching through gateways, it conquers our fears.
With agents undici, the routes rearrange,
Now pricing requests can easily change.
Through proxies we hop, with network delight—
The fetchers are ready, the future is bright!
🐇🌐

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Summary of Changes

Hello @yonghao2011, 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 primarily introduces robust proxy support to the ccusage tool, enabling it to function correctly in network-restricted environments by automatically detecting and utilizing proxy settings for fetching essential pricing data. This resolves issues where users in certain regions could not fetch data without workarounds. Additionally, it includes a substantial cleanup and simplification of the project's package.json file.

Highlights

  • Network Proxy Support: Implemented automatic proxy detection using http_proxy, https_proxy, HTTP_PROXY, and HTTPS_PROXY environment variables to enable ccusage to fetch pricing data in network-restricted environments.
  • Undici ProxyAgent Integration: Integrated undici's ProxyAgent for all fetch requests that require proxying, ensuring proper routing of network traffic for external data retrieval.
  • Build-Time Proxy Support: Extended proxy functionality to the build process, specifically for pre-fetching Claude pricing data via src/_macro.ts, resolving potential build failures in restricted networks.
  • Debugging & Observability: Added informative logging to src/pricing-fetcher.ts to indicate when a proxy is detected and being used, aiding in troubleshooting network connectivity issues.
  • Project Configuration Cleanup: Performed a significant cleanup and reduction of the package.json file, removing various development-related scripts, dependencies, and configurations, streamlining the project setup.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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 is currently in preview and 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 to provide feedback.

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.

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

Copy link
Copy Markdown
Contributor

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 adds proxy support for fetching pricing data, which enhances the tool for users in network-restricted environments. The implementation uses environment variables and undici's ProxyAgent. The package.json file has been unintentionally stripped of essential development configuration, which needs to be reverted. The proxy detection and setup logic is duplicated across two files, which should be refactored into a shared utility function.

Comment thread package.json Outdated
Comment thread src/_macro.ts
Comment on lines +19 to +27
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.HTTP_PROXY;

const fetchOptions: RequestInit = {};
if (proxyUrl) {
// For Node.js with undici, we need to use ProxyAgent
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The block of code for detecting the proxy URL and configuring fetchOptions is duplicated in src/pricing-fetcher.ts. To improve maintainability, extract this logic into a shared utility function.

Comment thread src/pricing-fetcher.ts
Comment on lines +67 to +76
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.HTTP_PROXY;

const fetchOptions: RequestInit = {};
if (proxyUrl) {
// For Node.js with undici, we need to use ProxyAgent
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
logger.info(`Using proxy: ${proxyUrl}`);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The proxy configuration logic is also present in src/_macro.ts. To avoid code duplication, extract this into a reusable helper function that both files can import and use.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/pricing-fetcher.ts (1)

66-78: Consider adding tests for proxy functionality.

The proxy support functionality is not covered by the existing test cases. Consider adding tests to verify:

  • Proxy detection from environment variables
  • ProxyAgent usage when proxy is configured
  • Fallback behavior when no proxy is configured

Example test structure:

describe('proxy support', () => {
  it('should use proxy when environment variable is set', async () => {
    process.env.https_proxy = 'http://proxy.example.com:8080';
    // Test implementation
  });
  
  it('should work without proxy when no environment variable is set', async () => {
    delete process.env.https_proxy;
    // Test implementation
  });
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bffbdc8 and 35306217bc62ddc5c64663b0d79c3429c51bb144.

📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/_macro.ts (1 hunks)
  • src/pricing-fetcher.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/_macro.ts (1)
src/_consts.ts (1)
  • LITELLM_PRICING_URL (7-8)
src/pricing-fetcher.ts (2)
src/logger.ts (1)
  • logger (18-18)
src/_consts.ts (1)
  • LITELLM_PRICING_URL (7-8)
🔇 Additional comments (1)
package.json (1)

1-34: LGTM! Package.json simplified appropriately for published package.

The removal of all development configurations (workspaces, scripts, devDependencies, etc.) is appropriate for a published npm package, focusing solely on essential package metadata. This simplification aligns well with the proxy support feature and improves package clarity.

Comment thread src/_macro.ts
Comment on lines +18 to +27
// Check for proxy configuration and create fetch options
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.HTTP_PROXY;

const fetchOptions: RequestInit = {};
if (proxyUrl) {
// For Node.js with undici, we need to use ProxyAgent
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Proxy implementation is correct but consider refactoring for reusability.

The proxy detection and ProxyAgent setup logic is implemented correctly. However, this exact same code pattern is duplicated in src/pricing-fetcher.ts (lines 66-76), violating the DRY principle.

Consider extracting this logic into a shared utility function:

// src/proxy-utils.ts
export async function createFetchOptionsWithProxy(): Promise<RequestInit> {
  const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY || 
                   process.env.http_proxy || process.env.HTTP_PROXY;
  
  const fetchOptions: RequestInit = {};
  if (proxyUrl) {
    const { ProxyAgent } = await import('undici');
    (fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
  }
  return fetchOptions;
}

Then use it in both files:

const fetchOptions = await createFetchOptionsWithProxy();
🤖 Prompt for AI Agents
In src/_macro.ts lines 18 to 27, the proxy detection and ProxyAgent setup code
is duplicated in src/pricing-fetcher.ts lines 66 to 76. To fix this, extract
this logic into a new shared async utility function (e.g.,
createFetchOptionsWithProxy) in a new file like src/proxy-utils.ts that returns
the fetch options with proxy if set. Then replace the duplicated code in both
src/_macro.ts and src/pricing-fetcher.ts with calls to this new utility function
to adhere to the DRY principle.

Comment thread src/_macro.ts
Comment on lines +25 to +26
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for the dynamic import.

The dynamic import of ProxyAgent should include error handling in case the undici package is not available. Currently, if the import fails, it will throw an unhandled error.

-    const { ProxyAgent } = await import('undici');
-    (fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
+    try {
+      const { ProxyAgent } = await import('undici');
+      (fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
+    } catch (error) {
+      throw new Error(`Failed to load proxy support. Please install undici: ${error.message}`);
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
try {
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
} catch (error) {
throw new Error(`Failed to load proxy support. Please install undici: ${error.message}`);
}
🤖 Prompt for AI Agents
In src/_macro.ts around lines 25 to 26, the dynamic import of ProxyAgent from
'undici' lacks error handling, which can cause unhandled exceptions if the
package is unavailable. Wrap the import statement in a try-catch block to catch
any errors during import, and handle the error gracefully, such as logging the
error or providing a fallback, to prevent the application from crashing.

Comment thread src/pricing-fetcher.ts
Comment on lines +73 to +74
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for the dynamic import (same as in _macro.ts).

The same error handling concern applies here as mentioned for src/_macro.ts. The dynamic import should be wrapped in try-catch to provide a meaningful error message if undici is not available.

🤖 Prompt for AI Agents
In src/pricing-fetcher.ts around lines 73 to 74, the dynamic import of 'undici'
lacks error handling. Wrap the import statement in a try-catch block to catch
any errors if the module is unavailable, and log or throw a meaningful error
message to aid debugging, similar to the approach used in src/_macro.ts.

Comment thread src/pricing-fetcher.ts
Comment on lines +66 to +76
// Check for proxy configuration and create fetch options
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.HTTP_PROXY;

const fetchOptions: RequestInit = {};
if (proxyUrl) {
// For Node.js with undici, we need to use ProxyAgent
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
logger.info(`Using proxy: ${proxyUrl}`);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Address code duplication and security concern with proxy URL logging.

This proxy implementation duplicates the exact same logic from src/_macro.ts (lines 18-27). As mentioned in the previous file review, this should be extracted into a shared utility function.

Additionally, logging the proxy URL could expose sensitive information if the URL contains credentials (e.g., http://username:[email protected]:8080).

Apply this diff to avoid logging sensitive proxy credentials:

-      logger.info(`Using proxy: ${proxyUrl}`);
+      const proxyHost = new URL(proxyUrl).host;
+      logger.info(`Using proxy: ${proxyHost}`);

And consider the same utility function approach suggested for src/_macro.ts to eliminate duplication.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Check for proxy configuration and create fetch options
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.HTTP_PROXY;
const fetchOptions: RequestInit = {};
if (proxyUrl) {
// For Node.js with undici, we need to use ProxyAgent
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
logger.info(`Using proxy: ${proxyUrl}`);
}
// Check for proxy configuration and create fetch options
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.HTTP_PROXY;
const fetchOptions: RequestInit = {};
if (proxyUrl) {
// For Node.js with undici, we need to use ProxyAgent
const { ProxyAgent } = await import('undici');
(fetchOptions as any).dispatcher = new ProxyAgent(proxyUrl);
const proxyHost = new URL(proxyUrl).host;
logger.info(`Using proxy: ${proxyHost}`);
}
🤖 Prompt for AI Agents
In src/pricing-fetcher.ts around lines 66 to 76, the proxy URL detection and
fetch options setup duplicates logic from src/_macro.ts and logs the full proxy
URL, risking exposure of sensitive credentials. Refactor by extracting the proxy
URL retrieval and fetch options creation into a shared utility function used by
both files. Also, modify the logging to avoid printing the full proxy URL;
instead, log a sanitized version that omits credentials or just indicate that a
proxy is used without revealing the URL.

- Add automatic proxy detection for http_proxy/https_proxy environment variables
- Use undici ProxyAgent for fetch requests when proxy is configured
- Support proxy for both runtime pricing fetches and build-time macro execution
- Fix issue where npx ccusage@latest fails in regions with GitHub access restrictions
- Add proxy usage logging for better debugging

Fixes network connectivity issues in environments like mainland China where
direct access to GitHub raw content may be blocked or slow.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/_macro.ts (1)

18-27: Code duplication and missing error handling already identified.

The proxy detection logic and missing error handling for the dynamic import have already been flagged in previous reviews. Please refer to the existing comments about extracting this to a shared utility function and adding try-catch around the undici import.

src/pricing-fetcher.ts (1)

66-76: Code duplication, security concern, and missing error handling already identified.

The proxy detection logic duplication, security issue with logging the full proxy URL (which may contain credentials), and missing error handling for the dynamic import have already been flagged in previous reviews. Please refer to the existing comments about these issues.

🧹 Nitpick comments (2)
src/_macro.ts (1)

19-20: Fix formatting and indentation issues.

The code has several formatting problems that should be addressed:

  • Mixed spaces and tabs for indentation
  • Trailing spaces on lines
  • Inconsistent operator placement

Apply this diff to fix the formatting issues:

-	const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY || 
-	                 process.env.http_proxy || process.env.HTTP_PROXY;
+	const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY
+		|| process.env.http_proxy || process.env.HTTP_PROXY;
src/pricing-fetcher.ts (1)

67-68: Fix formatting and indentation issues.

Similar to the other file, this code has formatting problems:

  • Mixed spaces and tabs for indentation
  • Trailing spaces on lines
  • Inconsistent operator placement

Apply this diff to fix the formatting issues:

-			const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY || 
-			                 process.env.http_proxy || process.env.HTTP_PROXY;
+			const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY
+				|| process.env.http_proxy || process.env.HTTP_PROXY;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35306217bc62ddc5c64663b0d79c3429c51bb144 and 913d975.

📒 Files selected for processing (2)
  • src/_macro.ts (1 hunks)
  • src/pricing-fetcher.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/pricing-fetcher.ts (2)
src/logger.ts (1)
  • logger (18-18)
src/_consts.ts (1)
  • LITELLM_PRICING_URL (7-8)
🪛 ESLint
src/_macro.ts

[error] 19-20: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 19-19: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 19-19: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 19-19: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 19-19: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 19-19: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 19-19: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 19-19: '||' should be placed at the beginning of the line.

(style/operator-linebreak)


[error] 19-19: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 20-20: Expected indentation of 2 tabs

(style/indent-binary-ops)


[error] 20-20: Mixed spaces and tabs.

(style/no-mixed-spaces-and-tabs)


[error] 20-20: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 20-20: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 20-20: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 20-20: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 20-20: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 21-21: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 23-23: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 25-25: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 26-26: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 26-26: Unsafe member access .dispatcher on an any value.

(ts/no-unsafe-member-access)


[error] 26-26: Unsafe construction of a(n) any typed value.

(ts/no-unsafe-call)


[error] 28-28: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 29-29: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 29-29: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)

src/pricing-fetcher.ts

[error] 65-65: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 67-68: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 67-67: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 67-67: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 67-67: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 67-67: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 67-67: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 67-67: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 67-67: '||' should be placed at the beginning of the line.

(style/operator-linebreak)


[error] 67-67: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 68-68: Expected indentation of 4 tabs

(style/indent-binary-ops)


[error] 68-68: Mixed spaces and tabs.

(style/no-mixed-spaces-and-tabs)


[error] 68-68: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 68-68: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 68-68: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 68-68: Unexpected use of the global variable 'process'. Use 'require("process")' instead.

(node/prefer-global/process)


[error] 68-68: Unsafe member access .env on an error typed value.

(ts/no-unsafe-member-access)


[error] 69-69: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 71-71: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 73-73: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 74-74: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 74-74: Unsafe member access .dispatcher on an any value.

(ts/no-unsafe-member-access)


[error] 74-74: Unsafe construction of a(n) any typed value.

(ts/no-unsafe-call)


[error] 75-75: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 75-75: Unsafe member access .info on an error typed value.

(ts/no-unsafe-member-access)


[error] 77-77: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 78-78: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 78-78: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)

@ryoppippi

Copy link
Copy Markdown
Member

we discuss it before.
--offline is not enough?

@evergood2025

evergood2025 commented Jun 22, 2025

Copy link
Copy Markdown
Author

we discuss it before. --offline is not enough?

Hi, I've tried adding the --offline parameter, but it doesn't work as expected. If my usage is incorrect, please let me know. I tested with my modified code (bunx ccusage-test) and it can successfully get the local proxy and use the proxy to access LiteLLM.

image

Problem: Node.js fetch() doesn't automatically read system proxy settings. Even when users set http_proxy/https_proxy environment variables, ccusage still attempts direct connections to the LiteLLM API, causing failures in corporate networks or proxy-required environments. This is particularly common in network-restricted regions like China.

My PR solution: Before making network requests, detect common proxy environment variables (http_proxy, https_proxy, etc.). If proxy configuration is detected, use undici's ProxyAgent to handle proxy connections, allowing fetch to access external services through the proxy. If no proxy is configured, maintain the original direct connection behavior, ensuring full backward compatibility.

The core issue is Node.js fetch()'s limitation - it doesn't automatically respect system proxy settings like other network tools (curl, browsers, etc.) do. My PR essentially fills this gap by adding the proxy support that fetch() should have had by default.

@ryoppippi

Copy link
Copy Markdown
Member

@yonghao2011 Thank you.
For us, including undici is huge. if the offline mode doesn't work, it must be a bug of offline mode!
I think we need to investigate the offline mode!

@ryoppippi

Copy link
Copy Markdown
Member

@yonghao2011 Also this is a good idea to use offline mode automatically if fetch fails.
What do you think?

@ryoppippi

Copy link
Copy Markdown
Member

which offline mode doesn't work

@ryoppippi

Copy link
Copy Markdown
Member

#169

Implemented auto-offline mode

@evergood2025

evergood2025 commented Jun 23, 2025

Copy link
Copy Markdown
Author

#169

Implemented auto-offline mode

Nice!
image

@ryoppippi

Copy link
Copy Markdown
Member

Is it enough? Or do we need to consider proxy feature?

@evergood2025

Copy link
Copy Markdown
Author

For network-restricted regions (like mainland China), the current solution will 100% fall back to cached/stale data. If proxy support is available, getting real-time data is naturally the better approach. Using undici is a solid choice worth considering, but the tool is definitely usable now as-is.

@ryoppippi

ryoppippi commented Jun 23, 2025

Copy link
Copy Markdown
Member

@yonghao2011 I'm really care about the bundle size actually. so how about adding a option to change the url.
or if you know some good api that is not blocked by GFW, let me know

@ryoppippi

ryoppippi commented Jun 23, 2025

Copy link
Copy Markdown
Member

@yonghao2011
This is my suggestion.
I try hono/proxy for this purpose. in my environment the bundle size is quite small.
if you try to use it and works fine, it must be great

@ryoppippi
ryoppippi force-pushed the main branch 2 times, most recently from 5f6191a to 8c2c97d Compare September 14, 2025 16:59
@evergood2025 evergood2025 closed this by deleting the head repository Dec 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants