import { ValConfig, ValModules } from "@valbuild/core"; import type { ValServerConfig } from "./ValServer.js"; import type { ValApiOptions } from "./ValRouter.js"; import { ValOpsFS } from "./ValOpsFS.js"; import { ValOpsHttp } from "./ValOpsHttp.js"; import { ValOpsMemory } from "./ValOpsMemory.js"; /** * Resolving how Val is configured, and building the data layer from it. * * Both live here rather than inside `createValApiRouter` because the MCP tool * registry needs exactly the same answers: which mode we are in, which * credential to use, and which `ValOps` implementation that implies. Two copies * of this would drift, and the failure would be quiet — a registry that decides * it is in fs mode while the Studio decides it is in proxy mode reads different * content from the same project. * * The type-only import from `./ValRouter` is deliberate: it keeps `ValApiOptions` * where its documentation lives without creating a runtime cycle. * * The credential-bearing URL check at the bottom of this file lives here for the * same reason: it is a check on the URLs `initHandlerOptions` resolves, and its * only caller is that function. Leaving it in `./ValRouter` would have meant * importing it back from there, which is the runtime cycle the paragraph above * exists to avoid. */ export declare const DEFAULT_VAL_BUILD_URL = "https://admin.val.build"; /** * Resolve options plus environment into a concrete {@link ValServerConfig}. * * Moved verbatim out of `createValApiRouter`; the precedence rules are load * bearing, so this is the one place they are written down. Note that "proxy" * mode is inferred when `VAL_API_KEY` or `VAL_SECRET` is present and no mode was * given, which is why a project can be pushed into proxy mode by setting an env * var alone. */ export declare function initHandlerOptions(route: string, opts: ValApiOptions, config: ValConfig): Promise; /** * Build the data layer a {@link ValServerConfig} calls for. * * The http backend always sees the app's own API key. That is what the Studio * wants — there the app has already verified a session cookie and is acting on * the user's behalf under its own authority — and it is now the only shape: * every caller that reaches here has been authenticated by the app itself, so * there is no request left on which the app is a pipe rather than an authority. * * This took a parameter for the other case: a caller acting for a user it had * *not* authenticated passed that user's personal access token, and the backend * decided what the caller could do. `ValOpsHttp` still accepts such a token — * the CLI's `debug` command uses the developer's own from `val login` — but no * server request builds one any more, because a request the app cannot * authenticate is now refused instead of relayed. * * What has not changed is why the API key must never stand in for a credential * that was merely *absent*: it works, and it works for every project the key * can reach, including the ones the caller cannot. Callers are refused for a * missing credential well before this point. */ export declare function createValOps(valModules: ValModules, options: ValServerConfig): ValOpsFS | ValOpsHttp | ValOpsMemory; /** * Hosts we send credentials to, and what each one puts at risk. They differ: * only `valBuildUrl` hands back the app token that becomes the session cookie, * so a single shared sentence would overstate one and understate the other. */ type CredentialBearingUrl = "valBuildUrl" | "valContentUrl"; /** * Returns a warning if `url` would send credentials somewhere they can be read * off the wire, or null if it is fine. * * Both URLs default to https, but each is overridable - `opts.valBuildUrl` / * `VAL_BUILD_URL`, `opts.valContentUrl` / `VAL_CONTENT_URL` - and neither * override has ever been scheme-checked. Point one at a plain http host and the * api key goes out in clear text, and whatever comes back is whatever the * network says: for `valBuildUrl` that includes the app token this server * re-signs into the session cookie. * * Loopback over http is exempt: that is a val.build running on the developer's * own machine, and there is no network to be on the wrong side of. * * This warns rather than throws. Both overrides are set by the operator, not by * an attacker, so this is a misconfiguration to surface - not untrusted input to * reject - and refusing to boot would break anyone deliberately pointing at an * internal http host today. */ export declare function insecureUrlWarning(name: CredentialBearingUrl, url: string): string | null; /** * Which credential talks to the content host about REMOTE FILES. * * A separate question from the one `createValOps` answers, and it has to be: * `ValOps` is authenticated per caller, but remote files are project-level — * looking up a project's public id and its buckets, and later pushing bytes to * them, is the same operation whoever asked for it. * * The rule, in order: * * 1. The app's API key, if there is one. Proxy mode always has one; fs mode has * one when `VAL_API_KEY` is set. * 2. In fs mode, the developer's own `val login` token, read off disk. This is * the same file `val validate --fix` reads, and it is why local remote * uploads work with no configuration beyond having logged in. * 3. Nothing, which is an error rather than a fallback. * * Lives here rather than inside `createValServer` because the MCP image tool * needs the same answer, and this is the file that exists so that two callers * cannot disagree about how a project is configured. A registry that decided it * had no credential while the Studio in the same process had one would be a * genuinely confusing afternoon. */ export type RemoteFileAuth = { apiKey: string; } | { pat: string; }; export type ResolveRemoteFileAuthResult = { status: "success"; auth: RemoteFileAuth; } | { status: "error"; errorCode: "project-not-configured" | "pat-error" | "api-key-missing"; message: string; }; export declare function resolveRemoteFileAuth(options: ValServerConfig): Promise; export {};