style(13-03): apply Prettier formatting across repo

Mechanical reformat — no logic changes. 398 files changed, 19125
insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc
(singleQuote:true, semi:true, tabWidth:2, trailingComma:all,
printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
Lucas Berger
2026-06-11 20:35:18 -04:00
parent 4bc0445173
commit 982438dc10
398 changed files with 19050 additions and 16382 deletions
@@ -47,7 +47,7 @@ outbox worker write-path, the events route, the PWA event form / auth-splash /
push-prompt components, the calendar store, and supporting tests + CSS.
The code is heavily commented and carries a clear audit trail of prior fixes. The
adversarial pass focused on the gaps *between* those documented fixes. The one
adversarial pass focused on the gaps _between_ those documented fixes. The one
Critical finding is a security-relevant injection vector in the RRULE `UNTIL`
assembly (the route validates the date-window query params and write-body lengths,
but `recurrenceUntil` is NOT validated as a date before being spliced into an RRULE
@@ -67,9 +67,9 @@ The route validates `recurrenceUntil` only as `z.string().max(10).optional()`
≤10-char string passes. The outbox worker then does:
```js
const dateDigits = until.replace(/-/g, '')
s += `;UNTIL=${dateDigits}` // all-day
s += `;UNTIL=${dateDigits}T235959Z` // timed
const dateDigits = until.replace(/-/g, '');
s += `;UNTIL=${dateDigits}`; // all-day
s += `;UNTIL=${dateDigits}T235959Z`; // timed
```
`until.replace(/-/g,'')` strips hyphens but leaves every other character. A payload
@@ -103,7 +103,7 @@ output is guaranteed digits-only and the injection vector closes.
**File:** `apps/api/src/routes/events.ts:199-203`
**Issue:**
The third `or()` branch selects *any* row with `dtstartDate` in `[start, end)`
The third `or()` branch selects _any_ row with `dtstartDate` in `[start, end)`
**without** gating on `hasRrule = 0`:
```js
@@ -111,7 +111,7 @@ and(
sql`${calendarEvents.dtstartDate} IS NOT NULL`,
sql`${calendarEvents.dtstartDate} >= ${start}`,
sql`${calendarEvents.dtstartDate} < ${end}`,
)
);
```
The timed branch above it explicitly gates `hasRrule = 0`, but this all-day branch
@@ -124,13 +124,14 @@ real on the wire and any consumer that counts occurrences (or a future view that
not dedup) sees doubles. Add the missing `hasRrule = 0` gate to the all-day branch.
**Fix:**
```js
and(
sql`${calendarEvents.hasRrule} = 0`,
sql`${calendarEvents.dtstartDate} IS NOT NULL`,
sql`${calendarEvents.dtstartDate} >= ${start}`,
sql`${calendarEvents.dtstartDate} < ${end}`,
)
);
```
### WR-02: EventForm silently creates an unbounded series when "On date" is selected but no date entered
@@ -154,9 +155,10 @@ On date"). Treat a blank `recurrenceUntil` while `bound === 'until'` as a valida
error.
**Fix:** Add to the `recurrence !== 'none'` block:
```js
if (recurrenceBound === 'until' && !recurrenceUntil) {
newErrors.recurrenceBound = 'Choose an end date'
newErrors.recurrenceBound = 'Choose an end date';
}
```
@@ -173,6 +175,7 @@ yielding an unbounded series. The 0 case is caught by validation, but the NaN ca
bypasses both the validation gate and the payload gate.
**Fix:** Sanitize on change and validate explicitly:
```js
onChange={(e) => {
const n = parseInt(e.target.value, 10)
@@ -192,8 +195,8 @@ if (recurrenceBound === 'count' && (!Number.isInteger(recurrenceCount) || recurr
`.toISOString().slice(0, 10)`. `eventDateTime.ts:64-65` and `EventForm.tsx:108-110`
explicitly document this as forbidden ("NEVER use toISOString().slice(0,10) — that
returns the UTC date, not the local date"). For a user west of UTC (the project's
primary zones are Toronto/Detroit/New_York/Edmonton — all negative offsets) after
~20:00 local, `todayIso()` returns *tomorrow's* date. This is the default
primary zones are Toronto/Detroit/New*York/Edmonton — all negative offsets) after
~20:00 local, `todayIso()` returns \_tomorrow's* date. This is the default
`selectedDate` and seeds the initial fetch window — so a late-evening cold load can
center the calendar on the wrong day and the EventForm create default (`todayIso()`
at EventForm.tsx:153/158) pre-fills tomorrow. The fix already exists as the private
@@ -201,6 +204,7 @@ at EventForm.tsx:153/158) pre-fills tomorrow. The fix already exists as the priv
**Fix:** Export `localDateISO` from `eventDateTime.ts` and use it in
`initialCalendarRange()`/`todayIso()`:
```js
function localDateISO(d: Date): string {
return `${d.getFullYear()}-${pad2(d.getMonth()+1)}-${pad2(d.getDate())}`
@@ -221,6 +225,7 @@ interstitial never arms, leaving the user on a hung query. The class uses a fixe
should defensively also check `name`.
**Fix:**
```js
function onGlobalError(error: unknown): void {
if (error instanceof SessionExpiredError ||
@@ -256,7 +261,7 @@ and let the next poll reconcile.
**Issue:**
`if (recurrenceUntil < startDate)` compares two strings lexicographically.
`recurrenceUntil` comes from a `type="date"` input (`YYYY-MM-DD`) and `startDate` is
also `YYYY-MM-DD`, so this works *today*. But it is silently coupled to both values
also `YYYY-MM-DD`, so this works _today_. But it is silently coupled to both values
always being zero-padded ISO dates. If `startDate` is ever blank (the IN-02 edit
parse-failure path sets it to `''`), `recurrenceUntil < ''` is always `false`, so the
bound-before-start guard is skipped exactly when the start is unknown. Low impact
@@ -272,7 +277,7 @@ the implicit format coupling is fragile. Compare parsed dates or assert non-empt
**Issue:**
`new Date(clean)` for a string like `'2026-13-45'` returns an `Invalid Date`, caught
and returned as `ok:false` — correct. But `new Date('2026-06')` (a partial date) is
parsed as a *valid* UTC instant in V8, so a truncated/garbled cached value would parse
parsed as a _valid_ UTC instant in V8, so a truncated/garbled cached value would parse
"successfully" to an unintended day/time and be saved on edit without tripping the
IN-02 blank-field guard. The function trusts `new Date()`'s permissive parsing.
Tighten the accepted timed-format (e.g. require a `T` and `:` before calling
@@ -287,7 +292,7 @@ Tighten the accepted timed-format (e.g. require a `T` and `:` before calling
### IN-01: Dead/misleading interface doc comment in `client.ts` CalendarOccurrence
**File:** `apps/pwa/src/api/client.ts:107`
**Issue:** The `id` field comment says ``` `${uid}::${dtstart_iso}` — stable identity ```
**Issue:** The `id` field comment says `` `${uid}::${dtstart_iso}` — stable identity ``
but the server (`expand.ts:101-104` `makeOccurrenceId`) now emits
`ev-<sanitized-uid>-<epochMs>`. The `::`-format comment is stale and contradicts the
actual wire contract (and the server-side comment that explains why `::` was