@frak-labs/frame-connector
Version: 
Generic, type-safe RPC communication layer for bidirectional postMessage communication
838 lines (792 loc) • 27.5 kB
TypeScript
import type { Prettify } from 'viem';
/**
 * Union of all message types that can be received
 */
export declare type AnyMessage = RpcMessage | LifecycleMessage;
/**
 * Lifecycle message format for client-to-iframe communication
 * These messages handle connection lifecycle events (handshake, heartbeat, etc.)
 */
export declare type ClientLifecycleMessage = {
    clientLifecycle: string;
    data?: unknown;
};
/** @ignore */
export declare class ClientNotFound extends FrakRpcError {
    constructor();
}
/**
 * The received encoded data from a client
 * -> The encoded should contain a HashProtectedData once decoded
 */
export declare type CompressedData = Uint8Array;
/**
 * Compress JSON data using CBOR encoding
 *
 * @param data - The data to compress
 * @returns CBOR-encoded data
 *
 * @example
 * ```ts
 * const compressed = compressJson({ foo: 'bar' })
 * // Returns Uint8Array with CBOR-encoded data
 * ```
 */
export declare function compressJson(data: unknown): Uint8Array;
/**
 * Client-side compression middleware
 *
 * Compresses outgoing requests and decompresses incoming responses.
 * Always uses the format: {method: string, params: unknown}
 *
 * @example Client side
 * ```ts
 * const client = createRpcClient({
 *   transport: iframe.contentWindow,
 *   targetOrigin: 'https://wallet.frak.id',
 *   middleware: [createClientCompressionMiddleware()]
 * })
 * ```
 */
export declare const createClientCompressionMiddleware: <TSchema extends RpcSchema, TContext>() => RpcMiddleware<TSchema, TContext>;
/**
 * Listener-side compression middleware
 *
 * Decompresses incoming requests and compresses outgoing responses.
 * Always uses the format: {method: string, params: unknown}
 *
 * @example Listener side
 * ```ts
 * const listener = createRpcListener({
 *   transport: window,
 *   allowedOrigins: ['https://example.com'],
 *   middleware: [createListenerCompressionMiddleware()]
 * })
 * ```
 */
export declare const createListenerCompressionMiddleware: <TSchema extends RpcSchema, TContext>() => RpcMiddleware<TSchema, TContext>;
/**
 * Create an RPC client for SDK-side communication
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TLifecycleEvent - Lifecycle event union type (e.g., ClientLifecycleEvent | IFrameLifecycleEvent)
 * @param config - Client configuration
 * @returns RPC client instance
 *
 * @example
 * ```ts
 * import type { IFrameRpcSchema, ClientLifecycleEvent, IFrameLifecycleEvent } from '@frak-labs/core-sdk'
 *
 * const client = createRpcClient<IFrameRpcSchema, ClientLifecycleEvent | IFrameLifecycleEvent>({
 *   emittingTransport: window,
 *   listeningTransport: window,
 *   targetOrigin: 'https://wallet.frak.id',
 *   lifecycleHandlers: {
 *     iframeLifecycle: (event, data) => {
 *       // event and data are now strongly typed!
 *     }
 *   }
 * })
 *
 * // One-shot request
 * const result = await client.request('frak_sendInteraction', [productId, interaction])
 *
 * // Listener
 * const unsubscribe = client.listen('frak_listenToWalletStatus', (status) => {
 *   console.log('Wallet status:', status)
 * })
 * ```
 */
