@novasamatech/product-sdk 0.5.4 → 0.6.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
@@ -12,6 +12,8 @@ Core features:
12
12
  - Accounts provider for product accounts and signing
13
13
  - Redirect [PAPI](https://papi.how/) requests to host application
14
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
15
17
 
16
18
  ## Installation
17
19
 
@@ -130,6 +132,29 @@ const subscriber = chat.subscribeAction((action) => {
130
132
  const chatListSubscriber = chat.subscribeChatList((rooms) => {
131
133
  console.log('Chat rooms updated:', rooms);
132
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
+ });
133
158
  ```
134
159
 
135
160
  **Note:** Messages sent before registration will be queued and sent automatically after successful registration.
@@ -149,9 +174,6 @@ const statementStore = createStatementStore();
149
174
  // Define topics (32-byte identifiers) to categorize statements
150
175
  const topic: Topic = new Uint8Array(32);
151
176
 
152
- // Query existing statements by topics
153
- const statements: SignedStatement[] = await statementStore.query([topic]);
154
-
155
177
  // Subscribe to statement updates for specific topics
156
178
  const subscription = statementStore.subscribe([topic], (statements) => {
157
179
  console.log('Received statement updates:', statements);
@@ -215,6 +237,12 @@ if (nonProductAccountsResult.isOk()) {
215
237
  console.log('Non-product accounts:', nonProductAccountsResult.value);
216
238
  }
217
239
 
240
+ // Subscribe to account connection status changes
241
+ const unsubscribe = accountsProvider.subscribeAccountConnectionStatus((status) => {
242
+ // status: 'connected' | 'disconnected'
243
+ console.log('Account connection status:', status);
244
+ });
245
+
218
246
  // Create a signer for a product account (for use with PAPI)
219
247
  const account: ProductAccount = {
220
248
  dotNsIdentifier: 'product.dot',
@@ -232,3 +260,61 @@ const productAccountSignedTx = await tx.signAndSubmit(signer);
232
260
  const nonProductAccountSignedTx = await tx.signAndSubmit(nonProductSigner);
233
261
  ```
234
262
 
263
+ ### Local Storage
264
+
265
+ The Local Storage module provides a way to persist data in the host application's storage.
266
+
267
+ ```ts
268
+ import { hostLocalStorage, createLocalStorage } from '@novasamatech/product-sdk';
269
+
270
+ // Use the default instance
271
+ const storage = hostLocalStorage;
272
+
273
+ // Or create a custom instance with a different transport
274
+ // const storage = createLocalStorage(customTransport);
275
+
276
+ // Write and read raw bytes
277
+ await storage.writeBytes('key', new Uint8Array([1, 2, 3]));
278
+ const bytes = await storage.readBytes('key');
279
+
280
+ // Write and read strings
281
+ await storage.writeString('greeting', 'Hello, World!');
282
+ const greeting = await storage.readString('greeting');
283
+
284
+ // Write and read JSON
285
+ await storage.writeJSON('config', { theme: 'dark', fontSize: 14 });
286
+ const config = await storage.readJSON('config');
287
+
288
+ // Clear a key
289
+ await storage.clear('key');
290
+ ```
291
+
292
+ ### Preimage Manager
293
+
294
+ The Preimage Manager allows you to lookup and submit preimages to the host application.
295
+
296
+ ```ts
297
+ import { preimageManager, createPreimageManager } from '@novasamatech/product-sdk';
298
+
299
+ // Use the default instance
300
+ const manager = preimageManager;
301
+
302
+ // Or create a custom instance with a different transport
303
+ // const manager = createPreimageManager(customTransport);
304
+
305
+ // Lookup a preimage by its hash key
306
+ const subscription = manager.lookup('0x1234...', (preimage) => {
307
+ if (preimage) {
308
+ console.log('Preimage found:', preimage);
309
+ } else {
310
+ console.log('Preimage not found');
311
+ }
312
+ });
313
+
314
+ // Unsubscribe when done
315
+ subscription.unsubscribe();
316
+
317
+ // Submit a preimage
318
+ const preimageKey = await manager.submit(new Uint8Array([1, 2, 3, 4]));
319
+ ```
320
+
@@ -1,4 +1,4 @@
1
- import type { CodecType, Transport } from '@novasamatech/host-api';
1
+ import type { AccountConnectionStatus as AccountConnectionStatusCodec, CodecType, Transport } from '@novasamatech/host-api';
2
2
  import { RingLocation } from '@novasamatech/host-api';
3
3
  import type { PolkadotSigner } from 'polkadot-api';
4
4
  export type ProductAccount = {
@@ -6,6 +6,7 @@ export type ProductAccount = {
6
6
  derivationIndex: number;
7
7
  publicKey: Uint8Array;
8
8
  };
9
+ export type AccountConnectionStatus = CodecType<typeof AccountConnectionStatusCodec>;
9
10
  export declare const createAccountsProvider: (transport?: Transport) => {
10
11
  getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
11
12
  publicKey: Uint8Array<ArrayBufferLike>;
@@ -37,5 +38,6 @@ export declare const createAccountsProvider: (transport?: Transport) => {
37
38
  reason: string;
38
39
  }, "CreateProofErr::Unknown">>;
39
40
  getProductAccountSigner(account: ProductAccount): PolkadotSigner;
41
+ subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): import("@novasamatech/host-api").Subscription;
40
42
  getNonProductAccountSigner(account: ProductAccount): PolkadotSigner;
41
43
  };
package/dist/accounts.js CHANGED
@@ -111,6 +111,13 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
111
111
  });
112
112
  });
