* The range every endpoint shares. Absent params default to the last 30 days * ending today so a bare `curl /api/summary` still answers something sensible; * the dashboard itself always sends both, anchored on /api/meta's latest day so * no chart ends on a day the nightly rollup has not written y
(url: URL)
| 93 | * no chart ends on a day the nightly rollup has not written yet. |
| 94 | */ |
| 95 | function parseRange(url: URL): Range | ApiResult { |
| 96 | const rawTo = url.searchParams.get('to'); |
| 97 | const rawFrom = url.searchParams.get('from'); |
| 98 | |
| 99 | if (rawTo !== null && !isValidDay(rawTo)) return fail('to must be YYYY-MM-DD'); |
| 100 | if (rawFrom !== null && !isValidDay(rawFrom)) return fail('from must be YYYY-MM-DD'); |
| 101 | |
| 102 | const to = rawTo ?? utcDay(Date.now()); |
| 103 | const from = rawFrom ?? addDays(to, -(DEFAULT_RANGE_DAYS - 1)); |
| 104 | if (from > to) return fail('from must not be after to'); |
| 105 | |
| 106 | const requested = daysApart(from, to) + 1; |
| 107 | const clamped = requested > MAX_RANGE_DAYS; |
| 108 | return { |
| 109 | from: clamped ? addDays(to, -(MAX_RANGE_DAYS - 1)) : from, |
| 110 | to, |
| 111 | days: clamped ? MAX_RANGE_DAYS : requested, |
| 112 | clamped, |
| 113 | }; |
| 114 | } |
| 115 | |
| 116 | const isApiResult = (v: Range | ApiResult): v is ApiResult => 'body' in v; |
| 117 |