@hasna/economy 0.5.2 → 0.5.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.
- package/CHANGELOG.md +6 -0
- package/dist/chunks/{billing-bkpxy4kv.js → billing-22az60hy.js} +2 -2
- package/dist/chunks/{config-j9mv3ehk.js → config-hsp7ndhj.js} +2 -2
- package/dist/chunks/{index-dj3tctqh.js → index-1vz1arz5.js} +14 -13
- package/dist/chunks/{index-hesxq90g.js → index-9wa1f2kv.js} +1 -1
- package/dist/chunks/{index-kzwqw3ve.js → index-bn04v378.js} +2 -2
- package/dist/chunks/{index-zpvea08j.js → index-c7h2rxx1.js} +38 -12
- package/dist/chunks/{index-k540hfww.js → index-dk5rq1rq.js} +1 -1
- package/dist/chunks/{index-ez9thsr7.js → index-f5jv6q5q.js} +38 -12
- package/dist/chunks/{index-9d2aky06.js → index-mhrkwvtk.js} +3 -3
- package/dist/chunks/{index-npsjjv96.js → index-s9mvven6.js} +2 -2
- package/dist/chunks/{index-2hwzmfgv.js → index-vajzfzgv.js} +38 -12
- package/dist/chunks/{open-projects-6z4pq6mx.js → open-projects-8qm46m3d.js} +1 -1
- package/dist/chunks/{pricing-vf2pycmh.js → pricing-462f8xkm.js} +1 -1
- package/dist/chunks/{pricing-f80p81gr.js → pricing-k9wsjwbz.js} +1 -1
- package/dist/chunks/{pricing-y21mcjsa.js → pricing-vxejj1qa.js} +1 -1
- package/dist/chunks/{serve-p2yarhm8.js → serve-8yqe7nhs.js} +18 -10
- package/dist/chunks/{sqlite-store-st99garx.js → sqlite-store-13nhr1z0.js} +2 -2
- package/dist/chunks/{sqlite-store-501f32ts.js → sqlite-store-gamn65xp.js} +2 -2
- package/dist/chunks/{sqlite-store-fq4natnf.js → sqlite-store-ht6frztj.js} +2 -2
- package/dist/chunks/{tui-x64hjfrh.js → tui-fe94bvp9.js} +4 -4
- package/dist/chunks/{watch-bxstjpbx.js → watch-ct8dvrpr.js} +5 -5
- package/dist/chunks/{webhooks-k4fh2t9c.js → webhooks-nw4daw9y.js} +20 -9
- package/dist/cli/index.js +27 -27
- package/dist/db/database.d.ts +2 -2
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/sync-pg.d.ts.map +1 -1
- package/dist/index.js +15 -14
- package/dist/lib/analytics.d.ts +1 -1
- package/dist/lib/analytics.d.ts.map +1 -1
- package/dist/lib/periods.d.ts +20 -1
- package/dist/lib/periods.d.ts.map +1 -1
- package/dist/lib/spikes.d.ts +3 -3
- package/dist/lib/spikes.d.ts.map +1 -1
- package/dist/mcp/index.js +18 -17
- package/dist/otel/index.js +1 -1
- package/dist/server/index.js +78 -33
- package/dist/server/service-operations.d.ts.map +1 -1
- package/dist/server/service-worker.js +78 -33
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Use consistent UTC calendar and rolling intervals for charts, forecasts and spike detection. Bound report windows on both ends, preserve millisecond boundaries for rolling hours, and require consecutive observed days before detecting a daily cost spike.
|
|
8
|
+
|
|
3
9
|
## 0.5.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
syncAnthropicBilling,
|
|
4
4
|
syncGeminiBilling,
|
|
5
5
|
syncOpenAIBilling
|
|
6
|
-
} from "./index-
|
|
7
|
-
import"./index-
|
|
6
|
+
} from "./index-dk5rq1rq.js";
|
|
7
|
+
import"./index-f5jv6q5q.js";
|
|
8
8
|
import"./index-p35cyhc4.js";
|
|
9
9
|
export {
|
|
10
10
|
syncOpenAIBilling,
|
|
@@ -14,12 +14,13 @@ import {
|
|
|
14
14
|
querySummary,
|
|
15
15
|
requireCurrentBillingSummary,
|
|
16
16
|
requireCurrentCostSummary,
|
|
17
|
+
resolveReportingInterval,
|
|
17
18
|
sessionOverlapWhere
|
|
18
|
-
} from "./index-
|
|
19
|
+
} from "./index-f5jv6q5q.js";
|
|
19
20
|
// package.json
|
|
20
21
|
var package_default = {
|
|
21
22
|
name: "@hasna/economy",
|
|
22
|
-
version: "0.5.
|
|
23
|
+
version: "0.5.3",
|
|
23
24
|
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
24
25
|
repository: {
|
|
25
26
|
type: "git",
|
|
@@ -1230,7 +1231,8 @@ function buildBrief(db, opts = {}) {
|
|
|
1230
1231
|
}
|
|
1231
1232
|
|
|
1232
1233
|
// src/lib/analytics.ts
|
|
1233
|
-
function queryProjectDetail(db, nameOrPath) {
|
|
1234
|
+
function queryProjectDetail(db, nameOrPath, now = new Date) {
|
|
1235
|
+
const dailyBounds = resolveReportingInterval({ kind: "rolling", unit: "day", count: 14 }, now);
|
|
1234
1236
|
const like = `%${nameOrPath}%`;
|
|
1235
1237
|
const sessions = db.prepare(`SELECT id, project_name, project_path, total_cost_usd, total_tokens, started_at
|
|
1236
1238
|
FROM economy_effective_sessions
|
|
@@ -1244,8 +1246,8 @@ function queryProjectDetail(db, nameOrPath) {
|
|
|
1244
1246
|
const daily = db.prepare(`SELECT DATE(r.timestamp) as date, COALESCE(SUM(r.cost_usd), 0) as cost_usd
|
|
1245
1247
|
FROM economy_effective_requests r JOIN economy_effective_sessions s ON r.session_id = s.id
|
|
1246
1248
|
WHERE (s.project_name LIKE ? OR s.project_path LIKE ?)
|
|
1247
|
-
AND r.timestamp >=
|
|
1248
|
-
GROUP BY date ORDER BY date ASC`).all(like, like);
|
|
1249
|
+
AND r.timestamp >= ? AND r.timestamp < ?
|
|
1250
|
+
GROUP BY date ORDER BY date ASC`).all(like, like, dailyBounds.start, dailyBounds.end_exclusive);
|
|
1249
1251
|
const models = db.prepare(`SELECT r.model as model, COUNT(*) as requests, COALESCE(SUM(r.cost_usd), 0) as cost_usd
|
|
1250
1252
|
FROM economy_effective_requests r JOIN economy_effective_sessions s ON r.session_id = s.id
|
|
1251
1253
|
WHERE s.project_name LIKE ? OR s.project_path LIKE ?
|
|
@@ -1284,18 +1286,17 @@ function queryRangeStats(db, from, to) {
|
|
|
1284
1286
|
return { cost: r.cost, requests: r.requests, tokens: r.tokens, sessions: s.sessions };
|
|
1285
1287
|
}
|
|
1286
1288
|
function queryForecast(db, now = new Date) {
|
|
1287
|
-
const
|
|
1288
|
-
const
|
|
1289
|
-
const
|
|
1290
|
-
const
|
|
1289
|
+
const month = resolveReportingInterval({ kind: "calendar", period: "month" }, now);
|
|
1290
|
+
const recent = resolveReportingInterval({ kind: "rolling", unit: "day", count: 7 }, now);
|
|
1291
|
+
const daysInMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0)).getUTCDate();
|
|
1292
|
+
const dayOfMonth = now.getUTCDate();
|
|
1293
|
+
const monthSoFar = db.prepare(`SELECT COALESCE(SUM(cost_usd),0) as cost FROM economy_effective_requests WHERE timestamp >= ? AND timestamp < ?`).get(month.start, recent.end_exclusive);
|
|
1291
1294
|
const dailyAvg = dayOfMonth > 0 ? monthSoFar.cost / dayOfMonth : 0;
|
|
1292
1295
|
const projected = dailyAvg * daysInMonth;
|
|
1293
|
-
const
|
|
1294
|
-
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
1295
|
-
const last7 = db.prepare(`SELECT COALESCE(SUM(cost_usd),0) as cost FROM economy_effective_requests WHERE DATE(timestamp) >= ?`).get(sevenDaysAgo.toISOString().substring(0, 10));
|
|
1296
|
+
const last7 = db.prepare(`SELECT COALESCE(SUM(cost_usd),0) as cost FROM economy_effective_requests WHERE timestamp >= ? AND timestamp < ?`).get(recent.start, recent.end_exclusive);
|
|
1296
1297
|
const last7DailyAvg = last7.cost / 7;
|
|
1297
1298
|
const dailyCosts = db.prepare(`SELECT DATE(timestamp) as date, COALESCE(SUM(cost_usd),0) as cost_usd
|
|
1298
|
-
FROM economy_effective_requests WHERE
|
|
1299
|
+
FROM economy_effective_requests WHERE timestamp >= ? AND timestamp < ? GROUP BY date ORDER BY cost_usd ASC`).all(month.start, recent.end_exclusive);
|
|
1299
1300
|
return {
|
|
1300
1301
|
day_of_month: dayOfMonth,
|
|
1301
1302
|
days_in_month: daysInMonth,
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
} from "./index-w3bvv0ns.js";
|
|
5
5
|
import {
|
|
6
6
|
getStore
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-mhrkwvtk.js";
|
|
8
8
|
import {
|
|
9
9
|
formatReportedUsd,
|
|
10
10
|
formatSummaryCoverage,
|
|
11
11
|
formatSummaryValue
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-f5jv6q5q.js";
|
|
13
13
|
|
|
14
14
|
// src/cli/commands/tui.ts
|
|
15
15
|
import chalk from "chalk";
|
|
@@ -1072,12 +1072,32 @@ function meteredBudgetAmounts(groups, limit, threshold) {
|
|
|
1072
1072
|
function ymd(date2) {
|
|
1073
1073
|
return date2.toISOString().substring(0, 10);
|
|
1074
1074
|
}
|
|
1075
|
-
function
|
|
1075
|
+
function resolveReportingInterval(interval, now = new Date) {
|
|
1076
1076
|
if (!Number.isFinite(now.getTime()))
|
|
1077
1077
|
throw new RangeError("Invalid reporting clock");
|
|
1078
|
-
const start = new Date(
|
|
1078
|
+
const start = new Date(now);
|
|
1079
|
+
start.setUTCHours(0, 0, 0, 0);
|
|
1079
1080
|
const end = new Date(start);
|
|
1080
|
-
|
|
1081
|
+
if (interval.kind === "rolling") {
|
|
1082
|
+
if (!Number.isSafeInteger(interval.count) || interval.count < 1)
|
|
1083
|
+
throw new RangeError("Invalid reporting window");
|
|
1084
|
+
if (interval.unit === "hour") {
|
|
1085
|
+
start.setTime(now.getTime() - interval.count * 3600000);
|
|
1086
|
+
if (!Number.isFinite(start.getTime()))
|
|
1087
|
+
throw new RangeError("Invalid reporting window");
|
|
1088
|
+
return { time_zone: "UTC", start: start.toISOString(), end_exclusive: now.toISOString() };
|
|
1089
|
+
}
|
|
1090
|
+
if (interval.unit !== "day")
|
|
1091
|
+
throw new RangeError("Invalid reporting unit");
|
|
1092
|
+
start.setUTCDate(start.getUTCDate() - interval.count + 1);
|
|
1093
|
+
end.setUTCDate(end.getUTCDate() + 1);
|
|
1094
|
+
if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime()))
|
|
1095
|
+
throw new RangeError("Invalid reporting window");
|
|
1096
|
+
return { time_zone: "UTC", start: ymd(start), end_exclusive: ymd(end) };
|
|
1097
|
+
}
|
|
1098
|
+
if (interval.kind !== "calendar")
|
|
1099
|
+
throw new RangeError("Invalid reporting interval");
|
|
1100
|
+
switch (interval.period) {
|
|
1081
1101
|
case "today":
|
|
1082
1102
|
end.setUTCDate(end.getUTCDate() + 1);
|
|
1083
1103
|
break;
|
|
@@ -1100,11 +1120,15 @@ function calendarPeriodBounds(period, now = new Date) {
|
|
|
1100
1120
|
end.setUTCFullYear(end.getUTCFullYear() + 1);
|
|
1101
1121
|
break;
|
|
1102
1122
|
case "all":
|
|
1103
|
-
return { time_zone: "UTC",
|
|
1123
|
+
return { time_zone: "UTC", start: null, end_exclusive: null };
|
|
1104
1124
|
default:
|
|
1105
1125
|
throw new RangeError("Invalid reporting period");
|
|
1106
1126
|
}
|
|
1107
|
-
return { time_zone: "UTC",
|
|
1127
|
+
return { time_zone: "UTC", start: ymd(start), end_exclusive: ymd(end) };
|
|
1128
|
+
}
|
|
1129
|
+
function calendarPeriodBounds(period, now = new Date) {
|
|
1130
|
+
const bounds = resolveReportingInterval({ kind: "calendar", period }, now);
|
|
1131
|
+
return { time_zone: bounds.time_zone, start_date: bounds.start, end_date_exclusive: bounds.end_exclusive };
|
|
1108
1132
|
}
|
|
1109
1133
|
function calendarPeriodWhere(period, column, now = new Date) {
|
|
1110
1134
|
if (!/^[a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)?$/i.test(column)) {
|
|
@@ -2450,20 +2474,22 @@ function queryAccountBreakdownSince(db, since) {
|
|
|
2450
2474
|
ORDER BY api_equivalent_usd DESC
|
|
2451
2475
|
`).all(since, since);
|
|
2452
2476
|
}
|
|
2453
|
-
function queryDailyBreakdown(db, days = 30, machine) {
|
|
2477
|
+
function queryDailyBreakdown(db, days = 30, machine, now = new Date) {
|
|
2478
|
+
const bounds = resolveReportingInterval({ kind: "rolling", unit: "day", count: days }, now);
|
|
2454
2479
|
const machineClause = machine ? " AND machine_id = ?" : "";
|
|
2455
|
-
const params = machine ? [
|
|
2480
|
+
const params = machine ? [bounds.start, bounds.end_exclusive, machine] : [bounds.start, bounds.end_exclusive];
|
|
2456
2481
|
return db.prepare(`
|
|
2457
2482
|
SELECT DATE(timestamp) as date, agent, COALESCE(SUM(cost_usd), 0) as cost_usd
|
|
2458
2483
|
FROM economy_effective_requests
|
|
2459
|
-
WHERE timestamp >=
|
|
2484
|
+
WHERE timestamp >= ? AND timestamp < ?${machineClause}
|
|
2460
2485
|
GROUP BY DATE(timestamp), agent
|
|
2461
2486
|
ORDER BY date ASC
|
|
2462
2487
|
`).all(...params);
|
|
2463
2488
|
}
|
|
2464
|
-
function queryHourlyBreakdown(db, machine, hours) {
|
|
2465
|
-
const
|
|
2466
|
-
const
|
|
2489
|
+
function queryHourlyBreakdown(db, machine, hours, now = new Date) {
|
|
2490
|
+
const bounds = resolveReportingInterval(hours == null ? { kind: "calendar", period: "today" } : { kind: "rolling", unit: "hour", count: hours }, now);
|
|
2491
|
+
const clauses = hours == null ? ["timestamp >= ? AND timestamp < ?"] : ["STRFTIME('%Y-%m-%dT%H:%M:%fZ', timestamp) >= ? AND STRFTIME('%Y-%m-%dT%H:%M:%fZ', timestamp) < ?"];
|
|
2492
|
+
const params = [bounds.start, bounds.end_exclusive];
|
|
2467
2493
|
if (machine) {
|
|
2468
2494
|
clauses.push("machine_id = ?");
|
|
2469
2495
|
params.push(machine);
|
|
@@ -3369,4 +3395,4 @@ function computeCostWithPricing(model, pricing, inputTokens, outputTokens, cache
|
|
|
3369
3395
|
return (inputTokens * effective.inputPer1M + outputTokens * effective.outputPer1M + cacheReadTokens * effective.cacheReadPer1M + cacheWriteTokens * effective.cacheWritePer1M + cacheWrite1hTokens * (effective.cacheWrite1hPer1M ?? effective.cacheWritePer1M) + cacheStorageTokenHours * (effective.cacheStoragePer1MHour ?? 0)) / 1e6;
|
|
3370
3396
|
}
|
|
3371
3397
|
|
|
3372
|
-
export { __require, AGENTS, COST_BASIS, isAgent, subscriptionId, MAX_INGEST_BYTES, stableJson, canonicalIngestBodyHash, validateIngest, calendarPeriodBounds, calendarPeriodWhere, usageSnapshotFilterForPeriod, sessionOverlapWhere, dataDir, cacheDir, getMachineId, getHomeDir, getResolverDataRoot, getLegacyDataRoot, adoptResolverDataRoot, getExactDataRoot, getDataDir, getDbPath, initSchema, upsertCostCenter, getCostCenter, upsertRequest, upsertSession, rollupSession, querySessions, queryTopSessions, querySummary, queryZeroCostTokenizedModels, queryModelBreakdown, queryAgentBreakdown, queryProjectBreakdown, queryAccountBreakdown, queryCostCenterBreakdown, queryProjectBreakdownSince, queryAgentBreakdownSince, queryModelBreakdownSince, queryAccountBreakdownSince, queryDailyBreakdown, queryHourlyBreakdown, upsertProject, getProject, listProjects, deleteProject, upsertBudget, listBudgets, deleteBudget, getBudgetStatuses, upsertGoal, deleteGoal, listGoals, getGoalStatuses, getIngestState, loadIngestState, setIngestState, queryRequestsSince, insertFeedback, upsertBillingDaily, clearBillingRange, queryBillingSummary, countBillingRecords, getSessionDetail, listMachines, upsertModelPricing, getModelPricing, listModelPricing, deleteModelPricing, seedModelPricing, upsertSubscription, listSubscriptions, deleteSubscription, upsertUsageSnapshot, upsertScanReceipt, queryScanReceipts, queryUsageSnapshots, listMachineRegistry, dedupeRequests, bulkIngest, DEFAULT_PRICING, normalizeModelName, ensurePricingSeeded, getPricingFromDb, getPricing, computeCost, computeCostFromDb, UnknownModelPricingError, assessCostFromDb, getPricingFromRows, estimateCostFromRows, assessCostFromRows, hasKnownUsagePrice, requireCurrentCostSummary, requireCurrentBillingSummary };
|
|
3398
|
+
export { __require, AGENTS, COST_BASIS, isAgent, subscriptionId, MAX_INGEST_BYTES, stableJson, canonicalIngestBodyHash, validateIngest, resolveReportingInterval, calendarPeriodBounds, calendarPeriodWhere, usageSnapshotFilterForPeriod, sessionOverlapWhere, dataDir, cacheDir, getMachineId, getHomeDir, getResolverDataRoot, getLegacyDataRoot, adoptResolverDataRoot, getExactDataRoot, getDataDir, getDbPath, initSchema, upsertCostCenter, getCostCenter, upsertRequest, upsertSession, rollupSession, querySessions, queryTopSessions, querySummary, queryZeroCostTokenizedModels, queryModelBreakdown, queryAgentBreakdown, queryProjectBreakdown, queryAccountBreakdown, queryCostCenterBreakdown, queryProjectBreakdownSince, queryAgentBreakdownSince, queryModelBreakdownSince, queryAccountBreakdownSince, queryDailyBreakdown, queryHourlyBreakdown, upsertProject, getProject, listProjects, deleteProject, upsertBudget, listBudgets, deleteBudget, getBudgetStatuses, upsertGoal, deleteGoal, listGoals, getGoalStatuses, getIngestState, loadIngestState, setIngestState, queryRequestsSince, insertFeedback, upsertBillingDaily, clearBillingRange, queryBillingSummary, countBillingRecords, getSessionDetail, listMachines, upsertModelPricing, getModelPricing, listModelPricing, deleteModelPricing, seedModelPricing, upsertSubscription, listSubscriptions, deleteSubscription, upsertUsageSnapshot, upsertScanReceipt, queryScanReceipts, queryUsageSnapshots, listMachineRegistry, dedupeRequests, bulkIngest, DEFAULT_PRICING, normalizeModelName, ensurePricingSeeded, getPricingFromDb, getPricing, computeCost, computeCostFromDb, UnknownModelPricingError, assessCostFromDb, getPricingFromRows, estimateCostFromRows, assessCostFromRows, hasKnownUsagePrice, requireCurrentCostSummary, requireCurrentBillingSummary };
|
|
@@ -1097,12 +1097,32 @@ function meteredBudgetAmounts(groups, limit, threshold) {
|
|
|
1097
1097
|
function ymd(date2) {
|
|
1098
1098
|
return date2.toISOString().substring(0, 10);
|
|
1099
1099
|
}
|
|
1100
|
-
function
|
|
1100
|
+
function resolveReportingInterval(interval, now = new Date) {
|
|
1101
1101
|
if (!Number.isFinite(now.getTime()))
|
|
1102
1102
|
throw new RangeError("Invalid reporting clock");
|
|
1103
|
-
const start = new Date(
|
|
1103
|
+
const start = new Date(now);
|
|
1104
|
+
start.setUTCHours(0, 0, 0, 0);
|
|
1104
1105
|
const end = new Date(start);
|
|
1105
|
-
|
|
1106
|
+
if (interval.kind === "rolling") {
|
|
1107
|
+
if (!Number.isSafeInteger(interval.count) || interval.count < 1)
|
|
1108
|
+
throw new RangeError("Invalid reporting window");
|
|
1109
|
+
if (interval.unit === "hour") {
|
|
1110
|
+
start.setTime(now.getTime() - interval.count * 3600000);
|
|
1111
|
+
if (!Number.isFinite(start.getTime()))
|
|
1112
|
+
throw new RangeError("Invalid reporting window");
|
|
1113
|
+
return { time_zone: "UTC", start: start.toISOString(), end_exclusive: now.toISOString() };
|
|
1114
|
+
}
|
|
1115
|
+
if (interval.unit !== "day")
|
|
1116
|
+
throw new RangeError("Invalid reporting unit");
|
|
1117
|
+
start.setUTCDate(start.getUTCDate() - interval.count + 1);
|
|
1118
|
+
end.setUTCDate(end.getUTCDate() + 1);
|
|
1119
|
+
if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime()))
|
|
1120
|
+
throw new RangeError("Invalid reporting window");
|
|
1121
|
+
return { time_zone: "UTC", start: ymd(start), end_exclusive: ymd(end) };
|
|
1122
|
+
}
|
|
1123
|
+
if (interval.kind !== "calendar")
|
|
1124
|
+
throw new RangeError("Invalid reporting interval");
|
|
1125
|
+
switch (interval.period) {
|
|
1106
1126
|
case "today":
|
|
1107
1127
|
end.setUTCDate(end.getUTCDate() + 1);
|
|
1108
1128
|
break;
|
|
@@ -1125,11 +1145,15 @@ function calendarPeriodBounds(period, now = new Date) {
|
|
|
1125
1145
|
end.setUTCFullYear(end.getUTCFullYear() + 1);
|
|
1126
1146
|
break;
|
|
1127
1147
|
case "all":
|
|
1128
|
-
return { time_zone: "UTC",
|
|
1148
|
+
return { time_zone: "UTC", start: null, end_exclusive: null };
|
|
1129
1149
|
default:
|
|
1130
1150
|
throw new RangeError("Invalid reporting period");
|
|
1131
1151
|
}
|
|
1132
|
-
return { time_zone: "UTC",
|
|
1152
|
+
return { time_zone: "UTC", start: ymd(start), end_exclusive: ymd(end) };
|
|
1153
|
+
}
|
|
1154
|
+
function calendarPeriodBounds(period, now = new Date) {
|
|
1155
|
+
const bounds = resolveReportingInterval({ kind: "calendar", period }, now);
|
|
1156
|
+
return { time_zone: bounds.time_zone, start_date: bounds.start, end_date_exclusive: bounds.end_exclusive };
|
|
1133
1157
|
}
|
|
1134
1158
|
function calendarPeriodWhere(period, column, now = new Date) {
|
|
1135
1159
|
if (!/^[a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)?$/i.test(column)) {
|
|
@@ -2518,20 +2542,22 @@ function queryAccountBreakdownSince(db, since) {
|
|
|
2518
2542
|
ORDER BY api_equivalent_usd DESC
|
|
2519
2543
|
`).all(since, since);
|
|
2520
2544
|
}
|
|
2521
|
-
function queryDailyBreakdown(db, days = 30, machine) {
|
|
2545
|
+
function queryDailyBreakdown(db, days = 30, machine, now = new Date) {
|
|
2546
|
+
const bounds = resolveReportingInterval({ kind: "rolling", unit: "day", count: days }, now);
|
|
2522
2547
|
const machineClause = machine ? " AND machine_id = ?" : "";
|
|
2523
|
-
const params = machine ? [
|
|
2548
|
+
const params = machine ? [bounds.start, bounds.end_exclusive, machine] : [bounds.start, bounds.end_exclusive];
|
|
2524
2549
|
return db.prepare(`
|
|
2525
2550
|
SELECT DATE(timestamp) as date, agent, COALESCE(SUM(cost_usd), 0) as cost_usd
|
|
2526
2551
|
FROM economy_effective_requests
|
|
2527
|
-
WHERE timestamp >=
|
|
2552
|
+
WHERE timestamp >= ? AND timestamp < ?${machineClause}
|
|
2528
2553
|
GROUP BY DATE(timestamp), agent
|
|
2529
2554
|
ORDER BY date ASC
|
|
2530
2555
|
`).all(...params);
|
|
2531
2556
|
}
|
|
2532
|
-
function queryHourlyBreakdown(db, machine, hours) {
|
|
2533
|
-
const
|
|
2534
|
-
const
|
|
2557
|
+
function queryHourlyBreakdown(db, machine, hours, now = new Date) {
|
|
2558
|
+
const bounds = resolveReportingInterval(hours == null ? { kind: "calendar", period: "today" } : { kind: "rolling", unit: "hour", count: hours }, now);
|
|
2559
|
+
const clauses = hours == null ? ["timestamp >= ? AND timestamp < ?"] : ["STRFTIME('%Y-%m-%dT%H:%M:%fZ', timestamp) >= ? AND STRFTIME('%Y-%m-%dT%H:%M:%fZ', timestamp) < ?"];
|
|
2560
|
+
const params = [bounds.start, bounds.end_exclusive];
|
|
2535
2561
|
if (machine) {
|
|
2536
2562
|
clauses.push("machine_id = ?");
|
|
2537
2563
|
params.push(machine);
|
|
@@ -3437,4 +3463,4 @@ function computeCostWithPricing(model, pricing, inputTokens, outputTokens, cache
|
|
|
3437
3463
|
return (inputTokens * effective.inputPer1M + outputTokens * effective.outputPer1M + cacheReadTokens * effective.cacheReadPer1M + cacheWriteTokens * effective.cacheWritePer1M + cacheWrite1hTokens * (effective.cacheWrite1hPer1M ?? effective.cacheWritePer1M) + cacheStorageTokenHours * (effective.cacheStoragePer1MHour ?? 0)) / 1e6;
|
|
3438
3464
|
}
|
|
3439
3465
|
|
|
3440
|
-
export { OBSERVATION_PG_MIGRATIONS, IngestError, observationId, subscriptionId, scanReceiptId, AGENTS, isAgent, parseAgent, MAX_INGEST_ROWS, MAX_INGEST_BYTES, stableJson, canonicalIngestBodyHash, validateIngest, INGEST_SCHEMA_SQL, LEGACY_PG_SQL, reconcileIngestReceipt, calendarPeriodBounds, calendarPeriodWhere, usageSnapshotFilterForPeriod, sessionOverlapWhere, dataDir, cacheDir, getMachineId, getHomeDir, getResolverDataRoot, getLegacyDataRoot, adoptResolverDataRoot, getExactDataRoot, getDataDir, getDbPath, initSchema, upsertCostCenter, getCostCenter, upsertRequest, upsertSession, rollupSession, querySessions, queryTopSessions, querySummary, queryZeroCostTokenizedModels, queryModelBreakdown, queryAgentBreakdown, queryProjectBreakdown, queryAccountBreakdown, queryCostCenterBreakdown, queryProjectBreakdownSince, queryAgentBreakdownSince, queryModelBreakdownSince, queryAccountBreakdownSince, queryDailyBreakdown, queryHourlyBreakdown, upsertProject, getProject, listProjects, deleteProject, upsertBudget, listBudgets, deleteBudget, getBudgetStatuses, upsertGoal, deleteGoal, listGoals, getGoalStatuses, getIngestState, loadIngestState, setIngestState, queryRequestsSince, insertFeedback, upsertBillingDaily, clearBillingRange, queryBillingSummary, countBillingRecords, getSessionDetail, listMachines, upsertModelPricing, getModelPricing, listModelPricing, deleteModelPricing, seedModelPricing, upsertSubscription, listSubscriptions, deleteSubscription, upsertUsageSnapshot, upsertScanReceipt, queryScanReceipts, queryUsageSnapshots, listMachineRegistry, dedupeRequests, bulkIngest, DEFAULT_PRICING, normalizeModelName, ensurePricingSeeded, getPricingFromDb, getPricing, computeCost, computeCostFromDb, UnknownModelPricingError, assessCostFromDb, getPricingFromRows, estimateCostFromRows, assessCostFromRows, formatReportedUsd, formatPlanMoney, hasKnownUsagePrice, requireCurrentCostSummary, formatSummaryValue, formatSummaryCoverage, requireCurrentBillingSummary, formatBillingValue };
|
|
3466
|
+
export { OBSERVATION_PG_MIGRATIONS, IngestError, observationId, subscriptionId, scanReceiptId, AGENTS, isAgent, parseAgent, MAX_INGEST_ROWS, MAX_INGEST_BYTES, stableJson, canonicalIngestBodyHash, validateIngest, INGEST_SCHEMA_SQL, LEGACY_PG_SQL, reconcileIngestReceipt, resolveReportingInterval, calendarPeriodBounds, calendarPeriodWhere, usageSnapshotFilterForPeriod, sessionOverlapWhere, dataDir, cacheDir, getMachineId, getHomeDir, getResolverDataRoot, getLegacyDataRoot, adoptResolverDataRoot, getExactDataRoot, getDataDir, getDbPath, initSchema, upsertCostCenter, getCostCenter, upsertRequest, upsertSession, rollupSession, querySessions, queryTopSessions, querySummary, queryZeroCostTokenizedModels, queryModelBreakdown, queryAgentBreakdown, queryProjectBreakdown, queryAccountBreakdown, queryCostCenterBreakdown, queryProjectBreakdownSince, queryAgentBreakdownSince, queryModelBreakdownSince, queryAccountBreakdownSince, queryDailyBreakdown, queryHourlyBreakdown, upsertProject, getProject, listProjects, deleteProject, upsertBudget, listBudgets, deleteBudget, getBudgetStatuses, upsertGoal, deleteGoal, listGoals, getGoalStatuses, getIngestState, loadIngestState, setIngestState, queryRequestsSince, insertFeedback, upsertBillingDaily, clearBillingRange, queryBillingSummary, countBillingRecords, getSessionDetail, listMachines, upsertModelPricing, getModelPricing, listModelPricing, deleteModelPricing, seedModelPricing, upsertSubscription, listSubscriptions, deleteSubscription, upsertUsageSnapshot, upsertScanReceipt, queryScanReceipts, queryUsageSnapshots, listMachineRegistry, dedupeRequests, bulkIngest, DEFAULT_PRICING, normalizeModelName, ensurePricingSeeded, getPricingFromDb, getPricing, computeCost, computeCostFromDb, UnknownModelPricingError, assessCostFromDb, getPricingFromRows, estimateCostFromRows, assessCostFromRows, formatReportedUsd, formatPlanMoney, hasKnownUsagePrice, requireCurrentCostSummary, formatSummaryValue, formatSummaryCoverage, requireCurrentBillingSummary, formatBillingValue };
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
querySavingsSummary,
|
|
15
15
|
requireCurrentBillingDiffSummary,
|
|
16
16
|
requireCurrentSavingsReport
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-1vz1arz5.js";
|
|
18
18
|
import {
|
|
19
19
|
deleteBudget,
|
|
20
20
|
deleteGoal,
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
upsertSubscription,
|
|
60
60
|
usageSnapshotFilterForPeriod,
|
|
61
61
|
validateIngest
|
|
62
|
-
} from "./index-
|
|
62
|
+
} from "./index-f5jv6q5q.js";
|
|
63
63
|
import {
|
|
64
64
|
__require
|
|
65
65
|
} from "./index-p35cyhc4.js";
|
|
@@ -92,7 +92,7 @@ class LocalStore {
|
|
|
92
92
|
_db;
|
|
93
93
|
async db() {
|
|
94
94
|
if (!this._db) {
|
|
95
|
-
const { openDatabase } = await import("./sqlite-store-
|
|
95
|
+
const { openDatabase } = await import("./sqlite-store-13nhr1z0.js");
|
|
96
96
|
this._db = openDatabase();
|
|
97
97
|
ensurePricingSeeded(this._db);
|
|
98
98
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
LOCAL_STORAGE_OPT_IN_KEYS
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-1vz1arz5.js";
|
|
5
5
|
import {
|
|
6
6
|
assessCostFromDb,
|
|
7
7
|
getIngestState,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
upsertSession,
|
|
20
20
|
upsertSubscription,
|
|
21
21
|
upsertUsageSnapshot
|
|
22
|
-
} from "./index-
|
|
22
|
+
} from "./index-f5jv6q5q.js";
|
|
23
23
|
import {
|
|
24
24
|
__require
|
|
25
25
|
} from "./index-p35cyhc4.js";
|
|
@@ -1064,12 +1064,32 @@ function meteredBudgetAmounts(groups, limit, threshold) {
|
|
|
1064
1064
|
function ymd(date2) {
|
|
1065
1065
|
return date2.toISOString().substring(0, 10);
|
|
1066
1066
|
}
|
|
1067
|
-
function
|
|
1067
|
+
function resolveReportingInterval(interval, now = new Date) {
|
|
1068
1068
|
if (!Number.isFinite(now.getTime()))
|
|
1069
1069
|
throw new RangeError("Invalid reporting clock");
|
|
1070
|
-
const start = new Date(
|
|
1070
|
+
const start = new Date(now);
|
|
1071
|
+
start.setUTCHours(0, 0, 0, 0);
|
|
1071
1072
|
const end = new Date(start);
|
|
1072
|
-
|
|
1073
|
+
if (interval.kind === "rolling") {
|
|
1074
|
+
if (!Number.isSafeInteger(interval.count) || interval.count < 1)
|
|
1075
|
+
throw new RangeError("Invalid reporting window");
|
|
1076
|
+
if (interval.unit === "hour") {
|
|
1077
|
+
start.setTime(now.getTime() - interval.count * 3600000);
|
|
1078
|
+
if (!Number.isFinite(start.getTime()))
|
|
1079
|
+
throw new RangeError("Invalid reporting window");
|
|
1080
|
+
return { time_zone: "UTC", start: start.toISOString(), end_exclusive: now.toISOString() };
|
|
1081
|
+
}
|
|
1082
|
+
if (interval.unit !== "day")
|
|
1083
|
+
throw new RangeError("Invalid reporting unit");
|
|
1084
|
+
start.setUTCDate(start.getUTCDate() - interval.count + 1);
|
|
1085
|
+
end.setUTCDate(end.getUTCDate() + 1);
|
|
1086
|
+
if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime()))
|
|
1087
|
+
throw new RangeError("Invalid reporting window");
|
|
1088
|
+
return { time_zone: "UTC", start: ymd(start), end_exclusive: ymd(end) };
|
|
1089
|
+
}
|
|
1090
|
+
if (interval.kind !== "calendar")
|
|
1091
|
+
throw new RangeError("Invalid reporting interval");
|
|
1092
|
+
switch (interval.period) {
|
|
1073
1093
|
case "today":
|
|
1074
1094
|
end.setUTCDate(end.getUTCDate() + 1);
|
|
1075
1095
|
break;
|
|
@@ -1092,11 +1112,15 @@ function calendarPeriodBounds(period, now = new Date) {
|
|
|
1092
1112
|
end.setUTCFullYear(end.getUTCFullYear() + 1);
|
|
1093
1113
|
break;
|
|
1094
1114
|
case "all":
|
|
1095
|
-
return { time_zone: "UTC",
|
|
1115
|
+
return { time_zone: "UTC", start: null, end_exclusive: null };
|
|
1096
1116
|
default:
|
|
1097
1117
|
throw new RangeError("Invalid reporting period");
|
|
1098
1118
|
}
|
|
1099
|
-
return { time_zone: "UTC",
|
|
1119
|
+
return { time_zone: "UTC", start: ymd(start), end_exclusive: ymd(end) };
|
|
1120
|
+
}
|
|
1121
|
+
function calendarPeriodBounds(period, now = new Date) {
|
|
1122
|
+
const bounds = resolveReportingInterval({ kind: "calendar", period }, now);
|
|
1123
|
+
return { time_zone: bounds.time_zone, start_date: bounds.start, end_date_exclusive: bounds.end_exclusive };
|
|
1100
1124
|
}
|
|
1101
1125
|
function calendarPeriodWhere(period, column, now = new Date) {
|
|
1102
1126
|
if (!/^[a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)?$/i.test(column)) {
|
|
@@ -2485,20 +2509,22 @@ function queryAccountBreakdownSince(db, since) {
|
|
|
2485
2509
|
ORDER BY api_equivalent_usd DESC
|
|
2486
2510
|
`).all(since, since);
|
|
2487
2511
|
}
|
|
2488
|
-
function queryDailyBreakdown(db, days = 30, machine) {
|
|
2512
|
+
function queryDailyBreakdown(db, days = 30, machine, now = new Date) {
|
|
2513
|
+
const bounds = resolveReportingInterval({ kind: "rolling", unit: "day", count: days }, now);
|
|
2489
2514
|
const machineClause = machine ? " AND machine_id = ?" : "";
|
|
2490
|
-
const params = machine ? [
|
|
2515
|
+
const params = machine ? [bounds.start, bounds.end_exclusive, machine] : [bounds.start, bounds.end_exclusive];
|
|
2491
2516
|
return db.prepare(`
|
|
2492
2517
|
SELECT DATE(timestamp) as date, agent, COALESCE(SUM(cost_usd), 0) as cost_usd
|
|
2493
2518
|
FROM economy_effective_requests
|
|
2494
|
-
WHERE timestamp >=
|
|
2519
|
+
WHERE timestamp >= ? AND timestamp < ?${machineClause}
|
|
2495
2520
|
GROUP BY DATE(timestamp), agent
|
|
2496
2521
|
ORDER BY date ASC
|
|
2497
2522
|
`).all(...params);
|
|
2498
2523
|
}
|
|
2499
|
-
function queryHourlyBreakdown(db, machine, hours) {
|
|
2500
|
-
const
|
|
2501
|
-
const
|
|
2524
|
+
function queryHourlyBreakdown(db, machine, hours, now = new Date) {
|
|
2525
|
+
const bounds = resolveReportingInterval(hours == null ? { kind: "calendar", period: "today" } : { kind: "rolling", unit: "hour", count: hours }, now);
|
|
2526
|
+
const clauses = hours == null ? ["timestamp >= ? AND timestamp < ?"] : ["STRFTIME('%Y-%m-%dT%H:%M:%fZ', timestamp) >= ? AND STRFTIME('%Y-%m-%dT%H:%M:%fZ', timestamp) < ?"];
|
|
2527
|
+
const params = [bounds.start, bounds.end_exclusive];
|
|
2502
2528
|
if (machine) {
|
|
2503
2529
|
clauses.push("machine_id = ?");
|
|
2504
2530
|
params.push(machine);
|
|
@@ -3404,4 +3430,4 @@ function computeCostWithPricing(model, pricing, inputTokens, outputTokens, cache
|
|
|
3404
3430
|
return (inputTokens * effective.inputPer1M + outputTokens * effective.outputPer1M + cacheReadTokens * effective.cacheReadPer1M + cacheWriteTokens * effective.cacheWritePer1M + cacheWrite1hTokens * (effective.cacheWrite1hPer1M ?? effective.cacheWritePer1M) + cacheStorageTokenHours * (effective.cacheStoragePer1MHour ?? 0)) / 1e6;
|
|
3405
3431
|
}
|
|
3406
3432
|
|
|
3407
|
-
export { observationId, subscriptionId, scanReceiptId, AGENTS, MAX_INGEST_ROWS, MAX_INGEST_BYTES, stableJson, canonicalIngestBodyHash, validateIngest, calendarPeriodBounds, calendarPeriodWhere, usageSnapshotFilterForPeriod, sessionOverlapWhere, dataDir, cacheDir, getMachineId, getHomeDir, getResolverDataRoot, getLegacyDataRoot, adoptResolverDataRoot, getExactDataRoot, getDataDir, getDbPath, initSchema, upsertCostCenter, getCostCenter, upsertRequest, upsertSession, rollupSession, querySessions, queryTopSessions, querySummary, queryZeroCostTokenizedModels, queryModelBreakdown, queryAgentBreakdown, queryProjectBreakdown, queryAccountBreakdown, queryCostCenterBreakdown, queryProjectBreakdownSince, queryAgentBreakdownSince, queryModelBreakdownSince, queryAccountBreakdownSince, queryDailyBreakdown, queryHourlyBreakdown, upsertProject, getProject, listProjects, deleteProject, upsertBudget, listBudgets, deleteBudget, getBudgetStatuses, upsertGoal, deleteGoal, listGoals, getGoalStatuses, getIngestState, loadIngestState, setIngestState, queryRequestsSince, insertFeedback, upsertBillingDaily, clearBillingRange, queryBillingSummary, countBillingRecords, getSessionDetail, listMachines, upsertModelPricing, getModelPricing, listModelPricing, deleteModelPricing, seedModelPricing, upsertSubscription, listSubscriptions, deleteSubscription, upsertUsageSnapshot, upsertScanReceipt, queryScanReceipts, queryUsageSnapshots, listMachineRegistry, dedupeRequests, bulkIngest, DEFAULT_PRICING, normalizeModelName, ensurePricingSeeded, getPricingFromDb, getPricing, computeCost, computeCostFromDb, UnknownModelPricingError, assessCostFromDb, getPricingFromRows, estimateCostFromRows, assessCostFromRows, formatReportedUsd, formatPlanMoney, hasKnownUsagePrice, requireCurrentCostSummary, formatSummaryValue, formatSummaryCoverage, requireCurrentBillingSummary, formatBillingValue };
|
|
3433
|
+
export { observationId, subscriptionId, scanReceiptId, AGENTS, MAX_INGEST_ROWS, MAX_INGEST_BYTES, stableJson, canonicalIngestBodyHash, validateIngest, resolveReportingInterval, calendarPeriodBounds, calendarPeriodWhere, usageSnapshotFilterForPeriod, sessionOverlapWhere, dataDir, cacheDir, getMachineId, getHomeDir, getResolverDataRoot, getLegacyDataRoot, adoptResolverDataRoot, getExactDataRoot, getDataDir, getDbPath, initSchema, upsertCostCenter, getCostCenter, upsertRequest, upsertSession, rollupSession, querySessions, queryTopSessions, querySummary, queryZeroCostTokenizedModels, queryModelBreakdown, queryAgentBreakdown, queryProjectBreakdown, queryAccountBreakdown, queryCostCenterBreakdown, queryProjectBreakdownSince, queryAgentBreakdownSince, queryModelBreakdownSince, queryAccountBreakdownSince, queryDailyBreakdown, queryHourlyBreakdown, upsertProject, getProject, listProjects, deleteProject, upsertBudget, listBudgets, deleteBudget, getBudgetStatuses, upsertGoal, deleteGoal, listGoals, getGoalStatuses, getIngestState, loadIngestState, setIngestState, queryRequestsSince, insertFeedback, upsertBillingDaily, clearBillingRange, queryBillingSummary, countBillingRecords, getSessionDetail, listMachines, upsertModelPricing, getModelPricing, listModelPricing, deleteModelPricing, seedModelPricing, upsertSubscription, listSubscriptions, deleteSubscription, upsertUsageSnapshot, upsertScanReceipt, queryScanReceipts, queryUsageSnapshots, listMachineRegistry, dedupeRequests, bulkIngest, DEFAULT_PRICING, normalizeModelName, ensurePricingSeeded, getPricingFromDb, getPricing, computeCost, computeCostFromDb, UnknownModelPricingError, assessCostFromDb, getPricingFromRows, estimateCostFromRows, assessCostFromRows, formatReportedUsd, formatPlanMoney, hasKnownUsagePrice, requireCurrentCostSummary, formatSummaryValue, formatSummaryCoverage, requireCurrentBillingSummary, formatBillingValue };
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./index-w3bvv0ns.js";
|
|
6
6
|
import {
|
|
7
7
|
syncAll
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-s9mvven6.js";
|
|
9
9
|
import {
|
|
10
10
|
buildBrief,
|
|
11
11
|
packageMetadata,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
queryProjectDetail,
|
|
17
17
|
queryRangeStats,
|
|
18
18
|
querySavingsSummary
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-1vz1arz5.js";
|
|
20
20
|
import {
|
|
21
21
|
AGENTS,
|
|
22
22
|
INGEST_SCHEMA_SQL,
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
queryTopSessions,
|
|
60
60
|
queryUsageSnapshots,
|
|
61
61
|
reconcileIngestReceipt,
|
|
62
|
+
resolveReportingInterval,
|
|
62
63
|
subscriptionId,
|
|
63
64
|
upsertBudget,
|
|
64
65
|
upsertGoal,
|
|
@@ -66,7 +67,7 @@ import {
|
|
|
66
67
|
upsertProject,
|
|
67
68
|
upsertSubscription,
|
|
68
69
|
usageSnapshotFilterForPeriod
|
|
69
|
-
} from "./index-
|
|
70
|
+
} from "./index-f5jv6q5q.js";
|
|
70
71
|
import {
|
|
71
72
|
__require
|
|
72
73
|
} from "./index-p35cyhc4.js";
|
|
@@ -133,15 +134,16 @@ function translateSqliteDates(sql) {
|
|
|
133
134
|
s = s.replace(/DATE\('now',\s*(\$\d+)\s*\|\|\s*' days'\)/gi, (_m, p) => isoDate(`now() + ((${p}) || ' days')::interval`));
|
|
134
135
|
s = s.replace(/DATETIME\('now',\s*(\$\d+)\)/gi, (_m, p) => `(now() + (${p})::interval)`);
|
|
135
136
|
s = s.replace(/DATETIME\('now',\s*'([^']+)'\)/gi, (_m, lit) => `(now() + interval '${lit}')`);
|
|
137
|
+
s = s.replace(/STRFTIME\('%Y-%m-%dT%H:%M:%fZ',\s*([A-Za-z_][A-Za-z0-9_]*)\)/gi, (_m, col) => `to_char(CAST("${col}" AS timestamptz) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`);
|
|
136
138
|
const strftimeMap = { "%H": "HH24", "%Y": "YYYY", "%m": "MM", "%d": "DD", "%M": "MI", "%S": "SS" };
|
|
137
139
|
s = s.replace(/STRFTIME\('([^']+)',\s*([A-Za-z_][A-Za-z0-9_]*)\)/gi, (_m, fmt, col) => {
|
|
138
140
|
const pgFmt = Object.entries(strftimeMap).reduce((acc, [k, v]) => acc.split(k).join(v), fmt);
|
|
139
|
-
return `to_char(CAST("${col}" AS timestamptz), '${pgFmt}')`;
|
|
141
|
+
return `to_char(CAST("${col}" AS timestamptz) AT TIME ZONE 'UTC', '${pgFmt}')`;
|
|
140
142
|
});
|
|
141
143
|
s = s.replace(/\bDATE\('now'\)/gi, isoDate("now()"));
|
|
142
144
|
s = s.replace(/\bDATETIME\('now'\)/gi, "now()");
|
|
143
145
|
s = s.replace(/\bDATETIME\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/gi, (_m, col) => `CAST("${col}" AS timestamptz)`);
|
|
144
|
-
s = s.replace(/\bDATE\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/gi, (_m, col) => `substr("${
|
|
146
|
+
s = s.replace(/\bDATE\(\s*([A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)?)\s*\)/gi, (_m, col) => `substr(${col.split(".").map((part) => `"${part}"`).join(".")}, 1, 10)`);
|
|
145
147
|
return s;
|
|
146
148
|
}
|
|
147
149
|
function resolveWorkerPath() {
|
|
@@ -3836,7 +3838,13 @@ function createDataHandler(db, actorId) {
|
|
|
3836
3838
|
if (path === "/api/daily" && method === "GET") {
|
|
3837
3839
|
const days = Number(url.searchParams.get("days") ?? 30);
|
|
3838
3840
|
const machine = url.searchParams.get("machine") ?? undefined;
|
|
3839
|
-
|
|
3841
|
+
const now = new Date;
|
|
3842
|
+
try {
|
|
3843
|
+
resolveReportingInterval({ kind: "rolling", unit: "day", count: days }, now);
|
|
3844
|
+
} catch {
|
|
3845
|
+
return err("days must be a positive integer within the supported UTC date range");
|
|
3846
|
+
}
|
|
3847
|
+
return ok(queryDailyBreakdown(db, days, machine, now));
|
|
3840
3848
|
}
|
|
3841
3849
|
if (path === "/api/hourly" && method === "GET") {
|
|
3842
3850
|
const machine = url.searchParams.get("machine") ?? undefined;
|
|
@@ -3902,7 +3910,7 @@ function createDataHandler(db, actorId) {
|
|
|
3902
3910
|
if (providers.some((provider) => !allowedProviders.has(provider)))
|
|
3903
3911
|
return err("invalid billing provider");
|
|
3904
3912
|
const results = {};
|
|
3905
|
-
const { syncAnthropicBilling, syncOpenAIBilling, syncGeminiBilling } = await import("./billing-
|
|
3913
|
+
const { syncAnthropicBilling, syncOpenAIBilling, syncGeminiBilling } = await import("./billing-22az60hy.js");
|
|
3906
3914
|
async function capture(provider, fn) {
|
|
3907
3915
|
try {
|
|
3908
3916
|
results[provider] = await fn();
|
|
@@ -4057,7 +4065,7 @@ function createDataHandler(db, actorId) {
|
|
|
4057
4065
|
const results = {};
|
|
4058
4066
|
if (sources === "all") {
|
|
4059
4067
|
try {
|
|
4060
|
-
const { syncOpenProjectsRegistry } = await import("./open-projects-
|
|
4068
|
+
const { syncOpenProjectsRegistry } = await import("./open-projects-8qm46m3d.js");
|
|
4061
4069
|
results["projects"] = await syncOpenProjectsRegistry(db);
|
|
4062
4070
|
} catch {}
|
|
4063
4071
|
}
|
|
@@ -4065,7 +4073,7 @@ function createDataHandler(db, actorId) {
|
|
|
4065
4073
|
const syncResult = await syncAll(db, selected);
|
|
4066
4074
|
Object.assign(results, syncResult);
|
|
4067
4075
|
try {
|
|
4068
|
-
const { checkAndFireWebhooks } = await import("./webhooks-
|
|
4076
|
+
const { checkAndFireWebhooks } = await import("./webhooks-nw4daw9y.js");
|
|
4069
4077
|
await checkAndFireWebhooks(db);
|
|
4070
4078
|
} catch {}
|
|
4071
4079
|
return ok(results);
|
|
@@ -4089,7 +4097,7 @@ function createDataHandler(db, actorId) {
|
|
|
4089
4097
|
return err("invalid JSON body");
|
|
4090
4098
|
const result = bulkIngest(db, body, { actorId });
|
|
4091
4099
|
try {
|
|
4092
|
-
const { checkAndFireWebhooks } = await import("./webhooks-
|
|
4100
|
+
const { checkAndFireWebhooks } = await import("./webhooks-nw4daw9y.js");
|
|
4093
4101
|
if (body["budget_mode"] !== "create")
|
|
4094
4102
|
await checkAndFireWebhooks(db);
|
|
4095
4103
|
} catch {}
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
upsertSession,
|
|
70
70
|
upsertSubscription,
|
|
71
71
|
upsertUsageSnapshot
|
|
72
|
-
} from "./index-
|
|
72
|
+
} from "./index-f5jv6q5q.js";
|
|
73
73
|
import {
|
|
74
74
|
__require
|
|
75
75
|
} from "./index-p35cyhc4.js";
|
|
@@ -180,7 +180,7 @@ function openDatabase(dbPath, skipSeed = false) {
|
|
|
180
180
|
}
|
|
181
181
|
}, `opening ${path}`);
|
|
182
182
|
if (!skipSeed) {
|
|
183
|
-
import("./pricing-
|
|
183
|
+
import("./pricing-462f8xkm.js").then(({ ensurePricingSeeded }) => ensurePricingSeeded(db)).catch(() => {});
|
|
184
184
|
}
|
|
185
185
|
return db;
|
|
186
186
|
}
|