export declare function createRpcClient<TSchema extends RpcSchema, TLifecycleEvent extends LifecycleMessage = LifecycleMessage>(config: RpcClientConfig<TSchema, TLifecycleEvent>): RpcClient<TSchema, TLifecycleEvent>;
/**
 * Create an RPC listener for Wallet-side communication
 *
 * Supports multiple schemas via union types, enabling a single listener to handle
 * different RPC protocols (e.g., IFrameRpcSchema | SsoRpcSchema).
 *
 * @typeParam TSchema - The RPC schema type (can be a union of multiple schemas)
 * @typeParam TContext - Custom context type augmented by middleware
 * @typeParam TLifecycleEvent - Lifecycle event union type (e.g., ClientLifecycleEvent | IFrameLifecycleEvent)
 * @param config - Listener configuration
 * @returns RPC listener instance
 *
 * @example
 * ```ts
 * import type { IFrameRpcSchema, SsoRpcSchema, ClientLifecycleEvent, IFrameLifecycleEvent } from '@frak-labs/core-sdk'
 *
 * // Single schema
 * const listener = createRpcListener<IFrameRpcSchema>({
 *   transport: window,
 *   allowedOrigins: ['https://example.com']
 * })
 *
 * // Multiple schemas (union type) with lifecycle events
 * type CombinedSchema = IFrameRpcSchema | SsoRpcSchema
 * const listener = createRpcListener<CombinedSchema, WalletContext, ClientLifecycleEvent | IFrameLifecycleEvent>({
 *   transport: window,
 *   allowedOrigins: '*',
 *   middleware: [compressionMiddleware, contextMiddleware],
 *   lifecycleHandlers: {
 *     clientLifecycle: (event, data, context) => {
 *       // event and data are now strongly typed!
 *     }
 *   }
 * })
 *
 * // Register handlers for IFrame methods
 * listener.handle('frak_sendInteraction', async (params, context) => {
 *   return { status: 'success', hash: '0x...' }
 * })
 *
 * // Register handlers for SSO methods
 * listener.handle('sso_complete', async (params, context) => {
 *   const [session, sdkJwt, ssoId] = params
 *   return { success: true }
 * })
 * ```
 */
export declare function createRpcListener<TSchema extends RpcSchema, TContext = Record<string, never>, TLifecycleEvent extends LifecycleMessage = LifecycleMessage>(config: RpcListenerConfig<TSchema, TContext, TLifecycleEvent>): RpcListener<TSchema, TContext>;
/**
 * Decompress and validate hash-protected data
 *
 * Security:
 * - Validates hash to ensure data integrity
 * - Throws RpcError if hash validation fails
 * - Prevents corrupted or tampered messages from processing
 *
 * @param compressedData - The compressed data to decompress
 * @returns The decompressed data with validation hash
 * @throws {Error} If decompression fails or hash validation fails
 *
 * @example
 * ```ts
 * const decompressed = decompressDataAndCheckHash(compressedData)
 * // Returns { foo: 'bar', baz: 123, validationHash: '0x...' }
 * ```
 */
export declare function decompressDataAndCheckHash<T>(compressedData: CompressedData): HashProtectedData<T>;
/**
 * Decompress CBOR-encoded data
 *
 * @param data - The compressed data
 * @returns Decompressed data or null if decompression fails
 *
 * @example
 * ```ts
 * const decompressed = decompressJson<MyType>(compressedData)
 * if (decompressed) {
 *   // Use decompressed data
 * }
 * ```
 */
export declare function decompressJson<T>(data: Uint8Array): T | null;
/**
 * Simple deferred promise wrapper
 * @ignore
 */
export declare class Deferred<T> {
    private readonly _promise;
    private _resolve;
    private _reject;
    constructor();
    get promise(): Promise<T>;
    resolve: (value: T | PromiseLike<T>) => void;
    reject: (reason?: unknown) => void;
}
/**
 * Type that extract the possible parameters from a RPC Schema
 * @ignore
 */
export declare type ExtractedParametersFromRpc<TRpcSchema extends RpcSchema> = {
    [K in keyof TRpcSchema]: Prettify<{
        method: TRpcSchema[K] extends TRpcSchema[number] ? TRpcSchema[K]["Method"] : string;
    } & (TRpcSchema[K] extends TRpcSchema[number] ? TRpcSchema[K]["Parameters"] extends undefined ? {
        params?: never;
    } : {
        params: TRpcSchema[K]["Parameters"];
    } : never)>;
}[number];
/**
 * Type that extract the possible parameters from a RPC Schema
 * @ignore
 */
