/** * Custom provider registry — runtime storage and resolution. * * Lets apps register arbitrary HTTP API providers at runtime without touching * the static PROVIDER_CONFIGS list. Provider rows live in the * `custom_api_providers` SQL table (created on first use). Credentials * referenced in the provider row continue to live in the existing secrets / * credentials store — this table stores only key NAMES, never values. * * Scoping mirrors the `app_secrets` table: each row is scoped to a user * (by email) or an organisation (by orgId). * * Supported auth kinds for custom providers: * - bearer → Authorization: Bearer * - basic → Authorization: Basic base64(user:pass) * - api-key-header → custom header: * * google-service-account and oauth-bearer are intentionally unsupported for * custom providers because they require additional out-of-band setup that * cannot be expressed in the simple header/key model. */ export type CustomProviderScope = "user" | "org"; export type CustomProviderAuthKind = { type: "bearer"; credentialKey: string; } | { type: "basic"; usernameKey: string; passwordKey: string; } | { type: "api-key-header"; credentialKey: string; headerName: string; } | { type: "none"; }; export interface CustomProviderConfig { id: string; scope: CustomProviderScope; scopeId: string; label: string; baseUrl: string; auth: CustomProviderAuthKind; docsUrls: string[]; allowedHostSuffixes: string[]; defaultHeaders: Record; notes: string; createdAt: number; updatedAt: number; } export interface UpsertCustomProviderArgs { scope: CustomProviderScope; scopeId: string; /** Slug used as the provider id (e.g. "my-api"). Must be lowercase, letters/digits/hyphens. */ id: string; label: string; baseUrl: string; auth: CustomProviderAuthKind; docsUrls?: string[]; allowedHostSuffixes?: string[]; defaultHeaders?: Record; notes?: string; /** * Caller's org role in the target org (`scopeId` when `scope === "org"`), * resolved by the caller (e.g. `provider-api-register.ts`) before invoking * this function. Required — see `assertCanMutateCustomProviderScope`. */ orgRole: string | null; } /** * Validate and normalise a custom provider base URL. Throws when the URL is * invalid, uses a non-http(s) scheme, or resolves to a private/internal host. */ export declare function validateCustomBaseUrl(rawUrl: string): Promise; /** * Validate user-supplied allowed host suffixes. Each suffix must look like a * real registrable domain (at least two labels) and must not be a bare TLD or * shared-hosting public suffix where unrelated parties control subdomains. */ export declare function validateAllowedHostSuffixes(suffixes: string[]): string[]; /** * Thrown by `assertCanMutateCustomProviderScope` when the caller is not * authorized to mutate a scoped custom provider row. */ export declare class CustomProviderAuthError extends Error { readonly statusCode: number; constructor(statusCode: number, message: string); } /** * Defense-in-depth authorization guard for custom-provider mutations. Mirrors * `assertCanMutateScope` in `server/scoped-key-storage.ts`: user-scoped writes * need no role check (each user only ever mutates their own row), but * org-scoped writes require the caller to be an owner or admin of the target * org (`scopeId`) — otherwise a plain member could repoint an org-wide * provider's base URL or attach a different credential key name that other * members' agents then trust. `scopeId` is accepted (unused today) for * signature parity with `assertCanMutateScope` in case a future scope value * needs it (e.g. a solo-workspace carve-out). * * The only caller today is `provider-api-register.ts`, which resolves * `orgRole` itself and enforces this same check before calling in; this * function is the second, harder-to-bypass layer so a future caller can't * reintroduce the gap by forgetting to check. */ export declare function assertCanMutateCustomProviderScope(scope: CustomProviderScope, _scopeId: string, orgRole: string | null): void; /** * Create or update a custom provider. Validates the base URL against SSRF * rules at write time. Returns the provider id. */ export declare function upsertCustomProvider(args: UpsertCustomProviderArgs): Promise; /** * Delete a custom provider. Returns true if a row was deleted. */ export declare function deleteCustomProvider(scope: CustomProviderScope, scopeId: string, id: string, orgRole: string | null): Promise; /** * List all custom providers visible to a given (scope, scopeId) pair. */ export declare function listCustomProviders(scope: CustomProviderScope, scopeId: string): Promise; /** * Look up one custom provider. Returns null when not found. */ export declare function getCustomProvider(scope: CustomProviderScope, scopeId: string, id: string): Promise; //# sourceMappingURL=custom-registry.d.ts.map