@coreplane/switchboard 1.221.1 → 1.222.0

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/dist/cli.js CHANGED
@@ -11840,7 +11840,10 @@ function buildCostReport(group, cfg, usage, llm, range) {
11840
11840
  if (row.workflowName in workflowNames) workflowsUsd += usd;
11841
11841
  }
11842
11842
  byResource.workflows += workflowsUsd;
11843
- const llmUsd2 = llm && cfg.anthropicWorkspaceId ? llm.filter((r) => r.date === date && r.workspaceId === cfg.anthropicWorkspaceId).reduce((s, r) => s + r.amountUsd, 0) : 0;
11843
+ const llmRows = llm && cfg.anthropicWorkspaceId ? llm.filter((r) => r.date === date && r.workspaceId === cfg.anthropicWorkspaceId) : [];
11844
+ const llmUsd2 = llmRows.reduce((s, r) => s + r.amountUsd, 0);
11845
+ const llmEstimated = llmRows.some((r) => r.estimated === true);
11846
+ const llmUnpricedTokens = llmRows.reduce((s, r) => s + (r.unpricedTokens ?? 0), 0);
11844
11847
  const cloudUsd2 = Object.values(containers).reduce((s, c) => s + c.total, 0) + Object.values(durableObjects).reduce((s, v) => s + v, 0) + doRequestsUsd + doRowsUsd + doStorageUsd + workersUsd + r2Usd + workflowsUsd;
11845
11848
  return {
11846
11849
  date,
@@ -11854,6 +11857,8 @@ function buildCostReport(group, cfg, usage, llm, range) {
11854
11857
  workflowsUsd,
11855
11858
  cloudUsd: cloudUsd2,
11856
11859
  llmUsd: llmUsd2,
11860
+ llmEstimated,
11861
+ llmUnpricedTokens,
11857
11862
  total: cloudUsd2 + llmUsd2
11858
11863
  };
11859
11864
  });
@@ -11870,6 +11875,20 @@ function buildCostReport(group, cfg, usage, llm, range) {
11870
11875
  attribution
11871
11876
  };
11872
11877
  }
11878
+ function anthropicPriceOf(modelId) {
11879
+ const exact = ANTHROPIC_PRICES[modelId];
11880
+ if (exact) return exact;
11881
+ for (const family of Object.keys(ANTHROPIC_PRICES)) {
11882
+ if (modelId.startsWith(family) && DATED_RELEASE_SUFFIX.test(modelId.slice(family.length)))
11883
+ return ANTHROPIC_PRICES[family];
11884
+ }
11885
+ return void 0;
11886
+ }
11887
+ function anthropicTokensCostUsd(modelId, t) {
11888
+ const p = anthropicPriceOf(modelId);
11889
+ if (!p) return void 0;
11890
+ return (t.uncachedInput * p.input + t.output * p.output + t.cacheRead * p.cacheRead + t.cacheWrite5m * p.cacheWrite5m + t.cacheWrite1h * p.cacheWrite1h) / 1e6;
11891
+ }
11873
11892
  function resolveRange(daysParam, now = new Date(systemClock())) {
11874
11893
  const parsed = daysParam === null ? NaN : Number(daysParam);
11875
11894
  const days = Number.isInteger(parsed) ? Math.min(MAX_DAYS, Math.max(1, parsed)) : DEFAULT_DAYS;
@@ -11899,7 +11918,7 @@ function createCostsService(cfg, cloudflare, llm, now = () => new Date(systemClo
11899
11918
  }
11900
11919
  };
11901
11920
  }
