export { migrationOAuthAuthorizationUrlFor, migrationOAuthClientAuthorizationUrlResolutionSource, migrationOAuthClientNeedsAuthorizationUrlResolution, migrationOAuthClientPlanKey, resolveMigrationOAuthAuthorizationUrls, type MigrationOAuthMetadataFetch, type ResolveMigrationOAuthAuthorizationUrlsOptions, } from "./migration-oauth-metadata";
export type MigrationOwner = "org" | "user";
/** v2 owner partition for a migrated row. `subject` is "" (ORG_SUBJECT) for org. */
export interface OwnerKeys {
    readonly owner: MigrationOwner;
    readonly subject: string;
    readonly tenant: string;
}
export declare const parseScope: (scopeId: string) => OwnerKeys | null;
export type ScopeOwnerResolver = (scopeId: string) => OwnerKeys | null;
/** Stable string identifying the partition an oauth_client is deduped within —
 *  shared org apps collapse across the org, personal apps stay per-user. */
export declare const ownerPartitionKey: (keys: OwnerKeys) => string;
export declare const DEFAULT_VAULT_PREFIX = "executor";
export declare const vaultV1ObjectName: (prefix: string, scopeId: string, secretId: string) => string;
/** The legacy un-url-encoded variant v1 falls back to on a 404. */
export declare const vaultV1LegacyObjectName: (prefix: string, scopeId: string, secretId: string) => string;
export declare const vaultV2ObjectName: (prefix: string, itemId: string) => string;
export declare const oauthClientDedupKey: (partition: string, clientId: string, tokenEndpoint: string) => string;
export declare const serializeOAuthScopes: (scopes: readonly string[]) => string;
export declare const DEFAULT_STATIC_NAMESPACES: readonly string[];
export type PolicyTransformResult = {
    readonly kind: "ok";
    readonly pattern: string;
} | {
    readonly kind: "static";
    readonly pattern: string;
} | {
    readonly kind: "dead";
    readonly slug: string;
};
export declare const migratePolicyPattern: (pattern: string, slugMap: ReadonlyMap<string, string>, staticNamespaces?: readonly string[]) => PolicyTransformResult;
export interface V1ToolRuntimeMetadataRow {
    readonly scopeId: string;
    readonly sourceId: string;
    readonly pluginId: string;
    readonly name: string;
    readonly annotations: unknown;
}
export interface V1PluginStorageRuntimeRow {
    readonly scopeId: string;
    readonly pluginId: string;
    readonly collection: string;
    readonly key: string;
    readonly data: unknown;
}
export interface LegacyMcpToolBinding {
    readonly toolName: string;
    readonly annotations?: Record<string, unknown>;
}
export interface V1RuntimeMetadataIndex {
    readonly mcpBindings: ReadonlyMap<string, LegacyMcpToolBinding>;
}
export type MigratedPluginStorageOwner = "source" | "catalog";
export interface MigratedPluginStorageRuntimeRow {
    readonly pluginId: string;
    readonly collection: string;
    readonly key: string;
    readonly data: unknown;
    /** `catalog` rows are v2 integration metadata and must be org-owned. */
    readonly owner: MigratedPluginStorageOwner;
}
export declare const buildV1RuntimeMetadataIndex: (rows: readonly V1PluginStorageRuntimeRow[]) => V1RuntimeMetadataIndex;
export declare const migrateV1ToolAnnotations: (tool: V1ToolRuntimeMetadataRow, index: V1RuntimeMetadataIndex) => unknown;
export declare const migrateV1PluginStorageRuntimeRow: (row: V1PluginStorageRuntimeRow) => MigratedPluginStorageRuntimeRow;
/** A v1 `config.headers` / `config.queryParams` entry. A bare string is a static
 *  value; the object forms are credential placements that pull from a binding /
 *  secret / inline text, optionally with a literal `prefix` (e.g. `"Bearer "`). */
