/**
 * The wire contract for a `table` panel's sort/filter state, and the helper a
 * provider uses to read it back.
 *
 * Sorting and filtering a dashboard table are done **server-side**: the UI never
 * holds more than the page it is showing, so sorting in the browser would sort
 * 50 rows out of 50,000 and quietly present the result as "the top of the list".
 * The state therefore travels to the provider the same way `page`/`limit`
 * already do — merged into the panel's `data.query` and serialized as query
 * params on `GET /telescope/api/ext/<ext>/data/<provider>`.
 *
 * Everything here is **additive**: a provider that never reads these params
 * behaves exactly as it did before they existed, and a panel whose columns
 * declare no `sortable`/`filterable` flag never sends them.
 *
 * The wire shape, flat because the query object is serialized through
 * `URLSearchParams` (a nested object would arrive as the string
 * `"[object Object]"`):
 *
 * ```text
 * ?page=2&limit=50&sort=duration&dir=desc&filter.status=failed
 * ```
 *
 * Note that params arrive as **strings** — the host controller passes
 * `@Query()` through verbatim — which is exactly the trap {@link readTableQuery}
 * exists to close: `query.page > 1` is `false` for the string `'2'`, silently,
 * with no type error to catch it.
 */
/** Query-param key naming the column the table is sorted by. */
export declare const TABLE_SORT_PARAM = "sort";
/** Query-param key carrying the sort direction (`'asc'` / `'desc'`). */
export declare const TABLE_SORT_DIR_PARAM = "dir";
/**
 * Prefix that namespaces a per-column filter — `filter.status=failed` filters
 * the column whose `key` is `status`.
 *
 * Prefixed rather than flat so a filterable column can never collide with a
 * param the panel itself declared in `data.query` (a panel with a static
 * `{ status: 'running' }` scope AND a filterable `status` column is an ordinary
 * combination, and one silently overwriting the other would be a bug nobody
 * could see from the outside).
 */
export declare const TABLE_FILTER_PREFIX = "filter.";
/** Which column a table is sorted by, and which way. */
export interface TableSort {
    /** The `Column.key` of the sorted column. */
    key: string;
    dir: 'asc' | 'desc';
}
/** A table panel's paging + sort + filter request, normalized off the raw query. */
export interface TableQuery {
    /** 1-based page, present only for a `paged: true` panel. */
    page?: number;
    /** Requested page size, present only for a `paged: true` panel. */
    limit?: number;
    /** Absent when the table is unsorted (the provider's own default order wins). */
    sort?: TableSort;
    /** Per-column filter text, keyed by `Column.key`. Empty when nothing is filtered. */
    filters: Record<string, string>;
}
/**
 * Normalizes the sort/filter/paging params out of a provider's raw `query`.
 *
 * Written as a guard-per-field rather than a cast: `query` is genuinely
 * untrusted — it is whatever was in the URL — and every field has a safe absent
 * behaviour, so a hand-typed `?sort=` or `?page=banana` degrades to "unsorted" /
 * "first page" instead of reaching a SQL builder as `NaN`.
 *
 * @example
 * ```ts
 * const provider: DataProvider = {
 *   name: 'durable.runs',
 *   async resolve(query) {
 *     const { page = 1, limit = 50, sort, filters } = readTableQuery(query);
 *     const rows = await store.findRuns({
 *       offset: (page - 1) * limit,
 *       limit,
 *       orderBy: sort ? { [sort.key]: sort.dir } : { startedAt: 'desc' },
 *       where: filters,
 *     });
 *     return { rows: rows.items, total: rows.total, page, limit };
 *   },
 * };
 * ```
 */
export declare function readTableQuery(query: Record<string, unknown> | undefined): TableQuery;
//# sourceMappingURL=table-query.d.ts.map