@novasamatech/host-api-wrapper 0.7.9-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,429 @@
1
+ # @novasamatech/host-api-wrapper
2
+
3
+ An easy way to embed Polkadot host functionality into your dapp.
4
+
5
+ ## Overview
6
+
7
+ Product SDK provides a set of tools to integrate your application with any Polkadot host application.
8
+ Core features:
9
+ - Generic injectWeb3 provider similar to [polkadot-js extension](https://polkadot.js.org/extension/)
10
+ - Chat module integration
11
+ - Statement store integration
12
+ - Accounts provider for product accounts and signing
13
+ - Redirect [PAPI](https://papi.how/) requests to host application
14
+ - Receive additional information from host application - supported chains, theme, etc.
15
+ - Local storage for persisting data in the host application
16
+ - Preimage manager for looking up and submitting preimages
17
+
18
+ ## Installation
19
+
20
+ ```shell
21
+ npm install @novasamatech/host-api-wrapper --save -E
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Injecting account provider into `injectedWeb3` interface
27
+
28
+ Product SDK can provide account information and signers with the same interface as any other Polkadot-compatible wallet.
29
+
30
+ ```ts
31
+ import { injectSpektrExtension, SpektrExtensionName } from '@novasamatech/host-api-wrapper';
32
+ import { connectInjectedExtension, type InjectedPolkadotAccount } from '@polkadot-api/pjs-signer';
33
+
34
+ async function getSpektrExtension() {
35
+ const ready = await injectSpektrExtension();
36
+
37
+ if (ready) {
38
+ return connectInjectedExtension(SpektrExtensionName)
39
+ }
40
+
41
+ return null;
42
+ }
43
+
44
+ async function getAccounts(): Promise<InjectedPolkadotAccount[]> {
45
+ const extension = await getSpektrExtension();
46
+
47
+ if (extension) {
48
+ return extension.getAccounts()
49
+ }
50
+
51
+ // fallback to other providers
52
+ return [];
53
+ }
54
+ ```
55
+
56
+ ### Redirecting PAPI requests to host application
57
+
58
+ You can wrap your PAPI provider with Spektr provider to support redirecting requests to the host application.
59
+
60
+ ```diff
61
+ import { createClient, type PolkadotClient } from 'polkadot-api';
62
+ import { getWsProvider } from 'polkadot-api/ws-provider';
63
+ import { createPapiProvider, WellKnownChain } from '@novasamatech/host-api-wrapper';
64
+
65
+ function createPapiClient(): PolkadotClient {
66
+ const polkadotEndpoint = 'wss://...';
67
+
68
+ - const provider = getWsProvider(polkadotEndpoint);
69
+ + const provider = createPapiProvider({
70
+ + chainId: WellKnownChain.polkadotRelay,
71
+ + fallback: getWsProvider(polkadotEndpoint),
72
+ + });
73
+
74
+ return createClient(provider);
75
+ }
76
+ ```
77
+
78
+ ### Subscribing host connection status
79
+
80
+ ```ts
81
+ import { metaProvider } from '@novasamatech/host-api-wrapper';
82
+
83
+ const unsubscribe = metaProvider.subscribeConnectionStatus((status) => {
84
+ console.log('connection status changed', status);
85
+ });
86
+ ```
87
+
88
+ ### Chat Integration
89
+
90
+ ```ts
91
+ import { createProductChatManager } from '@novasamatech/host-api-wrapper';
92
+
93
+ // Create manager instance
94
+ const chat = createProductChatManager();
95
+
96
+ // Register your product as a chat contact
97
+ const roomRegistrationStatus = await chat.registerRoom({
98
+ roomId: 'my-product-room',
99
+ name: 'My Product',
100
+ icon: 'https://example.com/icon.png'
101
+ });
102
+
103
+ // Register your product as a chat bot
104
+ const botRegistrationStatus = await chat.registerBot({
105
+ botId: 'my-product-bot',
106
+ name: 'My Product',
107
+ icon: 'https://example.com/icon.png'
108
+ });
109
+
110
+ // Send a message
111
+ const { messageId } = await chat.sendMessage('my-product-room', {
112
+ tag: 'Text',
113
+ value: 'Hello dear user!'
114
+ });
115
+
116
+ // Subscribing to chat actions (incoming messages, etc.)
117
+ const subscriber = chat.subscribeAction((action) => {
118
+ console.log('Room:', action.roomId);
119
+ console.log('Sender:', action.peer);
120
+
121
+ const payload = action.payload;
122
+
123
+ if (payload.tag === 'MessagePosted') {
124
+ console.log('Received message:', action.value);
125
+ }
126
+ if (payload.tag === 'ActionTriggered') {
127
+ console.log('User triggered action:', action.value)
128
+ }
129
+ });
130
+
131
+ // Subscribing to chat room list updates
132
+ const chatListSubscriber = chat.subscribeChatList((rooms) => {
133
+ console.log('Chat rooms updated:', rooms);
134
+ });
135
+
136
+ // Sending a custom message
137
+ await chat.sendMessage('my-product-room', {
138
+ tag: 'Custom',
139
+ value: { messageType: 'my-custom-type', payload: new Uint8Array([/* ... */]) }
140
+ });
141
+
142
+ // Handling custom message rendering requests from host
143
+ const unsubscribeRenderer = chat.onCustomMessageRenderingRequest((messageType, payload, render) => {
144
+ // Build a CustomRendererNode tree and pass it to render()
145
+ render({
146
+ tag: 'Text',
147
+ value: {
148
+ modifiers: undefined,
149
+ props: { style: undefined, color: undefined },
150
+ children: [{ tag: 'String', value: 'Custom message content' }],
151
+ },
152
+ });
153
+
154
+ return () => {
155
+ // cleanup when subscription ends
156
+ };
157
+ });
158
+ ```
159
+
160
+ **Note:** Messages sent before registration will be queued and sent automatically after successful registration.
161
+
162
+ ### Statement Store
163
+
164
+ The Statement Store provides a decentralized way to store statements (messages).
165
+ It can be used for various purposes like p2p communication, storing temp data, etc.
166
+
167
+ ```ts
168
+ import { createStatementStore } from '@novasamatech/host-api-wrapper';
169
+ import type { Topic, Statement, SignedStatement, StatementTopicFilter } from '@novasamatech/host-api-wrapper';
170
+
171
+ // Create statement store instance
172
+ const statementStore = createStatementStore();
173
+
174
+ // Define topics (32-byte identifiers) to categorize statements
175
+ const topic: Topic = new Uint8Array(32);
176
+
177
+ // Subscribe to statements matching ALL listed topics (AND semantics)
178
+ const filter: StatementTopicFilter = { matchAll: [topic] };
179
+ const subscription = statementStore.subscribe(filter, (page) => {
180
+ // page.isComplete is true once the initial historical dump is done
181
+ console.log('Received statements:', page.statements, 'synced:', page.isComplete);
182
+ });
183
+
184
+ // Create a proof for a new statement
185
+ const accountId = ['product.dot', 0]; // [DotNS identifier, derivation index]
186
+ const statement: Statement = {
187
+ proof: undefined,
188
+ decryptionKey: undefined,
189
+ priority: undefined,
190
+ channel: undefined,
191
+ topics: [topic],
192
+ data: new Uint8Array([/* your data */]),
193
+ };
194
+
195
+ const proof = await statementStore.createProof(accountId, statement);
196
+
197
+ // Submit a signed statement
198
+ const signedStatement: SignedStatement = {
199
+ ...statement,
200
+ proof,
201
+ };
202
+
203
+ await statementStore.submit(signedStatement);
204
+
205
+ // Unsubscribe when done
206
+ subscription.unsubscribe();
207
+ ```
208
+
209
+ ### Accounts Provider
210
+
211
+ The Accounts Provider allows you to access product accounts and create signers for signing transactions.
212
+
213
+ ```ts
214
+ import { accounts } from '@novasamatech/host-api-wrapper';
215
+ import type { ProductAccount } from '@novasamatech/host-api-wrapper';
216
+
217
+ // Get the user's primary DotNS username (RFC-0014)
218
+ // — prompts for permission on first call
219
+ const userIdResult = await accounts.getUserId();
220
+
221
+ if (userIdResult.isOk()) {
222
+ const { primaryUsername } = userIdResult.value;
223
+ console.log('Primary username:', primaryUsername);
224
+ } else {
225
+ const err = userIdResult.error;
226
+ if (err.tag === 'NotConnected') {
227
+ console.log('User is not logged in');
228
+ } else if (err.tag === 'PermissionDenied') {
229
+ console.log('User denied disclosure of their primary username');
230
+ }
231
+ }
232
+
233
+ // Request login — triggers host sign-in UI; reason is shown to the user
234
+ const loginResult = await accounts.requestLogin('Sign in to access your account');
235
+
236
+ if (loginResult.isOk()) {
237
+ const outcome = loginResult.value; // 'success' | 'alreadyConnected' | 'rejected'
238
+ if (outcome === 'rejected') {
239
+ console.log('User cancelled login');
240
+ }
241
+ } else {
242
+ console.error('Login error:', loginResult.error);
243
+ }
244
+
245
+ // Get a product account by DotNS identifier and derivation index
246
+ const accountResult = await accounts.getProductAccount('product.dot', 0);
247
+
248
+ if (accountResult.isOk()) {
249
+ const account: ProductAccount = accountResult.value;
250
+ console.log('Public key:', account.publicKey);
251
+ }
252
+
253
+ // Get account alias
254
+ const aliasResult = await accounts.getProductAccountAlias('product.dot', 0);
255
+
256
+ if (aliasResult.isOk()) {
257
+ console.log('Alias:', aliasResult.value);
258
+ }
259
+
260
+ // Get legacy accounts (external wallets)
261
+ const legacyAccountsResult = await accounts.getLegacyAccounts();
262
+
263
+ if (legacyAccountsResult.isOk()) {
264
+ console.log('Legacy accounts:', legacyAccountsResult.value);
265
+ }
266
+
267
+ // Subscribe to account connection status changes
268
+ const unsubscribe = accounts.subscribeAccountConnectionStatus((status) => {
269
+ // status: 'connected' | 'disconnected'
270
+ console.log('Account connection status:', status);
271
+ });
272
+
273
+ // Create a signer for a product account (for use with PAPI).
274
+ // Resolve the account first, then hand it to the signer factory.
275
+ const productAccountResult = await accounts.getProductAccount('product.dot', 0);
276
+
277
+ if (productAccountResult.isOk()) {
278
+ const productSigner = accounts.getProductAccountSigner(productAccountResult.value);
279
+ const signedTx = await tx.signAndSubmit(productSigner);
280
+ }
281
+
282
+ // Create a signer for a legacy account.
283
+ // Fetch the legacy account list, pick one, then pass it to the signer factory.
284
+ const legacyAccountsResult = await accounts.getLegacyAccounts();
285
+
286
+ if (legacyAccountsResult.isOk()) {
287
+ const [legacyAccount] = legacyAccountsResult.value;
288
+ if (legacyAccount) {
289
+ const legacySigner = accounts.getLegacyAccountSigner(legacyAccount);
290
+ const signedTx = await tx.signAndSubmit(legacySigner);
291
+ }
292
+ }
293
+ ```
294
+
295
+ > If you need a non-default transport (e.g. for tests or multi-host setups), use `createAccountsProvider(transport)` to build your own instance with the same API.
296
+
297
+ ### Local Storage
298
+
299
+ The Local Storage module provides a way to persist data in the host application's storage.
300
+
301
+ ```ts
302
+ import { hostLocalStorage, createLocalStorage } from '@novasamatech/host-api-wrapper';
303
+
304
+ // Use the default instance
305
+ const storage = hostLocalStorage;
306
+
307
+ // Or create a custom instance with a different transport
308
+ // const storage = createLocalStorage(customTransport);
309
+
310
+ // Write and read raw bytes
311
+ await storage.writeBytes('key', new Uint8Array([1, 2, 3]));
312
+ const bytes = await storage.readBytes('key');
313
+
314
+ // Write and read strings
315
+ await storage.writeString('greeting', 'Hello, World!');
316
+ const greeting = await storage.readString('greeting');
317
+
318
+ // Write and read JSON
319
+ await storage.writeJSON('config', { theme: 'dark', fontSize: 14 });
320
+ const config = await storage.readJSON('config');
321
+
322
+ // Clear a key
323
+ await storage.clear('key');
324
+ ```
325
+
326
+ ### Derive Entropy
327
+
328
+ The Derive Entropy function allows products to derive deterministic 32-byte entropy scoped to the product and a caller-chosen key.
329
+
330
+ ```ts
331
+ import { deriveEntropy } from '@novasamatech/host-api-wrapper';
332
+
333
+ const result = await deriveEntropy(new Uint8Array([1, 2, 3]));
334
+
335
+ if (result.isOk()) {
336
+ const entropy: Uint8Array = result.value;
337
+ console.log('Derived entropy:', entropy);
338
+ }
339
+ ```
340
+
341
+ ### Permissions
342
+
343
+ Products can request device and remote permissions from the host. Decisions are prompted once and persisted permanently — subsequent calls for the same permission resolve immediately without prompting.
344
+
345
+ ```ts
346
+ import { requestDevicePermission, requestPermission } from '@novasamatech/host-api-wrapper';
347
+
348
+ // Request a single device permission
349
+ const deviceResult = await requestDevicePermission('Camera');
350
+ if (deviceResult.isOk()) {
351
+ console.log('Camera granted:', deviceResult.value); // boolean
352
+ }
353
+
354
+ // Request remote permissions in a batch (single user prompt for all)
355
+ const remoteResult = await requestPermission([
356
+ { tag: 'Remote', value: ['api.coingecko.com', '*.example.com'] },
357
+ { tag: 'ChainSubmit', value: undefined },
358
+ ]);
359
+ if (remoteResult.isOk()) {
360
+ console.log('All remote permissions granted:', remoteResult.value); // boolean
361
+ }
362
+ ```
363
+
364
+ Available device permission values: `'Notifications'`, `'Camera'`, `'Microphone'`, `'Bluetooth'`, `'NFC'`, `'Location'`, `'Clipboard'`, `'OpenUrl'`, `'Biometrics'`.
365
+
366
+ Available remote permission tags: `'Remote'` (HTTP/WS domain patterns), `'WebRTC'`, `'ChainSubmit'`, `'PreimageSubmit'`, `'StatementSubmit'`.
367
+
368
+ > **Note:** `remote_chain_transaction_broadcast`, `remote_preimage_submit`, and `remote_statement_store_submit` implicitly trigger a permission prompt if the relevant permission has not yet been resolved. Call `requestPermission(...)` proactively before entering those flows for a controlled UX.
369
+
370
+ ### Preimage Manager
371
+
372
+ The Preimage Manager allows you to lookup and submit preimages to the host application.
373
+
374
+ ```ts
375
+ import { preimageManager, createPreimageManager } from '@novasamatech/host-api-wrapper';
376
+
377
+ // Use the default instance
378
+ const manager = preimageManager;
379
+
380
+ // Or create a custom instance with a different transport
381
+ // const manager = createPreimageManager(customTransport);
382
+
383
+ // Lookup a preimage by its hash key
384
+ const subscription = manager.lookup('0x1234...', (preimage) => {
385
+ if (preimage) {
386
+ console.log('Preimage found:', preimage);
387
+ } else {
388
+ console.log('Preimage not found');
389
+ }
390
+ });
391
+
392
+ // Unsubscribe when done
393
+ subscription.unsubscribe();
394
+
395
+ // Submit a preimage
396
+ const preimageKey = await manager.submit(new Uint8Array([1, 2, 3, 4]));
397
+ ```
398
+
399
+ ### Payment manager
400
+
401
+ ```ts
402
+ import { createPaymentManager } from '@novasamatech/host-api-wrapper';
403
+
404
+ const payments = createPaymentManager();
405
+
406
+ // Subscribe to the user's payment balance (host will prompt for consent)
407
+ const balanceSub = payments.subscribeBalance(balance => {
408
+ console.log('Available:', balance.available);
409
+ console.log('Pending:', balance.pending);
410
+ });
411
+ balanceSub.onInterrupt(() => console.log('Balance access denied or lost'));
412
+
413
+ // Top up the user's balance from a product account
414
+ await payments.topUp(1_000_000n, {
415
+ type: 'productAccount',
416
+ dotNsIdentifier: 'my-product.dot',
417
+ derivationIndex: 0,
418
+ });
419
+
420
+ // Request a payment from the user (host shows confirmation UI)
421
+ const destination = new Uint8Array(32); // 32-byte AccountId
422
+ const receipt = await payments.requestPayment(500_000n, destination);
423
+
424
+ // Track payment settlement
425
+ const statusSub = payments.subscribePaymentStatus(receipt.id, status => {
426
+ if (status.type === 'completed') console.log('Payment settled');
427
+ if (status.type === 'failed') console.log('Payment failed:', status.reason);
428
+ });
429
+ ```
@@ -0,0 +1,93 @@
1
+ import type { AccountConnectionStatus as AccountConnectionStatusCodec, CodecType, LegacyAccount as LegacyAccountCodec, ProductAccountId as ProductAccountIdCodec, Subscription, Transport } from '@novasamatech/host-api';
2
+ import { RingLocation } from '@novasamatech/host-api';
3
+ import type { PolkadotSigner } from 'polkadot-api';
4
+ export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
5
+ export type ProductAccount = {
6
+ dotNsIdentifier: string;
7
+ derivationIndex: number;
8
+ publicKey: Uint8Array;
9
+ };
10
+ export type LegacyAccount = CodecType<typeof LegacyAccountCodec>;
11
+ export type AccountConnectionStatus = CodecType<typeof AccountConnectionStatusCodec>;
12
+ export declare const createAccountsProvider: (transport?: Transport) => {
13
+ getUserId(): import("neverthrow").ResultAsync<{
14
+ primaryUsername: string;
15
+ }, import("@novasamatech/scale").CodecError<undefined, "GetUserIdErr::NotConnected"> | import("@novasamatech/scale").CodecError<{
16
+ reason: string;
17
+ }, "GetUserIdErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "GetUserIdErr::PermissionDenied">>;
18
+ requestLogin(reason?: string): import("neverthrow").ResultAsync<"success" | "alreadyConnected" | "rejected", import("@novasamatech/scale").CodecError<{
19
+ reason: string;
20
+ }, "LoginErr::Unknown">>;
21
+ getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
22
+ publicKey: Uint8Array<ArrayBufferLike>;
23
+ dotNsIdentifier: string;
24
+ derivationIndex: number;
25
+ }, import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
26
+ reason: string;
27
+ }, "RequestCredentialsErr::Unknown">>;
28
+ getProductAccountAlias(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
29
+ context: Uint8Array<ArrayBufferLike>;
30
+ alias: Uint8Array<ArrayBufferLike>;
31
+ }, import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
32
+ reason: string;
33
+ }, "RequestCredentialsErr::Unknown">>;
34
+ getLegacyAccounts(): import("neverthrow").ResultAsync<{
35
+ publicKey: Uint8Array<ArrayBufferLike>;
36
+ name: string | undefined;
37
+ }[], import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
38
+ reason: string;
39
+ }, "RequestCredentialsErr::Unknown">>;
40
+ createRingVRFProof(dotNsIdentifier: string, derivationIndex: number | undefined, location: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<Uint8Array<ArrayBufferLike>, import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::Rejected"> | import("@novasamatech/scale").CodecError<{
41
+ reason: string;
42
+ }, "CreateProofErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::RingNotFound">>;
43
+ /**
44
+ * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
45
+ *
46
+ * The factory is async because `PolkadotSigner.publicKey` must be a synchronous
47
+ * `Uint8Array` on the returned object — it is fetched up front via `host_account_get`.
48
+ */
49
+ getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"): PolkadotSigner;
50
+ subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): Subscription<void>;
51
+ getLegacyAccountSigner(account: LegacyAccount): PolkadotSigner;
52
+ };
53
+ export declare const accounts: {
54
+ getUserId(): import("neverthrow").ResultAsync<{
55
+ primaryUsername: string;
56
+ }, import("@novasamatech/scale").CodecError<undefined, "GetUserIdErr::NotConnected"> | import("@novasamatech/scale").CodecError<{
57
+ reason: string;
58
+ }, "GetUserIdErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "GetUserIdErr::PermissionDenied">>;
59
+ requestLogin(reason?: string): import("neverthrow").ResultAsync<"success" | "alreadyConnected" | "rejected", import("@novasamatech/scale").CodecError<{
60
+ reason: string;
61
+ }, "LoginErr::Unknown">>;
62
+ getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
63
+ publicKey: Uint8Array<ArrayBufferLike>;
64
+ dotNsIdentifier: string;
65
+ derivationIndex: number;
66
+ }, import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
67
+ reason: string;
68
+ }, "RequestCredentialsErr::Unknown">>;
69
+ getProductAccountAlias(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
70
+ context: Uint8Array<ArrayBufferLike>;
71
+ alias: Uint8Array<ArrayBufferLike>;
72
+ }, import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
73
+ reason: string;
74
+ }, "RequestCredentialsErr::Unknown">>;
75
+ getLegacyAccounts(): import("neverthrow").ResultAsync<{
76
+ publicKey: Uint8Array<ArrayBufferLike>;
77
+ name: string | undefined;
78
+ }[], import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
79
+ reason: string;
80
+ }, "RequestCredentialsErr::Unknown">>;
81
+ createRingVRFProof(dotNsIdentifier: string, derivationIndex: number | undefined, location: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<Uint8Array<ArrayBufferLike>, import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::Rejected"> | import("@novasamatech/scale").CodecError<{
82
+ reason: string;
83
+ }, "CreateProofErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::RingNotFound">>;
84
+ /**
85
+ * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
86
+ *
87
+ * The factory is async because `PolkadotSigner.publicKey` must be a synchronous
88
+ * `Uint8Array` on the returned object — it is fetched up front via `host_account_get`.
89
+ */
90
+ getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"): PolkadotSigner;
91
+ subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): Subscription<void>;
92
+ getLegacyAccountSigner(account: LegacyAccount): PolkadotSigner;
93
+ };