export type V1ConfiguredValue = string | {
    readonly kind: "binding";
    readonly slot: string;
    readonly prefix?: string;
} | {
    readonly kind: "secret";
    readonly secretId?: string;
    readonly prefix?: string;
} | {
    readonly kind: "text";
    readonly text: string;
    readonly prefix?: string;
};
export interface V1OAuth2Config {
    readonly securitySchemeName: string;
    readonly flow?: string;
    readonly authorizationUrl?: string;
    readonly tokenUrl: string;
    readonly scopes?: readonly string[];
}
export interface V1OpenApiAuthConfig {
    readonly headers?: Record<string, V1ConfiguredValue>;
    readonly queryParams?: Record<string, V1ConfiguredValue>;
    readonly oauth2?: V1OAuth2Config;
}
/** A part-array template value: `prefix ? [prefix, token] : [token]`. */
export type TemplatePart = string | {
    readonly type: "variable";
    readonly name: string;
};
export interface MigratedApiKeyAuth {
    readonly slug: string;
    readonly type: "apiKey";
    readonly headers?: Record<string, readonly TemplatePart[]>;
    readonly queryParams?: Record<string, readonly TemplatePart[]>;
}
export interface MigratedOAuthAuth {
    readonly slug: string;
    readonly type: "oauth";
    readonly authorizationUrl: string;
    readonly tokenUrl: string;
    readonly scopes: readonly string[];
}
export type MigratedAuthentication = MigratedApiKeyAuth | MigratedOAuthAuth;
export interface OpenApiAuthTemplateResult {
    readonly authenticationTemplate: readonly MigratedAuthentication[];
    /** Literal-string header/query entries — passed through to v2 `config`. */
    readonly staticHeaders: Record<string, string>;
    readonly staticQueryParams: Record<string, string>;
    /** v1 binding `slot_key` → the v2 method `slug` that consumes it. The
     *  connection pass uses this to set `connection.template`. */
    readonly slotToTemplateSlug: Record<string, string>;
    /** v1 binding `slot_key` → the v2 input variable its resolved secret fills. The
     *  connection migration writes one `item_ids` entry per (variable → secret), so
     *  a two-secret source (e.g. Datadog) lands both keys on one connection. */
    readonly slotToVariable: Record<string, string>;
    readonly warnings: readonly string[];
}
/** The single apiKey method slug — one apiKey method per source, so a constant
 *  is unique within the integration and every credential slot maps to it. */
export declare const API_KEY_TEMPLATE_SLUG = "apiKey";
/** The canonical variable for a single-input source. Multiple inputs derive
 *  distinct names instead (so a connection can carry both of e.g. Datadog's
 *  keys). Matches the runtime default in `connection.ts` / the plugins. */
export declare const PRIMARY_INPUT_VARIABLE = "token";
export declare const migrateOpenApiAuthTemplate: (config: V1OpenApiAuthConfig) => OpenApiAuthTemplateResult;
export type V1ConnectionKind = "authorization-code" | "dynamic-dcr" | "client-credentials";
export type MigrationGrant = "authorization_code" | "client_credentials";
export declare const migrateGrant: (kind: V1ConnectionKind) => MigrationGrant;
/** 1h — synthetic TTL for client_credentials connections whose v1 provider
 *  omitted `expires_in`. Re-mint is userless + cheap, so hourly churn is fine. */
export declare const SYNTHETIC_CLIENT_CREDENTIALS_TTL_MS: number;
export declare const migrateExpiresAt: (input: {
    readonly grant: MigrationGrant;
    readonly v1ExpiresAt: number | null;
    readonly nowMs: number;
}) => number | null;
export interface V1OpenApiSourceConfig extends V1OpenApiAuthConfig {
    readonly spec?: string;
    readonly sourceUrl?: string;
    readonly baseUrl?: string;
    readonly googleDiscoveryUrls?: readonly string[];
}
export interface V2OpenApiIntegrationConfig {
    readonly spec?: string;
    readonly sourceUrl?: string;
    readonly baseUrl?: string;
    readonly googleDiscoveryUrls?: readonly string[];
    readonly headers?: Record<string, string>;
    readonly queryParams?: Record<string, string>;
    readonly authenticationTemplate?: readonly MigratedAuthentication[];
}
export interface MigratedSourceConfig {
    /** The opaque v2 `integration.config` blob (openapi/mcp/graphql shaped). */
    readonly config: unknown;
    /** v1 binding `slot_key` → the v2 method slug it feeds (connection migration). */
    readonly slotToTemplateSlug: Record<string, string>;
    /** v1 binding `slot_key` → the v2 input variable its secret fills. */
    readonly slotToVariable: Record<string, string>;
    readonly warnings: readonly string[];
}
export declare const migrateOpenApiSourceConfig: (v1: V1OpenApiSourceConfig) => MigratedSourceConfig;
/** v1 mcp/graphql `auth` block. The oauth2 form carries a `connectionSlot` that
 *  bound a credential_binding; v2 drops it (the connection is the credential). */
