import type { H3Event } from "h3"; import type { CredentialFixer } from "../agent/engine/credential-state.js"; export { normalizeAgentEngineStatusModel, resolveAgentEngineStatus, type AgentEngineStatusResult, type AgentEngineStatusResponse, type AgentEngineStatusDeps, } from "../agent/engine-status.js"; import { type AppStateAnonymousOwnerResolver } from "../application-state/handlers.js"; import { type AuditAttribution } from "../audit/attribution.js"; import { type DatabaseSchemaHealthResult } from "../db/runtime-diagnostics.js"; import { ensureS3FileUploadProvider } from "../file-upload/s3.js"; import { type RemoteAgentAuth, type RemoteAgentKind } from "../resources/metadata.js"; import { getSetting, deleteSetting, mutateSetting, listSettingsByPrefix } from "../settings/store.js"; import { isAnonymousWaitlistSessionEmail } from "./anonymous-identity.js"; import { type AuthSession } from "./auth.js"; import { type BuilderConnectTrackingParams, type BuilderRelayCredentials } from "./builder-browser.js"; import { deleteBuilderOAuthSession, getBuilderOAuthGrants, hasStoredBuilderOAuthGrant, type BuilderConnectionScope, type BuilderOAuthGrantSummary, type BuilderOAuthScope } from "./builder-oauth.js"; import { type CoreRoutesMcpOptions, type ResolvedCoreRoutesMcp } from "./core-routes/mcp-connect-options.js"; import type { EnvKeyConfig } from "./create-server.js"; import { getBuilderKeyConnections } from "./credential-provider.js"; import { type DatabaseIdentityReadResult } from "./database-identity.js"; import { type DbPressure } from "./db-pressure.js"; import { type H3AppShim } from "./framework-request-handler.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"; /** * Resolve the identity the status answer depends on. Both lookups memoize per * request inside their own helpers, so repeating them here stays cheap. */ export declare function resolveAgentEngineStatusIdentity(event: H3Event): Promise<{ userEmail: string | undefined; orgId: string | undefined; orgScope?: "personal"; }>; /** * Shared Builder grants stay org-scoped, but connect initiation can come from * any authenticated member. Revocation still needs owner/admin authority. * Capture the org id at connect start so the grant is stored under the org * that was authorized, not one re-resolved after the OAuth round trip. */ export declare function resolveBuilderOrgMutation(event: H3Event, options?: { allowMemberInitiation?: boolean; }): Promise<{ orgId: string | null; role: string | null; deny: string | null; whoCanFix?: CredentialFixer; }>; export declare const BUILDER_CONNECT_NEEDS_ORGANIZATION = "Builder.io access is managed through an organization. Switch to one you belong to, or ask an organization owner or admin to invite you, then set up Builder.io again."; export declare const BUILDER_CONNECT_SESSION_NOT_SHARED = "This window can't see your sign-in, which happens in previews and embedded browsers. Open the app in its own browser tab, sign in, then set up Builder.io there."; export declare const BUILDER_ORG_MEMBERSHIP_UNREADABLE = "Couldn't check your organization membership. Try starting Builder.io setup again in a moment."; export declare const BUILDER_ORG_ALREADY_CONNECTED = "Your organization already has a Builder.io connection, and a new account would take its place. An organization owner or admin can sign in to Builder.io again in Settings."; export declare const BUILDER_ORG_RECONNECT_BY_LOGIN = "Your organization already has a Builder.io account. Sign in to Builder.io to use it."; /** Query/body field naming which Builder.io connection a request targets. */ export declare const BUILDER_CONNECTION_SCOPE_PARAM = "scope"; /** * `null` means the caller named no connection: connect then decides custody * by role and disconnect removes the first stored grant, as older clients * expect. Anything else that isn't a known scope is refused, never guessed. */ export declare function parseBuilderConnectionScope(value: unknown): BuilderConnectionScope | null | "invalid"; /** * Who may start a connect for the named Builder.io connection. The org * connection needs owner/admin; a personal one is for members only, and only * while the org allows personal grants. */ export declare function resolveBuilderConnectAuthorization(event: H3Event, ownerEmail: string, scope: BuilderConnectionScope | null): Promise<{ orgId: string | null; role: string | null; deny: string | null; }>; /** * A connect that names no connection lands as a personal grant for anyone who * isn't an owner or admin, so it is refused while personal keys are * restricted. Returns the refusal, or null. */ export declare function resolveScopelessBuilderConnectRestriction(event: H3Event, ownerEmail: string): Promise; /** * Decide custody when the OAuth callback lands, from the connector's role *now* * in the organization the flow started in. The start-time role only records * intent: a promotion, a demotion, or switching the active organization during * the OAuth round trip must not land a grant the connector can no longer hold. * An owner or admin connects for the organization and never personally, since * a personal grant would shadow the org's connection for them; anyone else * connects personally only while the org allows personal grants. A flow that * started in an organization the connector has since left is refused outright: * the policy check doesn't look at membership, so falling through to a personal * grant would hand a removed member a working connection. */ export declare function resolveBuilderCallbackWrite(input: { requestedScope: BuilderConnectionScope | null; pendingOrgId: string | null; /** The connector's current role in `pendingOrgId`, or null when not a member. */ currentRole: string | null; /** Whether the org's policy allows this connector a personal grant. */ personalAllowed: boolean; }): { scope?: BuilderOAuthScope; role: string | null; } | { deny: string; }; /** * Where a new Builder.io account from account activation is stored, or why it * is refused (see `decideCredentialWriteScope`). The connect route has already * refused a personal write the org's policy restricts. */ export declare function resolveBuilderActivationWrite(input: { requestedScope: BuilderConnectionScope | null; orgId: string | null; role: string | null; /** The org already holds a Builder.io grant or key pair. */ orgConnected: boolean; }): { orgId: string; role: string; } | null | { deny: string; code: "account_exists" | "not_permitted"; }; /** * Whether account activation may provision a new Builder.io account, and where * it is stored. Decided before provisioning, so a refused activation never * leaves an orphaned account behind. */ export declare function decideBuilderActivation(event: H3Event, input: { ownerEmail: string; requestedScope: BuilderConnectionScope | null; /** The membership a named-scope connect already resolved. */ member?: { orgId: string | null; role: string | null; deny: string | null; }; }, hasOrgConnection?: typeof hasBuilderOrgConnection): Promise<{ write: { orgId: string; role: string; } | null; } | { refuse: { status: number; message: string; reason: string; code: string; }; }>; declare function hasBuilderOrgConnection(ownerEmail: string, orgId: string): Promise; export type BuilderEffectiveConnection = "personal" | "org" | "workspace" | "env"; export declare function builderEffectiveConnectionFor(source: "user" | "org" | "workspace" | "env" | null | undefined): BuilderEffectiveConnection | null; export declare function hasUsableBuilderCredentialPair(credentials: { privateKey: string | null; publicKey: string | null; lookupFailed: boolean; }): credentials is { privateKey: string; publicKey: string; lookupFailed: false; }; /** * How a Builder.io connection is held. Account activation and older connect * flows store a key pair instead of an OAuth grant, and that pair is just as * much the org's or the member's connection. */ export type BuilderConnectionKind = "oauth" | "keys"; export type BuilderConnectionGrant = BuilderOAuthGrantSummary & { kind: BuilderConnectionKind; }; export interface BuilderConnectionGrants { org?: BuilderConnectionGrant; personal?: BuilderConnectionGrant & { /** Stored, but the org's personal-key restriction keeps it unused. */ restricted: boolean; }; } export interface BuilderConnectionsStatus { /** * The caller's stored Builder.io connections, org and personal read * independently. `{}` means none exist; `null` means the credential store * could not be read. */ grants: BuilderConnectionGrants | null; /** * Which connection this caller may connect or reconnect. Disconnecting the * org connection needs `org`; anyone may disconnect their own personal one. */ canConnect: Record; } export interface BuilderConnectionsStatusDeps { getGrants: typeof getBuilderOAuthGrants; getKeyConnections: typeof getBuilderKeyConnections; } export declare function resolveBuilderConnectionsStatus(input: { ownerEmail: string | null | undefined; orgId: string | null; role: string | null; }, deps?: BuilderConnectionsStatusDeps): Promise; export interface BuilderScopedDisconnectDeps { hasStoredGrant: typeof hasStoredBuilderOAuthGrant; deleteGrant: typeof deleteBuilderOAuthSession; /** Key pairs stored at each scope; throws when the store is unreadable. */ getKeyConnections: typeof getBuilderKeyConnections; deleteLegacy: (email: string, options?: { orgId?: string | null; role?: string | null; }) => Promise; recordAudit: typeof recordBuilderConnectionAudit; } /** * Disconnect exactly one Builder.io connection. The org connection needs an * owner/admin and removes the org grant plus any org-scoped legacy keys, which * would otherwise take over once the grant is gone. A personal disconnect * removes only the caller's own grant and keys, so members fall back to the * org's connection. A successful disconnect is recorded in the audit log at * the connection's scope. */ export declare function disconnectBuilderConnectionAtScope(input: { email: string; orgId: string | null; role: string | null; scope: BuilderConnectionScope; attribution: AuditAttribution; }, deps?: BuilderScopedDisconnectDeps): Promise<{ status: 200; body: { ok: true; scope: BuilderConnectionScope; remoteRevoked?: boolean; warning?: string; }; } | { status: 403 | 409; body: { error: string; }; }>; export declare function getFrameworkEnvKeys(): EnvKeyConfig[]; 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; /** * The probe hit its deadline instead of answering. Reported SEPARATELY from * `db: false`, because "the database said no" and "the database never * replied" are different failures and folding them together is exactly the * coercion this repo bans — a monitor cannot tell an app with no database * from one whose database is hanging. */ dbTimedOut?: 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; urlHash?: string; /** Pooler-agnostic identity of the physical database — see getDatabaseRuntimeFingerprint(). */ fingerprint?: string; appName?: string; netlifyDatabaseUrlConfigured: boolean; /** * Which app first recorded owning this database (the `beta.`/`` * pair share one). Present only when `db` is true — the read reuses the * connection the `SELECT 1` above just confirmed. `"timeout"` is its own * state distinct from `"unreadable"`: a hung read must never be reported * as "nothing recorded". */ identity?: DatabaseIdentityReadResult | { state: "timeout"; }; /** * True only when `identity.state === "recorded"` and the recorded app * differs from the app running this probe. Every other identity state * reports `false` — "not confirmed mismatched", never "confirmed * matching". */ identityMismatch?: boolean; /** * What this runtime believes its own app is (`app.slug ?? app.id`), or * `null` when the bundle cannot derive one. A null here is why a * mismatch cannot be claimed, and is itself a finding worth reading. */ runningApp?: string | null; }; /** * Hosted-realtime wiring, so a deploy can be verified without signing in. * * Registration is otherwise lazy behind the session-gated token mint, which * made "is this deploy actually on the gateway?" unanswerable until a real * user showed up. Resolving it here answers that with a curl — and, because * resolution registers on a miss, performs the registration too, the same way * this probe already warms a cold database. */ realtime: { /** `"hosted"` only when the transport env var is set. */ transport: "hosted" | "local"; /** A channel resolved — injected by the pipeline, or self-registered. */ registered: boolean; /** * First 8 chars of a SHA-256 of the channel id. This endpoint is public and * the channel id is half the gateway's auth story, so it is fingerprinted * rather than published — enough to tell two deploys apart or confirm a * rotation, useless for connecting. Mirrors `database.urlHash`. */ channelHash?: string; /** * Resolution FAILED, reported separately from `registered: false`. On a * diagnostic endpoint the difference is the whole point: "this deploy has * no channel" and "we could not find out" send you to different places. * Same split as `dbTimedOut` above. */ unavailable?: true; }; /** Optional metadata-only schema compatibility check. */ schema?: DatabaseSchemaHealthResult; /** * Optional `pg_stat_activity` pressure counters. Present only when asked for, * and shaped so "could not measure" cannot be read as "nothing wrong". */ pressure?: DbPressure; } export declare function runDbHealthProbe(exec?: () => { execute: (sql: string) => Promise; }, options?: { schema?: boolean; pressure?: 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 const BUILDER_STATUS_LEGACY_CREDENTIAL_KEYS: readonly ["BUILDER_PRIVATE_KEY", "BUILDER_CMS_PRIVATE_KEY"]; export declare function mountBuilderStatusRouteAliases(mount: (path: string, handler: T) => void, prefix: string, handler: T): void; export { isAnonymousWaitlistSessionEmail }; 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 | undefined; appUrl: string; prompt: string | undefined; source: string; template: string | undefined; useCase: string; }; _hp: string; _meta: { submitterEmail: string; pageUrl: string; source: string; template: string | undefined; useCase: string; }; }; export declare const AVATAR_RASTER_MIME: RegExp; export declare function resolveAvatarEmailParam(pathname: string, appBasePath?: string): string; /** * Scope of the connection a role-decided disconnect removed: the stored OAuth * grant's scope, else the legacy keys' scope. Only org-scoped legacy keys are * deleted with options. */ export declare function builderDisconnectAuditScope(oauthScope: "user" | "org" | null, legacyDeleteOptions: object | undefined): "user" | "org"; export declare function recordBuilderConnectionAudit(input: { connected: boolean; ownerEmail: string; orgId: string | null | undefined; scope: "user" | "org"; attribution: AuditAttribution; }): Promise; export declare function isBuilderConnectCallbackOwner(pendingOwner: string, sessionOwner: string | undefined): boolean; export declare function consumeBuilderConnectPendingState(state: string, dependencies?: { mutate: typeof mutateSetting; remove: typeof deleteSetting; }): Promise | null>; export declare function readBuilderConnectPendingState(state: string, read?: typeof getSetting): Promise | null>; /** * Narrows cookie-recovered states to the flows that could still complete. * Returns null when the pending store cannot be read: unreadable is not the * same as dead, and treating it as dead would discard live flows. */ export declare function selectLiveBuilderConnectStates(states: string[], now?: number, read?: typeof getSetting): Promise; export declare function purgeExpiredBuilderConnectPendingStates(now?: number, dependencies?: { list: typeof listSettingsByPrefix; remove: typeof deleteSetting; }): Promise; 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 { /** * Allow authenticated extension creation through * POST /_agent-native/extensions (and the legacy /tools alias). * Existing extension runtime, read, edit, and deep-link routes stay mounted * when this is false. Default: false. */ extensionTools?: boolean; /** Route path for the SSE endpoint. Default: "/_agent-native/events" */ sseRoute?: string; /** Disable the SSE endpoint entirely. */ disableSSE?: boolean; /** * Close an SSE stream after this many milliseconds instead of holding it * open indefinitely, so the stream ends at 200 and the client reconnects * instead of the platform killing the invocation and recording a runtime * timeout. Only applies on a long-lived host, or a production serverless * request from a bundle old enough to still stream (see the SSE mount) — * a request that opts into the 204 short-circuit never reaches the stream, * so this value is unused for it. Default: unset (no cap). * `createCoreRoutesPlugin` throws on a zero, negative, or non-finite value. */ sseMaxDurationMs?: number; /** Disable the /_agent-native/ping health check. */ disablePing?: boolean; /** Disable the /_agent-native/health DB liveness + warmup probe. */ disableHealth?: boolean; /** * Callback paths emitted by this app's Google OAuth health contract. The * default is the shared framework callback; app-owned callbacks must opt in * so fleet probes read the deployed app instead of guessing from a hostname. */ googleOAuthCallbackPaths?: string[]; /** Whether the managed Google client is deployment- or user-scoped. */ googleOAuthCredentialMode?: "managed" | "user"; /** * Whether this app exposes deployment-level Google workspace OAuth. Custom * core-route plugins must declare this; the framework default declares that * managed OAuth is not applicable. */ googleOAuthManagedConnection?: "required" | "not_applicable"; /** Disable the /_agent-native/application-state routes. */ disableAppState?: boolean; /** * Let anonymous visitors keep application state under the owner that * `anonymousOwner` resolves, instead of answering them 401. For apps whose * chat or pages run for visitors without a session (a guest chat): the * client's navigation, URL and composer preference sync then works for them * too. Off by default, since every anonymous visitor then gets state rows. */ anonymousApplicationState?: boolean; /** Disable the /_agent-native/open deep-link route. */ disableOpenRoute?: boolean; /** Disable the /_agent-native/embed/start iframe session launcher. */ disableEmbedRoute?: boolean; /** * Everything about this app's MCP connect surface — whether the Connect page * and OAuth endpoints are mounted, and the server id clients key it by. * See `CoreRoutesMcpOptions`. * * Replaces the top-level `disableMcpConnect`, `mcpConnectServerName`, * `mcpConnectAppId`, and `mcpConnectAppName`, which stay accepted for one * minor. Setting both forms to disagreeing values throws at plugin init * rather than silently picking one. */ mcp?: CoreRoutesMcpOptions; /** @deprecated Use `mcp.connect: false`. */ disableMcpConnect?: boolean; /** @deprecated Use `mcp.serverName`. */ mcpConnectServerName?: string; /** @deprecated Set `app.id` in `defineAppConfig()`. */ mcpConnectAppId?: string; /** @deprecated Set `app.name` in `defineAppConfig()`. */ 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; /** * Production release jobs own schema setup. Request functions must not spend * their cold-start budget on legacy cleanup or best-effort table warmups. */ export declare function shouldRunCoreRouteBootDatabaseWork(env?: NodeJS.ProcessEnv): boolean; /** Public discovery is a picker, not a credential registry. */ export declare function stripRemoteAgentAuth(agent: T): Omit; /** Credentialed probes may only replay a saved, access-scoped connection. */ export declare function matchesSavedHostedAgentProbe(agent: { url: string; cardUrl?: string; auth?: RemoteAgentAuth; kind?: RemoteAgentKind; }, requested: { url: string; cardUrl?: string; auth?: RemoteAgentAuth; kind?: RemoteAgentKind; }): boolean; type PublicAgentDiscovery = (selfAppId?: string) => Promise; export declare function createPublicRemoteAgentsHandler(discover?: PublicAgentDiscovery): import("h3").EventHandlerWithFetch[]; }>>; export declare function getBuilderConnectErrorDisposition(error: unknown, connectAttemptId: string | null): "correlated" | "legacy" | null; export declare function getBuilderConnectErrorKey(ownerEmail: string, connectAttemptId?: string | null): string; type BuilderConnectMember = { orgId: string | null; role: string | null; deny: string | null; }; export type BuilderAccountActivationResult = { ok: true; scope: "user" | "org"; } | { ok: false; status: number; message: string; /** Why it failed, for tracking. */ reason: string; /** What the client acts on, when it differs from a plain failure. */ code?: string; }; interface BuilderAccountActivationInput { ownerEmail: string; session: AuthSession | null; provisioningToken: string | null | undefined; requestedScope: BuilderConnectionScope | null; /** The membership `authorizeBuilderConnectScope` resolved. */ member: BuilderConnectMember | null; connectAttemptId: string | null; tracking: BuilderConnectTrackingParams; } /** * One-click Builder.io account activation: create the account with one * signed server-to-server call and store its keys for the signed-in owner. * `POST /builder/provision` and the popup-era `GET /builder/connect` provision * mode both run exactly this, after `authorizeBuilderConnectScope`. */ export declare function activateBuilderAccount(event: H3Event, input: BuilderAccountActivationInput): Promise; /** * `POST /_agent-native/builder/provision` — one-click Builder.io account * activation as a single JSON request, no popup. Session cookies are * SameSite=None, so this requires a JSON body (a cross-site form cannot send * one without a preflight), the same-origin gate `/builder/connect` uses, and * the provisioning token from `/builder/status`, which is bound to the * caller's session and readable only by the app itself. */ export declare function createBuilderProvisionHandler(resolveOwnerContext: (event: H3Event) => Promise): import("h3").EventHandlerWithFetch>; export { ensureS3FileUploadProvider }; export interface OAuthCustodyBuilderKeyStatus { privateKeyConfigured: boolean; publicKeyConfigured: boolean; orgName: string; /** * True when the key-pair lookup itself failed (credential store * unreadable, org lookup error, a thrown import) rather than confirming * no keys exist. privateKeyConfigured/publicKeyConfigured stay `false` in * both cases — this is the only signal that tells "never configured" * apart from "couldn't check right now", so a transient store blip can't * read downstream as "the user never connected Builder keys". */ keyLookupFailed: boolean; optionalMetadataLookupFailure?: "unreadable" | "unavailable"; } export declare function hasUnavailableBuilderCredentialPair(credentials: { privateKey: string | null; publicKey: string | null; lookupFailed: boolean; }): boolean; /** * Resolves the classic Builder key-pair status for a request that already * has Builder MCP OAuth custody (the connection-status handler's `configured` * is already `true` by the time this runs — OAuth alone proves the chat * gateway). Exported so the connection-status route's OAuth-custody branch is * unit-testable without standing up the full plugin. */ export declare function resolveOAuthCustodyBuilderKeyStatus(dependencies?: { role?: string | null; resolveOrgCredentialPair?: () => Promise<[string, string] | null>; resolveCredentialsDetailed?: () => Promise<{ privateKey: string | null; publicKey: string | null; orgName: string | null; lookupFailed: boolean; optionalMetadataLookupFailure?: "unreadable" | "unavailable"; }>; }): Promise; export declare function createOpenAiAppsChallengeHandler(getToken?: () => string | undefined): import("h3").EventHandlerWithFetch; export declare function createOAuthPopupWaitingHandler(): import("h3").EventHandlerWithFetch; /** * External-agent connection routes: OAuth metadata and the connect page, * device flow and token subroutes when connect is on, and the public identity * route either way. */ export declare function mountMcpConnectRoutes(app: H3AppShim, mcpConnect: ResolvedCoreRoutesMcp): void; export declare function mountImageRoutes(app: H3AppShim, routePrefix?: string): void; export declare function mountApplicationStateRoutes(nitroApp: any, routePrefix?: string, app?: H3AppShim, options?: { anonymousOwner?: AppStateAnonymousOwnerResolver; }): void; 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;