spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / mods / telemetry / hooks / telemetry-of / telemetry-of.ts
74 lines · 2.1 KBRaw
1import type { Telemetry } from '../../types'
2import Entries from '../entries'
3import { isAnalyticsOff } from '../is-analytics-off'
4import type { TelemetryDeps } from '../telemetry-deps'
5
6/**
7 * Builds `$.telemetry`: `log` and `mark` check the entry, read the environment
8 * and authorize afresh, build the first-party row and POST it to the ingest.
9 *
10 * One POST per call, rows one after another, nothing kept between them: a
11 * session that has moved to a third-party provider or a gateway, or turned
12 * analytics off, sends nothing more; no credential or a refusal rejects.
13 *
14 * @param deps the calls on the nouns beneath
15 * @returns the `$.telemetry` interface, `log` and `mark`
16 */
17export function telemetryOf(deps: TelemetryDeps): Telemetry {
18 let queue: Promise<unknown> = Promise.resolve()
19
20 async function post(
21 fields: Entries.Fields,
22 method: Entries.Method,
23 ): Promise<void> {
24 const environment = await deps.environment()
25
26 if (isAnalyticsOff(environment)) {
27 return
28 }
29
30 const body = Entries.batchOf(fields, {
31 sessionId: await deps.id(),
32 model: await deps.model(),
33 userType: environment.userType === 'ant' ? 'ant' : 'external',
34 })
35
36 const auth = await deps.authorize()
37
38 if (!auth) {
39 throw Entries.refusal(
40 'this session has no first-party credential to authorize',
41 method,
42 )
43 }
44
45 const response = await deps.fetch(Entries.INGEST_URL, {
46 method: 'POST',
47 headers: {
48 'Content-Type': 'application/json',
49 'x-service-name': 'claude-code',
50 },
51 auth: auth.handle,
52 body,
53 })
54
55 if (!response.ok) {
56 throw Entries.refusal(`the ingest answered ${response.status}`, method)
57 }
58 }
59
60 function queued(
61 fields: Entries.Fields,
62 method: Entries.Method,
63 ): Promise<void> {
64 const turn = queue.then(() => post(fields, method))
65 queue = turn.catch(() => undefined)
66
67 return turn
68 }
69
70 return {
71 log: async entry => queued(Entries.checkedFields(entry), 'log'),
72 mark: async entry => queued(Entries.checkedMark(entry), 'mark'),
73 }
74}