export type V1SourceAuth = {
    readonly kind: "none";
} | {
    readonly kind: "oauth2";
    readonly connectionSlot?: string;
};
export type V2SourceAuth = {
    readonly kind: "none";
} | {
    readonly kind: "oauth2";
};
export declare const migrateSourceAuth: (auth: V1SourceAuth | undefined) => V2SourceAuth;
export type SecretRole = "oauth-access" | "oauth-refresh" | "apikey" | "client-secret" | "client-id" | "orphan";
/** Classify a credential_binding `slot_key` into its v2 secret role. v1 slot
 *  shapes: `header:<name>` / `query_param:<name>` / `spec_fetch_header:<name>`
 *  (api key), `oauth2:<strat>:client-secret` / `:client-id` (BYO client creds),
 *  `oauth2:<strat>:connection` / `auth:oauth2:connection` (the oauth token — a
 *  `kind=connection` binding, not a secret; classified oauth-access for the rare
 *  cases it is secret-backed). */
export declare const classifyBindingSlot: (slotKey: string) => SecretRole;
export interface SecretReadRef {
    readonly scopeId: string;
    readonly secretId: string;
    readonly provider: string;
}
/** A v1 OAuth app to fold into the v2 `oauth_client` set. `clientIdSecretRef`
 *  carries legacy client IDs that v1 stored as secrets; runners resolve it into
 *  the v2 plaintext `oauth_client.client_id` column. `clientSecretRef` is an
 *  opaque handle (e.g. the v1 secret id/scope pair) the runner resolves to the
 *  actual secret value when writing the vault item; null for public/PKCE apps. */
export interface PlannedOAuthClientInput {
    readonly ownerKeys: OwnerKeys;
    readonly clientId: string;
    readonly clientIdSecretRef?: SecretReadRef | null;
    readonly tokenUrl: string;
    readonly authorizationUrl: string;
    readonly authorizationServerMetadataUrl?: string | null;
    readonly grant: MigrationGrant;
    readonly resource: string | null;
    readonly clientSecretRef: string | null;
}
export interface DedupedOAuthClient extends PlannedOAuthClientInput {
    readonly slug: string;
}
export interface OAuthClientDedupResult {
    readonly clients: readonly DedupedOAuthClient[];
    /** dedup key → assigned slug; the connection planner maps each v1 app to it. */
    readonly slugByDedupKey: Record<string, string>;
}
export declare const dedupeOAuthClients: (inputs: readonly PlannedOAuthClientInput[]) => OAuthClientDedupResult;
/** The dedup key for a v1 app — call with the same parts to look its slug up in
 *  `slugByDedupKey` when planning the connection that uses it. Secret-backed v1
 *  client IDs use their source secret reference so distinct BYO apps do not
 *  collapse before the runner can resolve plaintext values. */
export declare const oauthClientSlugKey: (input: {
    readonly ownerKeys: OwnerKeys;
    readonly clientId: string;
    readonly clientIdSecretRef?: SecretReadRef | null;
    readonly tokenUrl: string;
}) => string;
export interface PlannedIntegrationRow {
    readonly tenant: string;
    readonly owner: MigrationOwner;
    readonly subject: string;
    readonly slug: string;
    readonly plugin_id: string;
    readonly description: string;
    readonly config: unknown;
}
/** Build a v2 `integration` row from a v1 source + its migrated config. All prod
 *  sources are org-owned, but we derive owner from the scope generically (a local
 *  user-scoped source maps to owner=user). */
