/ utils / billing.ts
billing.ts
 1  import {
 2    getAnthropicApiKey,
 3    getAuthTokenSource,
 4    getSubscriptionType,
 5    isClaudeAISubscriber,
 6  } from './auth.js'
 7  import { getGlobalConfig } from './config.js'
 8  import { isEnvTruthy } from './envUtils.js'
 9  
10  export function hasConsoleBillingAccess(): boolean {
11    // Check if cost reporting is disabled via environment variable
12    if (isEnvTruthy(process.env.DISABLE_COST_WARNINGS)) {
13      return false
14    }
15  
16    const isSubscriber = isClaudeAISubscriber()
17  
18    // This might be wrong if user is signed into Max but also using an API key, but
19    // we already show a warning on launch in that case
20    if (isSubscriber) return false
21  
22    // Check if user has any form of authentication
23    const authSource = getAuthTokenSource()
24    const hasApiKey = getAnthropicApiKey() !== null
25  
26    // If user has no authentication at all (logged out), don't show costs
27    if (!authSource.hasToken && !hasApiKey) {
28      return false
29    }
30  
31    const config = getGlobalConfig()
32    const orgRole = config.oauthAccount?.organizationRole
33    const workspaceRole = config.oauthAccount?.workspaceRole
34  
35    if (!orgRole || !workspaceRole) {
36      return false // hide cost for grandfathered users who have not re-authed since we've added roles
37    }
38  
39    // Users have billing access if they are admins or billing roles at either workspace or organization level
40    return (
41      ['admin', 'billing'].includes(orgRole) ||
42      ['workspace_admin', 'workspace_billing'].includes(workspaceRole)
43    )
44  }
45  
46  // Mock billing access for /mock-limits testing (set by mockRateLimits.ts)
47  let mockBillingAccessOverride: boolean | null = null
48  
49  export function setMockBillingAccessOverride(value: boolean | null): void {
50    mockBillingAccessOverride = value
51  }
52  
53  export function hasClaudeAiBillingAccess(): boolean {
54    // Check for mock billing access first (for /mock-limits testing)
55    if (mockBillingAccessOverride !== null) {
56      return mockBillingAccessOverride
57    }
58  
59    if (!isClaudeAISubscriber()) {
60      return false
61    }
62  
63    const subscriptionType = getSubscriptionType()
64  
65    // Consumer plans (Max/Pro) - individual users always have billing access
66    if (subscriptionType === 'max' || subscriptionType === 'pro') {
67      return true
68    }
69  
70    // Team/Enterprise - check for admin or billing roles
71    const config = getGlobalConfig()
72    const orgRole = config.oauthAccount?.organizationRole
73  
74    return (
75      !!orgRole &&
76      ['admin', 'billing', 'owner', 'primary_owner'].includes(orgRole)
77    )
78  }