import { calendarHref } from "@/worker/caldav/paths"; import type { CalDavDoDb } from "@/worker/db/cal-dav-do/client"; import type { CalendarRow } from "@/worker/db/cal-dav-do/schema"; import { calendarById, calendarByName, calendarSyncToken, createCalendar as createCalendarRow, deleteCalendar as deleteCalendarRow, ensureDefaultCalendar, listCalendars as listCalendarRows, updateCalendar as updateCalendarRow, validCalendarName, } from "@/worker/db/cal-dav-do/repository"; import { calDavError as err, type CalDavError, type CalendarCreateInput, type CalendarDeleteByNameInput, type CalendarDeleteInput, type CalendarGetInput, type CalendarListInput, type CalendarRecord, type CalendarUpdateInput, } from "@/worker/objects/cal-dav/types"; import { createCollectionRecord, deleteCollectionRecord, deleteCollectionRecordByName, getCollectionRecord, listCollectionRecords, updateCollectionRecord, type CollectionCrudSpec, } from "@/worker/objects/common/collection-crud"; function recordCalendar(row: CalendarRow): CalendarRecord { return { id: row.id, name: row.name, displayName: row.displayName, description: row.description, href: calendarHref(row.name), color: row.color, orderIndex: row.orderIndex, timezoneIcal: row.timezoneIcal, createdAtMs: row.createdAtMs, modifiedAtMs: row.modifiedAtMs, syncToken: calendarSyncToken(row.syncSeq), }; } export function listCalendars(db: CalDavDoDb, input: CalendarListInput) { const result = listCollectionRecords(db, input, calendarCrudSpec); return { ok: true as const, calendars: result.records }; } export function getCalendar(db: CalDavDoDb, input: CalendarGetInput) { const result = getCollectionRecord(db, input, calendarCrudSpec); return result.ok ? { ok: true as const, calendar: result.record } : result; } export function createCalendar(db: CalDavDoDb, input: CalendarCreateInput) { const result = createCollectionRecord(db, input, calendarCrudSpec); return result.ok ? { ok: true as const, calendar: result.record } : result; } export function updateCalendar(db: CalDavDoDb, input: CalendarUpdateInput) { const result = updateCollectionRecord(db, input, calendarCrudSpec); return result.ok ? { ok: true as const, calendar: result.record } : result; } export function deleteCalendar(db: CalDavDoDb, input: CalendarDeleteInput) { return deleteCollectionRecord(db, input, calendarCrudSpec); } export function deleteCalendarByName(db: CalDavDoDb, input: CalendarDeleteByNameInput) { return deleteCollectionRecordByName(db, input, calendarCrudSpec); } const calendarCrudSpec = { ensureDefaultCollection: ensureDefaultCalendar, listCollections: listCalendarRows, collectionById: calendarById, collectionByName: calendarByName, validName: validCalendarName, deleteCollection: deleteCalendarRow, record: recordCalendar, createCollection: (db, input: CalendarCreateInput, displayName) => createCalendarRow(db, { subjectId: input.subjectId, name: input.name, displayName, description: input.description ?? null, color: input.color ?? null, orderIndex: input.orderIndex ?? 0, timezoneIcal: input.timezoneIcal ?? null, nowMs: input.nowMs, }), updateCollection: (db, input: CalendarUpdateInput, displayName) => updateCalendarRow(db, { id: input.id, displayName, description: input.description, color: input.color, orderIndex: input.orderIndex, timezoneIcal: input.timezoneIcal, nowMs: input.nowMs, }), invalidName: () => err(400, "bad_request", "Calendar name must be a DAV path segment."), nameConflict: () => err(409, "conflict", "Calendar name already exists"), collectionNotFound: () => err(404, "not_found", "Calendar not found"), emptyDisplayName: () => err(400, "bad_request", "Calendar display name cannot be empty."), defaultDeleteForbidden: () => err(403, "forbidden", "Default calendar cannot be deleted."), } satisfies CollectionCrudSpec & { createCollection(db: CalDavDoDb, input: CalendarCreateInput, displayName: string): CalendarRow; updateCollection( db: CalDavDoDb, input: CalendarUpdateInput, displayName: string | undefined, ): CalendarRow | undefined; };