import { type H3Event } from 'h3';
import { type Ctx, type Shape } from './runtime.ts';
type App = {
    route: (template: string, base?: Shape) => (p: Record<string, unknown>, ctx?: Ctx, shape?: Shape) => Promise<any>;
    telemetry?: {
        error: (err: unknown, source: string, callId?: string) => void;
    };
};
type Params = Record<string, unknown>;
export type RouteOptions<U> = Omit<Shape, 'stamp' | 'where'> & {
    /** the app's own access check, with the URL's parameters; what it returns is handed to the functions below */
    guard?: (event: H3Event, params: Record<string, string>) => U | Promise<U>;
    /**
     * HTML form semantics for the body: a checkbox left unticked is absent, so
     * the named fields default to false; an emptied text field means null.
     */
    form?: {
        checkboxes?: string[];
        nullable?: string[];
    };
    /** answer a failed rule with its first message only, as some forms show */
    firstError?: boolean;
    /**
     * Which URL parameters name the row (all by default). `false` when they name
     * something else — `/articles/:id/similar` reads other articles than `:id`.
     */
    pin?: string[] | false;
    /** the fields a response keeps from each row (`author.name` for a relation's) */
    fields?: string[];
    /** a read answered with a file: `row => ({ path, name, type })` */
    download?: (row: Record<string, any>, p: Params) => {
        path: string;
        name?: string;
        type?: string;
        inline?: boolean;
        headers?: Record<string, string>;
    } | null;
    /** caller context for the runtime (role, userId), from the guard's result */
    ctx?: (user: U) => Ctx;
    /** conditions the route always applies, besides the row the URL names */
    where?: Record<string, unknown> | ((p: Params, user: U) => Record<string, unknown>);
    /** options that depend on the request: page, search, sort, extra conditions (may be async) */
    shape?: (p: Params, user: U, event: H3Event) => Shape | Promise<Shape>;
    /** the only body fields a caller may write (a reader's form must not set a status) */
    only?: string[];
    /**
     * Columns the route writes itself: who, when, a counter's `{ add: 1 }`, or a
     * stored upload's path. May be async; it runs once the guard has passed.
     */
    stamp?: (p: Params, user: U) => Record<string, unknown> | Promise<Record<string, unknown>>;
    /** values to use when the request leaves them out (may be async) */
    fill?: Record<string, (p: Params, user: U) => unknown>;
    /** each row on its way out */
    row?: (row: Record<string, any>) => Record<string, any>;
    /** the response, when the front expects something other than the default */
    reply?: (result: any, p: Params, user: U, event: H3Event) => unknown;
    /** the message of a 404 when nothing matched — or its whole `data`, with a `message` */
    notFound?: string | Record<string, unknown>;
};
/**
 * An h3 route that is a sentence.
 *
 *   export default sentenceRoute(app, 'supprime la categorie {id}', { guard: requireAdmin })
 *
 * Parameters come from the route params, the body and the query, in that order
 * of precedence. Three facts about the request are handed to the runtime
 * rather than re-read by the model from the sentence: the HTTP method fixes the
 * operation, an `id` in the URL fixes the row, and a body's fields are written
 * to the columns they name. See `route` for the template syntax and for how a
 * sentence is compiled once and reused.
 */
export declare function sentenceRoute<U = unknown>(app: App, template: string, opts?: RouteOptions<U>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
/**
 * A whole API as a table of sentences, served by one catch-all handler.
 *
 *   // server/api/[...].ts
 *   export default defineRoutes(app, {
 *     'GET /api/events': 'montre les evenements publies',
 *     'DELETE /api/admin/events/:id': { say: 'supprime l evenement {id}', guard: 'events' },
 *   }, { guards: { events: e => requirePerm(e, 'events') } })
 *
 * An entry is a sentence, or the options of `sentenceRoute` plus `say`, with
 * `guard` naming one of `guards` (or given as a function). `:name` segments are
 * parameters. Route files the app still has win over the table, so the table
 * holds what is a sentence and files hold what is code.
 */
export declare function defineRoutes<U = unknown>(app: App, table: Record<string, string | ((event: H3Event) => unknown) | (RouteOptions<U> & {
    say: string;
    guard?: string | RouteOptions<U>['guard'];
})>, opts?: {
    guards?: Record<string, (event: H3Event, params: Record<string, string>) => U | Promise<U>>;
    defaults?: RouteOptions<U>;
    /**
     * Mount as middleware (`server/middleware/`) rather than as a catch-all
     * route: a request the table does not hold falls through to the app's
     * files. Nitro answers 405 when a file serves the same path for another
     * method, which a catch-all route never gets to see.
     */
    passthrough?: boolean;
}): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<unknown>>;
/**
 * Files stored by a table's `files` columns, served back: the path is checked to
 * stay inside `dir`, the type follows the extension, and `guard` may refuse one
 * (a private photo) by throwing.
 *
 *   'GET /uploads/:name': serveFiles('uploads', { guard: (name, event) => ... })
 */
export declare function serveFiles(dir: string, opts?: {
    guard?: (name: string, event: H3Event) => unknown;
    maxAge?: number;
}): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
/**
 * A per-client limit on requests, as middleware: `rateLimit({ max: 20, windowMs: 60_000 })`.
 * In memory, so per process.
 */
export declare function rateLimit(opts: {
    max: number;
    windowMs: number;
    methods?: string[];
    message?: string;
}): import("h3").EventHandler<import("h3").EventHandlerRequest, void>;
export type FeedItem = {
    url: string;
    title?: string;
    date?: unknown;
    description?: string;
    image?: string | null;
    author?: string | null;
    category?: string | null;
    changefreq?: string;
    priority?: number;
};
/**
 * An RSS feed or a sitemap from rows — the rows a sentence route reads, mapped
 * to items. `sitemap-news` is Google News' flavour (last two days only).
 *
 *   'GET /rss.xml': feed('rss', { title: 'Le Journal', rows: () => latest(), item: a => ({ url: `/articles/${a.slug}`, title: a.title, date: a.published_at }) })
 */
export declare function feed(kind: 'rss' | 'sitemap' | 'sitemap-news', o: {
    rows: (event: H3Event) => Promise<Record<string, any>[]> | Record<string, any>[];
    item: (row: Record<string, any>) => FeedItem | null;
    /** the site's origin; the request's by default */
    site?: string | ((event: H3Event) => string);
    title?: string;
    description?: string;
    language?: string;
    /** pages that are not rows (the home page, static pages), for a sitemap */
    extra?: FeedItem[];
    maxAge?: number;
    /** sitemap-news: how many days back (2 by default, 0 for all) */
    days?: number;
}): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
/** `show_in_nav` → `showInNav`, for fronts written against an ORM that camelCases. */
export declare const camelRow: (row: Record<string, any>) => {
    [k: string]: any;
};
export {};
