feat: added schemas for openapi (#452)

This commit is contained in:
Morfixx
2026-04-18 13:29:35 -07:00
committed by GitHub
parent 6056167063
commit ae4bc77407
15 changed files with 606 additions and 68 deletions

View File

@@ -8,6 +8,7 @@ import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { generateUID } from "@kan/shared/utils";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { attachmentConfirmResponseSchema } from "../schemas";
import { assertPermission } from "../utils/permissions";
import { deleteObject, generateUploadUrl } from "@kan/shared/utils";
@@ -110,7 +111,7 @@ export const attachmentRouter = createTRPCRouter({
size: z.number().positive(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof cardAttachmentRepo.create>>>())
.output(attachmentConfirmResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;

View File

@@ -16,6 +16,13 @@ import {
} from "@kan/shared/utils";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
import {
boardListItemSchema,
boardDetailSchema,
boardBySlugSchema,
boardCreateResponseSchema,
boardUpdateResponseSchema,
} from "../schemas";
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
export const boardRouter = createTRPCRouter({
@@ -37,9 +44,7 @@ export const boardRouter = createTRPCRouter({
archived: z.boolean().optional(),
}),
)
.output(
z.custom<Awaited<ReturnType<typeof boardRepo.getAllByWorkspaceId>>>(),
)
.output(z.array(boardListItemSchema))
.query(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -106,7 +111,7 @@ export const boardRouter = createTRPCRouter({
type: z.enum(["regular", "template"]).optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof boardRepo.getByPublicId>>>())
.output(boardDetailSchema)
.query(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -246,7 +251,7 @@ export const boardRouter = createTRPCRouter({
.optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof boardRepo.getBySlug>>>())
.output(boardBySlugSchema.nullable())
.query(async ({ ctx, input }) => {
const workspace = await workspaceRepo.getBySlugWithBoards(
ctx.db,
@@ -299,7 +304,7 @@ export const boardRouter = createTRPCRouter({
sourceBoardPublicId: z.string().min(12).optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof boardRepo.create>>>())
.output(boardCreateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -469,7 +474,7 @@ export const boardRouter = createTRPCRouter({
isArchived: z.boolean().optional(),
}),
)
.output(z.object({ success: z.boolean() }).or(z.custom<Awaited<ReturnType<typeof boardRepo.update>>>()))
.output(boardUpdateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;

View File

@@ -10,6 +10,14 @@ import * as listRepo from "@kan/db/repository/list.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
import {
cardCreateResponseSchema,
cardUpdateResponseSchema,
cardDetailSchema,
commentResponseSchema,
commentDeleteResponseSchema,
activityItemSchema,
} from "../schemas";
import { mergeActivities } from "../utils/activities";
import { sendMentionEmails } from "../utils/notifications";
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
@@ -42,7 +50,7 @@ export const cardRouter = createTRPCRouter({
dueDate: z.date().nullable().optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof cardRepo.create>>>())
.output(cardCreateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -215,7 +223,7 @@ export const cardRouter = createTRPCRouter({
comment: z.string().min(1),
}),
)
.output(z.custom<Awaited<ReturnType<typeof cardCommentRepo.create>>>())
.output(commentResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -288,7 +296,7 @@ export const cardRouter = createTRPCRouter({
comment: z.string().min(1),
}),
)
.output(z.custom<Awaited<ReturnType<typeof cardCommentRepo.update>>>())
.output(commentResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -376,7 +384,7 @@ export const cardRouter = createTRPCRouter({
commentPublicId: z.string().min(12),
}),
)
.output(z.custom<Awaited<ReturnType<typeof cardCommentRepo.softDelete>>>())
.output(commentDeleteResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -435,7 +443,7 @@ export const cardRouter = createTRPCRouter({
createdBy: userId,
});
return deletedComment;
return { publicId: input.commentPublicId };
}),
addOrRemoveLabel: protectedProcedure
.meta({
@@ -639,25 +647,7 @@ export const cardRouter = createTRPCRouter({
},
})
.input(z.object({ cardPublicId: z.string().min(12) }))
.output(
z.custom<
Omit<
NonNullable<
Awaited<ReturnType<typeof cardRepo.getWithListAndMembersByPublicId>>
>,
"attachments"
> & {
attachments: {
publicId: string;
contentType: string;
s3Key: string;
originalFilename: string | null;
size?: number | null;
url: string | null;
}[];
}
>(),
)
.output(cardDetailSchema)
.query(async ({ ctx, input }) => {
const card = await cardRepo.getWorkspaceAndCardIdByCardPublicId(
ctx.db,
@@ -763,15 +753,7 @@ export const cardRouter = createTRPCRouter({
)
.output(
z.object({
activities: z.array(
z.custom<
NonNullable<
Awaited<
ReturnType<typeof cardActivityRepo.getPaginatedActivities>
>
>["activities"][number]
>(),
),
activities: z.array(activityItemSchema),
hasMore: z.boolean(),
nextCursor: z.string().datetime().nullable(),
}),
@@ -871,7 +853,7 @@ export const cardRouter = createTRPCRouter({
dueDate: z.date().nullable().optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof cardRepo.update>>>())
.output(cardUpdateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;

View File

@@ -7,6 +7,7 @@ import * as activityRepo from "@kan/db/repository/cardActivity.repo";
import * as listRepo from "@kan/db/repository/list.repo";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { listCreateResponseSchema, listUpdateResponseSchema } from "../schemas";
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
export const listRouter = createTRPCRouter({
@@ -27,7 +28,7 @@ export const listRouter = createTRPCRouter({
boardPublicId: z.string().min(12),
}),
)
.output(z.custom<Awaited<ReturnType<typeof listRepo.create>>>())
.output(listCreateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -163,12 +164,7 @@ export const listRouter = createTRPCRouter({
index: z.number().optional(),
}),
)
.output(
z.custom<
| Awaited<ReturnType<typeof listRepo.update>>
| Awaited<ReturnType<typeof listRepo.reorder>>
>(),
)
.output(listUpdateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;

View File

@@ -16,6 +16,7 @@ import {
import { updateSubscriptionSeats } from "@kan/stripe";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
import { memberInviteResponseSchema } from "../schemas";
import {
assertCanManageMember,
assertCanManageRole,
@@ -40,7 +41,7 @@ export const memberRouter = createTRPCRouter({
workspacePublicId: z.string().min(12),
}),
)
.output(z.custom<Awaited<ReturnType<typeof memberRepo.create>>>())
.output(memberInviteResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;

View File

@@ -7,6 +7,14 @@ import * as workspaceSlugRepo from "@kan/db/repository/workspaceSlug.repo";
import { generateAvatarUrl, generateUID } from "@kan/shared/utils";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
import {
workspaceListItemSchema,
workspaceDetailSchema,
workspaceWithBoardsSchema,
workspaceCreateResponseSchema,
workspaceUpdateResponseSchema,
workspaceDeleteResponseSchema,
} from "../schemas";
import { assertPermission } from "../utils/permissions";
export const workspaceRouter = createTRPCRouter({
@@ -22,9 +30,7 @@ export const workspaceRouter = createTRPCRouter({
},
})
.input(z.void())
.output(
z.custom<Awaited<ReturnType<typeof workspaceRepo.getAllByUserId>>>(),
)
.output(z.array(workspaceListItemSchema))
.query(async ({ ctx }) => {
const userId = ctx.user?.id;
@@ -50,11 +56,7 @@ export const workspaceRouter = createTRPCRouter({
},
})
.input(z.object({ workspacePublicId: z.string().min(12) }))
.output(
z.custom<
Awaited<ReturnType<typeof workspaceRepo.getByPublicIdWithMembers>>
>(),
)
.output(workspaceDetailSchema)
.query(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -134,7 +136,7 @@ export const workspaceRouter = createTRPCRouter({
return {
...result,
members: sanitizedMembers,
} as Awaited<ReturnType<typeof workspaceRepo.getByPublicIdWithMembers>>;
};
}
return {
@@ -162,9 +164,7 @@ export const workspaceRouter = createTRPCRouter({
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/),
}),
)
.output(
z.custom<Awaited<ReturnType<typeof workspaceRepo.getBySlugWithBoards>>>(),
)
.output(workspaceWithBoardsSchema)
.query(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -211,7 +211,7 @@ export const workspaceRouter = createTRPCRouter({
.optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof workspaceRepo.create>>>())
.output(workspaceCreateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
const userEmail = ctx.user?.email;
@@ -270,7 +270,13 @@ export const workspaceRouter = createTRPCRouter({
code: "INTERNAL_SERVER_ERROR",
});
return result;
return {
publicId: result.publicId,
name: result.name!,
slug: result.slug!,
description: result.description ?? null,
plan: result.plan!,
};
}),
update: protectedProcedure
.meta({
@@ -300,7 +306,7 @@ export const workspaceRouter = createTRPCRouter({
.optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof workspaceRepo.update>>>())
.output(workspaceUpdateResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -383,7 +389,7 @@ export const workspaceRouter = createTRPCRouter({
},
})
.input(z.object({ workspacePublicId: z.string().min(12) }))
.output(z.custom<Awaited<ReturnType<typeof workspaceRepo.hardDelete>>>())
.output(workspaceDeleteResponseSchema)
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
@@ -405,12 +411,12 @@ export const workspaceRouter = createTRPCRouter({
});
await assertPermission(ctx.db, userId, workspace.id, "workspace:delete");
const result = await workspaceRepo.hardDelete(
await workspaceRepo.hardDelete(
ctx.db,
input.workspacePublicId,
);
return result;
return { success: true };
}),
checkSlugAvailability: publicProcedure
.meta({