Skip to Content
API ReferenceterminalOverview

@parity/product-sdk-terminal

npm install @parity/product-sdk-terminal

Exports

Classes

NameSummary
AllowanceError—

Functions

NameSummary
createNodeStorageAdapter()Create a file-based StorageAdapter for use with the host-papp SDK in Node.js.
createSessionSigner()Create a PolkadotSigner backed by a QR-paired mobile wallet session,
createSessionSignerForAccount()Create a PolkadotSigner for a specific sub-account of a paired session.
createTerminalAdapter()—
deriveProductPublicKey()The product account’s sr25519 public key for ref.
getBulletinSigner()Get a PolkadotSigner for a Bulletin allowance slot.
getProductSubtreePublicKey()Fetch the subtree public key for productId, reaching the wallet only on a
getStatementStoreProver()Get a StatementProver for a statement-store allowance slot.
hasBulletinAllowance()Cache-only probe for a Bulletin allowance slot. Resolves true when a
hasStatementStoreAllowance()Cache-only probe for a Statement Store allowance slot. Resolves true
isBenignTeardownError()Whether error is the benign teardown noise @novasamatech/statement-store
renderQrCode()Encode a string as a QR code rendered in Unicode half-block characters.
requestResourceAllocation()Send the AP request_resource_allocation message over the paired
sendResourceAllocation()Send an AP request_resource_allocation message over the paired session and
sessionRootPublicKey()The wallet’s own root account key. Product accounts do not derive from it:
waitForSessions()Wait for the adapter to load at least one persisted session, or resolve

Interfaces

NameSummary
ProductAccountRefIdentifies which sub-account of a paired session should sign.
ProductSubtreeOptions—
QrRenderOptionsOptions for QR code rendering.
RequestResourceAllocationOptions—
SessionSignerOptions—
TerminalAdapterOptionsOptions for creating a terminal adapter.

Type Aliases

NameSummary
AllocatableResourceOne resource a Host can request from the Account Holder. AutoSigning
AllowanceErrorReason—
AllowanceService—
ApAllocationOutcomePer-resource outcome. Allocated.value carries the materialized payload
HostMetadata—
OnExistingAllowancePolicy"Ignore": return existing keys if any, else allocate one slot.
PairingStatus—
PappAdapter—
SigningPayloadRequest—
SigningPayloadResponse—
SigningRawRequest—
StatementStoreEnvironmentNetwork keys with built-in endpoints in StatementStoreNetworks.
StoredUserSession—
TerminalAdapterA PappAdapter with the appId it was created with and a destroy method for cleanup.
UserSession—

Variables

NameSummary
INCOMPLETE_SESSION_MESSAGE—
SS_STABLE_STAGE_ENDPOINTS—
StatementStoreNetworks—

Re-exports

Convenience re-exports from leaf packages. Click through for the canonical documentation.

NameKindSource package
AllowanceExpiredErrorclass@parity/product-sdk-signer
SignerErrorclass@parity/product-sdk-signer

Classes

class AllowanceError

Extends: Error

Constructors

constructor
new AllowanceError(reason: AllowanceErrorReason, message?: string): AllowanceError

Properties

reason
propertyreadonlyAllowanceErrorReason

Functions

createNodeStorageAdapter()

Create a file-based StorageAdapter for use with the host-papp SDK in Node.js.

Data is stored as individual JSON files in the given directory (defaults to ~/.polkadot-apps/).

createNodeStorageAdapter(appId: string, storageDir?: string): StorageAdapter

createSessionSigner()

Create a PolkadotSigner backed by a QR-paired mobile wallet session, using the session’s default account (derivationIndex: 0).

For non-default sub-accounts, use createSessionSignerForAccount.

createSessionSigner(session: UserSession, adapter: TerminalAdapter, publicKey?: Uint8Array<ArrayBufferLike>, options?: SessionSignerOptions): Promise<PolkadotSigner>

