feat(01-04): wire broker + routes into bootstrap, add SSE endpoint, EventProof
- Mount /api/events, /api/sse in index.ts behind oidcAuthMiddleware; /callback + /health before guard - Call startBrokerPoller() on boot (5-min ctag-poll background schedule) - Add sseRouter with GET /heartbeat (streamSSE, 10s interval) for Pangolin SSE smoke test (D-08, T-04-01) - Add CAL-08 spike script (broker/spike.ts): createFastmailClient → fetchCalendars → print calendar URLs - Add fetchEvents() to pwa/api/client.ts with typed CalendarEvent/EventsResponse shapes - Add EventProof.tsx: React Query ['events'], renders first event title+date or empty-state (CAL-01 broker proof) - Update App.tsx to render MemberBadge + EventProof on landing page - Add ical.js@2.2.1 to PWA dependencies for VEVENT summary parsing in EventProof - All 24 API unit tests green; tsc --noEmit clean in both apps/api and apps/pwa
This commit is contained in:
@@ -32,3 +32,41 @@ export async function fetchMe(): Promise<MeResponse> {
|
||||
|
||||
return res.json() as Promise<MeResponse>
|
||||
}
|
||||
|
||||
/**
|
||||
* A single cached calendar event from the broker's MariaDB cache.
|
||||
* Mirrors the calendarEvents table schema from apps/api/src/db/schema.ts.
|
||||
*/
|
||||
export interface CalendarEvent {
|
||||
id: number
|
||||
calendarId: number
|
||||
uid: string
|
||||
etag: string | null
|
||||
rawVevent: string
|
||||
dtstartUtc: string | null
|
||||
dtstartDate: string | null
|
||||
allDay: boolean
|
||||
updatedAt: string | null
|
||||
}
|
||||
|
||||
export interface EventsResponse {
|
||||
events: CalendarEvent[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all cached calendar events from the broker's MariaDB cache.
|
||||
* No live Fastmail call — the 5-min poller keeps the cache fresh.
|
||||
*
|
||||
* Used by EventProof to display the first cached event as broker proof (CAL-01).
|
||||
*/
|
||||
export async function fetchEvents(): Promise<EventsResponse> {
|
||||
const res = await fetch('/api/events', {
|
||||
credentials: 'include',
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`GET /api/events failed: ${res.status}`)
|
||||
}
|
||||
|
||||
return res.json() as Promise<EventsResponse>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user