/** * Function definition constructors. * * These are the primary API for defining server-side functions. * * Each constructor (query / mutation / action) has two overloads: * * 1. `auth` omitted, or `auth: "user" | "admin"` → the framework * enforces a real signed-in user, so the handler's * `ctx.auth.userId` is narrowed from `string | null` to * `string`. The redundant `if (!ctx.auth.userId) throw …` * check disappears from app code. * * 2. `auth: "public" | "guest"` → the function is reachable by * anonymous callers, so `ctx.auth.userId` stays `string | null` * and the handler must check it manually if relevant. * * The framework gate happens BEFORE the handler runs (in Rust, * inside the router). A handler can't accidentally leak data by * forgetting an auth check — when `auth: "user"` is in effect, * an anonymous request never reaches the handler at all. */ import type { FnDefinition, QueryCtx, MutationCtx, ActionCtx, ValidatorSchema, InferArgs } from "./types"; interface CommonDef { args?: TSchema; /** * When true, the function is callable only via `ctx.runQuery()` / * `ctx.runMutation()` / `ctx.runAction()` from another function * — never via the public `/api/fn/` HTTP endpoint. The * router refuses external calls with `404 FN_NOT_FOUND` so * probing can't even confirm the name exists. * * Use for helper functions that are safe inside trusted * wrappers but unsafe if any caller could invoke them directly * (e.g. they trust args without re-checking caller authority). * * Internal functions inherit the wrapping handler's auth — the * `auth` field has no effect when `internal: true`. The router * isn't reachable anyway, and the caller has already passed its * own gate. */ internal?: boolean; /** * IDLE-timeout SECONDS for this function: how long it may go without * producing any activity (a stream chunk, a `ctx.db` op, an LLM * event) before the host cancels the call. Defaults to * `PYLON_FN_CALL_TIMEOUT` (30s). Activity restarts the budget, so a * streaming agent run stays alive as long as it keeps producing; a * silent hang is cancelled at the budget. Total lifetime is capped at * 10× this value however chatty the call is. * * Cancellation is per-call: the handler's next `ctx.*` call throws * `CALL_CANCELLED` and `ctx.signal` aborts — other in-flight calls on * the same worker are untouched. CAVEAT: the database transaction * rolls back on cancel, but non-ctx work already in flight (a `fetch`, * a payment SDK call) runs to completion unless you pass * `{ signal: ctx.signal }` — a cancelled call can otherwise leave an * external effect committed with its DB writes rolled back. Thread * ctx.signal into every external call that must not outlive the * handler. Raise the timeout for legitimately long * SILENT work (a single slow external call, synchronous CPU work); * this also lifts the runtime's wedge backstop for the worker while * such a call is in flight, so a busy-but-progressing worker (e.g. * one doing synchronous canvas/image work that blocks the event loop) * isn't respawned out from under the work. */ timeout?: number; } interface QueryDefRequired extends CommonDef { /** Defaults to `"user"`. See [`AuthMode`] for the full surface. */ auth?: "user" | "admin"; handler: (ctx: QueryCtx<"required">, args: TArgs) => Promise; } interface QueryDefOptional extends CommonDef { auth: "public" | "guest"; handler: (ctx: QueryCtx<"optional">, args: TArgs) => Promise; } interface MutationDefRequired extends CommonDef { auth?: "user" | "admin"; handler: (ctx: MutationCtx<"required">, args: TArgs) => Promise; } interface MutationDefOptional extends CommonDef { auth: "public" | "guest"; handler: (ctx: MutationCtx<"optional">, args: TArgs) => Promise; } interface ActionDefRequired extends CommonDef { auth?: "user" | "admin"; handler: (ctx: ActionCtx<"required">, args: TArgs) => Promise; } interface ActionDefOptional extends CommonDef { auth: "public" | "guest"; handler: (ctx: ActionCtx<"optional">, args: TArgs) => Promise; } /** * Define a read-only query function. * * Queries use the read pool — they never block writes and can run * concurrently. They cannot modify data. * * @example * ```typescript * export default query({ * // auth: "user" is the default — ctx.auth.userId is `string`, * // not `string | null`, inside the handler. * args: { auctionId: v.string() }, * async handler(ctx, args) { * return ctx.db.query("Lot", { * auctionId: args.auctionId, * authorId: ctx.auth.userId, * }); * }, * }); * ``` * * @example * ```typescript * // Explicitly public — landing-page count, never auth-shaped. * export default query({ * auth: "public", * async handler(ctx) { * return ctx.db.query("PublicPost", { published: true }); * }, * }); * ``` */ export declare function query(def: QueryDefRequired, TReturn, TSchema> & { args: TSchema; auth?: TAuth; }): FnDefinition, TReturn>; export declare function query(def: QueryDefOptional, TReturn, TSchema> & { args: TSchema; auth: TAuth; }): FnDefinition, TReturn>; export declare function query, TReturn = unknown>(def: QueryDefRequired): FnDefinition; export declare function query, TReturn = unknown>(def: QueryDefOptional): FnDefinition; /** * Define a transactional mutation function. * * The entire handler IS the transaction. If it returns, all writes commit * atomically. If it throws, all writes roll back — including scheduled * functions. * * Mutations can stream data to the client via `ctx.stream.write()`. * Stream chunks are sent immediately; DB writes commit at the end. * * @example * ```typescript * export default mutation({ * args: { lotId: v.string(), amount: v.number() }, * async handler(ctx, args) { * // ctx.auth.userId is `string` (not nullable) — the runtime * // already enforced `auth: "user"` (default) before reaching here. * const lot = await ctx.db.get("Lot", args.lotId); * if (!lot) throw ctx.error("NOT_FOUND", "Lot not found"); * await ctx.db.insert("Bid", { * lotId: args.lotId, * amount: args.amount, * bidderId: ctx.auth.userId, * }); * return { accepted: true }; * }, * }); * ``` */ export declare function mutation(def: MutationDefRequired, TReturn, TSchema> & { args: TSchema; auth?: TAuth; }): FnDefinition, TReturn>; export declare function mutation(def: MutationDefOptional, TReturn, TSchema> & { args: TSchema; auth: TAuth; }): FnDefinition, TReturn>; export declare function mutation, TReturn = unknown>(def: MutationDefRequired): FnDefinition; export declare function mutation, TReturn = unknown>(def: MutationDefOptional): FnDefinition; /** * Define an action function (external I/O allowed). * * Actions can call external APIs (fetch, email, Stripe, etc.) but cannot * access the database directly. Use `ctx.runQuery()` and `ctx.runMutation()` * for DB access — each runs in its own transaction. * * Actions are NOT automatically retried because they may have side effects. * * **Important:** policies don't gate actions — `auth: "user"` (the * default) is the only thing protecting an action from anonymous calls. * An action that charges Stripe, hits a private API, or reads a * secret will respond happily to anonymous POSTs unless this gate * fires. Pick `auth: "public"` explicitly only when the endpoint is * meant to be open (a webhook receiver, a public form submit, …). * * @example * ```typescript * export default action({ * args: { lotId: v.string() }, * async handler(ctx, args) { * const lot = await ctx.runQuery("lotDetails", { lotId: args.lotId }); * await fetch("https://api.sendgrid.com/...", { ... }); * await ctx.runMutation("markNotified", { lotId: args.lotId }); * }, * }); * ``` * * @example * ```typescript * // GitHub webhook receiver — public because GitHub doesn't sign * // in, the handler verifies the signature itself, then optionally * // elevates. * export default action({ * auth: "public", * async handler(ctx) { * const ok = verifyGithubSignature(secret, ctx.request!.rawBody, sig); * if (!ok) throw ctx.error("INVALID_SIGNATURE", "bad sig"); * await ctx.auth.elevate({ admin: true, reason: "github webhook hmac" }); * // … * }, * }); * ``` */ export declare function action(def: ActionDefRequired, TReturn, TSchema> & { args: TSchema; auth?: TAuth; }): FnDefinition, TReturn>; export declare function action(def: ActionDefOptional, TReturn, TSchema> & { args: TSchema; auth: TAuth; }): FnDefinition, TReturn>; export declare function action, TReturn = unknown>(def: ActionDefRequired): FnDefinition; export declare function action, TReturn = unknown>(def: ActionDefOptional): FnDefinition; export {};