2025-06-30 18:58:24 +02:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
*/
|
2025-03-05 16:02:26 +01:00
|
|
|
import { pipeline } from "node:stream";
|
2025-09-20 20:11:58 +02:00
|
|
|
import { createEventStream } from "~/server/streams";
|
2025-02-27 15:42:59 +01:00
|
|
|
|
2025-03-05 15:36:50 +01:00
|
|
|
export default defineEventHandler(async (event) => {
|
2025-07-07 22:42:49 +02:00
|
|
|
const session = await getServerSession(event, false);
|
2025-03-10 16:26:52 +01:00
|
|
|
|
2025-09-20 20:11:58 +02:00
|
|
|
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",
|
|
|
|
});
|
2025-02-27 15:42:59 +01:00
|
|
|
}
|
2025-09-20 20:11:58 +02:00
|
|
|
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);
|
2025-03-05 16:02:26 +01:00
|
|
|
|
|
|
|
// 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");
|
2025-09-20 20:11:58 +02:00
|
|
|
pipeline(stream as unknown as NodeJS.ReadableStream, event.node.res, (err) => { /* ignore */ });
|
2025-03-05 16:02:26 +01:00
|
|
|
event._handled = true;
|
2025-03-05 15:36:50 +01:00
|
|
|
});
|