All files / web/src/lib/abacus/print job-ownership.ts

100% Statements 40/40
100% Branches 4/4
100% Functions 3/3
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 411x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x  
/**
 * Job ownership map (Abacus Studio Phase 2a, #8.3).
 *
 * The print service stays the single source of truth for job state; these
 * rows only record which connection/user submitted a job so `jobs/*` proxy
 * reads can be authorized and doorbell rings resolved to the owning tenant.
 */
import { and, eq } from 'drizzle-orm'
import { db, schema } from '@/db'
import type { PrintJob } from '@/db/schema'
 
export async function recordJobOwnership(input: {
  jobId: string
  connectionId: string
  userId: string
  printerId: string
}): Promise<void> {
  await db.insert(schema.printJobs).values(input).onConflictDoNothing()
}
 
export async function getOwnedJob(userId: string, jobId: string): Promise<PrintJob | undefined> {
  return db.query.printJobs.findFirst({
    where: and(eq(schema.printJobs.jobId, jobId), eq(schema.printJobs.userId, userId)),
  })
}
 
/**
 * Every print-service job id THIS user submitted through abaci, as a Set for
 * O(1) roster intersection (#16). The print-service token is shared across
 * every app paired to it, so the raw `/jobs` list is over-broad; this is the
 * scope that narrows it. An empty set ⇒ the user owns nothing ⇒ an empty
 * roster (never the unfiltered list).
 */
export async function listOwnedJobIds(userId: string): Promise<Set<string>> {
  const rows = await db.query.printJobs.findMany({
    columns: { jobId: true },
    where: eq(schema.printJobs.userId, userId),
  })
  return new Set(rows.map((row) => row.jobId))
}