@novasamatech/product-sdk 0.5.0-8 → 0.5.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
@@ -1,12 +1,13 @@
1
1
  # @novasamatech/product-sdk
2
2
 
3
- Easy way to embed Polkadot host functionality into your dapp.
3
+ An easy way to embed Polkadot host functionality into your dapp.
4
4
 
5
5
  ## Overview
6
6
 
7
- Spektr SDK provides a set of tools to integrate your application with Spektr dapp browser.
7
+ Product SDK provides a set of tools to integrate your application with any Polkadot host application.
8
8
  Core features:
9
- - Generic account provider similar to [polkadot-js extension](https://polkadot.js.org/extension/).
9
+ - Generic account provider similar to [polkadot-js extension](https://polkadot.js.org/extension/)
10
+ - Chat module integration
10
11
  - Redirect [PAPI](https://papi.how/) requests to host application
11
12
  - Receive additional information from host application - supported chains, theme, etc.
12
13
 
@@ -20,7 +21,7 @@ npm install @novasamatech/product-sdk --save -E
20
21
 
21
22
  ### Injecting account provider into `injectedWeb3` interface
22
23
 
23
- Spektr SDK can provide account information and signers with same interface as any other polkadot compatible wallet.
24
+ Product SDK can provide account information and signers with the same interface as any other Polkadot-compatible wallet.
24
25
 
25
26
  ```ts
26
27
  import { injectSpektrExtension, SpektrExtensionName } from '@novasamatech/product-sdk';
@@ -50,7 +51,7 @@ async function getAccounts(): Promise<InjectedPolkadotAccount[]> {
50
51
 
51
52
  ### Redirecting PAPI requests to host application
52
53
 
53
- You can wrap your PAPI provider with spektr provider to support redirecting requests to host application.
54
+ You can wrap your PAPI provider with Spektr provider to support redirecting requests to the host application.
54
55
 
55
56
  ```diff
56
57
  import { createClient, type PolkadotClient } from 'polkadot-api';
@@ -80,3 +81,36 @@ const unsubscribe = spektrMetaProvider.subscribeConnectionStatus((status) => {
80
81
  });
81
82
  ```
82
83
 
84
+ ### Chat Integration
85
+
86
+ ```ts
87
+ import { createChat } from '@novasamatech/product-sdk';
88
+
89
+ // Create chat instance
90
+ const chat = createChat();
91
+
92
+ // Register your dapp as a chat contact
93
+ const registrationStatus = await chat.register({
94
+ name: 'My Product',
95
+ icon: 'https://example.com/icon.png'
96
+ });
97
+
98
+ // Send a message
99
+ const { messageId } = await chat.sendMessage({
100
+ tag: 'Text',
101
+ value: 'Hello dear user!'
102
+ });
103
+
104
+ // Subscribe to chat actions (incoming messages, etc.)
105
+ const subscriber = chat.subscribeAction((action) => {
106
+ if (action.tag === 'MessagePosted') {
107
+ console.log('Received message:', action.value);
108
+ }
109
+ if (action.tag === 'ActionTriggered') {
110
+ console.log('User triggered action:', action.value)
111
+ }
112
+ });
113
+ ```
114
+
115
+ **Note:** Messages sent before registration will be queued and sent automatically after successful registration.
116
+
package/dist/chat.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { ChatContactRegistrationStatus as ChatContactRegistrationStatusCodec, ChatMessage as ChatMessageCodec, CodecType, ReceivedChatAction as ReceivedChatActionCodec, Transport } from '@novasamatech/host-api';
2
+ export type ChatMessage = CodecType<typeof ChatMessageCodec>;
3
+ export type ReceivedChatAction = CodecType<typeof ReceivedChatActionCodec>;
4
+ export type ChatContactRegistrationStatus = CodecType<typeof ChatContactRegistrationStatusCodec>;
5
+ export declare const createChat: (transport?: Transport) => {
6
+ register(params: {
7
+ name: string;
8
+ icon: string;
9
+ }): Promise<"New" | "Exists">;
10
+ sendMessage(message: ChatMessage): Promise<{
11
+ messageId: string;
12
+ }>;
13
+ subscribeAction(callback: (action: ReceivedChatAction) => void): import("packages/host-api/dist/types.js").Subscription;
14
+ };
package/dist/chat.js ADDED
@@ -0,0 +1,62 @@
1
+ import { createHostApi, enumValue } from '@novasamatech/host-api';
2
+ import { defaultTransport } from './defaultTransport.js';
3
+ import { promiseWithResolvers } from './helpers.js';
4
+ promiseWithResolvers();
5
+ export const createChat = (transport = defaultTransport) => {
6
+ const hostApi = createHostApi(transport);
7
+ let registrationStatus = null;
8
+ const messageQueue = [];
9
+ const chat = {
10
+ async register(params) {
11
+ if (registrationStatus) {
12
+ return registrationStatus;
13
+ }
14
+ const result = await hostApi.chat_create_contact(enumValue('v1', params));
15
+ return result.match(payload => {
16
+ if (payload.tag === 'v1') {
17
+ registrationStatus = payload.value;
18
+ if (messageQueue.length > 0) {
19
+ messageQueue.forEach(({ message, resolve, reject }) => {
20
+ chat.sendMessage(message).then(resolve, reject);
21
+ });
22
+ messageQueue.length = 0;
23
+ }
24
+ return registrationStatus;
25
+ }
26
+ else {
27
+ throw new Error(`Unknown message version ${payload.tag}`);
28
+ }
29
+ }, err => {
30
+ throw err.value;
31
+ });
32
+ },
33
+ async sendMessage(message) {
34
+ if (registrationStatus) {
35
+ const result = await hostApi.chat_post_message(enumValue('v1', message));
36
+ return result.match(payload => {
37
+ if (payload.tag === 'v1') {
38
+ return { messageId: payload.value.messageId };
39
+ }
40
+ else {
41
+ throw new Error(`Unknown message version ${payload.tag}`);
42
+ }
43
+ }, err => {
44
+ throw err.value;
45
+ });
46
+ }
47
+ else {
48
+ const { promise, resolve, reject } = promiseWithResolvers();
49
+ messageQueue.push({ message, resolve, reject });
50
+ return promise;
51
+ }
52
+ },
53
+ subscribeAction(callback) {
54
+ return hostApi.chat_action_subscribe(enumValue('v1', undefined), action => {
55
+ if (action.tag === 'v1') {
56
+ callback(action.value);
57
+ }
58
+ });
59
+ },
60
+ };
61
+ return chat;
62
+ };
@@ -1,7 +1,7 @@
1
1
  import type { ConnectionStatus, Transport } from '@novasamatech/host-api';
2
- export declare function createSpektrMetaProvider(transport?: Transport): {
2
+ export declare function createMetaProvider(transport?: Transport): {
3
3
  subscribeConnectionStatus(callback: (connectionStatus: ConnectionStatus) => void): VoidFunction;
4
4
  };
5
- export declare const spektrMetaProvider: {
5
+ export declare const metaProvider: {
6
6
  subscribeConnectionStatus(callback: (connectionStatus: ConnectionStatus) => void): VoidFunction;
7
7
  };
@@ -0,0 +1,24 @@
1
+ import { defaultTransport } from './defaultTransport.js';
2
+ export function createMetaProvider(transport = defaultTransport) {
3
+ // if (transport.isCorrectEnvironment() && typeof window !== 'undefined') {
4
+ // const getUrl = () => {
5
+ // return window.location.pathname + window.location.hash + window.location.search;
6
+ // };
7
+ //
8
+ // window.addEventListener('hashchange', () => {
9
+ // transport.postMessage('_', { tag: 'locationChangedV1', value: getUrl() });
10
+ // });
11
+ //
12
+ // window.addEventListener('popstate', () => {
13
+ // transport.postMessage('_', { tag: 'locationChangedV1', value: getUrl() });
14
+ // });
15
+ //
16
+ // transport.postMessage('_', { tag: 'locationChangedV1', value: getUrl() });
17
+ // }
18
+ return {
19
+ subscribeConnectionStatus(callback) {
20
+ return transport.onConnectionStatusChange(callback);
21
+ },
22
+ };
23
+ }
24
+ export const metaProvider = createMetaProvider();
@@ -7,5 +7,5 @@ type Params = {
7
7
  type InternalParams = {
8
8
  transport?: Transport;
9
9
  };
10
- export declare function createSpektrPapiProvider({ chainId, fallback }: Params, internal?: InternalParams): JsonRpcProvider;
10
+ export declare function createPapiProvider({ chainId: genesisHash, fallback }: Params, internal?: InternalParams): JsonRpcProvider;
11
11
  export {};
@@ -0,0 +1,51 @@
1
+ import { createHostApi, enumValue, unwrapResultOrThrow } from '@novasamatech/host-api';
2
+ import { getSyncProvider } from '@polkadot-api/json-rpc-provider-proxy';
3
+ import { defaultTransport } from './defaultTransport.js';
4
+ export function createPapiProvider({ chainId: genesisHash, fallback }, internal) {
5
+ const version = 'v1';
6
+ const transport = internal?.transport ?? defaultTransport;
7
+ if (!transport.isCorrectEnvironment())
8
+ return fallback;
9
+ const hostApi = createHostApi(transport);
10
+ const spektrProvider = onMessage => {
11
+ const subscription = hostApi.jsonrpc_message_subscribe(enumValue(version, genesisHash), payload => {
12
+ switch (payload.tag) {
13
+ case version:
14
+ onMessage(payload.value);
15
+ break;
16
+ default:
17
+ transport.provider.logger.error('Unknown message version', payload.tag);
18
+ }
19
+ });
20
+ return {
21
+ send(message) {
22
+ hostApi.jsonrpc_message_send(enumValue(version, [genesisHash, message]));
23
+ },
24
+ disconnect() {
25
+ subscription.unsubscribe();
26
+ },
27
+ };
28
+ };
29
+ function checkIfReady() {
30
+ return transport.isReady().then(ready => {
31
+ if (!ready)
32
+ return false;
33
+ return transport
34
+ .request('feature', enumValue('v1', enumValue('Chain', genesisHash)))
35
+ .then(payload => {
36
+ switch (payload.tag) {
37
+ case 'v1': {
38
+ return unwrapResultOrThrow(payload.value, e => new Error(e.payload.reason));
39
+ }
40
+ default:
41
+ throw new Error(`Unknown message version ${payload.tag}`);
42
+ }
43
+ })
44
+ .catch(e => {
45
+ transport.provider.logger.error('Error checking chain support', e);
46
+ return false;
47
+ });
48
+ });
49
+ }
50
+ return getSyncProvider(() => checkIfReady().then(ready => (ready ? spektrProvider : fallback)));
51
+ }
@@ -1,3 +1,3 @@
1
- import type { TransportProvider } from '@novasamatech/host-api';
2
- export declare const defaultProvider: TransportProvider;
1
+ import type { Provider } from '@novasamatech/host-api';
2
+ export declare const defaultProvider: Provider;
3
3
  export declare const defaultTransport: import("@novasamatech/host-api").Transport;
@@ -54,4 +54,4 @@ function createDefaultSdkProvider() {
54
54
  };
55
55
  }
56
56
  export const defaultProvider = createDefaultSdkProvider();
57
- export const defaultTransport = createTransport(defaultProvider, { handshakeTimeout: 1_000 });
57
+ export const defaultTransport = createTransport(defaultProvider);
@@ -0,0 +1,7 @@
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 {};
@@ -0,0 +1,10 @@
1
+ export const promiseWithResolvers = () => {
2
+ let resolve;
3
+ let reject;
4
+ const promise = new Promise((res, rej) => {
5
+ resolve = res;
6
+ reject = rej;
7
+ });
8
+ // @ts-expect-error before assign
9
+ return { promise, resolve, reject };
10
+ };