@novasamatech/product-sdk 0.6.18 → 0.7.0-1

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 CHANGED
@@ -166,7 +166,7 @@ It can be used for various purposes like p2p communication, storing temp data, e
166
166
 
167
167
  ```ts
168
168
  import { createStatementStore } from '@novasamatech/product-sdk';
169
- import type { Topic, Statement, SignedStatement } from '@novasamatech/product-sdk';
169
+ import type { Topic, Statement, SignedStatement, StatementTopicFilter } from '@novasamatech/product-sdk';
170
170
 
171
171
  // Create statement store instance
172
172
  const statementStore = createStatementStore();
@@ -174,9 +174,11 @@ const statementStore = createStatementStore();
174
174
  // Define topics (32-byte identifiers) to categorize statements
175
175
  const topic: Topic = new Uint8Array(32);
176
176
 
177
- // Subscribe to statement updates for specific topics
178
- const subscription = statementStore.subscribe([topic], (statements) => {
179
- console.log('Received statement updates:', statements);
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);
180
182
  });
181
183
 
182
184
  // Create a proof for a new statement
@@ -215,6 +217,34 @@ import type { ProductAccount } from '@novasamatech/product-sdk';
215
217
  // Create accounts provider instance
216
218
  const accountsProvider = createAccountsProvider();
217
219
 
220
+ // Get the root (primary) account — prompts for permission on first call
221
+ const rootResult = await accountsProvider.getRootAccount();
222
+
223
+ if (rootResult.isOk()) {
224
+ const root = rootResult.value;
225
+ console.log('Root account public key:', root.publicKey);
226
+ console.log('Root DotNS name:', root.name);
227
+ } else {
228
+ const rootErr = rootResult.error;
229
+ if (rootErr.tag === 'Rejected') {
230
+ console.log('User denied access to root account');
231
+ } else if (rootErr.tag === 'NotFound') {
232
+ console.log('User has no DotNS account yet');
233
+ }
234
+ }
235
+
236
+ // Request login — triggers host sign-in UI; reason is shown to the user
237
+ const loginResult = await accountsProvider.requestLogin('Sign in to access your account');
238
+
239
+ if (loginResult.isOk()) {
240
+ const outcome = loginResult.value; // 'success' | 'alreadyConnected' | 'rejected'
241
+ if (outcome === 'rejected') {
242
+ console.log('User cancelled login');
243
+ }
244
+ } else {
245
+ console.error('Login error:', loginResult.error);
246
+ }
247
+
218
248
  // Get a product account by DotNS identifier and derivation index
219
249
  const accountResult = await accountsProvider.getProductAccount('product.dot', 0);
220
250
 
@@ -230,11 +260,11 @@ if (aliasResult.isOk()) {
230
260
  console.log('Alias:', aliasResult.value);
231
261
  }
232
262
 
233
- // Get non-product accounts (external wallets)
234
- const nonProductAccountsResult = await accountsProvider.getNonProductAccounts();
263
+ // Get legacy accounts (external wallets)
264
+ const legacyAccountsResult = await accountsProvider.getLegacyAccounts();
235
265
 
236
- if (nonProductAccountsResult.isOk()) {
237
- console.log('Non-product accounts:', nonProductAccountsResult.value);
266
+ if (legacyAccountsResult.isOk()) {
267
+ console.log('Legacy accounts:', legacyAccountsResult.value);
238
268
  }
239
269
 
240
270
  // Subscribe to account connection status changes
@@ -251,13 +281,13 @@ const account: ProductAccount = {
251
281
  };
252
282
  const signer = accountsProvider.getProductAccountSigner(account);
253
283
 
254
- // Create a signer for a non-product account
255
- const nonProductSigner = accountsProvider.getNonProductAccountSigner(account);
284
+ // Create a signer for a legacy account
285
+ const legacySigner = accountsProvider.getLegacyAccountSigner(account);
256
286
 
257
287
  // PAPI transaction signing example
258
288
 
259
289
  const productAccountSignedTx = await tx.signAndSubmit(signer);
260
- const nonProductAccountSignedTx = await tx.signAndSubmit(nonProductSigner);
290
+ const legacyAccountSignedTx = await tx.signAndSubmit(legacySigner);
261
291
  ```
