// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // The generated client receives only the current server-prepared binding. import { businessAppError, type RequestBusinessBinding, requestBusinessBinding, toBusinessError, } from "@conusai-kit/business" import { type Container, notFound, type ProcedureKind } from "@conusai-kit/core" import { type Activity, activitiesAddComment, activitiesCompleteTask, activitiesCreateTask, activitiesFindActivities, activitiesGetActivity, activitiesListComments, activitiesReopenTask, activitiesTimelineFor, activitiesUpdateActivity, type Comment, type Fields, type Receipt, } from "@conusai-sdk/activities" import { createClient } from "@conusai-sdk/activities/client" import type { CommentView, TaskReceipt } from "../contract/index.js" import { ACTIVITIES_SERVICE, type ActivitiesReads, type ActivitiesService, readsOf, type TaskRecord, } from "../core/ports.js" async function answer( operation: Promise<{ data?: T; error?: unknown; response?: Response }>, ): Promise> { let result: Awaited try { result = await operation } catch (error) { throw businessAppError(toBusinessError(error, undefined)) } if (result.error !== undefined || result.data === undefined) throw businessAppError(toBusinessError(result.error, result.response)) return result.data as Exclude } const view = (value: Activity): TaskRecord => { if (value.kind !== "task" || value.status === undefined || value.status === null || value.erased || value.deleted) throw notFound() return { taskId: value.id, subject: value.subject, body: value.body ?? "", revision: value.revision.toString(), status: value.status, targets: value.targets, createdAt: value.created_at, } } const commentView = (value: Comment): CommentView => ({ commentId: value.id, body: value.erased ? "" : value.body, author: value.author ?? null, erased: value.erased, }) const receiptView = (value: Receipt): TaskReceipt => ({ taskId: value.id, revision: value.revision.toString() }) const fieldsOf = (row: Activity): Fields => ({ subject: row.subject, targets: row.targets, ...(row.body === undefined ? {} : { body: row.body }), ...(row.assignee === undefined ? {} : { assignee: row.assignee }), ...(row.due_at === undefined ? {} : { due_at: row.due_at }), ...(row.ext === undefined ? {} : { ext: row.ext }), ...(row.participants === undefined ? {} : { participants: row.participants }), ...(row.pinned === undefined ? {} : { pinned: row.pinned }), }) /** No org-wide client constructor or deployment singleton is supported. */ export function sdkActivitiesService(binding: RequestBusinessBinding): ActivitiesService { const client = binding.client(createClient) const org = { org_slug: binding.orgSlug } const get = (id: string) => answer(activitiesGetActivity({ client, path: { ...org, activity_id: id } })) return { bindingId: binding.bindingId, async list(input) { const result = await answer( activitiesFindActivities({ client, path: org, query: { target: input.target, ...(input.status ? { status: input.status } : {}), ...(input.after ? { after: input.after } : {}), limit: 50n, }, }), ) return { rows: result.data.filter((row) => row.kind === "task" && !row.erased && !row.deleted).map(view), ...(result.next_after ? { after: result.next_after } : {}), } }, async get(id) { return view(await get(id)) }, async timeline(input) { const result = await answer( activitiesTimelineFor({ client, path: org, query: { target: input.target, ...(input.after ? { after: input.after } : {}), limit: 50n }, }), ) return { rows: result.data.filter((row) => row.kind === "task" && !row.erased && !row.deleted).map(view), ...(result.next_after ? { after: result.next_after } : {}), } }, async comments(input) { const result = await answer( activitiesListComments({ client, path: { ...org, activity_id: input.taskId }, query: { ...(input.after ? { after: input.after } : {}), limit: 50n, }, }), ) return { rows: result.data.map(commentView), ...(result.next_after ? { after: result.next_after } : {}) } }, async create(input) { return receiptView( await answer( activitiesCreateTask({ client, path: org, body: { kind: "task", idempotency_key: input.key, fields: { subject: input.subject, body: input.body, targets: [input.target], participants: [input.participant], }, }, }), ), ) }, async update(input) { const current = await get(input.task.taskId) if (!current.targets.includes(input.target)) throw notFound() return receiptView( await answer( activitiesUpdateActivity({ client, path: { ...org, activity_id: current.id }, body: { fields: { ...fieldsOf(current), subject: input.subject, body: input.body }, revision: BigInt(input.expectedVersion), idempotency_key: input.key, }, }), ), ) }, async change(input) { const operation = input.state === "done" ? activitiesCompleteTask : activitiesReopenTask return receiptView( await answer( operation({ client, path: { ...org, activity_id: input.taskId }, body: { revision: BigInt(input.expectedVersion), idempotency_key: input.key }, }), ), ) }, async comment(input) { const result = await answer( activitiesAddComment({ client, path: { ...org, activity_id: input.taskId }, body: { body: input.body, revision: BigInt(input.expectedVersion), idempotency_key: input.key }, }), ) return { commentId: result.id, revision: result.revision.toString() } }, } } export function activitiesServiceOf(container: Container, kind: "effect"): ActivitiesService export function activitiesServiceOf(container: Container, kind: ProcedureKind): ActivitiesReads export function activitiesServiceOf(container: Container, kind: ProcedureKind): ActivitiesReads { const service = container.has(ACTIVITIES_SERVICE) ? container.resolve(ACTIVITIES_SERVICE) : sdkActivitiesService(requestBusinessBinding(container)) return kind === "effect" ? service : readsOf(service) }