import type { H3Event } from "h3"; import { type DatabaseSchemaHealthResult } from "../db/runtime-diagnostics.js"; import { type AuthSession } from "./auth.js"; import { type BuilderConnectTrackingParams, type BuilderRelayCredentials } from "./builder-browser.js"; import type { EnvKeyConfig } from "./create-server.js"; /** * The base path prefix for all framework-level routes. * All agent-native core routes live under this namespace to avoid * collisions with template-specific `/api/*` routes. */ export declare const FRAMEWORK_ROUTE_PREFIX = "/_agent-native"; export declare const FRAMEWORK_EVENTS_ROUTE = "/_agent-native/events"; export declare const LEGACY_FRAMEWORK_EVENTS_ROUTE = "/_agent-native/poll-events"; export declare function normalizeAgentEngineStatusModel(entry: { name: string; defaultModel: string; supportedModels: readonly string[]; } | undefined, model: string | null | undefined): string; type AgentEngineStatusEntry = { name: string; defaultModel: string; supportedModels: readonly string[]; requiredEnvVars: readonly string[]; }; export interface AgentEngineStatusResult { configured: boolean; engine?: string; model?: string; source?: "settings" | "env" | "app_secrets"; envVar?: string; openAiBaseUrlConfigured?: boolean; } export interface AgentEngineStatusDeps { readStoredEngine: () => Promise<{ engine?: string; model?: string; } | null>; readOpenAiBaseUrlConfigured: () => boolean | Promise; isStoredEngineUsable: (stored: unknown, entry: E) => boolean | Promise; detectFromUserSecrets: () => Promise; detectFromEnv: () => E | null | Promise; lookupEntry?: (engine: string) => E | undefined; } /** * Resolve "does this request have a usable AI provider" for one identity. * * Every call site pays for these lookups on a user-visible path (the agent * composer blocks on the status probe), so the two identity-independent reads * start together and the expensive `app_secrets` sweep only runs when the * cheaper sources have not already answered. */ export declare function resolveAgentEngineStatus(deps: AgentEngineStatusDeps): Promise; /** * Share one in-flight status resolution between concurrent probes of the same * identity. Several client surfaces probe this route on mount and the client * retries after its own timeout; without this each probe re-ran the whole * credential sweep. The entry is dropped as soon as the lookup settles, so a * joiner never sees an answer older than one lookup — no TTL, nothing to * invalidate when a provider is added or removed. The key carries the identity * that decides the answer, so no tenant can read another's result. */ export declare function shareAgentEngineStatusLookup(identityKey: string, compute: () => Promise): Promise; export declare function agentEngineStatusIdentityKey(userEmail: string | undefined, orgId: string | undefined): string; export declare function getFrameworkEnvKeys(): EnvKeyConfig[]; /** Result of the `/_agent-native/health` liveness + DB-warmup probe. */ export interface DbHealthProbeResult { /** The serverless function is live and served the request. */ ok: true; /** Database + optional schema readiness for stricter production monitors. */ ready: boolean; /** A trivial `SELECT 1` reached the database (false = no DB or unreachable). */ db: boolean; /** Round-trip time of the probe in milliseconds. */ ms: number; /** Redacted database routing details useful for deploy/runtime checks. */ database: { configured: boolean; source: string; dialect: string; urlHash?: string; appName?: string; authTokenConfigured: boolean; netlifyDatabaseUrlConfigured: boolean; }; /** Optional metadata-only schema compatibility check. */ schema?: DatabaseSchemaHealthResult; } /** * Run a trivial `SELECT 1` to confirm the database is reachable and, as a side * effect, keep a scale-to-zero serverless database (e.g. Neon) warm. Touching * the DB on a schedule prevents the multi-second cold-start that otherwise * stalls the next real user request. * * Always resolves: an app with no database (or a momentarily unreachable one) * is still live, so the probe reports `db: false` rather than throwing. The * `exec` parameter is injectable purely for tests. */ export declare function runDbHealthProbe(exec?: () => { execute: (sql: string) => Promise; }, options?: { schema?: boolean; }): Promise; interface BuilderWaitlistFormTarget { formId: string; formsOrigin: string; } export interface BuilderWaitlistBody { email?: unknown; prompt?: unknown; orgName?: unknown; appUrl?: unknown; pageUrl?: unknown; source?: unknown; template?: unknown; useCase?: unknown; } export declare function resolveFrameworkSseRoutes(sseRoute?: string): string[]; export declare const BUILDER_STATUS_ROUTE_SUFFIXES: readonly ["/builder/status", "/connection-status/builder"]; export declare function mountBuilderStatusRouteAliases(mount: (path: string, handler: T) => void, prefix: string, handler: T): void; export declare function isAnonymousWaitlistSessionEmail(email: string): boolean; export declare function resolveWaitlistEmail(sessionEmail: string | undefined, bodyEmail: unknown): string | null; export declare function checkBuilderWaitlistRateLimit(event: H3Event, email: string, now?: number): { ok: true; } | { ok: false; retryAfterSeconds: number; }; export declare function resetBuilderWaitlistRateLimitForTests(): void; export declare function resolveBuilderWaitlistFormTargetForRequest(event: H3Event): BuilderWaitlistFormTarget | null; export declare function buildBuilderWaitlistFormPayload(event: H3Event, sessionEmail: string, body: BuilderWaitlistBody): { data: { email: string; orgName: string; appUrl: string; prompt: string; source: string; template: string; useCase: string; }; _hp: string; _meta: { submitterEmail: string; pageUrl: string; source: string; template: string; useCase: string; }; }; export declare const AVATAR_RASTER_MIME: RegExp; export declare function resolveAvatarEmailParam(pathname: string, appBasePath?: string): string; type BuilderAnonymousOwnerResolver = (event: H3Event) => string | null | Promise; export type BuilderOwnerContext = { email: string | undefined; session: AuthSession | null; anonymous: boolean; }; export declare function resolveBuilderOwnerContextForRequest(event: H3Event, options?: { anonymousOwner?: BuilderAnonymousOwnerResolver; getSessionForEvent?: (event: H3Event) => Promise; }, mode?: "connect" | "callback"): Promise; /** * Resolves the page-level legacy `/tools` → `/extensions` redirect target. * * Returns the absolute path (with optional query string) to redirect to, * or `null` if the request should fall through to the SPA / next handler. * * Skips: * - Framework API namespace (`/_agent-native/tools/*` is handled separately * as a legacy alias and intentionally stays mounted as `tools`). * - Anything that isn't `/tools` or a `/tools/...` page navigation, after * the configured app base path is stripped off. * * Exported for tests; the runtime middleware below is a thin wrapper. */ export declare function resolveLegacyToolsRedirect(rawPath: string, search: string): string | null; export declare function getFrameworkRouteRequestUrl(event: H3Event): URL; export interface BuilderRelayPendingRecord { ownerEmail: string; orgId: string | null; role: string | null; targetOrigin: string; basePath: string; expiresAt: number; tracking?: BuilderConnectTrackingParams; } export interface ConsumeBuilderRelayDependencies { getPending: (key: string) => Promise | null>; deletePending: (key: string) => Promise; writeCredentials: (ownerEmail: string, credentials: BuilderRelayCredentials, scope: { orgId: string | null; role: string | null; }) => Promise; } /** * Authenticated one-shot receiver for the second hop of Builder preview auth. * Owner and org scope always come from the preview's pending record; the * corporate callback cannot choose them in its POST body. */ export declare function consumeBuilderRelayRequest(input: { rawBody: string; timestamp: string | null | undefined; flowId: string | null | undefined; signature: string | null | undefined; requestOrigin: string; requestBasePath: string; now?: number; }, dependencies: ConsumeBuilderRelayDependencies): Promise<{ ok: true; } | { ok: false; status: number; error: string; }>; export declare function readBuilderRelayRequestBody(event: H3Event): Promise; type NitroPluginDef = (nitroApp: any) => void | Promise; export interface CoreRoutesPluginOptions { /** Route path for the SSE endpoint. Default: "/_agent-native/events" */ sseRoute?: string; /** Disable the SSE endpoint entirely. */ disableSSE?: boolean; /** Disable the /_agent-native/ping health check. */ disablePing?: boolean; /** Disable the /_agent-native/health DB liveness + warmup probe. */ disableHealth?: boolean; /** Disable the /_agent-native/application-state routes. */ disableAppState?: boolean; /** Disable the /_agent-native/open deep-link route. */ disableOpenRoute?: boolean; /** Disable the /_agent-native/embed/start iframe session launcher. */ disableEmbedRoute?: boolean; /** * Disable the /mcp/connect routes (browser Connect page + CLI device-code * flow that mints per-user, revocable MCP tokens) and the standard remote-MCP * OAuth endpoints under /mcp/oauth. The legacy /_agent-native/mcp aliases * are disabled at the same time. * Enabled by default — the routes are session-gated where they approve user * access; token endpoints are protected by single-use codes / refresh * tokens. */ disableMcpConnect?: boolean; /** Canonical app id (e.g. `mail`) for the MCP connect server name. */ mcpConnectAppId?: string; /** Explicit MCP server id for copyable config/device-flow grants. */ mcpConnectServerName?: string; /** Human app name shown on the MCP connect page. */ mcpConnectAppName?: string; /** Per-template override mapping deep-link params → client SPA path. * See `createOpenRouteHandler`. */ resolveOpenPath?: import("./open-route.js").OpenRouteOptions["resolveOpenPath"]; /** Per-template allowlist for open-route targets that may redirect without * a browser session. See `createOpenRouteHandler`. */ allowUnauthenticatedOpen?: import("./open-route.js").OpenRouteOptions["allowUnauthenticatedOpen"]; /** Env key configuration. Enables env-status and env-vars routes. */ envKeys?: EnvKeyConfig[]; /** * Optional owner resolver for narrowly-scoped public routes. Used by public * pages that let anonymous viewers connect Builder credentials for their * own browser-scoped agent session. */ anonymousOwner?: BuilderAnonymousOwnerResolver; } interface LegacyCoreRouteInitSettings { persistedEnvVars: Record | null; builderDisconnected: { at?: number; } | null; } type CoreRouteSettingReader = (key: string) => Promise | null>; export declare function readLegacyCoreRouteInitSettings(readSetting?: CoreRouteSettingReader): Promise; /** * Creates a Nitro plugin that mounts all standard agent-native framework routes. * * All routes are mounted under `/_agent-native/` to avoid collisions * with template-specific routes. * * Routes: * GET /_agent-native/poll — polling endpoint for change detection * GET /_agent-native/events (or custom) — SSE endpoint for real-time sync * GET /_agent-native/ping — health check * GET /_agent-native/health — DB liveness probe + scale-to-zero warmup * GET /_agent-native/env-status — env key configuration status (when envKeys provided) * POST /_agent-native/env-vars — compatibility route that saves keys to scoped DB secrets * GET /_agent-native/application-state/:key — read application state * PUT /_agent-native/application-state/:key — write application state * DELETE /_agent-native/application-state/:key — delete application state * GET /_agent-native/application-state/compose — list compose drafts * DELETE /_agent-native/application-state/compose — delete all compose drafts * GET /_agent-native/application-state/compose/:id — get compose draft * PUT /_agent-native/application-state/compose/:id — upsert compose draft * DELETE /_agent-native/application-state/compose/:id — delete compose draft */ export declare function createCoreRoutesPlugin(options?: CoreRoutesPluginOptions): NitroPluginDef; /** * Default core routes plugin — mount with no configuration needed. * * Usage in templates: * ```ts * // server/plugins/core-routes.ts * export { defaultCoreRoutesPlugin as default } from "@agent-native/core/server"; * ``` */ export declare const defaultCoreRoutesPlugin: NitroPluginDef; export {}; //# sourceMappingURL=core-routes-plugin.d.ts.map