262
292
 
263
293
  ### Local Storage
@@ -289,6 +319,50 @@ const config = await storage.readJSON('config');
289
319
  await storage.clear('key');
290
320
  ```
291
321
 
322
+ ### Derive Entropy
323
+
324
+ The Derive Entropy function allows products to derive deterministic 32-byte entropy scoped to the product and a caller-chosen key.
325
+
326
+ ```ts
327
+ import { deriveEntropy } from '@novasamatech/product-sdk';
328
+
329
+ const result = await deriveEntropy(new Uint8Array([1, 2, 3]));
330
+
331
+ if (result.isOk()) {
332
+ const entropy: Uint8Array = result.value;
333
+ console.log('Derived entropy:', entropy);
334
+ }
335
+ ```
336
+
337
+ ### Permissions
338
+
339
+ 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.
340
+
341
+ ```ts
342
+ import { requestDevicePermission, requestPermission } from '@novasamatech/product-sdk';
343
+
344
+ // Request a single device permission
345
+ const deviceResult = await requestDevicePermission('Camera');
346
+ if (deviceResult.isOk()) {
347
+ console.log('Camera granted:', deviceResult.value); // boolean
348
+ }
349
+
350
+ // Request remote permissions in a batch (single user prompt for all)
351
+ const remoteResult = await requestPermission([
352
+ { tag: 'Remote', value: ['api.coingecko.com', '*.example.com'] },
353
+ { tag: 'ChainSubmit', value: undefined },
354
+ ]);
355
+ if (remoteResult.isOk()) {
356
+ console.log('All remote permissions granted:', remoteResult.value); // boolean
357
+ }
358
+ ```
359
+
360
+ Available device permission values: `'Notifications'`, `'Camera'`, `'Microphone'`, `'Bluetooth'`, `'NFC'`, `'Location'`, `'Clipboard'`, `'OpenUrl'`, `'Biometrics'`.
361
+
362
+ Available remote permission tags: `'Remote'` (HTTP/WS domain patterns), `'WebRTC'`, `'ChainSubmit'`, `'PreimageSubmit'`, `'StatementSubmit'`.
363
+
364
+ > **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.
365
+
292
366
  ### Preimage Manager
293
367
 
294
368
  The Preimage Manager allows you to lookup and submit preimages to the host application.
@@ -318,3 +392,34 @@ subscription.unsubscribe();
318
392
  const preimageKey = await manager.submit(new Uint8Array([1, 2, 3, 4]));
319
393
  ```
320
394
 
395
+ ### Payment manager
396
+
397
+ ```ts
398
+ import { createPaymentManager } from '@novasamatech/product-sdk';
399
+
400
+ const payments = createPaymentManager();
401
+
402
+ // Subscribe to the user's payment balance (host will prompt for consent)
403
+ const balanceSub = payments.subscribeBalance(balance => {
404
+ console.log('Available:', balance.available);
405
+ console.log('Pending:', balance.pending);
406
+ });
407
+ balanceSub.onInterrupt(() => console.log('Balance access denied or lost'));
408
+
409
+ // Top up the user's balance from a product account
410
+ await payments.topUp(1_000_000n, {
411
+ type: 'productAccount',
412
+ dotNsIdentifier: 'my-product.dot',
413
+ derivationIndex: 0,
414
+ });
415
+
416
+ // Request a payment from the user (host shows confirmation UI)
417
+ const destination = new Uint8Array(32); // 32-byte AccountId
418
+ const receipt = await payments.requestPayment(500_000n, destination);
419
+
420
+ // Track payment settlement
421
+ const statusSub = payments.subscribePaymentStatus(receipt.id, status => {
422
+ if (status.type === 'completed') console.log('Payment settled');
423
+ if (status.type === 'failed') console.log('Payment failed:', status.reason);
424
+ });
425
+ ```
@@ -8,6 +8,15 @@ export type ProductAccount = {
8
8
  };