export declare const planIntegrationRow: (input: {
    readonly scopeId: string;
    readonly sourceId: string;
    readonly pluginId: string;
    readonly description: string;
    readonly config: unknown;
    readonly ownerForScope?: ScopeOwnerResolver;
}) => PlannedIntegrationRow | null;
export interface PlannedConnectionRow {
    readonly tenant: string;
    readonly owner: MigrationOwner;
    readonly subject: string;
    readonly integration: string;
    readonly name: string;
    readonly template: string;
    readonly provider: string;
    readonly identityLabel: string | null;
    readonly oauthClientSlug: string | null;
    readonly oauthClientOwner: MigrationOwner | null;
    readonly oauthScope: string | null;
    readonly expiresAt: number | null;
}
/** Build a v2 `connection` row (owner split, C1a expiry, oauth-client ref). The
 *  runner attaches `item_ids`/`refresh_item_id` from its secret-op results. */
export declare const planConnectionRow: (input: {
    readonly scopeId: string;
    readonly integration: string;
    readonly name: string;
    readonly template: string;
    readonly provider: string;
    readonly identityLabel: string | null;
    readonly grant: MigrationGrant;
    readonly v1ExpiresAt: number | null;
    readonly oauthScopes: readonly string[];
    readonly oauthClientSlug: string | null;
    readonly oauthClientOwner: OwnerKeys | null;
    readonly nowMs: number;
    readonly ownerForScope?: ScopeOwnerResolver;
}) => PlannedConnectionRow | null;
export declare const migratedItemId: (scopeId: string, secretId: string) => string;
/** The conventional oauth method slug for mcp/graphql (which carry no
 *  securitySchemeName). A connection's `template` points at it. */
export declare const OAUTH_TEMPLATE_SLUG = "oauth2";
export interface V1McpSourceConfig {
    readonly endpoint?: string;
    readonly transport?: string;
    readonly remoteTransport?: string;
    readonly headers?: Record<string, V1ConfiguredValue>;
    readonly queryParams?: Record<string, V1ConfiguredValue>;
    readonly auth?: V1SourceAuth;
}
export interface V1GraphqlSourceConfig {
    readonly endpoint?: string;
    readonly name?: string;
    readonly headers?: Record<string, V1ConfiguredValue>;
    readonly queryParams?: Record<string, V1ConfiguredValue>;
    readonly auth?: V1SourceAuth;
}
export declare const migrateMcpSourceConfig: (v1: V1McpSourceConfig) => MigratedSourceConfig;
export declare const migrateGraphqlSourceConfig: (v1: V1GraphqlSourceConfig) => MigratedSourceConfig;
export interface V1SourceRow {
    readonly scopeId: string;
    readonly id: string;
    readonly pluginId: string;
    readonly name: string;
}
export interface V1ProviderState {
    readonly kind?: string;
    readonly clientId?: string;
    readonly clientIdSecretId?: string;
    readonly clientIdSecretScopeId?: string | null;
    readonly clientSecretSecretId?: string;
    readonly clientSecretSecretScopeId?: string | null;
    readonly tokenEndpoint?: string;
    readonly authorizationEndpoint?: string;
    readonly authorizationServerUrl?: string;
    readonly authorizationServerMetadataUrl?: string;
    readonly authorizationServerMetadata?: {
        readonly authorization_endpoint?: string;
    } | null;
    readonly issuerUrl?: string;
    readonly resource?: string | null;
    readonly scopes?: readonly string[];
    readonly scope?: string;
}
export interface V1ConnectionRow {
    readonly id: string;
    readonly scopeId: string;
    readonly provider: string;
    readonly identityLabel: string | null;
    readonly accessTokenSecretId: string | null;
    readonly refreshTokenSecretId: string | null;
    readonly expiresAt: number | null;
    readonly providerState: V1ProviderState | null;
}
export interface V1BindingRow {
    readonly scopeId: string;
    readonly sourceScopeId?: string;
    readonly sourceId: string;
    readonly slotKey: string;
    readonly kind: "secret" | "connection" | "text";
    readonly secretId: string | null;
    readonly secretScopeId?: string | null;
    readonly connectionId: string | null;
    readonly textValue: string | null;
}
export interface V1PolicyRow {
    readonly id?: string;
    readonly scopeId: string;
    readonly pattern: string;
    readonly action: string;
    readonly position?: string;
}
export interface V1SecretRow {
    readonly id: string;
    readonly scopeId: string;
    readonly name: string;
    readonly provider: string;
    readonly ownedByConnectionId: string | null;
}
/** A v1 secret value to (re-)materialize in the v2 store. The runner resolves
 *  `fromSecret` via the provider (walking the scope-stack for client-* roles) or
 *  writes `fromText` verbatim, to the deterministic `itemId` under `owner`. */