declare type ExtractedSpecificParametersFromRpc<TRpcSchema extends RpcSchema, TMethod extends ExtractMethod<TRpcSchema>> = Extract<ExtractedParametersFromRpc<TRpcSchema>, {
    method: TMethod;
}>;
/**
 * Extract method names from a schema
 *
 * @typeParam TSchema - The RPC schema type
 *
 * @example
 * ```ts
 * type Methods = ExtractMethod<MySchema>
 * // "greet" | "watchTime"
 * ```
 */
export declare type ExtractMethod<TSchema extends RpcSchema> = TSchema[number]["Method"];
/**
 * Extract parameters type for a specific method
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TMethod - The method name
 *
 * @example
 * ```ts
 * type GreetParams = ExtractParams<MySchema, "greet">
 * // [name: string]
 * ```
 */
export declare type ExtractParams<TSchema extends RpcSchema, TMethod extends ExtractMethod<TSchema>> = ExtractSchemaEntry<TSchema, TMethod>["Parameters"];
/**
 * Extract return type for a specific method
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TMethod - The method name
 *
 * @example
 * ```ts
 * type GreetReturn = ExtractReturnType<MySchema, "greet">
 * // string
 * ```
 */
export declare type ExtractReturnType<TSchema extends RpcSchema, TMethod extends ExtractMethod<TSchema>> = ExtractSchemaEntry<TSchema, TMethod>["ReturnType"];
/**
 * Extract a specific schema entry by method name
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TMethod - The method name to extract
 *
 * @example
 * ```ts
 * type GreetEntry = ExtractSchemaEntry<MySchema, "greet">
 * // { Method: "greet"; Parameters: [name: string]; ReturnType: string; ResponseType: "promise" }
 * ```
 */
export declare type ExtractSchemaEntry<TSchema extends RpcSchema, TMethod extends ExtractMethod<TSchema>> = Extract<TSchema[number], {
    Method: TMethod;
}>;
/**
 * Generic Frak RPC error
 * @ignore
 */
export declare class FrakRpcError<T = undefined> extends Error {
    code: number;
    data?: T | undefined;
    constructor(code: number, message: string, data?: T | undefined);
    toJSON(): RpcError;
}
/**
 * Compress the given data with hash protection to prevent tampering
 *
 * Performance considerations:
 * - CBOR encoding is more compact than JSON and faster to parse
 * - Hash validation prevents man-in-the-middle modifications
 * - Single-pass encoding minimizes allocations
 *
 * @param data - The data to compress and protect
 * @returns Compressed CBOR-encoded data with validation hash
 *
 * @example
 * ```ts
 * const compressed = hashAndCompressData({ foo: 'bar', baz: 123 })
 * // Returns Uint8Array with CBOR-encoded data + validation hash
 * ```
 */
export declare function hashAndCompressData<T>(data: T): CompressedData;
/**
 * The encoded data to send to a client / received by a client
 */
export declare type HashProtectedData<DataType> = Readonly<DataType & {
    validationHash: string;
}>;
/**
 * Lifecycle message format for iframe-to-client communication
 */
export declare type IFrameLifecycleMessage = {
    iframeLifecycle: string;
    data?: unknown;
};
/** @ignore */
export declare class InternalError extends FrakRpcError {
    constructor(message: string);
}
/**
 * Lifecycle handler function
 * Handles lifecycle events using discriminated unions for automatic type narrowing
 *
 * @typeParam TLifecycleEvent - The lifecycle event union type (e.g., ClientLifecycleEvent | IFrameLifecycleEvent)
 *
 * @param event - The full lifecycle event object with discriminated union
 * @param context - Request context with origin and source
 *
 * @example
 * ```ts
 * const handler: LifecycleHandler<ClientLifecycleEvent> = (event, context) => {
 *   if (event.clientLifecycle === "modal-css") {
 *     // event.data is automatically typed as { cssLink: string }
 *     console.log(event.data.cssLink)
 *   }
 * }
 * ```
 */
