routstrd 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14293,13 +14293,22 @@ function renderToday(stats, width) {
14293
14293
  const currentHour = new Date().getHours();
14294
14294
  const _now = new Date;
14295
14295
  const todayDateStr = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
14296
- let todayStats;
14297
- let recentDays;
14298
- let hourlyMap;
14296
+ let todayStats = {
14297
+ date: todayDateStr,
14298
+ requests: 0,
14299
+ satsCost: 0,
14300
+ promptTokens: 0,
14301
+ completionTokens: 0,
14302
+ totalTokens: 0
14303
+ };
14304
+ let recentDays = [];
14305
+ let hourlyMap = new Map;
14299
14306
  if (stats.summary) {
14300
14307
  const { days, hoursToday } = stats.summary;
14301
14308
  const todayDayStat = days[0]?.date === todayDateStr ? days[0] : undefined;
14302
- todayStats = todayDayStat ? { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens } : { date: todayDateStr, requests: 0, satsCost: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0 };
14309
+ if (todayDayStat) {
14310
+ todayStats = { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens };
14311
+ }
14303
14312
  recentDays = days.filter((d) => d.date !== todayDateStr).slice(0, 6);
14304
14313
  hourlyMap = new Map(hoursToday.map((h) => [h.hour, { requests: h.requests, satsCost: h.satsCost }]));
14305
14314
  }
@@ -15587,7 +15596,7 @@ async function isCocodInstalled(cocodPath) {
15587
15596
  // package.json
15588
15597
  var package_default = {
15589
15598
  name: "routstrd",
15590
- version: "0.3.4",
15599
+ version: "0.3.5",
15591
15600
  module: "src/index.ts",
15592
15601
  type: "module",
15593
15602
  private: false,
@@ -15611,7 +15620,7 @@ var package_default = {
15611
15620
  },
15612
15621
  dependencies: {
15613
15622
  "@cashu/cashu-ts": "^4.3.0",
15614
- "@routstr/sdk": "^0.3.12",
15623
+ "@routstr/sdk": "^0.3.14",
15615
15624
  "applesauce-core": "^5.1.0",
15616
15625
  "applesauce-relay": "^5.1.0",
15617
15626
  "applesauce-wallet-connect": "^6.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routstrd",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "module": "src/index.ts",
5
5
  "type": "module",
6
6
  "private": false,
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@cashu/cashu-ts": "^4.3.0",
27
- "@routstr/sdk": "^0.3.12",
27
+ "@routstr/sdk": "^0.3.14",
28
28
  "applesauce-core": "^5.1.0",
29
29
  "applesauce-relay": "^5.1.0",
30
30
  "applesauce-wallet-connect": "^6.0.0",
@@ -6,15 +6,27 @@ import { getUsageSummary, __resetUsageSummaryCacheForTest } from "./usage-summar
6
6
 
7
7
  // ─── Test fixtures ────────────────────────────────────────────────────────────
8
8
  //
9
- // All timestamps fall within 30 days of 2026-06-02 (today as of this writing).
9
+ // All timestamps are computed relative to "now" so the fixtures never age
10
+ // out of getUsageSummary's 30-day rolling window. We anchor to a recent UTC
11
+ // midnight ~10 days ago and keep the same hour-of-day structure the
12
+ // tz-bucketing assertions depend on.
13
+ //
10
14
  // tz = 300 (UTC-5 / EST). After shifting by -300min, UTC dates become:
11
- // d1: 2026-05-20T10:00Z → shifted 2026-05-20T05:00Z → local day "2026-05-20", hour 05
12
- // d2: 2026-05-21T03:00Z → shifted 2026-05-20T22:00Z → local day "2026-05-20", hour 22
13
- // d3: 2026-05-21T06:00Z → shifted 2026-05-21T01:00Z → local day "2026-05-21", hour 01
14
-
15
- const D1 = new Date("2026-05-20T10:00:00Z").getTime(); // local 2026-05-20, hour 05
16
- const D2 = new Date("2026-05-21T03:00:00Z").getTime(); // local 2026-05-20, hour 22
17
- const D3 = new Date("2026-05-21T06:00:00Z").getTime(); // local 2026-05-21, hour 01
15
+ // d1: <anchor> 10:00Z → local <anchor> 05:00 → local day "<anchor>"
16
+ // d2: <anchor+1d> 03:00Z → local <anchor> 22:00 → local day "<anchor>"
17
+ // d3: <anchor+1d> 06:00Z → local <anchor+1d> 01:00 → local day "<anchor+1d>"
18
+
19
+ const _BASE_UTC_MIDNIGHT = Math.floor(Date.now() / 86_400_000) * 86_400_000;
20
+ const _ANCHOR_MS = _BASE_UTC_MIDNIGHT - 10 * 86_400_000; // 10 days ago UTC
21
+ const D1 = _ANCHOR_MS + 10 * 3_600_000; // 10:00Z → local day <anchor>
22
+ const D2 = _ANCHOR_MS + 1 * 86_400_000 + 3 * 3_600_000; // 03:00Z next day → local day <anchor>
23
+ const D3 = _ANCHOR_MS + 1 * 86_400_000 + 6 * 3_600_000; // 06:00Z next day → local day <anchor+1d>
24
+
25
+ /** Compute the local-day date string the same way the SDK's day grouping does. */
26
+ function localDayDateStr(ts: number, tzOffsetMinutes: number): string {
27
+ const d = new Date(ts - tzOffsetMinutes * 60_000);
28
+ return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`;
29
+ }
18
30
 
19
31
  const BASE_ENTRY: Omit<UsageTrackingEntry, "id" | "timestamp" | "modelId" | "client" | "totalTokens"> = {
20
32
  baseUrl: "https://api.openai.com/",
@@ -152,23 +164,24 @@ describe("getUsageSummary", () => {
152
164
  const summary = await getUsageSummary(driver, CLIENTS, TZ);
153
165
  const { days } = summary;
154
166
 
155
- // D1 (10:00Z) → local 2026-05-20, D2 (03:00Z) → local 2026-05-20, D3 (06:00Z) → local 2026-05-21
156
- // So: day 2026-05-20 has e1+e2, day 2026-05-21 has e3+e4
167
+ // D1 (10:00Z) and D2 (next day 03:00Z) both bucket to local day <anchor>;
168
+ // D3 (next day 06:00Z) buckets to local day <anchor+1d>.
169
+ // So: day <anchor> has e1+e2, day <anchor+1d> has e3+e4
157
170
  expect(days.length).toBeGreaterThanOrEqual(2);
158
171
 
159
- // Most-recent-first: 2026-05-21 first
160
- expect(days[0]!.date).toBe("2026-05-21");
172
+ // Most-recent-first: <anchor+1d> first
173
+ expect(days[0]!.date).toBe(localDayDateStr(D3, TZ));
161
174
  expect(days[0]!.requests).toBe(2); // e3, e4
162
175
  expect(days[0]!.satsCost).toBe(8 + 50);
163
176
 
164
- expect(days[1]!.date).toBe("2026-05-20");
177
+ expect(days[1]!.date).toBe(localDayDateStr(D1, TZ));
165
178
  expect(days[1]!.requests).toBe(2); // e1, e2
166
179
  expect(days[1]!.satsCost).toBe(10 + 20);
167
180
  });
168
181
 
169
182
  it("returns empty hoursToday (test entries are not today)", async () => {
170
183
  const summary = await getUsageSummary(driver, CLIENTS, TZ);
171
- // Test entries are in May 2026, not today (June 2026)
184
+ // Test entries are ~10 days ago, not today
172
185
  expect(summary.hoursToday).toHaveLength(0);
173
186
  });
174
187
 
@@ -278,18 +278,25 @@ export function renderToday(stats: UsageStats, width: number): string {
278
278
  const _now = new Date();
279
279
  const todayDateStr = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
280
280
 
281
- let todayStats: { date: string; requests: number; satsCost: number; promptTokens: number; completionTokens: number; totalTokens: number };
282
- let recentDays: Array<{ date: string; requests: number; satsCost: number; totalTokens: number; promptTokens: number; completionTokens: number }>;
283
- let hourlyMap: Map<number, { requests: number; satsCost: number }>;
281
+ let todayStats: { date: string; requests: number; satsCost: number; promptTokens: number; completionTokens: number; totalTokens: number } = {
282
+ date: todayDateStr,
283
+ requests: 0,
284
+ satsCost: 0,
285
+ promptTokens: 0,
286
+ completionTokens: 0,
287
+ totalTokens: 0,
288
+ };
289
+ let recentDays: Array<{ date: string; requests: number; satsCost: number; totalTokens: number; promptTokens: number; completionTokens: number }> = [];
290
+ let hourlyMap: Map<number, { requests: number; satsCost: number }> = new Map();
284
291
 
285
292
  if (stats.summary) {
286
293
  // Use server-aggregated data
287
294
  const { days, hoursToday } = stats.summary;
288
295
  // days[0] is most-recent-first; check if it's today
289
296
  const todayDayStat = days[0]?.date === todayDateStr ? days[0] : undefined;
290
- todayStats = todayDayStat
291
- ? { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens }
292
- : { date: todayDateStr, requests: 0, satsCost: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0 };
297
+ if (todayDayStat) {
298
+ todayStats = { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens };
299
+ }
293
300
  // Exclude today by date (it has its own box) rather than by position —
294
301
  // days[0] is only today when there was activity today.
295
302
  recentDays = days.filter((d) => d.date !== todayDateStr).slice(0, 6);
package/say_hi.sh DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- LANGUAGES=(
5
- "Mandarin Chinese"
6
- "Spanish"
7
- "English"
8
- "Hindi"
9
- "Arabic"
10
- "Portuguese"
11
- "Bengali"
12
- "Russian"
13
- "Japanese"
14
- "German"
15
- "French"
16
- "Italian"
17
- "Korean"
18
- "Turkish"
19
- "Vietnamese"
20
- "Tamil"
21
- "Polish"
22
- "Dutch"
23
- "Swahili"
24
- "Thai"
25
- "Greek"
26
- )
27
-
28
- for lang in "${LANGUAGES[@]}"; do
29
- echo "=== $lang ==="
30
- pi -p -c "in $lang"
31
- echo
32
- done