9
9
  export type AccountConnectionStatus = CodecType<typeof AccountConnectionStatusCodec>;
10
10
  export declare const createAccountsProvider: (transport?: Transport) => {
11
+ getRootAccount(): import("neverthrow").ResultAsync<{
12
+ publicKey: Uint8Array<ArrayBufferLike>;
13
+ name: string | undefined;
14
+ }, import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("packages/scale/src/err.js").CodecError<{
15
+ reason: string;
16
+ }, "RequestCredentialsErr::Unknown">>;
17
+ requestLogin(reason?: string): import("neverthrow").ResultAsync<"success" | "alreadyConnected" | "rejected", import("packages/scale/src/err.js").CodecError<{
18
+ reason: string;
19
+ }, "LoginErr::Unknown">>;
11
20
  getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
12
21
  publicKey: Uint8Array<ArrayBufferLike>;
13
22
  name: string | undefined;
@@ -20,7 +29,7 @@ export declare const createAccountsProvider: (transport?: Transport) => {
20
29
  }, import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("packages/scale/src/err.js").CodecError<{
21
30
  reason: string;
22
31
  }, "RequestCredentialsErr::Unknown">>;
23
- getNonProductAccounts(): import("neverthrow").ResultAsync<{
32
+ getLegacyAccounts(): import("neverthrow").ResultAsync<{
24
33
  publicKey: Uint8Array<ArrayBufferLike>;
25
34
  name: string | undefined;
26
35
  }[], import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("packages/scale/src/err.js").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("packages/scale/src/err.js").CodecError<{
@@ -31,5 +40,5 @@ export declare const createAccountsProvider: (transport?: Transport) => {
31
40
  }, "CreateProofErr::Unknown"> | import("packages/scale/src/err.js").CodecError<undefined, "CreateProofErr::RingNotFound">>;
32
41
  getProductAccountSigner(account: ProductAccount): PolkadotSigner;
33
42
  subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): import("@novasamatech/host-api").Subscription;
34
- getNonProductAccountSigner(account: ProductAccount): PolkadotSigner;
43
+ getLegacyAccountSigner(account: ProductAccount): PolkadotSigner;
35
44
  };
package/dist/accounts.js CHANGED
@@ -1,11 +1,35 @@
1
- import { CreateProofErr, RequestCredentialsErr, RingLocation, assertEnumVariant, createHostApi, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
2
- import { getPolkadotSignerFromPjs } from '@polkadot-api/pjs-signer';
1
+ import { CreateProofErr, LoginErr, RequestCredentialsErr, RingLocation, SigningPayload, SigningPayloadWithoutAccount, SigningRawPayload, SigningRawPayloadWithoutAccount, assertEnumVariant, createHostApi, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
3
2
  import { err, ok } from 'neverthrow';
3
+ import { getPolkadotSignerFromPjs } from 'polkadot-api/pjs-signer';
4
4
  import { sandboxTransport } from './sandboxTransport.js';
5
5
  const UNSUPPORTED_VERSION_ERROR = 'Unsupported message version';
6
6
  export const createAccountsProvider = (transport = sandboxTransport) => {
7
7
  const hostApi = createHostApi(transport);
8
8
  return {
9
+ getRootAccount() {
10
+ return hostApi
11
+ .accountGetRoot(enumValue('v1', undefined))
12
+ .mapErr(e => e.value)
13
+ .andThen(response => {
14
+ if (isEnumVariant(response, 'v1')) {
15
+ return ok(response.value);
16
+ }
17
+ // @ts-expect-error response.tag is never here
18
+ return err(new RequestCredentialsErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
19
+ });
20
+ },
21
+ requestLogin(reason) {
22
+ return hostApi
23
+ .requestLogin(enumValue('v1', reason))
24
+ .mapErr(e => e.value)
25
+ .andThen(response => {
26
+ if (isEnumVariant(response, 'v1')) {
27
+ return ok(response.value);
28
+ }
29
+ // @ts-expect-error response.tag is never here
30
+ return err(new LoginErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
31
+ });
32
+ },
9
33
  getProductAccount(dotNsIdentifier, derivationIndex = 0) {
10
34
  return hostApi
11
35
  .accountGet(enumValue('v1', [dotNsIdentifier, derivationIndex]))
@@ -30,9 +54,9 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
30
54
  return err(new RequestCredentialsErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
31
55
  });
32
56
  },
33
- getNonProductAccounts() {
57
+ getLegacyAccounts() {
34
58
  return hostApi
35
- .getNonProductAccounts(enumValue('v1', undefined))
59
+ .getLegacyAccounts(enumValue('v1', undefined))
36
60
  .mapErr(e => e.value)
37
61
  .andThen(response => {
38
62
  if (isEnumVariant(response, 'v1')) {
@@ -57,20 +81,8 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
57
81
  getProductAccountSigner(account) {
58
82
  return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
59
83
  const codecPayload = {
60
- ...payload,
61
- blockHash: payload.blockHash,
62
- blockNumber: payload.blockNumber,
63
- era: payload.era,
64
- genesisHash: payload.genesisHash,
65
- nonce: payload.nonce,
66
- method: payload.method,
67
- specVersion: payload.specVersion,
68
- transactionVersion: payload.transactionVersion,
69
- metadataHash: payload.metadataHash,
70
- tip: payload.tip,
71
- assetId: payload.assetId,
72
- mode: payload.mode,
73
- withSignedTransaction: payload.withSignedTransaction,
84
+ account: [account.dotNsIdentifier, account.derivationIndex],
85
+ payload: buildSigningPayloadFields(payload),
74
86
  };
75
87
  const response = await hostApi.signPayload(enumValue('v1', codecPayload));
76
88
  return response.match(response => {
@@ -86,11 +98,11 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
86
98
  });
87
99
  }, async (raw) => {
88
100
  const payload = {
89
- address: raw.address,
90
- data: raw.type === 'bytes'
101
+ account: [account.dotNsIdentifier, account.derivationIndex],
102
+ payload: raw.type === 'bytes'
91
103
  ? {
92
104
  tag: 'Bytes',
93
- value: fromHex(raw.data),
105
+ value: fromHex(asHex(raw.data)),
94
106
  }
95
107
  : {
96
108
  tag: 'Payload',
@@ -118,25 +130,13 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
118
130
  }
119
131
  });
120
132
  },
121
- getNonProductAccountSigner(account) {
133
+ getLegacyAccountSigner(account) {
122
134
  return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
123
135
  const codecPayload = {
124
- ...payload,
125
- blockHash: payload.blockHash,
126
- blockNumber: payload.blockNumber,
127
- era: payload.era,
128
- genesisHash: payload.genesisHash,
129
- nonce: payload.nonce,
130
- method: payload.method,
131
- specVersion: payload.specVersion,
132
- transactionVersion: payload.transactionVersion,
133
- metadataHash: payload.metadataHash,
134
- tip: payload.tip,
135
- assetId: payload.assetId,
136
- mode: payload.mode,
137
- withSignedTransaction: payload.withSignedTransaction,
136
+ signer: payload.address,
137
+ payload: buildSigningPayloadFields(payload),
138
138
  };
139
- const response = await hostApi.signPayload(enumValue('v1', codecPayload));
139
+ const response = await hostApi.signPayloadWithLegacyAccount(enumValue('v1', codecPayload));
140
140
  return response.match(response => {
141
141
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
142
142
  return {
@@ -150,18 +150,10 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
150
150
  });
151
151
  }, async (raw) => {
152
152
  const payload = {
153
- address: raw.address,
154
- data: raw.type === 'bytes'
155
- ? {
156
- tag: 'Bytes',
157
- value: fromHex(raw.data),
158
- }
159
- : {
160
- tag: 'Payload',
161
- value: raw.data,
162
- },
153
+ signer: raw.address,
154
+ payload: { tag: 'Bytes', value: fromHex(asHex(raw.data)) },
163
155
  };
164
- const response = await hostApi.signRaw(enumValue('v1', payload));
156
+ const response = await hostApi.signRawWithLegacyAccount(enumValue('v1', payload));
165
157
  return response.match(response => {
166
158
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
167
159
  return {
@@ -177,3 +169,27 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
177
169
  },
178
170
  };
179
171
  };
172
+ function asHex(v) {
173
+ if (v.startsWith('0x'))
174
+ return v;
175
+ return `0x${v}`;
176
+ }
177
+ function buildSigningPayloadFields(payload) {
178
+ return {
179
+ blockHash: asHex(payload.blockHash),
180
+ blockNumber: asHex(payload.blockNumber),
181
+ era: asHex(payload.era),
182
+ genesisHash: asHex(payload.genesisHash),
183
+ nonce: asHex(payload.nonce),
184
+ method: asHex(payload.method),
185
+ specVersion: asHex(payload.specVersion),
186
+ transactionVersion: asHex(payload.transactionVersion),
187
+ metadataHash: payload.metadataHash ? asHex(payload.metadataHash) : undefined,
188
+ tip: asHex(payload.tip),
189
+ assetId: payload.assetId !== undefined ? payload.assetId : undefined,
190
+ mode: payload.mode,
191
+ withSignedTransaction: payload.withSignedTransaction,
192
+ signedExtensions: payload.signedExtensions,
193
+ version: payload.version,
194
+ };
195
+ }
package/dist/index.d.ts CHANGED
@@ -2,13 +2,20 @@ export { SpektrExtensionName, WellKnownChain } from './constants.js';
2
2
  export { sandboxProvider, sandboxTransport } from './sandboxTransport.js';
3
3
  export { hostApi } from './hostApi.js';
4
4
  export { createMetaProvider, metaProvider } from './metaProvider.js';
5
- export { createNonProductExtensionEnableFactory, injectSpektrExtension } from './injectWeb3.js';
5
+ export { createLegacyExtensionEnableFactory, injectSpektrExtension } from './injectWeb3.js';
6
6
  export { createPapiProvider } from './papiProvider.js';
7
7
  export type { ChatBotRegistrationResult, ChatCustomMessageRenderer, ChatCustomMessageRendererParams, ChatMessageContent, ChatReceivedAction, ChatRoom, ChatRoomRegistrationResult, } from './chat.js';
8
8
  export { createProductChatManager, matchChatCustomRenderers } from './chat.js';
9
- export type { ProductAccountId, SignedStatement, Statement, Topic } from './statementStore.js';
9
+ export type { ProductAccountId, SignedStatement, Statement, StatementTopicFilter, StatementsPage, Topic, } from './statementStore.js';
10
10
  export { createStatementStore } from './statementStore.js';
11
11
  export type { AccountConnectionStatus, ProductAccount } from './accounts.js';
12
12
  export { createAccountsProvider } from './accounts.js';
13
+ export type { ThemeMode, ThemeSubscription } from './theme.js';
14
+ export { createThemeProvider } from './theme.js';
13
15
  export { createLocalStorage, hostLocalStorage } from './localStorage.js';
14
16
  export { createPreimageManager, preimageManager } from './preimage.js';
17
+ export type { PaymentBalance, PaymentStatus, TopUpSource } from './payments.js';
18
+ export { createPaymentManager, paymentManager } from './payments.js';
19
+ export { deriveEntropy } from './deriveEntropy.js';
20
+ export type { DevicePermissionKind, RemotePermissionItem } from './permission.js';
21
+ export { requestDevicePermission, requestPermission } from './permission.js';
package/dist/index.js CHANGED
@@ -2,10 +2,14 @@ export { SpektrExtensionName, WellKnownChain } from './constants.js';
2
2
  export { sandboxProvider, sandboxTransport } from './sandboxTransport.js';
3
3
  export { hostApi } from './hostApi.js';
4
4
  export { createMetaProvider, metaProvider } from './metaProvider.js';
5
- export { createNonProductExtensionEnableFactory, injectSpektrExtension } from './injectWeb3.js';
5
+ export { createLegacyExtensionEnableFactory, injectSpektrExtension } from './injectWeb3.js';
6
6
  export { createPapiProvider } from './papiProvider.js';
7
7
  export { createProductChatManager, matchChatCustomRenderers } from './chat.js';
8
8
  export { createStatementStore } from './statementStore.js';
9
9
  export { createAccountsProvider } from './accounts.js';
10
+ export { createThemeProvider } from './theme.js';
10
11
  export { createLocalStorage, hostLocalStorage } from './localStorage.js';
11
12
  export { createPreimageManager, preimageManager } from './preimage.js';
13
+ export { createPaymentManager, paymentManager } from './payments.js';
14
+ export { deriveEntropy } from './deriveEntropy.js';
15
+ export { requestDevicePermission, requestPermission } from './permission.js';
@@ -19,6 +19,6 @@ interface Injected {
19
19
  accounts: InjectedAccounts;
20
20
  signer: Signer;
21
21
  }
22
- export declare function createNonProductExtensionEnableFactory(transport: Transport): Promise<(() => Promise<Injected>) | null>;
22
+ export declare function createLegacyExtensionEnableFactory(transport: Transport): Promise<(() => Promise<Injected>) | null>;
23
23
  export declare function injectSpektrExtension(transport?: Transport | null): Promise<boolean>;
24
24
  export {};
@@ -1,10 +1,10 @@
1
1
  import { assertEnumVariant, createHostApi, enumValue, fromHex, toHex } from '@novasamatech/host-api';
2
2
  import { injectExtension } from '@polkadot/extension-inject';
3
- import { AccountId } from '@polkadot-api/substrate-bindings';
3
+ import { AccountId } from 'polkadot-api';
4
4
  import { SpektrExtensionName, Version } from './constants.js';
5
5
  import { sandboxTransport } from './sandboxTransport.js';
6
6
  const UNSUPPORTED_VERSION_ERROR = 'Unsupported message version';
7
- export async function createNonProductExtensionEnableFactory(transport) {
7
+ export async function createLegacyExtensionEnableFactory(transport) {
8
8
  const ready = await transport.isReady();
9
9
  if (!ready)
10
10
  return null;
@@ -12,7 +12,7 @@ export async function createNonProductExtensionEnableFactory(transport) {
12
12
  const accountId = AccountId();
13
13
  async function enable() {
14
14
  async function getAccounts() {
15
- const response = await hostApi.getNonProductAccounts(enumValue('v1', undefined));
15
+ const response = await hostApi.getLegacyAccounts(enumValue('v1', undefined));
16
16
  return response.match(response => {
17
17
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
18
18
  return response.value.map(account => ({
@@ -40,8 +40,8 @@ export async function createNonProductExtensionEnableFactory(transport) {
40
40
  signer: {
41
41
  async signRaw(raw) {
42
42
  const payload = {
43
- address: raw.address,
44
- data: raw.type === 'bytes'
43
+ signer: raw.address,
44
+ payload: raw.type === 'bytes'
45
45
  ? {
46
46
  tag: 'Bytes',
47
47
  value: fromHex(raw.data),
@@ -51,7 +51,7 @@ export async function createNonProductExtensionEnableFactory(transport) {
51
51
  value: raw.data,
52
52
  },
53
53
  };
54
- const response = await hostApi.signRaw(enumValue('v1', payload));
54
+ const response = await hostApi.signRawWithLegacyAccount(enumValue('v1', payload));
55
55
  return response.match(response => {
56
56
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
57
57
  return {
@@ -66,14 +66,26 @@ export async function createNonProductExtensionEnableFactory(transport) {
66
66
  },
67
67
  async signPayload(payload) {
68
68
  const codecPayload = {
69
- ...payload,
70
- method: payload.method,
71
- assetId: payload.assetId,
72
- mode: payload.mode,
73
- withSignedTransaction: payload.withSignedTransaction,
74
- metadataHash: payload.metadataHash,
69
+ signer: payload.address,
70
+ payload: {
71
+ blockHash: payload.blockHash,
72
+ blockNumber: payload.blockNumber,
73
+ era: payload.era,
74
+ genesisHash: payload.genesisHash,
75
+ nonce: payload.nonce,
76
+ method: payload.method,
77
+ specVersion: payload.specVersion,
78
+ transactionVersion: payload.transactionVersion,
79
+ metadataHash: payload.metadataHash,
80
+ tip: payload.tip,
81
+ assetId: payload.assetId,
82
+ mode: payload.mode,
83
+ withSignedTransaction: payload.withSignedTransaction,
84
+ signedExtensions: payload.signedExtensions,
85
+ version: payload.version,
86
+ },
75
87
  };
76
- const response = await hostApi.signPayload(enumValue('v1', codecPayload));
88
+ const response = await hostApi.signPayloadWithLegacyAccount(enumValue('v1', codecPayload));
77
89
  return response.match(response => {
78
90
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
79
91
  return {
@@ -87,7 +99,7 @@ export async function createNonProductExtensionEnableFactory(transport) {
87
99
  });
88
100
  },
89
101
  async createTransaction(payload) {
90
- const response = await hostApi.createTransactionWithNonProductAccount(enumValue('v1', payload));
102
+ const response = await hostApi.createTransactionWithLegacyAccount(enumValue('v1', payload));
91
103
  return response.match(response => {
92
104
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
93
105
  return toHex(response.value);
@@ -105,7 +117,7 @@ export async function injectSpektrExtension(transport = sandboxTransport) {
105
117
  if (!transport)
106
118
  return false;
107
119
  try {
108
- const enable = await createNonProductExtensionEnableFactory(transport);
120
+ const enable = await createLegacyExtensionEnableFactory(transport);
109
121
  if (enable) {
110
122
  injectExtension(enable, { name: SpektrExtensionName, version: Version });
111
123
  return true;
@@ -1,5 +1,5 @@
1
1
  import type { HexString, Transport } from '@novasamatech/host-api';
2
- import type { JsonRpcProvider } from '@polkadot-api/json-rpc-provider';
2
+ import type { JsonRpcProvider } from 'polkadot-api';
3
3
  type InternalParams = {
4
4
  transport?: Transport;
5
5
  };
@@ -18,17 +18,17 @@ __fallback, internal) {
18
18
  return `follow_${nextSubId++}`;
19
19
  }
20
20
  function sendJsonRpcResponse(id, result) {
21
- onMessage(JSON.stringify({ jsonrpc: '2.0', id, result }));
21
+ onMessage({ jsonrpc: '2.0', id, result });
22
22
  }
23
23
  function sendJsonRpcError(id, code, message) {
24
- onMessage(JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } }));
24
+ onMessage({ jsonrpc: '2.0', id, error: { code, message } });
25
25
  }
26
26
  function sendFollowEvent(syntheticSubId, event) {
27
- onMessage(JSON.stringify({
27
+ onMessage({
28
28
  jsonrpc: '2.0',
29
29
  method: 'chainHead_v1_followEvent',
30
30
  params: { subscription: syntheticSubId, result: event },
31
- }));
31
+ });
32
32
  }
33
33
  function convertTypedEventToJsonRpc(event) {
34
34
  switch (event.tag) {
@@ -145,14 +145,9 @@ __fallback, internal) {
145
145
  return { result: 'limitReached' };
146
146
  }
147
147
  function handleMessage(message) {
148
- let parsed;
149
- try {
150
- parsed = JSON.parse(message);
151
- }
152
- catch {
153
- return;
154
- }
155
- const { id, method, params } = parsed;
148
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
149
+ const id = message.id;
150
+ const { method, params } = message;
156
151
  switch (method) {
157
152
  case 'chainHead_v1_follow': {
158
153
  const [withRuntime] = params;
@@ -319,20 +314,27 @@ __fallback, internal) {
319
314
  });
320
315
  });
321
316
  }
322
- return getSyncProvider(() => checkIfReady().then(ready => {
323
- if (ready)
324
- return typedProvider;
325
- if (__fallback)
326
- return __fallback;
317
+ return getSyncProvider(onResult => {
318
+ checkIfReady().then(ready => {
319
+ if (ready) {
320
+ onResult((onMessage, _onHalt) => typedProvider(onMessage));
321
+ }
322
+ else if (__fallback) {
323
+ onResult((onMessage, _onHalt) => __fallback(onMessage));
324
+ }
325
+ else {
326
+ onResult((_onMessage, _onHalt) => ({
327
+ send() {
328
+ transport.provider.logger.error(`Provider for chain ${genesisHash} was not started because Host doesn't support it`);
329
+ },
330
+ disconnect() {
331
+ /* empty */
332
+ },
333
+ }));
334
+ }
335
+ });
327
336
  return () => {
328
- return {
329
- send() {
330
- transport.provider.logger.error(`Provider for chain ${genesisHash} was not started because Host doesn't support it`);
331
- },
332
- disconnect() {
333
- /* empty */
334
- },
335
- };
337
+ /* empty */
336
338
  };
337
- }));
339
+ });
338
340
  }
@@ -3,8 +3,17 @@ export type Statement = CodecType<typeof StatementCodec>;
3
3
  export type SignedStatement = CodecType<typeof SignedStatementCodec>;
4
4
  export type Topic = CodecType<typeof TopicCodec>;
5
5
  export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
6
+ export type StatementTopicFilter = {
7
+ matchAll: Topic[];
8
+ } | {
9
+ matchAny: Topic[];
10
+ };
11
+ export type StatementsPage = {
12
+ statements: SignedStatement[];
13
+ isComplete: boolean;
14
+ };
6
15
  export declare const createStatementStore: (transport?: Transport) => {
7
- subscribe(topics: Topic[], callback: (statements: SignedStatement[]) => void): import("@novasamatech/host-api").Subscription;
16
+ subscribe(filter: StatementTopicFilter, callback: (page: StatementsPage) => void): import("@novasamatech/host-api").Subscription;
8
17
  createProof(accountId: ProductAccountId, statement: Statement): Promise<{
9
18
  tag: "Sr25519";
10
19
  value: {
@@ -3,8 +3,9 @@ import { sandboxTransport } from './sandboxTransport.js';
3
3
  export const createStatementStore = (transport = sandboxTransport) => {
4
4
  const hostApi = createHostApi(transport);
5
5
  return {
6
- subscribe(topics, callback) {
7
- return hostApi.statementStoreSubscribe(enumValue('v1', topics), payload => {
6
+ subscribe(filter, callback) {
7
+ const scaleFilter = 'matchAll' in filter ? enumValue('MatchAll', filter.matchAll) : enumValue('MatchAny', filter.matchAny);
8
+ return hostApi.statementStoreSubscribe(enumValue('v1', scaleFilter), payload => {
8
9
  if (payload.tag === 'v1') {
9
10
  callback(payload.value);
10
11
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/product-sdk",
3
3
  "type": "module",
4
- "version": "0.6.18",
4
+ "version": "0.7.0-1",
5
5
  "description": "Polkadot product SDK: integrate and run your product inside Polkadot browser.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -25,11 +25,11 @@
25
25
  "README.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@polkadot/extension-inject": "^0.62.6",
29
- "@polkadot-api/substrate-bindings": "^0.17.0",
30
- "@polkadot-api/json-rpc-provider": "^0.0.4",
31
- "@polkadot-api/json-rpc-provider-proxy": "^0.2.7",
32
- "@novasamatech/host-api": "0.6.18"
28
+ "@polkadot/extension-inject": "^0.63.1",
29
+ "@polkadot-api/json-rpc-provider-proxy": "^0.4.0",
30
+ "@novasamatech/host-api": "0.7.0-1",
31
+ "polkadot-api": ">=2",
32
+ "neverthrow": "^8.2.0"
33
33
  },
34
34
  "publishConfig": {
35
35
  "access": "public"