export declare type LifecycleHandler<TLifecycleEvent = unknown> = (event: TLifecycleEvent, context: RpcRequestContext) => void | Promise<void>;
/**
 * Union of all lifecycle message types
 */
export declare type LifecycleMessage = ClientLifecycleMessage | IFrameLifecycleMessage;
/** @ignore */
export declare class MethodNotFoundError extends FrakRpcError<{
    method: string;
}> {
    constructor(message: string, method: string);
}
/**
 * RPC Client interface
 * Provides methods for making RPC calls to the wallet
 *
 * @typeParam TSchema - The RPC schema type
 */
export declare type RpcClient<TSchema extends RpcSchema, TLifecycleEvent extends LifecycleMessage> = {
    /**
     * Make a one-shot request that returns a promise
     * Used for methods with ResponseType: "promise"
     */
    request: <TMethod extends ExtractMethod<TSchema>>(args: ExtractedSpecificParametersFromRpc<TSchema, TMethod>) => Promise<ExtractReturnType<TSchema, TMethod>>;
    /**
     * Subscribe to a listener method with a callback
     * Used for methods with ResponseType: "stream"
     * Returns an unsubscribe function
     *
     * @example
     * ```ts
     * const unsubscribe = client.listen('frak_listenToWalletStatus', (status) => {
     *   console.log('Status:', status)
     * })
     *
     * // Later, unsubscribe
     * unsubscribe()
     * ```
     */
    listen: <TMethod extends ExtractMethod<TSchema>>(args: ExtractedSpecificParametersFromRpc<TSchema, TMethod>, callback: (result: ExtractReturnType<TSchema, TMethod>) => void) => () => void;
    /**
     * Send a lifecycle event to the server
     * Bypasses middleware and is used for connection management
     *
     * @example
     * ```ts
     * client.sendLifecycle({ clientLifecycle: 'heartbeat' })
     * client.sendLifecycle({ clientLifecycle: 'modal-css', data: { cssLink: '...' } })
     * ```
     */
    sendLifecycle: (message: TLifecycleEvent) => void;
    /**
     * Clean up resources and close connections
     */
    cleanup: () => void;
};
/**
 * RPC Client configuration
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TLifecycleEvent - Lifecycle event union type (e.g., ClientLifecycleEvent | IFrameLifecycleEvent)
 */
export declare type RpcClientConfig<TSchema extends RpcSchema, TLifecycleEvent = unknown> = {
    /**
     * The transport to use for emitting events (e.g., window or iframe.contentWindow)
     */
    emittingTransport: RpcTransport;
    /**
     * The transport to use for listening to events (e.g., window or iframe.contentWindow)
     */
    listeningTransport: RpcTransport;
    /**
     * The target origin for postMessage
     */
    targetOrigin: string;
    /**
     * Middleware stack (executed in order)
     * Middleware can transform outgoing requests and incoming responses
     * Client-side middleware uses empty context {}
     *
     * @example
     * ```ts
     * middleware: [
     *   compressionMiddleware,  // Compress outgoing, decompress incoming
     *   loggingMiddleware,      // Log RPC calls
     * ]
     * ```
     */
    middleware?: RpcMiddleware<TSchema>[];
    /**
     * Lifecycle event handlers
     * Handles incoming lifecycle events from the server
     *
     * @example
     * ```ts
     * lifecycleHandlers: {
     *   iframeLifecycle: (event, data) => {
     *     if (event === 'connected') {
     *       console.log('Wallet ready')
     *     }
     *   }
     * }
     * ```
     */
    lifecycleHandlers?: {
        clientLifecycle?: LifecycleHandler<Extract<TLifecycleEvent, {
            clientLifecycle: string;
        }>>;
        iframeLifecycle?: LifecycleHandler<Extract<TLifecycleEvent, {
            iframeLifecycle: string;
        }>>;
    };
};
/**
 * RPC error object
 */
