@novasamatech/host-api 0.4.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 ADDED
@@ -0,0 +1,9 @@
1
+ # @novasamatech/host-api
2
+
3
+ Protocol and transport implementation for host <=> product interaction inside Polkadot ecosystem.
4
+
5
+ ## Installation
6
+
7
+ ```shell
8
+ npm install @novasamatech/host-api --save -E
9
+ ```
@@ -0,0 +1,16 @@
1
+ import type { Codec } from 'scale-ts';
2
+ export declare const hexEncoder: Codec<`0x${string}`>;
3
+ export declare function responseEncoder<T>(codec: Codec<T>): Codec<{
4
+ tag: "success";
5
+ value: T;
6
+ } | {
7
+ tag: "error";
8
+ value: string;
9
+ }>;
10
+ export declare function createNullableEncoder<T>(codec: Codec<T>): Codec<{
11
+ tag: "value";
12
+ value: T;
13
+ } | {
14
+ tag: "null";
15
+ value: undefined;
16
+ }>;
@@ -0,0 +1,20 @@
1
+ import { fromHex, toHex } from '@polkadot-api/utils';
2
+ import { Bytes, Enum, _void, str } from 'scale-ts';
3
+ import { createTransportEncoder } from './createTransportEncoder.js';
4
+ export const hexEncoder = createTransportEncoder({
5
+ codec: Bytes(),
6
+ from: v => toHex(v),
7
+ to: fromHex,
8
+ });
9
+ export function responseEncoder(codec) {
10
+ return Enum({
11
+ success: codec,
12
+ error: str,
13
+ });
14
+ }
15
+ export function createNullableEncoder(codec) {
16
+ return Enum({
17
+ value: codec,
18
+ null: _void,
19
+ });
20
+ }
@@ -0,0 +1 @@
1
+ export declare const HANDSHAKE_INTERVAL = 50;
@@ -0,0 +1 @@
1
+ export const HANDSHAKE_INTERVAL = 50;
@@ -0,0 +1,6 @@
1
+ import type { Transport, TransportProvider } from './types.js';
2
+ type TransportParams = Partial<{
3
+ handshakeTimeout: number;
4
+ }>;
5
+ export declare function createTransport(provider: TransportProvider, params?: TransportParams): Transport;
6
+ export {};
@@ -0,0 +1,183 @@
1
+ import { createNanoEvents } from 'nanoevents';
2
+ import { nanoid } from 'nanoid';
3
+ import { HANDSHAKE_INTERVAL } from './constants.js';
4
+ import { delay, promiseWithResolvers } from './helpers.js';
5
+ import { messageEncoder } from './messageEncoder.js';
6
+ export function createTransport(provider, params) {
7
+ const handshakeTimeout = params?.handshakeTimeout ?? Number.POSITIVE_INFINITY;
8
+ const handshakeAbortController = new AbortController();
9
+ let handshakePromise = null;
10
+ let connectionStatusResolved = false;
11
+ let connectionStatus = 'disconnected';
12
+ let disposed = false;
13
+ const events = createNanoEvents();
14
+ events.on('connectionStatus', value => {
15
+ connectionStatus = value;
16
+ });
17
+ function changeConnectionStatus(status) {
18
+ events.emit('connectionStatus', status);
19
+ }
20
+ function throwIfDisposed() {
21
+ if (disposed) {
22
+ throw new Error('Transport is disposed');
23
+ }
24
+ }
25
+ function throwIfIncorrectEnvironment() {
26
+ if (!provider.isCorrectEnvironment()) {
27
+ throw new Error('Environment is not correct');
28
+ }
29
+ }
30
+ function connectionStatusToBoolean(connectionStatus) {
31
+ switch (connectionStatus) {
32
+ case 'disconnected':
33
+ case 'connecting':
34
+ return false;
35
+ case 'connected':
36
+ return true;
37
+ }
38
+ }
39
+ const transportInstance = {
40
+ provider,
41
+ isCorrectEnvironment() {
42
+ return provider.isCorrectEnvironment();
43
+ },
44
+ isReady() {
45
+ throwIfIncorrectEnvironment();
46
+ throwIfDisposed();
47
+ if (connectionStatusResolved) {
48
+ return Promise.resolve(connectionStatusToBoolean(connectionStatus));
49
+ }
50
+ if (handshakePromise) {
51
+ return handshakePromise;
52
+ }
53
+ changeConnectionStatus('connecting');
54
+ let resolved = false;
55
+ const request = new Promise(resolve => {
56
+ const id = nanoid();
57
+ const unsubscribe = transportInstance.subscribe('handshakeResponseV1', responseId => {
58
+ if (responseId !== id)
59
+ return;
60
+ clearInterval(interval);
61
+ unsubscribe();
62
+ handshakeAbortController.signal.removeEventListener('abort', unsubscribe);
63
+ resolved = true;
64
+ resolve(true);
65
+ });
66
+ handshakeAbortController.signal.addEventListener('abort', unsubscribe, { once: true });
67
+ const interval = setInterval(() => {
68
+ if (handshakeAbortController.signal.aborted) {
69
+ clearInterval(interval);
70
+ resolve(false);
71
+ return;
72
+ }
73
+ transportInstance.postMessage(id, { tag: 'handshakeRequestV1', value: undefined });
74
+ }, HANDSHAKE_INTERVAL);
75
+ });
76
+ const promise = handshakeTimeout === Number.POSITIVE_INFINITY
77
+ ? request
78
+ : Promise.race([
79
+ request,
80
+ delay(handshakeTimeout).then(() => {
81
+ if (!resolved) {
82
+ handshakeAbortController.abort('Timeout');
83
+ }
84
+ return false;
85
+ }),
86
+ ]);
87
+ handshakePromise = promise.then(result => {
88
+ handshakePromise = null;
89
+ connectionStatusResolved = true;
90
+ changeConnectionStatus(result ? 'connected' : 'disconnected');
91
+ return result;
92
+ });
93
+ return handshakePromise;
94
+ },
95
+ subscribeAny(callback) {
96
+ throwIfIncorrectEnvironment();
97
+ throwIfDisposed();
98
+ return provider.subscribe(message => {
99
+ let result;
100
+ try {
101
+ result = messageEncoder.dec(message);
102
+ }
103
+ catch {
104
+ return;
105
+ }
106
+ callback(result.id, result.payload);
107
+ });
108
+ },
109
+ subscribe(type, callback) {
110
+ throwIfIncorrectEnvironment();
111
+ throwIfDisposed();
112
+ return transportInstance.subscribeAny((id, message) => {
113
+ if (message.tag == type) {
114
+ callback(id, message.value);
115
+ }
116
+ });
117
+ },
118
+ postMessage(id, payload) {
119
+ throwIfIncorrectEnvironment();
120
+ throwIfDisposed();
121
+ const encoded = messageEncoder.enc({ id, payload });
122
+ provider.postMessage(encoded);
123
+ return id;
124
+ },
125
+ async request(payload, response, abortSignal) {
126
+ throwIfIncorrectEnvironment();
127
+ throwIfDisposed();
128
+ const ready = await transportInstance.isReady();
129
+ if (!ready) {
130
+ throw new Error('Polkadot host is not ready');
131
+ }
132
+ abortSignal?.throwIfAborted();
133
+ const requestId = nanoid();
134
+ const { resolve, reject, promise } = promiseWithResolvers();
135
+ const unsubscribe = transportInstance.subscribe(response, (receivedId, payload) => {
136
+ if (receivedId === requestId) {
137
+ abortSignal?.removeEventListener('abort', stop);
138
+ unsubscribe();
139
+ resolve(payload);
140
+ }
141
+ });
142
+ const stop = () => {
143
+ unsubscribe();
144
+ reject(abortSignal?.reason ?? new Error('Request aborted'));
145
+ };
146
+ abortSignal?.addEventListener('abort', stop, { once: true });
147
+ transportInstance.postMessage(requestId, payload);
148
+ return promise;
149
+ },
150
+ handleMessage(type, handler) {
151
+ throwIfIncorrectEnvironment();
152
+ throwIfDisposed();
153
+ return transportInstance.subscribe(type, (id, payload) => {
154
+ handler(payload).then(result => {
155
+ if (!result)
156
+ return;
157
+ transportInstance.postMessage(id, result);
158
+ });
159
+ });
160
+ },
161
+ onConnectionStatusChange(callback) {
162
+ callback(connectionStatus);
163
+ return events.on('connectionStatus', callback);
164
+ },
165
+ dispose() {
166
+ disposed = true;
167
+ provider.dispose();
168
+ changeConnectionStatus('disconnected');
169
+ events.events = {};
170
+ handshakeAbortController.abort('Transport disposed');
171
+ },
172
+ };
173
+ if (provider.isCorrectEnvironment()) {
174
+ transportInstance.handleMessage('handshakeRequestV1', async () => ({
175
+ tag: 'handshakeResponseV1',
176
+ value: {
177
+ tag: 'success',
178
+ value: undefined,
179
+ },
180
+ }));
181
+ }
182
+ return transportInstance;
183
+ }
@@ -0,0 +1,7 @@
1
+ import type { Codec, CodecType } from 'scale-ts';
2
+ export type TransportEncoder<Public, Transported extends Codec<any>> = {
3
+ codec: Transported;
4
+ from: (decoded: CodecType<Transported>) => Public;
5
+ to: (value: Public) => CodecType<Transported>;
6
+ };
7
+ export declare function createTransportEncoder<Public, Transported extends Codec<any>>(encoder: TransportEncoder<Public, Transported>): Codec<Public>;
@@ -0,0 +1,5 @@
1
+ import { enhanceCodec } from 'scale-ts';
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ export function createTransportEncoder(encoder) {
4
+ return enhanceCodec(encoder.codec, encoder.to, encoder.from);
5
+ }
@@ -0,0 +1,8 @@
1
+ export declare function delay(ttl: number): Promise<void>;
2
+ type PromiseWithResolvers<T> = {
3
+ promise: Promise<T>;
4
+ resolve: (value: T) => void;
5
+ reject: (reason: unknown) => void;
6
+ };
7
+ export declare const promiseWithResolvers: <const T>() => PromiseWithResolvers<T>;
8
+ export {};
@@ -0,0 +1,13 @@
1
+ export function delay(ttl) {
2
+ return new Promise(resolve => setTimeout(resolve, ttl));
3
+ }
4
+ export const promiseWithResolvers = () => {
5
+ let resolve;
6
+ let reject;
7
+ const promise = new Promise((res, rej) => {
8
+ resolve = res;
9
+ reject = rej;
10
+ });
11
+ // @ts-expect-error before assign
12
+ return { promise, resolve, reject };
13
+ };
@@ -0,0 +1,7 @@
1
+ export { messageEncoder, unwrapResponseOrThrow } from './messageEncoder.js';
2
+ export { type MessagePayloadSchema, type MessageType, type PickMessagePayload, type PickMessagePayloadValue, } from './messageEncoder.js';
3
+ export { createTransport } from './createTransport.js';
4
+ export type { ConnectionStatus, HexString, Logger, Transport, TransportProvider } from './types.js';
5
+ export { createDefaultLogger } from './logger.js';
6
+ export { type InjectedAccountSchema } from './interactions/accounts.js';
7
+ export { type TxPayloadV1 } from './interactions/sign.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { messageEncoder, unwrapResponseOrThrow } from './messageEncoder.js';
2
+ export {} from './messageEncoder.js';
3
+ export { createTransport } from './createTransport.js';
4
+ export { createDefaultLogger } from './logger.js';
5
+ export {} from './interactions/accounts.js';
6
+ export {} from './interactions/sign.js';
@@ -0,0 +1,12 @@
1
+ import type { InjectedAccount } from '@polkadot-api/pjs-signer';
2
+ import type { Codec, CodecType } from 'scale-ts';
3
+ /**
4
+ * @see {import('@polkadot/extension-inject/types').InjectedAccount}
5
+ */
6
+ export type InjectedAccountSchema = CodecType<typeof injectedAccountEncoder>;
7
+ declare const injectedAccountEncoder: Codec<InjectedAccount>;
8
+ export declare const getAccountsRequestV1Encoder: Codec<undefined>;
9
+ export declare const getAccountsResponseV1Encoder: Codec<InjectedAccount[]>;
10
+ export declare const accountSubscriptionV1Encoder: Codec<undefined>;
11
+ export declare const accountUnsubscriptionV1Encoder: Codec<undefined>;
12
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Enum, Option, Struct, Vector, _void, str } from 'scale-ts';
2
+ import { createTransportEncoder } from '../createTransportEncoder.js';
3
+ const keypairCodec = Enum({
4
+ ed25519: _void,
5
+ sr25519: _void,
6
+ ecdsa: _void,
7
+ });
8
+ const keypairEncoder = createTransportEncoder({
9
+ codec: keypairCodec,
10
+ from: v => v.tag,
11
+ to: keypair => ({
12
+ tag: keypair,
13
+ value: undefined,
14
+ }),
15
+ });
16
+ const injectedAccountCodec = Struct({
17
+ address: str,
18
+ genesisHash: Option(str),
19
+ name: Option(str),
20
+ type: Option(keypairEncoder),
21
+ });
22
+ const injectedAccountEncoder = createTransportEncoder({
23
+ codec: injectedAccountCodec,
24
+ from(decoded) {
25
+ return decoded;
26
+ },
27
+ to(value) {
28
+ return {
29
+ address: value.address,
30
+ genesisHash: value.genesisHash ? value.genesisHash : undefined,
31
+ name: value.name,
32
+ type: value.type,
33
+ };
34
+ },
35
+ });
36
+ export const getAccountsRequestV1Encoder = _void;
37
+ export const getAccountsResponseV1Encoder = Vector(injectedAccountEncoder);
38
+ export const accountSubscriptionV1Encoder = _void;
39
+ export const accountUnsubscriptionV1Encoder = _void;
@@ -0,0 +1,13 @@
1
+ export declare const supportFeatureRequestV1Encoder: import("scale-ts").Codec<{
2
+ tag: "chain";
3
+ value: {
4
+ chainId: `0x${string}`;
5
+ };
6
+ }>;
7
+ export declare const supportFeatureResponseV1: import("scale-ts").Codec<{
8
+ tag: "chain";
9
+ value: {
10
+ chainId: `0x${string}`;
11
+ result: boolean;
12
+ };
13
+ }>;
@@ -0,0 +1,13 @@
1
+ import { Enum, Struct, bool } from 'scale-ts';
2
+ import { hexEncoder } from '../commonEncoders.js';
3
+ export const supportFeatureRequestV1Encoder = Enum({
4
+ chain: Struct({
5
+ chainId: hexEncoder,
6
+ }),
7
+ });
8
+ export const supportFeatureResponseV1 = Enum({
9
+ chain: Struct({
10
+ chainId: hexEncoder,
11
+ result: bool,
12
+ }),
13
+ });
@@ -0,0 +1,2 @@
1
+ export declare const handshakeRequestV1Encoder: import("scale-ts").Codec<undefined>;
2
+ export declare const handshakeResponseV1Encoder: import("scale-ts").Codec<undefined>;
@@ -0,0 +1,3 @@
1
+ import { _void } from 'scale-ts';
2
+ export const handshakeRequestV1Encoder = _void;
3
+ export const handshakeResponseV1Encoder = _void;
@@ -0,0 +1,8 @@
1
+ export declare const papiProviderSendMessageV1Encoder: import("scale-ts").Codec<{
2
+ chainId: string;
3
+ message: string;
4
+ }>;
5
+ export declare const papiProviderReceiveMessageV1Encoder: import("scale-ts").Codec<{
6
+ chainId: string;
7
+ message: string;
8
+ }>;
@@ -0,0 +1,9 @@
1
+ import { Struct, str } from 'scale-ts';
2
+ export const papiProviderSendMessageV1Encoder = Struct({
3
+ chainId: str,
4
+ message: str,
5
+ });
6
+ export const papiProviderReceiveMessageV1Encoder = Struct({
7
+ chainId: str,
8
+ message: str,
9
+ });
@@ -0,0 +1,101 @@
1
+ import type { SignerPayloadJSON, SignerPayloadRaw, SignerResult } from '@polkadot/types/types';
2
+ import type { CodecType } from 'scale-ts';
3
+ import type { HexString } from '../types.js';
4
+ /**
5
+ * @see {import('@polkadot/types/types').SignerPayloadRaw}
6
+ */
7
+ export type SignRawRequestSchema = CodecType<typeof signRawRequestV1Encoder>;
8
+ export declare const signRawRequestV1Encoder: import("scale-ts").Codec<SignerPayloadRaw>;
9
+ /**
10
+ * @see {import('@polkadot/types/types').SignerPayloadJSON}
11
+ */
12
+ export type SignPayloadRequestSchema = CodecType<typeof signPayloadRequestV1Encoder>;
13
+ export declare const signPayloadCodec: import("scale-ts").Codec<{
14
+ address: string;
15
+ assetId: `0x${string}` | undefined;
16
+ blockHash: `0x${string}`;
17
+ blockNumber: `0x${string}`;
18
+ era: `0x${string}`;
19
+ genesisHash: `0x${string}`;
20
+ metadataHash: `0x${string}` | undefined;
21
+ method: string;
22
+ mode: number | undefined;
23
+ nonce: `0x${string}`;
24
+ specVersion: `0x${string}`;
25
+ tip: `0x${string}`;
26
+ transactionVersion: `0x${string}`;
27
+ signedExtensions: string[];
28
+ version: number;
29
+ withSignedTransaction: boolean | undefined;
30
+ }>;
31
+ export declare const signPayloadRequestV1Encoder: import("scale-ts").Codec<SignerPayloadJSON>;
32
+ export declare const signResponseV1Encoder: import("scale-ts").Codec<SignerResult>;
33
+ /**
34
+ * createTransaction implementation
35
+ * @see https://github.com/polkadot-js/api/issues/6213
36
+ */
37
+ export interface TxPayloadV1 {
38
+ /** Payload version. MUST be 1. */
39
+ version: 1;
40
+ /**
41
+ * Signer selection hint. Allows the implementer to identify which private-key / scheme to use.
42
+ * - Use a wallet-defined handle (e.g., address/SS58, account-name, etc). This identifier
43
+ * was previously made available to the consumer.
44
+ * - Set `null` to let the implementer pick the signer (or if the signer is implied).
45
+ */
46
+ signer: string | null;
47
+ /**
48
+ * SCALE-encoded Call (module indicator + function indicator + params).
49
+ */
50
+ callData: HexString;
51
+ /**
52
+ * Transaction extensions supplied by the caller (order irrelevant).
53
+ * The consumer SHOULD provide every extension that is relevant to them.
54
+ * The implementer MAY infer missing ones.
55
+ */
56
+ extensions: Array<{
57
+ /** Identifier as defined in metadata (e.g., "CheckSpecVersion", "ChargeAssetTxPayment"). */
58
+ id: string;
59
+ /**
60
+ * Explicit "extra" to sign (goes into the extrinsic body).
61
+ * SCALE-encoded per the extension's "extra" type as defined in the metadata.
62
+ */
63
+ extra: HexString;
64
+ /**
65
+ * "Implicit" data to sign (known by the chain, not included into the extrinsic body).
66
+ * SCALE-encoded per the extension's "additionalSigned" type as defined in the metadata.
67
+ */
68
+ additionalSigned: HexString;
69
+ }>;
70
+ /**
71
+ * Transaction Extension Version.
72
+ * - For Extrinsic V4 MUST be 0.
73
+ * - For Extrinsic V5, set to any version supported by the runtime.
74
+ * The implementer:
75
+ * - MUST use this field to determine the required extensions for creating the extrinsic.
76
+ * - MAY use this field to infer missing extensions that the implementer could know how to handle.
77
+ */
78
+ txExtVersion: number;
79
+ /**
80
+ * Context needed for decoding, display, and (optionally) inferring certain extensions.
81
+ */
82
+ context: {
83
+ /**
84
+ * RuntimeMetadataPrefixed blob (SCALE), starting with ASCII "meta" magic (`0x6d657461`),
85
+ * then a metadata version (V14+). For V5+ versioned extensions, MUST provide V16+.
86
+ */
87
+ metadata: HexString;
88
+ /**
89
+ * Native token display info (used by some implementers), also needed to compute
90
+ * the `CheckMetadataHash` value.
91
+ */
92
+ tokenSymbol: string;
93
+ tokenDecimals: number;
94
+ /**
95
+ * Highest known block number to aid mortality UX.
96
+ */
97
+ bestBlockHeight: number;
98
+ };
99
+ }
100
+ export declare const createTransactionRequestV1Encoder: import("scale-ts").Codec<TxPayloadV1>;
101
+ export declare const createTransactionResponseV1Encoder: import("scale-ts").Codec<`0x${string}`>;
@@ -0,0 +1,177 @@
1
+ import { Bytes, Enum, Option, Struct, Vector, _void, bool, str, u16, u32 } from 'scale-ts';
2
+ import { createNullableEncoder, hexEncoder } from '../commonEncoders.js';
3
+ import { createTransportEncoder } from '../createTransportEncoder.js';
4
+ const signRawRequestCodec = Struct({
5
+ address: str,
6
+ data: str,
7
+ type: Enum({
8
+ bytes: _void,
9
+ payload: _void,
10
+ }),
11
+ });
12
+ export const signRawRequestV1Encoder = createTransportEncoder({
13
+ codec: signRawRequestCodec,
14
+ from(decoded) {
15
+ return {
16
+ address: decoded.address,
17
+ data: decoded.data,
18
+ type: decoded.type.tag,
19
+ };
20
+ },
21
+ to(value) {
22
+ return {
23
+ address: value.address,
24
+ data: value.data,
25
+ type: {
26
+ tag: value.type,
27
+ value: undefined,
28
+ },
29
+ };
30
+ },
31
+ });
32
+ export const signPayloadCodec = Struct({
33
+ address: str,
34
+ assetId: Option(hexEncoder),
35
+ blockHash: hexEncoder,
36
+ blockNumber: hexEncoder,
37
+ era: hexEncoder,
38
+ genesisHash: hexEncoder,
39
+ metadataHash: Option(hexEncoder),
40
+ method: str,
41
+ mode: Option(u32),
42
+ nonce: hexEncoder,
43
+ specVersion: hexEncoder,
44
+ tip: hexEncoder,
45
+ transactionVersion: hexEncoder,
46
+ signedExtensions: Vector(str),
47
+ version: u32,
48
+ withSignedTransaction: Option(bool),
49
+ });
50
+ export const signPayloadRequestV1Encoder = createTransportEncoder({
51
+ codec: signPayloadCodec,
52
+ from(decoded) {
53
+ return {
54
+ address: decoded.address,
55
+ assetId: decoded.assetId,
56
+ blockHash: decoded.blockHash,
57
+ blockNumber: decoded.blockNumber,
58
+ era: decoded.era,
59
+ genesisHash: decoded.genesisHash,
60
+ metadataHash: decoded.metadataHash,
61
+ method: decoded.method,
62
+ mode: decoded.mode,
63
+ nonce: decoded.nonce,
64
+ specVersion: decoded.specVersion,
65
+ tip: decoded.tip,
66
+ transactionVersion: decoded.transactionVersion,
67
+ signedExtensions: decoded.signedExtensions,
68
+ version: decoded.version,
69
+ withSignedTransaction: decoded.withSignedTransaction,
70
+ };
71
+ },
72
+ to(value) {
73
+ return {
74
+ address: value.address,
75
+ assetId: value.assetId,
76
+ blockHash: value.blockHash,
77
+ blockNumber: value.blockNumber,
78
+ era: value.era,
79
+ genesisHash: value.genesisHash,
80
+ metadataHash: value.metadataHash,
81
+ method: value.method,
82
+ mode: value.mode,
83
+ nonce: value.nonce,
84
+ specVersion: value.specVersion,
85
+ tip: value.tip,
86
+ transactionVersion: value.transactionVersion,
87
+ signedExtensions: value.signedExtensions,
88
+ version: value.version,
89
+ withSignedTransaction: value.withSignedTransaction,
90
+ };
91
+ },
92
+ });
93
+ const signResult = Struct({
94
+ id: u32,
95
+ signature: hexEncoder,
96
+ signedTransaction: Option(Enum({
97
+ hex: hexEncoder,
98
+ buffer: Bytes(),
99
+ })),
100
+ });
101
+ export const signResponseV1Encoder = createTransportEncoder({
102
+ codec: signResult,
103
+ from(decoded) {
104
+ return {
105
+ id: decoded.id,
106
+ signature: decoded.signature,
107
+ signedTransaction: decoded.signedTransaction ? decoded.signedTransaction.value : undefined,
108
+ };
109
+ },
110
+ to(value) {
111
+ let signedTransaction = undefined;
112
+ if (value.signedTransaction) {
113
+ if (typeof value.signedTransaction === 'string') {
114
+ signedTransaction = {
115
+ tag: 'hex',
116
+ value: value.signedTransaction,
117
+ };
118
+ }
119
+ else {
120
+ signedTransaction = {
121
+ tag: 'buffer',
122
+ value: value.signedTransaction,
123
+ };
124
+ }
125
+ }
126
+ return {
127
+ id: value.id,
128
+ signature: value.signature,
129
+ signedTransaction: signedTransaction,
130
+ };
131
+ },
132
+ });
133
+ const createTransactionRequestCodec = Struct({
134
+ version: u16,
135
+ signer: createNullableEncoder(str),
136
+ callData: hexEncoder,
137
+ extensions: Vector(Struct({
138
+ id: str,
139
+ extra: hexEncoder,
140
+ additionalSigned: hexEncoder,
141
+ })),
142
+ txExtVersion: u16,
143
+ context: Struct({
144
+ metadata: hexEncoder,
145
+ tokenSymbol: str,
146
+ tokenDecimals: u32,
147
+ bestBlockHeight: u32,
148
+ }),
149
+ });
150
+ export const createTransactionRequestV1Encoder = createTransportEncoder({
151
+ codec: createTransactionRequestCodec,
152
+ from({ version, signer, ...rest }) {
153
+ if (version !== 1) {
154
+ throw new Error(`TxPayload supported version are: 1. Got ${version}`);
155
+ }
156
+ return {
157
+ version,
158
+ signer: signer.value ?? null,
159
+ ...rest,
160
+ };
161
+ },
162
+ to({ signer, ...rest }) {
163
+ return {
164
+ signer: typeof signer === 'string'
165
+ ? {
166
+ tag: 'value',
167
+ value: signer,
168
+ }
169
+ : {
170
+ tag: 'null',
171
+ value: undefined,
172
+ },
173
+ ...rest,
174
+ };
175
+ },
176
+ });
177
+ export const createTransactionResponseV1Encoder = hexEncoder;
@@ -0,0 +1,2 @@
1
+ import type { Logger } from './types.js';
2
+ export declare function createDefaultLogger(): Logger;
package/dist/logger.js ADDED
@@ -0,0 +1,8 @@
1
+ export function createDefaultLogger() {
2
+ return {
3
+ info: (...args) => console.info(...args),
4
+ error: (...args) => console.error(...args),
5
+ warn: (...args) => console.warn(...args),
6
+ log: (...args) => console.log(...args),
7
+ };
8
+ }
@@ -0,0 +1,217 @@
1
+ import type { CodecType } from 'scale-ts';
2
+ import { responseEncoder } from './commonEncoders.js';
3
+ export declare function unwrapResponseOrThrow<T>(response: CodecType<ReturnType<typeof responseEncoder<T>>>): T;
4
+ export type MessagePayloadSchema = CodecType<typeof messagePayloadEncoder>;
5
+ export declare const messagePayloadEncoder: import("scale-ts").Codec<{
6
+ tag: "handshakeRequestV1";
7
+ value: undefined;
8
+ } | {
9
+ tag: "handshakeResponseV1";
10
+ value: {
11
+ tag: "success";
12
+ value: undefined;
13
+ } | {
14
+ tag: "error";
15
+ value: string;
16
+ };
17
+ } | {
18
+ tag: "getAccountsRequestV1";
19
+ value: undefined;
20
+ } | {
21
+ tag: "getAccountsResponseV1";
22
+ value: {
23
+ tag: "success";
24
+ value: import("@polkadot-api/pjs-signer").InjectedAccount[];
25
+ } | {
26
+ tag: "error";
27
+ value: string;
28
+ };
29
+ } | {
30
+ tag: "accountSubscriptionV1";
31
+ value: undefined;
32
+ } | {
33
+ tag: "accountUnsubscriptionV1";
34
+ value: undefined;
35
+ } | {
36
+ tag: "supportFeatureRequestV1";
37
+ value: {
38
+ tag: "chain";
39
+ value: {
40
+ chainId: `0x${string}`;
41
+ };
42
+ };
43
+ } | {
44
+ tag: "supportFeatureResponseV1";
45
+ value: {
46
+ tag: "success";
47
+ value: {
48
+ tag: "chain";
49
+ value: {
50
+ chainId: `0x${string}`;
51
+ result: boolean;
52
+ };
53
+ };
54
+ } | {
55
+ tag: "error";
56
+ value: string;
57
+ };
58
+ } | {
59
+ tag: "papiProviderSendMessageV1";
60
+ value: {
61
+ chainId: string;
62
+ message: string;
63
+ };
64
+ } | {
65
+ tag: "papiProviderReceiveMessageV1";
66
+ value: {
67
+ tag: "success";
68
+ value: {
69
+ chainId: string;
70
+ message: string;
71
+ };
72
+ } | {
73
+ tag: "error";
74
+ value: string;
75
+ };
76
+ } | {
77
+ tag: "signRawRequestV1";
78
+ value: import("@polkadot/types/types").SignerPayloadRaw;
79
+ } | {
80
+ tag: "signPayloadRequestV1";
81
+ value: import("@polkadot/types/types").SignerPayloadJSON;
82
+ } | {
83
+ tag: "signResponseV1";
84
+ value: {
85
+ tag: "success";
86
+ value: import("@polkadot/types/types").SignerResult;
87
+ } | {
88
+ tag: "error";
89
+ value: string;
90
+ };
91
+ } | {
92
+ tag: "createTransactionRequestV1";
93
+ value: import("./interactions/sign.js").TxPayloadV1;
94
+ } | {
95
+ tag: "createTransactionResponseV1";
96
+ value: {
97
+ tag: "success";
98
+ value: `0x${string}`;
99
+ } | {
100
+ tag: "error";
101
+ value: string;
102
+ };
103
+ } | {
104
+ tag: "locationChangedV1";
105
+ value: string;
106
+ }>;
107
+ export type MessageSchema = CodecType<typeof messageEncoder>;
108
+ export declare const messageEncoder: import("scale-ts").Codec<{
109
+ id: string;
110
+ payload: {
111
+ tag: "handshakeRequestV1";
112
+ value: undefined;
113
+ } | {
114
+ tag: "handshakeResponseV1";
115
+ value: {
116
+ tag: "success";
117
+ value: undefined;
118
+ } | {
119
+ tag: "error";
120
+ value: string;
121
+ };
122
+ } | {
123
+ tag: "getAccountsRequestV1";
124
+ value: undefined;
125
+ } | {
126
+ tag: "getAccountsResponseV1";
127
+ value: {
128
+ tag: "success";
129
+ value: import("@polkadot-api/pjs-signer").InjectedAccount[];
130
+ } | {
131
+ tag: "error";
132
+ value: string;
133
+ };
134
+ } | {
135
+ tag: "accountSubscriptionV1";
136
+ value: undefined;
137
+ } | {
138
+ tag: "accountUnsubscriptionV1";
139
+ value: undefined;
140
+ } | {
141
+ tag: "supportFeatureRequestV1";
142
+ value: {
143
+ tag: "chain";
144
+ value: {
145
+ chainId: `0x${string}`;
146
+ };
147
+ };
148
+ } | {
149
+ tag: "supportFeatureResponseV1";
150
+ value: {
151
+ tag: "success";
152
+ value: {
153
+ tag: "chain";
154
+ value: {
155
+ chainId: `0x${string}`;
156
+ result: boolean;
157
+ };
158
+ };
159
+ } | {
160
+ tag: "error";
161
+ value: string;
162
+ };
163
+ } | {
164
+ tag: "papiProviderSendMessageV1";
165
+ value: {
166
+ chainId: string;
167
+ message: string;
168
+ };
169
+ } | {
170
+ tag: "papiProviderReceiveMessageV1";
171
+ value: {
172
+ tag: "success";
173
+ value: {
174
+ chainId: string;
175
+ message: string;
176
+ };
177
+ } | {
178
+ tag: "error";
179
+ value: string;
180
+ };
181
+ } | {
182
+ tag: "signRawRequestV1";
183
+ value: import("@polkadot/types/types").SignerPayloadRaw;
184
+ } | {
185
+ tag: "signPayloadRequestV1";
186
+ value: import("@polkadot/types/types").SignerPayloadJSON;
187
+ } | {
188
+ tag: "signResponseV1";
189
+ value: {
190
+ tag: "success";
191
+ value: import("@polkadot/types/types").SignerResult;
192
+ } | {
193
+ tag: "error";
194
+ value: string;
195
+ };
196
+ } | {
197
+ tag: "createTransactionRequestV1";
198
+ value: import("./interactions/sign.js").TxPayloadV1;
199
+ } | {
200
+ tag: "createTransactionResponseV1";
201
+ value: {
202
+ tag: "success";
203
+ value: `0x${string}`;
204
+ } | {
205
+ tag: "error";
206
+ value: string;
207
+ };
208
+ } | {
209
+ tag: "locationChangedV1";
210
+ value: string;
211
+ };
212
+ }>;
213
+ export type MessageType = MessagePayloadSchema['tag'];
214
+ export type PickMessagePayload<T extends MessageType> = Extract<MessagePayloadSchema, {
215
+ tag: T;
216
+ }>;
217
+ export type PickMessagePayloadValue<T extends MessageType> = PickMessagePayload<T>['value'];
@@ -0,0 +1,37 @@
1
+ import { Enum, Struct, str } from 'scale-ts';
2
+ import { responseEncoder } from './commonEncoders.js';
3
+ import { accountSubscriptionV1Encoder, accountUnsubscriptionV1Encoder, getAccountsRequestV1Encoder, getAccountsResponseV1Encoder, } from './interactions/accounts.js';
4
+ import { supportFeatureRequestV1Encoder, supportFeatureResponseV1 } from './interactions/features.js';
5
+ import { handshakeRequestV1Encoder, handshakeResponseV1Encoder } from './interactions/handshake.js';
6
+ import { papiProviderReceiveMessageV1Encoder, papiProviderSendMessageV1Encoder } from './interactions/papiProvider.js';
7
+ import { createTransactionRequestV1Encoder, createTransactionResponseV1Encoder, signPayloadRequestV1Encoder, signRawRequestV1Encoder, signResponseV1Encoder, } from './interactions/sign.js';
8
+ export function unwrapResponseOrThrow(response) {
9
+ if (response.tag === 'success') {
10
+ return response.value;
11
+ }
12
+ else {
13
+ throw new Error(response.value);
14
+ }
15
+ }
16
+ export const messagePayloadEncoder = Enum({
17
+ handshakeRequestV1: handshakeRequestV1Encoder,
18
+ handshakeResponseV1: responseEncoder(handshakeResponseV1Encoder),
19
+ getAccountsRequestV1: getAccountsRequestV1Encoder,
20
+ getAccountsResponseV1: responseEncoder(getAccountsResponseV1Encoder),
21
+ accountSubscriptionV1: accountSubscriptionV1Encoder,
22
+ accountUnsubscriptionV1: accountUnsubscriptionV1Encoder,
23
+ supportFeatureRequestV1: supportFeatureRequestV1Encoder,
24
+ supportFeatureResponseV1: responseEncoder(supportFeatureResponseV1),
25
+ papiProviderSendMessageV1: papiProviderSendMessageV1Encoder,
26
+ papiProviderReceiveMessageV1: responseEncoder(papiProviderReceiveMessageV1Encoder),
27
+ signRawRequestV1: signRawRequestV1Encoder,
28
+ signPayloadRequestV1: signPayloadRequestV1Encoder,
29
+ signResponseV1: responseEncoder(signResponseV1Encoder),
30
+ createTransactionRequestV1: createTransactionRequestV1Encoder,
31
+ createTransactionResponseV1: responseEncoder(createTransactionResponseV1Encoder),
32
+ locationChangedV1: str,
33
+ });
34
+ export const messageEncoder = Struct({
35
+ id: str,
36
+ payload: messagePayloadEncoder,
37
+ });
@@ -0,0 +1,23 @@
1
+ import type { MessagePayloadSchema, MessageType, PickMessagePayload, PickMessagePayloadValue } from './messageEncoder.js';
2
+ export type HexString = `0x${string}`;
3
+ export type Logger = Record<'info' | 'warn' | 'error' | 'log', (...args: unknown[]) => void>;
4
+ export type TransportProvider = {
5
+ logger: Logger;
6
+ isCorrectEnvironment(): boolean;
7
+ postMessage(message: Uint8Array): void;
8
+ subscribe(callback: (message: Uint8Array) => void): () => void;
9
+ dispose(): void;
10
+ };
11
+ export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected';
12
+ export type Transport = {
13
+ readonly provider: TransportProvider;
14
+ isCorrectEnvironment(): boolean;
15
+ isReady(): Promise<boolean>;
16
+ subscribeAny(callback: (id: string, payload: MessagePayloadSchema) => void): VoidFunction;
17
+ subscribe<const Type extends MessageType>(type: Type, callback: (id: string, payload: PickMessagePayloadValue<Type>) => void): VoidFunction;
18
+ postMessage(id: string, payload: MessagePayloadSchema): string;
19
+ request<Response extends MessageType>(payload: MessagePayloadSchema, response: Response, abortSignal?: AbortSignal): Promise<PickMessagePayloadValue<Response>>;
20
+ handleMessage<Request extends MessageType, Response extends MessageType>(type: Request, handler: (message: PickMessagePayloadValue<Request>) => Promise<PickMessagePayload<Response> | void>): VoidFunction;
21
+ onConnectionStatusChange(callback: (status: ConnectionStatus) => void): VoidFunction;
22
+ dispose(): void;
23
+ };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@novasamatech/host-api",
3
+ "type": "module",
4
+ "version": "0.4.0-0",
5
+ "description": "Host API: transport implementation for host - product integration.",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/novasamatech/spektr-sdk.git"
10
+ },
11
+ "main": "dist/index.js",
12
+ "exports": {
13
+ "./package.json": "./package.json",
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "dependencies": {
24
+ "@polkadot-api/utils": "0.2.0",
25
+ "nanoevents": "9.1.0",
26
+ "nanoid": "5.1.6",
27
+ "scale-ts": "1.6.1"
28
+ },
29
+ "peerDependencies": {
30
+ "@polkadot-api/pjs-signer": "^0.6.17"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ }
35
+ }