File size: 1,869 Bytes
1f21206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
 * Proxy-side Claude Code billing attribution based on sub2api gateway behavior.
 * Reference: https://github.com/Wei-Shaw/sub2api
 * License: LGPL-3.0-or-later, Copyright (c) 2026 Wesley Liddick.
 */
import {
  CLAUDE_CODE_BILLING_HEADER_PREFIX,
  CLAUDE_CODE_COMPAT_VERSION,
  formatClaudeCodeBillingHeader,
} from '../../constants/claudeCodeCompatibility.js'
import { computeFingerprint } from '../../utils/fingerprint.js'
import type { AnthropicRequest } from './transform/types.js'

export function extractFirstUserText(body: AnthropicRequest): string {
  for (const message of body.messages) {
    if (message.role !== 'user') continue

    if (typeof message.content === 'string') {
      return message.content
    }

    const textBlock = message.content.find(block => block.type === 'text')
    return textBlock?.type === 'text' ? textBlock.text : ''
  }

  return ''
}

export function ensureClaudeCodeAttribution(body: AnthropicRequest): AnthropicRequest {
  if (hasBillingAttribution(body.system)) return body

  const fingerprint = computeFingerprint(extractFirstUserText(body), CLAUDE_CODE_COMPAT_VERSION)
  const billingBlock = {
    type: 'text' as const,
    text: formatClaudeCodeBillingHeader({
      fingerprint,
      entrypoint: process.env.CLAUDE_CODE_ENTRYPOINT ?? 'unknown',
    }),
  }

  return {
    ...body,
    system: typeof body.system === 'string'
      ? [billingBlock, { type: 'text', text: body.system }]
      : [billingBlock, ...(body.system ?? [])],
  }
}

function hasBillingAttribution(system: AnthropicRequest['system']): boolean {
  if (typeof system === 'string') {
    return system.startsWith(CLAUDE_CODE_BILLING_HEADER_PREFIX)
  }

  return Array.isArray(system) && system.some(block => (
    block?.type === 'text' && typeof block.text === 'string' && block.text.startsWith(CLAUDE_CODE_BILLING_HEADER_PREFIX)
  ))
}