Files
chad/server/routes/chat.ts

112 lines
3.0 KiB
TypeScript

import type { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox'
import { Type } from 'typebox'
import { ChatMessageSchema, NewChatMessagePayloadSchema } from '../plugins/schemas/chat.ts'
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
fastify.post(
'/chat/send',
{
schema: {
summary: 'Send message',
tags: ['Chat'],
operationId: 'chat.send',
body: NewChatMessagePayloadSchema,
response: {
200: ChatMessageSchema,
},
},
},
async (req, reply) => {
const user = req.user!
const message = await fastify.prisma.message.create({
data: {
text: req.body.text,
senderId: user.id,
attachments: {
create: (req.body.attachments ?? []).map((attachmentId) => {
return {
attachment: {
connect: {
id: attachmentId,
},
},
}
}),
},
},
})
if (!message) {
return reply.unprocessableEntity()
}
const response = {
id: message.id,
senderId: user.id,
text: message.text,
createdAt: message.createdAt.toISOString(),
updatedAt: message.updatedAt.toISOString(),
attachments: req.body.attachments ?? [],
}
fastify.bus.emit('chat:new-message', response)
return response
},
)
fastify.get(
'/chat',
{
schema: {
summary: 'Get messages',
tags: ['Chat'],
operationId: 'chat.messages',
querystring: Type.Object({
cursor: Type.Optional(Type.String({ format: 'uuid', description: 'Cursor to message' })),
limit: Type.Number({ minimum: 1, maximum: 100, default: 10 }),
}),
response: {
200: Type.Object({
messages: Type.Array(ChatMessageSchema),
nextCursor: Type.Optional(Type.String({ format: 'uuid', description: 'Cursor to last message' })),
}),
},
},
},
// eslint-disable-next-line ts/ban-ts-comment
// @ts-expect-error
async (req) => {
const messages = await fastify.prisma.message.findMany({
orderBy: { createdAt: 'desc' },
take: req.query.limit + 1,
include: { attachments: true },
...(req.query.cursor && {
cursor: {
id: req.query.cursor,
},
// skip: 1,
}),
})
const hasMore = messages.length > req.query.limit
const cursorMessage = hasMore ? messages.pop() : undefined
return {
messages: messages.map((message) => {
return {
...message,
createdAt: message.createdAt.toISOString(),
updatedAt: message.updatedAt.toISOString(),
attachments: message.attachments.map(({ attachmentId }) => attachmentId),
}
}),
nextCursor: cursorMessage?.id,
}
},
)
}
export default plugin