Files
template-app/modules/documents/contract/procedures.ts
T

81 lines
3.0 KiB
TypeScript

// 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<typeof documentViewSchema>
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()