/**
 * Enbox Connect Protocol
 *
 * A capability delegation protocol for DWN access. Enables apps to request
 * scoped permission grants from a wallet (provider), receiving a delegate DID
 * with the granted permissions.
 *
 * Two transport modes:
 * - Local (`dwn://connect`): same-device, direct HTTP against the local DWN
 * - Remote (`enbox://connect`): cross-device, relay-mediated with QR/deep link
 *
 * The protocol uses JWTs for signing, JWE (XChaCha20-Poly1305) for encryption,
 * and ECDH (Ed25519 → X25519 + HKDF) for key agreement.
 */
import type { DerivedPrivateJwk } from '@enbox/dwn-sdk-js';
import type { EnboxPlatformAgent } from './types/agent.js';
import type { RequireOnly } from '@enbox/common';
import type { DidDocument, PortableDid } from '@enbox/dids';
import type { DwnDataEncodedRecordsWriteMessage, DwnPermissionScope, DwnProtocolDefinition } from './types/dwn.js';
/**
 * The protocols of permissions requested, along with the definition and permission scopes for each protocol.
 */
export type ConnectPermissionRequest = {
    /**
     * The definition of the protocol the permissions are being requested for.
     * In the event that the protocol is not already installed, the wallet will install this given protocol definition.
     */
    protocolDefinition: DwnProtocolDefinition;
    /** The scope of the permissions being requested for the given protocol */
    permissionScopes: DwnPermissionScope[];
};
/**
 * A scope-aware decryption key delivered to delegates during the connect flow.
 *
 * Two scope kinds:
 *
 * - **`protocol`** — protocol-wide key at depth `[ProtocolPath, protocolUri]`.
 *   Can derive leaf keys for any type path within the protocol.
 *   Issued when the grant covers the entire protocol (no `protocolPath`).
 *
 * - **`protocolPath`** — exact-path key at depth
 *   `[ProtocolPath, protocolUri, ...pathSegments]`.
 *   Can only decrypt records at that exact path — not siblings or descendants.
 *   Issued when the grant is narrowed to a specific `protocolPath`.
 *
 * Common conditions (both kinds):
 * 1. The protocol has `encryptionRequired: true` types (single-party only)
 * 2. The delegate has at least one `Records.Read` scope
 * 3. The protocol does NOT use multi-party / role-based access patterns
 *
 * Out of scope (fail closed):
 * - `contextId`-scoped encrypted delegate reads
 * - multi-party / ProtocolContext encrypted delegate reads
 */
export type DelegateDecryptionKey = {
    /** The protocol URI this key is scoped to. */
    protocol: string;
    /** Protocol-wide decryption scope. */
    scope: {
        kind: 'protocol';
    };
    /** The derived private key material for ProtocolPath decryption. */
    derivedPrivateKey: DerivedPrivateJwk;
} | {
    /** The protocol URI this key is scoped to. */
    protocol: string;
    /** Exact-path decryption scope — siblings and descendants are NOT accessible. */
    scope: {
        kind: 'protocolPath';
        protocolPath: string;
        match: 'exact';
    };
    /** The derived private key material for ProtocolPath decryption. */
    derivedPrivateKey: DerivedPrivateJwk;
};
/**
 * A context-scoped decryption key for a multi-party encrypted protocol.
 *
 * Delivered to delegates during the connect flow so they can decrypt
 * ProtocolContext-encrypted records without the owner's root X25519 key.
 *
 * Each key is scoped to one rootContextId — it unlocks all records within
 * that context domain but cannot access other contexts in the protocol.
 *
 * Delivered only when:
 * 1. The protocol has multi-party access patterns (detected by `isMultiPartyContext`)
 * 2. The delegate has a protocol-wide `Records.Read` scope (no protocolPath/contextId)
 * 3. The protocol has `encryptionRequired: true` types
 */
export type DelegateContextKey = {
    /** The protocol URI this key belongs to. */
    protocol: string;
    /** The root context ID this key unlocks. */
    contextId: string;
    /** The derived private key at `[ProtocolContext, rootContextId]`. */
    derivedPrivateKey: DerivedPrivateJwk;
};
import type { Jwk } from '@enbox/crypto';
import { type BearerDid } from '@enbox/dids';
/**
 * Pushed to the connect server so the wallet can retrieve it later.
 * The request is encrypted (JWE) before being pushed.
 *
 * Inspired by RFC 9126 (Pushed Authorization Requests).
 */
export type ConnectPushedRequest = {
    /** The encrypted JWE containing the signed {@link EnboxConnectRequest} JWT. */
    request: string;
};
/**
 * Returned by the connect server after a {@link ConnectPushedRequest}.
 * Contains a URI the wallet uses to fetch the encrypted request,
 * and the TTL before it expires.
 */