113
113
  },
114
+ subscribeAccountConnectionStatus(callback) {
115
+ return hostApi.accountConnectionStatusSubscribe(enumValue('v1', undefined), status => {
116
+ if (status.tag === 'v1') {
117
+ callback(status.value);
118
+ }
119
+ });
120
+ },
114
121
  getNonProductAccountSigner(account) {
115
122
  return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
116
123
  const codecPayload = {
package/dist/chat.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ChatBotRegistrationStatus as ChatBotRegistrationStatusCodec, ChatMessageContent as ChatMessageContentCodec, ChatRoom as ChatRoomCodec, ChatRoomRegistrationStatus as ChatRoomRegistrationStatusCodec, CodecType, ReceivedChatAction as ReceivedChatActionCodec, Transport } from '@novasamatech/host-api';
2
+ import { CustomRendererNode } from '@novasamatech/host-api';
2
3
  export type ChatMessageContent = CodecType<typeof ChatMessageContentCodec>;
3
4
  export type ReceivedChatAction = CodecType<typeof ReceivedChatActionCodec>;
4
5
  export type ChatRoomRegistrationResult = CodecType<typeof ChatRoomRegistrationStatusCodec>;
@@ -20,4 +21,5 @@ export declare const createProductChatManager: (transport?: Transport) => {
20
21
  }>;
21
22
  subscribeChatList(callback: (rooms: ChatRoom[]) => void): import("@novasamatech/host-api").Subscription;
22
23
  subscribeAction(callback: (action: ReceivedChatAction) => void): import("@novasamatech/host-api").Subscription;
24
+ onCustomMessageRenderingRequest(callback: (messageType: string, payload: Uint8Array, render: (node: CodecType<typeof CustomRendererNode>) => void) => VoidFunction): VoidFunction;
23
25
  };
package/dist/chat.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createHostApi, enumValue } from '@novasamatech/host-api';
1
+ import { CustomRendererNode, createHostApi, enumValue } from '@novasamatech/host-api';
2
2
  import { sandboxTransport } from './sandboxTransport.js';
3
3
  export const createProductChatManager = (transport = sandboxTransport) => {
4
4
  const hostApi = createHostApi(transport);
@@ -75,6 +75,18 @@ export const createProductChatManager = (transport = sandboxTransport) => {
75
75
  }
76
76
  });
77
77
  },
78
+ onCustomMessageRenderingRequest(callback) {
79
+ return transport.handleSubscription('product_chat_custom_message_render_subscribe', (params, send, interrupt) => {
80
+ if (params.tag === 'v1') {
81
+ return callback(params.value.messageType, params.value.payload, node => send(enumValue('v1', node)));
82
+ }
83
+ // unsupported version
84
+ interrupt();
85
+ return () => {
86
+ /* empty */
87
+ };
88
+ });
89
+ },
78
90
  };
79
91
  return chat;
80
92
  };
