import { ok, err, type ReadonlyDB, UnauthenticatedError, type CallerContext, type PaginationInput, buildPaginatedResult, DEFAULT_PAGE_SIZE, } from "@tailor-platform/erp-kit/core"; import type { DB } from "../generated/kysely-tailordb"; import { ForbiddenError } from "../lib/errors.generated"; type SubscriptionOrderByField = "subscribedAt" | "createdAt"; export interface ListNotificationSubscriptionsInput extends PaginationInput { // Optional source narrowing, applied on top of the caller's own rows. sourceType?: string; sourceId?: string; // Optional explicit user filter; must match the caller. userId?: string; } /** * Returns the caller's own NotificationSubscriptions, optionally narrowed by source, as a paginated result. */ export async function run( db: ReadonlyDB, input: ListNotificationSubscriptionsInput, 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()); const limit = input.limit ?? DEFAULT_PAGE_SIZE; const offset = input.offset ?? 0; const orderBy = input.orderBy ?? "subscribedAt"; const orderDirection = input.orderDirection ?? "desc"; // Self-scope: an explicit userId filter must match the caller; results are // always restricted to the caller's own subscriptions. if (input.userId !== undefined && input.userId !== actorId) { return err(new ForbiddenError(input.userId)); } let query = db.selectFrom("NotificationSubscription").selectAll().where("userId", "=", actorId); if (input.sourceType !== undefined) { query = query.where("sourceType", "=", input.sourceType); } if (input.sourceId !== undefined) { query = query.where("sourceId", "=", input.sourceId); } const rows = await query .orderBy(orderBy, orderDirection) .limit(limit + 1) .offset(offset) .execute(); return ok(buildPaginatedResult(rows, limit)); }