export type ConnectPushedResponse = {
    /** URI where the wallet can fetch the encrypted auth request. */
    request_uri: string;
    /** Seconds until the request expires. */
    expires_in: number;
};
/**
 * A connect request from an app to a wallet, asking for DWN permissions.
 *
 * The app creates this, signs it as a JWT, encrypts it as a JWE, and pushes
 * it to the connect server. The wallet retrieves, decrypts, verifies, and
 * displays it in a consent UI.
 */
export type EnboxConnectRequest = {
    /** Ephemeral DID (did:jwk) used for ECDH key agreement and request signing. */
    clientDid: string;
    /** Human-readable name of the requesting application, shown in the consent UI. */
    appName: string;
    /** DWN protocols and permission scopes being requested. */
    permissionRequests: ConnectPermissionRequest[];
    /** Anti-replay nonce (random base64url). */
    nonce: string;
    /** State correlator for matching request to response (random base64url). */
    state: string;
    /** URL where the wallet should POST the encrypted response. */
    callbackUrl: string;
    /** Response mode — always `direct_post` (wallet POSTs response to callbackUrl). */
    responseMode: 'direct_post';
    /** Supported DID methods for the connected identity. */
    supportedDidMethods: string[];
};
/**
 * A connect response from a wallet, granting DWN permissions.
 *
 * The wallet creates this after user consent, signs it as a JWT with the
 * delegate DID, encrypts it via ECDH, and POSTs it to the connect server.
 * The app retrieves, decrypts (using ECDH + optional PIN), and verifies it.
 */
export type EnboxConnectResponse = {
    /** The wallet owner's real DID that authorised the delegation. */
    providerDid: string;
    /** The newly created delegate DID identifier. */
    delegateDid: string;
    /** Audience — must match the `clientDid` from the request. */
    aud: string;
    /** Issued-at timestamp (Unix seconds). */
    iat: number;
    /** Expiration timestamp (Unix seconds). */
    exp: number;
    /** Echo of the request nonce. */
    nonce?: string;
    /** DWN permission grant messages (serialised RecordsWrite with encoded data). */
    delegateGrants: DwnDataEncodedRecordsWriteMessage[];
    /** The delegate DID's full portable form, including private keys. */
    delegatePortableDid: PortableDid;
    /**
     * Scope-aware decryption keys for encrypted protocols.
     *
     * Derived only for `Records.Read` permission scopes on
     * protocols with `encryptionRequired: true` types. Write-only delegates
     * receive no decryption keys.
     */
    delegateDecryptionKeys?: DelegateDecryptionKey[];
    /**
     * Context-scoped decryption keys for multi-party encrypted protocols.
     *
     * Derived at connect time for each existing rootContextId in multi-party
     * protocols where the delegate has a protocol-wide `Records.Read` scope.
     * Each key is scoped to `[ProtocolContext, rootContextId]` and can decrypt
     * all records within that context domain.
     *
     * Contexts created after connect are delivered automatically by
     * `postWriteKeyDelivery()` when the owner creates a new multi-party root
     * record on the same agent instance (same-process delivery).
     * Cross-device delivery is a documented follow-up.
     */
    delegateContextKeys?: DelegateContextKey[];
    /**
     * Protocol URIs that have multi-party encrypted access patterns.
     *
     * Delivered even when no contexts exist yet (cold-start), so the
     * delegate's agent can register for future context key delivery.
     */
    delegateMultiPartyProtocols?: string[];
    /** Per-grant revocation mappings for session-bound self-revocation on disconnect. */
    sessionRevocations?: {
        grantId: string;
        revocationGrantId: string;
    }[];
};
/** The connect server endpoint types. */
export type ConnectEndpoint = 'pushedAuthorizationRequest' | 'authorize' | 'callback' | 'token';
/**
 * Builds the URL for a connect server endpoint.
 *
 * @param options.baseURL - The connect server base URL (e.g. `http://localhost:3000/connect/`)
 * @param options.endpoint - The endpoint type
 * @param options.authParam - Required for `authorize` endpoint (the request ID)
 * @param options.tokenParam - Required for `token` endpoint (the state value)
 */
declare function buildConnectUrl({ baseURL, endpoint, authParam, tokenParam, }: {
    baseURL: string;
    endpoint: ConnectEndpoint;
    authParam?: string;
    tokenParam?: string;
}): string;
/**
 * Signs an object as a JWT using an Ed25519 DID key.
 *
 * `data` is constrained to `object` so callers don't have to widen
 * typed payload shapes (e.g. `EnboxConnectResponse`) to
 * `Record<string, unknown>` at the call site. `Convert.object(data)`
 * stringifies whatever JSON-serializable shape is passed.
 */
