import { expect, test } from "bun:test"; import { actionPrerenderNativeFlowSchema, NATIVE_FLOW_SESSION_OPT_IN, NATIVE_FLOW_SESSION_PROTOCOL, nativeFlowBlockSchema, nativeFlowInteractionSchema, } from "./native-flow-session.js"; test("live draft sync requires the v2 opt-in and protocol", () => { expect(NATIVE_FLOW_SESSION_OPT_IN).toBe( "experimental.native-flow-session.v2", ); expect(NATIVE_FLOW_SESSION_PROTOCOL).toBe("native-flow-session.v2"); expect( nativeFlowInteractionSchema.safeParse({ flowRunId: "run", nodeId: "page", intent: "draft", draft: { name: "Ada" }, }).success, ).toBe(true); }); test("native semantic input has a bounded, closed grammar", () => { const command = { flowRunId: "run", nodeId: "page", intent: "continue", draft: { name: "" }, }; expect(nativeFlowInteractionSchema.safeParse(command).success).toBe(true); for (const invalid of [ { ...command, url: "https://example.com" }, { ...command, intent: "execute" }, { ...command, draft: { name: "x".repeat(4001) } }, { ...command, draft: { choice: ["one", "two"] } }, ]) expect(nativeFlowInteractionSchema.safeParse(invalid).success).toBe(false); }); test("native projection carries text and known controls, never arbitrary host props or srcdoc", () => { const block = { kind: "text", key: "name", label: "Name", required: true }; expect(nativeFlowBlockSchema.safeParse(block).success).toBe(true); expect( nativeFlowBlockSchema.safeParse({ ...block, onPress: "action" }).success, ).toBe(false); expect( nativeFlowBlockSchema.safeParse({ kind: "image", key: "image", uri: "https://example.com", }).success, ).toBe(false); expect( actionPrerenderNativeFlowSchema.safeParse({ t: "getuserfeedback:action:prerenderNativeFlow", gen: 1, viewId: "view", instanceId: "instance", flowRunId: "run", srcdoc: "", }).success, ).toBe(false); });