import { table, text, integer, now, ownableColumns, createSharesTable, } from "@agent-native/core/db/schema"; export const designs = table("designs", { id: text("id").primaryKey(), title: text("title").notNull(), description: text("description"), data: text("data").notNull(), // Monotonic per-client sequence numbers for path-addressed data writes. // Kept outside `data` so editor/export payloads stay free of transport // bookkeeping while late keepalive requests can be rejected atomically. dataOperationRevisions: text("data_operation_revisions") .notNull() .default("{}"), projectType: text("project_type").notNull().default("prototype"), designSystemId: text("design_system_id"), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), ...ownableColumns(), }); export const designShares = createSharesTable("design_shares"); /** * Reusable starting points captured from a Design project. Template metadata * stays light enough for the gallery list; the full design data and file * contents load only when a template is instantiated. */ export const designTemplates = table("design_templates", { id: text("id").primaryKey(), title: text("title").notNull(), description: text("description"), category: text("category", { enum: [ "ad", "one-pager", "landing-page", "social", "presentation", "other", ], }) .notNull() .default("other"), sourceDesignId: text("source_design_id"), designSystemId: text("design_system_id"), data: text("data").notNull().default("{}"), width: integer("width"), height: integer("height"), lockedLayerCount: integer("locked_layer_count").notNull().default(0), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), ...ownableColumns(), }); export const designTemplateShares = createSharesTable("design_template_shares"); export const designTemplateFiles = table("design_template_files", { id: text("id").primaryKey(), templateId: text("template_id").notNull(), filename: text("filename").notNull(), content: text("content").notNull(), fileType: text("file_type").notNull().default("html"), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), }); export const designSystems = table("design_systems", { id: text("id").primaryKey(), title: text("title").notNull(), description: text("description"), data: text("data").notNull(), assets: text("assets"), customInstructions: text("custom_instructions").notNull().default(""), isDefault: integer("is_default", { mode: "boolean" }) .notNull() .default(false), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), ...ownableColumns(), }); export const designSystemShares = createSharesTable("design_system_shares"); export const designFiles = table("design_files", { id: text("id").primaryKey(), designId: text("design_id").notNull(), filename: text("filename").notNull(), content: text("content").notNull(), // Last accepted browser content-save operation. This transport metadata // stays beside (rather than inside) the document so a late unload // keepalive can be rejected without parsing or rewriting user content. contentOperationSource: text("content_operation_source"), contentOperationRevision: integer("content_operation_revision"), contentOperationResultHash: text("content_operation_result_hash"), fileType: text("file_type").notNull().default("html"), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), }); export const designVersions = table("design_versions", { id: text("id").primaryKey(), designId: text("design_id").notNull(), label: text("label"), snapshot: text("snapshot").notNull(), createdAt: text("created_at").default(now()), }); export const designLocalhostConnections = table( "design_localhost_connections", { id: text("id").primaryKey(), name: text("name").notNull(), sourceType: text("source_type", { enum: ["localhost"] }) .notNull() .default("localhost"), devServerUrl: text("dev_server_url").notNull(), bridgeUrl: text("bridge_url"), rootPath: text("root_path"), routeManifest: text("route_manifest").notNull().default("{}"), capabilities: text("capabilities").notNull().default("[]"), status: text("status", { enum: ["connected", "detected", "manual", "error"], }) .notNull() .default("connected"), lastSeenAt: text("last_seen_at"), /** Read-only credential used by browser preview/bridge-registration calls. * It is one-way derived from the filesystem token when not supplied by a * newer bridge, so leaking it cannot grant source-file access. */ previewToken: text("preview_token"), bridgeToken: text("bridge_token"), ownerEmail: text("owner_email").notNull(), orgId: text("org_id"), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), }, ); // --------------------------------------------------------------------------- // New tables — additive only; never alter existing tables. // All ownable tables are read/written through accessFilter / assertAccess. // --------------------------------------------------------------------------- /** * Real-app component metadata indexed from TS prop types, cva/tailwind-variants * variants, and Storybook stories. Scoped to one design + source ref. */ export const componentIndex = table("component_index", { id: text("id").primaryKey(), designId: text("design_id").notNull(), /** Opaque string identifying the source connection (localhost bridge id, fusion project id, etc.) */ sourceRef: text("source_ref"), name: text("name").notNull(), filePath: text("file_path"), exportName: text("export_name"), /** JSON: parsed prop types / cva variant definitions */ props: text("props"), /** JSON: variant groups (size, color, state, …) */ variants: text("variants"), /** JSON: Storybook stories referencing this component */ stories: text("stories"), /** JSON: runtime CSS selectors used to outline instances on the canvas */ runtimeSelectors: text("runtime_selectors"), createdAt: text("created_at").default(now()), updatedAt: text("updated_at").default(now()), ...ownableColumns(), }); /** * Motion timeline — scoped to one design + source ref + screen/file. * A design may have many timelines (one per screen or animation target). * The compiled CSS is the runtime truth; tracks JSON aids editing only. */ export const motionTimeline = table("motion_timeline", { id: text("id").primaryKey(), designId: text("design_id").notNull(), /** Opaque source connection ref; null for inline designs. */ sourceRef: text("source_ref"), /** File path for real-app CSS modules; null for inline (managed