// ─── Resource Definitions (what users write) ─── export interface CollectionResource { kind: 'collection' id?: number slug?: string name: string description?: string parent?: string // parent collection name, undefined = root } export interface NativeQuestionResource { kind: 'question' id?: number name: string collection: string database: string type: 'native' query: string templateTags?: Record display?: string visualizationSettings?: Record description?: string cardType?: 'model' | 'question' | 'metric' } export interface StructuredQuestionResource { kind: 'question' id?: number name: string collection: string database: string type: 'structured' query?: MBQLQuery datasetQuery?: Record // full dataset_query for MLv2/stages-based queries display?: string visualizationSettings?: Record description?: string cardType?: 'model' | 'question' | 'metric' } export type QuestionResource = NativeQuestionResource | StructuredQuestionResource export interface ParameterMapping { parameter_id: string card_id: number | null target: unknown[] [key: string]: unknown } export interface DashboardCardRef { question: string // question name questionId?: number width: number height: number row: number col: number parameterMappings?: ParameterMapping[] visualizationSettings?: Record } export interface DashboardTextCard { text: string width: number height: number row: number col: number parameterMappings?: ParameterMapping[] } export interface DashboardVirtualCard { virtualCard: Record width: number height: number row: number col: number visualizationSettings?: Record parameterMappings?: ParameterMapping[] } export interface DashboardParameter { name: string slug: string id: string type: string sectionId?: string default?: unknown [key: string]: unknown } export interface DashboardResource { kind: 'dashboard' id?: number name: string collection: string description?: string cards: (DashboardCardRef | DashboardTextCard | DashboardVirtualCard)[] parameters?: DashboardParameter[] } export interface SnippetResource { kind: 'snippet' id?: number name: string description?: string content: string } export type Resource = CollectionResource | QuestionResource | DashboardResource | SnippetResource // ─── MBQL (Metabase Query Language) ─── export interface MBQLQuery { 'source-table': string // "database.table" aggregation?: unknown[][] breakout?: unknown[][] filter?: unknown[] 'order-by'?: unknown[][] limit?: number } export interface TemplateTags { name: string 'display-name': string type: 'text' | 'number' | 'date' | 'dimension' default?: string } // ─── Builder functions ─── export const collection = (c: Omit): CollectionResource => ({ kind: 'collection', ...c, }) export const nativeQuestion = (q: Omit): NativeQuestionResource => ({ kind: 'question', type: 'native', ...q, }) export const structuredQuestion = ( q: Omit, ): StructuredQuestionResource => ({ kind: 'question', type: 'structured', ...q, }) export const dashboard = (d: Omit): DashboardResource => ({ kind: 'dashboard', ...d, }) export const snippet = (s: Omit): SnippetResource => ({ kind: 'snippet', ...s, }) // ─── Metabase API response types ─── export interface MetabaseSnippet { id: number name: string description: string | null content: string collection_id: number | null archived: boolean } export interface MetabaseCollection { id: number name: string description: string | null slug: string parent_id: number | null location: string archived: boolean } export interface MetabaseCard { id: number name: string description: string | null collection_id: number | null database_id: number type?: 'model' | 'question' | 'metric' dataset_query: { type: 'native' | 'query' database: number native?: { query: string; 'template-tags'?: Record } query?: Record } display: string visualization_settings: Record archived: boolean } export interface MetabaseDashboard { id: number name: string description: string | null collection_id: number | null parameters: DashboardParameter[] dashcards: MetabaseDashcard[] archived: boolean } export interface MetabaseDashcard { id: number card_id: number | null card?: MetabaseCard row: number col: number size_x: number size_y: number visualization_settings: Record parameter_mappings?: ParameterMapping[] series?: unknown[] } export interface MetabaseDatabase { id: number name: string engine: string tables?: MetabaseTable[] } export interface MetabaseTable { id: number name: string db_id: number fields?: MetabaseField[] } export interface MetabaseField { id: number name: string table_id: number } // ─── State file ─── export interface StateEntry { kind: Resource['kind'] name: string metabaseId: number collection?: string } export type StateFile = StateEntry[]