owltide/server/api/events.ts

50 lines
1.7 KiB
TypeScript
Raw Normal View History

/*
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { pipeline } from "node:stream";
import { createEventStream } from "~/server/streams";
export default defineEventHandler(async (event) => {
const session = await getServerSession(event, false);
let lastEventId: number | undefined;
const lastEventIdHeader = event.headers.get("Last-Event-ID");
const lastEventIdQuery = getQuery(event)["lastEventId"];
if (lastEventIdHeader) {
if (!/^[0-9]{1,15}$/.test(lastEventIdHeader)) {
throw createError({
statusCode: 400,
statusMessage: "Bad Request",
message: "Malformed Last-Event-ID header",
});
}
lastEventId = Number.parseInt(lastEventIdHeader, 10);
} else if (lastEventIdQuery) {
if (typeof lastEventIdQuery !== "string" || !/^[0-9]{1,15}$/.test(lastEventIdQuery)) {
throw createError({
statusCode: 400,
statusMessage: "Bad Request",
message: "Malformed lastEventId",
});
}
lastEventId = Number.parseInt(lastEventIdQuery, 10);
} else {
throw createError({
statusCode: 400,
statusMessage: "Bad Request",
message: "lastEventId is required",
});
}
const source = event.headers.get("x-forwarded-for") ?? "";
const stream = await createEventStream(event, source, lastEventId, session);
// Workaround to properly handle stream errors. See https://github.com/unjs/h3/issues/986
setHeader(event, "Access-Control-Allow-Origin", "*");
setHeader(event, "Content-Type", "text/event-stream");
setHeader(event, "Cache-Control", "no-store");
pipeline(stream as unknown as NodeJS.ReadableStream, event.node.res, (err) => { /* ignore */ });
event._handled = true;
});