import { addressbookHref } from "@/worker/carddav/paths"; import type { CardDavDoDb } from "@/worker/db/card-dav-do/client"; import type { AddressbookRow } from "@/worker/db/card-dav-do/schema"; import { addressSyncToken, addressbookById, addressbookByName, createAddressbook as createAddressbookRow, deleteAddressbook as deleteAddressbookRow, ensureDefaultAddressbook, listAddressbooks as listAddressbookRows, updateAddressbook as updateAddressbookRow, validAddressbookName, } from "@/worker/db/card-dav-do/repository"; import { cardDavError as err, type CardDavError, type AddressbookCreateInput, type AddressbookDeleteInput, type AddressbookGetInput, type AddressbookListInput, type AddressbookRecord, type AddressbookUpdateInput, } from "@/worker/objects/card-dav/types"; import { createCollectionRecord, deleteCollectionRecord, getCollectionRecord, listCollectionRecords, updateCollectionRecord, type CollectionCrudSpec, } from "@/worker/objects/common/collection-crud"; function recordAddressbook(row: AddressbookRow): AddressbookRecord { return { id: row.id, name: row.name, displayName: row.displayName, description: row.description, href: addressbookHref(row.name), createdAtMs: row.createdAtMs, modifiedAtMs: row.modifiedAtMs, syncToken: addressSyncToken(row.syncSeq), }; } export function listAddressbooks(db: CardDavDoDb, input: AddressbookListInput) { const result = listCollectionRecords(db, input, addressbookCrudSpec); return { ok: true as const, addressbooks: result.records }; } export function getAddressbook(db: CardDavDoDb, input: AddressbookGetInput) { const result = getCollectionRecord(db, input, addressbookCrudSpec); return result.ok ? { ok: true as const, addressbook: result.record } : result; } export function createAddressbook(db: CardDavDoDb, input: AddressbookCreateInput) { const result = createCollectionRecord(db, input, addressbookCrudSpec); return result.ok ? { ok: true as const, addressbook: result.record } : result; } export function updateAddressbook(db: CardDavDoDb, input: AddressbookUpdateInput) { const result = updateCollectionRecord(db, input, addressbookCrudSpec); return result.ok ? { ok: true as const, addressbook: result.record } : result; } export function deleteAddressbook(db: CardDavDoDb, input: AddressbookDeleteInput) { return deleteCollectionRecord(db, input, addressbookCrudSpec); } const addressbookCrudSpec = { ensureDefaultCollection: ensureDefaultAddressbook, listCollections: listAddressbookRows, collectionById: addressbookById, collectionByName: addressbookByName, validName: validAddressbookName, deleteCollection: deleteAddressbookRow, record: recordAddressbook, createCollection: (db, input: AddressbookCreateInput, displayName) => createAddressbookRow(db, { subjectId: input.subjectId, name: input.name, displayName, description: input.description ?? null, nowMs: input.nowMs, }), updateCollection: (db, input: AddressbookUpdateInput, displayName) => updateAddressbookRow(db, { id: input.id, displayName, description: input.description, nowMs: input.nowMs, }), invalidName: () => err(400, "bad_request", "Address book name must be a non-empty DAV path segment."), nameConflict: () => err(409, "conflict", "Address book name already exists"), collectionNotFound: () => err(404, "not_found", "Address book not found"), emptyDisplayName: () => err(400, "bad_request", "Address book display name cannot be empty."), defaultDeleteForbidden: () => err(403, "forbidden", "Default address book cannot be deleted."), } satisfies CollectionCrudSpec & { createCollection(db: CardDavDoDb, input: AddressbookCreateInput, displayName: string): AddressbookRow; updateCollection( db: CardDavDoDb, input: AddressbookUpdateInput, displayName: string | undefined, ): AddressbookRow | undefined; };