import { ok, err, buildPaginatedResult, DEFAULT_PAGE_SIZE, type ReadonlyDB, UnauthenticatedError, type CallerContext, type PaginationInput, } from "@tailor-platform/erp-kit/core"; import type { DB } from "../generated/kysely-tailordb"; import { ForbiddenError } from "../lib/errors.generated"; type PreferenceOrderByField = "createdAt" | "categoryId" | "channelId"; export interface ListNotificationPreferencesInput extends PaginationInput { userId?: string; } /** * Returns the caller's persisted NotificationPreference rows as a paginated result. Self-service only. */ export async function run( db: ReadonlyDB, input: ListNotificationPreferencesInput, ctx: CallerContext, ) { // Every result here is scoped to the caller, so there is nothing to return when // there is no caller. Queries carry no permission gate of their own. const { actorId } = ctx; if (actorId === null) return err(new UnauthenticatedError()); // Default to caller when userId is omitted; otherwise enforce self-only access. const userId = input.userId ?? actorId; if (userId !== actorId) { return err(new ForbiddenError(userId)); } const limit = input.limit ?? DEFAULT_PAGE_SIZE; const offset = input.offset ?? 0; const orderBy = input.orderBy ?? "createdAt"; const orderDirection = input.orderDirection ?? "desc"; const rows = await db .selectFrom("NotificationPreference") .selectAll() .where("userId", "=", userId) .orderBy(orderBy, orderDirection) .limit(limit + 1) .offset(offset) .execute(); return ok(buildPaginatedResult(rows, limit)); }