@rawdash/connector-anthropic 0.27.0 → 0.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,31 +37,32 @@ Authenticates with an Anthropic organization admin API key (sk-ant-admin-). Admi
37
37
  - Endpoint: `GET /v1/organizations/usage_report/messages`
38
38
  - Unit: tokens
39
39
  - Granularity: daily
40
- - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`
40
+ - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`, `account_id`, `service_account_id`
41
41
  - Sample value is uncached_input_tokens. Cache-read and cache-creation token volumes are mirrored on their own metrics so a cache hit ratio can be computed at query time.
42
42
  - **`anthropic_output_tokens`** _(metric)_ - Daily output tokens generated by the Anthropic Messages API, grouped by model and workspace.
43
43
  - Endpoint: `GET /v1/organizations/usage_report/messages`
44
44
  - Unit: tokens
45
45
  - Granularity: daily
46
- - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`
46
+ - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`, `account_id`, `service_account_id`
47
47
  - Written alongside anthropic_input_tokens from the same usage_messages API call.
48
48
  - **`anthropic_cache_read_tokens`** _(metric)_ - Daily input tokens read from the prompt cache, grouped by model and workspace.
49
49
  - Endpoint: `GET /v1/organizations/usage_report/messages`
50
50
  - Unit: tokens
51
51
  - Granularity: daily
52
- - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`
52
+ - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`, `account_id`, `service_account_id`
53
53
  - Cache hits are charged at a fraction of the uncached rate, so this metric paired with anthropic_input_tokens gives the cache hit ratio.
54
54
  - **`anthropic_cache_creation_tokens`** _(metric)_ - Daily input tokens written into the prompt cache (sum of the 1h and 5m ephemeral caches), grouped by model and workspace.
55
55
  - Endpoint: `GET /v1/organizations/usage_report/messages`
56
56
  - Unit: tokens
57
57
  - Granularity: daily
58
- - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`
59
- - The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are mirrored in attributes for finer-grained widgets.
58
+ - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`, `account_id`, `service_account_id`
59
+ - Measures: `ephemeral_1h_input_tokens`, `ephemeral_5m_input_tokens`
60
+ - The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are declared measures for finer-grained widgets.
60
61
  - **`anthropic_web_search_requests`** _(metric)_ - Daily count of web-search tool requests executed server-side by Claude, grouped by model and workspace.
61
62
  - Endpoint: `GET /v1/organizations/usage_report/messages`
62
63
  - Unit: requests
63
64
  - Granularity: daily