declare function signJwt({ did, data, }: {
    did: BearerDid;
    data: object;
}): Promise<string>;
/**
 * Verifies a JWT signature using the DID in the `kid` header. Returns the
 * parsed payload as an untyped object.
 *
 * The return type is intentionally `Record<string, unknown>` rather than a
 * caller-supplied generic — a JWT payload is bytes from a remote party, and
 * we can't soundly assert its shape without runtime validation. Callers must
 * apply one of the {@link assertConnectRequest} / {@link assertConnectResponse}
 * assertion helpers (or their own type guard) to narrow the payload before
 * accessing fields.
 */
declare function verifyJwt({ jwt }: {
    jwt: string;
}): Promise<Record<string, unknown>>;
/**
 * Runtime assertion that a verified JWT payload has the shape of an
 * {@link EnboxConnectRequest}. Use immediately after `verifyJwt()` to narrow
 * a `Record<string, unknown>` payload before accessing fields.
 */
declare function assertConnectRequest(payload: Record<string, unknown>): asserts payload is EnboxConnectRequest;
/**
 * Runtime assertion that a verified JWT payload has the shape of an
 * {@link EnboxConnectResponse}. Use immediately after `verifyJwt()` to narrow
 * a `Record<string, unknown>` payload before accessing fields.
 */
declare function assertConnectResponse(payload: Record<string, unknown>): asserts payload is EnboxConnectResponse;
/** Encrypts the connect request JWT with a symmetric key (shared via QR code or deep link). */
declare function encryptRequest({ jwt, encryptionKey, }: {
    jwt: string;
    encryptionKey: Uint8Array;
}): Promise<string>;
/** Decrypts an encrypted connect request JWE using the symmetric key from the QR/deep link. */
declare function decryptRequest({ jwe, encryptionKey, }: {
    jwe: string;
    encryptionKey: string;
}): Promise<string>;
/** Derives a shared ECDH key for encrypting/decrypting the connect response. */
declare function deriveSharedKey(privateKeyDid: BearerDid, publicKeyDid: DidDocument): Promise<Uint8Array>;
/**
 * Encrypts the connect response JWT.
 *
 * For remote (relay-mediated) flows, `pin` is required — it is added to the
 * AAD to prevent MITM attacks via the untrusted relay.
 *
 * For local (same-device) flows, `pin` may be omitted — the ECDH encryption
 * alone is sufficient when there is no untrusted intermediary.
 */
declare function encryptResponse({ jwt, encryptionKey, delegatePublicKeyJwk, pin, }: {
    jwt: string;
    encryptionKey: Uint8Array;
    delegatePublicKeyJwk: Jwk;
    pin?: string;
}): Promise<string>;
/**
 * Decrypts the connect response JWE using ECDH + optional PIN.
 *
 * @param clientDid - The ephemeral DID used at connect initiation (for ECDH).
 * @param jwe - The encrypted response JWE.
 * @param pin - The PIN entered by the user (required for remote flows, omit for local).
 */
declare function decryptResponse(clientDid: BearerDid, jwe: string, pin?: string): Promise<string>;
/** Creates an {@link EnboxConnectRequest}. */
declare function createConnectRequest(options: RequireOnly<EnboxConnectRequest, 'clientDid' | 'callbackUrl' | 'permissionRequests' | 'appName'>): Promise<EnboxConnectRequest>;
/**
 * Fetches an encrypted connect request from the authorize endpoint
 * and decrypts it using the encryption key from the QR/deep link.
 */
declare function getConnectRequest(requestUri: string, encryptionKey: string): Promise<EnboxConnectRequest>;
/** Creates an {@link EnboxConnectResponse} with timestamps. */
declare function createConnectResponse(options: RequireOnly<EnboxConnectResponse, 'providerDid' | 'delegateDid' | 'aud' | 'delegateGrants' | 'delegatePortableDid'>): Promise<EnboxConnectResponse>;
/**
 * Creates permission grants that assign the requested scopes to a delegate DID.
 */
