/** * The door. Everything an app's SQL is allowed to say, and the ONE place * `mine.` becomes one person's rows. * * Generated SQL is HOSTILE INPUT. What keeps one person out of another's rows * is not anything the model writes, and not a privilege of the host's database * either — a BYO Postgres url is very often a superuser, and a fence that * evaporates when the operator's role is too strong is not a fence. So the * fence is NAME RESOLUTION, in four layers: * * 1. `mine.x` and `shared.x` are the only table addresses that exist. They * become physical names carrying a ":" — a character no identifier this * grammar admits can contain — so a physical table has no spelling inside * an app's SQL, and one person's tables have no spelling in another's. * 2. Unqualified names resolve inside the app's own namespace and nowhere * else (the adapter's half), so a name that somehow got past layer 1 still * cannot leave the app. * 3. Any qualifier that is not `mine`/`shared` is handed back to the caller, * which refuses it when the database says it names a real schema. Table * aliases pass; `public.vendo_records` does not. * 4. ONE statement, from a short allowlist, with no session, role, schema or * catalog verb anywhere in it. * * Anything this file cannot account for is REFUSED, never guessed at. */ import { type RiskLabel } from "@vendoai/core"; /** What a statement DOES, graded before it runs, so a running app's SELECT can take the query arm the ui kit's `useToolQuery` needs. Pessimistic on purpose: it reads the raw text (a keyword inside a string counts), because over-grading costs an approval card and under-grading costs a silent write. Cheap and total — it never throws, and the guard proper still runs after. */ export declare const sqlRisk: (sql: string) => RiskLabel; export interface GuardedSql { /** The statement with every `mine.`/`shared.` address replaced by its physical name, and `?` markers spelled for the dialect. */ sql: string; /** Changes the app's schema. When it also touches `mine.`, it is recorded in the app's DDL log and replayed for everyone else who opens the app. */ ddl: boolean; /** Touches at least one `mine.` table. */ mine: boolean; /** Every qualifier that was neither `mine` nor `shared` — aliases, unless the database says one of them is a schema, which the caller checks. */ qualifiers: string[]; } /** what happened · why · fix — the sentence a table with no namespace earns. */ export declare const unnamespaced: (name: string) => never; /** The physical name of a table. The ":" is the fence: no name the grammar above admits can contain one, so these are unwritable from inside an app's SQL and unguessable across people. */ export declare const sharedTable: (name: string) => string; export declare const mineTable: (owner: string, name: string) => string; export declare const templateOf: (sql: string, owner: string) => string; export declare const replayFor: (template: string, owner: string) => string; /** The statement, guarded and rewritten for ONE person. Throws with what·why·fix on anything it will not run. */ export declare function guardSql(sql: string, owner: string, dialect: "postgres" | "sqlite"): GuardedSql; //# sourceMappingURL=app-sql-guard.d.ts.map