metabase-cli 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/metabase.js +44 -18
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config/store.ts","../src/client.ts","../src/safety/guard.ts","../src/api/session.ts","../src/utils/export.ts","../src/api/dataset.ts","../src/api/card.ts","../src/api/dashboard.ts","../src/api/collection.ts","../src/api/database.ts","../src/api/table.ts","../src/api/field.ts","../src/api/snippet.ts","../src/api/search.ts","../src/api/user.ts","../src/utils/output.ts"],"sourcesContent":["// Core\nexport { MetabaseClient } from \"./client.js\";\nexport { SafetyGuard } from \"./safety/guard.js\";\n\n// Config\nexport {\n loadConfig,\n saveConfig,\n getActiveProfile,\n setActiveProfile,\n addProfile,\n removeProfile,\n updateProfile,\n listProfiles,\n} from \"./config/store.js\";\n\n// API modules\nexport { SessionApi } from \"./api/session.js\";\nexport { DatasetApi } from \"./api/dataset.js\";\nexport { CardApi } from \"./api/card.js\";\nexport { DashboardApi } from \"./api/dashboard.js\";\nexport { CollectionApi } from \"./api/collection.js\";\nexport { DatabaseApi } from \"./api/database.js\";\nexport { TableApi } from \"./api/table.js\";\nexport { FieldApi } from \"./api/field.js\";\nexport { SnippetApi } from \"./api/snippet.js\";\nexport { SearchApi } from \"./api/search.js\";\nexport { UserApi } from \"./api/user.js\";\n\n// Types\nexport type * from \"./types.js\";\n\n// Utils\nexport { formatDatasetResponse, formatJson, formatEntityTable } from \"./utils/output.js\";\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport type { Config, Profile } from \"../types.js\";\n\nfunction getConfigDir(): string {\n return path.join(os.homedir(), \".metabase-cli\");\n}\n\nfunction getConfigFile(): string {\n return path.join(getConfigDir(), \"config.json\");\n}\n\nfunction ensureConfigDir(): void {\n if (!fs.existsSync(getConfigDir())) {\n fs.mkdirSync(getConfigDir(), { recursive: true, mode: 0o700 });\n }\n}\n\nfunction defaultConfig(): Config {\n return { activeProfile: \"\", profiles: {} };\n}\n\nexport function loadConfig(): Config {\n ensureConfigDir();\n if (!fs.existsSync(getConfigFile())) {\n return defaultConfig();\n }\n const raw = fs.readFileSync(getConfigFile(), \"utf-8\");\n return JSON.parse(raw) as Config;\n}\n\nexport function saveConfig(config: Config): void {\n ensureConfigDir();\n fs.writeFileSync(getConfigFile(), JSON.stringify(config, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function getActiveProfile(): Profile | null {\n const config = loadConfig();\n if (!config.activeProfile || !config.profiles[config.activeProfile]) {\n return null;\n }\n return config.profiles[config.activeProfile];\n}\n\nexport function setActiveProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.activeProfile = name;\n saveConfig(config);\n}\n\nexport function addProfile(profile: Profile): void {\n const config = loadConfig();\n config.profiles[profile.name] = profile;\n if (!config.activeProfile) {\n config.activeProfile = profile.name;\n }\n saveConfig(config);\n}\n\nexport function removeProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n delete config.profiles[name];\n if (config.activeProfile === name) {\n const remaining = Object.keys(config.profiles);\n config.activeProfile = remaining.length > 0 ? remaining[0] : \"\";\n }\n saveConfig(config);\n}\n\nexport function updateProfile(\n name: string,\n updates: Partial<Profile>,\n): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.profiles[name] = { ...config.profiles[name], ...updates };\n saveConfig(config);\n}\n\nexport function listProfiles(): { profiles: Profile[]; active: string } {\n const config = loadConfig();\n return {\n profiles: Object.values(config.profiles),\n active: config.activeProfile,\n };\n}\n","import type { Profile, SessionAuth, SessionResponse, User, CachedUser } from \"./types.js\";\nimport { updateProfile } from \"./config/store.js\";\n\nexport class MetabaseClient {\n private domain: string;\n private sessionToken?: string;\n private apiKey?: string;\n private profile: Profile;\n\n constructor(profile: Profile) {\n this.profile = profile;\n this.domain = profile.domain.replace(/\\/+$/, \"\");\n\n if (profile.auth.method === \"session\") {\n this.sessionToken = profile.auth.sessionToken;\n } else {\n this.apiKey = profile.auth.apiKey;\n }\n }\n\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return headers;\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<T> {\n let url = `${this.domain}${path}`;\n\n if (params) {\n const qs = new URLSearchParams(params).toString();\n url += `?${qs}`;\n }\n\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n const retryRes = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!retryRes.ok) {\n const err = await retryRes.text();\n throw new Error(`${retryRes.status} ${retryRes.statusText}: ${err}`);\n }\n const retryText = await retryRes.text();\n if (!retryText) return undefined as T;\n return JSON.parse(retryText) as T;\n }\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`${res.status} ${res.statusText}: ${err}`);\n }\n\n const text = await res.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>(\"GET\", path, undefined, params);\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n\n async requestFormExport(\n path: string,\n fields: Record<string, string>,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n\n const body = new URLSearchParams(fields);\n const res = await fetch(url, { method: \"POST\", headers, body });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return fetch(url, { method: \"POST\", headers, body: new URLSearchParams(fields) });\n }\n\n return res;\n }\n\n async requestRaw(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n return fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n return res;\n }\n\n async login(): Promise<SessionResponse> {\n const auth = this.profile.auth as SessionAuth;\n const res = await fetch(`${this.domain}/api/session`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ username: auth.email, password: auth.password }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Login failed: ${res.status} ${err}`);\n }\n\n const session = (await res.json()) as SessionResponse;\n this.sessionToken = session.id;\n\n // Cache session token in profile\n updateProfile(this.profile.name, {\n auth: { ...auth, sessionToken: session.id },\n });\n\n // Fetch and cache user info\n const user = await this.get<User>(\"/api/user/current\");\n const cachedUser: CachedUser = {\n id: user.id,\n email: user.email,\n first_name: user.first_name,\n last_name: user.last_name,\n is_superuser: user.is_superuser,\n };\n updateProfile(this.profile.name, { user: cachedUser });\n this.profile.user = cachedUser;\n\n return session;\n }\n\n async logout(): Promise<void> {\n await this.delete(\"/api/session\");\n this.sessionToken = undefined;\n if (this.profile.auth.method === \"session\") {\n updateProfile(this.profile.name, {\n auth: { ...this.profile.auth, sessionToken: undefined },\n });\n }\n }\n\n async ensureAuthenticated(): Promise<void> {\n if (this.apiKey) return;\n if (!this.sessionToken) {\n await this.login();\n }\n }\n\n getProfile(): Profile {\n return this.profile;\n }\n\n getUserId(): number | null {\n return this.profile.user?.id ?? null;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\n\ninterface OwnedEntity {\n creator_id: number;\n [key: string]: unknown;\n}\n\nexport class SafetyGuard {\n private client: MetabaseClient;\n private unsafe: boolean;\n\n constructor(client: MetabaseClient, unsafe = false) {\n this.client = client;\n this.unsafe = unsafe;\n }\n\n async checkOwnership(entityType: string, entityId: number): Promise<{ owned: boolean; creatorId: number }> {\n const pathMap: Record<string, string> = {\n card: `/api/card/${entityId}`,\n dashboard: `/api/dashboard/${entityId}`,\n snippet: `/api/native-query-snippet/${entityId}`,\n collection: `/api/collection/${entityId}`,\n };\n\n const path = pathMap[entityType];\n if (!path) {\n throw new Error(`Unknown entity type: ${entityType}`);\n }\n\n const entity = await this.client.get<OwnedEntity>(path);\n const userId = this.client.getUserId();\n\n if (userId === null) {\n throw new Error(\"No cached user ID. Run 'metabase-cli login' or 'metabase-cli whoami --refresh' first.\");\n }\n\n return {\n owned: entity.creator_id === userId,\n creatorId: entity.creator_id,\n };\n }\n\n async guard<T>(\n entityType: string,\n entityId: number,\n action: string,\n fn: () => Promise<T>,\n ): Promise<T> {\n if (this.unsafe) {\n return fn();\n }\n\n const { owned, creatorId } = await this.checkOwnership(entityType, entityId);\n\n if (!owned) {\n const userId = this.client.getUserId();\n throw new Error(\n `Safe mode: Cannot ${action} ${entityType} #${entityId} — ` +\n `owned by user #${creatorId}, you are user #${userId}. ` +\n `Use --unsafe to bypass.`,\n );\n }\n\n return fn();\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User } from \"../types.js\";\n\nexport class SessionApi {\n constructor(private client: MetabaseClient) {}\n\n async getCurrentUser(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n\n async getSessionProperties(): Promise<Record<string, unknown>> {\n return this.client.get(\"/api/session/properties\");\n }\n}\n","/**\n * Checks if an export response body is actually a JSON error from Metabase.\n * Metabase streaming export endpoints may return 200 with a JSON error body\n * instead of the expected format (CSV/XLSX).\n */\nexport function checkExportError(buf: Buffer, format: string): void {\n // For non-JSON formats, if the response starts with '{' it's likely a JSON error body\n if (format !== \"json\" && buf.length > 0 && buf[0] === 0x7b) {\n try {\n const parsed = JSON.parse(buf.toString(\"utf-8\"));\n if (parsed.status === \"failed\" || parsed.error) {\n throw new Error(`Query failed: ${parsed.error || \"unknown error\"}`);\n }\n } catch (e: any) {\n if (e.message.startsWith(\"Query failed:\")) throw e;\n }\n }\n}\n\n/** Map file extensions to export format identifiers */\nexport const EXT_TO_FORMAT: Record<string, string> = {\n \".csv\": \"csv\",\n \".tsv\": \"tsv\",\n \".json\": \"json\",\n \".xlsx\": \"xlsx\",\n};\n","import type { MetabaseClient } from \"../client.js\";\nimport type { DatasetQuery, DatasetResponse } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport class DatasetApi {\n constructor(private client: MetabaseClient) {}\n\n async query(datasetQuery: DatasetQuery): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(\"/api/dataset\", datasetQuery);\n }\n\n async queryNative(\n database: number,\n sql: string,\n templateTags?: Record<string, unknown>,\n ): Promise<DatasetResponse> {\n return this.query({\n type: \"native\",\n database,\n native: {\n query: sql,\n \"template-tags\": templateTags ?? {},\n },\n });\n }\n\n async export(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/dataset/${format}`,\n datasetQuery,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async exportBinary(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<Buffer> {\n const res = await this.client.requestFormExport(\n `/api/dataset/${format}`,\n { query: JSON.stringify(datasetQuery) },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Card, DatasetResponse, DatasetQuery } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport interface CreateCardParams {\n name: string;\n dataset_query: DatasetQuery;\n display: string;\n description?: string;\n collection_id?: number;\n visualization_settings?: Record<string, unknown>;\n parameters?: unknown[];\n}\n\nexport interface UpdateCardParams {\n name?: string;\n description?: string;\n parameters?: unknown[];\n collection_id?: number;\n dataset_query?: DatasetQuery;\n display?: string;\n visualization_settings?: Record<string, unknown>;\n archived?: boolean;\n}\n\nexport class CardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Card[]> {\n return this.client.get<Card[]>(\"/api/card\", params);\n }\n\n async get(id: number): Promise<Card> {\n return this.client.get<Card>(`/api/card/${id}`);\n }\n\n async create(params: CreateCardParams): Promise<Card> {\n return this.client.post<Card>(\"/api/card\", params);\n }\n\n async update(id: number, params: UpdateCardParams): Promise<Card> {\n return this.client.put<Card>(`/api/card/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/card/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateCardParams>): Promise<Card> {\n return this.client.post<Card>(`/api/card/${id}/copy`, overrides);\n }\n\n async query(id: number, parameters?: unknown[]): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(`/api/card/${id}/query`, {\n parameters: parameters ?? [],\n });\n }\n\n async queryExport(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/card/${id}/query/${format}`,\n { parameters: parameters ?? [] },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async queryExportBinary(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<Buffer> {\n const fields: Record<string, string> = {};\n if (parameters && parameters.length > 0) {\n fields.parameters = JSON.stringify(parameters);\n }\n const res = await this.client.requestFormExport(\n `/api/card/${id}/query/${format}`,\n fields,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Dashboard } from \"../types.js\";\n\nexport interface CreateDashboardParams {\n name: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n}\n\nexport interface UpdateDashboardParams {\n name?: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n dashcards?: unknown[];\n archived?: boolean;\n}\n\nexport class DashboardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Dashboard[]> {\n return this.client.get<Dashboard[]>(\"/api/dashboard\", params);\n }\n\n async get(id: number): Promise<Dashboard> {\n return this.client.get<Dashboard>(`/api/dashboard/${id}`);\n }\n\n async create(params: CreateDashboardParams): Promise<Dashboard> {\n return this.client.post<Dashboard>(\"/api/dashboard\", params);\n }\n\n async update(id: number, params: UpdateDashboardParams): Promise<Dashboard> {\n return this.client.put<Dashboard>(`/api/dashboard/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/dashboard/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateDashboardParams>): Promise<Dashboard> {\n return this.client.post<Dashboard>(`/api/dashboard/${id}/copy`, overrides);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Collection } from \"../types.js\";\n\nexport interface CreateCollectionParams {\n name: string;\n description?: string;\n parent_id?: number;\n}\n\nexport interface UpdateCollectionParams {\n name?: string;\n description?: string;\n parent_id?: number;\n archived?: boolean;\n}\n\nexport interface CollectionItem {\n id: number;\n name: string;\n model: string;\n description: string | null;\n [key: string]: unknown;\n}\n\nexport class CollectionApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection\");\n }\n\n async tree(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection/tree\");\n }\n\n async get(id: number | \"root\"): Promise<Collection> {\n return this.client.get<Collection>(`/api/collection/${id}`);\n }\n\n async items(\n id: number | \"root\",\n params?: Record<string, string>,\n ): Promise<{ data: CollectionItem[]; total: number }> {\n return this.client.get(`/api/collection/${id}/items`, params);\n }\n\n async create(params: CreateCollectionParams): Promise<Collection> {\n return this.client.post<Collection>(\"/api/collection\", params);\n }\n\n async update(id: number, params: UpdateCollectionParams): Promise<Collection> {\n return this.client.put<Collection>(`/api/collection/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Database, Table } from \"../types.js\";\n\nexport class DatabaseApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<{ data: Database[] }> {\n return this.client.get(\"/api/database\");\n }\n\n async get(id: number): Promise<Database> {\n return this.client.get<Database>(`/api/database/${id}`);\n }\n\n async metadata(id: number): Promise<Database & { tables: Table[] }> {\n return this.client.get(`/api/database/${id}/metadata`);\n }\n\n async schemas(id: number): Promise<string[]> {\n return this.client.get<string[]>(`/api/database/${id}/schemas`);\n }\n\n async tablesInSchema(id: number, schema: string): Promise<Table[]> {\n return this.client.get<Table[]>(\n `/api/database/${id}/schema/${encodeURIComponent(schema)}`,\n );\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Table, Field } from \"../types.js\";\n\nexport class TableApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Table> {\n return this.client.get<Table>(`/api/table/${id}`);\n }\n\n async queryMetadata(id: number): Promise<Table & { fields: Field[] }> {\n return this.client.get(`/api/table/${id}/query_metadata`);\n }\n\n async foreignKeys(id: number): Promise<unknown[]> {\n return this.client.get(`/api/table/${id}/fks`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Field } from \"../types.js\";\n\nexport class FieldApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Field> {\n return this.client.get<Field>(`/api/field/${id}`);\n }\n\n async values(id: number): Promise<{ values: unknown[][] }> {\n return this.client.get(`/api/field/${id}/values`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Snippet } from \"../types.js\";\n\nexport interface CreateSnippetParams {\n name: string;\n content: string;\n description?: string;\n collection_id?: number;\n}\n\nexport interface UpdateSnippetParams {\n name?: string;\n content?: string;\n description?: string;\n collection_id?: number;\n archived?: boolean;\n}\n\nexport class SnippetApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Snippet[]> {\n return this.client.get<Snippet[]>(\"/api/native-query-snippet\", params);\n }\n\n async get(id: number): Promise<Snippet> {\n return this.client.get<Snippet>(`/api/native-query-snippet/${id}`);\n }\n\n async create(params: CreateSnippetParams): Promise<Snippet> {\n return this.client.post<Snippet>(\"/api/native-query-snippet\", params);\n }\n\n async update(id: number, params: UpdateSnippetParams): Promise<Snippet> {\n return this.client.put<Snippet>(`/api/native-query-snippet/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { SearchResult, PaginatedResponse } from \"../types.js\";\n\nexport class SearchApi {\n constructor(private client: MetabaseClient) {}\n\n async search(\n query: string,\n params?: {\n models?: string[];\n limit?: number;\n offset?: number;\n },\n ): Promise<PaginatedResponse<SearchResult>> {\n const qs: Record<string, string> = { q: query };\n if (params?.models?.length) {\n qs.models = params.models.join(\",\");\n }\n if (params?.limit !== undefined) qs.limit = String(params.limit);\n if (params?.offset !== undefined) qs.offset = String(params.offset);\n\n return this.client.get(\"/api/search\", qs);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User, PaginatedResponse } from \"../types.js\";\n\nexport class UserApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<PaginatedResponse<User>> {\n return this.client.get(\"/api/user\", params);\n }\n\n async get(id: number): Promise<User> {\n return this.client.get<User>(`/api/user/${id}`);\n }\n\n async current(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n}\n","import Table from \"cli-table3\";\nimport type { DatasetResponse, OutputFormat } from \"../types.js\";\n\nexport function formatDatasetResponse(\n dataset: DatasetResponse,\n format: OutputFormat = \"table\",\n columns?: string[],\n): string {\n const cols = dataset.data.cols;\n const rows = dataset.data.rows;\n\n // Filter columns if specified\n let colIndices: number[];\n if (columns?.length) {\n colIndices = columns.map((name) => {\n const idx = cols.findIndex(\n (c) => c.name === name || c.display_name === name,\n );\n if (idx === -1) throw new Error(`Column \"${name}\" not found`);\n return idx;\n });\n } else {\n colIndices = cols.map((_, i) => i);\n }\n\n const filteredCols = colIndices.map((i) => cols[i]);\n const filteredRows = rows.map((row) => colIndices.map((i) => row[i]));\n\n switch (format) {\n case \"json\":\n return JSON.stringify(\n filteredRows.map((row) =>\n Object.fromEntries(\n filteredCols.map((col, i) => [col.name, row[i]]),\n ),\n ),\n null,\n 2,\n );\n\n case \"csv\":\n return formatDelimited(filteredCols, filteredRows, \",\");\n\n case \"tsv\":\n return formatDelimited(filteredCols, filteredRows, \"\\t\");\n\n case \"table\":\n default:\n return formatTable(filteredCols, filteredRows);\n }\n}\n\nfunction formatDelimited(\n cols: { name: string }[],\n rows: unknown[][],\n delimiter: string,\n): string {\n const header = cols.map((c) => escapeCsvField(String(c.name), delimiter)).join(delimiter);\n const body = rows.map((row) =>\n row.map((cell) => escapeCsvField(formatCell(cell), delimiter)).join(delimiter),\n );\n return [header, ...body].join(\"\\n\");\n}\n\nfunction escapeCsvField(value: string, delimiter: string): string {\n if (value.includes(delimiter) || value.includes('\"') || value.includes(\"\\n\")) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nfunction formatTable(cols: { display_name: string }[], rows: unknown[][]): string {\n const table = new Table({\n head: cols.map((c) => c.display_name),\n style: { head: [\"cyan\"] },\n });\n\n for (const row of rows) {\n table.push(row.map((cell) => formatCell(cell)));\n }\n\n return table.toString();\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\nexport function formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nexport function formatEntityTable(\n items: Record<string, unknown>[],\n columns: { key: string; header: string }[],\n): string {\n const table = new Table({\n head: columns.map((c) => c.header),\n style: { head: [\"cyan\"] },\n });\n\n for (const item of items) {\n table.push(columns.map((c) => formatCell(item[c.key])));\n }\n\n return table.toString();\n}\n"],"mappings":"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","names":["path","path","Table"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config/store.ts","../src/client.ts","../src/safety/guard.ts","../src/api/session.ts","../src/utils/export.ts","../src/api/dataset.ts","../src/api/card.ts","../src/api/dashboard.ts","../src/api/collection.ts","../src/api/database.ts","../src/api/table.ts","../src/api/field.ts","../src/api/snippet.ts","../src/api/search.ts","../src/api/user.ts","../src/utils/output.ts"],"sourcesContent":["// Core\nexport { MetabaseClient } from \"./client.js\";\nexport { SafetyGuard } from \"./safety/guard.js\";\n\n// Config\nexport {\n loadConfig,\n saveConfig,\n getActiveProfile,\n setActiveProfile,\n addProfile,\n removeProfile,\n updateProfile,\n listProfiles,\n} from \"./config/store.js\";\n\n// API modules\nexport { SessionApi } from \"./api/session.js\";\nexport { DatasetApi } from \"./api/dataset.js\";\nexport { CardApi } from \"./api/card.js\";\nexport { DashboardApi } from \"./api/dashboard.js\";\nexport { CollectionApi } from \"./api/collection.js\";\nexport { DatabaseApi } from \"./api/database.js\";\nexport { TableApi } from \"./api/table.js\";\nexport { FieldApi } from \"./api/field.js\";\nexport { SnippetApi } from \"./api/snippet.js\";\nexport { SearchApi } from \"./api/search.js\";\nexport { UserApi } from \"./api/user.js\";\n\n// Types\nexport type * from \"./types.js\";\n\n// Utils\nexport { formatDatasetResponse, formatJson, formatEntityTable } from \"./utils/output.js\";\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport type { Config, Profile } from \"../types.js\";\n\nfunction getConfigDir(): string {\n return path.join(os.homedir(), \".metabase-cli\");\n}\n\nfunction getConfigFile(): string {\n return path.join(getConfigDir(), \"config.json\");\n}\n\nfunction ensureConfigDir(): void {\n if (!fs.existsSync(getConfigDir())) {\n fs.mkdirSync(getConfigDir(), { recursive: true, mode: 0o700 });\n }\n}\n\nfunction defaultConfig(): Config {\n return { activeProfile: \"\", profiles: {} };\n}\n\nexport function loadConfig(): Config {\n ensureConfigDir();\n if (!fs.existsSync(getConfigFile())) {\n return defaultConfig();\n }\n const raw = fs.readFileSync(getConfigFile(), \"utf-8\");\n return JSON.parse(raw) as Config;\n}\n\nexport function saveConfig(config: Config): void {\n ensureConfigDir();\n fs.writeFileSync(getConfigFile(), JSON.stringify(config, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function getActiveProfile(): Profile | null {\n const config = loadConfig();\n if (!config.activeProfile || !config.profiles[config.activeProfile]) {\n return null;\n }\n return config.profiles[config.activeProfile];\n}\n\nexport function setActiveProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.activeProfile = name;\n saveConfig(config);\n}\n\nexport function addProfile(profile: Profile): void {\n const config = loadConfig();\n config.profiles[profile.name] = profile;\n if (!config.activeProfile) {\n config.activeProfile = profile.name;\n }\n saveConfig(config);\n}\n\nexport function removeProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n delete config.profiles[name];\n if (config.activeProfile === name) {\n const remaining = Object.keys(config.profiles);\n config.activeProfile = remaining.length > 0 ? remaining[0] : \"\";\n }\n saveConfig(config);\n}\n\nexport function updateProfile(\n name: string,\n updates: Partial<Profile>,\n): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.profiles[name] = { ...config.profiles[name], ...updates };\n saveConfig(config);\n}\n\nexport function getProfile(name: string): Profile | null {\n const config = loadConfig();\n return config.profiles[name] ?? null;\n}\n\nexport function listProfiles(): { profiles: Profile[]; active: string } {\n const config = loadConfig();\n return {\n profiles: Object.values(config.profiles),\n active: config.activeProfile,\n };\n}\n","import type { Profile, SessionAuth, SessionResponse, User, CachedUser } from \"./types.js\";\nimport { updateProfile } from \"./config/store.js\";\n\nexport class MetabaseClient {\n private domain: string;\n private sessionToken?: string;\n private apiKey?: string;\n private profile: Profile;\n\n constructor(profile: Profile) {\n this.profile = profile;\n this.domain = profile.domain.replace(/\\/+$/, \"\");\n\n if (profile.auth.method === \"session\") {\n this.sessionToken = profile.auth.sessionToken;\n } else {\n this.apiKey = profile.auth.apiKey;\n }\n }\n\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return headers;\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<T> {\n let url = `${this.domain}${path}`;\n\n if (params) {\n const qs = new URLSearchParams(params).toString();\n url += `?${qs}`;\n }\n\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n const retryRes = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!retryRes.ok) {\n const err = await retryRes.text();\n throw new Error(`${retryRes.status} ${retryRes.statusText}: ${err}`);\n }\n const retryText = await retryRes.text();\n if (!retryText) return undefined as T;\n return JSON.parse(retryText) as T;\n }\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`${res.status} ${res.statusText}: ${err}`);\n }\n\n const text = await res.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>(\"GET\", path, undefined, params);\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n\n async requestFormExport(\n path: string,\n fields: Record<string, string>,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n\n const body = new URLSearchParams(fields);\n const res = await fetch(url, { method: \"POST\", headers, body });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return fetch(url, { method: \"POST\", headers, body: new URLSearchParams(fields) });\n }\n\n return res;\n }\n\n async requestRaw(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n return fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n return res;\n }\n\n async login(): Promise<SessionResponse> {\n const auth = this.profile.auth as SessionAuth;\n const res = await fetch(`${this.domain}/api/session`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ username: auth.email, password: auth.password }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Login failed: ${res.status} ${err}`);\n }\n\n const session = (await res.json()) as SessionResponse;\n this.sessionToken = session.id;\n\n // Cache session token in profile\n updateProfile(this.profile.name, {\n auth: { ...auth, sessionToken: session.id },\n });\n\n // Fetch and cache user info\n const user = await this.get<User>(\"/api/user/current\");\n const cachedUser: CachedUser = {\n id: user.id,\n email: user.email,\n first_name: user.first_name,\n last_name: user.last_name,\n is_superuser: user.is_superuser,\n };\n updateProfile(this.profile.name, { user: cachedUser });\n this.profile.user = cachedUser;\n\n return session;\n }\n\n async logout(): Promise<void> {\n await this.delete(\"/api/session\");\n this.sessionToken = undefined;\n if (this.profile.auth.method === \"session\") {\n updateProfile(this.profile.name, {\n auth: { ...this.profile.auth, sessionToken: undefined },\n });\n }\n }\n\n async ensureAuthenticated(): Promise<void> {\n if (this.apiKey) return;\n if (!this.sessionToken) {\n await this.login();\n }\n }\n\n getProfile(): Profile {\n return this.profile;\n }\n\n getUserId(): number | null {\n return this.profile.user?.id ?? null;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\n\ninterface OwnedEntity {\n creator_id: number;\n [key: string]: unknown;\n}\n\nexport class SafetyGuard {\n private client: MetabaseClient;\n private unsafe: boolean;\n\n constructor(client: MetabaseClient, unsafe = false) {\n this.client = client;\n this.unsafe = unsafe;\n }\n\n async checkOwnership(entityType: string, entityId: number): Promise<{ owned: boolean; creatorId: number }> {\n const pathMap: Record<string, string> = {\n card: `/api/card/${entityId}`,\n dashboard: `/api/dashboard/${entityId}`,\n snippet: `/api/native-query-snippet/${entityId}`,\n collection: `/api/collection/${entityId}`,\n };\n\n const path = pathMap[entityType];\n if (!path) {\n throw new Error(`Unknown entity type: ${entityType}`);\n }\n\n const entity = await this.client.get<OwnedEntity>(path);\n const userId = this.client.getUserId();\n\n if (userId === null) {\n throw new Error(\"No cached user ID. Run 'metabase-cli login' or 'metabase-cli whoami --refresh' first.\");\n }\n\n return {\n owned: entity.creator_id === userId,\n creatorId: entity.creator_id,\n };\n }\n\n async guard<T>(\n entityType: string,\n entityId: number,\n action: string,\n fn: () => Promise<T>,\n ): Promise<T> {\n if (this.unsafe) {\n return fn();\n }\n\n const { owned, creatorId } = await this.checkOwnership(entityType, entityId);\n\n if (!owned) {\n const userId = this.client.getUserId();\n throw new Error(\n `Safe mode: Cannot ${action} ${entityType} #${entityId} — ` +\n `owned by user #${creatorId}, you are user #${userId}. ` +\n `Use --unsafe to bypass.`,\n );\n }\n\n return fn();\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User } from \"../types.js\";\n\nexport class SessionApi {\n constructor(private client: MetabaseClient) {}\n\n async getCurrentUser(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n\n async getSessionProperties(): Promise<Record<string, unknown>> {\n return this.client.get(\"/api/session/properties\");\n }\n}\n","/**\n * Checks if an export response body is actually a JSON error from Metabase.\n * Metabase streaming export endpoints may return 200 with a JSON error body\n * instead of the expected format (CSV/XLSX).\n */\nexport function checkExportError(buf: Buffer, format: string): void {\n // For non-JSON formats, if the response starts with '{' it's likely a JSON error body\n if (format !== \"json\" && buf.length > 0 && buf[0] === 0x7b) {\n try {\n const parsed = JSON.parse(buf.toString(\"utf-8\"));\n if (parsed.status === \"failed\" || parsed.error) {\n throw new Error(`Query failed: ${parsed.error || \"unknown error\"}`);\n }\n } catch (e: any) {\n if (e.message.startsWith(\"Query failed:\")) throw e;\n }\n }\n}\n\n/** Map file extensions to export format identifiers */\nexport const EXT_TO_FORMAT: Record<string, string> = {\n \".csv\": \"csv\",\n \".tsv\": \"tsv\",\n \".json\": \"json\",\n \".xlsx\": \"xlsx\",\n};\n","import type { MetabaseClient } from \"../client.js\";\nimport type { DatasetQuery, DatasetResponse } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport class DatasetApi {\n constructor(private client: MetabaseClient) {}\n\n async query(datasetQuery: DatasetQuery): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(\"/api/dataset\", datasetQuery);\n }\n\n async queryNative(\n database: number,\n sql: string,\n templateTags?: Record<string, unknown>,\n ): Promise<DatasetResponse> {\n return this.query({\n type: \"native\",\n database,\n native: {\n query: sql,\n \"template-tags\": templateTags ?? {},\n },\n });\n }\n\n async export(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/dataset/${format}`,\n datasetQuery,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async exportBinary(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<Buffer> {\n const res = await this.client.requestFormExport(\n `/api/dataset/${format}`,\n { query: JSON.stringify(datasetQuery) },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Card, DatasetResponse, DatasetQuery } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport interface CreateCardParams {\n name: string;\n dataset_query: DatasetQuery;\n display: string;\n description?: string;\n collection_id?: number;\n visualization_settings?: Record<string, unknown>;\n parameters?: unknown[];\n}\n\nexport interface UpdateCardParams {\n name?: string;\n description?: string;\n parameters?: unknown[];\n collection_id?: number;\n dataset_query?: DatasetQuery;\n display?: string;\n visualization_settings?: Record<string, unknown>;\n archived?: boolean;\n}\n\nexport class CardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Card[]> {\n return this.client.get<Card[]>(\"/api/card\", params);\n }\n\n async get(id: number): Promise<Card> {\n return this.client.get<Card>(`/api/card/${id}`);\n }\n\n async create(params: CreateCardParams): Promise<Card> {\n return this.client.post<Card>(\"/api/card\", params);\n }\n\n async update(id: number, params: UpdateCardParams): Promise<Card> {\n return this.client.put<Card>(`/api/card/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/card/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateCardParams>): Promise<Card> {\n return this.client.post<Card>(`/api/card/${id}/copy`, overrides);\n }\n\n async query(id: number, parameters?: unknown[]): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(`/api/card/${id}/query`, {\n parameters: parameters ?? [],\n });\n }\n\n async queryExport(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/card/${id}/query/${format}`,\n { parameters: parameters ?? [] },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async queryExportBinary(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<Buffer> {\n const fields: Record<string, string> = {};\n if (parameters && parameters.length > 0) {\n fields.parameters = JSON.stringify(parameters);\n }\n const res = await this.client.requestFormExport(\n `/api/card/${id}/query/${format}`,\n fields,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Dashboard } from \"../types.js\";\n\nexport interface CreateDashboardParams {\n name: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n}\n\nexport interface UpdateDashboardParams {\n name?: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n dashcards?: unknown[];\n archived?: boolean;\n}\n\nexport class DashboardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Dashboard[]> {\n return this.client.get<Dashboard[]>(\"/api/dashboard\", params);\n }\n\n async get(id: number): Promise<Dashboard> {\n return this.client.get<Dashboard>(`/api/dashboard/${id}`);\n }\n\n async create(params: CreateDashboardParams): Promise<Dashboard> {\n return this.client.post<Dashboard>(\"/api/dashboard\", params);\n }\n\n async update(id: number, params: UpdateDashboardParams): Promise<Dashboard> {\n return this.client.put<Dashboard>(`/api/dashboard/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/dashboard/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateDashboardParams>): Promise<Dashboard> {\n return this.client.post<Dashboard>(`/api/dashboard/${id}/copy`, overrides);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Collection } from \"../types.js\";\n\nexport interface CreateCollectionParams {\n name: string;\n description?: string;\n parent_id?: number;\n}\n\nexport interface UpdateCollectionParams {\n name?: string;\n description?: string;\n parent_id?: number;\n archived?: boolean;\n}\n\nexport interface CollectionItem {\n id: number;\n name: string;\n model: string;\n description: string | null;\n [key: string]: unknown;\n}\n\nexport class CollectionApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection\");\n }\n\n async tree(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection/tree\");\n }\n\n async get(id: number | \"root\"): Promise<Collection> {\n return this.client.get<Collection>(`/api/collection/${id}`);\n }\n\n async items(\n id: number | \"root\",\n params?: Record<string, string>,\n ): Promise<{ data: CollectionItem[]; total: number }> {\n return this.client.get(`/api/collection/${id}/items`, params);\n }\n\n async create(params: CreateCollectionParams): Promise<Collection> {\n return this.client.post<Collection>(\"/api/collection\", params);\n }\n\n async update(id: number, params: UpdateCollectionParams): Promise<Collection> {\n return this.client.put<Collection>(`/api/collection/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Database, Table } from \"../types.js\";\n\nexport class DatabaseApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<{ data: Database[] }> {\n return this.client.get(\"/api/database\");\n }\n\n async get(id: number): Promise<Database> {\n return this.client.get<Database>(`/api/database/${id}`);\n }\n\n async metadata(id: number): Promise<Database & { tables: Table[] }> {\n return this.client.get(`/api/database/${id}/metadata`);\n }\n\n async schemas(id: number): Promise<string[]> {\n return this.client.get<string[]>(`/api/database/${id}/schemas`);\n }\n\n async tablesInSchema(id: number, schema: string): Promise<Table[]> {\n return this.client.get<Table[]>(\n `/api/database/${id}/schema/${encodeURIComponent(schema)}`,\n );\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Table, Field } from \"../types.js\";\n\nexport class TableApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Table> {\n return this.client.get<Table>(`/api/table/${id}`);\n }\n\n async queryMetadata(id: number): Promise<Table & { fields: Field[] }> {\n return this.client.get(`/api/table/${id}/query_metadata`);\n }\n\n async foreignKeys(id: number): Promise<unknown[]> {\n return this.client.get(`/api/table/${id}/fks`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Field } from \"../types.js\";\n\nexport class FieldApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Field> {\n return this.client.get<Field>(`/api/field/${id}`);\n }\n\n async values(id: number): Promise<{ values: unknown[][] }> {\n return this.client.get(`/api/field/${id}/values`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Snippet } from \"../types.js\";\n\nexport interface CreateSnippetParams {\n name: string;\n content: string;\n description?: string;\n collection_id?: number;\n}\n\nexport interface UpdateSnippetParams {\n name?: string;\n content?: string;\n description?: string;\n collection_id?: number;\n archived?: boolean;\n}\n\nexport class SnippetApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Snippet[]> {\n return this.client.get<Snippet[]>(\"/api/native-query-snippet\", params);\n }\n\n async get(id: number): Promise<Snippet> {\n return this.client.get<Snippet>(`/api/native-query-snippet/${id}`);\n }\n\n async create(params: CreateSnippetParams): Promise<Snippet> {\n return this.client.post<Snippet>(\"/api/native-query-snippet\", params);\n }\n\n async update(id: number, params: UpdateSnippetParams): Promise<Snippet> {\n return this.client.put<Snippet>(`/api/native-query-snippet/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { SearchResult, PaginatedResponse } from \"../types.js\";\n\nexport class SearchApi {\n constructor(private client: MetabaseClient) {}\n\n async search(\n query: string,\n params?: {\n models?: string[];\n limit?: number;\n offset?: number;\n },\n ): Promise<PaginatedResponse<SearchResult>> {\n const qs: Record<string, string> = { q: query };\n if (params?.models?.length) {\n qs.models = params.models.join(\",\");\n }\n if (params?.limit !== undefined) qs.limit = String(params.limit);\n if (params?.offset !== undefined) qs.offset = String(params.offset);\n\n return this.client.get(\"/api/search\", qs);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User, PaginatedResponse } from \"../types.js\";\n\nexport class UserApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<PaginatedResponse<User>> {\n return this.client.get(\"/api/user\", params);\n }\n\n async get(id: number): Promise<User> {\n return this.client.get<User>(`/api/user/${id}`);\n }\n\n async current(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n}\n","import Table from \"cli-table3\";\nimport type { DatasetResponse, OutputFormat } from \"../types.js\";\n\nexport function formatDatasetResponse(\n dataset: DatasetResponse,\n format: OutputFormat = \"table\",\n columns?: string[],\n): string {\n const cols = dataset.data.cols;\n const rows = dataset.data.rows;\n\n // Filter columns if specified\n let colIndices: number[];\n if (columns?.length) {\n colIndices = columns.map((name) => {\n const idx = cols.findIndex(\n (c) => c.name === name || c.display_name === name,\n );\n if (idx === -1) throw new Error(`Column \"${name}\" not found`);\n return idx;\n });\n } else {\n colIndices = cols.map((_, i) => i);\n }\n\n const filteredCols = colIndices.map((i) => cols[i]);\n const filteredRows = rows.map((row) => colIndices.map((i) => row[i]));\n\n switch (format) {\n case \"json\":\n return JSON.stringify(\n filteredRows.map((row) =>\n Object.fromEntries(\n filteredCols.map((col, i) => [col.name, row[i]]),\n ),\n ),\n null,\n 2,\n );\n\n case \"csv\":\n return formatDelimited(filteredCols, filteredRows, \",\");\n\n case \"tsv\":\n return formatDelimited(filteredCols, filteredRows, \"\\t\");\n\n case \"table\":\n default:\n return formatTable(filteredCols, filteredRows);\n }\n}\n\nfunction formatDelimited(\n cols: { name: string }[],\n rows: unknown[][],\n delimiter: string,\n): string {\n const header = cols.map((c) => escapeCsvField(String(c.name), delimiter)).join(delimiter);\n const body = rows.map((row) =>\n row.map((cell) => escapeCsvField(formatCell(cell), delimiter)).join(delimiter),\n );\n return [header, ...body].join(\"\\n\");\n}\n\nfunction escapeCsvField(value: string, delimiter: string): string {\n if (value.includes(delimiter) || value.includes('\"') || value.includes(\"\\n\")) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nfunction formatTable(cols: { display_name: string }[], rows: unknown[][]): string {\n const table = new Table({\n head: cols.map((c) => c.display_name),\n style: { head: [\"cyan\"] },\n });\n\n for (const row of rows) {\n table.push(row.map((cell) => formatCell(cell)));\n }\n\n return table.toString();\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\nexport function formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nexport function formatEntityTable(\n items: Record<string, unknown>[],\n columns: { key: string; header: string }[],\n): string {\n const table = new Table({\n head: columns.map((c) => c.header),\n style: { head: [\"cyan\"] },\n });\n\n for (const item of items) {\n table.push(columns.map((c) => formatCell(item[c.key])));\n }\n\n return table.toString();\n}\n"],"mappings":"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","names":["path","path","Table"]}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/store.ts","../src/client.ts","../src/safety/guard.ts","../src/api/session.ts","../src/utils/export.ts","../src/api/dataset.ts","../src/api/card.ts","../src/api/dashboard.ts","../src/api/collection.ts","../src/api/database.ts","../src/api/table.ts","../src/api/field.ts","../src/api/snippet.ts","../src/api/search.ts","../src/api/user.ts","../src/utils/output.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport type { Config, Profile } from \"../types.js\";\n\nfunction getConfigDir(): string {\n return path.join(os.homedir(), \".metabase-cli\");\n}\n\nfunction getConfigFile(): string {\n return path.join(getConfigDir(), \"config.json\");\n}\n\nfunction ensureConfigDir(): void {\n if (!fs.existsSync(getConfigDir())) {\n fs.mkdirSync(getConfigDir(), { recursive: true, mode: 0o700 });\n }\n}\n\nfunction defaultConfig(): Config {\n return { activeProfile: \"\", profiles: {} };\n}\n\nexport function loadConfig(): Config {\n ensureConfigDir();\n if (!fs.existsSync(getConfigFile())) {\n return defaultConfig();\n }\n const raw = fs.readFileSync(getConfigFile(), \"utf-8\");\n return JSON.parse(raw) as Config;\n}\n\nexport function saveConfig(config: Config): void {\n ensureConfigDir();\n fs.writeFileSync(getConfigFile(), JSON.stringify(config, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function getActiveProfile(): Profile | null {\n const config = loadConfig();\n if (!config.activeProfile || !config.profiles[config.activeProfile]) {\n return null;\n }\n return config.profiles[config.activeProfile];\n}\n\nexport function setActiveProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.activeProfile = name;\n saveConfig(config);\n}\n\nexport function addProfile(profile: Profile): void {\n const config = loadConfig();\n config.profiles[profile.name] = profile;\n if (!config.activeProfile) {\n config.activeProfile = profile.name;\n }\n saveConfig(config);\n}\n\nexport function removeProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n delete config.profiles[name];\n if (config.activeProfile === name) {\n const remaining = Object.keys(config.profiles);\n config.activeProfile = remaining.length > 0 ? remaining[0] : \"\";\n }\n saveConfig(config);\n}\n\nexport function updateProfile(\n name: string,\n updates: Partial<Profile>,\n): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.profiles[name] = { ...config.profiles[name], ...updates };\n saveConfig(config);\n}\n\nexport function listProfiles(): { profiles: Profile[]; active: string } {\n const config = loadConfig();\n return {\n profiles: Object.values(config.profiles),\n active: config.activeProfile,\n };\n}\n","import type { Profile, SessionAuth, SessionResponse, User, CachedUser } from \"./types.js\";\nimport { updateProfile } from \"./config/store.js\";\n\nexport class MetabaseClient {\n private domain: string;\n private sessionToken?: string;\n private apiKey?: string;\n private profile: Profile;\n\n constructor(profile: Profile) {\n this.profile = profile;\n this.domain = profile.domain.replace(/\\/+$/, \"\");\n\n if (profile.auth.method === \"session\") {\n this.sessionToken = profile.auth.sessionToken;\n } else {\n this.apiKey = profile.auth.apiKey;\n }\n }\n\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return headers;\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<T> {\n let url = `${this.domain}${path}`;\n\n if (params) {\n const qs = new URLSearchParams(params).toString();\n url += `?${qs}`;\n }\n\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n const retryRes = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!retryRes.ok) {\n const err = await retryRes.text();\n throw new Error(`${retryRes.status} ${retryRes.statusText}: ${err}`);\n }\n const retryText = await retryRes.text();\n if (!retryText) return undefined as T;\n return JSON.parse(retryText) as T;\n }\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`${res.status} ${res.statusText}: ${err}`);\n }\n\n const text = await res.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>(\"GET\", path, undefined, params);\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n\n async requestFormExport(\n path: string,\n fields: Record<string, string>,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n\n const body = new URLSearchParams(fields);\n const res = await fetch(url, { method: \"POST\", headers, body });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return fetch(url, { method: \"POST\", headers, body: new URLSearchParams(fields) });\n }\n\n return res;\n }\n\n async requestRaw(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n return fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n return res;\n }\n\n async login(): Promise<SessionResponse> {\n const auth = this.profile.auth as SessionAuth;\n const res = await fetch(`${this.domain}/api/session`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ username: auth.email, password: auth.password }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Login failed: ${res.status} ${err}`);\n }\n\n const session = (await res.json()) as SessionResponse;\n this.sessionToken = session.id;\n\n // Cache session token in profile\n updateProfile(this.profile.name, {\n auth: { ...auth, sessionToken: session.id },\n });\n\n // Fetch and cache user info\n const user = await this.get<User>(\"/api/user/current\");\n const cachedUser: CachedUser = {\n id: user.id,\n email: user.email,\n first_name: user.first_name,\n last_name: user.last_name,\n is_superuser: user.is_superuser,\n };\n updateProfile(this.profile.name, { user: cachedUser });\n this.profile.user = cachedUser;\n\n return session;\n }\n\n async logout(): Promise<void> {\n await this.delete(\"/api/session\");\n this.sessionToken = undefined;\n if (this.profile.auth.method === \"session\") {\n updateProfile(this.profile.name, {\n auth: { ...this.profile.auth, sessionToken: undefined },\n });\n }\n }\n\n async ensureAuthenticated(): Promise<void> {\n if (this.apiKey) return;\n if (!this.sessionToken) {\n await this.login();\n }\n }\n\n getProfile(): Profile {\n return this.profile;\n }\n\n getUserId(): number | null {\n return this.profile.user?.id ?? null;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\n\ninterface OwnedEntity {\n creator_id: number;\n [key: string]: unknown;\n}\n\nexport class SafetyGuard {\n private client: MetabaseClient;\n private unsafe: boolean;\n\n constructor(client: MetabaseClient, unsafe = false) {\n this.client = client;\n this.unsafe = unsafe;\n }\n\n async checkOwnership(entityType: string, entityId: number): Promise<{ owned: boolean; creatorId: number }> {\n const pathMap: Record<string, string> = {\n card: `/api/card/${entityId}`,\n dashboard: `/api/dashboard/${entityId}`,\n snippet: `/api/native-query-snippet/${entityId}`,\n collection: `/api/collection/${entityId}`,\n };\n\n const path = pathMap[entityType];\n if (!path) {\n throw new Error(`Unknown entity type: ${entityType}`);\n }\n\n const entity = await this.client.get<OwnedEntity>(path);\n const userId = this.client.getUserId();\n\n if (userId === null) {\n throw new Error(\"No cached user ID. Run 'metabase-cli login' or 'metabase-cli whoami --refresh' first.\");\n }\n\n return {\n owned: entity.creator_id === userId,\n creatorId: entity.creator_id,\n };\n }\n\n async guard<T>(\n entityType: string,\n entityId: number,\n action: string,\n fn: () => Promise<T>,\n ): Promise<T> {\n if (this.unsafe) {\n return fn();\n }\n\n const { owned, creatorId } = await this.checkOwnership(entityType, entityId);\n\n if (!owned) {\n const userId = this.client.getUserId();\n throw new Error(\n `Safe mode: Cannot ${action} ${entityType} #${entityId} — ` +\n `owned by user #${creatorId}, you are user #${userId}. ` +\n `Use --unsafe to bypass.`,\n );\n }\n\n return fn();\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User } from \"../types.js\";\n\nexport class SessionApi {\n constructor(private client: MetabaseClient) {}\n\n async getCurrentUser(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n\n async getSessionProperties(): Promise<Record<string, unknown>> {\n return this.client.get(\"/api/session/properties\");\n }\n}\n","/**\n * Checks if an export response body is actually a JSON error from Metabase.\n * Metabase streaming export endpoints may return 200 with a JSON error body\n * instead of the expected format (CSV/XLSX).\n */\nexport function checkExportError(buf: Buffer, format: string): void {\n // For non-JSON formats, if the response starts with '{' it's likely a JSON error body\n if (format !== \"json\" && buf.length > 0 && buf[0] === 0x7b) {\n try {\n const parsed = JSON.parse(buf.toString(\"utf-8\"));\n if (parsed.status === \"failed\" || parsed.error) {\n throw new Error(`Query failed: ${parsed.error || \"unknown error\"}`);\n }\n } catch (e: any) {\n if (e.message.startsWith(\"Query failed:\")) throw e;\n }\n }\n}\n\n/** Map file extensions to export format identifiers */\nexport const EXT_TO_FORMAT: Record<string, string> = {\n \".csv\": \"csv\",\n \".tsv\": \"tsv\",\n \".json\": \"json\",\n \".xlsx\": \"xlsx\",\n};\n","import type { MetabaseClient } from \"../client.js\";\nimport type { DatasetQuery, DatasetResponse } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport class DatasetApi {\n constructor(private client: MetabaseClient) {}\n\n async query(datasetQuery: DatasetQuery): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(\"/api/dataset\", datasetQuery);\n }\n\n async queryNative(\n database: number,\n sql: string,\n templateTags?: Record<string, unknown>,\n ): Promise<DatasetResponse> {\n return this.query({\n type: \"native\",\n database,\n native: {\n query: sql,\n \"template-tags\": templateTags ?? {},\n },\n });\n }\n\n async export(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/dataset/${format}`,\n datasetQuery,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async exportBinary(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<Buffer> {\n const res = await this.client.requestFormExport(\n `/api/dataset/${format}`,\n { query: JSON.stringify(datasetQuery) },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Card, DatasetResponse, DatasetQuery } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport interface CreateCardParams {\n name: string;\n dataset_query: DatasetQuery;\n display: string;\n description?: string;\n collection_id?: number;\n visualization_settings?: Record<string, unknown>;\n parameters?: unknown[];\n}\n\nexport interface UpdateCardParams {\n name?: string;\n description?: string;\n parameters?: unknown[];\n collection_id?: number;\n dataset_query?: DatasetQuery;\n display?: string;\n visualization_settings?: Record<string, unknown>;\n archived?: boolean;\n}\n\nexport class CardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Card[]> {\n return this.client.get<Card[]>(\"/api/card\", params);\n }\n\n async get(id: number): Promise<Card> {\n return this.client.get<Card>(`/api/card/${id}`);\n }\n\n async create(params: CreateCardParams): Promise<Card> {\n return this.client.post<Card>(\"/api/card\", params);\n }\n\n async update(id: number, params: UpdateCardParams): Promise<Card> {\n return this.client.put<Card>(`/api/card/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/card/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateCardParams>): Promise<Card> {\n return this.client.post<Card>(`/api/card/${id}/copy`, overrides);\n }\n\n async query(id: number, parameters?: unknown[]): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(`/api/card/${id}/query`, {\n parameters: parameters ?? [],\n });\n }\n\n async queryExport(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/card/${id}/query/${format}`,\n { parameters: parameters ?? [] },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async queryExportBinary(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<Buffer> {\n const fields: Record<string, string> = {};\n if (parameters && parameters.length > 0) {\n fields.parameters = JSON.stringify(parameters);\n }\n const res = await this.client.requestFormExport(\n `/api/card/${id}/query/${format}`,\n fields,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Dashboard } from \"../types.js\";\n\nexport interface CreateDashboardParams {\n name: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n}\n\nexport interface UpdateDashboardParams {\n name?: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n dashcards?: unknown[];\n archived?: boolean;\n}\n\nexport class DashboardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Dashboard[]> {\n return this.client.get<Dashboard[]>(\"/api/dashboard\", params);\n }\n\n async get(id: number): Promise<Dashboard> {\n return this.client.get<Dashboard>(`/api/dashboard/${id}`);\n }\n\n async create(params: CreateDashboardParams): Promise<Dashboard> {\n return this.client.post<Dashboard>(\"/api/dashboard\", params);\n }\n\n async update(id: number, params: UpdateDashboardParams): Promise<Dashboard> {\n return this.client.put<Dashboard>(`/api/dashboard/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/dashboard/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateDashboardParams>): Promise<Dashboard> {\n return this.client.post<Dashboard>(`/api/dashboard/${id}/copy`, overrides);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Collection } from \"../types.js\";\n\nexport interface CreateCollectionParams {\n name: string;\n description?: string;\n parent_id?: number;\n}\n\nexport interface UpdateCollectionParams {\n name?: string;\n description?: string;\n parent_id?: number;\n archived?: boolean;\n}\n\nexport interface CollectionItem {\n id: number;\n name: string;\n model: string;\n description: string | null;\n [key: string]: unknown;\n}\n\nexport class CollectionApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection\");\n }\n\n async tree(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection/tree\");\n }\n\n async get(id: number | \"root\"): Promise<Collection> {\n return this.client.get<Collection>(`/api/collection/${id}`);\n }\n\n async items(\n id: number | \"root\",\n params?: Record<string, string>,\n ): Promise<{ data: CollectionItem[]; total: number }> {\n return this.client.get(`/api/collection/${id}/items`, params);\n }\n\n async create(params: CreateCollectionParams): Promise<Collection> {\n return this.client.post<Collection>(\"/api/collection\", params);\n }\n\n async update(id: number, params: UpdateCollectionParams): Promise<Collection> {\n return this.client.put<Collection>(`/api/collection/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Database, Table } from \"../types.js\";\n\nexport class DatabaseApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<{ data: Database[] }> {\n return this.client.get(\"/api/database\");\n }\n\n async get(id: number): Promise<Database> {\n return this.client.get<Database>(`/api/database/${id}`);\n }\n\n async metadata(id: number): Promise<Database & { tables: Table[] }> {\n return this.client.get(`/api/database/${id}/metadata`);\n }\n\n async schemas(id: number): Promise<string[]> {\n return this.client.get<string[]>(`/api/database/${id}/schemas`);\n }\n\n async tablesInSchema(id: number, schema: string): Promise<Table[]> {\n return this.client.get<Table[]>(\n `/api/database/${id}/schema/${encodeURIComponent(schema)}`,\n );\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Table, Field } from \"../types.js\";\n\nexport class TableApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Table> {\n return this.client.get<Table>(`/api/table/${id}`);\n }\n\n async queryMetadata(id: number): Promise<Table & { fields: Field[] }> {\n return this.client.get(`/api/table/${id}/query_metadata`);\n }\n\n async foreignKeys(id: number): Promise<unknown[]> {\n return this.client.get(`/api/table/${id}/fks`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Field } from \"../types.js\";\n\nexport class FieldApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Field> {\n return this.client.get<Field>(`/api/field/${id}`);\n }\n\n async values(id: number): Promise<{ values: unknown[][] }> {\n return this.client.get(`/api/field/${id}/values`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Snippet } from \"../types.js\";\n\nexport interface CreateSnippetParams {\n name: string;\n content: string;\n description?: string;\n collection_id?: number;\n}\n\nexport interface UpdateSnippetParams {\n name?: string;\n content?: string;\n description?: string;\n collection_id?: number;\n archived?: boolean;\n}\n\nexport class SnippetApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Snippet[]> {\n return this.client.get<Snippet[]>(\"/api/native-query-snippet\", params);\n }\n\n async get(id: number): Promise<Snippet> {\n return this.client.get<Snippet>(`/api/native-query-snippet/${id}`);\n }\n\n async create(params: CreateSnippetParams): Promise<Snippet> {\n return this.client.post<Snippet>(\"/api/native-query-snippet\", params);\n }\n\n async update(id: number, params: UpdateSnippetParams): Promise<Snippet> {\n return this.client.put<Snippet>(`/api/native-query-snippet/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { SearchResult, PaginatedResponse } from \"../types.js\";\n\nexport class SearchApi {\n constructor(private client: MetabaseClient) {}\n\n async search(\n query: string,\n params?: {\n models?: string[];\n limit?: number;\n offset?: number;\n },\n ): Promise<PaginatedResponse<SearchResult>> {\n const qs: Record<string, string> = { q: query };\n if (params?.models?.length) {\n qs.models = params.models.join(\",\");\n }\n if (params?.limit !== undefined) qs.limit = String(params.limit);\n if (params?.offset !== undefined) qs.offset = String(params.offset);\n\n return this.client.get(\"/api/search\", qs);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User, PaginatedResponse } from \"../types.js\";\n\nexport class UserApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<PaginatedResponse<User>> {\n return this.client.get(\"/api/user\", params);\n }\n\n async get(id: number): Promise<User> {\n return this.client.get<User>(`/api/user/${id}`);\n }\n\n async current(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n}\n","import Table from \"cli-table3\";\nimport type { DatasetResponse, OutputFormat } from \"../types.js\";\n\nexport function formatDatasetResponse(\n dataset: DatasetResponse,\n format: OutputFormat = \"table\",\n columns?: string[],\n): string {\n const cols = dataset.data.cols;\n const rows = dataset.data.rows;\n\n // Filter columns if specified\n let colIndices: number[];\n if (columns?.length) {\n colIndices = columns.map((name) => {\n const idx = cols.findIndex(\n (c) => c.name === name || c.display_name === name,\n );\n if (idx === -1) throw new Error(`Column \"${name}\" not found`);\n return idx;\n });\n } else {\n colIndices = cols.map((_, i) => i);\n }\n\n const filteredCols = colIndices.map((i) => cols[i]);\n const filteredRows = rows.map((row) => colIndices.map((i) => row[i]));\n\n switch (format) {\n case \"json\":\n return JSON.stringify(\n filteredRows.map((row) =>\n Object.fromEntries(\n filteredCols.map((col, i) => [col.name, row[i]]),\n ),\n ),\n null,\n 2,\n );\n\n case \"csv\":\n return formatDelimited(filteredCols, filteredRows, \",\");\n\n case \"tsv\":\n return formatDelimited(filteredCols, filteredRows, \"\\t\");\n\n case \"table\":\n default:\n return formatTable(filteredCols, filteredRows);\n }\n}\n\nfunction formatDelimited(\n cols: { name: string }[],\n rows: unknown[][],\n delimiter: string,\n): string {\n const header = cols.map((c) => escapeCsvField(String(c.name), delimiter)).join(delimiter);\n const body = rows.map((row) =>\n row.map((cell) => escapeCsvField(formatCell(cell), delimiter)).join(delimiter),\n );\n return [header, ...body].join(\"\\n\");\n}\n\nfunction escapeCsvField(value: string, delimiter: string): string {\n if (value.includes(delimiter) || value.includes('\"') || value.includes(\"\\n\")) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nfunction formatTable(cols: { display_name: string }[], rows: unknown[][]): string {\n const table = new Table({\n head: cols.map((c) => c.display_name),\n style: { head: [\"cyan\"] },\n });\n\n for (const row of rows) {\n table.push(row.map((cell) => formatCell(cell)));\n }\n\n return table.toString();\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\nexport function formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nexport function formatEntityTable(\n items: Record<string, unknown>[],\n columns: { key: string; header: string }[],\n): string {\n const table = new Table({\n head: columns.map((c) => c.header),\n style: { head: [\"cyan\"] },\n });\n\n for (const item of items) {\n table.push(columns.map((c) => formatCell(item[c.key])));\n }\n\n return table.toString();\n}\n"],"mappings":"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","names":["path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/config/store.ts","../src/client.ts","../src/safety/guard.ts","../src/api/session.ts","../src/utils/export.ts","../src/api/dataset.ts","../src/api/card.ts","../src/api/dashboard.ts","../src/api/collection.ts","../src/api/database.ts","../src/api/table.ts","../src/api/field.ts","../src/api/snippet.ts","../src/api/search.ts","../src/api/user.ts","../src/utils/output.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport type { Config, Profile } from \"../types.js\";\n\nfunction getConfigDir(): string {\n return path.join(os.homedir(), \".metabase-cli\");\n}\n\nfunction getConfigFile(): string {\n return path.join(getConfigDir(), \"config.json\");\n}\n\nfunction ensureConfigDir(): void {\n if (!fs.existsSync(getConfigDir())) {\n fs.mkdirSync(getConfigDir(), { recursive: true, mode: 0o700 });\n }\n}\n\nfunction defaultConfig(): Config {\n return { activeProfile: \"\", profiles: {} };\n}\n\nexport function loadConfig(): Config {\n ensureConfigDir();\n if (!fs.existsSync(getConfigFile())) {\n return defaultConfig();\n }\n const raw = fs.readFileSync(getConfigFile(), \"utf-8\");\n return JSON.parse(raw) as Config;\n}\n\nexport function saveConfig(config: Config): void {\n ensureConfigDir();\n fs.writeFileSync(getConfigFile(), JSON.stringify(config, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function getActiveProfile(): Profile | null {\n const config = loadConfig();\n if (!config.activeProfile || !config.profiles[config.activeProfile]) {\n return null;\n }\n return config.profiles[config.activeProfile];\n}\n\nexport function setActiveProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.activeProfile = name;\n saveConfig(config);\n}\n\nexport function addProfile(profile: Profile): void {\n const config = loadConfig();\n config.profiles[profile.name] = profile;\n if (!config.activeProfile) {\n config.activeProfile = profile.name;\n }\n saveConfig(config);\n}\n\nexport function removeProfile(name: string): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n delete config.profiles[name];\n if (config.activeProfile === name) {\n const remaining = Object.keys(config.profiles);\n config.activeProfile = remaining.length > 0 ? remaining[0] : \"\";\n }\n saveConfig(config);\n}\n\nexport function updateProfile(\n name: string,\n updates: Partial<Profile>,\n): void {\n const config = loadConfig();\n if (!config.profiles[name]) {\n throw new Error(`Profile \"${name}\" does not exist`);\n }\n config.profiles[name] = { ...config.profiles[name], ...updates };\n saveConfig(config);\n}\n\nexport function getProfile(name: string): Profile | null {\n const config = loadConfig();\n return config.profiles[name] ?? null;\n}\n\nexport function listProfiles(): { profiles: Profile[]; active: string } {\n const config = loadConfig();\n return {\n profiles: Object.values(config.profiles),\n active: config.activeProfile,\n };\n}\n","import type { Profile, SessionAuth, SessionResponse, User, CachedUser } from \"./types.js\";\nimport { updateProfile } from \"./config/store.js\";\n\nexport class MetabaseClient {\n private domain: string;\n private sessionToken?: string;\n private apiKey?: string;\n private profile: Profile;\n\n constructor(profile: Profile) {\n this.profile = profile;\n this.domain = profile.domain.replace(/\\/+$/, \"\");\n\n if (profile.auth.method === \"session\") {\n this.sessionToken = profile.auth.sessionToken;\n } else {\n this.apiKey = profile.auth.apiKey;\n }\n }\n\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return headers;\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<T> {\n let url = `${this.domain}${path}`;\n\n if (params) {\n const qs = new URLSearchParams(params).toString();\n url += `?${qs}`;\n }\n\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n const retryRes = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!retryRes.ok) {\n const err = await retryRes.text();\n throw new Error(`${retryRes.status} ${retryRes.statusText}: ${err}`);\n }\n const retryText = await retryRes.text();\n if (!retryText) return undefined as T;\n return JSON.parse(retryText) as T;\n }\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`${res.status} ${res.statusText}: ${err}`);\n }\n\n const text = await res.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>(\"GET\", path, undefined, params);\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n\n async requestFormExport(\n path: string,\n fields: Record<string, string>,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n headers[\"X-Api-Key\"] = this.apiKey;\n } else if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n\n const body = new URLSearchParams(fields);\n const res = await fetch(url, { method: \"POST\", headers, body });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n if (this.sessionToken) {\n headers[\"X-Metabase-Session\"] = this.sessionToken;\n }\n return fetch(url, { method: \"POST\", headers, body: new URLSearchParams(fields) });\n }\n\n return res;\n }\n\n async requestRaw(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<Response> {\n const url = `${this.domain}${path}`;\n const res = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (res.status === 401 && this.profile.auth.method === \"session\") {\n await this.login();\n return fetch(url, {\n method,\n headers: this.getHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n }\n\n return res;\n }\n\n async login(): Promise<SessionResponse> {\n const auth = this.profile.auth as SessionAuth;\n const res = await fetch(`${this.domain}/api/session`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ username: auth.email, password: auth.password }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Login failed: ${res.status} ${err}`);\n }\n\n const session = (await res.json()) as SessionResponse;\n this.sessionToken = session.id;\n\n // Cache session token in profile\n updateProfile(this.profile.name, {\n auth: { ...auth, sessionToken: session.id },\n });\n\n // Fetch and cache user info\n const user = await this.get<User>(\"/api/user/current\");\n const cachedUser: CachedUser = {\n id: user.id,\n email: user.email,\n first_name: user.first_name,\n last_name: user.last_name,\n is_superuser: user.is_superuser,\n };\n updateProfile(this.profile.name, { user: cachedUser });\n this.profile.user = cachedUser;\n\n return session;\n }\n\n async logout(): Promise<void> {\n await this.delete(\"/api/session\");\n this.sessionToken = undefined;\n if (this.profile.auth.method === \"session\") {\n updateProfile(this.profile.name, {\n auth: { ...this.profile.auth, sessionToken: undefined },\n });\n }\n }\n\n async ensureAuthenticated(): Promise<void> {\n if (this.apiKey) return;\n if (!this.sessionToken) {\n await this.login();\n }\n }\n\n getProfile(): Profile {\n return this.profile;\n }\n\n getUserId(): number | null {\n return this.profile.user?.id ?? null;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\n\ninterface OwnedEntity {\n creator_id: number;\n [key: string]: unknown;\n}\n\nexport class SafetyGuard {\n private client: MetabaseClient;\n private unsafe: boolean;\n\n constructor(client: MetabaseClient, unsafe = false) {\n this.client = client;\n this.unsafe = unsafe;\n }\n\n async checkOwnership(entityType: string, entityId: number): Promise<{ owned: boolean; creatorId: number }> {\n const pathMap: Record<string, string> = {\n card: `/api/card/${entityId}`,\n dashboard: `/api/dashboard/${entityId}`,\n snippet: `/api/native-query-snippet/${entityId}`,\n collection: `/api/collection/${entityId}`,\n };\n\n const path = pathMap[entityType];\n if (!path) {\n throw new Error(`Unknown entity type: ${entityType}`);\n }\n\n const entity = await this.client.get<OwnedEntity>(path);\n const userId = this.client.getUserId();\n\n if (userId === null) {\n throw new Error(\"No cached user ID. Run 'metabase-cli login' or 'metabase-cli whoami --refresh' first.\");\n }\n\n return {\n owned: entity.creator_id === userId,\n creatorId: entity.creator_id,\n };\n }\n\n async guard<T>(\n entityType: string,\n entityId: number,\n action: string,\n fn: () => Promise<T>,\n ): Promise<T> {\n if (this.unsafe) {\n return fn();\n }\n\n const { owned, creatorId } = await this.checkOwnership(entityType, entityId);\n\n if (!owned) {\n const userId = this.client.getUserId();\n throw new Error(\n `Safe mode: Cannot ${action} ${entityType} #${entityId} — ` +\n `owned by user #${creatorId}, you are user #${userId}. ` +\n `Use --unsafe to bypass.`,\n );\n }\n\n return fn();\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User } from \"../types.js\";\n\nexport class SessionApi {\n constructor(private client: MetabaseClient) {}\n\n async getCurrentUser(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n\n async getSessionProperties(): Promise<Record<string, unknown>> {\n return this.client.get(\"/api/session/properties\");\n }\n}\n","/**\n * Checks if an export response body is actually a JSON error from Metabase.\n * Metabase streaming export endpoints may return 200 with a JSON error body\n * instead of the expected format (CSV/XLSX).\n */\nexport function checkExportError(buf: Buffer, format: string): void {\n // For non-JSON formats, if the response starts with '{' it's likely a JSON error body\n if (format !== \"json\" && buf.length > 0 && buf[0] === 0x7b) {\n try {\n const parsed = JSON.parse(buf.toString(\"utf-8\"));\n if (parsed.status === \"failed\" || parsed.error) {\n throw new Error(`Query failed: ${parsed.error || \"unknown error\"}`);\n }\n } catch (e: any) {\n if (e.message.startsWith(\"Query failed:\")) throw e;\n }\n }\n}\n\n/** Map file extensions to export format identifiers */\nexport const EXT_TO_FORMAT: Record<string, string> = {\n \".csv\": \"csv\",\n \".tsv\": \"tsv\",\n \".json\": \"json\",\n \".xlsx\": \"xlsx\",\n};\n","import type { MetabaseClient } from \"../client.js\";\nimport type { DatasetQuery, DatasetResponse } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport class DatasetApi {\n constructor(private client: MetabaseClient) {}\n\n async query(datasetQuery: DatasetQuery): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(\"/api/dataset\", datasetQuery);\n }\n\n async queryNative(\n database: number,\n sql: string,\n templateTags?: Record<string, unknown>,\n ): Promise<DatasetResponse> {\n return this.query({\n type: \"native\",\n database,\n native: {\n query: sql,\n \"template-tags\": templateTags ?? {},\n },\n });\n }\n\n async export(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/dataset/${format}`,\n datasetQuery,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async exportBinary(\n datasetQuery: DatasetQuery,\n format: \"csv\" | \"json\" | \"xlsx\",\n ): Promise<Buffer> {\n const res = await this.client.requestFormExport(\n `/api/dataset/${format}`,\n { query: JSON.stringify(datasetQuery) },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Card, DatasetResponse, DatasetQuery } from \"../types.js\";\nimport { checkExportError } from \"../utils/export.js\";\n\nexport interface CreateCardParams {\n name: string;\n dataset_query: DatasetQuery;\n display: string;\n description?: string;\n collection_id?: number;\n visualization_settings?: Record<string, unknown>;\n parameters?: unknown[];\n}\n\nexport interface UpdateCardParams {\n name?: string;\n description?: string;\n parameters?: unknown[];\n collection_id?: number;\n dataset_query?: DatasetQuery;\n display?: string;\n visualization_settings?: Record<string, unknown>;\n archived?: boolean;\n}\n\nexport class CardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Card[]> {\n return this.client.get<Card[]>(\"/api/card\", params);\n }\n\n async get(id: number): Promise<Card> {\n return this.client.get<Card>(`/api/card/${id}`);\n }\n\n async create(params: CreateCardParams): Promise<Card> {\n return this.client.post<Card>(\"/api/card\", params);\n }\n\n async update(id: number, params: UpdateCardParams): Promise<Card> {\n return this.client.put<Card>(`/api/card/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/card/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateCardParams>): Promise<Card> {\n return this.client.post<Card>(`/api/card/${id}/copy`, overrides);\n }\n\n async query(id: number, parameters?: unknown[]): Promise<DatasetResponse> {\n return this.client.post<DatasetResponse>(`/api/card/${id}/query`, {\n parameters: parameters ?? [],\n });\n }\n\n async queryExport(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<string> {\n const res = await this.client.requestRaw(\n \"POST\",\n `/api/card/${id}/query/${format}`,\n { parameters: parameters ?? [] },\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n return res.text();\n }\n\n async queryExportBinary(\n id: number,\n format: \"csv\" | \"json\" | \"xlsx\",\n parameters?: unknown[],\n ): Promise<Buffer> {\n const fields: Record<string, string> = {};\n if (parameters && parameters.length > 0) {\n fields.parameters = JSON.stringify(parameters);\n }\n const res = await this.client.requestFormExport(\n `/api/card/${id}/query/${format}`,\n fields,\n );\n if (!res.ok) {\n throw new Error(`Export failed: ${res.status} ${await res.text()}`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n checkExportError(buf, format);\n return buf;\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Dashboard } from \"../types.js\";\n\nexport interface CreateDashboardParams {\n name: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n}\n\nexport interface UpdateDashboardParams {\n name?: string;\n description?: string;\n collection_id?: number;\n parameters?: unknown[];\n dashcards?: unknown[];\n archived?: boolean;\n}\n\nexport class DashboardApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Dashboard[]> {\n return this.client.get<Dashboard[]>(\"/api/dashboard\", params);\n }\n\n async get(id: number): Promise<Dashboard> {\n return this.client.get<Dashboard>(`/api/dashboard/${id}`);\n }\n\n async create(params: CreateDashboardParams): Promise<Dashboard> {\n return this.client.post<Dashboard>(\"/api/dashboard\", params);\n }\n\n async update(id: number, params: UpdateDashboardParams): Promise<Dashboard> {\n return this.client.put<Dashboard>(`/api/dashboard/${id}`, params);\n }\n\n async delete(id: number): Promise<void> {\n await this.client.delete(`/api/dashboard/${id}`);\n }\n\n async copy(id: number, overrides?: Partial<CreateDashboardParams>): Promise<Dashboard> {\n return this.client.post<Dashboard>(`/api/dashboard/${id}/copy`, overrides);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Collection } from \"../types.js\";\n\nexport interface CreateCollectionParams {\n name: string;\n description?: string;\n parent_id?: number;\n}\n\nexport interface UpdateCollectionParams {\n name?: string;\n description?: string;\n parent_id?: number;\n archived?: boolean;\n}\n\nexport interface CollectionItem {\n id: number;\n name: string;\n model: string;\n description: string | null;\n [key: string]: unknown;\n}\n\nexport class CollectionApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection\");\n }\n\n async tree(): Promise<Collection[]> {\n return this.client.get<Collection[]>(\"/api/collection/tree\");\n }\n\n async get(id: number | \"root\"): Promise<Collection> {\n return this.client.get<Collection>(`/api/collection/${id}`);\n }\n\n async items(\n id: number | \"root\",\n params?: Record<string, string>,\n ): Promise<{ data: CollectionItem[]; total: number }> {\n return this.client.get(`/api/collection/${id}/items`, params);\n }\n\n async create(params: CreateCollectionParams): Promise<Collection> {\n return this.client.post<Collection>(\"/api/collection\", params);\n }\n\n async update(id: number, params: UpdateCollectionParams): Promise<Collection> {\n return this.client.put<Collection>(`/api/collection/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Database, Table } from \"../types.js\";\n\nexport class DatabaseApi {\n constructor(private client: MetabaseClient) {}\n\n async list(): Promise<{ data: Database[] }> {\n return this.client.get(\"/api/database\");\n }\n\n async get(id: number): Promise<Database> {\n return this.client.get<Database>(`/api/database/${id}`);\n }\n\n async metadata(id: number): Promise<Database & { tables: Table[] }> {\n return this.client.get(`/api/database/${id}/metadata`);\n }\n\n async schemas(id: number): Promise<string[]> {\n return this.client.get<string[]>(`/api/database/${id}/schemas`);\n }\n\n async tablesInSchema(id: number, schema: string): Promise<Table[]> {\n return this.client.get<Table[]>(\n `/api/database/${id}/schema/${encodeURIComponent(schema)}`,\n );\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Table, Field } from \"../types.js\";\n\nexport class TableApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Table> {\n return this.client.get<Table>(`/api/table/${id}`);\n }\n\n async queryMetadata(id: number): Promise<Table & { fields: Field[] }> {\n return this.client.get(`/api/table/${id}/query_metadata`);\n }\n\n async foreignKeys(id: number): Promise<unknown[]> {\n return this.client.get(`/api/table/${id}/fks`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Field } from \"../types.js\";\n\nexport class FieldApi {\n constructor(private client: MetabaseClient) {}\n\n async get(id: number): Promise<Field> {\n return this.client.get<Field>(`/api/field/${id}`);\n }\n\n async values(id: number): Promise<{ values: unknown[][] }> {\n return this.client.get(`/api/field/${id}/values`);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { Snippet } from \"../types.js\";\n\nexport interface CreateSnippetParams {\n name: string;\n content: string;\n description?: string;\n collection_id?: number;\n}\n\nexport interface UpdateSnippetParams {\n name?: string;\n content?: string;\n description?: string;\n collection_id?: number;\n archived?: boolean;\n}\n\nexport class SnippetApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<Snippet[]> {\n return this.client.get<Snippet[]>(\"/api/native-query-snippet\", params);\n }\n\n async get(id: number): Promise<Snippet> {\n return this.client.get<Snippet>(`/api/native-query-snippet/${id}`);\n }\n\n async create(params: CreateSnippetParams): Promise<Snippet> {\n return this.client.post<Snippet>(\"/api/native-query-snippet\", params);\n }\n\n async update(id: number, params: UpdateSnippetParams): Promise<Snippet> {\n return this.client.put<Snippet>(`/api/native-query-snippet/${id}`, params);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { SearchResult, PaginatedResponse } from \"../types.js\";\n\nexport class SearchApi {\n constructor(private client: MetabaseClient) {}\n\n async search(\n query: string,\n params?: {\n models?: string[];\n limit?: number;\n offset?: number;\n },\n ): Promise<PaginatedResponse<SearchResult>> {\n const qs: Record<string, string> = { q: query };\n if (params?.models?.length) {\n qs.models = params.models.join(\",\");\n }\n if (params?.limit !== undefined) qs.limit = String(params.limit);\n if (params?.offset !== undefined) qs.offset = String(params.offset);\n\n return this.client.get(\"/api/search\", qs);\n }\n}\n","import type { MetabaseClient } from \"../client.js\";\nimport type { User, PaginatedResponse } from \"../types.js\";\n\nexport class UserApi {\n constructor(private client: MetabaseClient) {}\n\n async list(params?: Record<string, string>): Promise<PaginatedResponse<User>> {\n return this.client.get(\"/api/user\", params);\n }\n\n async get(id: number): Promise<User> {\n return this.client.get<User>(`/api/user/${id}`);\n }\n\n async current(): Promise<User> {\n return this.client.get<User>(\"/api/user/current\");\n }\n}\n","import Table from \"cli-table3\";\nimport type { DatasetResponse, OutputFormat } from \"../types.js\";\n\nexport function formatDatasetResponse(\n dataset: DatasetResponse,\n format: OutputFormat = \"table\",\n columns?: string[],\n): string {\n const cols = dataset.data.cols;\n const rows = dataset.data.rows;\n\n // Filter columns if specified\n let colIndices: number[];\n if (columns?.length) {\n colIndices = columns.map((name) => {\n const idx = cols.findIndex(\n (c) => c.name === name || c.display_name === name,\n );\n if (idx === -1) throw new Error(`Column \"${name}\" not found`);\n return idx;\n });\n } else {\n colIndices = cols.map((_, i) => i);\n }\n\n const filteredCols = colIndices.map((i) => cols[i]);\n const filteredRows = rows.map((row) => colIndices.map((i) => row[i]));\n\n switch (format) {\n case \"json\":\n return JSON.stringify(\n filteredRows.map((row) =>\n Object.fromEntries(\n filteredCols.map((col, i) => [col.name, row[i]]),\n ),\n ),\n null,\n 2,\n );\n\n case \"csv\":\n return formatDelimited(filteredCols, filteredRows, \",\");\n\n case \"tsv\":\n return formatDelimited(filteredCols, filteredRows, \"\\t\");\n\n case \"table\":\n default:\n return formatTable(filteredCols, filteredRows);\n }\n}\n\nfunction formatDelimited(\n cols: { name: string }[],\n rows: unknown[][],\n delimiter: string,\n): string {\n const header = cols.map((c) => escapeCsvField(String(c.name), delimiter)).join(delimiter);\n const body = rows.map((row) =>\n row.map((cell) => escapeCsvField(formatCell(cell), delimiter)).join(delimiter),\n );\n return [header, ...body].join(\"\\n\");\n}\n\nfunction escapeCsvField(value: string, delimiter: string): string {\n if (value.includes(delimiter) || value.includes('\"') || value.includes(\"\\n\")) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nfunction formatTable(cols: { display_name: string }[], rows: unknown[][]): string {\n const table = new Table({\n head: cols.map((c) => c.display_name),\n style: { head: [\"cyan\"] },\n });\n\n for (const row of rows) {\n table.push(row.map((cell) => formatCell(cell)));\n }\n\n return table.toString();\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\nexport function formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nexport function formatEntityTable(\n items: Record<string, unknown>[],\n columns: { key: string; header: string }[],\n): string {\n const table = new Table({\n head: columns.map((c) => c.header),\n style: { head: [\"cyan\"] },\n });\n\n for (const item of items) {\n table.push(columns.map((c) => formatCell(item[c.key])));\n }\n\n return table.toString();\n}\n"],"mappings":"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","names":["path","path"]}
|
package/dist/metabase.js
CHANGED
|
@@ -107,6 +107,10 @@ function updateProfile(name, updates) {
|
|
|
107
107
|
config.profiles[name] = { ...config.profiles[name], ...updates };
|
|
108
108
|
saveConfig(config);
|
|
109
109
|
}
|
|
110
|
+
function getProfile(name) {
|
|
111
|
+
const config = loadConfig();
|
|
112
|
+
return config.profiles[name] ?? null;
|
|
113
|
+
}
|
|
110
114
|
function listProfiles() {
|
|
111
115
|
const config = loadConfig();
|
|
112
116
|
return {
|
|
@@ -532,8 +536,20 @@ var MetabaseClient = class {
|
|
|
532
536
|
};
|
|
533
537
|
|
|
534
538
|
// src/commands/helpers.ts
|
|
539
|
+
function resolveProfile() {
|
|
540
|
+
const profileName = process.env._METABASE_CLI_PROFILE;
|
|
541
|
+
if (profileName) {
|
|
542
|
+
const profile = getProfile(profileName);
|
|
543
|
+
if (!profile) {
|
|
544
|
+
console.error(`Error: Profile "${profileName}" does not exist.`);
|
|
545
|
+
process.exit(1);
|
|
546
|
+
}
|
|
547
|
+
return profile;
|
|
548
|
+
}
|
|
549
|
+
return getActiveProfile();
|
|
550
|
+
}
|
|
535
551
|
async function resolveClient() {
|
|
536
|
-
const profile =
|
|
552
|
+
const profile = resolveProfile();
|
|
537
553
|
if (!profile) {
|
|
538
554
|
console.error("No active profile. Run: metabase-cli profile add <name>");
|
|
539
555
|
process.exit(1);
|
|
@@ -544,7 +560,7 @@ async function resolveClient() {
|
|
|
544
560
|
}
|
|
545
561
|
function resolveDb(optDb) {
|
|
546
562
|
if (optDb !== void 0) return optDb;
|
|
547
|
-
const profile =
|
|
563
|
+
const profile = resolveProfile();
|
|
548
564
|
if (profile?.defaultDb) return profile.defaultDb;
|
|
549
565
|
console.error("Error: --db is required (or set a default with: metabase-cli profile set-default-db <id>)");
|
|
550
566
|
process.exit(1);
|
|
@@ -1633,7 +1649,12 @@ function handleError(err) {
|
|
|
1633
1649
|
// bin/metabase.ts
|
|
1634
1650
|
var pkg = JSON.parse((0, import_node_fs3.readFileSync)((0, import_node_path3.resolve)(__dirname, "..", "package.json"), "utf-8"));
|
|
1635
1651
|
var program = new import_commander9.Command();
|
|
1636
|
-
program.name("metabase-cli").description("Headless CLI for Metabase instances").version(pkg.version).option("--unsafe", "Bypass safe mode globally")
|
|
1652
|
+
program.name("metabase-cli").description("Headless CLI for Metabase instances").version(pkg.version).option("--unsafe", "Bypass safe mode globally").option("--profile <name>", "Use a specific profile for this command").hook("preAction", (thisCommand) => {
|
|
1653
|
+
const opts = thisCommand.opts();
|
|
1654
|
+
if (opts.profile) {
|
|
1655
|
+
process.env._METABASE_CLI_PROFILE = opts.profile;
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1637
1658
|
program.addCommand(profileCommand());
|
|
1638
1659
|
program.addCommand(queryCommand());
|
|
1639
1660
|
program.addCommand(questionCommand());
|
|
@@ -1644,14 +1665,27 @@ program.addCommand(tableCommand());
|
|
|
1644
1665
|
program.addCommand(fieldCommand());
|
|
1645
1666
|
program.addCommand(searchCommand());
|
|
1646
1667
|
program.addCommand(snippetCommand());
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1668
|
+
function resolveProfile2() {
|
|
1669
|
+
const name = process.env._METABASE_CLI_PROFILE;
|
|
1670
|
+
if (name) {
|
|
1671
|
+
const p2 = getProfile(name);
|
|
1672
|
+
if (!p2) {
|
|
1673
|
+
console.error(`Error: Profile "${name}" does not exist.`);
|
|
1674
|
+
process.exit(1);
|
|
1675
|
+
}
|
|
1676
|
+
return p2;
|
|
1677
|
+
}
|
|
1678
|
+
const p = getActiveProfile();
|
|
1679
|
+
if (!p) {
|
|
1652
1680
|
console.error("No active profile. Run: metabase-cli profile add <name>");
|
|
1653
1681
|
process.exit(1);
|
|
1654
1682
|
}
|
|
1683
|
+
return p;
|
|
1684
|
+
}
|
|
1685
|
+
program.command("login").description("Login to the active profile").addHelpText("after", `
|
|
1686
|
+
Examples:
|
|
1687
|
+
$ metabase-cli login`).action(async () => {
|
|
1688
|
+
const profile = resolveProfile2();
|
|
1655
1689
|
if (profile.auth.method !== "session") {
|
|
1656
1690
|
console.log("Profile uses API key auth \u2014 no login needed.");
|
|
1657
1691
|
return;
|
|
@@ -1666,11 +1700,7 @@ Examples:
|
|
|
1666
1700
|
program.command("logout").description("Logout from the active profile").addHelpText("after", `
|
|
1667
1701
|
Examples:
|
|
1668
1702
|
$ metabase-cli logout`).action(async () => {
|
|
1669
|
-
const profile =
|
|
1670
|
-
if (!profile) {
|
|
1671
|
-
console.error("No active profile.");
|
|
1672
|
-
process.exit(1);
|
|
1673
|
-
}
|
|
1703
|
+
const profile = resolveProfile2();
|
|
1674
1704
|
const client = new MetabaseClient(profile);
|
|
1675
1705
|
await client.logout();
|
|
1676
1706
|
console.log("Logged out.");
|
|
@@ -1679,11 +1709,7 @@ program.command("whoami").description("Show current user info").option("--refres
|
|
|
1679
1709
|
Examples:
|
|
1680
1710
|
$ metabase-cli whoami
|
|
1681
1711
|
$ metabase-cli whoami --refresh`).action(async (opts) => {
|
|
1682
|
-
const profile =
|
|
1683
|
-
if (!profile) {
|
|
1684
|
-
console.error("No active profile.");
|
|
1685
|
-
process.exit(1);
|
|
1686
|
-
}
|
|
1712
|
+
const profile = resolveProfile2();
|
|
1687
1713
|
if (!opts.refresh && profile.user) {
|
|
1688
1714
|
console.log(`${profile.user.first_name} ${profile.user.last_name}`);
|
|
1689
1715
|
console.log(`Email: ${profile.user.email}`);
|