export declare type RpcError = {
    code: number;
    message: string;
    data?: unknown;
};
/**
 * RPC error codes
 * Follows JSON-RPC 2.0 specification with Frak-specific extensions
 */
export declare const RpcErrorCodes: {
    readonly parseError: -32700;
    readonly invalidRequest: -32600;
    readonly methodNotFound: -32601;
    readonly invalidParams: -32602;
    readonly internalError: -32603;
    readonly serverError: -32000;
    readonly clientNotConnected: -32001;
    readonly configError: -32002;
    readonly corruptedResponse: -32003;
    readonly clientAborted: -32004;
    readonly walletNotConnected: -32005;
    readonly serverErrorForInteractionDelegation: -32006;
    readonly userRejected: -32007;
};
/**
 * RPC Listener interface
 * Handles incoming RPC requests from the SDK
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TContext - Custom context type augmented by middleware
 */
export declare type RpcListener<TSchema extends RpcSchema, TContext = Record<string, never>> = {
    /**
     * Register a handler for a promise-based method
     */
    handle: <TMethod extends ExtractMethod<TSchema>>(method: TMethod, handler: RpcPromiseHandler<TSchema, TMethod, TContext>) => void;
    /**
     * Register a handler for a streaming method
     */
    handleStream: <TMethod extends ExtractMethod<TSchema>>(method: TMethod, handler: RpcStreamHandler<TSchema, TMethod, TContext>) => void;
    /**
     * Unregister a handler
     */
    unregister: (method: ExtractMethod<TSchema>) => void;
    /**
     * Clean up resources
     */
    cleanup: () => void;
};
/**
 * RPC Listener configuration
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TContext - Custom context type to augment base context
 * @typeParam TLifecycleEvent - Lifecycle event union type (e.g., ClientLifecycleEvent | IFrameLifecycleEvent)
 */
export declare type RpcListenerConfig<TSchema extends RpcSchema, TContext = Record<string, never>, TLifecycleEvent extends LifecycleMessage = LifecycleMessage> = {
    /**
     * The transport to use for communication (e.g., window)
     */
    transport: RpcTransport;
    /**
     * Allowed origins for security
     * Can be a single origin or array of origins
     */
    allowedOrigins: string | string[];
    /**
     * Middleware stack (executed in order)
     * Middleware can augment context, validate requests, and transform responses
     *
     * Note: Middleware only applies to RPC messages, not lifecycle or custom messages
     *
     * @example
     * ```ts
     * middleware: [
     *   loggingMiddleware,
     *   compressionMiddleware,
     *   contextAugmentationMiddleware
     * ]
     * ```
     */
    middleware?: RpcMiddleware<TSchema, TContext>[];
    /**
     * Lifecycle event handlers
     * Handles client-to-iframe and iframe-to-client lifecycle events
     *
     * @example
     * ```ts
     * lifecycleHandlers: {
     *   clientLifecycle: (event, data, context) => {
     *     if (event === 'heartbeat') {
     *       console.log('Client heartbeat received')
     *     }
     *   }
     * }
     * ```
     */
    lifecycleHandlers?: {
        clientLifecycle?: LifecycleHandler<Extract<TLifecycleEvent, {
            clientLifecycle: string;
        }>>;
        iframeLifecycle?: LifecycleHandler<Extract<TLifecycleEvent, {
            iframeLifecycle: string;
        }>>;
    };
};
/**
 * RPC message format (maintains backward compatibility)
 * This is the exact format sent over the wire
 *
 * @typeParam TMethod - The method name type (defaults to string for flexibility)
 */
