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
+67 -70
View File
@@ -31,10 +31,10 @@
* breaks the prototype chain.
*/
export class SessionExpiredError extends Error {
readonly name = 'SessionExpiredError'
readonly name = 'SessionExpiredError';
constructor() {
super('Session expired — re-authentication required')
Object.setPrototypeOf(this, SessionExpiredError.prototype)
super('Session expired — re-authentication required');
Object.setPrototypeOf(this, SessionExpiredError.prototype);
}
}
@@ -50,23 +50,23 @@ export class SessionExpiredError extends Error {
*/
function handleAuthResponse(res: Response, label: string): void {
if (res.type === 'opaqueredirect' || res.status === 401) {
throw new SessionExpiredError()
throw new SessionExpiredError();
}
if (!res.ok) {
throw new Error(`${label} failed: ${res.status}`)
throw new Error(`${label} failed: ${res.status}`);
}
}
// ── /api/me ────────────────────────────────────────────────────────────────
export interface MeUser {
id: number
displayName: string | null
color: string
id: number;
displayName: string | null;
color: string;
}
export interface MeResponse {
user: MeUser
user: MeUser;
}
export async function fetchMe(): Promise<MeResponse> {
@@ -80,11 +80,11 @@ export async function fetchMe(): Promise<MeResponse> {
const res = await fetch('/api/me', {
credentials: 'include',
redirect: 'manual',
})
});
handleAuthResponse(res, 'GET /api/me')
handleAuthResponse(res, 'GET /api/me');
return res.json() as Promise<MeResponse>
return res.json() as Promise<MeResponse>;
}
// ── /api/events (windowed — Phase 2) ─────────────────────────────────────
@@ -104,35 +104,35 @@ export async function fetchMe(): Promise<MeResponse> {
* to build the Schedule-X calendarId that keys into buildCalendarConfig().
*/
export interface CalendarOccurrence {
id: string // `ev-<sanitized-uid>-<epochMs>` — stable identity (server: expand.ts makeOccurrenceId)
uid: string
calendarId: number // DB calendar-row id — do NOT use for SX calendarId routing
calendarName: string
ownerUserId: number // DB user id — the correct Schedule-X routing key
id: string; // `ev-<sanitized-uid>-<epochMs>` — stable identity (server: expand.ts makeOccurrenceId)
uid: string;
calendarId: number; // DB calendar-row id — do NOT use for SX calendarId routing
calendarName: string;
ownerUserId: number; // DB user id — the correct Schedule-X routing key
/**
* Display name of the calendar owner (users.displayName from the API).
* Null when the user has not configured a display name.
* Popover renders: isShared ? 'Family' : (ownerName ?? calendarName)
*/
ownerName: string | null
color: string // hex from users.color or shared-family constant
isShared: boolean // true → 'shared' slot; false → String(ownerUserId) slot
title: string
start: string // 'YYYY-MM-DD' for allDay:true; ISO 8601 with IANA tz for timed
end: string
allDay: boolean
location: string | null
description: string | null
ownerName: string | null;
color: string; // hex from users.color or shared-family constant
isShared: boolean; // true → 'shared' slot; false → String(ownerUserId) slot
title: string;
start: string; // 'YYYY-MM-DD' for allDay:true; ISO 8601 with IANA tz for timed
end: string;
allDay: boolean;
location: string | null;
description: string | null;
/**
* True when this occurrence belongs to a recurring series (has an RRULE).
* Mirrors CalendarOccurrence.hasRrule in apps/api/src/broker/expand.ts — must
* stay in sync with the server type (Pitfall 4 — atomic mirror, Plan 06-05).
*/
hasRrule: boolean
hasRrule: boolean;
}
export interface OccurrencesResponse {
occurrences: CalendarOccurrence[]
occurrences: CalendarOccurrence[];
}
/**
@@ -144,18 +144,15 @@ export interface OccurrencesResponse {
* @param start ISO date string 'YYYY-MM-DD' — window start (inclusive)
* @param end ISO date string 'YYYY-MM-DD' — window end (exclusive)
*/
export async function fetchEvents(
start: string,
end: string,
): Promise<OccurrencesResponse> {
export async function fetchEvents(start: string, end: string): Promise<OccurrencesResponse> {
const res = await fetch(`/api/events?start=${start}&end=${end}`, {
credentials: 'include',
redirect: 'manual',
})
});
handleAuthResponse(res, 'GET /api/events')
handleAuthResponse(res, 'GET /api/events');
return res.json() as Promise<OccurrencesResponse>
return res.json() as Promise<OccurrencesResponse>;
}
// Phase 1 legacy types (CalendarEvent, EventsResponse, fetchEventsLegacy) removed in Plan 05
@@ -167,40 +164,40 @@ export async function fetchEvents(
* Recurrence presets supported by the EventForm.
* Maps 1:1 to the RRULE frequency values the API accepts.
*/
export type RecurrencePreset = 'none' | 'daily' | 'weekly' | 'monthly' | 'yearly'
export type RecurrencePreset = 'none' | 'daily' | 'weekly' | 'monthly' | 'yearly';
/**
* Payload for creating or updating a calendar event.
* Mirrors the Zod schema on POST /api/events/create and PATCH /api/events/:uid/edit.
*/
export interface CreateEventPayload {
title: string
allDay: boolean
start: string // 'YYYY-MM-DD' for allDay; ISO 8601 for timed
end: string // same format as start
title: string;
allDay: boolean;
start: string; // 'YYYY-MM-DD' for allDay; ISO 8601 for timed
end: string; // same format as start
// WR-01: optional. CREATE always sends it; EDIT omits it so the API/worker preserve
// the event's existing RRULE (the occurrence contract does not expose recurrence, so
// the form cannot echo it back without silently resetting it to 'none').
recurrence?: RecurrencePreset
recurrence?: RecurrencePreset;
/**
* RRULE UNTIL date (D-06). ISO 'YYYY-MM-DD' string. Only sent when recurrence !== 'none'
* and the user selects the "On date" bound. Mutually exclusive with recurrenceCount.
* The outbox worker converts this to RRULE UNTIL format (DATE for all-day, DATETIME UTC for timed).
*/
recurrenceUntil?: string
recurrenceUntil?: string;
/**
* RRULE COUNT (D-06). Integer >= 1. Only sent when recurrence !== 'none' and the user
* selects the "After N times" bound. Mutually exclusive with recurrenceUntil.
*/
recurrenceCount?: number
location?: string
description?: string
calendarUrl?: string // omit to use the member's default writable calendar (D-01)
recurrenceCount?: number;
location?: string;
description?: string;
calendarUrl?: string; // omit to use the member's default writable calendar (D-01)
}
/** Response from POST /api/events/create and PATCH /api/events/:uid/edit */
export interface CreateEventResponse {
uid: string
uid: string;
}
/**
@@ -209,10 +206,10 @@ export interface CreateEventResponse {
* The client never derives writability — it reads this endpoint verbatim.
*/
export interface WritableCalendar {
url: string
displayName: string
color: string
isShared: boolean
url: string;
displayName: string;
color: string;
isShared: boolean;
}
/**
@@ -228,11 +225,11 @@ export async function createEvent(payload: CreateEventPayload): Promise<CreateEv
credentials: 'include',
redirect: 'manual',
body: JSON.stringify(payload),
})
});
handleAuthResponse(res, 'POST /api/events/create')
handleAuthResponse(res, 'POST /api/events/create');
return res.json() as Promise<CreateEventResponse>
return res.json() as Promise<CreateEventResponse>;
}
/**
@@ -251,11 +248,11 @@ export async function updateEvent(
credentials: 'include',
redirect: 'manual',
body: JSON.stringify(payload),
})
});
handleAuthResponse(res, `PATCH /api/events/${uid}/edit`)
handleAuthResponse(res, `PATCH /api/events/${uid}/edit`);
return res.json() as Promise<CreateEventResponse>
return res.json() as Promise<CreateEventResponse>;
}
/**
@@ -269,9 +266,9 @@ export async function deleteEvent(uid: string): Promise<void> {
method: 'DELETE',
credentials: 'include',
redirect: 'manual',
})
});
handleAuthResponse(res, `DELETE /api/events/${uid}`)
handleAuthResponse(res, `DELETE /api/events/${uid}`);
}
// ── /api/events/sync-status (Plan 03-06) ─────────────────────────────────────
@@ -280,17 +277,17 @@ export async function deleteEvent(uid: string): Promise<void> {
* Status values for an outbox write operation.
* Mirrors the calendarOutbox.status enum on the server.
*/
export type SyncStatusValue = 'pending' | 'done' | 'failed' | 'dead'
export type SyncStatusValue = 'pending' | 'done' | 'failed' | 'dead';
/**
* Response from GET /api/events/sync-status?uid=
* The server returns the current outbox status for the given UID + member.
*/
export interface SyncStatus {
uid: string
status: SyncStatusValue
uid: string;
status: SyncStatusValue;
/** Present on failed status — may contain '412' prefix for conflict detection. */
error?: string
error?: string;
}
/**
@@ -303,11 +300,11 @@ export async function fetchSyncStatus(uid: string): Promise<SyncStatus> {
const res = await fetch(`/api/events/sync-status?uid=${uid}`, {
credentials: 'include',
redirect: 'manual',
})
});
handleAuthResponse(res, 'GET /api/events/sync-status')
handleAuthResponse(res, 'GET /api/events/sync-status');
return res.json() as Promise<SyncStatus>
return res.json() as Promise<SyncStatus>;
}
/**
@@ -321,10 +318,10 @@ export async function fetchWritableCalendars(): Promise<WritableCalendar[]> {
const res = await fetch('/api/events/writable-calendars', {
credentials: 'include',
redirect: 'manual',
})
});
handleAuthResponse(res, 'GET /api/events/writable-calendars')
handleAuthResponse(res, 'GET /api/events/writable-calendars');
const body = (await res.json()) as { calendars: WritableCalendar[] }
return body.calendars
const body = (await res.json()) as { calendars: WritableCalendar[] };
return body.calendars;
}