export interface SecretOp {
    readonly itemId: string;
    readonly role: SecretRole;
    readonly owner: OwnerKeys;
    readonly targetProvider: string;
    readonly fromSecret?: {
        readonly scopeId: string;
        readonly secretId: string;
        readonly provider: string;
    };
    readonly fromText?: string;
}
export interface PlannedConnectionFull {
    readonly credentialScopeId: string;
    readonly sourceScopeId: string;
    readonly sourceId: string;
    readonly row: PlannedConnectionRow;
    /** variable → v2 item id (the connection's `item_ids` map). */
    readonly itemIds: Record<string, string>;
    readonly refreshItemId: string | null;
}
export interface PlannedOAuthClientFull extends DedupedOAuthClient {
    /** Vault item id for the client secret (when one existed); else null. */
    readonly clientSecretItemId: string | null;
}
export interface PlannedPolicy {
    readonly owner: OwnerKeys;
    readonly id: string;
    readonly pattern: string;
    readonly action: string;
    readonly position: string;
    readonly status: "ok" | "static" | "dead-inert";
}
export interface MigrationReport {
    readonly integrations: number;
    readonly connections: number;
    readonly oauthClients: number;
    readonly secretOps: number;
    /** v1 connection rows with no source binding — not migrated (stale residue). */
    readonly staleConnections: number;
    readonly policies: {
        readonly ok: number;
        readonly static: number;
        readonly deadInert: number;
    };
    readonly warnings: readonly string[];
}
export interface MigrationPlan {
    readonly integrations: readonly PlannedIntegrationRow[];
    readonly oauthClients: readonly PlannedOAuthClientFull[];
    readonly connections: readonly PlannedConnectionFull[];
    readonly secretOps: readonly SecretOp[];
    readonly policies: readonly PlannedPolicy[];
    readonly report: MigrationReport;
}
export interface MigrationInput {
    readonly sources: readonly V1SourceRow[];
    /** `${scopeId} ${sourceId}` → the migrated config + slot maps (the runner
     *  builds these per kind via the `migrate*SourceConfig` assemblers). */
    readonly migratedConfigs: ReadonlyMap<string, MigratedSourceConfig>;
    /** `${sourceScopeId} ${sourceId}` → live OAuth resource discovered from
     *  protected-resource metadata. Runners populate this for MCP sources; the
     *  pure planner stays deterministic and only consumes explicit overrides. */
    readonly oauthResourceOverrides?: ReadonlyMap<string, string>;
    readonly connections: readonly V1ConnectionRow[];
    readonly bindings: readonly V1BindingRow[];
    readonly secrets: readonly V1SecretRow[];
    readonly policies: readonly V1PolicyRow[];
    /** Tool `source_id`s with no `source` row (Class B orphans) — folded into the
     *  slug map so their policies/tools survive. */
    readonly toolSourceIds: readonly string[];
    readonly nowMs: number;
    readonly ownerForScope?: ScopeOwnerResolver;
    readonly defaultWritableProvider?: string;
}
/** The map key joining a (scopeId, sourceId) pair. Exported so the runner keys
 *  `migratedConfigs` identically to the weave's lookup. */
export declare const migrationSourceKey: (scopeId: string, sourceId: string) => string;
export declare const planMigration: (input: MigrationInput) => MigrationPlan;
//# sourceMappingURL=migration-spec.d.ts.map