// The procedure contracts of the documents module. This file is what another module, a browser and // the OpenAPI document may import: schemas and names, no handler and no port. // // Approving and rejecting a line are not here. They are the proposals module's own procedures // (`proposals.proposal.approve`, `.reject`, `.approveMany`), which this module's writer is called // from, so a review decision has one implementation, one permission and one audit event whichever // screen it was made on (decision AT-D22). import { procedure } from "@conusai-kit/core" import { z } from "zod" import { DOCUMENT_STATUSES, FAILURE_CODES, PAGE_CLASSES } from "./constants.js" import { EXPORT_CREATED, LINE_EDITED, lineViewSchema } from "./lines.js" const inProject = { org: z.string(), workspace: z.string(), project: z.string() } /** A file with no document row yet has been uploaded and not picked up by the job: `queued`. */ export const documentViewSchema = z.object({ fileId: z.string(), filename: z.string(), status: z.enum(["queued", ...DOCUMENT_STATUSES]), failureCode: z.enum(FAILURE_CODES).nullable(), pageCount: z.number().int().nullable(), /** The pages the extraction left out, with the class that excluded each: a reviewer sees what was not read. */ skippedPages: z.array(z.object({ page: z.number().int().min(1), pageClass: z.enum(PAGE_CLASSES) })), /** Lines waiting for a decision, and lines approved: the two numbers a reviewer scans a list for. */ pending: z.number().int(), approved: z.number().int(), uploadedAt: z.string(), }) export type DocumentView = z.output export const documentList = procedure("documents.document.list") .kind("read") .scope("project") .permission("documents.document.read") .input(z.object({ ...inProject })) .output(z.object({ documents: z.array(documentViewSchema) })) .contract() export const documentGet = procedure("documents.document.get") .kind("read") .scope("project") .permission("documents.document.read") .input(z.object({ ...inProject, fileId: z.string() })) .output(z.object({ document: documentViewSchema, lines: z.array(lineViewSchema) })) .contract() export const lineEdit = procedure("documents.line.edit") .kind("write") .scope("project") .permission("documents.line.edit") .input( z.object({ ...inProject, lineId: z.string(), label: z.string().min(1).max(200), value: z.string().min(1).max(2_000), }), ) .output(lineViewSchema) .audit(LINE_EDITED) .contract() export const exportCreate = procedure("documents.export.create") .kind("effect") .scope("project") .permission("documents.export.create") .input(z.object({ ...inProject, fileId: z.string() })) .output( z.object({ filename: z.string(), contentType: z.string(), /** The workbook, standard base64: a procedure's answer has to survive JSON on every transport. */ body: z.string(), lineCount: z.number().int(), }), ) .audit(EXPORT_CREATED) .contract()