import { defineAction } from "@agent-native/core"; import { assertAccess } from "@agent-native/core/sharing"; import { and, desc, eq } from "drizzle-orm"; import { z } from "zod"; import { getDb, schema } from "../server/db/index.js"; import "../server/db/index.js"; // ensure registerShareableResource runs import { extractManagedMotionCss, hashCss, parse, parseFirstAnimationDurationMs, parsePlaybackMode, parseTimelineSpanMs, } from "../shared/motion-compiler.js"; import type { MotionPlaybackMode, MotionTrack, } from "../shared/motion-timeline.js"; import { MOTION_DEFAULT_PLAYBACK_MODE, readTimelinePlaybackMode, } from "../shared/motion-timeline.js"; type TimelineSource = "stored" | "recovered-css" | "stored-css-drift"; interface TimelineResult { id: string | null; designId: string; sourceRef: string | null; filePath: string | null; tracks: unknown; durationMs: number; /** * Timeline playback mode: from the tracks JSON stamp for stored rows, * recovered from animation-iteration-count/direction for CSS-recovered * timelines, "once" for timelines that predate the field. */ playbackMode: MotionPlaybackMode; defaultEase: string; compiledHash: string | null; cssHash?: string | null; source: TimelineSource; createdAt: string | null; updatedAt: string | null; } function parseTrackJson(raw: string | null): MotionTrack[] { try { const parsed: unknown = JSON.parse(raw ?? "[]"); return Array.isArray(parsed) ? (parsed as MotionTrack[]) : []; } catch { return []; } } async function readManagedCssForSource(args: { designId: string; sourceRef?: string; }): Promise<{ css: string; hash: string; tracks: MotionTrack[]; durationMs: number | null; playbackMode: MotionPlaybackMode | null; } | null> { if (!args.sourceRef) return null; const db = getDb(); const [file] = await db .select({ id: schema.designFiles.id, content: schema.designFiles.content, }) .from(schema.designFiles) .where( and( eq(schema.designFiles.designId, args.designId), eq(schema.designFiles.id, args.sourceRef), ), ) .limit(1); if (!file) return null; // Read the managed block from the SQL content, NOT a live collab snapshot: // apply-motion-edit persists the managed