export declare type RpcMessage<TMethod extends string = string> = {
    /**
     * Unique message identifier for correlating requests and responses
     */
    id: string;
    /**
     * The RPC method name (topic for backward compatibility)
     */
    topic: TMethod;
    /**
     * The message payload (compressed data) or raw params
     */
    data: unknown;
};
/**
 * Unified middleware function for RPC requests (both listener and client)
 * Works on both listener-side (with context augmentation) and client-side (empty context)
 *
 * Key features:
 * - Can mutate message.data directly for efficiency (compression, validation)
 * - Can mutate response.result directly for transformation
 * - Listener-side: Can augment context by returning modified context
 * - Client-side: Uses TContext = {} (empty context), always returns unchanged
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TContext - Custom context type to augment base context (empty {} for client-side)
 *
 * @example Listener-side with context augmentation
 * ```ts
 * type WalletContext = { productId: string, sourceUrl: string }
 * const contextMiddleware: RpcMiddleware<MySchema, WalletContext> = {
 *   onRequest: async (message, context) => {
 *     // Read from store and augment context
 *     const productId = await getProductId(context.origin)
 *     return { ...context, productId, sourceUrl: context.origin }
 *   }
 * }
 * ```
 *
 * @example Client-side (empty context)
 * ```ts
 * const compressionMiddleware: RpcMiddleware<MySchema> = {
 *   onRequest: async (message, context) => {
 *     // Mutate message.data directly
 *     message.data = compress(message.data)
 *     return context  // Empty context, unchanged
 *   },
 *   onResponse: async (message, response, context) => {
 *     // Mutate response.result directly
 *     response.result = decompress(response.result)
 *     return response
 *   }
 * }
 * ```
 *
 * @example Shared middleware (works on both sides)
 * ```ts
 * const loggingMiddleware: RpcMiddleware<MySchema> = {
 *   onRequest: async (message, context) => {
 *     console.log(`[RPC] ${message.topic}`, context.origin || 'client')
 *     return context
 *   },
 *   onResponse: async (message, response, context) => {
 *     console.log(`[RPC] ${message.topic} completed`)
 *     return response
 *   }
 * }
 * ```
 */
export declare type RpcMiddleware<TSchema extends RpcSchema, TContext = Record<string, never>> = {
    /**
     * Called before handler execution (listener) or before sending (client)
     *
     * For listener: Can augment context and mutate message
     * For client: Can mutate message, context is empty {}
     *
     * @param message - The RPC message (can be mutated)
     * @param context - Request context (listener-side) or empty (client-side)
     * @returns Updated context (listener mutates this, client returns unchanged)
     * @throws FrakRpcError to reject the request with a specific error code
     */
    onRequest?: (message: RpcMessage<ExtractMethod<TSchema>>, context: RpcMiddlewareContext<TContext>) => Promise<RpcMiddlewareContext<TContext>> | RpcMiddlewareContext<TContext>;
    /**
     * Called after handler execution (listener) or after receiving (client)
     *
     * @param message - The original RPC message
     * @param response - The response (can be mutated)
     * @param context - Request context (listener-side) or empty (client-side)
     * @returns Transformed response
     * @throws Error to send an error response instead
     */
    onResponse?: (message: RpcMessage<ExtractMethod<TSchema>>, response: RpcResponse, context: RpcMiddlewareContext<TContext>) => Promise<RpcResponse> | RpcResponse;
};
/**
 * Middleware context that can be augmented with custom fields
 * Generic type parameter allows domain-specific context augmentation
 *
 * @typeParam TCustomContext - Custom context fields to merge with base context
 *
 * @example
 * ```ts
 * type WalletContext = RpcMiddlewareContext<{
 *   productId: string
 *   sourceUrl: string
 *   isAutoContext: boolean
 * }>
 * // { origin: string, source: MessageEventSource | null, productId: string, sourceUrl: string, isAutoContext: boolean }
 * ```
 */