11902
- var DEFAULT_CF_TOKEN_ENV, DEFAULT_ANTHROPIC_ADMIN_ENV, CLOUDFLARE_PRICES, GIB, GB, DAYS_PER_MONTH, TEMPLATE_BUCKET_NAMES, TEMPLATE_WORKFLOW_NAMES, emptySplit, DEFAULT_DAYS, MAX_DAYS, NullLlmCostSource, CF_GRAPHQL, CF_USAGE_QUERY, WORKFLOW_STEP_EVENTS, num2, str2, CloudflareGraphqlUsageSource, ANTHROPIC_COST_REPORT, ANTHROPIC_VERSION, MAX_COST_PAGES, AnthropicCostReportSource, COSTS_OFF_MESSAGE, NullCostsService;
11921
+ var DEFAULT_CF_TOKEN_ENV, DEFAULT_ANTHROPIC_ADMIN_ENV, CLOUDFLARE_PRICES, GIB, GB, DAYS_PER_MONTH, TEMPLATE_BUCKET_NAMES, TEMPLATE_WORKFLOW_NAMES, emptySplit, ANTHROPIC_PRICES, DATED_RELEASE_SUFFIX, DEFAULT_DAYS, MAX_DAYS, NullLlmCostSource, CF_GRAPHQL, CF_USAGE_QUERY, WORKFLOW_STEP_EVENTS, num2, str2, CloudflareGraphqlUsageSource, ANTHROPIC_COST_REPORT, ANTHROPIC_USAGE_REPORT, ANTHROPIC_VERSION, MAX_COST_PAGES, MAX_ESTIMATED_DAYS, AnthropicCostReportSource, COSTS_OFF_MESSAGE, NullCostsService;
11903
11922
  var init_costs = __esm({
11904
11923
  "../../src/core/costs.ts"() {
11905
11924
  "use strict";
@@ -11949,6 +11968,26 @@ var init_costs = __esm({
11949
11968
  r2: 0,
11950
11969
  workflows: 0
11951
11970
  });
11971
+ ANTHROPIC_PRICES = {
11972
+ "claude-fable-5-1": { input: 10, output: 50, cacheWrite5m: 12.5, cacheWrite1h: 20, cacheRead: 0.25 },
11973
+ "claude-mythos-5-1": { input: 10, output: 50, cacheWrite5m: 12.5, cacheWrite1h: 20, cacheRead: 0.25 },
11974
+ "claude-fable-5": { input: 10, output: 50, cacheWrite5m: 12.5, cacheWrite1h: 20, cacheRead: 1 },
11975
+ "claude-mythos-5": { input: 10, output: 50, cacheWrite5m: 12.5, cacheWrite1h: 20, cacheRead: 1 },
11976
+ "claude-opus-5": { input: 5, output: 25, cacheWrite5m: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
11977
+ "claude-opus-4-8": { input: 5, output: 25, cacheWrite5m: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
11978
+ "claude-opus-4-7": { input: 5, output: 25, cacheWrite5m: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
11979
+ "claude-opus-4-6": { input: 5, output: 25, cacheWrite5m: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
11980
+ "claude-opus-4-5": { input: 5, output: 25, cacheWrite5m: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
11981
+ "claude-opus-4-1": { input: 15, output: 75, cacheWrite5m: 18.75, cacheWrite1h: 30, cacheRead: 1.5 },
11982
+ "claude-opus-4": { input: 15, output: 75, cacheWrite5m: 18.75, cacheWrite1h: 30, cacheRead: 1.5 },
11983
+ "claude-sonnet-5": { input: 2, output: 10, cacheWrite5m: 2.5, cacheWrite1h: 4, cacheRead: 0.2 },
11984
+ "claude-sonnet-4-6": { input: 3, output: 15, cacheWrite5m: 3.75, cacheWrite1h: 6, cacheRead: 0.3 },
11985
+ "claude-sonnet-4-5": { input: 3, output: 15, cacheWrite5m: 3.75, cacheWrite1h: 6, cacheRead: 0.3 },
11986
+ "claude-sonnet-4": { input: 3, output: 15, cacheWrite5m: 3.75, cacheWrite1h: 6, cacheRead: 0.3 },
11987
+ "claude-haiku-4-5": { input: 1, output: 5, cacheWrite5m: 1.25, cacheWrite1h: 2, cacheRead: 0.1 },
11988
+ "claude-haiku-3-5": { input: 0.8, output: 4, cacheWrite5m: 1, cacheWrite1h: 1.6, cacheRead: 0.08 }
11989
+ };
11990
+ DATED_RELEASE_SUFFIX = /^-\d{8}$/;
11952
11991
  DEFAULT_DAYS = 30;
11953
11992
  MAX_DAYS = 90;
11954
11993
  NullLlmCostSource = class {
@@ -12062,8 +12101,10 @@ var init_costs = __esm({
12062
12101
  }
12063
12102
  };
12064
12103
  ANTHROPIC_COST_REPORT = "https://api.anthropic.com/v1/organizations/cost_report";
12104
+ ANTHROPIC_USAGE_REPORT = "https://api.anthropic.com/v1/organizations/usage_report/messages";
12065
12105
  ANTHROPIC_VERSION = "2023-06-01";
12066
12106
  MAX_COST_PAGES = 20;
12107
+ MAX_ESTIMATED_DAYS = 3;
12067
12108
  AnthropicCostReportSource = class {
12068
12109
  adminKey;
12069
12110
  fetchImpl;
@@ -12072,7 +12113,79 @@ var init_costs = __esm({
12072
12113
  this.fetchImpl = opts.fetchImpl ?? fetch;
12073
12114
  }
12074
12115
  async fetchDailyCost(range) {
12116
+ const report2 = await this.fetchCostReport(range);
12117
+ const open2 = eachDay(range).filter((date) => report2.closedThrough === null || date > report2.closedThrough);
12118
+ const estimated = await Promise.all(open2.slice(-MAX_ESTIMATED_DAYS).map((date) => this.estimateDay(date)));
12119
+ return [...report2.rows, ...estimated.flat()];
12120
+ }
12121
+ /** The hourly usage report for one day, summed per workspace × model and
12122
+ * priced at list; one row per workspace, `estimated`, with the tokens of
12123
+ * any model the price table does not know reported as `unpricedTokens`. */
12124
+ async estimateDay(date) {
12125
+ const perWorkspace = /* @__PURE__ */ new Map();
12126
+ let page2 = null;
12127
+ for (let i = 0; ; i++) {
12128
+ if (i >= MAX_COST_PAGES)
12129
+ throw new Error(
12130
+ `anthropic usage_report: more than ${MAX_COST_PAGES} pages for ${date}; refusing a truncated estimate`
12131
+ );
12132
+ const url = new URL(ANTHROPIC_USAGE_REPORT);
12133
+ url.searchParams.set("starting_at", `${date}T00:00:00Z`);
12134
+ url.searchParams.set("ending_at", `${addDays2(date, 1)}T00:00:00Z`);
12135
+ url.searchParams.set("bucket_width", "1h");
12136
+ url.searchParams.append("group_by[]", "workspace_id");
12137
+ url.searchParams.append("group_by[]", "model");
12138
+ url.searchParams.set("limit", "24");
12139
+ if (page2) url.searchParams.set("page", page2);
12140
+ const res = await this.fetchImpl(url.toString(), {
12141
+ headers: { "x-api-key": this.adminKey, "anthropic-version": ANTHROPIC_VERSION }
12142
+ });
12143
+ if (res.status !== 200)
12144
+ throw new Error(`anthropic usage_report ${res.status}: ${(await res.text()).slice(0, 300)}`);
12145
+ const body = await res.json();
12146
+ for (const bucket of body.data ?? []) {
12147
+ for (const r of bucket.results ?? []) {
12148
+ const ws = r.workspace_id ?? null;
12149
+ const byModel = perWorkspace.get(ws) ?? /* @__PURE__ */ new Map();
12150
+ const model = str2(r.model);
12151
+ const t = byModel.get(model) ?? {
12152
+ uncachedInput: 0,
12153
+ output: 0,
12154
+ cacheRead: 0,
12155
+ cacheWrite5m: 0,
12156
+ cacheWrite1h: 0
12157
+ };
12158
+ t.uncachedInput += num2(r.uncached_input_tokens);
12159
+ t.output += num2(r.output_tokens);
12160
+ t.cacheRead += num2(r.cache_read_input_tokens);
12161
+ t.cacheWrite5m += num2(r.cache_creation?.ephemeral_5m_input_tokens);
12162
+ t.cacheWrite1h += num2(r.cache_creation?.ephemeral_1h_input_tokens);
12163
+ byModel.set(model, t);
12164
+ perWorkspace.set(ws, byModel);
12165
+ }
12166
+ }
12167
+ if (!body.has_more || !body.next_page) break;
12168
+ page2 = body.next_page;
12169
+ }
12170
+ const out = [];
12171
+ for (const [workspaceId, byModel] of perWorkspace) {
12172
+ let amountUsd = 0;
12173
+ let unpricedTokens = 0;
12174
+ for (const [model, t] of byModel) {
12175
+ const usd = anthropicTokensCostUsd(model, t);
12176
+ if (usd === void 0)
12177
+ unpricedTokens += t.uncachedInput + t.output + t.cacheRead + t.cacheWrite5m + t.cacheWrite1h;
12178
+ else amountUsd += usd;
12179
+ }
12180
+ out.push({ date, workspaceId, amountUsd, estimated: true, unpricedTokens });
12181
+ }
12182
+ return out;
12183
+ }
12184
+ /** Every page of the cost report for the range, plus the last day it has a
12185
+ * bucket for (null when it has none in the range). */
12186
+ async fetchCostReport(range) {
12075
12187
  const rows = [];
12188
+ let closedThrough = null;
12076
12189
  let page2 = null;
12077
12190
  for (let i = 0; ; i++) {
12078
12191
  if (i >= MAX_COST_PAGES)
@@ -12094,6 +12207,7 @@ var init_costs = __esm({
12094
12207
  const body = await res.json();
12095
12208
  for (const bucket of body.data ?? []) {
12096
12209
  const date = str2(bucket.starting_at).slice(0, 10);
12210
+ if (closedThrough === null || date > closedThrough) closedThrough = date;
12097
12211
  for (const r of bucket.results ?? []) {
12098
12212
  if (r.currency !== "USD") throw new Error(`anthropic cost_report: unexpected currency ${r.currency ?? "?"}`);
12099
12213
  const cents = Number(r.amount);
@@ -12104,7 +12218,7 @@ var init_costs = __esm({
12104
12218
  if (!body.has_more || !body.next_page) break;
12105
12219
  page2 = body.next_page;
12106
12220
  }
12107
- return rows;
12221
+ return { rows, closedThrough };
12108
12222
  }
12109
12223
  };
12110
12224
  COSTS_OFF_MESSAGE = "Cost reporting isn't configured \u2014 set costs.cloudflareAccountId + costs.groups in config and the CF_ANALYTICS_TOKEN secret to enable this view.";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreplane/switchboard",
3
- "version": "1.221.1",
3
+ "version": "1.222.0",
4
4
  "description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://openswitchboard.dev",
@@ -1 +0,0 @@
1
- import{t as e}from"./AppShell-lYVcj-k7.js";import{Ci as t,Lr as n,Xt as r,_n as i,cn as a,gn as o,ir as s,ln as c,on as l,r as u,sn as d,un as f,ur as p,vi as m,wi as h,xi as g,yn as _}from"./seed-DeKSHrt2.js";var v=`Durable Objects`,y=`Workers · storage · R2`,b=`LLM (Anthropic)`,x=(e,t=2)=>`$${e.toFixed(t)}`,S=e=>e.workersUsd+e.doRowsUsd+e.doStorageUsd+e.r2Usd+e.workflowsUsd;function ee(e){let t=[];for(let n of e.days)for(let e of Object.keys(n.containers))t.includes(e)||t.push(e);return e.days.some(e=>Object.keys(e.durableObjects).length>0)&&t.push(v),e.days.some(e=>S(e)>0)&&t.push(y),e.llmAvailable&&t.push(b),t}function C(e,t){return t===`Durable Objects`?Object.values(e.durableObjects).reduce((e,t)=>e+t,0)+e.doRequestsUsd:t===`Workers · storage · R2`?S(e):t===`LLM (Anthropic)`?e.llmUsd:e.containers[t]?.total??0}function w(e){let t=e.range.partialLastDay?e.days.slice(0,-1):e.days,n=t[t.length-1],r=t.slice(-7),i=r.length?r.reduce((e,t)=>e+t.total,0)/r.length:0,a=e.totals.total>0?Math.round(e.totals.llmUsd/e.totals.total*100):0,o=e.account.cloudUsd>0?Math.round(e.totals.cloudUsd/e.account.cloudUsd*100):0;return{...n?{yesterday:{date:n.date,total:n.total}}:{},avg7:i,projectedMonth:i*30.4,llmShare:a,accountShare:o}}function T(e,t){let n={t:12,r:12,b:30,l:48},r=960-n.l-n.r,i=260-n.t-n.b,a=e.days,o=Math.max(1e-9,...a.map(e=>e.total))*1.08,s=r/Math.max(1,a.length),c=Math.min(10,s*.28),l=e=>n.t+i-e/o*i,u=Array.from({length:5},(e,t)=>{let n=o/4*t;return{y:Number(l(n).toFixed(1)),label:x(n)}}),d=[],f=[];return a.forEach((e,r)=>{let i=0,o=n.l+r*s+c/2,u=s-c;t.forEach((t,n)=>{let r=C(e,t);if(r<=0)return;let a=l(i+r),s=l(i),c=Math.max(0,s-a-2);d.push({seriesIndex:n,x:Number(o.toFixed(1)),y:Number(a.toFixed(1)),width:Number(u.toFixed(1)),height:Number(c.toFixed(1)),title:`${e.date} · ${t} · ${x(r)}`}),i+=r}),(a.length<=16||r%Math.ceil(a.length/16)===0)&&f.push({x:Number((o+u/2).toFixed(1)),label:e.date.slice(5)})}),{width:960,height:260,gridLines:u,segments:d,dayLabels:f,axisY:Number(l(0).toFixed(1)),marginLeft:n.l,marginRight:n.r}}function E(e){let t=e.totals.byResource,n=[[`Memory (provisioned while awake)`,t.memory],[`vCPU (active use only)`,t.cpu],[`Durable Object duration + requests`,t.durableObjects],[`Disk (provisioned while awake)`,t.disk],[`Workers requests + CPU`,t.workers],[`Durable Object SQLite rows`,t.doRows],[`Durable Object SQLite storage`,t.doStorage],[`R2 storage + operations`,t.r2],[`Workflow steps + state`,t.workflows]],r=n.reduce((e,t)=>e+t[1],0)||1;return n.map(([e,t])=>({label:e,usd:t,percent:t/r*100}))}var D=[`fill-[#4478b8] dark:fill-[#7aa7e0]`,`fill-[#c8823b] dark:fill-[#e0a95a]`,`fill-[#4c8c57] dark:fill-[#6fae7a]`,`fill-[#b8963e] dark:fill-[#d4b45a]`,`fill-[#b0568c] dark:fill-[#d489b8]`,`fill-[#6b7bcc] dark:fill-[#98a5e6]`,`fill-[#d05252] dark:fill-[#e07a74]`,`fill-[#3e8e96] dark:fill-[#6fb9c0]`],O=[`bg-[#4478b8] dark:bg-[#7aa7e0]`,`bg-[#c8823b] dark:bg-[#e0a95a]`,`bg-[#4c8c57] dark:bg-[#6fae7a]`,`bg-[#b8963e] dark:bg-[#d4b45a]`,`bg-[#b0568c] dark:bg-[#d489b8]`,`bg-[#6b7bcc] dark:bg-[#98a5e6]`,`bg-[#d05252] dark:bg-[#e07a74]`,`bg-[#3e8e96] dark:bg-[#6fb9c0]`],k={class:`overflow-x-auto`},A=[`viewBox`],j=[`x1`,`x2`,`y1`,`y2`],M=[`x`,`y`],N=[`x`,`y`,`width`,`height`],P=[`x`,`y`],F=[`x1`,`x2`,`y1`,`y2`],I=_({__name:`CostChart`,props:{report:{},series:{}},setup(e){let t=e,n=l(()=>T(t.report,t.series));return(e,t)=>(s(),f(`div`,k,[(s(),f(`svg`,{class:`block h-auto w-full font-mono`,viewBox:`0 0 ${n.value.width} ${n.value.height}`,role:`img`,"aria-label":`Daily cost, stacked by component`},[(s(!0),f(r,null,p(n.value.gridLines,(e,t)=>(s(),f(r,{key:`g${t}`},[d(`line`,{class:`stroke-(--ui-border-muted)`,x1:n.value.marginLeft,x2:n.value.width-n.value.marginRight,y1:e.y,y2:e.y},null,8,j),d(`text`,{class:`fill-(--ui-text-dimmed) text-[11px] tabular-nums`,x:n.value.marginLeft-8,y:e.y+4,"text-anchor":`end`},h(e.label),9,M)],64))),128)),(s(!0),f(r,null,p(n.value.segments,(e,t)=>(s(),f(`rect`,{key:`s${t}`,class:g([`seg hover:opacity-85`,m(D)[e.seriesIndex%m(D).length]]),x:e.x,y:e.y,width:e.width,height:e.height},[d(`title`,null,h(e.title),1)],10,N))),128)),(s(!0),f(r,null,p(n.value.dayLabels,(e,t)=>(s(),f(`text`,{key:`d${t}`,class:`fill-(--ui-text-dimmed) text-[11px]`,x:e.x,y:n.value.height-10,"text-anchor":`middle`},h(e.label),9,P))),128)),d(`line`,{class:`stroke-(--ui-border)`,x1:n.value.marginLeft,x2:n.value.width-n.value.marginRight,y1:n.value.axisY,y2:n.value.axisY},null,8,F)],8,A))]))}}),L={class:`text-xs text-muted`},R={key:1,class:`text-highlighted`},z=[`href`],B={class:`mb-4 flex flex-wrap items-center gap-x-4 gap-y-2`},V={key:0,class:`flex items-center gap-1`,"aria-label":`Cost groups`},H={key:0,class:`rounded-md bg-accented px-2.5 py-1 text-xs font-medium text-highlighted`,"aria-current":`page`},U=[`href`],W={class:`font-mono text-sm tabular-nums text-muted`},G={class:`mb-5 grid grid-cols-[repeat(auto-fit,minmax(190px,1fr))] gap-3`},K={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},q={class:`font-mono text-2xl font-medium tabular-nums`},J={class:`text-xs text-muted`},Y={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},X={class:`font-mono text-2xl font-medium tabular-nums`},Z={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},Q={class:`font-mono text-2xl font-medium tabular-nums`},te={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},ne={class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},re={class:`font-mono text-2xl font-medium tabular-nums`},ie={class:`text-xs text-muted`},ae={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},oe={class:`font-mono text-2xl font-medium tabular-nums`},se={class:`text-xs text-muted`},ce={class:`mb-5 grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`},le={class:`flex flex-wrap items-baseline justify-between gap-x-4 gap-y-2`},ue={class:`legend flex flex-wrap gap-x-4 gap-y-1.5 text-xs text-muted`},de={key:0,class:`text-xs text-warn`},fe={class:`mb-5 grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`},pe={class:`w-full border-collapse font-mono text-[0.8125rem] tabular-nums`},me={class:`px-2.5 py-1.5`},he={class:`px-2.5 py-1.5 text-right`},ge={class:`px-2.5 py-1.5 text-right`},_e={class:`w-2/5 px-2.5 py-1.5`},ve={class:`mb-5 grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`},ye={open:``},be={class:`mt-2.5 overflow-x-auto`},$={class:`data w-full min-w-[38rem] border-collapse whitespace-nowrap font-mono text-[0.8125rem] tabular-nums`},xe=[`title`],Se={key:0,class:`text-xs text-dimmed`},Ce={class:`border-b border-muted px-2.5 py-1.5 text-right font-medium`},we={class:`text-xs text-muted`},Te={class:`rounded bg-accented px-1 py-0.5`},Ee={class:`border-t border-default pt-3.5 text-xs text-dimmed`},De={class:`mt-2 grid gap-1.5`},Oe=_({__name:`CostsPage`,setup(_){let v=u(`costs`),y=l(()=>v?.report??null),b=l(()=>v?.groups??[]),S=l(()=>y.value?ee(y.value):[]),T=l(()=>y.value?w(y.value):null),D=l(()=>y.value?E(y.value):[]),k=[7,30,90];function A(e){let t=new Date(`${e}T00:00:00Z`);return Number.isNaN(t.getTime())?e:`${[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`][t.getUTCMonth()]} ${t.getUTCDate()}`}return(l,u)=>y.value&&T.value?(s(),a(e,{key:0,title:`${y.value.label} spend`,nav:`costs`},{actions:n(()=>[d(`span`,L,[(s(),f(r,null,p(k,(e,t)=>(s(),f(r,{key:e},[t>0?(s(),f(r,{key:0},[o(` · `)],64)):c(``,!0),e===y.value.range.days?(s(),f(`b`,R,h(e)+`d`,1)):(s(),f(`a`,{key:2,class:`text-primary hover:underline`,href:`/costs/${y.value.group}?days=${e}`},h(e)+`d`,9,z))],64))),64))])]),default:n(()=>[d(`div`,B,[b.value.length>1?(s(),f(`nav`,V,[(s(!0),f(r,null,p(b.value,e=>(s(),f(r,{key:e},[e===y.value.group?(s(),f(`span`,H,h(e),1)):(s(),f(`a`,{key:1,class:`rounded-md px-2.5 py-1 text-xs text-muted no-underline hover:bg-elevated hover:text-highlighted`,href:`/costs/${e}`},h(e),9,U))],64))),128))])):c(``,!0),d(`p`,W,[o(h(A(y.value.range.from))+` → `+h(A(y.value.range.to))+` · `+h(y.value.range.days)+`d`,1),y.value.range.partialLastDay?(s(),f(r,{key:0},[o(` · today partial`)],64)):c(``,!0)])]),d(`section`,G,[d(`div`,K,[u[0]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Yesterday`,-1),d(`span`,q,h(T.value.yesterday?m(x)(T.value.yesterday.total):`—`),1),d(`span`,J,h(T.value.yesterday?`${T.value.yesterday.date} · last full day`:`no full day in range`),1)]),d(`div`,Y,[u[1]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`7-day average`,-1),d(`span`,X,h(m(x)(T.value.avg7)),1),u[2]||=d(`span`,{class:`text-xs text-muted`},`per day, full days only`,-1)]),d(`div`,Z,[u[3]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Projected month`,-1),d(`span`,Q,h(m(x)(T.value.projectedMonth,0)),1),u[4]||=d(`span`,{class:`text-xs text-muted`},`7-day rate × 30.4, before plan fees and included allowances`,-1)]),d(`div`,te,[d(`span`,ne,h(y.value.llmAvailable?`LLM share`:`LLM spend`),1),d(`span`,re,h(y.value.llmAvailable?`${T.value.llmShare}%`:`—`),1),d(`span`,ie,h(y.value.llmAvailable?`of the range total`:`LLM spend not configured`),1)]),d(`div`,ae,[u[5]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Share of account`,-1),d(`span`,oe,h(T.value.accountShare)+`%`,1),d(`span`,se,h(m(x)(y.value.totals.cloudUsd))+` of `+h(m(x)(y.value.account.cloudUsd))+` Cloudflare spend in range`,1)])]),d(`section`,ce,[d(`div`,le,[u[6]||=d(`div`,null,[d(`h2`,{class:`text-[0.9375rem] font-medium`},`Daily cost`),d(`p`,{class:`text-sm text-muted`},`Stacked by component · USD list price`)],-1),d(`div`,ue,[(s(!0),f(r,null,p(S.value,(e,t)=>(s(),f(`span`,{key:e,class:`inline-flex items-center gap-1.5`},[d(`i`,{class:g([`inline-block size-2.5 rounded-xs`,m(O)[t%m(O).length]])},null,2),o(h(e),1)]))),128))])]),i(I,{report:y.value,series:S.value},null,8,[`report`,`series`]),y.value.llmAvailable?c(``,!0):(s(),f(`p`,de,[...u[7]||=[o(` LLM spend not configured — set `,-1),d(`code`,null,`ANTHROPIC_ADMIN_KEY`,-1),o(` and the group's `,-1),d(`code`,null,`anthropicWorkspaceId`,-1),o(` to layer it in. `,-1)]]))]),d(`section`,fe,[u[8]||=d(`div`,null,[d(`h2`,{class:`text-[0.9375rem] font-medium`},`What each cloud dollar buys`)],-1),d(`table`,pe,[d(`tbody`,null,[(s(!0),f(r,null,p(D.value,e=>(s(),f(`tr`,{key:e.label,class:`border-b border-muted`},[d(`td`,me,h(e.label),1),d(`td`,he,h(m(x)(e.usd)),1),d(`td`,ge,h(Math.round(e.percent))+`%`,1),d(`td`,_e,[d(`i`,{class:`block h-2.5 rounded-xs bg-primary opacity-75`,style:t({width:`${e.percent.toFixed(1)}%`})},null,4)])]))),128))])])]),d(`section`,ve,[d(`details`,ye,[u[11]||=d(`summary`,{class:`cursor-pointer text-sm text-muted`},`Table view — daily cost by component (USD)`,-1),d(`div`,be,[d(`table`,$,[d(`thead`,null,[d(`tr`,null,[u[9]||=d(`th`,{class:`border-b border-muted bg-(--ui-bg-muted) px-2.5 py-1.5 text-left text-xs font-medium text-muted`},` Date `,-1),(s(!0),f(r,null,p(S.value,e=>(s(),f(`th`,{key:e,class:`border-b border-muted bg-(--ui-bg-muted) px-2.5 py-1.5 text-right text-xs font-medium text-muted`},h(e),1))),128)),u[10]||=d(`th`,{class:`border-b border-muted bg-(--ui-bg-muted) px-2.5 py-1.5 text-right text-xs font-medium text-muted`},` Total `,-1)])]),d(`tbody`,null,[(s(!0),f(r,null,p(y.value.days,e=>(s(),f(`tr`,{key:e.date},[d(`td`,{class:`border-b border-muted px-2.5 py-1.5`,title:e.date},[o(h(A(e.date))+` `,1),y.value.range.partialLastDay&&e.date===y.value.range.to?(s(),f(`span`,Se,`(partial day)`)):c(``,!0)],8,xe),(s(!0),f(r,null,p(S.value,t=>(s(),f(`td`,{key:t,class:`border-b border-muted px-2.5 py-1.5 text-right`},h(m(x)(m(C)(e,t),3)),1))),128)),d(`td`,Ce,h(m(x)(e.total,3)),1)]))),128))])])])]),d(`p`,we,[u[12]||=o(` Machine-readable twin: `,-1),d(`code`,Te,`GET /costs/`+h(y.value.group)+`.json`,1),u[13]||=o(` (same Access gate). `,-1)])]),d(`footer`,Ee,[d(`details`,null,[u[18]||=d(`summary`,{class:`cursor-pointer text-muted`},`How these numbers are computed`,-1),d(`div`,De,[u[16]||=d(`div`,null,[d(`b`,null,`Live.`),o(` Both billing sources are read live from this page — nothing cached, nothing stored. Cloudflare bills vCPU on active use only; memory and disk bill on the provisioned size for every second a container is awake. LLM spend is the Anthropic Admin API cost report for this group's workspace (gross, USD). `)],-1),u[17]||=d(`div`,null,[d(`b`,null,`Method.`),o(` Cloudflare GraphQL Analytics, every meter a Workers deployment is billed on: `),d(`code`,null,`containersUsageAdaptiveGroups`),o(` (cpuTimeSec, allocatedMemory, allocatedDisk per app per UTC day), `),d(`code`,null,`durableObjectsPeriodicGroups`),o(` (billable `),d(`code`,null,`duration`),o(` GB-s and SQLite rows read and written per namespace), `),d(`code`,null,`durableObjectsInvocationsAdaptiveGroups`),o(` (requests per namespace), `),d(`code`,null,`durableObjectsSqlStorageGroups`),o(` (bytes stored), `),d(`code`,null,`workersInvocationsAdaptive`),o(` (requests, CPU time), `),d(`code`,null,`r2StorageAdaptiveGroups`),o(` and `),d(`code`,null,`r2OperationsAdaptiveGroups`),o(` (bytes stored, class A/B operations). Prices: vCPU $0.000020/s, memory $0.0000025/GiB-s, disk $0.00000007/GB-s, DO duration $12.50 per million GB-s, DO requests $0.15/M, SQLite rows $0.001/M read and $1.00/M written, DO storage $0.20/GB-month, Workers $0.30/M requests and $0.02/M CPU-ms, R2 $0.015/GB-month, $4.50/M class A and $0.36/M class B (deletes free). Storage is the day's peak, prorated over a 30.44-day month. Gross list price — plan fees and included allowances are not subtracted; Workers Logs volume has no analytics dataset and is not priced. `)],-1),d(`div`,null,[u[14]||=d(`b`,null,`Scope.`,-1),u[15]||=o(` Attributed to this group: the Workers `,-1),d(`code`,null,h(y.value.attribution.workers.join(`, `)),1),o(`, every Durable Object namespace they host (`+h(Object.keys(y.value.attribution.durableObjectNamespaces).length)+`), the R2 buckets named after them (`+h(Object.keys(y.value.attribution.r2Buckets).length)+`), and the container apps mapped in `,1),d(`code`,null,`costs.groups.`+h(y.value.group),1),o(` (`+h(Object.keys(y.value.attribution.containerApps).length)+`). Everything else in the account is priced the same way into the account total, which is what "share of account" divides by. `,1)])])])])]),_:1},8,[`title`])):c(``,!0)}});export{Oe as default};