meetings.ts
Language TypeScript2.2 KB67 lines
/*** Meetings, and the action items inside them.** The unit of work is the action item, but the unit of access is the meeting:* who was invited decides who may see anything about it, so the two travel* together and this resource never returns items detached from their meeting.*/import { FATHOM_PAGE_SIZE } from '../constants.js'import type { FathomClient } from '../http.js'import type { FathomMeeting, MeetingWindow } from '../types.js'interface ListResponse {items?: FathomMeeting[]/*** The end sentinel is an empty string, not null and not absent (verified* live). A loop written as `while (cursor !== undefined)` never terminates.* Same family as the Plinth unassigned sentinel: trust the wire over the* docs.*/next_cursor?: string | nulllimit?: number}export class MeetingsResource {constructor(private readonly client: FathomClient) {}/*** Meetings created since `sinceIso`, newest first, with their action items.** `include_action_items` is deliberately the only include set. It is not in* Fathom's "heavy request" list, so this stays on the 60-calls/60s global* bucket; adding include_summary or include_transcript would move every call* into the bucket that can be squeezed to five a minute.** A page cap that is hit returns `truncated: true` with everything fetched so* far. Never throw away fetched data to guard against a hypothetical.*/async listSince(sinceIso: string, maxPages = 20): Promise<MeetingWindow> {const meetings: FathomMeeting[] = []let cursor: string | undefinedlet pages = 0let truncated = truefor (let page = 0; page < maxPages; page++) {const body = await this.client.get<ListResponse>('/meetings', {created_after: sinceIso,include_action_items: true,limit: FATHOM_PAGE_SIZE,cursor,})pages = page + 1meetings.push(...(body.items ?? []))// Empty string, null and undefined all mean "no more pages". Only a// non-empty cursor continues the sweep.const next = body.next_cursorif (!next) {truncated = falsebreak}cursor = next}return { meetings, truncated, pages }}}