export declare type RpcMiddlewareContext<TCustomContext = Record<string, never>> = RpcRequestContext & TCustomContext;
/**
 * Promise handler function type
 * Handles one-shot requests that return a single promise
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TMethod - The method name from the schema
 * @typeParam TContext - Custom context type augmented by middleware
 */
export declare type RpcPromiseHandler<TSchema extends RpcSchema, TMethod extends ExtractMethod<TSchema>, TContext = Record<string, never>> = (params: ExtractParams<TSchema, TMethod>, context: RpcMiddlewareContext<TContext>) => Promise<ExtractReturnType<TSchema, TMethod>>;
/**
 * Request context for handlers
 * Contains information about the origin and source of the request
 */
export declare type RpcRequestContext = {
    /**
     * Origin of the request
     */
    origin: string;
    /**
     * Message source (for responding)
     */
    source: MessageEventSource | null;
};
/**
 * RPC response wrapper
 * Contains either a successful result or an error
 */
export declare type RpcResponse<TResult = unknown> = {
    result: TResult;
    error?: never;
} | {
    result?: never;
    error: RpcError;
};
/**
 * An RPC schema is a readonly array of schema entries
 *
 * @example
 * ```ts
 * type MySchema = [
 *   {
 *     Method: "greet";
 *     Parameters: [name: string];
 *     ReturnType: string;
 *     ResponseType: "promise";
 *   },
 *   {
 *     Method: "watchTime";
 *     Parameters?: undefined;
 *     ReturnType: number;
 *     ResponseType: "stream";
 *   }
 * ]
 * ```
 */
export declare type RpcSchema = readonly RpcSchemaEntry[];
/**
 * Generic shape of a single RPC schema entry
 *
 * Each entry defines a method with its parameters, return type, and response kind
 *
 * @typeParam TMethod - The method name (string literal)
 * @typeParam TParams - The parameters type (can be undefined for no parameters)
 * @typeParam TReturn - The return type
 * @typeParam TResponseKind - Either "promise" or "stream"
 */
export declare type RpcSchemaEntry<TMethod extends string = string, TParams = unknown, TReturn = unknown> = {
    /**
     * The method name (e.g., "frak_sendInteraction")
     */
    Method: TMethod;
    /**
     * The parameters type (undefined if no parameters)
     */
    Parameters?: TParams;
    /**
     * The return type
     */
    ReturnType: TReturn;
};
/**
 * Stream handler function type
 * Handles streaming requests that can emit multiple values
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TMethod - The method name from the schema
 * @typeParam TContext - Custom context type augmented by middleware
 */
export declare type RpcStreamHandler<TSchema extends RpcSchema, TMethod extends ExtractMethod<TSchema>, TContext = Record<string, never>> = (params: ExtractParams<TSchema, TMethod>, emitter: StreamEmitter<ExtractReturnType<TSchema, TMethod>>, context: RpcMiddlewareContext<TContext>) => Promise<void> | void;
/**
 * Transport interface for RPC communication
 * Abstracts the underlying message passing mechanism (postMessage, etc)
 */
export declare type RpcTransport = {
    /**
     * Send a message through the transport
     */
    postMessage: (message: RpcMessage, targetOrigin: string) => void;
    /**
     * Listen for messages
     */
    addEventListener: (type: "message", listener: (event: MessageEvent<RpcMessage>) => void) => void;
    /**
     * Remove message listener
     */
    removeEventListener: (type: "message", listener: (event: MessageEvent<RpcMessage>) => void) => void;
};
/**
 * Stream emitter function
 * Used by stream handlers to emit multiple values
 */
export declare type StreamEmitter<TResult> = (chunk: TResult) => void;
/**
 * Type-safe request parameters
 *
 * @typeParam TSchema - The RPC schema type
 * @typeParam TMethod - The method name from the schema
 */
export declare type TypedRpcRequest<TSchema extends RpcSchema, TMethod extends ExtractMethod<TSchema>> = {
    method: TMethod;
    params: ExtractParams<TSchema, TMethod>;
};
export { }