import * as z from "zod/mini"; import { createGeneration, type Generation, generationSchema, } from "./v3-generation.js"; const canonicalIdStringSchema = z.string().check(z.trim(), z.minLength(1)); const viewHostLifecycleEventEnvelopeSchema = z.strictObject({ t: z.string().check(z.startsWith("getuserfeedback:")), gen: generationSchema, viewId: canonicalIdStringSchema, }); export const eventViewPrerenderedSchema = z.extend( viewHostLifecycleEventEnvelopeSchema, { t: z.literal("getuserfeedback:event:viewPrerendered"), }, ); export type EventViewPrerendered = z.output; export const eventViewActivatedSchema = z.extend( viewHostLifecycleEventEnvelopeSchema, { t: z.literal("getuserfeedback:event:viewActivated"), }, ); export type EventViewActivated = z.output; export const eventViewClosedSchema = z.extend( viewHostLifecycleEventEnvelopeSchema, { t: z.literal("getuserfeedback:event:viewClosed"), reason: z.optional(z.enum(["user", "error", "timeout", "unknown"])), lifetimeMs: z.optional(z.number().check(z.nonnegative())), }, ); export type EventViewClosed = z.output; export const eventViewAllocationFailedSchema = z.extend( viewHostLifecycleEventEnvelopeSchema, { t: z.literal("getuserfeedback:event:viewAllocationFailed"), flowRunId: canonicalIdStringSchema, }, ); export type EventViewAllocationFailed = z.output< typeof eventViewAllocationFailedSchema >; const closeFailureMessageSchema = z .string() .check(z.trim(), z.minLength(1), z.maxLength(255)); export const eventViewCloseFailedSchema = z.extend( viewHostLifecycleEventEnvelopeSchema, { t: z.literal("getuserfeedback:event:viewCloseFailed"), closeAttemptId: canonicalIdStringSchema, reason: z.enum(["close-failed", "unknown-occurrence"]), message: z.optional(closeFailureMessageSchema), }, ); export type EventViewCloseFailed = z.output; const toGeneration = (generation: number | Generation): Generation => typeof generation === "number" ? createGeneration(generation) : generation; export function buildEventViewPrerendered(input: { gen: number | Generation; viewId: string; }): EventViewPrerendered { return { t: "getuserfeedback:event:viewPrerendered", gen: toGeneration(input.gen), viewId: input.viewId, }; } export function buildEventViewActivated(input: { gen: number | Generation; viewId: string; }): EventViewActivated { return { t: "getuserfeedback:event:viewActivated", gen: toGeneration(input.gen), viewId: input.viewId, }; } export function buildEventViewClosed(input: { gen: number | Generation; viewId: string; reason?: "user" | "error" | "timeout" | "unknown"; lifetimeMs?: number; }): EventViewClosed { const lifetimeMs = typeof input.lifetimeMs === "number" ? input.lifetimeMs : undefined; return { t: "getuserfeedback:event:viewClosed", gen: toGeneration(input.gen), viewId: input.viewId, reason: input.reason, ...(lifetimeMs !== undefined ? { lifetimeMs } : {}), }; } export function buildEventViewAllocationFailed(input: { gen: number | Generation; viewId: string; flowRunId: string; }): EventViewAllocationFailed { return { t: "getuserfeedback:event:viewAllocationFailed", gen: toGeneration(input.gen), viewId: input.viewId, flowRunId: input.flowRunId, }; } export function buildEventViewCloseFailed(input: { gen: number | Generation; viewId: string; closeAttemptId: string; reason: EventViewCloseFailed["reason"]; message?: string; }): EventViewCloseFailed { return { t: "getuserfeedback:event:viewCloseFailed", gen: toGeneration(input.gen), viewId: input.viewId, closeAttemptId: input.closeAttemptId, reason: input.reason, ...(input.message !== undefined ? { message: input.message } : {}), }; }