package/dist/helpers.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- type PromiseWithResolvers<T> = {
2
- promise: Promise<T>;
3
- resolve: (value: T) => void;
4
- reject: (reason: unknown) => void;
5
- };
6
- export declare const promiseWithResolvers: <const T>() => PromiseWithResolvers<T>;
7
- export {};
1
+ import type { ResultAsync } from 'neverthrow';
2
+ export declare function unwrapVersionedResult<OK, KO, V extends string>(version: V, result: ResultAsync<{
3
+ tag: V;
4
+ value: OK;
5
+ }, {
6
+ tag: V;
7
+ value: KO;
8
+ }>): ResultAsync<OK, Error | KO>;
9
+ export declare function resultToPromise<T>(result: ResultAsync<T, unknown>): Promise<T>;
package/dist/helpers.js CHANGED
@@ -1,10 +1,19 @@
1
- export const promiseWithResolvers = () => {
2
- let resolve;
3
- let reject;
4
- const promise = new Promise((res, rej) => {
5
- resolve = res;
6
- reject = rej;
1
+ import { err, ok } from 'neverthrow';
2
+ export function unwrapVersionedResult(version, result) {
3
+ return result
4
+ .orElse(payload => {
5
+ if (payload.tag !== version) {
6
+ return err(new Error(`Unsupported result version ${payload.tag}`));
7
+ }
8
+ return err(payload.value);
9
+ })
10
+ .andThen(payload => {
11
+ if (payload.tag !== version) {
12
+ return err(new Error(`Unsupported result version ${payload.tag}`));
13
+ }
14
+ return ok(payload.value);
7
15
  });
8
- // @ts-expect-error before assign
9
- return { promise, resolve, reject };
10
- };
16
+ }
17
+ export function resultToPromise(result) {
18
+ return new Promise((resolve, reject) => result.match(resolve, reject));
19
+ }
package/dist/index.d.ts CHANGED
@@ -8,5 +8,7 @@ export type { ChatBotRegistrationResult, ChatMessageContent, ChatRoom, ChatRoomR
8
8
  export { createProductChatManager } from './chat.js';
9
9
  export type { ProductAccountId, SignedStatement, Statement, Topic } from './statementStore.js';
10
10
  export { createStatementStore } from './statementStore.js';
11
- export type { ProductAccount } from './accounts.js';
11
+ export type { AccountConnectionStatus, ProductAccount } from './accounts.js';
12
12
  export { createAccountsProvider } from './accounts.js';
13
+ export { createLocalStorage, hostLocalStorage } from './localStorage.js';
14
+ export { createPreimageManager, preimageManager } from './preimage.js';
package/dist/index.js CHANGED
@@ -7,3 +7,5 @@ export { createPapiProvider } from './papiProvider.js';
7
7
  export { createProductChatManager } from './chat.js';
8
8
  export { createStatementStore } from './statementStore.js';
9
9
  export { createAccountsProvider } from './accounts.js';
10
+ export { createLocalStorage, hostLocalStorage } from './localStorage.js';
11
+ export { createPreimageManager, preimageManager } from './preimage.js';
@@ -0,0 +1,18 @@
1
+ export declare const createLocalStorage: (transport?: import("@novasamatech/host-api").Transport) => {
2
+ clear(key: string): Promise<undefined>;
3
+ readBytes(key: string): Promise<Uint8Array<ArrayBufferLike> | undefined>;
4
+ writeBytes(key: string, value: Uint8Array): Promise<undefined>;
5
+ readString(key: string): Promise<string>;
6
+ writeString(key: string, value: string): Promise<undefined>;
7
+ readJSON(key: string): Promise<any>;
8
+ writeJSON(key: string, value: unknown): Promise<undefined>;
9
+ };
10
+ export declare const hostLocalStorage: {
11
+ clear(key: string): Promise<undefined>;
12
+ readBytes(key: string): Promise<Uint8Array<ArrayBufferLike> | undefined>;
13
+ writeBytes(key: string, value: Uint8Array): Promise<undefined>;
14
+ readString(key: string): Promise<string>;
15
+ writeString(key: string, value: string): Promise<undefined>;
16
+ readJSON(key: string): Promise<any>;
17
+ writeJSON(key: string, value: unknown): Promise<undefined>;
18
+ };
@@ -0,0 +1,44 @@
1
+ import { createHostApi, enumValue } from '@novasamatech/host-api';
2
+ import { resultToPromise, unwrapVersionedResult } from './helpers.js';
3
+ import { sandboxTransport } from './sandboxTransport.js';
4
+ export const createLocalStorage = (transport = sandboxTransport) => {
5
+ const supportedVersion = 'v1';
6
+ const hostApi = createHostApi(transport);
7
+ const textEncoder = new TextEncoder();
8
+ const textDecoder = new TextDecoder();
9
+ function readBytes(key) {
10
+ return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.localStorageRead(enumValue(supportedVersion, key))));
11
+ }
12
+ function writeBytes(key, value) {
13
+ return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.localStorageWrite(enumValue(supportedVersion, [key, value]))));
14
+ }
15
+ function clearKey(key) {
16
+ return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.localStorageClear(enumValue(supportedVersion, key))));
17
+ }
18
+ return {
19
+ async clear(key) {
20
+ return clearKey(key);
21
+ },
22
+ async readBytes(key) {
23
+ return readBytes(key);
24
+ },
25
+ async writeBytes(key, value) {
26
+ return writeBytes(key, value);
27
+ },
28
+ async readString(key) {
29
+ return readBytes(key).then(bytes => textDecoder.decode(bytes));
30
+ },
31
+ async writeString(key, value) {
32
+ return writeBytes(key, textEncoder.encode(value));
33
+ },
34
+ async readJSON(key) {
35
+ return readBytes(key)
36
+ .then(bytes => textDecoder.decode(bytes))
37
+ .then(JSON.parse);
38
+ },
39
+ async writeJSON(key, value) {
40
+ return writeBytes(key, textEncoder.encode(JSON.stringify(value)));
41
+ },
42
+ };
43
+ };
44
+ export const hostLocalStorage = createLocalStorage();
@@ -34,7 +34,7 @@ __fallback, internal) {
34
34
  if (!ready)
35
35
  return false;
36
36
  return transport
37
- .request('feature', enumValue('v1', enumValue('Chain', genesisHash)))
37
+ .request('host_feature_supported', enumValue('v1', enumValue('Chain', genesisHash)))
38
38
  .then(payload => {
39
39
  switch (payload.tag) {
40
40
  case 'v1': {
@@ -0,0 +1,9 @@
1
+ import type { HexString } from '@novasamatech/host-api';
2
+ export declare const createPreimageManager: (transport?: import("@novasamatech/host-api").Transport) => {
3
+ lookup(key: HexString, callback: (preimage: Uint8Array | null) => void): import("@novasamatech/host-api").Subscription;
4
+ submit(value: Uint8Array): Promise<`0x${string}`>;
5
+ };
6
+ export declare const preimageManager: {
7
+ lookup(key: HexString, callback: (preimage: Uint8Array | null) => void): import("@novasamatech/host-api").Subscription;
8
+ submit(value: Uint8Array): Promise<`0x${string}`>;
9
+ };
@@ -0,0 +1,20 @@
1
+ import { createHostApi, enumValue } from '@novasamatech/host-api';
2
+ import { resultToPromise, unwrapVersionedResult } from './helpers.js';
3
+ import { sandboxTransport } from './sandboxTransport.js';
4
+ export const createPreimageManager = (transport = sandboxTransport) => {
5
+ const supportedVersion = 'v1';
6
+ const hostApi = createHostApi(transport);
7
+ return {
8
+ lookup(key, callback) {
9
+ return hostApi.preimageLookupSubscribe(enumValue(supportedVersion, key), payload => {
10
+ if (payload.tag === supportedVersion) {
11
+ callback(payload.value);
12
+ }
13
+ });
14
+ },
15
+ submit(value) {
16
+ return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.preimageSubmit(enumValue(supportedVersion, value))));
17
+ },
18
+ };
19
+ };
20
+ export const preimageManager = createPreimageManager();
@@ -4,7 +4,6 @@ export type SignedStatement = CodecType<typeof SignedStatementCodec>;
4
4
  export type Topic = CodecType<typeof TopicCodec>;
5
5
  export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
6
6
  export declare const createStatementStore: (transport?: Transport) => {
7
- query(topics: Topic[]): Promise<SignedStatement[]>;
8
7
  subscribe(topics: Topic[], callback: (statements: SignedStatement[]) => void): import("@novasamatech/host-api").Subscription;
9
8
  createProof(accountId: ProductAccountId, statement: Statement): Promise<{
10
9
  tag: "Sr25519";
@@ -3,17 +3,6 @@ import { sandboxTransport } from './sandboxTransport.js';
3
3
  export const createStatementStore = (transport = sandboxTransport) => {
4
4
  const hostApi = createHostApi(transport);
5
5
  return {
6
- async query(topics) {
7
- const result = await hostApi.statementStoreQuery(enumValue('v1', topics));
8
- return result.match(payload => {
9
- if (payload.tag === 'v1') {
10
- return payload.value;
11
- }
12
- throw new Error(`Unknown response version ${payload.tag}`);
13
- }, err => {
14
- throw err.value;
15
- });
16
- },
17
6
  subscribe(topics, callback) {
18
7
  return hostApi.statementStoreSubscribe(enumValue('v1', topics), payload => {
19
8
  if (payload.tag === 'v1') {
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@novasamatech/product-sdk",
3
3
  "type": "module",
4
- "version": "0.5.4",
4
+ "version": "0.6.0",
5
5
  "description": "Polkadot product SDK: integrate and run your product inside Polkadot browser.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/novasamatech/spektr-sdk.git"
9
+ "url": "git+https://github.com/Polkadot-Community-Foundation/triangle-js-sdks.git"
10
10
  },
11
11
  "keywords": [
12
12
  "polkadot",
@@ -30,7 +30,7 @@
30
30
  "@polkadot-api/substrate-bindings": "^0.17.0",
31
31
  "@polkadot-api/json-rpc-provider": "^0.0.4",
32
32
  "@polkadot-api/json-rpc-provider-proxy": "^0.2.7",
33
- "@novasamatech/host-api": "0.5.4"
33
+ "@novasamatech/host-api": "0.6.0"
34
34
  },
35
35
  "publishConfig": {
36
36
  "access": "public"