64
- - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`
65
+ - Dimensions: `model`, `workspace_id`, `api_key_id`, `service_tier`, `context_window`, `inference_geo`, `account_id`, `service_account_id`
65
66
  - Sourced from server_tool_use.web_search_requests on each usage bucket. Zero rows are still written so a "no usage today" widget renders correctly.
66
67
  - **`anthropic_cost_usd`** _(metric)_ - Daily organization spend in USD, broken down by workspace and cost line item, pulled from the Anthropic Cost Report.
67
68
  - Endpoint: `GET /v1/organizations/cost_report`
package/dist/index.d.ts CHANGED
@@ -86,6 +86,12 @@ declare const anthropicResources: {
86
86
  }, {
87
87
  readonly name: "inference_geo";
88
88
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
89
+ }, {
90
+ readonly name: "account_id";
91
+ readonly description: "Account id the usage is attributed to (or null).";
92
+ }, {
93
+ readonly name: "service_account_id";
94
+ readonly description: "Service account id the usage is attributed to (or null).";
89
95
  }];
90
96
  readonly notes: "Sample value is uncached_input_tokens. Cache-read and cache-creation token volumes are mirrored on their own metrics so a cache hit ratio can be computed at query time.";
91
97
  readonly responses: {
@@ -143,6 +149,12 @@ declare const anthropicResources: {
143
149
  }, {
144
150
  readonly name: "inference_geo";
145
151
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
152
+ }, {
153
+ readonly name: "account_id";
154
+ readonly description: "Account id the usage is attributed to (or null).";
155
+ }, {
156
+ readonly name: "service_account_id";
157
+ readonly description: "Service account id the usage is attributed to (or null).";
146
158
  }];
147
159
  readonly notes: "Written alongside anthropic_input_tokens from the same usage_messages API call.";
148
160
  };
@@ -170,6 +182,12 @@ declare const anthropicResources: {
170
182
  }, {
171
183
  readonly name: "inference_geo";
172
184
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
185
+ }, {
186
+ readonly name: "account_id";
187
+ readonly description: "Account id the usage is attributed to (or null).";
188
+ }, {
189
+ readonly name: "service_account_id";
190
+ readonly description: "Service account id the usage is attributed to (or null).";
173
191
  }];
174
192
  readonly notes: "Cache hits are charged at a fraction of the uncached rate, so this metric paired with anthropic_input_tokens gives the cache hit ratio.";
175
193
  };
@@ -197,8 +215,21 @@ declare const anthropicResources: {
197
215
  }, {
198
216
  readonly name: "inference_geo";
199
217
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
218
+ }, {
219
+ readonly name: "account_id";
220
+ readonly description: "Account id the usage is attributed to (or null).";
221
+ }, {
222
+ readonly name: "service_account_id";
223
+ readonly description: "Service account id the usage is attributed to (or null).";
224
+ }];
225
+ readonly measures: [{
226
+ readonly name: "ephemeral_1h_input_tokens";
227
+ readonly description: "Input tokens written into the 1-hour ephemeral prompt cache (a component of the sample value).";
228
+ }, {
229
+ readonly name: "ephemeral_5m_input_tokens";
230
+ readonly description: "Input tokens written into the 5-minute ephemeral prompt cache (a component of the sample value).";
200
231
  }];
201
- readonly notes: "The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are mirrored in attributes for finer-grained widgets.";
232
+ readonly notes: "The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are declared measures for finer-grained widgets.";
202
233
  };
203
234
  readonly anthropic_web_search_requests: {
204
235
  readonly shape: "metric";
@@ -224,6 +255,12 @@ declare const anthropicResources: {
224
255
  }, {
225
256
  readonly name: "inference_geo";
226
257
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
258
+ }, {
259
+ readonly name: "account_id";
260
+ readonly description: "Account id the usage is attributed to (or null).";
261
+ }, {
262
+ readonly name: "service_account_id";
263
+ readonly description: "Service account id the usage is attributed to (or null).";
227
264
  }];
228
265
  readonly notes: "Sourced from server_tool_use.web_search_requests on each usage bucket. Zero rows are still written so a \"no usage today\" widget renders correctly.";
229
266
  };
@@ -299,6 +336,8 @@ declare const id = "anthropic";
299
336
  interface UsageWindow {
300
337
  startingAt: string;
301
338
  endingAt: string;
339
+ startMs: number;
340
+ endMs: number;
302
341
  }
303
342
  declare function getUsageWindow(options: SyncOptions, lookbackDays: number, now?: number): UsageWindow;
304
343
  declare function buildUsageSamples(buckets: readonly BucketPage<UsageResult>[]): {
@@ -336,6 +375,12 @@ declare class AnthropicConnector extends BaseConnector<AnthropicSettings, Anthro
336
375
  }, {
337
376
  readonly name: "inference_geo";
338
377
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
378
+ }, {
379
+ readonly name: "account_id";
380
+ readonly description: "Account id the usage is attributed to (or null).";
381
+ }, {
382
+ readonly name: "service_account_id";
383
+ readonly description: "Service account id the usage is attributed to (or null).";
339
384
  }];
340
385
  readonly notes: "Sample value is uncached_input_tokens. Cache-read and cache-creation token volumes are mirrored on their own metrics so a cache hit ratio can be computed at query time.";
341
386
  readonly responses: {
@@ -393,6 +438,12 @@ declare class AnthropicConnector extends BaseConnector<AnthropicSettings, Anthro
393
438
  }, {
394
439
  readonly name: "inference_geo";
395
440
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
441
+ }, {
442
+ readonly name: "account_id";
443
+ readonly description: "Account id the usage is attributed to (or null).";
444
+ }, {
445
+ readonly name: "service_account_id";
446
+ readonly description: "Service account id the usage is attributed to (or null).";
396
447
  }];
397
448
  readonly notes: "Written alongside anthropic_input_tokens from the same usage_messages API call.";
398
449
  };
@@ -420,6 +471,12 @@ declare class AnthropicConnector extends BaseConnector<AnthropicSettings, Anthro
420
471
  }, {
421
472
  readonly name: "inference_geo";
422
473
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
474
+ }, {
475
+ readonly name: "account_id";
476
+ readonly description: "Account id the usage is attributed to (or null).";
477
+ }, {
478
+ readonly name: "service_account_id";
479
+ readonly description: "Service account id the usage is attributed to (or null).";
423
480
  }];
424
481
  readonly notes: "Cache hits are charged at a fraction of the uncached rate, so this metric paired with anthropic_input_tokens gives the cache hit ratio.";
425
482
  };
@@ -447,8 +504,21 @@ declare class AnthropicConnector extends BaseConnector<AnthropicSettings, Anthro
447
504
  }, {
448
505
  readonly name: "inference_geo";
449
506
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
507
+ }, {
508
+ readonly name: "account_id";
509
+ readonly description: "Account id the usage is attributed to (or null).";
510
+ }, {
511
+ readonly name: "service_account_id";
512
+ readonly description: "Service account id the usage is attributed to (or null).";
513
+ }];
514
+ readonly measures: [{
515
+ readonly name: "ephemeral_1h_input_tokens";
516
+ readonly description: "Input tokens written into the 1-hour ephemeral prompt cache (a component of the sample value).";
517
+ }, {
518
+ readonly name: "ephemeral_5m_input_tokens";
519
+ readonly description: "Input tokens written into the 5-minute ephemeral prompt cache (a component of the sample value).";
450
520
  }];
451
- readonly notes: "The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are mirrored in attributes for finer-grained widgets.";
521
+ readonly notes: "The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are declared measures for finer-grained widgets.";
452
522
  };
453
523
  readonly anthropic_web_search_requests: {
454
524
  readonly shape: "metric";
@@ -474,6 +544,12 @@ declare class AnthropicConnector extends BaseConnector<AnthropicSettings, Anthro
474
544
  }, {
475
545
  readonly name: "inference_geo";
476
546
  readonly description: "Inference geo the request ran in (global, us, not_available), or null.";
547
+ }, {
548
+ readonly name: "account_id";
549
+ readonly description: "Account id the usage is attributed to (or null).";
550
+ }, {
551
+ readonly name: "service_account_id";
552
+ readonly description: "Service account id the usage is attributed to (or null).";
477
553
  }];
478
554
  readonly notes: "Sourced from server_tool_use.web_search_requests on each usage bucket. Zero rows are still written so a \"no usage today\" widget renders correctly.";
479
555
  };
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ import {
33
33
  defineConnectorDoc,
34
34
  defineResources,
35
35
  makeChunkedCursorGuard,
36
+ metricSample,
36
37
  schemasFromResources,
37
38
  selectActivePhases
38
39
  } from "@rawdash/core";
@@ -195,6 +196,14 @@ var USAGE_DIMENSIONS = [
195
196
  {
196
197
  name: "inference_geo",
197
198
  description: "Inference geo the request ran in (global, us, not_available), or null."
199
+ },
200
+ {
201
+ name: "account_id",
202
+ description: "Account id the usage is attributed to (or null)."
203
+ },
204
+ {
205
+ name: "service_account_id",
206
+ description: "Service account id the usage is attributed to (or null)."
198
207
  }
199
208
  ];
200
209
  var COST_DIMENSIONS = [
@@ -267,7 +276,17 @@ var anthropicResources = defineResources({
267
276
  unit: "tokens",
268
277
  granularity: "daily",
269
278
  dimensions: [...USAGE_DIMENSIONS],
270
- notes: "The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are mirrored in attributes for finer-grained widgets."
279
+ measures: [
280
+ {
281
+ name: "ephemeral_1h_input_tokens",
282
+ description: "Input tokens written into the 1-hour ephemeral prompt cache (a component of the sample value)."
283
+ },
284
+ {
285
+ name: "ephemeral_5m_input_tokens",
286
+ description: "Input tokens written into the 5-minute ephemeral prompt cache (a component of the sample value)."
287
+ }
288
+ ],
289
+ notes: "The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are declared measures for finer-grained widgets."
271
290
  },
272
291
  anthropic_web_search_requests: {
273
292
  shape: "metric",
@@ -315,7 +334,9 @@ function getUsageWindow(options, lookbackDays, now = Date.now()) {
315
334
  const startMs = endMs - days * MS_PER_DAY;
316
335
  return {
317
336
  startingAt: new Date(startMs).toISOString(),
318
- endingAt: new Date(endMs).toISOString()
337
+ endingAt: new Date(endMs).toISOString(),
338
+ startMs,
339
+ endMs
319
340
  };
320
341
  }
321
342
  function resourceToPhase(resource) {
@@ -365,40 +386,45 @@ function buildUsageSamples(buckets) {
365
386
  for (const row of bucket.results) {
366
387
  const common = usageDimensionAttributes(row);
367
388
  const cacheCreation = row.cache_creation;
368
- inputTokens.push({
369
- name: "anthropic_input_tokens",
370
- ts,
371
- value: row.uncached_input_tokens,
372
- attributes: { ...common }
373
- });
374
- outputTokens.push({
375
- name: "anthropic_output_tokens",
376
- ts,
377
- value: row.output_tokens,
378
- attributes: { ...common }
379
- });
380
- cacheReadTokens.push({
381
- name: "anthropic_cache_read_tokens",
382
- ts,
383
- value: row.cache_read_input_tokens,
384
- attributes: { ...common }
385
- });
386
- cacheCreationTokens.push({
387
- name: "anthropic_cache_creation_tokens",
388
- ts,
389
- value: cacheCreationTotal(row),
390
- attributes: {
391
- ...common,
392
- ephemeral_1h_input_tokens: cacheCreation?.ephemeral_1h_input_tokens ?? 0,
393
- ephemeral_5m_input_tokens: cacheCreation?.ephemeral_5m_input_tokens ?? 0
394
- }
395
- });
396
- webSearchRequests.push({
397
- name: "anthropic_web_search_requests",
398
- ts,
399
- value: row.server_tool_use?.web_search_requests ?? 0,
400
- attributes: { ...common }
401
- });
389
+ inputTokens.push(
390
+ metricSample(anthropicResources, "anthropic_input_tokens", {
391
+ ts,
392
+ value: row.uncached_input_tokens,
393
+ attributes: { ...common }
394
+ })
395
+ );
396
+ outputTokens.push(
397
+ metricSample(anthropicResources, "anthropic_output_tokens", {
398
+ ts,
399
+ value: row.output_tokens,
400
+ attributes: { ...common }
401
+ })
402
+ );
403
+ cacheReadTokens.push(
404
+ metricSample(anthropicResources, "anthropic_cache_read_tokens", {
405
+ ts,
406
+ value: row.cache_read_input_tokens,
407
+ attributes: { ...common }
408
+ })
409
+ );
410
+ cacheCreationTokens.push(
411
+ metricSample(anthropicResources, "anthropic_cache_creation_tokens", {
412
+ ts,
413
+ value: cacheCreationTotal(row),
414
+ attributes: {
415
+ ...common,
416
+ ephemeral_1h_input_tokens: cacheCreation?.ephemeral_1h_input_tokens ?? 0,
417
+ ephemeral_5m_input_tokens: cacheCreation?.ephemeral_5m_input_tokens ?? 0
418
+ }
419
+ })
420
+ );
421
+ webSearchRequests.push(
422
+ metricSample(anthropicResources, "anthropic_web_search_requests", {
423
+ ts,
424
+ value: row.server_tool_use?.web_search_requests ?? 0,
425
+ attributes: { ...common }
426
+ })
427
+ );
402
428
  }
403
429
  }
404
430
  return {
@@ -419,21 +445,22 @@ function buildCostSamples(buckets) {
419
445
  for (const row of bucket.results) {
420
446
  const rawAmount = Number.parseFloat(row.amount);
421
447
  const value = Number.isFinite(rawAmount) ? rawAmount / COST_AMOUNT_DIVISOR : 0;
422
- samples.push({
423
- name: "anthropic_cost_usd",
424
- ts,
425
- value,
426
- attributes: {
427
- workspace_id: nullableString(row.workspace_id),
428
- description: nullableString(row.description),
429
- cost_type: nullableString(row.cost_type),
430
- model: nullableString(row.model),
431
- token_type: nullableString(row.token_type),
432
- service_tier: nullableString(row.service_tier),
433
- context_window: nullableString(row.context_window),
434
- currency: row.currency
435
- }
436
- });
448
+ samples.push(
449
+ metricSample(anthropicResources, "anthropic_cost_usd", {
450
+ ts,
451
+ value,
452
+ attributes: {
453
+ workspace_id: nullableString(row.workspace_id),
454
+ description: nullableString(row.description),
455
+ cost_type: nullableString(row.cost_type),
456
+ model: nullableString(row.model),
457
+ token_type: nullableString(row.token_type),
458
+ service_tier: nullableString(row.service_tier),
459
+ context_window: nullableString(row.context_window),
460
+ currency: row.currency
461
+ }
462
+ })
463
+ );
437
464
  }
438
465
  }
439
466
  return samples;
@@ -551,7 +578,7 @@ var AnthropicConnector = class _AnthropicConnector extends BaseConnector {
551
578
  }
552
579
  pageUrl = nextUrl;
553
580
  }
554
- await this.writePhase(storage, phase, buckets);
581
+ await this.writePhase(storage, phase, buckets, window);
555
582
  this.logger.info("resource done", {
556
583
  resource: phase,
557
584
  pages: pageCount,
@@ -581,30 +608,39 @@ var AnthropicConnector = class _AnthropicConnector extends BaseConnector {
581
608
  );
582
609
  }
583
610
  }
584
- async writePhase(storage, phase, buckets) {
611
+ async writePhase(storage, phase, buckets, window) {
612
+ const replaceWindow = { start: window.startMs, end: window.endMs };
585
613
  switch (phase) {
586
614
  case "usage_messages": {
587
615
  const samples = buildUsageSamples(buckets);
588
616
  await storage.metrics(samples.inputTokens, {
589
- names: ["anthropic_input_tokens"]
617
+ names: ["anthropic_input_tokens"],
618
+ replaceWindow
590
619
  });
591
620
  await storage.metrics(samples.outputTokens, {
592
- names: ["anthropic_output_tokens"]
621
+ names: ["anthropic_output_tokens"],
622
+ replaceWindow
593
623
  });
594
624
  await storage.metrics(samples.cacheReadTokens, {
595
- names: ["anthropic_cache_read_tokens"]
625
+ names: ["anthropic_cache_read_tokens"],
626
+ replaceWindow
596
627
  });
597
628
  await storage.metrics(samples.cacheCreationTokens, {
598
- names: ["anthropic_cache_creation_tokens"]
629
+ names: ["anthropic_cache_creation_tokens"],
630
+ replaceWindow
599
631
  });
600
632
  await storage.metrics(samples.webSearchRequests, {
601
- names: ["anthropic_web_search_requests"]
633
+ names: ["anthropic_web_search_requests"],
634
+ replaceWindow
602
635
  });
603
636
  return;
604
637
  }
605
638
  case "cost_report": {
606
639
  const samples = buildCostSamples(buckets);
607
- await storage.metrics(samples, { names: ["anthropic_cost_usd"] });
640
+ await storage.metrics(samples, {
641
+ names: ["anthropic_cost_usd"],
642
+ replaceWindow
643
+ });
608
644
  return;
609
645
  }
610
646
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../connector-shared/src/errors.ts","../../../connector-shared/src/retry.ts","../../../connector-shared/src/version.ts","../../../connector-shared/src/request.ts","../../../connector-shared/src/rate-limit.ts","../../../connector-shared/src/map-concurrent.ts","../../../connector-shared/src/sanitize.ts","../../../connector-shared/src/epoch.ts","../../../connector-shared/src/pagination.ts","../../../connector-shared/src/logger.ts","../src/anthropic.ts","../src/index.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n\nexport function connectorUserAgent(connectorId: string): string {\n return `rawdash-connector-${connectorId}/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n}\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions,\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport interface StandardRateLimitPolicyConfig {\n remainingHeader: string;\n resetHeader: string;\n resetUnit: 's' | 'ms';\n resetFallbackMs?: number;\n}\n\nexport function standardRateLimitPolicy(\n config: StandardRateLimitPolicyConfig,\n): RateLimitPolicy {\n const { remainingHeader, resetHeader, resetUnit, resetFallbackMs } = config;\n const multiplier = resetUnit === 's' ? 1000 : 1;\n return {\n parse(h) {\n const remainingRaw = h.get(remainingHeader);\n if (remainingRaw === null || remainingRaw.trim() === '') {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n const resetRaw = h.get(resetHeader);\n if (resetRaw === null) {\n if (resetFallbackMs === undefined) {\n return null;\n }\n return {\n remaining,\n resetAt: new Date(Date.now() + resetFallbackMs),\n };\n }\n if (resetRaw.trim() === '') {\n return null;\n }\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n const resetMs = reset * multiplier;\n if (!Number.isFinite(resetMs)) {\n return null;\n }\n return { remaining, resetAt: new Date(resetMs) };\n },\n };\n}\n","export async function mapWithConcurrency<T, R>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n if (items.length === 0) {\n return results;\n }\n const normalized = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const limit = Math.max(1, Math.min(normalized, items.length));\n let next = 0;\n let failed = false;\n\n async function worker(): Promise<void> {\n while (!failed) {\n const i = next++;\n if (i >= items.length) {\n return;\n }\n try {\n results[i] = await fn(items[i]!, i);\n } catch (err) {\n failed = true;\n throw err;\n }\n }\n }\n\n const workers: Promise<void>[] = [];\n for (let w = 0; w < limit; w++) {\n workers.push(worker());\n }\n await Promise.all(workers);\n return results;\n}\n","export interface SanitizeAllowedUrlOptions {\n url: string | null;\n host: string;\n pathname: string;\n protocol?: 'https:' | 'http:';\n}\n\nexport function sanitizeAllowedUrl(\n options: SanitizeAllowedUrlOptions,\n): string | null {\n const { url, host, pathname, protocol = 'https:' } = options;\n if (url === null) {\n return null;\n }\n try {\n const u = new URL(url);\n if (u.protocol !== protocol || u.host !== host || u.pathname !== pathname) {\n return null;\n }\n return u.toString();\n } catch {\n return null;\n }\n}\n","export type EpochUnit = 'ms' | 's' | 'iso';\n\nexport function parseEpoch(\n value: number | string | null | undefined,\n unit: EpochUnit,\n): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n if (unit === 'iso') {\n if (typeof value !== 'string') {\n return null;\n }\n const ms = new Date(value).getTime();\n return Number.isFinite(ms) ? ms : null;\n }\n if (typeof value === 'string' && value.trim() === '') {\n return null;\n }\n const n = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(n)) {\n return null;\n }\n const result = unit === 's' ? n * 1000 : n;\n return Number.isFinite(result) ? result : null;\n}\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n options: { resource: string },\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request(\n {\n ...initial,\n url: next,\n },\n { resource: options.resource },\n );\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req, { resource: options.resource });\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req, { resource: options.resource });\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","export type LogFields = Record<string, unknown>;\n\nexport interface ConnectorLogger {\n info(event: string, fields?: LogFields): void;\n warn(event: string, fields?: LogFields): void;\n}\n\nexport interface ConnectorLoggerOptions {\n scope: string;\n}\n\nconst MAX_VALUE_LEN = 120;\n\nfunction truncate(s: string, max = MAX_VALUE_LEN): string {\n if (s.length <= max) {\n return s;\n }\n return `${s.slice(0, max - 1)}…`;\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (value === undefined) {\n return '';\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (typeof value === 'string') {\n const t = truncate(value);\n if (/[\\s\"=]/.test(t)) {\n return JSON.stringify(t);\n }\n return t;\n }\n if (typeof value === 'bigint') {\n return value.toString();\n }\n let json: string | undefined;\n try {\n json = JSON.stringify(value);\n } catch {\n json = undefined;\n }\n return truncate(json ?? String(value));\n}\n\nexport function formatLogFields(fields?: LogFields): string {\n if (!fields) {\n return '';\n }\n const parts: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (v === undefined) {\n continue;\n }\n parts.push(`${k}=${formatValue(v)}`);\n }\n return parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\nexport function formatLogLine(\n scope: string,\n event: string,\n fields?: LogFields,\n): string {\n return `[${scope}] ${event}${formatLogFields(fields)}`;\n}\n\nexport function createDefaultConnectorLogger(\n opts: ConnectorLoggerOptions,\n): ConnectorLogger {\n return {\n info(event, fields) {\n console.info(formatLogLine(opts.scope, event, fields));\n },\n warn(event, fields) {\n console.warn(formatLogLine(opts.scope, event, fields));\n },\n };\n}\n\nconst NOOP_LOGGER: ConnectorLogger = {\n info() {},\n warn() {},\n};\n\nexport function noopConnectorLogger(): ConnectorLogger {\n return NOOP_LOGGER;\n}\n","import {\n type HttpResponse,\n connectorUserAgent,\n parseEpoch,\n} from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ConnectorContext,\n type ConnectorDoc,\n type CredentialsSchema,\n type JSONValue,\n type MetricSample,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n defineConnectorDoc,\n defineResources,\n makeChunkedCursorGuard,\n schemasFromResources,\n selectActivePhases,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nconst ANTHROPIC_API_HOST = 'api.anthropic.com';\nconst ANTHROPIC_API_BASE = `https://${ANTHROPIC_API_HOST}`;\nconst ANTHROPIC_API_VERSION = '2023-06-01';\nconst USAGE_PAGE_LIMIT = 31;\nconst COSTS_PAGE_LIMIT = 31;\nconst MS_PER_DAY = 86_400_000;\nconst DEFAULT_LOOKBACK_DAYS = 30;\nconst INCREMENTAL_LOOKBACK_DAYS = 2;\n// Cost report `amount` is a decimal string in the lowest currency unit (cents\n// for USD): e.g. \"123.45\" represents $1.2345. Divide by 100 to get dollars.\nconst COST_AMOUNT_DIVISOR = 100;\n\nexport const configFields = defineConfigFields(\n z.object({\n adminApiKey: z.object({ $secret: z.string().min(1) }).meta({\n label: 'Admin API key',\n description:\n 'Anthropic organization admin API key (starts with sk-ant-admin-). Create one at console.anthropic.com -> Settings -> Admin keys. Regular API keys (sk-ant-api-) cannot read the Usage and Cost reports.',\n placeholder: 'ANTHROPIC_ADMIN_API_KEY',\n secret: true,\n }),\n workspaceIds: z.array(z.string().min(1)).nonempty().optional().meta({\n label: 'Workspace IDs (optional)',\n description:\n 'Restrict usage and cost queries to specific Anthropic workspace ids (wrkspc_...). Omit to aggregate every workspace the admin key can see.',\n }),\n resources: z\n .array(\n z.enum([\n 'anthropic_input_tokens',\n 'anthropic_output_tokens',\n 'anthropic_cache_read_tokens',\n 'anthropic_cache_creation_tokens',\n 'anthropic_web_search_requests',\n 'anthropic_cost_usd',\n ]),\n )\n .nonempty()\n .optional()\n .meta({\n label: 'Resources',\n description:\n 'Which Anthropic metric series to sync. Omit to sync all of them. The five usage metrics share one upstream call to the Messages Usage Report; enabling any one of them fetches the report and writes all five.',\n }),\n lookbackDays: z.number().int().positive().max(180).optional().meta({\n label: 'Backfill window (days)',\n description:\n 'How many days of usage history to fetch on a full sync. Defaults to 30. The Usage Report returns at most 31 buckets per page, so longer windows paginate.',\n placeholder: '30',\n }),\n }),\n);\n\nexport const doc: ConnectorDoc = defineConnectorDoc({\n displayName: 'Anthropic',\n category: 'engineering',\n brandColor: '#D97757',\n tagline:\n 'Track Anthropic spend, daily token usage across Claude models, cache hit volumes, and web-search tool requests from the Anthropic Admin API.',\n vendor: {\n name: 'Anthropic',\n domain: 'anthropic.com',\n apiDocs:\n 'https://docs.claude.com/en/api/admin-api/usage-cost/get-messages-usage-report',\n website: 'https://anthropic.com',\n },\n auth: {\n summary:\n 'Authenticates with an Anthropic organization admin API key (sk-ant-admin-). Admin keys are the only key class that can read the Usage and Cost reports; regular API keys return 403.',\n setup: [\n 'Open console.anthropic.com -> Settings -> Admin Keys and create a new admin key. Admin keys are organization-scoped, so create the key from the organization whose usage you want to read.',\n 'Store the key as a secret (e.g. ANTHROPIC_ADMIN_API_KEY).',\n 'Reference it from config as `adminApiKey: secret(\"ANTHROPIC_ADMIN_API_KEY\")`.',\n 'Optionally set `workspaceIds` to restrict the query to a subset of workspaces.',\n ],\n },\n rateLimit:\n 'The Admin API returns 429 with a Retry-After header on burst; the shared HTTP client honors it automatically. Daily syncs against the Usage and Cost reports are well below the per-organization Admin API budget.',\n limitations: [\n 'Only the organization Messages Usage Report and Cost Report endpoints are synced. Per-request logs and individual message bodies are not exposed by the Admin API.',\n 'All samples are bucketed daily (1d bucket_width). The Usage Report also supports hourly and per-minute granularity but those are not exposed here in v1.',\n 'The Cost Report only supports 1d bucket_width and reports cost in USD; non-USD billing currencies are not converted.',\n 'Admin API keys are required - regular sk-ant-api- keys do not have access to the organization Usage and Cost reports.',\n ],\n});\n\nconst PHASE_ORDER = ['usage_messages', 'cost_report'] as const;\n\ntype AnthropicPhase = (typeof PHASE_ORDER)[number];\n\nexport type AnthropicResource =\n | 'anthropic_input_tokens'\n | 'anthropic_output_tokens'\n | 'anthropic_cache_read_tokens'\n | 'anthropic_cache_creation_tokens'\n | 'anthropic_web_search_requests'\n | 'anthropic_cost_usd';\n\nconst isAnthropicSyncCursor = makeChunkedCursorGuard(PHASE_ORDER);\n\nconst RESOURCES_BY_PHASE: Record<AnthropicPhase, readonly AnthropicResource[]> =\n {\n usage_messages: [\n 'anthropic_input_tokens',\n 'anthropic_output_tokens',\n 'anthropic_cache_read_tokens',\n 'anthropic_cache_creation_tokens',\n 'anthropic_web_search_requests',\n ],\n cost_report: ['anthropic_cost_usd'],\n };\n\nconst PHASE_ENDPOINT_PATH: Record<AnthropicPhase, string> = {\n usage_messages: '/v1/organizations/usage_report/messages',\n cost_report: '/v1/organizations/cost_report',\n};\n\nconst usageCacheCreationSchema = z.object({\n ephemeral_1h_input_tokens: z.number().nonnegative().nullish(),\n ephemeral_5m_input_tokens: z.number().nonnegative().nullish(),\n});\n\nconst usageServerToolUseSchema = z.object({\n web_search_requests: z.number().int().nonnegative().nullish(),\n});\n\nconst usageResultSchema = z.object({\n account_id: z.string().nullish(),\n api_key_id: z.string().nullish(),\n cache_creation: usageCacheCreationSchema.nullish(),\n cache_read_input_tokens: z.number().nonnegative(),\n context_window: z.string().nullish(),\n inference_geo: z.string().nullish(),\n model: z.string().nullish(),\n output_tokens: z.number().nonnegative(),\n server_tool_use: usageServerToolUseSchema.nullish(),\n service_account_id: z.string().nullish(),\n service_tier: z.string().nullish(),\n uncached_input_tokens: z.number().nonnegative(),\n workspace_id: z.string().nullish(),\n});\n\nconst costResultSchema = z.object({\n amount: z.string(),\n context_window: z.string().nullish(),\n cost_type: z.string().nullish(),\n currency: z.string(),\n description: z.string().nullish(),\n inference_geo: z.string().nullish(),\n model: z.string().nullish(),\n service_tier: z.string().nullish(),\n token_type: z.string().nullish(),\n workspace_id: z.string().nullish(),\n});\n\nfunction bucketResponseSchema<T extends z.ZodTypeAny>(resultSchema: T) {\n return z.object({\n data: z.array(\n z.object({\n starting_at: z.string(),\n ending_at: z.string(),\n results: z.array(resultSchema),\n }),\n ),\n has_more: z.boolean(),\n next_page: z.string().nullish(),\n });\n}\n\nconst usageResponseSchema = bucketResponseSchema(usageResultSchema);\nconst costResponseSchema = bucketResponseSchema(costResultSchema);\n\ntype UsageResult = z.infer<typeof usageResultSchema>;\ntype CostResult = z.infer<typeof costResultSchema>;\n\ninterface BucketPage<TResult> {\n starting_at: string;\n ending_at: string;\n results: TResult[];\n}\n\ninterface PageResponse<TResult> {\n buckets: BucketPage<TResult>[];\n nextPage: string | null;\n}\n\nconst USAGE_DIMENSIONS = [\n {\n name: 'model',\n description: 'Claude model id reported by Anthropic (or null).',\n },\n {\n name: 'workspace_id',\n description:\n 'Anthropic workspace id the usage is attributed to (or null for the default workspace).',\n },\n {\n name: 'api_key_id',\n description: 'API key id the usage is attributed to (or null).',\n },\n {\n name: 'service_tier',\n description:\n 'Service tier the request ran under (standard, batch, priority, flex, etc.), or null.',\n },\n {\n name: 'context_window',\n description:\n 'Context window bucket the request used (0-200k or 200k-1M), or null.',\n },\n {\n name: 'inference_geo',\n description:\n 'Inference geo the request ran in (global, us, not_available), or null.',\n },\n] as const;\n\nconst COST_DIMENSIONS = [\n {\n name: 'workspace_id',\n description:\n 'Anthropic workspace id the cost is attributed to (or null for the default workspace).',\n },\n {\n name: 'description',\n description:\n 'Human-readable cost line item label (e.g. \"Claude Sonnet 4 Usage - Input Tokens\"), or null when ungrouped.',\n },\n {\n name: 'cost_type',\n description:\n 'Cost category (tokens, web_search, code_execution, session_usage), or null.',\n },\n {\n name: 'model',\n description:\n 'Claude model the cost is attributed to (or null for non-token costs).',\n },\n {\n name: 'token_type',\n description:\n 'Token category for token costs (uncached_input_tokens, output_tokens, cache_read_input_tokens, cache_creation.ephemeral_*_input_tokens), or null.',\n },\n {\n name: 'service_tier',\n description:\n 'Service tier the cost is attributed to (standard or batch), or null.',\n },\n {\n name: 'context_window',\n description:\n 'Context window the cost is attributed to (0-200k or 200k-1M), or null.',\n },\n {\n name: 'currency',\n description:\n 'Billing currency reported by Anthropic (currently always USD).',\n },\n] as const;\n\nexport const anthropicResources = defineResources({\n anthropic_input_tokens: {\n shape: 'metric',\n description:\n 'Daily uncached input tokens processed by the Anthropic Messages API, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Sample value is uncached_input_tokens. Cache-read and cache-creation token volumes are mirrored on their own metrics so a cache hit ratio can be computed at query time.',\n responses: { usage_messages: usageResponseSchema },\n },\n anthropic_output_tokens: {\n shape: 'metric',\n description:\n 'Daily output tokens generated by the Anthropic Messages API, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Written alongside anthropic_input_tokens from the same usage_messages API call.',\n },\n anthropic_cache_read_tokens: {\n shape: 'metric',\n description:\n 'Daily input tokens read from the prompt cache, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Cache hits are charged at a fraction of the uncached rate, so this metric paired with anthropic_input_tokens gives the cache hit ratio.',\n },\n anthropic_cache_creation_tokens: {\n shape: 'metric',\n description:\n 'Daily input tokens written into the prompt cache (sum of the 1h and 5m ephemeral caches), grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are mirrored in attributes for finer-grained widgets.',\n },\n anthropic_web_search_requests: {\n shape: 'metric',\n description:\n 'Daily count of web-search tool requests executed server-side by Claude, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'requests',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Sourced from server_tool_use.web_search_requests on each usage bucket. Zero rows are still written so a \"no usage today\" widget renders correctly.',\n },\n anthropic_cost_usd: {\n shape: 'metric',\n description:\n 'Daily organization spend in USD, broken down by workspace and cost line item, pulled from the Anthropic Cost Report.',\n endpoint: 'GET /v1/organizations/cost_report',\n unit: 'USD',\n granularity: 'daily',\n dimensions: [...COST_DIMENSIONS],\n notes:\n 'The Cost Report returns amounts as a decimal string in the lowest currency unit (cents for USD). The connector divides by 100 so the stored metric value is dollars. Costs can be revised for a couple of days after the fact; incremental syncs refetch a short trailing window to pick up adjustments.',\n responses: { cost_report: costResponseSchema },\n },\n});\n\nexport interface AnthropicSettings {\n workspaceIds?: readonly string[];\n resources?: readonly AnthropicResource[];\n lookbackDays?: number;\n}\n\nconst anthropicCredentials = {\n adminApiKey: {\n description: 'Anthropic organization admin API key (sk-ant-admin-...)',\n auth: 'required' as const,\n },\n} satisfies CredentialsSchema;\n\ntype AnthropicCredentials = typeof anthropicCredentials;\n\nexport const id = 'anthropic';\n\ninterface UsageWindow {\n startingAt: string;\n endingAt: string;\n}\n\nexport function getUsageWindow(\n options: SyncOptions,\n lookbackDays: number,\n now: number = Date.now(),\n): UsageWindow {\n const todayStart = Math.floor(now / MS_PER_DAY) * MS_PER_DAY;\n const endMs = todayStart + MS_PER_DAY;\n\n let days = lookbackDays;\n if (options.mode === 'latest') {\n days = INCREMENTAL_LOOKBACK_DAYS;\n } else if (options.since !== undefined) {\n const sinceMs = parseEpoch(options.since, 'iso');\n if (sinceMs !== null) {\n const elapsed = Math.ceil((now - sinceMs) / MS_PER_DAY);\n days = Math.min(\n Math.max(elapsed + INCREMENTAL_LOOKBACK_DAYS, 1),\n lookbackDays,\n );\n }\n }\n const startMs = endMs - days * MS_PER_DAY;\n return {\n startingAt: new Date(startMs).toISOString(),\n endingAt: new Date(endMs).toISOString(),\n };\n}\n\nfunction resourceToPhase(resource: AnthropicResource): AnthropicPhase {\n for (const phase of PHASE_ORDER) {\n if ((RESOURCES_BY_PHASE[phase] as readonly string[]).includes(resource)) {\n return phase;\n }\n }\n // unreachable - RESOURCES_BY_PHASE covers every AnthropicResource\n throw new Error(`anthropic: unmapped resource ${resource}`);\n}\n\nfunction nullableString(value: string | null | undefined): string | null {\n return value === undefined || value === null ? null : value;\n}\n\nfunction usageDimensionAttributes(row: UsageResult): Record<string, JSONValue> {\n return {\n model: nullableString(row.model),\n workspace_id: nullableString(row.workspace_id),\n api_key_id: nullableString(row.api_key_id),\n service_tier: nullableString(row.service_tier),\n context_window: nullableString(row.context_window),\n inference_geo: nullableString(row.inference_geo),\n account_id: nullableString(row.account_id),\n service_account_id: nullableString(row.service_account_id),\n };\n}\n\nfunction cacheCreationTotal(row: UsageResult): number {\n const c = row.cache_creation;\n if (!c) {\n return 0;\n }\n return (\n (c.ephemeral_1h_input_tokens ?? 0) + (c.ephemeral_5m_input_tokens ?? 0)\n );\n}\n\nfunction tsFromBucket(bucket: BucketPage<unknown>): number | null {\n return parseEpoch(bucket.starting_at, 'iso');\n}\n\nexport function buildUsageSamples(\n buckets: readonly BucketPage<UsageResult>[],\n): {\n inputTokens: MetricSample[];\n outputTokens: MetricSample[];\n cacheReadTokens: MetricSample[];\n cacheCreationTokens: MetricSample[];\n webSearchRequests: MetricSample[];\n} {\n const inputTokens: MetricSample[] = [];\n const outputTokens: MetricSample[] = [];\n const cacheReadTokens: MetricSample[] = [];\n const cacheCreationTokens: MetricSample[] = [];\n const webSearchRequests: MetricSample[] = [];\n for (const bucket of buckets) {\n const ts = tsFromBucket(bucket);\n if (ts === null) {\n continue;\n }\n for (const row of bucket.results) {\n const common = usageDimensionAttributes(row);\n const cacheCreation = row.cache_creation;\n inputTokens.push({\n name: 'anthropic_input_tokens',\n ts,\n value: row.uncached_input_tokens,\n attributes: { ...common },\n });\n outputTokens.push({\n name: 'anthropic_output_tokens',\n ts,\n value: row.output_tokens,\n attributes: { ...common },\n });\n cacheReadTokens.push({\n name: 'anthropic_cache_read_tokens',\n ts,\n value: row.cache_read_input_tokens,\n attributes: { ...common },\n });\n cacheCreationTokens.push({\n name: 'anthropic_cache_creation_tokens',\n ts,\n value: cacheCreationTotal(row),\n attributes: {\n ...common,\n ephemeral_1h_input_tokens:\n cacheCreation?.ephemeral_1h_input_tokens ?? 0,\n ephemeral_5m_input_tokens:\n cacheCreation?.ephemeral_5m_input_tokens ?? 0,\n },\n });\n webSearchRequests.push({\n name: 'anthropic_web_search_requests',\n ts,\n value: row.server_tool_use?.web_search_requests ?? 0,\n attributes: { ...common },\n });\n }\n }\n return {\n inputTokens,\n outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n webSearchRequests,\n };\n}\n\nexport function buildCostSamples(\n buckets: readonly BucketPage<CostResult>[],\n): MetricSample[] {\n const samples: MetricSample[] = [];\n for (const bucket of buckets) {\n const ts = tsFromBucket(bucket);\n if (ts === null) {\n continue;\n }\n for (const row of bucket.results) {\n const rawAmount = Number.parseFloat(row.amount);\n const value = Number.isFinite(rawAmount)\n ? rawAmount / COST_AMOUNT_DIVISOR\n : 0;\n samples.push({\n name: 'anthropic_cost_usd',\n ts,\n value,\n attributes: {\n workspace_id: nullableString(row.workspace_id),\n description: nullableString(row.description),\n cost_type: nullableString(row.cost_type),\n model: nullableString(row.model),\n token_type: nullableString(row.token_type),\n service_tier: nullableString(row.service_tier),\n context_window: nullableString(row.context_window),\n currency: row.currency,\n },\n });\n }\n }\n return samples;\n}\n\nexport class AnthropicConnector extends BaseConnector<\n AnthropicSettings,\n AnthropicCredentials\n> {\n static readonly id = id;\n\n static readonly resources = anthropicResources;\n\n static readonly schemas = schemasFromResources(anthropicResources);\n\n static create(input: unknown, ctx?: ConnectorContext): AnthropicConnector {\n const parsed = configFields.parse(input);\n return new AnthropicConnector(\n {\n workspaceIds: parsed.workspaceIds,\n resources: parsed.resources,\n lookbackDays: parsed.lookbackDays,\n },\n { adminApiKey: parsed.adminApiKey },\n ctx,\n );\n }\n\n readonly id = id;\n override readonly credentials = anthropicCredentials;\n\n private buildHeaders(): Record<string, string> {\n return {\n 'X-Api-Key': String(this.creds.adminApiKey),\n 'anthropic-version': ANTHROPIC_API_VERSION,\n 'User-Agent': connectorUserAgent(this.id),\n };\n }\n\n private fetch<T>(\n url: string,\n resource: string,\n signal?: AbortSignal,\n ): Promise<HttpResponse<T>> {\n return this.get<T>(url, {\n resource,\n headers: this.buildHeaders(),\n signal,\n });\n }\n\n private buildInitialUrl(phase: AnthropicPhase, window: UsageWindow): string {\n const url = new URL(`${ANTHROPIC_API_BASE}${PHASE_ENDPOINT_PATH[phase]}`);\n url.searchParams.set('starting_at', window.startingAt);\n url.searchParams.set('ending_at', window.endingAt);\n url.searchParams.set('bucket_width', '1d');\n if (phase === 'usage_messages') {\n url.searchParams.set('limit', String(USAGE_PAGE_LIMIT));\n url.searchParams.append('group_by', 'model');\n url.searchParams.append('group_by', 'workspace_id');\n url.searchParams.append('group_by', 'api_key_id');\n url.searchParams.append('group_by', 'service_tier');\n url.searchParams.append('group_by', 'context_window');\n url.searchParams.append('group_by', 'inference_geo');\n for (const workspaceId of this.settings.workspaceIds ?? []) {\n url.searchParams.append('workspace_ids', workspaceId);\n }\n } else {\n url.searchParams.set('limit', String(COSTS_PAGE_LIMIT));\n url.searchParams.append('group_by', 'workspace_id');\n url.searchParams.append('group_by', 'description');\n }\n return url.toString();\n }\n\n private buildNextUrl(currentUrl: string, nextPage: string): string {\n const url = new URL(currentUrl);\n url.searchParams.set('page', nextPage);\n return url.toString();\n }\n\n private async fetchPhasePage<T>(\n phase: AnthropicPhase,\n schema: z.ZodType<T>,\n initialUrl: string,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<{ url: string; parsed: T; nextUrl: string | null }> {\n const url = page ?? initialUrl;\n const res = await this.fetch<unknown>(url, phase, signal);\n const parsed = schema.parse(res.body);\n const body = parsed as unknown as {\n next_page?: string | null;\n has_more?: boolean;\n };\n const nextPage =\n body.has_more === true &&\n typeof body.next_page === 'string' &&\n body.next_page.length > 0\n ? body.next_page\n : null;\n const nextUrl = nextPage ? this.buildNextUrl(url, nextPage) : null;\n return { url, parsed, nextUrl };\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n const cursor = isAnthropicSyncCursor(options.cursor)\n ? options.cursor\n : undefined;\n const lookbackDays = this.settings.lookbackDays ?? DEFAULT_LOOKBACK_DAYS;\n const window = getUsageWindow(options, lookbackDays);\n\n const phases = selectActivePhases<AnthropicResource, AnthropicPhase>(\n resourceToPhase,\n PHASE_ORDER,\n this.settings.resources,\n );\n\n const startIdx = cursor ? phases.indexOf(cursor.phase) : 0;\n const resumeIdx = startIdx >= 0 ? startIdx : 0;\n\n for (let i = resumeIdx; i < phases.length; i++) {\n const phase = phases[i]!;\n if (signal?.aborted) {\n return { done: false, cursor: { phase, page: null } };\n }\n const phaseStart = Date.now();\n const initialUrl = this.buildInitialUrl(phase, window);\n let pageUrl: string | null = null;\n let pageCount = 0;\n const buckets: BucketPage<unknown>[] = [];\n\n while (true) {\n if (signal?.aborted) {\n return { done: false, cursor: { phase, page: null } };\n }\n pageCount += 1;\n const { parsed, nextUrl } = await this.fetchAnyPhasePage(\n phase,\n initialUrl,\n pageUrl,\n signal,\n );\n const data = parsed.data as BucketPage<unknown>[];\n buckets.push(...data);\n this.logger.info('fetched page', {\n resource: phase,\n page: pageCount,\n items: data.length,\n });\n if (nextUrl === null) {\n break;\n }\n pageUrl = nextUrl;\n }\n\n await this.writePhase(storage, phase, buckets);\n this.logger.info('resource done', {\n resource: phase,\n pages: pageCount,\n items: buckets.length,\n duration_ms: Date.now() - phaseStart,\n });\n }\n\n return { done: true };\n }\n\n private async fetchAnyPhasePage(\n phase: AnthropicPhase,\n initialUrl: string,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<{\n parsed: { data: BucketPage<unknown>[] };\n nextUrl: string | null;\n }> {\n switch (phase) {\n case 'usage_messages':\n return this.fetchPhasePage(\n phase,\n usageResponseSchema,\n initialUrl,\n page,\n signal,\n );\n case 'cost_report':\n return this.fetchPhasePage(\n phase,\n costResponseSchema,\n initialUrl,\n page,\n signal,\n );\n }\n }\n\n private async writePhase(\n storage: StorageHandle,\n phase: AnthropicPhase,\n buckets: BucketPage<unknown>[],\n ): Promise<void> {\n switch (phase) {\n case 'usage_messages': {\n const samples = buildUsageSamples(buckets as BucketPage<UsageResult>[]);\n await storage.metrics(samples.inputTokens, {\n names: ['anthropic_input_tokens'],\n });\n await storage.metrics(samples.outputTokens, {\n names: ['anthropic_output_tokens'],\n });\n await storage.metrics(samples.cacheReadTokens, {\n names: ['anthropic_cache_read_tokens'],\n });\n await storage.metrics(samples.cacheCreationTokens, {\n names: ['anthropic_cache_creation_tokens'],\n });\n await storage.metrics(samples.webSearchRequests, {\n names: ['anthropic_web_search_requests'],\n });\n return;\n }\n case 'cost_report': {\n const samples = buildCostSamples(buckets as BucketPage<CostResult>[]);\n await storage.metrics(samples, { names: ['anthropic_cost_usd'] });\n return;\n }\n }\n }\n}\n\nexport type { PageResponse, BucketPage, UsageResult, CostResult };\n","import { AnthropicConnector } from './anthropic';\n\nexport {\n AnthropicConnector,\n anthropicResources as resources,\n buildCostSamples,\n buildUsageSamples,\n configFields,\n doc,\n getUsageWindow,\n id,\n} from './anthropic';\nexport type {\n AnthropicResource,\n AnthropicSettings,\n BucketPage,\n CostResult,\n PageResponse,\n UsageResult,\n} from './anthropic';\nexport default AnthropicConnector;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../connector-shared/src/errors.ts","../../../connector-shared/src/retry.ts","../../../connector-shared/src/version.ts","../../../connector-shared/src/request.ts","../../../connector-shared/src/rate-limit.ts","../../../connector-shared/src/map-concurrent.ts","../../../connector-shared/src/sanitize.ts","../../../connector-shared/src/epoch.ts","../../../connector-shared/src/pagination.ts","../../../connector-shared/src/logger.ts","../src/anthropic.ts","../src/index.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n\nexport function connectorUserAgent(connectorId: string): string {\n return `rawdash-connector-${connectorId}/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n}\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(\n res: Response,\n parseJson: boolean,\n binary: boolean,\n): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n if (binary) {\n return new Uint8Array(await res.arrayBuffer());\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions,\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n const binary = req.binary ?? false;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson, binary);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport interface StandardRateLimitPolicyConfig {\n remainingHeader: string;\n resetHeader: string;\n resetUnit: 's' | 'ms';\n resetFallbackMs?: number;\n}\n\nexport function standardRateLimitPolicy(\n config: StandardRateLimitPolicyConfig,\n): RateLimitPolicy {\n const { remainingHeader, resetHeader, resetUnit, resetFallbackMs } = config;\n const multiplier = resetUnit === 's' ? 1000 : 1;\n return {\n parse(h) {\n const remainingRaw = h.get(remainingHeader);\n if (remainingRaw === null || remainingRaw.trim() === '') {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n const resetRaw = h.get(resetHeader);\n if (resetRaw === null) {\n if (resetFallbackMs === undefined) {\n return null;\n }\n return {\n remaining,\n resetAt: new Date(Date.now() + resetFallbackMs),\n };\n }\n if (resetRaw.trim() === '') {\n return null;\n }\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n const resetMs = reset * multiplier;\n if (!Number.isFinite(resetMs)) {\n return null;\n }\n return { remaining, resetAt: new Date(resetMs) };\n },\n };\n}\n","export async function mapWithConcurrency<T, R>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n if (items.length === 0) {\n return results;\n }\n const normalized = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const limit = Math.max(1, Math.min(normalized, items.length));\n let next = 0;\n let failed = false;\n\n async function worker(): Promise<void> {\n while (!failed) {\n const i = next++;\n if (i >= items.length) {\n return;\n }\n try {\n results[i] = await fn(items[i]!, i);\n } catch (err) {\n failed = true;\n throw err;\n }\n }\n }\n\n const workers: Promise<void>[] = [];\n for (let w = 0; w < limit; w++) {\n workers.push(worker());\n }\n await Promise.all(workers);\n return results;\n}\n","export interface SanitizeAllowedUrlOptions {\n url: string | null;\n host: string;\n pathname: string;\n protocol?: 'https:' | 'http:';\n}\n\nexport function sanitizeAllowedUrl(\n options: SanitizeAllowedUrlOptions,\n): string | null {\n const { url, host, pathname, protocol = 'https:' } = options;\n if (url === null) {\n return null;\n }\n try {\n const u = new URL(url);\n if (u.protocol !== protocol || u.host !== host || u.pathname !== pathname) {\n return null;\n }\n return u.toString();\n } catch {\n return null;\n }\n}\n","export type EpochUnit = 'ms' | 's' | 'iso';\n\nexport function parseEpoch(\n value: number | string | null | undefined,\n unit: EpochUnit,\n): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n if (unit === 'iso') {\n if (typeof value !== 'string') {\n return null;\n }\n const ms = new Date(value).getTime();\n return Number.isFinite(ms) ? ms : null;\n }\n if (typeof value === 'string' && value.trim() === '') {\n return null;\n }\n const n = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(n)) {\n return null;\n }\n const result = unit === 's' ? n * 1000 : n;\n return Number.isFinite(result) ? result : null;\n}\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n options: { resource: string },\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request(\n {\n ...initial,\n url: next,\n },\n { resource: options.resource },\n );\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req, { resource: options.resource });\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req, { resource: options.resource });\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","export type LogFields = Record<string, unknown>;\n\nexport interface ConnectorLogger {\n info(event: string, fields?: LogFields): void;\n warn(event: string, fields?: LogFields): void;\n}\n\nexport interface ConnectorLoggerOptions {\n scope: string;\n}\n\nconst MAX_VALUE_LEN = 120;\n\nfunction truncate(s: string, max = MAX_VALUE_LEN): string {\n if (s.length <= max) {\n return s;\n }\n return `${s.slice(0, max - 1)}…`;\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (value === undefined) {\n return '';\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (typeof value === 'string') {\n const t = truncate(value);\n if (/[\\s\"=]/.test(t)) {\n return JSON.stringify(t);\n }\n return t;\n }\n if (typeof value === 'bigint') {\n return value.toString();\n }\n let json: string | undefined;\n try {\n json = JSON.stringify(value);\n } catch {\n json = undefined;\n }\n return truncate(json ?? String(value));\n}\n\nexport function formatLogFields(fields?: LogFields): string {\n if (!fields) {\n return '';\n }\n const parts: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (v === undefined) {\n continue;\n }\n parts.push(`${k}=${formatValue(v)}`);\n }\n return parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\nexport function formatLogLine(\n scope: string,\n event: string,\n fields?: LogFields,\n): string {\n return `[${scope}] ${event}${formatLogFields(fields)}`;\n}\n\nexport function createDefaultConnectorLogger(\n opts: ConnectorLoggerOptions,\n): ConnectorLogger {\n return {\n info(event, fields) {\n console.info(formatLogLine(opts.scope, event, fields));\n },\n warn(event, fields) {\n console.warn(formatLogLine(opts.scope, event, fields));\n },\n };\n}\n\nconst NOOP_LOGGER: ConnectorLogger = {\n info() {},\n warn() {},\n};\n\nexport function noopConnectorLogger(): ConnectorLogger {\n return NOOP_LOGGER;\n}\n","import {\n type HttpResponse,\n connectorUserAgent,\n parseEpoch,\n} from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ConnectorContext,\n type ConnectorDoc,\n type CredentialsSchema,\n type MetricSample,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n defineConnectorDoc,\n defineResources,\n makeChunkedCursorGuard,\n metricSample,\n schemasFromResources,\n selectActivePhases,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nconst ANTHROPIC_API_HOST = 'api.anthropic.com';\nconst ANTHROPIC_API_BASE = `https://${ANTHROPIC_API_HOST}`;\nconst ANTHROPIC_API_VERSION = '2023-06-01';\nconst USAGE_PAGE_LIMIT = 31;\nconst COSTS_PAGE_LIMIT = 31;\nconst MS_PER_DAY = 86_400_000;\nconst DEFAULT_LOOKBACK_DAYS = 30;\nconst INCREMENTAL_LOOKBACK_DAYS = 2;\n// Cost report `amount` is a decimal string in the lowest currency unit (cents\n// for USD): e.g. \"123.45\" represents $1.2345. Divide by 100 to get dollars.\nconst COST_AMOUNT_DIVISOR = 100;\n\nexport const configFields = defineConfigFields(\n z.object({\n adminApiKey: z.object({ $secret: z.string().min(1) }).meta({\n label: 'Admin API key',\n description:\n 'Anthropic organization admin API key (starts with sk-ant-admin-). Create one at console.anthropic.com -> Settings -> Admin keys. Regular API keys (sk-ant-api-) cannot read the Usage and Cost reports.',\n placeholder: 'ANTHROPIC_ADMIN_API_KEY',\n secret: true,\n }),\n workspaceIds: z.array(z.string().min(1)).nonempty().optional().meta({\n label: 'Workspace IDs (optional)',\n description:\n 'Restrict usage and cost queries to specific Anthropic workspace ids (wrkspc_...). Omit to aggregate every workspace the admin key can see.',\n }),\n resources: z\n .array(\n z.enum([\n 'anthropic_input_tokens',\n 'anthropic_output_tokens',\n 'anthropic_cache_read_tokens',\n 'anthropic_cache_creation_tokens',\n 'anthropic_web_search_requests',\n 'anthropic_cost_usd',\n ]),\n )\n .nonempty()\n .optional()\n .meta({\n label: 'Resources',\n description:\n 'Which Anthropic metric series to sync. Omit to sync all of them. The five usage metrics share one upstream call to the Messages Usage Report; enabling any one of them fetches the report and writes all five.',\n }),\n lookbackDays: z.number().int().positive().max(180).optional().meta({\n label: 'Backfill window (days)',\n description:\n 'How many days of usage history to fetch on a full sync. Defaults to 30. The Usage Report returns at most 31 buckets per page, so longer windows paginate.',\n placeholder: '30',\n }),\n }),\n);\n\nexport const doc: ConnectorDoc = defineConnectorDoc({\n displayName: 'Anthropic',\n category: 'engineering',\n brandColor: '#D97757',\n tagline:\n 'Track Anthropic spend, daily token usage across Claude models, cache hit volumes, and web-search tool requests from the Anthropic Admin API.',\n vendor: {\n name: 'Anthropic',\n domain: 'anthropic.com',\n apiDocs:\n 'https://docs.claude.com/en/api/admin-api/usage-cost/get-messages-usage-report',\n website: 'https://anthropic.com',\n },\n auth: {\n summary:\n 'Authenticates with an Anthropic organization admin API key (sk-ant-admin-). Admin keys are the only key class that can read the Usage and Cost reports; regular API keys return 403.',\n setup: [\n 'Open console.anthropic.com -> Settings -> Admin Keys and create a new admin key. Admin keys are organization-scoped, so create the key from the organization whose usage you want to read.',\n 'Store the key as a secret (e.g. ANTHROPIC_ADMIN_API_KEY).',\n 'Reference it from config as `adminApiKey: secret(\"ANTHROPIC_ADMIN_API_KEY\")`.',\n 'Optionally set `workspaceIds` to restrict the query to a subset of workspaces.',\n ],\n },\n rateLimit:\n 'The Admin API returns 429 with a Retry-After header on burst; the shared HTTP client honors it automatically. Daily syncs against the Usage and Cost reports are well below the per-organization Admin API budget.',\n limitations: [\n 'Only the organization Messages Usage Report and Cost Report endpoints are synced. Per-request logs and individual message bodies are not exposed by the Admin API.',\n 'All samples are bucketed daily (1d bucket_width). The Usage Report also supports hourly and per-minute granularity but those are not exposed here in v1.',\n 'The Cost Report only supports 1d bucket_width and reports cost in USD; non-USD billing currencies are not converted.',\n 'Admin API keys are required - regular sk-ant-api- keys do not have access to the organization Usage and Cost reports.',\n ],\n});\n\nconst PHASE_ORDER = ['usage_messages', 'cost_report'] as const;\n\ntype AnthropicPhase = (typeof PHASE_ORDER)[number];\n\nexport type AnthropicResource =\n | 'anthropic_input_tokens'\n | 'anthropic_output_tokens'\n | 'anthropic_cache_read_tokens'\n | 'anthropic_cache_creation_tokens'\n | 'anthropic_web_search_requests'\n | 'anthropic_cost_usd';\n\nconst isAnthropicSyncCursor = makeChunkedCursorGuard(PHASE_ORDER);\n\nconst RESOURCES_BY_PHASE: Record<AnthropicPhase, readonly AnthropicResource[]> =\n {\n usage_messages: [\n 'anthropic_input_tokens',\n 'anthropic_output_tokens',\n 'anthropic_cache_read_tokens',\n 'anthropic_cache_creation_tokens',\n 'anthropic_web_search_requests',\n ],\n cost_report: ['anthropic_cost_usd'],\n };\n\nconst PHASE_ENDPOINT_PATH: Record<AnthropicPhase, string> = {\n usage_messages: '/v1/organizations/usage_report/messages',\n cost_report: '/v1/organizations/cost_report',\n};\n\nconst usageCacheCreationSchema = z.object({\n ephemeral_1h_input_tokens: z.number().nonnegative().nullish(),\n ephemeral_5m_input_tokens: z.number().nonnegative().nullish(),\n});\n\nconst usageServerToolUseSchema = z.object({\n web_search_requests: z.number().int().nonnegative().nullish(),\n});\n\nconst usageResultSchema = z.object({\n account_id: z.string().nullish(),\n api_key_id: z.string().nullish(),\n cache_creation: usageCacheCreationSchema.nullish(),\n cache_read_input_tokens: z.number().nonnegative(),\n context_window: z.string().nullish(),\n inference_geo: z.string().nullish(),\n model: z.string().nullish(),\n output_tokens: z.number().nonnegative(),\n server_tool_use: usageServerToolUseSchema.nullish(),\n service_account_id: z.string().nullish(),\n service_tier: z.string().nullish(),\n uncached_input_tokens: z.number().nonnegative(),\n workspace_id: z.string().nullish(),\n});\n\nconst costResultSchema = z.object({\n amount: z.string(),\n context_window: z.string().nullish(),\n cost_type: z.string().nullish(),\n currency: z.string(),\n description: z.string().nullish(),\n inference_geo: z.string().nullish(),\n model: z.string().nullish(),\n service_tier: z.string().nullish(),\n token_type: z.string().nullish(),\n workspace_id: z.string().nullish(),\n});\n\nfunction bucketResponseSchema<T extends z.ZodTypeAny>(resultSchema: T) {\n return z.object({\n data: z.array(\n z.object({\n starting_at: z.string(),\n ending_at: z.string(),\n results: z.array(resultSchema),\n }),\n ),\n has_more: z.boolean(),\n next_page: z.string().nullish(),\n });\n}\n\nconst usageResponseSchema = bucketResponseSchema(usageResultSchema);\nconst costResponseSchema = bucketResponseSchema(costResultSchema);\n\ntype UsageResult = z.infer<typeof usageResultSchema>;\ntype CostResult = z.infer<typeof costResultSchema>;\n\ninterface BucketPage<TResult> {\n starting_at: string;\n ending_at: string;\n results: TResult[];\n}\n\ninterface PageResponse<TResult> {\n buckets: BucketPage<TResult>[];\n nextPage: string | null;\n}\n\nconst USAGE_DIMENSIONS = [\n {\n name: 'model',\n description: 'Claude model id reported by Anthropic (or null).',\n },\n {\n name: 'workspace_id',\n description:\n 'Anthropic workspace id the usage is attributed to (or null for the default workspace).',\n },\n {\n name: 'api_key_id',\n description: 'API key id the usage is attributed to (or null).',\n },\n {\n name: 'service_tier',\n description:\n 'Service tier the request ran under (standard, batch, priority, flex, etc.), or null.',\n },\n {\n name: 'context_window',\n description:\n 'Context window bucket the request used (0-200k or 200k-1M), or null.',\n },\n {\n name: 'inference_geo',\n description:\n 'Inference geo the request ran in (global, us, not_available), or null.',\n },\n {\n name: 'account_id',\n description: 'Account id the usage is attributed to (or null).',\n },\n {\n name: 'service_account_id',\n description: 'Service account id the usage is attributed to (or null).',\n },\n] as const;\n\nconst COST_DIMENSIONS = [\n {\n name: 'workspace_id',\n description:\n 'Anthropic workspace id the cost is attributed to (or null for the default workspace).',\n },\n {\n name: 'description',\n description:\n 'Human-readable cost line item label (e.g. \"Claude Sonnet 4 Usage - Input Tokens\"), or null when ungrouped.',\n },\n {\n name: 'cost_type',\n description:\n 'Cost category (tokens, web_search, code_execution, session_usage), or null.',\n },\n {\n name: 'model',\n description:\n 'Claude model the cost is attributed to (or null for non-token costs).',\n },\n {\n name: 'token_type',\n description:\n 'Token category for token costs (uncached_input_tokens, output_tokens, cache_read_input_tokens, cache_creation.ephemeral_*_input_tokens), or null.',\n },\n {\n name: 'service_tier',\n description:\n 'Service tier the cost is attributed to (standard or batch), or null.',\n },\n {\n name: 'context_window',\n description:\n 'Context window the cost is attributed to (0-200k or 200k-1M), or null.',\n },\n {\n name: 'currency',\n description:\n 'Billing currency reported by Anthropic (currently always USD).',\n },\n] as const;\n\nexport const anthropicResources = defineResources({\n anthropic_input_tokens: {\n shape: 'metric',\n description:\n 'Daily uncached input tokens processed by the Anthropic Messages API, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Sample value is uncached_input_tokens. Cache-read and cache-creation token volumes are mirrored on their own metrics so a cache hit ratio can be computed at query time.',\n responses: { usage_messages: usageResponseSchema },\n },\n anthropic_output_tokens: {\n shape: 'metric',\n description:\n 'Daily output tokens generated by the Anthropic Messages API, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Written alongside anthropic_input_tokens from the same usage_messages API call.',\n },\n anthropic_cache_read_tokens: {\n shape: 'metric',\n description:\n 'Daily input tokens read from the prompt cache, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Cache hits are charged at a fraction of the uncached rate, so this metric paired with anthropic_input_tokens gives the cache hit ratio.',\n },\n anthropic_cache_creation_tokens: {\n shape: 'metric',\n description:\n 'Daily input tokens written into the prompt cache (sum of the 1h and 5m ephemeral caches), grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'tokens',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n measures: [\n {\n name: 'ephemeral_1h_input_tokens',\n description:\n 'Input tokens written into the 1-hour ephemeral prompt cache (a component of the sample value).',\n },\n {\n name: 'ephemeral_5m_input_tokens',\n description:\n 'Input tokens written into the 5-minute ephemeral prompt cache (a component of the sample value).',\n },\n ],\n notes:\n 'The per-cache-bucket counts (ephemeral_1h_input_tokens, ephemeral_5m_input_tokens) are declared measures for finer-grained widgets.',\n },\n anthropic_web_search_requests: {\n shape: 'metric',\n description:\n 'Daily count of web-search tool requests executed server-side by Claude, grouped by model and workspace.',\n endpoint: 'GET /v1/organizations/usage_report/messages',\n unit: 'requests',\n granularity: 'daily',\n dimensions: [...USAGE_DIMENSIONS],\n notes:\n 'Sourced from server_tool_use.web_search_requests on each usage bucket. Zero rows are still written so a \"no usage today\" widget renders correctly.',\n },\n anthropic_cost_usd: {\n shape: 'metric',\n description:\n 'Daily organization spend in USD, broken down by workspace and cost line item, pulled from the Anthropic Cost Report.',\n endpoint: 'GET /v1/organizations/cost_report',\n unit: 'USD',\n granularity: 'daily',\n dimensions: [...COST_DIMENSIONS],\n notes:\n 'The Cost Report returns amounts as a decimal string in the lowest currency unit (cents for USD). The connector divides by 100 so the stored metric value is dollars. Costs can be revised for a couple of days after the fact; incremental syncs refetch a short trailing window to pick up adjustments.',\n responses: { cost_report: costResponseSchema },\n },\n});\n\nexport interface AnthropicSettings {\n workspaceIds?: readonly string[];\n resources?: readonly AnthropicResource[];\n lookbackDays?: number;\n}\n\nconst anthropicCredentials = {\n adminApiKey: {\n description: 'Anthropic organization admin API key (sk-ant-admin-...)',\n auth: 'required' as const,\n },\n} satisfies CredentialsSchema;\n\ntype AnthropicCredentials = typeof anthropicCredentials;\n\nexport const id = 'anthropic';\n\ninterface UsageWindow {\n startingAt: string;\n endingAt: string;\n startMs: number;\n endMs: number;\n}\n\nexport function getUsageWindow(\n options: SyncOptions,\n lookbackDays: number,\n now: number = Date.now(),\n): UsageWindow {\n const todayStart = Math.floor(now / MS_PER_DAY) * MS_PER_DAY;\n const endMs = todayStart + MS_PER_DAY;\n\n let days = lookbackDays;\n if (options.mode === 'latest') {\n days = INCREMENTAL_LOOKBACK_DAYS;\n } else if (options.since !== undefined) {\n const sinceMs = parseEpoch(options.since, 'iso');\n if (sinceMs !== null) {\n const elapsed = Math.ceil((now - sinceMs) / MS_PER_DAY);\n days = Math.min(\n Math.max(elapsed + INCREMENTAL_LOOKBACK_DAYS, 1),\n lookbackDays,\n );\n }\n }\n const startMs = endMs - days * MS_PER_DAY;\n return {\n startingAt: new Date(startMs).toISOString(),\n endingAt: new Date(endMs).toISOString(),\n startMs,\n endMs,\n };\n}\n\nfunction resourceToPhase(resource: AnthropicResource): AnthropicPhase {\n for (const phase of PHASE_ORDER) {\n if ((RESOURCES_BY_PHASE[phase] as readonly string[]).includes(resource)) {\n return phase;\n }\n }\n // unreachable - RESOURCES_BY_PHASE covers every AnthropicResource\n throw new Error(`anthropic: unmapped resource ${resource}`);\n}\n\nfunction nullableString(value: string | null | undefined): string | null {\n return value === undefined || value === null ? null : value;\n}\n\ninterface UsageDimensionAttributes {\n model: string | null;\n workspace_id: string | null;\n api_key_id: string | null;\n service_tier: string | null;\n context_window: string | null;\n inference_geo: string | null;\n account_id: string | null;\n service_account_id: string | null;\n}\n\nfunction usageDimensionAttributes(row: UsageResult): UsageDimensionAttributes {\n return {\n model: nullableString(row.model),\n workspace_id: nullableString(row.workspace_id),\n api_key_id: nullableString(row.api_key_id),\n service_tier: nullableString(row.service_tier),\n context_window: nullableString(row.context_window),\n inference_geo: nullableString(row.inference_geo),\n account_id: nullableString(row.account_id),\n service_account_id: nullableString(row.service_account_id),\n };\n}\n\nfunction cacheCreationTotal(row: UsageResult): number {\n const c = row.cache_creation;\n if (!c) {\n return 0;\n }\n return (\n (c.ephemeral_1h_input_tokens ?? 0) + (c.ephemeral_5m_input_tokens ?? 0)\n );\n}\n\nfunction tsFromBucket(bucket: BucketPage<unknown>): number | null {\n return parseEpoch(bucket.starting_at, 'iso');\n}\n\nexport function buildUsageSamples(\n buckets: readonly BucketPage<UsageResult>[],\n): {\n inputTokens: MetricSample[];\n outputTokens: MetricSample[];\n cacheReadTokens: MetricSample[];\n cacheCreationTokens: MetricSample[];\n webSearchRequests: MetricSample[];\n} {\n const inputTokens: MetricSample[] = [];\n const outputTokens: MetricSample[] = [];\n const cacheReadTokens: MetricSample[] = [];\n const cacheCreationTokens: MetricSample[] = [];\n const webSearchRequests: MetricSample[] = [];\n for (const bucket of buckets) {\n const ts = tsFromBucket(bucket);\n if (ts === null) {\n continue;\n }\n for (const row of bucket.results) {\n const common = usageDimensionAttributes(row);\n const cacheCreation = row.cache_creation;\n inputTokens.push(\n metricSample(anthropicResources, 'anthropic_input_tokens', {\n ts,\n value: row.uncached_input_tokens,\n attributes: { ...common },\n }),\n );\n outputTokens.push(\n metricSample(anthropicResources, 'anthropic_output_tokens', {\n ts,\n value: row.output_tokens,\n attributes: { ...common },\n }),\n );\n cacheReadTokens.push(\n metricSample(anthropicResources, 'anthropic_cache_read_tokens', {\n ts,\n value: row.cache_read_input_tokens,\n attributes: { ...common },\n }),\n );\n cacheCreationTokens.push(\n metricSample(anthropicResources, 'anthropic_cache_creation_tokens', {\n ts,\n value: cacheCreationTotal(row),\n attributes: {\n ...common,\n ephemeral_1h_input_tokens:\n cacheCreation?.ephemeral_1h_input_tokens ?? 0,\n ephemeral_5m_input_tokens:\n cacheCreation?.ephemeral_5m_input_tokens ?? 0,\n },\n }),\n );\n webSearchRequests.push(\n metricSample(anthropicResources, 'anthropic_web_search_requests', {\n ts,\n value: row.server_tool_use?.web_search_requests ?? 0,\n attributes: { ...common },\n }),\n );\n }\n }\n return {\n inputTokens,\n outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n webSearchRequests,\n };\n}\n\nexport function buildCostSamples(\n buckets: readonly BucketPage<CostResult>[],\n): MetricSample[] {\n const samples: MetricSample[] = [];\n for (const bucket of buckets) {\n const ts = tsFromBucket(bucket);\n if (ts === null) {\n continue;\n }\n for (const row of bucket.results) {\n const rawAmount = Number.parseFloat(row.amount);\n const value = Number.isFinite(rawAmount)\n ? rawAmount / COST_AMOUNT_DIVISOR\n : 0;\n samples.push(\n metricSample(anthropicResources, 'anthropic_cost_usd', {\n ts,\n value,\n attributes: {\n workspace_id: nullableString(row.workspace_id),\n description: nullableString(row.description),\n cost_type: nullableString(row.cost_type),\n model: nullableString(row.model),\n token_type: nullableString(row.token_type),\n service_tier: nullableString(row.service_tier),\n context_window: nullableString(row.context_window),\n currency: row.currency,\n },\n }),\n );\n }\n }\n return samples;\n}\n\nexport class AnthropicConnector extends BaseConnector<\n AnthropicSettings,\n AnthropicCredentials\n> {\n static readonly id = id;\n\n static readonly resources = anthropicResources;\n\n static readonly schemas = schemasFromResources(anthropicResources);\n\n static create(input: unknown, ctx?: ConnectorContext): AnthropicConnector {\n const parsed = configFields.parse(input);\n return new AnthropicConnector(\n {\n workspaceIds: parsed.workspaceIds,\n resources: parsed.resources,\n lookbackDays: parsed.lookbackDays,\n },\n { adminApiKey: parsed.adminApiKey },\n ctx,\n );\n }\n\n readonly id = id;\n override readonly credentials = anthropicCredentials;\n\n private buildHeaders(): Record<string, string> {\n return {\n 'X-Api-Key': String(this.creds.adminApiKey),\n 'anthropic-version': ANTHROPIC_API_VERSION,\n 'User-Agent': connectorUserAgent(this.id),\n };\n }\n\n private fetch<T>(\n url: string,\n resource: string,\n signal?: AbortSignal,\n ): Promise<HttpResponse<T>> {\n return this.get<T>(url, {\n resource,\n headers: this.buildHeaders(),\n signal,\n });\n }\n\n private buildInitialUrl(phase: AnthropicPhase, window: UsageWindow): string {\n const url = new URL(`${ANTHROPIC_API_BASE}${PHASE_ENDPOINT_PATH[phase]}`);\n url.searchParams.set('starting_at', window.startingAt);\n url.searchParams.set('ending_at', window.endingAt);\n url.searchParams.set('bucket_width', '1d');\n if (phase === 'usage_messages') {\n url.searchParams.set('limit', String(USAGE_PAGE_LIMIT));\n url.searchParams.append('group_by', 'model');\n url.searchParams.append('group_by', 'workspace_id');\n url.searchParams.append('group_by', 'api_key_id');\n url.searchParams.append('group_by', 'service_tier');\n url.searchParams.append('group_by', 'context_window');\n url.searchParams.append('group_by', 'inference_geo');\n for (const workspaceId of this.settings.workspaceIds ?? []) {\n url.searchParams.append('workspace_ids', workspaceId);\n }\n } else {\n url.searchParams.set('limit', String(COSTS_PAGE_LIMIT));\n url.searchParams.append('group_by', 'workspace_id');\n url.searchParams.append('group_by', 'description');\n }\n return url.toString();\n }\n\n private buildNextUrl(currentUrl: string, nextPage: string): string {\n const url = new URL(currentUrl);\n url.searchParams.set('page', nextPage);\n return url.toString();\n }\n\n private async fetchPhasePage<T>(\n phase: AnthropicPhase,\n schema: z.ZodType<T>,\n initialUrl: string,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<{ url: string; parsed: T; nextUrl: string | null }> {\n const url = page ?? initialUrl;\n const res = await this.fetch<unknown>(url, phase, signal);\n const parsed = schema.parse(res.body);\n const body = parsed as unknown as {\n next_page?: string | null;\n has_more?: boolean;\n };\n const nextPage =\n body.has_more === true &&\n typeof body.next_page === 'string' &&\n body.next_page.length > 0\n ? body.next_page\n : null;\n const nextUrl = nextPage ? this.buildNextUrl(url, nextPage) : null;\n return { url, parsed, nextUrl };\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n const cursor = isAnthropicSyncCursor(options.cursor)\n ? options.cursor\n : undefined;\n const lookbackDays = this.settings.lookbackDays ?? DEFAULT_LOOKBACK_DAYS;\n const window = getUsageWindow(options, lookbackDays);\n\n const phases = selectActivePhases<AnthropicResource, AnthropicPhase>(\n resourceToPhase,\n PHASE_ORDER,\n this.settings.resources,\n );\n\n const startIdx = cursor ? phases.indexOf(cursor.phase) : 0;\n const resumeIdx = startIdx >= 0 ? startIdx : 0;\n\n for (let i = resumeIdx; i < phases.length; i++) {\n const phase = phases[i]!;\n if (signal?.aborted) {\n return { done: false, cursor: { phase, page: null } };\n }\n const phaseStart = Date.now();\n const initialUrl = this.buildInitialUrl(phase, window);\n let pageUrl: string | null = null;\n let pageCount = 0;\n const buckets: BucketPage<unknown>[] = [];\n\n while (true) {\n if (signal?.aborted) {\n return { done: false, cursor: { phase, page: null } };\n }\n pageCount += 1;\n const { parsed, nextUrl } = await this.fetchAnyPhasePage(\n phase,\n initialUrl,\n pageUrl,\n signal,\n );\n const data = parsed.data as BucketPage<unknown>[];\n buckets.push(...data);\n this.logger.info('fetched page', {\n resource: phase,\n page: pageCount,\n items: data.length,\n });\n if (nextUrl === null) {\n break;\n }\n pageUrl = nextUrl;\n }\n\n await this.writePhase(storage, phase, buckets, window);\n this.logger.info('resource done', {\n resource: phase,\n pages: pageCount,\n items: buckets.length,\n duration_ms: Date.now() - phaseStart,\n });\n }\n\n return { done: true };\n }\n\n private async fetchAnyPhasePage(\n phase: AnthropicPhase,\n initialUrl: string,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<{\n parsed: { data: BucketPage<unknown>[] };\n nextUrl: string | null;\n }> {\n switch (phase) {\n case 'usage_messages':\n return this.fetchPhasePage(\n phase,\n usageResponseSchema,\n initialUrl,\n page,\n signal,\n );\n case 'cost_report':\n return this.fetchPhasePage(\n phase,\n costResponseSchema,\n initialUrl,\n page,\n signal,\n );\n }\n }\n\n private async writePhase(\n storage: StorageHandle,\n phase: AnthropicPhase,\n buckets: BucketPage<unknown>[],\n window: UsageWindow,\n ): Promise<void> {\n const replaceWindow = { start: window.startMs, end: window.endMs };\n switch (phase) {\n case 'usage_messages': {\n const samples = buildUsageSamples(buckets as BucketPage<UsageResult>[]);\n await storage.metrics(samples.inputTokens, {\n names: ['anthropic_input_tokens'],\n replaceWindow,\n });\n await storage.metrics(samples.outputTokens, {\n names: ['anthropic_output_tokens'],\n replaceWindow,\n });\n await storage.metrics(samples.cacheReadTokens, {\n names: ['anthropic_cache_read_tokens'],\n replaceWindow,\n });\n await storage.metrics(samples.cacheCreationTokens, {\n names: ['anthropic_cache_creation_tokens'],\n replaceWindow,\n });\n await storage.metrics(samples.webSearchRequests, {\n names: ['anthropic_web_search_requests'],\n replaceWindow,\n });\n return;\n }\n case 'cost_report': {\n const samples = buildCostSamples(buckets as BucketPage<CostResult>[]);\n await storage.metrics(samples, {\n names: ['anthropic_cost_usd'],\n replaceWindow,\n });\n return;\n }\n }\n }\n}\n\nexport type { PageResponse, BucketPage, UsageResult, CostResult };\n","import { AnthropicConnector } from './anthropic';\n\nexport {\n AnthropicConnector,\n anthropicResources as resources,\n buildCostSamples,\n buildUsageSamples,\n configFields,\n doc,\n getUsageWindow,\n id,\n} from './anthropic';\nexport type {\n AnthropicResource,\n AnthropicSettings,\n BucketPage,\n CostResult,\n PageResponse,\n UsageResult,\n} from './anthropic';\nexport default AnthropicConnector;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawdash/connector-anthropic",
3
- "version": "0.27.0",
3
+ "version": "0.28.2",
4
4
  "description": "Rawdash connector for Anthropic — daily token usage and spend from the Anthropic Admin API (usage and cost reports)",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "zod": "^4.4.3",
27
- "@rawdash/core": "0.27.0"
27
+ "@rawdash/core": "0.28.2"
28
28
  },
29
29
  "devDependencies": {
30
30
  "fast-check": "^4.8.0",