tokentracker-cli 0.2.27 → 0.3.3

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.
@@ -836,8 +836,39 @@ async function parseClaudeFile({
836
836
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
837
837
 
838
838
  let eventsAggregated = 0;
839
+ const isMainSession = !filePath.includes("/subagents/");
839
840
  for await (const line of rl) {
840
- if (!line || !line.includes('\"usage\"')) continue;
841
+ if (!line) continue;
842
+
843
+ // Count user-typed messages as conversations (main sessions only).
844
+ // Exclude tool_result messages — those are auto-generated by tool calls,
845
+ // not manually typed by the user. Only count messages with a "text" block.
846
+ if (isMainSession && line.includes('"type":"user"')) {
847
+ let userObj;
848
+ try {
849
+ userObj = JSON.parse(line);
850
+ } catch (_e) {
851
+ /* skip */
852
+ }
853
+ if (userObj?.type === "user") {
854
+ const content = userObj?.message?.content;
855
+ const hasText =
856
+ typeof content === "string" ||
857
+ (Array.isArray(content) && content.some((b) => b?.type === "text"));
858
+ if (hasText) {
859
+ const userTs = typeof userObj?.timestamp === "string" ? userObj.timestamp : null;
860
+ const userBucketStart = userTs ? toUtcHalfHourStart(userTs) : null;
861
+ if (userBucketStart) {
862
+ const userModel = DEFAULT_MODEL;
863
+ const userBucket = getHourlyBucket(hourlyState, source, userModel, userBucketStart);
864
+ userBucket.totals.conversation_count += 1;
865
+ touchedBuckets.add(bucketKey(source, userModel, userBucketStart));
866
+ }
867
+ }
868
+ }
869
+ }
870
+
871
+ if (!line.includes('"usage"')) continue;
841
872
  let obj;
842
873
  try {
843
874
  obj = JSON.parse(line);
@@ -864,7 +895,7 @@ async function parseClaudeFile({
864
895
 
865
896
  const delta = normalizeClaudeUsage(usage);
866
897
  if (!delta || isAllZeroUsage(delta)) continue;
867
- delta.conversation_count = 1;
898
+ delta.conversation_count = 0;
868
899
 
869
900
  const bucketStart = toUtcHalfHourStart(tokenTimestamp);
870
901
  if (!bucketStart) continue;
@@ -2483,16 +2514,299 @@ async function resolveProjectContextForDb({
2483
2514
  });
2484
2515
  }
2485
2516
 
2517
+ // ── Cursor (API-based) ──
2518
+
2519
+ /**
2520
+ * Incremental parser for Cursor usage data fetched via API.
2521
+ *
2522
+ * Unlike other parsers that read local files, this one receives pre-parsed
2523
+ * CSV records from cursor-config.js and aggregates them into 30-min buckets.
2524
+ *
2525
+ * Incremental state is tracked in `cursors.cursorApi.lastRecordTimestamp`.
2526
+ */
2527
+ async function parseCursorApiIncremental({
2528
+ records,
2529
+ cursors,
2530
+ queuePath,
2531
+ onProgress,
2532
+ source,
2533
+ }) {
2534
+ await ensureDir(path.dirname(queuePath));
2535
+ const defaultSource = normalizeSourceInput(source) || "cursor";
2536
+ const hourlyState = normalizeHourlyState(cursors?.hourly);
2537
+ const touchedBuckets = new Set();
2538
+
2539
+ // Incremental: skip records we already processed
2540
+ const lastTs = cursors?.cursorApi?.lastRecordTimestamp || null;
2541
+ let latestTs = lastTs;
2542
+ let eventsAggregated = 0;
2543
+ const cb = typeof onProgress === "function" ? onProgress : null;
2544
+ const total = records.length;
2545
+
2546
+ for (let i = 0; i < records.length; i++) {
2547
+ const record = records[i];
2548
+ const recordDate = record.date;
2549
+ if (!recordDate) continue;
2550
+
2551
+ // Skip records we already processed (CSV is ordered newest-first)
2552
+ if (lastTs && recordDate <= lastTs) continue;
2553
+
2554
+ const { normalizeCursorUsage } = require("./cursor-config");
2555
+ const delta = normalizeCursorUsage(record);
2556
+ if (isAllZeroUsage(delta)) continue;
2557
+
2558
+ delta.conversation_count = 1;
2559
+
2560
+ const bucketStart = toUtcHalfHourStart(recordDate);
2561
+ if (!bucketStart) continue;
2562
+
2563
+ const model = normalizeModelInput(record.model) || DEFAULT_MODEL;
2564
+ const bucket = getHourlyBucket(hourlyState, defaultSource, model, bucketStart);
2565
+ addTotals(bucket.totals, delta);
2566
+ touchedBuckets.add(bucketKey(defaultSource, model, bucketStart));
2567
+
2568
+ eventsAggregated += 1;
2569
+
2570
+ // Track latest timestamp
2571
+ if (!latestTs || recordDate > latestTs) {
2572
+ latestTs = recordDate;
2573
+ }
2574
+
2575
+ if (cb && (i % 200 === 0 || i === records.length - 1)) {
2576
+ cb({
2577
+ index: i + 1,
2578
+ total,
2579
+ eventsAggregated,
2580
+ bucketsQueued: touchedBuckets.size,
2581
+ });
2582
+ }
2583
+ }
2584
+
2585
+ const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
2586
+ hourlyState.updatedAt = new Date().toISOString();
2587
+ cursors.hourly = hourlyState;
2588
+
2589
+ // Update cursor state
2590
+ if (!cursors.cursorApi) cursors.cursorApi = {};
2591
+ if (latestTs && latestTs !== lastTs) {
2592
+ cursors.cursorApi.lastRecordTimestamp = latestTs;
2593
+ }
2594
+ cursors.cursorApi.updatedAt = new Date().toISOString();
2595
+
2596
+ return { recordsProcessed: total, eventsAggregated, bucketsQueued };
2597
+ }
2598
+
2599
+ // ---------------------------------------------------------------------------
2600
+ // Kiro token tracking (reads from devdata.sqlite)
2601
+ // ---------------------------------------------------------------------------
2602
+
2603
+ function resolveKiroBasePath() {
2604
+ const home = require("node:os").homedir();
2605
+ return path.join(
2606
+ home,
2607
+ "Library",
2608
+ "Application Support",
2609
+ "Kiro",
2610
+ "User",
2611
+ "globalStorage",
2612
+ "kiro.kiroagent",
2613
+ );
2614
+ }
2615
+
2616
+ function resolveKiroDbPath() {
2617
+ return path.join(resolveKiroBasePath(), "dev_data", "devdata.sqlite");
2618
+ }
2619
+
2620
+ function readKiroDbTokens(dbPath, sinceId) {
2621
+ if (!dbPath || !fssync.existsSync(dbPath)) return [];
2622
+ const minId = Number.isFinite(sinceId) && sinceId > 0 ? sinceId : 0;
2623
+ const sql = `SELECT id, model, provider, tokens_prompt, tokens_generated, timestamp FROM tokens_generated WHERE id > ${minId} ORDER BY id ASC`;
2624
+ let raw;
2625
+ try {
2626
+ raw = cp.execFileSync("sqlite3", ["-json", dbPath, sql], {
2627
+ encoding: "utf8",
2628
+ maxBuffer: 10 * 1024 * 1024,
2629
+ timeout: 15_000,
2630
+ });
2631
+ } catch (_e) {
2632
+ return [];
2633
+ }
2634
+ if (!raw || !raw.trim()) return [];
2635
+ let rows;
2636
+ try {
2637
+ rows = JSON.parse(raw);
2638
+ } catch (_e) {
2639
+ return [];
2640
+ }
2641
+ return Array.isArray(rows) ? rows : [];
2642
+ }
2643
+
2644
+ // Build a sorted timeline of model usage from Kiro .chat metadata files
2645
+ function buildKiroModelTimeline(basePath) {
2646
+ const timeline = []; // [{ startMs, endMs, model }]
2647
+ if (!basePath || !fssync.existsSync(basePath)) return timeline;
2648
+ let dirs;
2649
+ try {
2650
+ dirs = fssync.readdirSync(basePath, { withFileTypes: true });
2651
+ } catch (_e) {
2652
+ return timeline;
2653
+ }
2654
+ for (const entry of dirs) {
2655
+ if (!entry.isDirectory()) continue;
2656
+ const dirPath = path.join(basePath, entry.name);
2657
+ let files;
2658
+ try {
2659
+ files = fssync.readdirSync(dirPath).filter((f) => f.endsWith(".chat"));
2660
+ } catch (_e) {
2661
+ continue;
2662
+ }
2663
+ for (const file of files) {
2664
+ try {
2665
+ const raw = fssync.readFileSync(path.join(dirPath, file), "utf8");
2666
+ const data = JSON.parse(raw);
2667
+ const meta = data?.metadata;
2668
+ if (!meta?.modelId || !meta?.startTime) continue;
2669
+ timeline.push({
2670
+ startMs: meta.startTime,
2671
+ endMs: meta.endTime || meta.startTime,
2672
+ model: String(meta.modelId),
2673
+ });
2674
+ } catch (_e) {}
2675
+ }
2676
+ }
2677
+ timeline.sort((a, b) => a.startMs - b.startMs);
2678
+ return timeline;
2679
+ }
2680
+
2681
+ // Find the model for a given UTC timestamp string using the .chat timeline
2682
+ function resolveKiroModel(timeline, utcTimestamp) {
2683
+ if (!timeline.length || !utcTimestamp) return null;
2684
+ const ts = new Date(utcTimestamp).getTime();
2685
+ if (!Number.isFinite(ts)) return null;
2686
+
2687
+ // Binary search for the closest .chat entry
2688
+ let lo = 0;
2689
+ let hi = timeline.length - 1;
2690
+ let best = null;
2691
+ let bestDist = Infinity;
2692
+ while (lo <= hi) {
2693
+ const mid = (lo + hi) >>> 1;
2694
+ const entry = timeline[mid];
2695
+ // Check if timestamp falls within the .chat execution window
2696
+ if (ts >= entry.startMs && ts <= entry.endMs) return entry.model;
2697
+ const dist = Math.min(Math.abs(ts - entry.startMs), Math.abs(ts - entry.endMs));
2698
+ if (dist < bestDist) {
2699
+ bestDist = dist;
2700
+ best = entry.model;
2701
+ }
2702
+ if (ts < entry.startMs) hi = mid - 1;
2703
+ else lo = mid + 1;
2704
+ }
2705
+ // Only match if within 10 minutes
2706
+ return bestDist < 10 * 60 * 1000 ? best : null;
2707
+ }
2708
+
2709
+ // Normalize Kiro internal model IDs to readable names
2710
+ // e.g. "CLAUDE_SONNET_4_20250514_V1_0" → "claude-sonnet-4"
2711
+ function normalizeKiroModelName(raw) {
2712
+ if (!raw || typeof raw !== "string") return null;
2713
+ let name = raw.trim();
2714
+ if (!name) return null;
2715
+ // Already lowercase with dashes (e.g. "claude-opus-4.5") → keep as-is
2716
+ if (name === name.toLowerCase() && name.includes("-")) return name;
2717
+ // UPPER_SNAKE_CASE internal names: strip date/version suffixes, convert to lowercase-dash
2718
+ name = name
2719
+ .replace(/_\d{8}_V\d+_\d+$/i, "") // remove _20250514_V1_0
2720
+ .replace(/_V\d+$/i, "") // remove _V1
2721
+ .toLowerCase()
2722
+ .replace(/_/g, "-");
2723
+ return name || null;
2724
+ }
2725
+
2726
+ async function parseKiroIncremental({ dbPath, cursors, queuePath, onProgress }) {
2727
+ await ensureDir(path.dirname(queuePath));
2728
+ const kiroState = cursors.kiro && typeof cursors.kiro === "object" ? cursors.kiro : {};
2729
+ const lastId = typeof kiroState.lastId === "number" ? kiroState.lastId : 0;
2730
+
2731
+ const resolvedDbPath = dbPath || resolveKiroDbPath();
2732
+ const rows = readKiroDbTokens(resolvedDbPath, lastId);
2733
+ if (rows.length === 0) {
2734
+ return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
2735
+ }
2736
+
2737
+ // Build model timeline from .chat files for model name resolution
2738
+ const basePath = resolveKiroBasePath();
2739
+ const modelTimeline = buildKiroModelTimeline(basePath);
2740
+
2741
+ const hourlyState = normalizeHourlyState(cursors?.hourly);
2742
+ const touchedBuckets = new Set();
2743
+ const cb = typeof onProgress === "function" ? onProgress : null;
2744
+ let eventsAggregated = 0;
2745
+ let maxId = lastId;
2746
+
2747
+ for (let i = 0; i < rows.length; i++) {
2748
+ const row = rows[i];
2749
+ const inputTokens = toNonNegativeInt(row.tokens_prompt);
2750
+ const outputTokens = toNonNegativeInt(row.tokens_generated);
2751
+ if (inputTokens === 0 && outputTokens === 0) continue;
2752
+
2753
+ // timestamp format: "2026-01-09 15:25:30" (UTC from SQLite DEFAULT CURRENT_TIMESTAMP)
2754
+ const ts = row.timestamp ? row.timestamp.replace(" ", "T") + "Z" : null;
2755
+ const bucketStart = ts ? toUtcHalfHourStart(ts) : null;
2756
+ if (!bucketStart) continue;
2757
+
2758
+ // Resolve actual model from .chat timeline, fallback to "kiro-agent"
2759
+ const resolvedModel = resolveKiroModel(modelTimeline, ts);
2760
+ const model = normalizeKiroModelName(resolvedModel) || "kiro-agent";
2761
+
2762
+ const delta = {
2763
+ input_tokens: inputTokens,
2764
+ cached_input_tokens: 0,
2765
+ output_tokens: outputTokens,
2766
+ reasoning_output_tokens: 0,
2767
+ total_tokens: inputTokens + outputTokens,
2768
+ conversation_count: 1,
2769
+ };
2770
+
2771
+ const bucket = getHourlyBucket(hourlyState, "kiro", model, bucketStart);
2772
+ addTotals(bucket.totals, delta);
2773
+ touchedBuckets.add(bucketKey("kiro", model, bucketStart));
2774
+ eventsAggregated++;
2775
+
2776
+ if (row.id && row.id > maxId) maxId = row.id;
2777
+
2778
+ if (cb) {
2779
+ cb({
2780
+ index: i + 1,
2781
+ total: rows.length,
2782
+ recordsProcessed: i + 1,
2783
+ eventsAggregated,
2784
+ bucketsQueued: touchedBuckets.size,
2785
+ });
2786
+ }
2787
+ }
2788
+
2789
+ const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
2790
+ hourlyState.updatedAt = new Date().toISOString();
2791
+ cursors.hourly = hourlyState;
2792
+ cursors.kiro = { lastId: maxId, updatedAt: new Date().toISOString() };
2793
+
2794
+ return { recordsProcessed: rows.length, eventsAggregated, bucketsQueued };
2795
+ }
2796
+
2486
2797
  module.exports = {
2487
2798
  listRolloutFiles,
2488
2799
  listClaudeProjectFiles,
2489
2800
  listGeminiSessionFiles,
2490
2801
  listOpencodeMessageFiles,
2491
2802
  readOpencodeDbMessages,
2803
+ resolveKiroDbPath,
2492
2804
  parseRolloutIncremental,
2493
2805
  parseClaudeIncremental,
2494
2806
  parseGeminiIncremental,
2495
2807
  parseOpencodeIncremental,
2496
2808
  parseOpencodeDbIncremental,
2497
2809
  parseOpenclawIncremental,
2810
+ parseCursorApiIncremental,
2811
+ parseKiroIncremental,
2498
2812
  };
@@ -1 +0,0 @@
1
- import{b as k,ad as Z,d as ue,ae as z,af as L,ag as le,ah as de,ai as fe,aj as me,ak as pe,al as ge,am as ke,_ as ye,an as he,ao as Te,ap as we,m}from"./main-oIbJf8pA.js";const xe="Backend runtime unavailable (InsForge). Please retry later.",p={usageSummary:"vibeusage-usage-summary",usageDaily:"vibeusage-usage-daily",usageHourly:"vibeusage-usage-hourly",usageMonthly:"vibeusage-usage-monthly",usageHeatmap:"vibeusage-usage-heatmap",usageModelBreakdown:"vibeusage-usage-model-breakdown",projectUsageSummary:"vibeusage-project-usage-summary",leaderboard:"vibeusage-leaderboard",leaderboardProfile:"vibeusage-leaderboard-profile",userStatus:"vibeusage-user-status",linkCodeInit:"vibeusage-link-code-init",publicViewProfile:"vibeusage-public-view-profile",publicVisibility:"vibeusage-public-visibility"},J="/functions",be="/api/functions",h={business:"business",probe:"probe"};let D=null;async function f(e){return await ue(e)}async function Ee({baseUrl:e,accessToken:s,signal:t}={}){const a=await f(s),n=we(new Date);return await y({baseUrl:e,accessToken:a,slug:p.usageSummary,params:{from:n,to:n},fetchOptions:{cache:"no-store",signal:t},retry:!1,requestKind:h.probe}),{status:200}}async function Ce({baseUrl:e,accessToken:s,from:t,to:a,source:n,model:r,timeZone:l,tzOffsetMinutes:i,rolling:c=!1}={}){const u=await f(s);if(k())return de({from:t,to:a,seed:u,rolling:c});const o=M({timeZone:l,tzOffsetMinutes:i}),d=P({source:n,model:r}),v=c?{rolling:"1"}:{};return y({baseUrl:e,accessToken:u,slug:p.usageSummary,params:{from:t,to:a,...d,...o,...v}})}async function je({baseUrl:e,accessToken:s,from:t,to:a,source:n,limit:r,timeZone:l,tzOffsetMinutes:i}={}){const c=await f(s);if(k())return me({seed:c,limit:r});const u=M({timeZone:l,tzOffsetMinutes:i}),d={...P({source:n}),...u};return t&&(d.from=t),a&&(d.to=a),r!=null&&(d.limit=String(r)),y({baseUrl:e,accessToken:c,slug:p.projectUsageSummary,params:d})}async function Ie({baseUrl:e,accessToken:s,period:t,metric:a,limit:n,offset:r}={}){const l=await f(s);if(k())return Z({seed:l,period:t,metric:a,limit:n,offset:r});const c=(typeof t=="string"?t:"week").trim().toLowerCase(),o={period:c==="month"||c==="total"||c==="week"?c:"week"};return a&&(o.metric=String(a)),n!=null&&(o.limit=String(n)),r!=null&&(o.offset=String(r)),y({baseUrl:e,accessToken:l,slug:p.leaderboard,params:o})}async function Ne({baseUrl:e,accessToken:s}={}){const t=await f(s);return k()?{enabled:!1,updated_at:null,share_token:null}:y({baseUrl:e,accessToken:t,slug:p.publicVisibility})}async function De({baseUrl:e,accessToken:s,enabled:t}={}){const a=await f(s);return k()?{enabled:!!t,updated_at:new Date().toISOString(),share_token:t?"pv1-mock-token":null}:X({baseUrl:e,accessToken:a,slug:p.publicVisibility,body:{enabled:!!t}})}async function Le({baseUrl:e,accessToken:s,userId:t,period:a}={}){const n=await f(s);if(k()){const r=Z({seed:n,period:a,metric:"all",limit:250,offset:0}),i=(Array.isArray(r?.entries)?r.entries:[]).find(c=>c?.user_id===t)||null;return{period:r?.period??"week",from:r?.from??null,to:r?.to??null,generated_at:r?.generated_at??new Date().toISOString(),entry:i?{user_id:i.user_id??null,display_name:i.display_name??null,avatar_url:i.avatar_url??null,rank:i.rank??null,gpt_tokens:i.gpt_tokens??"0",claude_tokens:i.claude_tokens??"0",other_tokens:i.other_tokens??"0",total_tokens:i.total_tokens??"0"}:null}}return y({baseUrl:e,accessToken:n,slug:p.leaderboardProfile,params:{user_id:String(t||""),period:String(a||"")}})}async function He({baseUrl:e,accessToken:s}={}){const t=await f(s);if(k()){const a=new Date().toISOString();return{user_id:"mock-user",created_at:a,pro:{active:!0,sources:["mock"],expires_at:null,partial:!1,as_of:a},subscriptions:{partial:!1,as_of:a,items:[{tool:"codex",provider:"openai",product:"chatgpt",plan_type:"pro",updated_at:a},{tool:"claude",provider:"anthropic",product:"subscription",plan_type:"max",rate_limit_tier:"default_claude_max_5x",updated_at:a}]},install:{partial:!1,as_of:a,has_active_device_token:!1,has_active_device:!1,active_device_tokens:0,active_devices:0,latest_token_activity_at:null,latest_device_seen_at:null}}}return y({baseUrl:e,accessToken:t,slug:p.userStatus})}async function ze({signal:e}={}){const s=await fetch("/functions/vibeusage-local-sync",{method:"POST",headers:{Accept:"application/json"},cache:"no-store",signal:e}),t=await s.json().catch(()=>({ok:!1,error:`Local sync request failed with HTTP ${s.status}`}));if(!s.ok||t?.ok===!1){const a=t?.error||t?.message||`Local sync request failed with HTTP ${s.status}`,n=new Error(a);throw n.status=s.status,n.statusCode=s.status,n.payload=t,n}return t}async function Ue({baseUrl:e,accessToken:s,from:t,to:a,source:n,timeZone:r,tzOffsetMinutes:l}={}){const i=await f(s);if(k())return fe({from:t,to:a,seed:i});const c=M({timeZone:r,tzOffsetMinutes:l}),u=P({source:n});return y({baseUrl:e,accessToken:i,slug:p.usageModelBreakdown,params:{from:t,to:a,...u,...c}})}async function Be({baseUrl:e,accessToken:s,from:t,to:a,source:n,model:r,timeZone:l,tzOffsetMinutes:i}={}){const c=await f(s);if(k())return le({from:t,to:a,seed:c});const u=M({timeZone:l,tzOffsetMinutes:i}),o=P({source:n,model:r});return y({baseUrl:e,accessToken:c,slug:p.usageDaily,params:{from:t,to:a,...o,...u}})}async function Oe({baseUrl:e,accessToken:s,day:t,source:a,model:n,timeZone:r,tzOffsetMinutes:l}={}){const i=await f(s);if(k())return pe({day:t,seed:i});const c=M({timeZone:r,tzOffsetMinutes:l}),u=P({source:a,model:n});return y({baseUrl:e,accessToken:i,slug:p.usageHourly,params:t?{day:t,...u,...c}:{...u,...c}})}async function Fe({baseUrl:e,accessToken:s,months:t,to:a,source:n,model:r,timeZone:l,tzOffsetMinutes:i}={}){const c=await f(s);if(k())return ge({months:t,to:a,seed:c});const u=M({timeZone:l,tzOffsetMinutes:i}),o=P({source:n,model:r});return y({baseUrl:e,accessToken:c,slug:p.usageMonthly,params:{...t?{months:String(t)}:{},...a?{to:a}:{},...o,...u}})}async function qe({baseUrl:e,accessToken:s,weeks:t,to:a,weekStartsOn:n,source:r,model:l,timeZone:i,tzOffsetMinutes:c}={}){const u=await f(s);if(k())return ke({weeks:t,to:a,weekStartsOn:n,seed:u});const o=M({timeZone:i,tzOffsetMinutes:c}),d=P({source:r,model:l});return y({baseUrl:e,accessToken:u,slug:p.usageHeatmap,params:{weeks:String(t),to:a,week_starts_on:n,...d,...o}})}async function Ve({baseUrl:e,accessToken:s}={}){const t=await f(s);return k()?{link_code:"mock_link_code",expires_at:new Date(Date.now()+10*6e4).toISOString()}:X({baseUrl:e,accessToken:t,slug:p.linkCodeInit,body:{}})}async function $e({baseUrl:e,accessToken:s}={}){const t=await f(s);return y({baseUrl:e,accessToken:t,slug:p.publicViewProfile})}function M({timeZone:e,tzOffsetMinutes:s}={}){const t={},a=typeof e=="string"?e.trim():"";return a&&(t.tz=a),Number.isFinite(s)&&(t.tz_offset_minutes=String(Math.trunc(s))),t}function P({source:e,model:s}={}){const t={},a=typeof e=="string"?e.trim().toLowerCase():"";a&&(t.source=a);const n=typeof s=="string"?s.trim():"";return n&&(t.model=n),t}async function y({baseUrl:e,accessToken:s,slug:t,params:a,fetchOptions:n,errorPrefix:r,retry:l,requestKind:i=h.business,skipSessionExpiry:c=!1,allowRefresh:u=!0}={}){let o=await f(s),d=E(o),v=z({baseUrl:e,accessToken:o??void 0}).getHttpClient();const C=ae(l,"GET"),b=c?h.probe:i;let A=0;const{primaryPath:j,fallbackPath:I}=Q(t);for(;;)try{const S=await G({http:v,primaryPath:j,fallbackPath:I,params:a,fetchOptions:n});return U({hadAccessToken:d,accessToken:o}),S}catch(S){const T=S;if(T?.name==="AbortError")throw S;let w=null;const B=T?.statusCode??T?.status;if(u&&se({status:B,requestKind:b,hadAccessToken:d,accessToken:o})){const g=(await te())?.accessToken??null;if(E(g)){const N=z({baseUrl:e,accessToken:g}).getHttpClient();o=g,d=!0,v=N;try{const x=await G({http:N,primaryPath:j,fallbackPath:I,params:a,fetchOptions:n});return U({hadAccessToken:!0,accessToken:g}),x}catch(x){const F=x?.statusCode??x?.status;$({status:F,hadAccessToken:!0,accessToken:g,skipSessionExpiry:b===h.probe})&&L(),w=R(x,{errorPrefix:r,hadAccessToken:!0,accessToken:g,skipSessionExpiry:!0})}}else H({hadAccessToken:d,accessToken:o,skipSessionExpiry:b===h.probe})&&L();w??=R(T,{errorPrefix:r,hadAccessToken:d,accessToken:o,skipSessionExpiry:!0})}if(w??=R(T,{errorPrefix:r,hadAccessToken:d,accessToken:o,skipSessionExpiry:b===h.probe}),!ne({err:w,attempt:A,retryOptions:C}))throw w;const O=re({retryOptions:C,attempt:A});await ie(O),A+=1}}async function X({baseUrl:e,accessToken:s,slug:t,body:a,fetchOptions:n,errorPrefix:r,retry:l,requestKind:i=h.business,skipSessionExpiry:c=!1,allowRefresh:u=!0}={}){let o=await f(s),d=E(o),v=z({baseUrl:e,accessToken:o??void 0}).getHttpClient();const C=ae(l,"POST"),b=c?h.probe:i;let A=0;const{primaryPath:j,fallbackPath:I}=Q(t);for(;;)try{const S=await K({http:v,primaryPath:j,fallbackPath:I,body:a,fetchOptions:n});return U({hadAccessToken:d,accessToken:o}),S}catch(S){const T=S;if(T?.name==="AbortError")throw S;let w=null;const B=T?.statusCode??T?.status;if(u&&se({status:B,requestKind:b,hadAccessToken:d,accessToken:o})){const g=(await te())?.accessToken??null;if(E(g)){const N=z({baseUrl:e,accessToken:g}).getHttpClient();o=g,d=!0,v=N;try{const x=await K({http:N,primaryPath:j,fallbackPath:I,body:a,fetchOptions:n});return U({hadAccessToken:!0,accessToken:g}),x}catch(x){const F=x?.statusCode??x?.status;$({status:F,hadAccessToken:!0,accessToken:g,skipSessionExpiry:b===h.probe})&&L(),w=R(x,{errorPrefix:r,hadAccessToken:!0,accessToken:g,skipSessionExpiry:!0})}}else H({hadAccessToken:d,accessToken:o,skipSessionExpiry:b===h.probe})&&L();w??=R(T,{errorPrefix:r,hadAccessToken:d,accessToken:o,skipSessionExpiry:!0})}if(w??=R(T,{errorPrefix:r,hadAccessToken:d,accessToken:o,skipSessionExpiry:b===h.probe}),!ne({err:w,attempt:A,retryOptions:C}))throw w;const O=re({retryOptions:C,attempt:A});await ie(O),A+=1}}function Q(e){const s=Se(e),t=`${V(J)}/${s}`,a=`${V(be)}/${s}`;return{primaryPath:t,fallbackPath:a}}function Se(e){return(typeof e=="string"?e.trim():"").replace(/^\/+/,"")}function V(e){const s=typeof e=="string"?e.trim():"";return s.endsWith("/")?s.slice(0,-1):s}async function G({http:e,primaryPath:s,fallbackPath:t,params:a,fetchOptions:n}={}){try{return await e.get(s,{params:a,...n||{}})}catch(r){if(!Y(r,s))throw r;return await e.get(t,{params:a,...n||{}})}}async function K({http:e,primaryPath:s,fallbackPath:t,body:a,fetchOptions:n}={}){try{return await W({http:e,path:s,body:a,fetchOptions:n})}catch(r){if(!Y(r,s))throw r;return await W({http:e,path:t,body:a,fetchOptions:n})}}async function W({http:e,path:s,body:t,fetchOptions:a}={}){return await e.post(s,t,{...a||{}})}function Y(e,s){return!s||!s.startsWith(`${V(J)}/`)?!1:(e?.statusCode??e?.status)===404}function R(e,{errorPrefix:s,hadAccessToken:t,accessToken:a,skipSessionExpiry:n}={}){const r=typeof e?.message=="string"?e.message.trim():"",l=typeof e?.error=="string"?e.error.trim():"",i=r||l||String(e||"Unknown error"),c=ve(i),u=new Error(s?`${s}: ${c}`:c);u.cause=e;const o=e?.statusCode??e?.status;return $({status:o,hadAccessToken:t,accessToken:a,skipSessionExpiry:n})&&L(),typeof o=="number"&&(u.status=o,u.statusCode=o),u.retryable=Ae(o)||Me(i),c!==i&&(u.originalMessage=i),e?.nextActions&&(u.nextActions=e.nextActions),e?.error&&(u.error=e.error),u}function H({hadAccessToken:e,accessToken:s,skipSessionExpiry:t}={}){return t||!e||!E(s)?!1:Pe(s)}function $({status:e,hadAccessToken:s,accessToken:t,skipSessionExpiry:a}={}){return e!==401?!1:H({hadAccessToken:s,accessToken:t,skipSessionExpiry:a})}function _e({hadAccessToken:e,accessToken:s}={}){return H({hadAccessToken:e,accessToken:s})}function U({hadAccessToken:e,accessToken:s}={}){_e({hadAccessToken:e,accessToken:s})&&he()}function ve(e){return ee(e)?xe:String(e||"Unknown error")}function ee(e){const s=String(e||"").toLowerCase();return s?!!(s.includes("deno:")||s.includes("deno")||s.includes("econnreset")||s.includes("econnrefused")||s.includes("etimedout")||s.includes("timeout")&&s.includes("request")||s.includes("upstream")&&(s.includes("deno")||s.includes("connect"))):!1}function se({status:e,requestKind:s,hadAccessToken:t,accessToken:a}={}){return e!==401||s!==h.business?!1:H({hadAccessToken:t,accessToken:a})}async function te(){return D||(D=Te.auth.getCurrentSession().then(({data:e})=>e?.session??null).catch(()=>null).finally(()=>{D=null}),D)}function Ae(e){return e===502||e===503||e===504}function Me(e){const s=String(e||"").toLowerCase();return s?!!(ee(s)||s.includes("econnreset")||s.includes("econnrefused")||s.includes("etimedout")||s.includes("timeout")||s.includes("networkerror")||s.includes("failed to fetch")||s.includes("socket hang up")||s.includes("connection reset")):!1}function ae(e,s){const a=(s||"GET").toUpperCase()==="GET"?{maxRetries:2,baseDelayMs:300,maxDelayMs:1500,jitterRatio:.2}:{maxRetries:0,baseDelayMs:0,maxDelayMs:0,jitterRatio:0};if(e==null)return a;if(e===!1)return{maxRetries:0,baseDelayMs:0,maxDelayMs:0,jitterRatio:0};const n=q(e.maxRetries??a.maxRetries,0,10),r=q(e.baseDelayMs??a.baseDelayMs,50,6e4),l=q(e.maxDelayMs??a.maxDelayMs,r,12e4),i=typeof e.jitterRatio=="number"?Math.max(0,Math.min(.5,e.jitterRatio)):a.jitterRatio;return{maxRetries:n,baseDelayMs:r,maxDelayMs:l,jitterRatio:i}}function E(e){return!!ye(e)}function Pe(e){if(!E(e))return!1;const s=e.split(".");return s.length!==3?!1:s.every(t=>/^[A-Za-z0-9_-]+$/.test(t))}function ne({err:e,attempt:s,retryOptions:t}={}){return!t||t.maxRetries<=0||s>=t.maxRetries?!1:!!(e&&e.retryable)}function re({retryOptions:e,attempt:s}={}){if(!e||e.maxRetries<=0)return 0;const t=e.baseDelayMs*Math.pow(2,s),a=Math.min(e.maxDelayMs,t),n=a*e.jitterRatio*Math.random();return Math.round(a+n)}function q(e,s,t){const a=Number(e);return Number.isFinite(a)?Math.min(t,Math.max(s,Math.floor(a))):s}function ie(e){return!e||e<=0?Promise.resolve():new Promise(s=>setTimeout(s,e))}const _={TOP_LEFT:"┌",TOP_RIGHT:"┐",BOTTOM_LEFT:"└",BOTTOM_RIGHT:"┘",HORIZONTAL:"─",VERTICAL:"│"};function Ge({title:e,subtitle:s,children:t,className:a="",bodyClassName:n=""}){return m.jsxs("div",{className:`relative flex flex-col matrix-panel ${a}`,children:[m.jsxs("div",{className:"flex items-center leading-none",children:[m.jsx("span",{className:"shrink-0 text-matrix-dim",children:_.TOP_LEFT}),m.jsx("span",{className:"mx-3 shrink-0 text-heading uppercase text-matrix-primary px-2 py-1 bg-matrix-panelStrong border border-matrix-ghost",children:e}),s?m.jsxs("span",{className:"text-caption text-matrix-muted mr-2 uppercase",children:["[",s,"]"]}):null,m.jsx("span",{className:"flex-1 overflow-hidden whitespace-nowrap text-matrix-ghost",children:_.HORIZONTAL.repeat(100)}),m.jsx("span",{className:"shrink-0 text-matrix-dim",children:_.TOP_RIGHT})]}),m.jsxs("div",{className:"flex flex-1",children:[m.jsx("div",{className:"shrink-0 w-3 flex justify-center text-matrix-ghost",children:_.VERTICAL}),m.jsx("div",{className:`flex-1 min-w-0 py-5 px-4 relative z-10 ${n}`,children:t}),m.jsx("div",{className:"shrink-0 w-3 flex justify-center text-matrix-ghost",children:_.VERTICAL})]}),m.jsxs("div",{className:"flex items-center leading-none text-matrix-ghost",children:[m.jsx("span",{className:"shrink-0",children:_.BOTTOM_LEFT}),m.jsx("span",{className:"flex-1 overflow-hidden whitespace-nowrap",children:_.HORIZONTAL.repeat(100)}),m.jsx("span",{className:"shrink-0",children:_.BOTTOM_RIGHT})]})]})}export{Ge as A,Be as a,je as b,Oe as c,Fe as d,Ce as e,Ue as f,qe as g,Ne as h,$e as i,He as j,Ie as k,Le as l,Ee as p,Ve as r,De as s,ze as t};