| |
| |
| |
| |
| |
| |
| |
|
|
| const BASE = (import.meta.env.VITE_API_BASE as string | undefined) ?? ""; |
|
|
| async function post<T>(path: string, body: unknown): Promise<T> { |
| const res = await fetch(`${BASE}${path}`, { |
| method: "POST", |
| headers: { "Content-Type": "application/json" }, |
| body: JSON.stringify(body), |
| }); |
| if (!res.ok) { |
| const text = await res.text().catch(() => ""); |
| throw new Error(`API error ${res.status}: ${text.slice(0, 400)}`); |
| } |
| return res.json() as Promise<T>; |
| } |
|
|
| async function get<T>(path: string): Promise<T> { |
| const res = await fetch(`${BASE}${path}`); |
| if (!res.ok) { |
| const text = await res.text().catch(() => ""); |
| throw new Error(`API error ${res.status}: ${text.slice(0, 400)}`); |
| } |
| return res.json() as Promise<T>; |
| } |
|
|
| |
|
|
| export interface LintViolation { |
| line_no: number; |
| line_pos: number; |
| code: string; |
| description: string; |
| name: string; |
| warning: boolean; |
| fixable: boolean; |
| } |
|
|
| export interface LintResult { |
| dialect: string; |
| violations: LintViolation[]; |
| passed: boolean; |
| stats: { total: number; errors: number; warnings: number; fixable: number }; |
| } |
|
|
| export interface AstNode { |
| id: string; |
| type: string; |
| name: string; |
| raw: string | null; |
| start_line: number | null; |
| start_pos: number | null; |
| end_line: number | null; |
| end_pos: number | null; |
| is_leaf: boolean; |
| children: AstNode[]; |
| } |
|
|
| export interface ParseResult { |
| dialect: string; |
| tree: AstNode; |
| token_count: number; |
| depth: number; |
| } |
|
|
| export interface FormatResult { |
| dialect: string; |
| original: string; |
| formatted: string; |
| changed: boolean; |
| fixes_applied: number; |
| } |
|
|
| export interface InjectionPattern { |
| pattern_id: string; |
| risk_level: "critical" | "high" | "medium" | "low"; |
| category: string; |
| description: string; |
| detail: string; |
| offending_token: string | null; |
| line_no: number | null; |
| line_pos: number | null; |
| recommendation: string; |
| } |
|
|
| export interface InjectionResult { |
| dialect: string; |
| safe: boolean; |
| risk_score: number; |
| patterns: InjectionPattern[]; |
| summary: string; |
| } |
|
|
| export interface HealthResult { |
| status: string; |
| version: string; |
| dialects: string[]; |
| } |
|
|
| |
|
|
| export const api = { |
| health: () => get<HealthResult>("/api/health"), |
| lint: (sql: string, dialect: string) => post<LintResult>("/api/lint", { sql, dialect }), |
| parse: (sql: string, dialect: string) => post<ParseResult>("/api/parse", { sql, dialect }), |
| format: (sql: string, dialect: string) => post<FormatResult>("/api/format", { sql, dialect }), |
| inject: (sql: string, dialect: string) => post<InjectionResult>("/api/inject", { sql, dialect }), |
| }; |
|
|