import * as polkadot_api from 'polkadot-api'; import { PolkadotSigner } from 'polkadot-api'; import { S as SignerProvider, P as ProviderType, a as SignerAccount, b as SignerError, C as ConnectionStatus, U as Unsubscribe, c as SignerManagerOptions, d as SignerState } from './errors-C_RqDLqL.js'; export { A as AccountNotFoundError, e as AccountPersistence, f as ConnectContext, D as DestroyedError, H as HostDisconnectedError, g as HostRejectedError, h as HostUnavailableError, N as NoAccountsError, O as OnConnect, i as ProviderFactory, j as SigningFailedError, T as TimeoutError, k as isHostError } from './errors-C_RqDLqL.js'; import { RemotePermission } from '@parity/product-sdk-host'; import { Result } from '@parity/result'; export { Result, err, ok } from '@parity/result'; export { SdkError, isSdkError } from '@parity/product-sdk-errors'; import '@parity/product-sdk-address'; /** Options for the Host API provider. */ interface HostProviderOptions { /** SS58 prefix for address encoding. Default: 42 */ ss58Prefix?: number; /** Max retry attempts for initial connection. Default: 3 */ maxRetries?: number; /** Initial retry delay in ms. Default: 500 */ retryDelay?: number; /** * Dapp identifier the SDK falls back to when {@link productAccount} is * not set, so `connect()` can still surface a usable account on hosts * that don't enumerate legacy accounts. * * The value is treated as a product identifier (`.dot` is appended to * non-local names) and routed through `getProductAccount(dappName, 0)`. If * the host rejects the derivation (e.g. the identifier isn't registered), * `connect()` resolves with an empty accounts list rather than * throwing — consumers can still drive the explicit signing paths * (`signMessageWithDotNsIdentity`, `getLegacyAccountSigner`). * * Wired through from `SignerManager` automatically; only set directly * when instantiating `HostProvider` outside the manager. */ dappName?: string; /** * Custom accounts-provider loader. Defaults to `@parity/product-sdk-host`'s * `getAccountsProvider`, which returns `null` outside a host container. * Override for testing or custom host setups. * @internal */ loadAccountsProvider?: () => Promise; /** * Custom `ChainSubmit` permission requester. Defaults to a thin adapter over * `@parity/product-sdk-host`'s `requestPermission` that unwraps its `Result` * (throwing the typed error on the `err` channel). Override for testing. * @internal */ requestChainSubmitPermissionFn?: (permission: RemotePermission) => Promise; /** * Whether to request the host's `ChainSubmit` permission after a * successful `connect()`. Without this, subsequent signing requests are * rejected by the host with `PermissionDenied`. Default: `true`. * * Set to `false` if your app needs to defer the permission prompt or * drives it manually. * * (Previously named `requestTransactionSubmitPermission` — alias kept * for backwards compatibility but the new wire format uses `ChainSubmit`.) */ requestChainSubmitPermission?: boolean; /** @deprecated Renamed to `requestChainSubmitPermission`. */ requestTransactionSubmitPermission?: boolean; /** * If set, `connect()` returns a single product account for the given * `dotNsIdentifier`, skipping the legacy fetch entirely. For apps * that sign exclusively with a per-dapp derived account. * * Signing goes through the host's `createTransaction` path (see PR #96). */ productAccount?: { /** App identifier (e.g., `"playground.dot"`). */ dotNsIdentifier: string; /** Derivation index within the app scope. Default: 0. */ derivationIndex?: number; /** * Populate `SignerAccount.name` best-effort from * `accounts.getUserId().primaryUsername`. * * On by default. Set to `false` to skip the fetch: `getUserId` * triggers a host identity-permission prompt, so apps that don't * render the user's name (those with their own display chain, e.g. * registry username → fallback) can opt out and avoid the prompt. * When enabled and the fetch fails (NotConnected, PermissionDenied, * codec drift) the name stays null and connect still succeeds. The * name can also be fetched later on demand via * {@link HostProvider.getUserId}. Default: `true`. */ requestName?: boolean; }; } /** * A product account — an app-scoped derived account managed by the host wallet. * * The host derives a unique keypair for each app (identified by `dotNsIdentifier`) * so apps get their own account that the user controls but is scoped to the app. */ interface ProductAccount { /** App identifier (e.g., "mark3t.dot"). */ dotNsIdentifier: string; /** Derivation index within the app scope. Default: 0 */ derivationIndex: number; /** Raw public key (32 bytes). */ publicKey: Uint8Array; } /** * A contextual alias obtained from Ring VRF. * * Proves account membership in a ring without revealing which account. */ interface ContextualAlias { /** Ring context (32 bytes). */ context: Uint8Array; /** The Ring VRF alias bytes. */ alias: Uint8Array; } /** * Location of a Ring VRF ring on-chain: the hosting chain's genesis hash plus * the junction path addressing the ring within it. * * Matches the product-sdk's `RingLocation` codec shape. */ interface RingLocation { /** Genesis hash of the chain hosting the ring. */ chainId: string; /** Path addressing the ring within the chain. */ junctions: Array<{ tag: "PalletInstance"; value: number; } | { tag: "CollectionId"; value: string; }>; } /** * A product-scoped proof context, hashed by the host into the 32-byte context * a proof or alias is bound to. * * Matches the product-sdk's `ProductProofContext` codec shape. */ interface ProductProofContext { /** dotNS product identifier (e.g. "my-product.dot") scoping the context. */ productId: string; /** Hex-encoded suffix distinguishing contexts within the product. */ suffix: string; } /** * A Ring VRF proof plus the values needed to verify it downstream. * * Matches the product-sdk's decoded proof shape. */ interface RingVRFProof { /** Raw ring VRF proof bytes. */ proof: Uint8Array; /** Alias derived for the request's context. */ contextualAlias: ContextualAlias; /** Index of the selected member key within the ring. */ ringIndex: number; /** Ring revision the proof was generated against. */ ringRevision: number; } interface RawAccount { publicKey: Uint8Array; name?: string | undefined; } interface NeverthrowResultAsync { match: (ok: (t: T) => A, err: (e: E) => B) => Promise; } /** @internal */ interface AccountsProvider { getLegacyAccounts: () => NeverthrowResultAsync; getLegacyAccountSigner: (account: { publicKey: Uint8Array; }) => polkadot_api.PolkadotSigner; getProductAccount: (dotNsIdentifier: string, derivationIndex?: number) => NeverthrowResultAsync; getProductAccountSigner: (account: ProductAccount) => polkadot_api.PolkadotSigner; getProductAccountAlias: (context: ProductProofContext, location: RingLocation) => NeverthrowResultAsync; getUserId: () => NeverthrowResultAsync<{ primaryUsername: string; }, unknown>; createRingVRFProof: (context: ProductProofContext, location: RingLocation, message: Uint8Array) => NeverthrowResultAsync; subscribeAccountConnectionStatus: (callback: (status: string) => void) => { unsubscribe: () => void; } | (() => void); } /** * Provider for the Host API (Polkadot Desktop / Android). * * Backed by `@parity/product-sdk-host`'s `getAccountsProvider`, which talks to * the host over `@parity/truapi`. Apps running outside a host container — e.g. * a plain browser tab during `npm run dev` — get a `HOST_UNAVAILABLE` error * (the provider resolves to `null`) with actionable guidance, surfaced before * any host RPC call. * * Supports both non-product accounts (user's external wallets) and product * accounts (app-scoped derived accounts managed by the host). */ declare class HostProvider implements SignerProvider { readonly type: ProviderType; private readonly ss58Prefix; private readonly maxRetries; private readonly retryDelay; private readonly loadAccountsProvider; private readonly requestChainSubmitPermissionFn; private readonly requestChainSubmitPermission; private readonly productAccount; private readonly dappName; private accountsProvider; private statusCleanup; private statusListeners; private accountListeners; constructor(options?: HostProviderOptions); connect(signal?: AbortSignal): Promise>; disconnect(): void; onStatusChange(callback: (status: ConnectionStatus) => void): Unsubscribe; onAccountsChange(callback: (accounts: SignerAccount[]) => void): Unsubscribe; /** * Get an app-scoped product account from the host. * * Product accounts are derived by the host wallet for each app, identified * by `dotNsIdentifier` (e.g., "mark3t.dot"). The user controls these accounts * but they are scoped to the requesting app. * * Requires a prior successful `connect()` call. */ getProductAccount(dotNsIdentifier: string, derivationIndex?: number): Promise>; /** * Get a PolkadotSigner for a product account. * * Convenience method for when you already have the product account details. * Requires a prior successful `connect()` call. * * Signing routes through the host's `createTransaction` path, so unknown * signed extensions (e.g. `AsPgas` on Paseo Next) are forwarded to the host * as opaque bytes for metadata-driven decoding. */ getProductAccountSigner(account: ProductAccount): polkadot_api.PolkadotSigner; /** * Get a contextual alias for a product account via Ring VRF. * * Aliases prove account membership in a ring without revealing which * account produced the alias. * * Requires a prior successful `connect()` call. */ getProductAccountAlias(context: ProductProofContext, location: RingLocation): Promise>; /** * Fetch the connected user's primary username from the host. * * Use this to retrieve the name lazily — e.g. on a profile screen that * actually displays it — when `connect()` ran without * `productAccount.requestName` (the default) and so never fetched it. * Like the connect-time fetch this triggers a host identity-permission * prompt; unlike it, the result is returned as a structured `Result` so * callers can react to a `PermissionDenied` / `NotConnected` rejection * explicitly instead of silently falling back to a nameless account. * * Requires a prior successful `connect()` call. */ getUserId(): Promise>; /** * Create a Ring VRF proof for anonymous operations. * * Proves that a member of the ring at the given location produced the * proof without revealing which member — the host selects the member key. * Returns the proof plus its verification values ({@link RingVRFProof}). * * Requires a prior successful `connect()` call. */ createRingVRFProof(context: ProductProofContext, location: RingLocation, message: Uint8Array): Promise>; private tryConnect; private fetchProductSignerAccount; } /** * Core orchestrator for signer management. * * Manages account discovery and signer creation via the Host API. * Framework-agnostic — use the `subscribe()` pattern to integrate with * React, Vue, or any framework. * * ## Lifecycle * * ``` * disconnected → connecting → connected ──── selectAccount / signRaw / … * ▲ │ │ * │ ▼ ▼ * └── disconnect() provider drops → auto-reconnect → connected * (onConnect re-fires) * * ┌─ destroy() ──► (terminal — manager unusable) * ▼ * ``` * * ## Callbacks * * - **`subscribe(cb)`** fires synchronously on every state mutation, in * registration order, inside the call stack that mutated state. It does * **not** fire with the initial state — call `getState()` if you need a * priming read. Multiple mutations during the same operation produce * multiple notifications. * * - **`onConnect(account, ctx)`** (from `SignerManagerOptions`) fires * exactly when the manager transitions from non-connected to * `"connected"` with a selected account. It fires on a microtask * *after* the `subscribe` notification, so subscribers always observe * `state.status === "connected"` before `onConnect`'s side effects run. * It re-fires after auto-reconnect (the SDK reconnects automatically * when the provider drops), and re-fires after a fresh `connect()`. * * - **Internal `onAccountsChange` wiring** is worth a behavioral note: * when the provider reports an updated account list, the manager * preserves the current selection if its address is still present, or * sets `selectedAccount` to `null` if it isn't — it does **not** fall * back to `accounts[0]`. The fallback-to-first only applies on * connect-success, where there is no prior selection to preserve. * * ## `disconnect()` vs `destroy()` * * - `disconnect()` resets state to initial. Subsequent `connect()` calls * work normally. Reversible. * - `destroy()` is **terminal**: the instance is marked unusable, all * subscribers are cleared, and any further call returns `DestroyedError`. * Use in framework teardown (React `useEffect` cleanup, HMR dispose). * * Both methods cancel any in-flight `connect`, reconnect attempt, and * `onConnect` callback (the `ctx.signal` becomes aborted). * * @example * ```ts * const manager = new SignerManager({ * onConnect: async (_account, { requestResourceAllocation }) => { * await requestResourceAllocation([{ tag: "AutoSigning", value: undefined }]); * }, * }); * manager.subscribe(state => console.log(state.status)); * * await manager.connect(); // host provider (default) * await manager.connect("dev"); // Alice / Bob / … for testing * * manager.selectAccount("5GrwvaEF…"); * const signer = manager.getSigner(); * ``` */ declare class SignerManager { private state; private provider; private subscribers; private cleanups; private isDestroyed; private reconnectController; private connectController; private readonly ss58Prefix; private readonly hostTimeout; private readonly maxRetries; private readonly providerFactory; private readonly dappName; private readonly persistenceOption; private resolvedPersistence; private readonly onConnectCallback; private onConnectController; constructor(options?: SignerManagerOptions); private getPersistence; /** Get a snapshot of the current state. */ getState(): SignerState; /** * Subscribe to state changes. * * The callback fires synchronously on every state mutation, in * registration order, inside the call stack that mutated state. It * does **not** fire with the current state at subscription time — * call {@link getState} if you need a priming read. * * For "fired once when the user connects" semantics, prefer the * {@link SignerManagerOptions.onConnect} option instead of gating on * `state.status` inside this callback — `subscribe` will fire many * times while connected (`selectAccount`, account swaps, etc.). * * @returns an unsubscribe function. */ subscribe(callback: (state: SignerState) => void): () => void; /** * Connect to a provider. * * If no provider type is specified, connects to the Host API. * The SDK is designed to run exclusively inside a host container. * * When connecting to a specific provider type: * - `"host"`: Connect to the Host API (default, recommended) * - `"dev"`: Connect using dev accounts (for testing) */ connect(providerType?: ProviderType): Promise>; /** * Disconnect from the current provider and reset state to initial. * * Reversible — subsequent `connect()` calls work normally. Cancels * any in-flight `connect`, reconnect attempt, or `onConnect` callback * (`ctx.signal` becomes aborted). */ disconnect(): void; /** * Select an account by address. * Returns the account on success, or ACCOUNT_NOT_FOUND error. */ selectAccount(address: string): Result; /** * Get the PolkadotSigner for the currently selected account. * Returns null if no account is selected or manager is disconnected. */ getSigner(): PolkadotSigner | null; /** * Sign arbitrary bytes with the currently selected account. * * Convenience wrapper around `PolkadotSigner.signBytes` — useful for * master key derivation, message signing, and proof generation without * constructing a full transaction. * * Returns a SIGNING_FAILED error if no account is selected or signing fails. */ signRaw(data: Uint8Array): Promise>; /** * Fetch the connected user's host identity. * * This uses the Host API identity permission path and is only available * when connected through the host provider. The primary username can be * used by higher-level helpers that need to bind an action to the user's * DotNS / people username. */ getUserId(): Promise>; /** * Get an app-scoped product account from the host. * * Product accounts are derived by the host wallet for each app, identified * by `dotNsIdentifier` (e.g., "mark3t.dot"). Only available when connected * via the host provider — returns HOST_UNAVAILABLE otherwise. * * @example * ```ts * const result = await manager.getProductAccount("myapp.dot"); * if (result.ok) { * const signer = result.value.getSigner(); * } * ``` */ getProductAccount(dotNsIdentifier: string, derivationIndex?: number): Promise>; /** * Get a contextual alias for a proof context and ring via Ring VRF. * * Aliases prove account membership in a ring without revealing which * account produced the alias; the host selects the member key. Only * available when connected via the host provider — returns * HOST_UNAVAILABLE otherwise. */ getProductAccountAlias(context: ProductProofContext, location: RingLocation): Promise>; /** * Create a Ring VRF proof for anonymous operations. * * Proves that a ring member at the given location produced the proof * without revealing which member — the host selects the member key. The * result carries the proof plus its verification values. Only available * when connected via the host provider — returns HOST_UNAVAILABLE * otherwise. */ createRingVRFProof(context: ProductProofContext, location: RingLocation, message: Uint8Array): Promise>; /** * Destroy the manager and release all resources. * * **Terminal** — clears all subscribers, cancels in-flight work, and * marks the instance unusable. Any subsequent method returns * `DestroyedError`. Idempotent. Use in framework teardown (React * `useEffect` cleanup, HMR dispose). For a reversible reset, use * {@link disconnect} instead. */ destroy(): void; private connectToProvider; private createProvider; private handleProviderStatusChange; private attemptReconnect; /** Returns the underlying HostProvider if connected via host, or null otherwise. */ private getHostProvider; private cancelConnect; private cancelReconnect; private cancelOnConnect; private fireOnConnect; private disconnectInternal; private persistAccount; private loadPersistedAccount; private setState; } /** * Sleep for a given duration, cancellable via AbortSignal. * * Resolves immediately if the signal is already aborted. * Cleans up the abort listener when the timer fires naturally * to prevent listener accumulation in retry loops. */ declare function sleep(ms: number, signal?: AbortSignal): Promise; /** Options for retry with exponential backoff. */ interface RetryOptions { /** Maximum number of attempts. Default: 3 */ maxAttempts?: number; /** Initial delay in ms before first retry. Default: 500 */ initialDelay?: number; /** Multiplier applied to delay after each attempt. Default: 2 */ backoffMultiplier?: number; /** Maximum delay cap in ms. Default: 10_000 */ maxDelay?: number; /** AbortSignal to cancel retries early. */ signal?: AbortSignal; } /** * Retry an async operation with exponential backoff. * * Calls `fn` up to `maxAttempts` times. If `fn` returns an error result, * waits with exponential backoff before the next attempt. Returns the first * successful result or the last error. */ declare function withRetry(fn: (attempt: number) => Promise>, options?: RetryOptions): Promise>; /** Standard Substrate dev account names. */ declare const DEFAULT_DEV_NAMES: readonly ["Alice", "Bob", "Charlie", "Dave", "Eve", "Ferdie"]; /** A well-known Substrate development account name (Alice, Bob, …) used to derive deterministic dev accounts from the standard Substrate dev mnemonic. */ type DevAccountName = (typeof DEFAULT_DEV_NAMES)[number]; /** Supported key types for dev account derivation. */ type DevKeyType = "sr25519" | "ed25519"; /** Options for the dev account provider. */ interface DevProviderOptions { /** Which dev accounts to create. Default: all 6 standard accounts. */ names?: readonly string[]; /** Custom mnemonic phrase instead of DEV_PHRASE. */ mnemonic?: string; /** SS58 prefix for address encoding. Default: 42 */ ss58Prefix?: number; /** Key type for account derivation. Default: "sr25519" */ keyType?: DevKeyType; } /** * Provider for Substrate development accounts. * * Uses the well-known DEV_PHRASE with hard derivation paths (`//Alice`, `//Bob`, etc.) * to create deterministic accounts for local development and testing. */ declare class DevProvider implements SignerProvider { readonly type: "dev"; private readonly names; private readonly mnemonic; private readonly ss58Prefix; private readonly keyType; constructor(options?: DevProviderOptions); connect(): Promise>; disconnect(): void; onStatusChange(_callback: (status: "disconnected" | "connecting" | "connected") => void): Unsubscribe; onAccountsChange(_callback: (accounts: SignerAccount[]) => void): Unsubscribe; } export { ConnectionStatus, type ContextualAlias, type DevAccountName, type DevKeyType, DevProvider, type DevProviderOptions, HostProvider, type HostProviderOptions, type ProductAccount, type ProductProofContext, ProviderType, type RetryOptions, type RingLocation, type RingVRFProof, SignerAccount, SignerError, SignerManager, SignerManagerOptions, SignerProvider, SignerState, Unsubscribe, sleep, withRetry };