@@ -0,0 +1,163 @@
|
||||
// The procedure contracts of the archive module: schemas and names, no handler and no port.
|
||||
//
|
||||
// The module is a client of the platform's Archive service (B-wave contract §3.14): documents, their
|
||||
// versions and their retention live there, in the deployment's organization, and the bytes in the
|
||||
// platform's Blob store. A read reads; a change is an `effect` (it calls an external service and writes
|
||||
// nothing of this app's own). A version is made from a file the project holds, so a procedure names a
|
||||
// `fileId`, never a hash or a Blob reference of the caller's. The service's int64 fields are their digits
|
||||
// here, so what a page loads is JSON.
|
||||
|
||||
import { procedure } from "@conusai-kit/core"
|
||||
import { z } from "zod"
|
||||
import { ARCHIVE_PERMISSIONS, RETENTION_BASES } from "./constants.js"
|
||||
|
||||
const inProject = { org: z.string(), workspace: z.string(), project: z.string() }
|
||||
const page = { after: z.string().max(128).optional(), limit: z.number().int().min(1).max(200).optional() }
|
||||
/** What a form generates once per submission, so a retried request applies once. */
|
||||
const requestId = z.string().uuid()
|
||||
const documentId = z.string().min(1).max(64)
|
||||
const fileId = z.string().uuid()
|
||||
/** A revision as its digits: the service's are 64-bit. */
|
||||
const revision = z.string().regex(/^\d{1,19}$/)
|
||||
|
||||
export const documentViewSchema = z.object({
|
||||
documentId: z.string(),
|
||||
title: z.string(),
|
||||
/** An optional UNTDID 1001 document code. */
|
||||
kind: z.string().nullable(),
|
||||
retentionClass: z.string(),
|
||||
legalHold: z.boolean(),
|
||||
status: z.enum(["active", "disposed"]),
|
||||
/** Whether the document is past changing: disposed, or erased. */
|
||||
disposed: z.boolean(),
|
||||
revision,
|
||||
createdAt: z.string(),
|
||||
lastVersionAt: z.string(),
|
||||
disposedAt: z.string().nullable(),
|
||||
})
|
||||
export type DocumentView = z.output<typeof documentViewSchema>
|
||||
|
||||
export const versionViewSchema = z.object({
|
||||
versionId: z.string(),
|
||||
sequence: z.number().int(),
|
||||
sha256: z.string(),
|
||||
mediaType: z.string(),
|
||||
/** Bytes, as digits. */
|
||||
size: z.string(),
|
||||
createdAt: z.string(),
|
||||
})
|
||||
export type VersionView = z.output<typeof versionViewSchema>
|
||||
|
||||
export const retentionClassViewSchema = z.object({
|
||||
code: z.string(),
|
||||
keepFor: z.string(),
|
||||
from: z.enum(RETENTION_BASES),
|
||||
createdAt: z.string(),
|
||||
})
|
||||
export type RetentionClassView = z.output<typeof retentionClassViewSchema>
|
||||
|
||||
/** A version's immutable facts, as the use cases take them from the stored file. */
|
||||
export interface VersionFacts {
|
||||
readonly sha256: string
|
||||
readonly mediaType: string
|
||||
readonly size: number
|
||||
readonly blobRef: string
|
||||
}
|
||||
|
||||
const receipt = z.object({ documentId: z.string(), revision })
|
||||
export type DocumentReceipt = z.output<typeof receipt>
|
||||
|
||||
const documentPage = z.object({ rows: z.array(documentViewSchema), after: z.string().optional() })
|
||||
|
||||
export const documentList = procedure("archive.document.list")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.read)
|
||||
.input(z.object({ ...inProject, q: z.string().max(200).optional(), ...page }))
|
||||
.output(documentPage)
|
||||
.contract()
|
||||
|
||||
export const documentGet = procedure("archive.document.get")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.read)
|
||||
.input(z.object({ ...inProject, documentId }))
|
||||
.output(z.object({ document: documentViewSchema, versions: z.array(versionViewSchema) }))
|
||||
.contract()
|
||||
|
||||
export const documentRegister = procedure("archive.document.register")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.write)
|
||||
.input(
|
||||
z.object({
|
||||
...inProject,
|
||||
title: z.string().trim().min(1).max(200),
|
||||
kind: z
|
||||
.string()
|
||||
.regex(/^\d{1,4}$/)
|
||||
.optional(),
|
||||
retentionClass: z.string().min(1).max(64),
|
||||
fileId,
|
||||
requestId,
|
||||
}),
|
||||
)
|
||||
.output(receipt)
|
||||
.contract()
|
||||
|
||||
export const versionAdd = procedure("archive.version.add")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.write)
|
||||
.input(z.object({ ...inProject, documentId, revision, fileId, requestId }))
|
||||
.output(receipt)
|
||||
.contract()
|
||||
|
||||
export const documentHold = procedure("archive.document.hold")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.manage)
|
||||
.input(z.object({ ...inProject, documentId, revision, legalHold: z.boolean(), requestId }))
|
||||
.output(receipt)
|
||||
.contract()
|
||||
|
||||
export const documentDispose = procedure("archive.document.dispose")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.manage)
|
||||
.input(z.object({ ...inProject, documentId, revision, requestId }))
|
||||
.output(receipt)
|
||||
.contract()
|
||||
|
||||
export const retentionList = procedure("archive.retention.list")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.read)
|
||||
.input(z.object({ ...inProject, ...page }))
|
||||
.output(z.object({ rows: z.array(retentionClassViewSchema), after: z.string().optional() }))
|
||||
.contract()
|
||||
|
||||
export const retentionCreate = procedure("archive.retention.create")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.manage)
|
||||
.input(
|
||||
z.object({
|
||||
...inProject,
|
||||
code: z.string().regex(/^[A-Za-z0-9_-]{1,64}$/),
|
||||
/** An ISO 8601 duration such as P10Y; the service reads it. */
|
||||
keepFor: z.string().min(2).max(64),
|
||||
from: z.enum(RETENTION_BASES),
|
||||
requestId,
|
||||
}),
|
||||
)
|
||||
.output(z.object({ code: z.string() }))
|
||||
.contract()
|
||||
|
||||
export const disposalList = procedure("archive.disposal.list")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission(ARCHIVE_PERMISSIONS.read)
|
||||
.input(z.object({ ...inProject, ...page }))
|
||||
.output(documentPage)
|
||||
.contract()
|
||||
Reference in New Issue
Block a user