@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// Project-scoped task and comment contracts. Authority comes from resolved scope.
|
||||
import { procedure } from "@conusai-kit/core"
|
||||
import { z } from "zod"
|
||||
|
||||
const inProject = { org: z.string(), workspace: z.string(), project: z.string() }
|
||||
const id = z.string().uuid()
|
||||
const resourceSuffix = "[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"
|
||||
export const activityId = z.string().regex(new RegExp(`^act_${resourceSuffix}$`))
|
||||
const commentId = z.string().regex(new RegExp(`^cmt_${resourceSuffix}$`))
|
||||
// Cursors belong to the service and are forwarded unchanged; they are not resource IDs.
|
||||
const cursor = z.string().min(1).max(4096)
|
||||
const revision = z.string().regex(/^[1-9][0-9]{0,18}$/)
|
||||
export const taskView = z.object({
|
||||
taskId: activityId,
|
||||
subject: z.string(),
|
||||
body: z.string(),
|
||||
revision,
|
||||
status: z.enum(["open", "done", "cancelled"]),
|
||||
createdAt: z.string(),
|
||||
})
|
||||
export type TaskView = z.output<typeof taskView>
|
||||
export const commentView = z.object({
|
||||
commentId,
|
||||
body: z.string(),
|
||||
author: z.string().nullable(),
|
||||
erased: z.boolean(),
|
||||
})
|
||||
export type CommentView = z.output<typeof commentView>
|
||||
export const commentReceipt = z.object({ commentId, revision })
|
||||
export type CommentReceipt = z.output<typeof commentReceipt>
|
||||
export const receipt = z.object({ taskId: activityId, revision })
|
||||
export type TaskReceipt = z.output<typeof receipt>
|
||||
const write = { ...inProject, taskId: activityId, expectedVersion: revision, requestId: id }
|
||||
export const taskList = procedure("activities.task.list")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission("activities.task.read")
|
||||
.input(z.object({ ...inProject, status: z.enum(["open", "done", "cancelled"]).optional(), after: cursor.optional() }))
|
||||
.output(z.object({ rows: z.array(taskView), after: cursor.optional() }))
|
||||
.contract()
|
||||
export const taskGet = procedure("activities.task.get")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission("activities.task.read")
|
||||
.input(z.object({ ...inProject, taskId: activityId }))
|
||||
.output(taskView)
|
||||
.contract()
|
||||
export const taskCreate = procedure("activities.task.create")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission("activities.task.write")
|
||||
.input(
|
||||
z.object({
|
||||
...inProject,
|
||||
subject: z.string().trim().min(1).max(200),
|
||||
body: z.string().max(10000).optional(),
|
||||
requestId: id,
|
||||
}),
|
||||
)
|
||||
.output(receipt)
|
||||
.contract()
|
||||
export const taskUpdate = procedure("activities.task.update")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission("activities.task.write")
|
||||
.input(z.object({ ...write, subject: z.string().trim().min(1).max(200), body: z.string().max(10000) }))
|
||||
.output(receipt)
|
||||
.contract()
|
||||
export const taskComplete = procedure("activities.task.complete")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission("activities.task.write")
|
||||
.input(z.object(write))
|
||||
.output(receipt)
|
||||
.contract()
|
||||
export const taskReopen = procedure("activities.task.reopen")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission("activities.task.write")
|
||||
.input(z.object(write))
|
||||
.output(receipt)
|
||||
.contract()
|
||||
export const commentList = procedure("activities.comment.list")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission("activities.task.read")
|
||||
.input(z.object({ ...inProject, taskId: activityId, after: cursor.optional() }))
|
||||
.output(z.object({ rows: z.array(commentView), after: cursor.optional() }))
|
||||
.contract()
|
||||
export const commentAdd = procedure("activities.comment.add")
|
||||
.kind("effect")
|
||||
.scope("project")
|
||||
.permission("activities.comment.write")
|
||||
.input(z.object({ ...write, body: z.string().trim().min(1).max(10000) }))
|
||||
.output(commentReceipt)
|
||||
.contract()
|
||||
export const timeline = procedure("activities.timeline.list")
|
||||
.kind("read")
|
||||
.scope("project")
|
||||
.permission("activities.task.read")
|
||||
.input(z.object({ ...inProject, after: cursor.optional() }))
|
||||
.output(z.object({ rows: z.array(taskView), after: cursor.optional() }))
|
||||
.contract()
|
||||
Reference in New Issue
Block a user