feat(upload): add realtime SSE updates
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
export type RealtimeRefreshFilter =
|
||||
| { kind: "form"; formId?: string }
|
||||
| { kind: "uploads" }
|
||||
| { kind: "xp" }
|
||||
| { kind: "vc"; channelId?: string };
|
||||
|
||||
export type RealtimeRefreshHandlers = {
|
||||
onOpen: () => void;
|
||||
onForm: (event: { formId: string }) => void;
|
||||
onUpload: () => void;
|
||||
onXp: () => void;
|
||||
onVc: (event: { channelId: string }) => void;
|
||||
};
|
||||
@@ -50,6 +52,9 @@ export function startRealtimeRefresh({
|
||||
onXp() {
|
||||
if (filter.kind === "xp") scheduleRefresh();
|
||||
},
|
||||
onUpload() {
|
||||
if (filter.kind === "uploads") scheduleRefresh();
|
||||
},
|
||||
onVc(event) {
|
||||
if (
|
||||
filter.kind === "vc"
|
||||
|
||||
@@ -37,3 +37,32 @@ describe("leaderboard SSE contract", () => {
|
||||
)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("upload SSE contract", () => {
|
||||
test("registers an admin-only upload topic", () => {
|
||||
expect(isSseTopic("uploads")).toBeTrue();
|
||||
expect(sse.uploads.adminOnly).toBeTrue();
|
||||
});
|
||||
|
||||
test("validates upload job status events", () => {
|
||||
const message = JSON.stringify({
|
||||
event: "update",
|
||||
data: {
|
||||
uploadId: "upload-1",
|
||||
jobId: "job-1",
|
||||
platform: "youtube",
|
||||
status: "completed",
|
||||
},
|
||||
});
|
||||
|
||||
expect(sse.uploads.parseRedisMessage(message)).toEqual({
|
||||
event: "update",
|
||||
data: {
|
||||
uploadId: "upload-1",
|
||||
jobId: "job-1",
|
||||
platform: "youtube",
|
||||
status: "completed",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -306,6 +306,24 @@ export const sse = createSseEndpoints({
|
||||
}).strict(),
|
||||
},
|
||||
},
|
||||
uploads: {
|
||||
adminOnly: true,
|
||||
events: {
|
||||
update: z.object({
|
||||
uploadId: z.string().min(1),
|
||||
jobId: z.string().min(1).optional(),
|
||||
platform: z.enum(["youtube", "tiktok"]).optional(),
|
||||
status: z.enum([
|
||||
"scheduled",
|
||||
"processing",
|
||||
"pending",
|
||||
"completed",
|
||||
"partial",
|
||||
"failed",
|
||||
]),
|
||||
}).strict(),
|
||||
},
|
||||
},
|
||||
leaderboards: {
|
||||
events: {
|
||||
xp: z.object({}).strict(),
|
||||
|
||||
Reference in New Issue
Block a user