Parameters

  • session: The paired user session.
  • adapter: The TerminalAdapter that loaded the session. Its appId is used as the productId in the wire request.
  • publicKey: The product account’s sr25519 public key for [adapter.appId, 0]. Optional — when omitted it’s fetched and derived. See ProductAccountRef.publicKey.

createSessionSignerForAccount()

Create a PolkadotSigner for a specific sub-account of a paired session.

Use this when you need a derivation index other than 0, or a productId different from the adapter’s appId. For the common default-account case, prefer createSessionSigner.

createSessionSignerForAccount(session: UserSession, ref: ProductAccountRef, options?: SessionSignerOptions): Promise<PolkadotSigner>

Parameters

  • session: The paired user session.
  • ref: The product account to sign as: \{ productId, derivationIndex \}.

createTerminalAdapter()

createTerminalAdapter(options: TerminalAdapterOptions): TerminalAdapter

deriveProductPublicKey()

The product account’s sr25519 public key for ref.

The one place product-account math happens, so a displayed address cannot desync from what the signer signs with.

deriveProductPublicKey(session: UserSession, ref: ProductAccountRef, options?: ProductSubtreeOptions): Promise<Uint8Array<ArrayBufferLike>>

Throws

  • Error when the wallet is unreachable on a cold cache.

getBulletinSigner()

Get a PolkadotSigner for a Bulletin allowance slot.

Allocates an allowance slot via the paired wallet (or returns the cached one), derives the slot-account keypair, and returns a PolkadotSigner that signs Bulletin extrinsics with it. Replaces the manual requestResourceAllocation + createSlotAccountSigner two-step for the common case.

getBulletinSigner(adapter: TerminalAdapter, productId: string, sessionId?: string): Promise<PolkadotSigner>

Parameters

  • adapter: Terminal adapter.
  • productId: The product id the slot is allocated under. Passed to the host as the calling product id in the allowance request.
  • sessionId: Paired session to allocate against. Defaults to the only paired session; throws AllowanceError('NoSession') when zero or more than one sessions are paired and no explicit id is supplied.

Throws

  • On rejection, missing session, host-side failure, or unexpected response shape.

Examples

import { createTerminalAdapter, getBulletinSigner } from "@parity/product-sdk-terminal"; const adapter = createTerminalAdapter({ appId: "my-cli" }); // ... QR pair, wait for session ... const signer = await getBulletinSigner(adapter, "my-cli.dot"); await client.bulletin.tx.TransactionStorage.store({ data }).signAndSubmit(signer);

getProductSubtreePublicKey()

Fetch the subtree public key for productId, reaching the wallet only on a cold cache.

getProductSubtreePublicKey(session: UserSession, productId: string, options: ProductSubtreeOptions = {}): Promise<Uint8Array<ArrayBufferLike>>

Throws

  • Error when the wallet rejects the request or returns a malformed key.

getStatementStoreProver()

Get a StatementProver for a statement-store allowance slot.

Allocates an allowance slot via the paired wallet (or returns the cached one) and returns the upstream StatementProver for the slot. Use when publishing statements through @novasamatech/statement-store without holding a long-lived key yourself.

getStatementStoreProver(adapter: TerminalAdapter, productId: string, sessionId?: string): Promise<StatementProver>

Parameters

  • adapter: Terminal adapter.
  • productId: The product id the slot is allocated under.
  • sessionId: Paired session to allocate against. Defaults to the only paired session; throws AllowanceError('NoSession') when zero or more than one sessions are paired and no explicit id is supplied.

Throws

  • On rejection, missing session, host-side failure, or unexpected response shape.

hasBulletinAllowance()

Cache-only probe for a Bulletin allowance slot. Resolves true when a slot key for (sessionId, productId, bulletin) is already cached on disk; false when it is not. Never prompts the paired wallet.

Pair with getBulletinSigner for the “check first, fetch only if needed” flow:

hasBulletinAllowance(adapter: TerminalAdapter, productId: string, sessionId?: string): Promise<boolean>

Examples

if (await hasBulletinAllowance(adapter, "my-cli.dot")) { // happy path — fetch the signer without risking a wallet prompt const signer = await getBulletinSigner(adapter, "my-cli.dot"); } else { // tell the user a wallet prompt will fire, then call getBulletinSigner }

hasStatementStoreAllowance()

Cache-only probe for a Statement Store allowance slot. Resolves true when a slot key for (sessionId, productId, statementStore) is already cached on disk; false when it is not. Never prompts the paired wallet.

Pair with getStatementStoreProver for the “check first, fetch only if needed” flow.

hasStatementStoreAllowance(adapter: TerminalAdapter, productId: string, sessionId?: string): Promise<boolean>

isBenignTeardownError()

Whether error is the benign teardown noise @novasamatech/statement-store emits when a statement subscription’s observable errors because the client was destroyed underneath it — the raw-client’s DestroyedError: Client destroyed.

Matches on the message text only. Matching the DestroyedError name would also swallow @parity/product-sdk-signer’s own DestroyedError (a direct dependency, message “SignerManager has been destroyed”), so a real signer failure during teardown would vanish — and this predicate is exported, so it would carry that to consumers. Client destroyed is unique to the upstream line.

Exported so a consumer’s own console.error guard can drop this line without reinventing the match. createTerminalAdapter’s own destroy() already suppresses it (see suppressBenignTeardownErrors); this is for code paths outside that window.

isBenignTeardownError(error: unknown): boolean

renderQrCode()

Encode a string as a QR code rendered in Unicode half-block characters.

Returns a multi-line string suitable for console.log.

renderQrCode(data: string, options?: QrRenderOptions): Promise<string>

requestResourceAllocation()

Send the AP request_resource_allocation message over the paired session; block on the user’s mobile dialog; return outcomes in request order. Granted key material is cached on disk so subsequent calls skip the wallet prompt.

requestResourceAllocation(session: UserSession, adapter: TerminalAdapter, resources: { tag: "StatementStoreAllowance"; value: undefined } | { tag: "SmartContractAllowance"; value: { tag: "Index"; value: number } | { tag: "Raw"; value: Uint8Array<ArrayBufferLike> } } | { tag: "AutoSigning"; value: undefined } | { tag: "BulletInAllowance"; value: undefined }[], options: RequestResourceAllocationOptions = {}): Promise<{ tag: "Rejected"; value: undefined } | { tag: "Allocated"; value: { tag: "StatementStoreAllowance"; value: { slotAccountKey: Uint8Array<ArrayBufferLike> } } | { tag: "SmartContractAllowance"; value: undefined } | { tag: "AutoSigning"; value: { productRootPrivateKey: Uint8Array<ArrayBufferLike>; ringVrfDomainEntropy: Uint8Array<ArrayBufferLike> } } | { tag: "BulletInAllowance"; value: { slotAccountKey: Uint8Array<ArrayBufferLike> } } } | { tag: "NotAvailable"; value: undefined }[]>

Throws

  • If the session call fails (transport, timeout, AH protocol error).

Examples

const [session] = adapter.sessions.sessions.read(); const outcomes = await requestResourceAllocation(session, adapter, [ { tag: "BulletInAllowance", value: undefined }, ]);

sendResourceAllocation()

Send an AP request_resource_allocation message over the paired session and return the outcomes in request order. This is the raw wire call: no disk cache, no onExisting auto-pick, no adapter. Callers that want the caching / slot-reuse behaviour should use requestResourceAllocation instead; this primitive exists for consumers (e.g. @parity/product-sdk-auth) that only hold a productId and manage their own policy.

sendResourceAllocation(session: UserSession, productId: string, resources: { tag: "StatementStoreAllowance"; value: undefined } | { tag: "SmartContractAllowance"; value: { tag: "Index"; value: number } | { tag: "Raw"; value: Uint8Array<ArrayBufferLike> } } | { tag: "AutoSigning"; value: undefined } | { tag: "BulletInAllowance"; value: undefined }[], onExisting: "Ignore" | "Increase"): Promise<{ tag: "Rejected"; value: undefined } | { tag: "Allocated"; value: { tag: "StatementStoreAllowance"; value: { slotAccountKey: Uint8Array<ArrayBufferLike> } } | { tag: "SmartContractAllowance"; value: undefined } | { tag: "AutoSigning"; value: { productRootPrivateKey: Uint8Array<ArrayBufferLike>; ringVrfDomainEntropy: Uint8Array<ArrayBufferLike> } } | { tag: "BulletInAllowance"; value: { slotAccountKey: Uint8Array<ArrayBufferLike> } } } | { tag: "NotAvailable"; value: undefined }[]>

Throws

  • If the session call fails (transport, timeout, AH protocol error).

sessionRootPublicKey()

The wallet’s own root account key. Product accounts do not derive from it: RFC-0022 puts two hard junctions in between.

sessionRootPublicKey(session: UserSession): Uint8Array

Throws

  • INCOMPLETE_SESSION_MESSAGE if the session predates the rootAccountId field.

waitForSessions()

Wait for the adapter to load at least one persisted session, or resolve with an empty array after timeoutMs.

The session manager loads sessions from storage asynchronously, so a synchronous adapter.sessions.sessions.read() immediately after createTerminalAdapter() may return [] even when sessions exist on disk. Use this helper to give the loader a chance to populate before deciding whether the user is logged in.

waitForSessions(adapter: TerminalAdapter, timeoutMs: number = 3000): Promise<UserSession[]>

Interfaces

interface ProductAccountRef

Identifies which sub-account of a paired session should sign.

Mirrors the host-papp wire format productAccountId: [productId, index]: productId is the dotNS-style identifier for the requesting product (matches the adapter’s appId in normal usage); derivationIndex is the BIP32-style child-key index, where 0 is the session’s default account.

Properties

derivationIndex
propertynumber

Child-key derivation index. 0 is the default account.

productId
propertystring

The product identifier. Usually equal to the adapter’s appId.

publicKey
propertyoptionalUint8Array<ArrayBufferLike>

The product account’s sr25519 public key (32 bytes), as derived by the host for [productId, derivationIndex].

PAPI stamps this into the extrinsic’s signer address and verifies against it, so a mismatch produces an invalid signature.

When omitted, the signer fetches the subtree key and derives it. Supply it to skip that round trip.

interface ProductSubtreeOptions

Properties

appId
propertyoptionalstring

Names the cache file. Defaults to the productId.

storageDir
propertyoptionalstring

interface QrRenderOptions

Options for QR code rendering.

Properties

errorCorrectionLevel
propertyoptional"L" | "M" | "Q" | "H"

Error correction level. Default: “M”.

margin
propertyoptionalnumber

Quiet zone size in modules. Default: 2.

interface RequestResourceAllocationOptions

Properties

onExisting
propertyoptional"Ignore" | "Increase"

Override the auto-picked onExisting. Default: Ignore unless every requested resource is a cached slot-table variant, then Increase.

productId
propertyoptionalstring

Product id the allocation is scoped to. Sent on the wire as callingProductId and used as the slot-cache namespace. Defaults to adapter.appId.

Pass this when the product id the app signs as differs from the terminal’s storage appId — the wallet derives every per-product artifact (including the on-chain account PGAS is minted to and auto-mapped for) from this id, so allocating under the wrong id lands the allowance on the wrong account. Mirrors the explicit productId that getBulletinSigner already takes.

interface SessionSignerOptions

Extends: ProductSubtreeOptions

Properties

txExtVersion
propertyoptionalnumber

Extension version of the supplied signTx bytes. Defaults to 0; does not change encoding.

interface TerminalAdapterOptions

Options for creating a terminal adapter.

Properties

appId
propertystring

Unique app identifier. Used as the storage namespace.

endpoints
propertyoptionalstring[]

Statement store WebSocket endpoints. Defaults to StatementStoreNetworks.paseo.

hostMetadata
propertyoptionalHandshakeMetadata

Optional host metadata for the Sign-In screen.

storageDir
propertyoptionalstring

Directory where session files are persisted. Defaults to ~/.polkadot-apps/. Override in tests to point at a temporary directory populated with createTestSession from @parity/product-sdk-terminal/testing.

Type Aliases

type AllocatableResource

One resource a Host can request from the Account Holder. AutoSigning currently returns NotAvailable on both Android and iOS wallets.

type AllocatableResource = ResourceAllocationRequest["resources"][number]

type AllowanceErrorReason

type AllowanceErrorReason = "NoSession" | "Rejected" | "NotAvailable" | "UnexpectedResponse"

type AllowanceService

type AllowanceService = unknown

type ApAllocationOutcome

Per-resource outcome. Allocated.value carries the materialized payload (slot account key for Bulletin/SSS; subtree key + secret for AutoSigning; undefined for SC). Each entry is independent — no rollback on partial success.

type ApAllocationOutcome = ExtractOk<ReturnType<UserSession["requestResourceAllocation"]>>[number]

type HostMetadata

type HostMetadata = HandshakeMetadata

type OnExistingAllowancePolicy

"Ignore": return existing keys if any, else allocate one slot. "Increase": add one slot to an existing allowance account.

type OnExistingAllowancePolicy = ResourceAllocationRequest["onExisting"]

type PairingStatus

type PairingStatus = { step: "none" } | { step: "initial" } | { payload: string; step: "pairing" } | { stage: string; step: "pending" } | { message: string; step: "pairingError" } | { session: StoredUserSession; step: "finished" }

type PappAdapter

type PappAdapter = unknown

type SigningPayloadRequest

type SigningPayloadRequest = CodecType<typeof SigningPayloadRequestCodec>

type SigningPayloadResponse

type SigningPayloadResponse = CodecType<typeof SigningResponseCodec>

type SigningRawRequest

type SigningRawRequest = CodecType<typeof SigningRawRequestCodec>

type StatementStoreEnvironment

Network keys with built-in endpoints in StatementStoreNetworks.

type StatementStoreEnvironment = keyof typeof StatementStoreNetworks

type StoredUserSession

type StoredUserSession = CodecType<typeof storedUserSessionCodec>

type TerminalAdapter

A PappAdapter with the appId it was created with and a destroy method for cleanup.

type TerminalAdapter = PappAdapter & { readonly appId: string; readonly storageDir?: string; destroy: unknown }

type UserSession

type UserSession = StoredUserSession & { abortPendingRequests: unknown; createRingVrfProof: unknown; createTransaction: unknown; createTransactionLegacy: unknown; dispose: unknown; getIdentity: unknown; getProductSubtree: unknown; getRingVrfAlias: unknown; listRingVrfKeys: unknown; readAllowance: unknown; registerRingVrfKey: unknown; requestResourceAllocation: unknown; ringVrfSign: unknown; sendDisconnectMessage: unknown; signPayload: unknown; signRaw: unknown; signRawLegacy: unknown; signVrf: unknown; subscribe: unknown }

Variables

INCOMPLETE_SESSION_MESSAGE

let INCOMPLETE_SESSION_MESSAGE: "Stored login session is missing the root account public key. Run \"logout\" and then \"login\" to pair again." = 'Stored login session is missing the root account public key. Run "logout" and then "login" to pair again.'

SS_STABLE_STAGE_ENDPOINTS

let SS_STABLE_STAGE_ENDPOINTS: string[]

StatementStoreNetworks

let StatementStoreNetworks: { paseo: string[]; previewnet: string[] } = ...