@novasamatech/product-sdk 0.6.17 → 0.7.0-0

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
@@ -289,6 +289,21 @@ const config = await storage.readJSON('config');
289
289
  await storage.clear('key');
290
290
  ```
291
291
 
292
+ ### Derive Entropy
293
+
294
+ The Derive Entropy function allows products to derive deterministic 32-byte entropy scoped to the product and a caller-chosen key.
295
+
296
+ ```ts
297
+ import { deriveEntropy } from '@novasamatech/product-sdk';
298
+
299
+ const result = await deriveEntropy(new Uint8Array([1, 2, 3]));
300
+
301
+ if (result.isOk()) {
302
+ const entropy: Uint8Array = result.value;
303
+ console.log('Derived entropy:', entropy);
304
+ }
305
+ ```
306
+
292
307
  ### Preimage Manager
293
308
 
294
309
  The Preimage Manager allows you to lookup and submit preimages to the host application.
@@ -318,3 +333,34 @@ subscription.unsubscribe();
318
333
  const preimageKey = await manager.submit(new Uint8Array([1, 2, 3, 4]));
319
334
  ```
320
335
 
336
+ ### Payment manager
337
+
338
+ ```ts
339
+ import { createPaymentManager } from '@novasamatech/product-sdk';
340
+
341
+ const payments = createPaymentManager();
342
+
343
+ // Subscribe to the user's payment balance (host will prompt for consent)
344
+ const balanceSub = payments.subscribeBalance(balance => {
345
+ console.log('Available:', balance.available);
346
+ console.log('Pending:', balance.pending);
347
+ });
348
+ balanceSub.onInterrupt(() => console.log('Balance access denied or lost'));
349
+
350
+ // Top up the user's balance from a product account
351
+ await payments.topUp(1_000_000n, {
352
+ type: 'productAccount',
353
+ dotNsIdentifier: 'my-product.dot',
354
+ derivationIndex: 0,
355
+ });
356
+
357
+ // Request a payment from the user (host shows confirmation UI)
358
+ const destination = new Uint8Array(32); // 32-byte AccountId
359
+ const receipt = await payments.requestPayment(500_000n, destination);
360
+
361
+ // Track payment settlement
362
+ const statusSub = payments.subscribePaymentStatus(receipt.id, status => {
363
+ if (status.type === 'completed') console.log('Payment settled');
364
+ if (status.type === 'failed') console.log('Payment failed:', status.reason);
365
+ });
366
+ ```
package/dist/accounts.js CHANGED
@@ -1,4 +1,4 @@
1
- import { CreateProofErr, RequestCredentialsErr, RingLocation, assertEnumVariant, createHostApi, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
1
+ import { CreateProofErr, RequestCredentialsErr, RingLocation, SigningPayload, SigningPayloadWithoutAccount, SigningRawPayload, SigningRawPayloadWithoutAccount, assertEnumVariant, createHostApi, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
2
2
  import { getPolkadotSignerFromPjs } from '@polkadot-api/pjs-signer';
3
3
  import { err, ok } from 'neverthrow';
4
4
  import { sandboxTransport } from './sandboxTransport.js';
@@ -57,20 +57,24 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
57
57
  getProductAccountSigner(account) {
58
58
  return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
59
59
  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,
60
+ account: [account.dotNsIdentifier, account.derivationIndex],
61
+ payload: {
62
+ blockHash: asHex(payload.blockHash),
63
+ blockNumber: asHex(payload.blockNumber),
64
+ era: asHex(payload.era),
65
+ genesisHash: asHex(payload.genesisHash),
66
+ nonce: asHex(payload.nonce),
67
+ method: asHex(payload.method),
68
+ specVersion: asHex(payload.specVersion),
69
+ transactionVersion: asHex(payload.transactionVersion),
70
+ metadataHash: payload.metadataHash ? asHex(payload.metadataHash) : undefined,
71
+ tip: asHex(payload.tip),
72
+ assetId: payload.assetId !== undefined ? payload.assetId : undefined,
73
+ mode: payload.mode,
74
+ withSignedTransaction: payload.withSignedTransaction,
75
+ signedExtensions: payload.signedExtensions,
76
+ version: payload.version,
77
+ },
74
78
  };
75
79
  const response = await hostApi.signPayload(enumValue('v1', codecPayload));
76
80
  return response.match(response => {
@@ -86,11 +90,11 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
86
90
  });
87
91
  }, async (raw) => {
88
92
  const payload = {
89
- address: raw.address,
90
- data: raw.type === 'bytes'
93
+ account: [account.dotNsIdentifier, account.derivationIndex],
94
+ payload: raw.type === 'bytes'
91
95
  ? {
92
96
  tag: 'Bytes',
93
- value: fromHex(raw.data),
97
+ value: fromHex(asHex(raw.data)),
94
98
  }
95
99
  : {
96
100
  tag: 'Payload',
@@ -121,22 +125,26 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
121
125
  getNonProductAccountSigner(account) {
122
126
  return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
123
127
  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,
128
+ signer: payload.address,
129
+ payload: {
130
+ blockHash: asHex(payload.blockHash),
131
+ blockNumber: asHex(payload.blockNumber),
132
+ era: asHex(payload.era),
133
+ genesisHash: asHex(payload.genesisHash),
134
+ nonce: asHex(payload.nonce),
135
+ method: asHex(payload.method),
136
+ specVersion: asHex(payload.specVersion),
137
+ transactionVersion: asHex(payload.transactionVersion),
138
+ metadataHash: payload.metadataHash ? asHex(payload.metadataHash) : undefined,
139
+ tip: asHex(payload.tip),
140
+ assetId: payload.assetId !== undefined ? payload.assetId : undefined,
141
+ mode: payload.mode,
142
+ withSignedTransaction: payload.withSignedTransaction,
143
+ signedExtensions: payload.signedExtensions,
144
+ version: payload.version,
145
+ },
138
146
  };
139
- const response = await hostApi.signPayload(enumValue('v1', codecPayload));
147
+ const response = await hostApi.signPayloadWithNonProductAccount(enumValue('v1', codecPayload));
140
148
  return response.match(response => {
141
149
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
142
150
  return {
@@ -150,18 +158,10 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
150
158
  });
151
159
  }, async (raw) => {
152
160
  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
- },
161
+ signer: raw.address,
162
+ payload: { tag: 'Bytes', value: fromHex(asHex(raw.data)) },
163
163
  };
164
- const response = await hostApi.signRaw(enumValue('v1', payload));
164
+ const response = await hostApi.signRawWithNonProductAccount(enumValue('v1', payload));
165
165
  return response.match(response => {
166
166
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
167
167
  return {
@@ -177,3 +177,8 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
177
177
  },
178
178
  };
179
179
  };
180
+ function asHex(v) {
181
+ if (v.startsWith('0x'))
182
+ return v;
183
+ return `0x${v}`;
184
+ }
package/dist/index.d.ts CHANGED
@@ -10,5 +10,10 @@ export type { ProductAccountId, SignedStatement, Statement, Topic } from './stat
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';
package/dist/index.js CHANGED
@@ -7,5 +7,8 @@ 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';
@@ -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.signRawWithNonProductAccount(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.signPayloadWithNonProductAccount(enumValue('v1', codecPayload));
77
89
  return response.match(response => {
78
90
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
79
91
  return {
@@ -0,0 +1,36 @@
1
+ import type { Subscription, Transport } from '@novasamatech/host-api';
2
+ export type PaymentBalance = {
3
+ available: bigint;
4
+ };
5
+ export type PaymentStatus = {
6
+ type: 'processing';
7
+ } | {
8
+ type: 'completed';
9
+ } | {
10
+ type: 'failed';
11
+ reason: string;
12
+ };
13
+ export type TopUpSource = {
14
+ type: 'productAccount';
15
+ dotNsIdentifier: string;
16
+ derivationIndex: number;
17
+ } | {
18
+ type: 'privateKey';
19
+ key: Uint8Array;
20
+ };
21
+ export declare const createPaymentManager: (transport?: Transport) => {
22
+ subscribeBalance(callback: (balance: PaymentBalance) => void): Subscription;
23
+ topUp(amount: bigint, source: TopUpSource): Promise<void>;
24
+ requestPayment(amount: bigint, destination: Uint8Array): Promise<{
25
+ id: string;
26
+ }>;
27
+ subscribePaymentStatus(id: string, callback: (status: PaymentStatus) => void): Subscription;
28
+ };
29
+ export declare const paymentManager: {
30
+ subscribeBalance(callback: (balance: PaymentBalance) => void): Subscription;
31
+ topUp(amount: bigint, source: TopUpSource): Promise<void>;
32
+ requestPayment(amount: bigint, destination: Uint8Array): Promise<{
33
+ id: string;
34
+ }>;
35
+ subscribePaymentStatus(id: string, callback: (status: PaymentStatus) => void): Subscription;
36
+ };
@@ -0,0 +1,45 @@
1
+ import { createHostApi, enumValue } from '@novasamatech/host-api';
2
+ import { resultToPromise, unwrapVersionedResult } from './helpers.js';
3
+ import { sandboxTransport } from './sandboxTransport.js';
4
+ export const createPaymentManager = (transport = sandboxTransport) => {
5
+ const hostApi = createHostApi(transport);
6
+ const version = 'v1';
7
+ return {
8
+ subscribeBalance(callback) {
9
+ return hostApi.paymentBalanceSubscribe(enumValue(version, undefined), payload => {
10
+ if (payload.tag === version) {
11
+ callback(payload.value);
12
+ }
13
+ });
14
+ },
15
+ topUp(amount, source) {
16
+ const sourceCodec = source.type === 'productAccount'
17
+ ? {
18
+ tag: 'ProductAccount',
19
+ value: [source.dotNsIdentifier, source.derivationIndex],
20
+ }
21
+ : { tag: 'PrivateKey', value: source.key };
22
+ return resultToPromise(unwrapVersionedResult(version, hostApi.paymentTopUp(enumValue(version, { amount, source: sourceCodec }))));
23
+ },
24
+ requestPayment(amount, destination) {
25
+ return resultToPromise(unwrapVersionedResult(version, hostApi.paymentRequest(enumValue(version, { amount, destination }))));
26
+ },
27
+ subscribePaymentStatus(id, callback) {
28
+ return hostApi.paymentStatusSubscribe(enumValue(version, id), payload => {
29
+ if (payload.tag === version) {
30
+ const raw = payload.value;
31
+ if (raw.tag === 'Processing') {
32
+ callback({ type: 'processing' });
33
+ }
34
+ else if (raw.tag === 'Completed') {
35
+ callback({ type: 'completed' });
36
+ }
37
+ else if (raw.tag === 'Failed') {
38
+ callback({ type: 'failed', reason: raw.value });
39
+ }
40
+ }
41
+ });
42
+ },
43
+ };
44
+ };
45
+ export const paymentManager = createPaymentManager();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/product-sdk",
3
3
  "type": "module",
4
- "version": "0.6.17",
4
+ "version": "0.7.0-0",
5
5
  "description": "Polkadot product SDK: integrate and run your product inside Polkadot browser.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "@polkadot-api/substrate-bindings": "^0.17.0",
30
30
  "@polkadot-api/json-rpc-provider": "^0.0.4",
31
31
  "@polkadot-api/json-rpc-provider-proxy": "^0.2.7",
32
- "@novasamatech/host-api": "0.6.17"
32
+ "@novasamatech/host-api": "0.7.0-0"
33
33
  },
34
34
  "publishConfig": {
35
35
  "access": "public"