feat: ditch triplit, move to postgresql + drizzle orm
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { db } from "~~/server/lib/db";
|
||||
import { topicEvents } from "~~/server/utils/events";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await protectRoute(event);
|
||||
|
||||
const topicId = getRouterParam(event, 'topicId')!;
|
||||
const isSSE = getHeader(event, 'accept')?.includes('text/event-stream') ?? false;
|
||||
|
||||
const userId = event.context.user!.id as string;
|
||||
|
||||
const topic = await db.query.topics.findFirst({
|
||||
where: {
|
||||
id: topicId,
|
||||
userId,
|
||||
},
|
||||
with: {
|
||||
messages: {
|
||||
orderBy: {
|
||||
createdAt: 'asc',
|
||||
},
|
||||
with: {
|
||||
parts: {
|
||||
orderBy: {
|
||||
createdAt: 'asc',
|
||||
},
|
||||
with: {
|
||||
toolCall: true,
|
||||
}
|
||||
},
|
||||
attachments: {
|
||||
with: {
|
||||
file: true,
|
||||
}
|
||||
},
|
||||
generation: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!topic) {
|
||||
console.log("topic not found");
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Not Found',
|
||||
});
|
||||
}
|
||||
|
||||
if (isSSE === false) {
|
||||
return topic;
|
||||
}
|
||||
|
||||
setHeader(event, 'Content-Type', 'text/event-stream');
|
||||
setHeader(event, 'Cache-Control', 'no-cache');
|
||||
setHeader(event, 'Connection', 'keep-alive');
|
||||
|
||||
const { lastUpdate, count } = getQuery(event);
|
||||
const serverLastUpdate = topic.messages.at(-1)?.updatedAt;
|
||||
const serverCount = topic.messages.length;
|
||||
|
||||
// TODO: there is potentially a race condition here where the client could
|
||||
// connect at milisecond 87, and the last database write was at 0 (there
|
||||
// is a write every 100ms for some operations), if there were tokens sent
|
||||
// at 20 40 and 60, those tokens are lost to the client.
|
||||
let streamController: ReadableStreamDefaultController;
|
||||
let interval: NodeJS.Timeout;
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
streamController = controller;
|
||||
controller.enqueue(`:connected\n\n`);
|
||||
|
||||
if ((lastUpdate && count) && (lastUpdate === serverLastUpdate?.toISOString() && count === serverCount)) {
|
||||
controller.enqueue(':already_synced\n\n')
|
||||
} else {
|
||||
controller.enqueue(`data: ${JSON.stringify({
|
||||
type: 'initial_state',
|
||||
payload: topic
|
||||
})}\n\n`);
|
||||
}
|
||||
|
||||
interval = setInterval(() => {
|
||||
controller.enqueue(`:heartbeat\n\n`);
|
||||
}, 15000);
|
||||
|
||||
topicEvents.subscribe(topicId, streamController);
|
||||
},
|
||||
cancel() {
|
||||
topicEvents.unsubscribe(topicId, streamController);
|
||||
clearInterval(interval);
|
||||
}
|
||||
});
|
||||
|
||||
return sendStream(event, stream);
|
||||
});
|
||||
Reference in New Issue
Block a user