tokentracker-cli 0.2.26 → 0.3.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/README.md +60 -28
- package/dashboard/dist/assets/DashboardPage-CdsMxGgP.js +12 -0
- package/dashboard/dist/assets/{LandingExtras-7PDallbH.js → LandingExtras-BPCBL0OB.js} +1 -1
- package/dashboard/dist/assets/LeaderboardPage-T0DeP6QE.js +1 -0
- package/dashboard/dist/assets/LeaderboardProfilePage-DeXNLaq5.js +1 -0
- package/dashboard/dist/assets/{MatrixRain-DR9XEe-r.js → MatrixRain-DNvnkted.js} +1 -1
- package/dashboard/dist/assets/MatrixShell-p6MtAS33.js +1 -0
- package/dashboard/dist/assets/{main-B206gspN.js → main-CvjKTqMk.js} +10 -8
- package/dashboard/dist/assets/main-DJvWJCv5.css +1 -0
- package/dashboard/dist/assets/vibeusage-api-By1xP_lg.js +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/share.html +2 -2
- package/package.json +2 -2
- package/src/commands/init.js +22 -1
- package/src/commands/sync.js +52 -2
- package/src/lib/cursor-config.js +328 -0
- package/src/lib/local-api.js +119 -23
- package/src/lib/rollout.js +149 -9
- package/dashboard/dist/assets/AsciiBox-fxqdUErY.js +0 -1
- package/dashboard/dist/assets/DashboardPage-rdYpdfso.js +0 -12
- package/dashboard/dist/assets/LeaderboardPage-CU_JeLPO.js +0 -1
- package/dashboard/dist/assets/LeaderboardProfilePage-D3B45Jjd.js +0 -1
- package/dashboard/dist/assets/MatrixShell-B6_X7zAp.js +0 -1
- package/dashboard/dist/assets/main-hwTpulbk.css +0 -1
package/src/lib/local-api.js
CHANGED
|
@@ -12,14 +12,7 @@ const TRACKER_BIN = path.resolve(__dirname, "../../bin/tracker.js");
|
|
|
12
12
|
|
|
13
13
|
function resolveQueuePath() {
|
|
14
14
|
const home = os.homedir();
|
|
15
|
-
|
|
16
|
-
path.join(home, ".tokentracker", "tracker", "queue.jsonl"),
|
|
17
|
-
path.join(home, ".vibeusage", "tracker", "queue.jsonl"),
|
|
18
|
-
];
|
|
19
|
-
for (const p of candidates) {
|
|
20
|
-
if (fs.existsSync(p)) return p;
|
|
21
|
-
}
|
|
22
|
-
return candidates[0];
|
|
15
|
+
return path.join(home, ".tokentracker", "tracker", "queue.jsonl");
|
|
23
16
|
}
|
|
24
17
|
|
|
25
18
|
function readQueueData(queuePath) {
|
|
@@ -46,6 +39,7 @@ function aggregateByDay(rows) {
|
|
|
46
39
|
input_tokens: 0,
|
|
47
40
|
output_tokens: 0,
|
|
48
41
|
cached_input_tokens: 0,
|
|
42
|
+
cache_creation_input_tokens: 0,
|
|
49
43
|
reasoning_output_tokens: 0,
|
|
50
44
|
conversation_count: 0,
|
|
51
45
|
});
|
|
@@ -56,12 +50,118 @@ function aggregateByDay(rows) {
|
|
|
56
50
|
a.input_tokens += row.input_tokens || 0;
|
|
57
51
|
a.output_tokens += row.output_tokens || 0;
|
|
58
52
|
a.cached_input_tokens += row.cached_input_tokens || 0;
|
|
53
|
+
a.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
|
|
59
54
|
a.reasoning_output_tokens += row.reasoning_output_tokens || 0;
|
|
60
55
|
a.conversation_count += row.conversation_count || 0;
|
|
61
56
|
}
|
|
62
57
|
return Array.from(byDay.values()).sort((a, b) => a.day.localeCompare(b.day));
|
|
63
58
|
}
|
|
64
59
|
|
|
60
|
+
function getTimeZoneContext(url) {
|
|
61
|
+
const tz = String(url.searchParams.get("tz") || "").trim();
|
|
62
|
+
const rawOffset = Number(url.searchParams.get("tz_offset_minutes"));
|
|
63
|
+
return {
|
|
64
|
+
timeZone: tz || null,
|
|
65
|
+
offsetMinutes: Number.isFinite(rawOffset) ? Math.trunc(rawOffset) : null,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getZonedParts(date, { timeZone, offsetMinutes } = {}) {
|
|
70
|
+
const dt = date instanceof Date ? date : new Date(date);
|
|
71
|
+
if (!Number.isFinite(dt.getTime())) return null;
|
|
72
|
+
|
|
73
|
+
if (timeZone && typeof Intl !== "undefined" && Intl.DateTimeFormat) {
|
|
74
|
+
try {
|
|
75
|
+
const formatter = new Intl.DateTimeFormat("en-CA", {
|
|
76
|
+
timeZone,
|
|
77
|
+
year: "numeric",
|
|
78
|
+
month: "2-digit",
|
|
79
|
+
day: "2-digit",
|
|
80
|
+
hour: "2-digit",
|
|
81
|
+
minute: "2-digit",
|
|
82
|
+
second: "2-digit",
|
|
83
|
+
hourCycle: "h23",
|
|
84
|
+
});
|
|
85
|
+
const parts = formatter.formatToParts(dt);
|
|
86
|
+
const values = parts.reduce((acc, part) => {
|
|
87
|
+
if (part.type && part.value) acc[part.type] = part.value;
|
|
88
|
+
return acc;
|
|
89
|
+
}, {});
|
|
90
|
+
const year = Number(values.year);
|
|
91
|
+
const month = Number(values.month);
|
|
92
|
+
const day = Number(values.day);
|
|
93
|
+
const hour = Number(values.hour);
|
|
94
|
+
const minute = Number(values.minute);
|
|
95
|
+
const second = Number(values.second);
|
|
96
|
+
if ([year, month, day, hour, minute, second].every(Number.isFinite)) {
|
|
97
|
+
return { year, month, day, hour, minute, second };
|
|
98
|
+
}
|
|
99
|
+
} catch (_e) {
|
|
100
|
+
// fall through
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (Number.isFinite(offsetMinutes)) {
|
|
105
|
+
const shifted = new Date(dt.getTime() + offsetMinutes * 60 * 1000);
|
|
106
|
+
return {
|
|
107
|
+
year: shifted.getUTCFullYear(),
|
|
108
|
+
month: shifted.getUTCMonth() + 1,
|
|
109
|
+
day: shifted.getUTCDate(),
|
|
110
|
+
hour: shifted.getUTCHours(),
|
|
111
|
+
minute: shifted.getUTCMinutes(),
|
|
112
|
+
second: shifted.getUTCSeconds(),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
year: dt.getFullYear(),
|
|
118
|
+
month: dt.getMonth() + 1,
|
|
119
|
+
day: dt.getDate(),
|
|
120
|
+
hour: dt.getHours(),
|
|
121
|
+
minute: dt.getMinutes(),
|
|
122
|
+
second: dt.getSeconds(),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function formatPartsDayKey(parts) {
|
|
127
|
+
if (!parts) return "";
|
|
128
|
+
return `${parts.year}-${String(parts.month).padStart(2, "0")}-${String(parts.day).padStart(2, "0")}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function aggregateHourlyByDay(rows, dayKey, timeZoneContext) {
|
|
132
|
+
const byHour = new Map();
|
|
133
|
+
for (const row of rows) {
|
|
134
|
+
if (!row.hour_start) continue;
|
|
135
|
+
const parts = getZonedParts(new Date(row.hour_start), timeZoneContext);
|
|
136
|
+
if (!parts) continue;
|
|
137
|
+
if (formatPartsDayKey(parts) !== dayKey) continue;
|
|
138
|
+
const hourKey = `${dayKey}T${String(parts.hour).padStart(2, "0")}:00:00`;
|
|
139
|
+
if (!byHour.has(hourKey)) {
|
|
140
|
+
byHour.set(hourKey, {
|
|
141
|
+
hour: hourKey,
|
|
142
|
+
total_tokens: 0,
|
|
143
|
+
billable_total_tokens: 0,
|
|
144
|
+
input_tokens: 0,
|
|
145
|
+
output_tokens: 0,
|
|
146
|
+
cached_input_tokens: 0,
|
|
147
|
+
cache_creation_input_tokens: 0,
|
|
148
|
+
reasoning_output_tokens: 0,
|
|
149
|
+
conversation_count: 0,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const bucket = byHour.get(hourKey);
|
|
153
|
+
bucket.total_tokens += row.total_tokens || 0;
|
|
154
|
+
bucket.billable_total_tokens += row.total_tokens || 0;
|
|
155
|
+
bucket.input_tokens += row.input_tokens || 0;
|
|
156
|
+
bucket.output_tokens += row.output_tokens || 0;
|
|
157
|
+
bucket.cached_input_tokens += row.cached_input_tokens || 0;
|
|
158
|
+
bucket.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
|
|
159
|
+
bucket.reasoning_output_tokens += row.reasoning_output_tokens || 0;
|
|
160
|
+
bucket.conversation_count += row.conversation_count || 0;
|
|
161
|
+
}
|
|
162
|
+
return Array.from(byHour.values()).sort((a, b) => a.hour.localeCompare(b.hour));
|
|
163
|
+
}
|
|
164
|
+
|
|
65
165
|
// ---------------------------------------------------------------------------
|
|
66
166
|
// Sync helper
|
|
67
167
|
// ---------------------------------------------------------------------------
|
|
@@ -261,11 +361,12 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
261
361
|
acc.input_tokens += r.input_tokens;
|
|
262
362
|
acc.output_tokens += r.output_tokens;
|
|
263
363
|
acc.cached_input_tokens += r.cached_input_tokens;
|
|
364
|
+
acc.cache_creation_input_tokens += r.cache_creation_input_tokens;
|
|
264
365
|
acc.reasoning_output_tokens += r.reasoning_output_tokens;
|
|
265
366
|
acc.conversation_count += r.conversation_count;
|
|
266
367
|
return acc;
|
|
267
368
|
},
|
|
268
|
-
{ total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, reasoning_output_tokens: 0, conversation_count: 0 },
|
|
369
|
+
{ total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, conversation_count: 0 },
|
|
269
370
|
);
|
|
270
371
|
const totalCost = (totals.total_tokens * 1.75) / 1_000_000;
|
|
271
372
|
|
|
@@ -379,22 +480,24 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
379
480
|
const src = row.source || "unknown";
|
|
380
481
|
const mdl = row.model || "unknown";
|
|
381
482
|
if (!bySource.has(src))
|
|
382
|
-
bySource.set(src, { source: src, totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: "0" }, models: new Map() });
|
|
483
|
+
bySource.set(src, { source: src, totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: "0" }, models: new Map() });
|
|
383
484
|
const sa = bySource.get(src);
|
|
384
485
|
sa.totals.total_tokens += row.total_tokens || 0;
|
|
385
486
|
sa.totals.billable_total_tokens += row.total_tokens || 0;
|
|
386
487
|
sa.totals.input_tokens += row.input_tokens || 0;
|
|
387
488
|
sa.totals.output_tokens += row.output_tokens || 0;
|
|
388
489
|
sa.totals.cached_input_tokens += row.cached_input_tokens || 0;
|
|
490
|
+
sa.totals.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
|
|
389
491
|
sa.totals.reasoning_output_tokens += row.reasoning_output_tokens || 0;
|
|
390
492
|
if (!sa.models.has(mdl))
|
|
391
|
-
sa.models.set(mdl, { model: mdl, model_id: mdl, totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: "0" } });
|
|
493
|
+
sa.models.set(mdl, { model: mdl, model_id: mdl, totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: "0" } });
|
|
392
494
|
const ma = sa.models.get(mdl);
|
|
393
495
|
ma.totals.total_tokens += row.total_tokens || 0;
|
|
394
496
|
ma.totals.billable_total_tokens += row.total_tokens || 0;
|
|
395
497
|
ma.totals.input_tokens += row.input_tokens || 0;
|
|
396
498
|
ma.totals.output_tokens += row.output_tokens || 0;
|
|
397
499
|
ma.totals.cached_input_tokens += row.cached_input_tokens || 0;
|
|
500
|
+
ma.totals.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
|
|
398
501
|
ma.totals.reasoning_output_tokens += row.reasoning_output_tokens || 0;
|
|
399
502
|
}
|
|
400
503
|
|
|
@@ -463,17 +566,9 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
463
566
|
// --- usage-hourly (stub for day-view) ---
|
|
464
567
|
if (p === "/functions/vibeusage-usage-hourly") {
|
|
465
568
|
const day = url.searchParams.get("day") || new Date().toISOString().slice(0, 10);
|
|
466
|
-
const
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
total_tokens: r.total_tokens || 0,
|
|
470
|
-
billable_total_tokens: r.total_tokens || 0,
|
|
471
|
-
input_tokens: r.input_tokens || 0,
|
|
472
|
-
output_tokens: r.output_tokens || 0,
|
|
473
|
-
cached_input_tokens: r.cached_input_tokens || 0,
|
|
474
|
-
reasoning_output_tokens: r.reasoning_output_tokens || 0,
|
|
475
|
-
conversation_count: r.conversation_count || 0,
|
|
476
|
-
}));
|
|
569
|
+
const timeZoneContext = getTimeZoneContext(url);
|
|
570
|
+
const rows = readQueueData(qp);
|
|
571
|
+
const data = aggregateHourlyByDay(rows, day, timeZoneContext);
|
|
477
572
|
json(res, { day, data });
|
|
478
573
|
return true;
|
|
479
574
|
}
|
|
@@ -490,13 +585,14 @@ function createLocalApiHandler({ queuePath }) {
|
|
|
490
585
|
if (day < from || day > to) continue;
|
|
491
586
|
const month = day.slice(0, 7);
|
|
492
587
|
if (!byMonth.has(month))
|
|
493
|
-
byMonth.set(month, { month, total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, reasoning_output_tokens: 0, conversation_count: 0 });
|
|
588
|
+
byMonth.set(month, { month, total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, conversation_count: 0 });
|
|
494
589
|
const a = byMonth.get(month);
|
|
495
590
|
a.total_tokens += row.total_tokens || 0;
|
|
496
591
|
a.billable_total_tokens += row.total_tokens || 0;
|
|
497
592
|
a.input_tokens += row.input_tokens || 0;
|
|
498
593
|
a.output_tokens += row.output_tokens || 0;
|
|
499
594
|
a.cached_input_tokens += row.cached_input_tokens || 0;
|
|
595
|
+
a.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
|
|
500
596
|
a.reasoning_output_tokens += row.reasoning_output_tokens || 0;
|
|
501
597
|
a.conversation_count += row.conversation_count || 0;
|
|
502
598
|
}
|
package/src/lib/rollout.js
CHANGED
|
@@ -206,6 +206,7 @@ async function parseClaudeIncremental({
|
|
|
206
206
|
const projectMetaCache = projectEnabled ? new Map() : null;
|
|
207
207
|
const publicRepoCache = projectEnabled ? new Map() : null;
|
|
208
208
|
const touchedBuckets = new Set();
|
|
209
|
+
const seenMessageHashes = new Set();
|
|
209
210
|
const defaultSource = normalizeSourceInput(source) || "claude";
|
|
210
211
|
|
|
211
212
|
if (!cursors.files || typeof cursors.files !== "object") {
|
|
@@ -250,6 +251,7 @@ async function parseClaudeIncremental({
|
|
|
250
251
|
projectTouchedBuckets,
|
|
251
252
|
projectRef,
|
|
252
253
|
projectKey,
|
|
254
|
+
seenMessageHashes,
|
|
253
255
|
});
|
|
254
256
|
|
|
255
257
|
cursors.files[key] = {
|
|
@@ -822,6 +824,7 @@ async function parseClaudeFile({
|
|
|
822
824
|
projectTouchedBuckets,
|
|
823
825
|
projectRef,
|
|
824
826
|
projectKey,
|
|
827
|
+
seenMessageHashes,
|
|
825
828
|
}) {
|
|
826
829
|
const st = await fs.stat(filePath).catch(() => null);
|
|
827
830
|
if (!st || !st.isFile()) return { endOffset: startOffset, eventsAggregated: 0 };
|
|
@@ -833,8 +836,39 @@ async function parseClaudeFile({
|
|
|
833
836
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
834
837
|
|
|
835
838
|
let eventsAggregated = 0;
|
|
839
|
+
const isMainSession = !filePath.includes("/subagents/");
|
|
836
840
|
for await (const line of rl) {
|
|
837
|
-
if (!line
|
|
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;
|
|
838
872
|
let obj;
|
|
839
873
|
try {
|
|
840
874
|
obj = JSON.parse(line);
|
|
@@ -845,13 +879,23 @@ async function parseClaudeFile({
|
|
|
845
879
|
const usage = obj?.message?.usage || obj?.usage;
|
|
846
880
|
if (!usage || typeof usage !== "object") continue;
|
|
847
881
|
|
|
882
|
+
if (seenMessageHashes) {
|
|
883
|
+
const msgId = obj?.message?.id;
|
|
884
|
+
const reqId = obj?.requestId;
|
|
885
|
+
if (msgId && reqId) {
|
|
886
|
+
const hash = `${msgId}:${reqId}`;
|
|
887
|
+
if (seenMessageHashes.has(hash)) continue;
|
|
888
|
+
seenMessageHashes.add(hash);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
848
892
|
const model = normalizeModelInput(obj?.message?.model || obj?.model) || DEFAULT_MODEL;
|
|
849
893
|
const tokenTimestamp = typeof obj?.timestamp === "string" ? obj.timestamp : null;
|
|
850
894
|
if (!tokenTimestamp) continue;
|
|
851
895
|
|
|
852
896
|
const delta = normalizeClaudeUsage(usage);
|
|
853
897
|
if (!delta || isAllZeroUsage(delta)) continue;
|
|
854
|
-
delta.conversation_count =
|
|
898
|
+
delta.conversation_count = 0;
|
|
855
899
|
|
|
856
900
|
const bucketStart = toUtcHalfHourStart(tokenTimestamp);
|
|
857
901
|
if (!bucketStart) continue;
|
|
@@ -1180,6 +1224,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
|
|
|
1180
1224
|
hour_start: group.hourStart,
|
|
1181
1225
|
input_tokens: zeroTotals.input_tokens,
|
|
1182
1226
|
cached_input_tokens: zeroTotals.cached_input_tokens,
|
|
1227
|
+
cache_creation_input_tokens: zeroTotals.cache_creation_input_tokens,
|
|
1183
1228
|
output_tokens: zeroTotals.output_tokens,
|
|
1184
1229
|
reasoning_output_tokens: zeroTotals.reasoning_output_tokens,
|
|
1185
1230
|
total_tokens: zeroTotals.total_tokens,
|
|
@@ -1227,6 +1272,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
|
|
|
1227
1272
|
hour_start: group.hourStart,
|
|
1228
1273
|
input_tokens: totals.input_tokens,
|
|
1229
1274
|
cached_input_tokens: totals.cached_input_tokens,
|
|
1275
|
+
cache_creation_input_tokens: totals.cache_creation_input_tokens,
|
|
1230
1276
|
output_tokens: totals.output_tokens,
|
|
1231
1277
|
reasoning_output_tokens: totals.reasoning_output_tokens,
|
|
1232
1278
|
total_tokens: totals.total_tokens,
|
|
@@ -1274,6 +1320,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
|
|
|
1274
1320
|
hour_start: group.hourStart,
|
|
1275
1321
|
input_tokens: zeroTotals.input_tokens,
|
|
1276
1322
|
cached_input_tokens: zeroTotals.cached_input_tokens,
|
|
1323
|
+
cache_creation_input_tokens: zeroTotals.cache_creation_input_tokens,
|
|
1277
1324
|
output_tokens: zeroTotals.output_tokens,
|
|
1278
1325
|
reasoning_output_tokens: zeroTotals.reasoning_output_tokens,
|
|
1279
1326
|
total_tokens: zeroTotals.total_tokens,
|
|
@@ -1294,6 +1341,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
|
|
|
1294
1341
|
hour_start: group.hourStart,
|
|
1295
1342
|
input_tokens: unknownBucket.totals.input_tokens,
|
|
1296
1343
|
cached_input_tokens: unknownBucket.totals.cached_input_tokens,
|
|
1344
|
+
cache_creation_input_tokens: unknownBucket.totals.cache_creation_input_tokens,
|
|
1297
1345
|
output_tokens: unknownBucket.totals.output_tokens,
|
|
1298
1346
|
reasoning_output_tokens: unknownBucket.totals.reasoning_output_tokens,
|
|
1299
1347
|
total_tokens: unknownBucket.totals.total_tokens,
|
|
@@ -1339,6 +1387,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
|
|
|
1339
1387
|
hour_start: group.hourStart,
|
|
1340
1388
|
input_tokens: group.totals.input_tokens,
|
|
1341
1389
|
cached_input_tokens: group.totals.cached_input_tokens,
|
|
1390
|
+
cache_creation_input_tokens: group.totals.cache_creation_input_tokens,
|
|
1342
1391
|
output_tokens: group.totals.output_tokens,
|
|
1343
1392
|
reasoning_output_tokens: group.totals.reasoning_output_tokens,
|
|
1344
1393
|
total_tokens: group.totals.total_tokens,
|
|
@@ -1392,6 +1441,7 @@ async function enqueueTouchedProjectBuckets({
|
|
|
1392
1441
|
hour_start: bucket.hour_start,
|
|
1393
1442
|
input_tokens: totals.input_tokens,
|
|
1394
1443
|
cached_input_tokens: totals.cached_input_tokens,
|
|
1444
|
+
cache_creation_input_tokens: totals.cache_creation_input_tokens,
|
|
1395
1445
|
output_tokens: totals.output_tokens,
|
|
1396
1446
|
reasoning_output_tokens: totals.reasoning_output_tokens,
|
|
1397
1447
|
total_tokens: totals.total_tokens,
|
|
@@ -1646,6 +1696,7 @@ function initTotals() {
|
|
|
1646
1696
|
return {
|
|
1647
1697
|
input_tokens: 0,
|
|
1648
1698
|
cached_input_tokens: 0,
|
|
1699
|
+
cache_creation_input_tokens: 0,
|
|
1649
1700
|
output_tokens: 0,
|
|
1650
1701
|
reasoning_output_tokens: 0,
|
|
1651
1702
|
total_tokens: 0,
|
|
@@ -1656,6 +1707,7 @@ function initTotals() {
|
|
|
1656
1707
|
function addTotals(target, delta) {
|
|
1657
1708
|
target.input_tokens += delta.input_tokens || 0;
|
|
1658
1709
|
target.cached_input_tokens += delta.cached_input_tokens || 0;
|
|
1710
|
+
target.cache_creation_input_tokens += delta.cache_creation_input_tokens || 0;
|
|
1659
1711
|
target.output_tokens += delta.output_tokens || 0;
|
|
1660
1712
|
target.reasoning_output_tokens += delta.reasoning_output_tokens || 0;
|
|
1661
1713
|
target.total_tokens += delta.total_tokens || 0;
|
|
@@ -1666,6 +1718,7 @@ function totalsKey(totals) {
|
|
|
1666
1718
|
return [
|
|
1667
1719
|
totals.input_tokens || 0,
|
|
1668
1720
|
totals.cached_input_tokens || 0,
|
|
1721
|
+
totals.cache_creation_input_tokens || 0,
|
|
1669
1722
|
totals.output_tokens || 0,
|
|
1670
1723
|
totals.reasoning_output_tokens || 0,
|
|
1671
1724
|
totals.total_tokens || 0,
|
|
@@ -1998,6 +2051,7 @@ function normalizeGeminiTokens(tokens) {
|
|
|
1998
2051
|
return {
|
|
1999
2052
|
input_tokens: input,
|
|
2000
2053
|
cached_input_tokens: cached,
|
|
2054
|
+
cache_creation_input_tokens: 0,
|
|
2001
2055
|
output_tokens: output + tool,
|
|
2002
2056
|
reasoning_output_tokens: thoughts,
|
|
2003
2057
|
total_tokens: total,
|
|
@@ -2011,12 +2065,12 @@ function normalizeOpencodeTokens(tokens) {
|
|
|
2011
2065
|
const reasoning = toNonNegativeInt(tokens.reasoning);
|
|
2012
2066
|
const cached = toNonNegativeInt(tokens.cache?.read);
|
|
2013
2067
|
const cacheWrite = toNonNegativeInt(tokens.cache?.write);
|
|
2014
|
-
|
|
2015
|
-
const total = input + output + reasoning;
|
|
2068
|
+
const total = input + output + reasoning + cached + cacheWrite;
|
|
2016
2069
|
|
|
2017
2070
|
return {
|
|
2018
2071
|
input_tokens: input,
|
|
2019
2072
|
cached_input_tokens: cached,
|
|
2073
|
+
cache_creation_input_tokens: cacheWrite,
|
|
2020
2074
|
output_tokens: output,
|
|
2021
2075
|
reasoning_output_tokens: reasoning,
|
|
2022
2076
|
total_tokens: total,
|
|
@@ -2122,6 +2176,7 @@ function normalizeUsage(u) {
|
|
|
2122
2176
|
for (const k of [
|
|
2123
2177
|
"input_tokens",
|
|
2124
2178
|
"cached_input_tokens",
|
|
2179
|
+
"cache_creation_input_tokens",
|
|
2125
2180
|
"output_tokens",
|
|
2126
2181
|
"reasoning_output_tokens",
|
|
2127
2182
|
"total_tokens",
|
|
@@ -2135,13 +2190,13 @@ function normalizeUsage(u) {
|
|
|
2135
2190
|
function normalizeClaudeUsage(u) {
|
|
2136
2191
|
const inputTokens = toNonNegativeInt(u?.input_tokens);
|
|
2137
2192
|
const outputTokens = toNonNegativeInt(u?.output_tokens);
|
|
2138
|
-
const
|
|
2139
|
-
const
|
|
2140
|
-
|
|
2141
|
-
: inputTokens + outputTokens;
|
|
2193
|
+
const cacheCreation = toNonNegativeInt(u?.cache_creation_input_tokens);
|
|
2194
|
+
const cacheRead = toNonNegativeInt(u?.cache_read_input_tokens);
|
|
2195
|
+
const totalTokens = inputTokens + outputTokens + cacheCreation + cacheRead;
|
|
2142
2196
|
return {
|
|
2143
2197
|
input_tokens: inputTokens,
|
|
2144
|
-
cached_input_tokens:
|
|
2198
|
+
cached_input_tokens: cacheRead,
|
|
2199
|
+
cache_creation_input_tokens: cacheCreation,
|
|
2145
2200
|
output_tokens: outputTokens,
|
|
2146
2201
|
reasoning_output_tokens: 0,
|
|
2147
2202
|
total_tokens: totalTokens,
|
|
@@ -2157,6 +2212,7 @@ function isAllZeroUsage(u) {
|
|
|
2157
2212
|
for (const k of [
|
|
2158
2213
|
"input_tokens",
|
|
2159
2214
|
"cached_input_tokens",
|
|
2215
|
+
"cache_creation_input_tokens",
|
|
2160
2216
|
"output_tokens",
|
|
2161
2217
|
"reasoning_output_tokens",
|
|
2162
2218
|
"total_tokens",
|
|
@@ -2170,6 +2226,7 @@ function sameUsage(a, b) {
|
|
|
2170
2226
|
for (const k of [
|
|
2171
2227
|
"input_tokens",
|
|
2172
2228
|
"cached_input_tokens",
|
|
2229
|
+
"cache_creation_input_tokens",
|
|
2173
2230
|
"output_tokens",
|
|
2174
2231
|
"reasoning_output_tokens",
|
|
2175
2232
|
"total_tokens",
|
|
@@ -2457,6 +2514,88 @@ async function resolveProjectContextForDb({
|
|
|
2457
2514
|
});
|
|
2458
2515
|
}
|
|
2459
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
|
+
|
|
2460
2599
|
module.exports = {
|
|
2461
2600
|
listRolloutFiles,
|
|
2462
2601
|
listClaudeProjectFiles,
|
|
@@ -2469,4 +2608,5 @@ module.exports = {
|
|
|
2469
2608
|
parseOpencodeIncremental,
|
|
2470
2609
|
parseOpencodeDbIncremental,
|
|
2471
2610
|
parseOpenclawIncremental,
|
|
2611
|
+
parseCursorApiIncremental,
|
|
2472
2612
|
};
|
|
@@ -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-B206gspN.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};
|