ccdeck 1.43.0 → 1.44.1

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.
@@ -0,0 +1,78 @@
1
+ // When a quota window resets, written one way — for the Claude lanes and the
2
+ // Codex lanes both, which land in the same panel.
3
+ //
4
+ // WHY THIS MODULE EXISTS (#374). quota.mjs had `fmtResetIso` and codex-quota.mjs
5
+ // had `fmtReset`. They passed identical option bags to `toLocaleString` and then
6
+ // post-processed the result differently, and codex-quota's own doc comment said
7
+ // of its copy: "matches the Claude quota formatting so both read alike." It did
8
+ // not. Over the same instant:
9
+ //
10
+ // toLocaleString : "Jun 18, 4:09 PM"
11
+ // quota.mjs : "Jun 18, 4:09pm"
12
+ // codex-quota.mjs: "jun 18 4:09pm" ← comma stripped, month lower-cased
13
+ //
14
+ // Swept over 2,794 instants across 40 days, the two disagreed on every single
15
+ // one — not at a boundary, on all of them, because the difference is two
16
+ // unconditional string operations rather than a tier that rarely fires. Both
17
+ // strings surface in the same usage panel, one lane above the other.
18
+ //
19
+ // The Claude rendering is the one kept, on the comment's own terms: it is the
20
+ // one the other claimed to match, and it is the one that reads like a date —
21
+ // `Intl` capitalises the month and puts the comma in for the locale's own
22
+ // reasons, and stripping both is a hand edit to output that was already right.
23
+ // This is a FIX to what the Codex lanes print, not a neutral merge, and it is
24
+ // the only visible change in this consolidation.
25
+ //
26
+ // The one genuine difference between the copies was the input unit — Codex
27
+ // answers with a Unix timestamp in seconds and Anthropic with an ISO-8601
28
+ // string — so that is the wrapper below rather than a second formatter.
29
+ //
30
+ // A module of its own rather than one importing the other: quota.mjs reads
31
+ // Claude's OAuth credentials off disk, and having the Codex path import that to
32
+ // reach a date formatter would drag the whole Claude credential chain into a
33
+ // request that has nothing to do with it.
34
+
35
+ /** en-US on purpose, not the host locale. This string is generated on the
36
+ * server and shipped to a browser whose locale nobody here has asked, so a
37
+ * server set to de-DE would otherwise send "18. Juni, 16:09" into a panel
38
+ * written in English. Both copies already hardcoded en-US; it is written down
39
+ * here so the next reader knows it was a decision. */
40
+ const OPTS = { month: "short", day: "numeric", hour: "numeric", minute: "2-digit", hour12: true };
41
+
42
+ /** The rendering itself, over a Date both entry points have already validated.
43
+ * The meridiem is lower-cased and its space removed — the only edit made to
44
+ * what `Intl` produces — because "4:09 PM" shouts in a lane label that is a
45
+ * few characters of chrome wide. */
46
+ function label(d) {
47
+ return d.toLocaleString("en-US", OPTS).replace(/\s+(AM|PM)/, (_, p) => p.toLowerCase());
48
+ }
49
+
50
+ /** "Jun 18, 4:09pm" from a Unix timestamp in seconds, which is how the Codex
51
+ * usage endpoint spells a reset time. Null when there is no reset to name.
52
+ *
53
+ * The validity check is inherited from the ISO copy, which had one where the
54
+ * seconds copy did not: a finite but absurd number — the only shape that gets
55
+ * past the falsy guard and still fails to be a date — used to render as the
56
+ * literal string "invalid date" in a quota lane. Nothing observed sends one,
57
+ * so this is hardening rather than a fix, and it is the safer of the two
58
+ * behaviours in the same way `isOlder`'s type guard is. */
59
+ export function resetLabel(unixSec) {
60
+ if (!unixSec) return null;
61
+ const d = new Date(unixSec * 1000);
62
+ if (isNaN(d.getTime())) return null;
63
+ return label(d);
64
+ }
65
+
66
+ /** The same label from an ISO-8601 instant, which is how Anthropic's usage
67
+ * endpoint spells a reset time. Invalid and absent both answer null, so a
68
+ * malformed field renders as no reset rather than "Invalid Date".
69
+ *
70
+ * Not written as `resetLabel(d.getTime() / 1000)`: that would send an instant
71
+ * at the Unix epoch through the falsy guard above and answer null for a date
72
+ * this function has already established is valid. */
73
+ export function resetLabelIso(iso) {
74
+ if (!iso) return null;
75
+ const d = new Date(iso);
76
+ if (isNaN(d.getTime())) return null;
77
+ return label(d);
78
+ }