declare function createPermissionGrants(selectedDid: string, delegateBearerDid: BearerDid, agent: EnboxPlatformAgent, scopes: DwnPermissionScope[], delegateKeyDeliveryData?: {
    rootKeyId: string;
    publicKeyJwk: Record<string, any>;
}): Promise<DwnDataEncodedRecordsWriteMessage[]>;
/**
 * Derives the minimal set of decryption keys implied by read-like permission
 * scopes for a single-party encrypted protocol.
 *
 * Rules:
 *   - Only Records.Read scopes contribute.
 *   - Write / Delete / Count scopes produce no decryption keys.
 *   - If any unrestricted (no `protocolPath`) read scope exists, one
 *     protocol-wide key is emitted and narrower keys are dropped.
 *   - Otherwise one exact-path key is emitted per unique `protocolPath`.
 *   - Scopes with `contextId` cause a fail-closed error.
 *   - Multi-party protocols cause a fail-closed error.
 *
 * @param agent - The platform agent (must hold the owner's KMS keys)
 * @param ownerDid - The DID of the protocol owner
 * @param protocolUri - The protocol URI
 * @param scopes - The permission scopes for this protocol
 * @param protocolDefinition - The protocol definition (for multi-party detection)
 * @returns An array of `DelegateDecryptionKey` (may be empty)
 */
declare function deriveScopedDecryptionKeys(agent: EnboxPlatformAgent, ownerDid: string, protocolUri: string, scopes: DwnPermissionScope[], protocolDefinition: DwnProtocolDefinition): Promise<DelegateDecryptionKey[]>;
/**
 * Detects whether a protocol definition has any root-level type whose subtree
 * triggers multi-party semantics. Delegates to the canonical
 * `isMultiPartyContext()` from `protocol-utils.ts` which checks:
 *
 *   - `$role: true` descendants in the subtree
 *   - Relational `who`/`of` `$actions` rules that grant `read` access
 *
 * These patterns cause the DWN agent to use ProtocolContext encryption at
 * write time, which is not supported in delegate sessions yet.
 */
/**
 * Classifies root-level types in a protocol definition into multi-party
 * and single-party buckets. Used to detect mixed protocols that cannot
 * be safely modeled with a single key type.
 */
declare function classifyProtocolRoots(definition: DwnProtocolDefinition): {
    multiParty: string[];
    singleParty: string[];
};
/**
 * Derives per-context decryption keys for a delegate's access to a multi-party
 * encrypted protocol. Queries the owner's DWN for all root-level records
 * (thread roots, etc.) and derives a `[ProtocolContext, rootContextId]` key
 * for each.
 *
 * Validates scopes first — only protocol-wide `Records.Read` scopes are accepted.
 * `protocolPath`-scoped and `contextId`-scoped reads throw (not yet supported).
 * Write-only scopes return empty (no decryption keys needed).
 *
 * @param agent - The platform agent (must hold the owner's KMS keys)
 * @param ownerDid - The DID of the protocol owner
 * @param protocolDefinition - The protocol definition
 * @param scopes - The permission scopes for this protocol
 * @returns An array of `DelegateContextKey` (may be empty)
 */
declare function deriveContextKeysForDelegate(agent: EnboxPlatformAgent, ownerDid: string, protocolDefinition: DwnProtocolDefinition, scopes: DwnPermissionScope[]): Promise<DelegateContextKey[]>;
/**
 * Executes the full wallet-side (provider) flow:
 * 1. Creates a delegate DID
 * 2. Installs requested protocols
 * 3. Creates permission grants
 * 4. Builds, signs, and encrypts the response
 * 5. POSTs the encrypted response to the callback URL
 *
 * @param selectedDid - The provider's DID that is granting access.
 * @param connectRequest - The decoded connect request from the app.
 * @param pin - The PIN for response encryption AAD (required for remote flows).
 * @param agent - The agent instance for DWN operations.
 */
declare function submitConnectResponse(selectedDid: string, connectRequest: EnboxConnectRequest, pin: string | undefined, agent: EnboxPlatformAgent): Promise<void>;
export declare const EnboxConnectProtocol: {
    buildConnectUrl: typeof buildConnectUrl;
    signJwt: typeof signJwt;
    verifyJwt: typeof verifyJwt;
    assertConnectRequest: typeof assertConnectRequest;
    assertConnectResponse: typeof assertConnectResponse;
    encryptRequest: typeof encryptRequest;
    decryptRequest: typeof decryptRequest;
    encryptResponse: typeof encryptResponse;
    decryptResponse: typeof decryptResponse;
    deriveSharedKey: typeof deriveSharedKey;
    createConnectRequest: typeof createConnectRequest;
    getConnectRequest: typeof getConnectRequest;
    createConnectResponse: typeof createConnectResponse;
    createPermissionGrants: typeof createPermissionGrants;
    submitConnectResponse: typeof submitConnectResponse;
    deriveScopedDecryptionKeys: typeof deriveScopedDecryptionKeys;
    deriveContextKeysForDelegate: typeof deriveContextKeysForDelegate;
    classifyProtocolRoots: typeof classifyProtocolRoots;
};
export {};
//# sourceMappingURL=enbox-connect-protocol.d.ts.map