The content of the events stream is generated live in response to changes done in the system as they occur. It therefore can't be meaningfully cached or stored in any way. Mark the response as uncacheable to prevent potential problems with caches.
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
/*
|
|
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;
|
|
});
|