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
| 1 | import Entries from '../entries' |
| 2 | import { isAnalyticsOff } from '../is-analytics-off' |
| 3 | import type { TelemetryDeps } from '../telemetry-deps' |
| 4 | import type TelemetryTypes from '../telemetry-types' |
| 5 | |
| 6 | /** |
| 7 | * Builds `$.telemetry`: `log` and `mark` check the entry, authorize once, build |
| 8 | * the first-party row and POST it to the ingest. |
| 9 | * |
| 10 | * One POST per call, none batched, one attempt; a session with no credential to |
| 11 | * authorize, or an ingest that refuses, rejects the caller's promise. A failed |
| 12 | * authorize or environment read is not memoized, so a later call retries it. |
| 13 | * |
| 14 | * @param deps the calls on the nouns beneath |
| 15 | * @returns the `$.telemetry` interface, `log` and `mark`, each authorizing once |
| 16 | * (memoized) before it posts |
| 17 | */ |
| 18 | export function telemetryOf(deps: TelemetryDeps): TelemetryTypes.Telemetry { |
| 19 | let held: ReturnType<TelemetryDeps['authorize']> | undefined |
| 20 | let read: ReturnType<TelemetryDeps['environment']> | undefined |
| 21 | |
| 22 | async function post( |
| 23 | fields: Entries.Fields, |
| 24 | method: TelemetryTypes.Method, |
| 25 | ): Promise<void> { |
| 26 | read ??= deps.environment().catch((error: unknown) => { |
| 27 | read = undefined |
| 28 | |
| 29 | throw error |
| 30 | }) |
| 31 | const environment = await read |
| 32 | |
| 33 | if (isAnalyticsOff(environment)) { |
| 34 | return |
| 35 | } |
| 36 | |
| 37 | if (!held) { |
| 38 | held = deps.authorize().catch((error: unknown) => { |
| 39 | held = undefined |
| 40 | |
| 41 | throw error |
| 42 | }) |
| 43 | } |
| 44 | |
| 45 | const auth = await held |
| 46 | |
| 47 | if (!auth) { |
| 48 | held = undefined |
| 49 | |
| 50 | throw Entries.refusal( |
| 51 | 'this session has no first-party credential to authorize', |
| 52 | method, |
| 53 | ) |
| 54 | } |
| 55 | |
| 56 | const body = Entries.batchOf(fields, { |
| 57 | sessionId: await deps.id(), |
| 58 | model: await deps.model(), |
| 59 | userType: environment.userType === 'ant' ? 'ant' : 'external', |
| 60 | }) |
| 61 | const response = await deps.fetch(Entries.INGEST_URL, { |
| 62 | method: 'POST', |
| 63 | headers: { |
| 64 | 'Content-Type': 'application/json', |
| 65 | 'x-service-name': 'claude-code', |
| 66 | }, |
| 67 | auth: auth.handle, |
| 68 | body, |
| 69 | }) |
| 70 | |
| 71 | if (!response.ok) { |
| 72 | throw Entries.refusal(`the ingest answered ${response.status}`, method) |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | return { |
| 77 | log: async entry => post(Entries.checkedFields(entry), 'log'), |
| 78 | mark: async entry => post(Entries.checkedMark(entry), 'mark'), |
| 79 | } |
| 80 | } |