ConusAI vendor v0.1.0-beta.114
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-beta.114
2026-11-14 09:56:45 +00:00
commit 1ce8d23c35
867 changed files with 122104 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
import { token } from "@conusai-kit/core"
import type { CommentReceipt, CommentView, TaskReceipt, TaskView } from "../contract/index.js"
export interface Page<T> {
rows: T[]
after?: string
}
export interface TaskRecord extends TaskView {
targets: string[]
}
export interface ActivitiesReads {
readonly bindingId: string
list(input: { target: string; status?: "open" | "done" | "cancelled"; after?: string }): Promise<Page<TaskView>>
get(taskId: string): Promise<TaskRecord>
comments(input: { taskId: string; after?: string }): Promise<Page<CommentView>>
timeline(input: { target: string; after?: string }): Promise<Page<TaskView>>
}
export interface ActivitiesService extends ActivitiesReads {
create(input: {
subject: string
body: string
target: string
participant: string
key: string
}): Promise<TaskReceipt>
update(input: {
task: TaskRecord
target: string
subject: string
body: string
expectedVersion: string
key: string
}): Promise<TaskReceipt>
change(input: { taskId: string; state: "done" | "open"; expectedVersion: string; key: string }): Promise<TaskReceipt>
comment(input: { taskId: string; body: string; expectedVersion: string; key: string }): Promise<CommentReceipt>
}
export const readsOf = (service: ActivitiesReads): ActivitiesReads => ({
bindingId: service.bindingId,
list: (input) => service.list(input),
get: (id) => service.get(id),
comments: (input) => service.comments(input),
timeline: (input) => service.timeline(input),
})
export const ACTIVITIES_SERVICE = token<ActivitiesService>("activities.service", {
views: { read: readsOf, write: readsOf },
})
+98
View File
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
import { actorRef, projectRef } from "@conusai-kit/business"
import { conflict, notFound, type ProjectScope } from "@conusai-kit/core"
import type { ActivitiesReads, ActivitiesService } from "./ports.js"
const keyOf = (scope: ProjectScope, operation: string, requestId: string) =>
`activities:${scope.projectId}:${operation}:${requestId}`
const targetOf = (service: ActivitiesReads, scope: ProjectScope) => projectRef(service.bindingId, scope.projectId)
/** An app project is a narrower boundary than its organization partition. */
export async function ownedTask(service: ActivitiesReads, scope: ProjectScope, taskId: string) {
const task = await service.get(taskId)
if (!task.targets.includes(targetOf(service, scope))) throw notFound()
return task
}
function currentOrRetry(actual: string, requested: string) {
// A future revision could become valid after a concurrent target move. A
// prior revision must reach the service's idempotency check on a real retry.
if (BigInt(requested) > BigInt(actual)) throw conflict("The task changed; reload before editing.")
}
export const listTasks = (
service: ActivitiesReads,
scope: ProjectScope,
input: { status?: "open" | "done" | "cancelled" | undefined; after?: string | undefined },
) =>
service.list({
target: targetOf(service, scope),
status: input.status ?? "open",
...(input.after ? { after: input.after } : {}),
})
export const projectTimeline = (service: ActivitiesReads, scope: ProjectScope, after?: string) =>
service.timeline({ target: targetOf(service, scope), ...(after ? { after } : {}) })
export const createTask = (
service: ActivitiesService,
scope: ProjectScope,
input: { subject: string; body?: string | undefined; requestId: string },
) =>
service.create({
subject: input.subject.trim(),
body: input.body ?? "",
target: targetOf(service, scope),
participant: actorRef(service.bindingId, scope.actor.userId),
key: keyOf(scope, "create", input.requestId),
})
export async function updateTask(
service: ActivitiesService,
scope: ProjectScope,
input: { taskId: string; subject: string; body: string; expectedVersion: string; requestId: string },
) {
const task = await ownedTask(service, scope, input.taskId)
currentOrRetry(task.revision, input.expectedVersion)
return service.update({
task,
target: targetOf(service, scope),
subject: input.subject.trim(),
body: input.body,
expectedVersion: input.expectedVersion,
key: keyOf(scope, "update", input.requestId),
})
}
export async function changeTask(
service: ActivitiesService,
scope: ProjectScope,
input: { taskId: string; expectedVersion: string; requestId: string },
state: "done" | "open",
) {
const task = await ownedTask(service, scope, input.taskId)
currentOrRetry(task.revision, input.expectedVersion)
return service.change({
taskId: task.taskId,
state,
expectedVersion: input.expectedVersion,
key: keyOf(scope, state, input.requestId),
})
}
export async function listComments(
service: ActivitiesReads,
scope: ProjectScope,
input: { taskId: string; after?: string | undefined },
) {
await ownedTask(service, scope, input.taskId)
const comments = await service.comments({ taskId: input.taskId, ...(input.after ? { after: input.after } : {}) })
await ownedTask(service, scope, input.taskId)
return comments
}
export async function addComment(
service: ActivitiesService,
scope: ProjectScope,
input: { taskId: string; body: string; expectedVersion: string; requestId: string },
) {
const task = await ownedTask(service, scope, input.taskId)
currentOrRetry(task.revision, input.expectedVersion)
return service.comment({
taskId: input.taskId,
body: input.body.trim(),
expectedVersion: input.expectedVersion,
key: keyOf(scope, "comment", input.requestId),
})
}