@novasamatech/statement-store 0.5.0-10
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 +11 -0
- package/dist/adapter/lazyClient.d.ts +7 -0
- package/dist/adapter/lazyClient.js +17 -0
- package/dist/adapter/rpc.d.ts +3 -0
- package/dist/adapter/rpc.js +93 -0
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +1 -0
- package/dist/crypto.d.ts +7 -0
- package/dist/crypto.js +16 -0
- package/dist/helpers.d.ts +2 -0
- package/dist/helpers.js +12 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +8 -0
- package/dist/model/session.d.ts +5 -0
- package/dist/model/session.js +18 -0
- package/dist/model/sessionAccount.d.ts +23 -0
- package/dist/model/sessionAccount.js +28 -0
- package/dist/session/encyption.d.ts +6 -0
- package/dist/session/encyption.js +24 -0
- package/dist/session/error.d.ts +9 -0
- package/dist/session/error.js +15 -0
- package/dist/session/messageMapper.d.ts +4 -0
- package/dist/session/messageMapper.js +20 -0
- package/dist/session/scale/statementData.d.ts +24 -0
- package/dist/session/scale/statementData.js +40 -0
- package/dist/session/session.d.ts +13 -0
- package/dist/session/session.js +144 -0
- package/dist/session/statementProver.d.ts +6 -0
- package/dist/session/statementProver.js +1 -0
- package/dist/session/types.d.ts +30 -0
- package/dist/session/types.js +1 -0
- package/dist/transport/impl.d.ts +32 -0
- package/dist/transport/impl.js +59 -0
- package/dist/transport/scale/opaque.d.ts +1 -0
- package/dist/transport/scale/opaque.js +1 -0
- package/dist/transport/scale/statementData.d.ts +24 -0
- package/dist/transport/scale/statementData.js +36 -0
- package/dist/transport/transport.d.ts +31 -0
- package/dist/transport/transport.js +56 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { JsonRpcProvider } from '@polkadot-api/json-rpc-provider';
|
|
2
|
+
import type { PolkadotClient } from 'polkadot-api';
|
|
3
|
+
export type LazyClient = ReturnType<typeof createLazyClient>;
|
|
4
|
+
export declare const createLazyClient: (provider: JsonRpcProvider) => {
|
|
5
|
+
getClient(): PolkadotClient;
|
|
6
|
+
disconnect(): void;
|
|
7
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createClient } from 'polkadot-api';
|
|
2
|
+
export const createLazyClient = (provider) => {
|
|
3
|
+
let client = null;
|
|
4
|
+
return {
|
|
5
|
+
getClient() {
|
|
6
|
+
if (!client) {
|
|
7
|
+
client = createClient(provider);
|
|
8
|
+
}
|
|
9
|
+
return client;
|
|
10
|
+
},
|
|
11
|
+
disconnect() {
|
|
12
|
+
if (client) {
|
|
13
|
+
client.destroy();
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createStatementSdk } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import { Binary } from '@polkadot-api/substrate-bindings';
|
|
3
|
+
import { toHex } from '@polkadot-api/utils';
|
|
4
|
+
import { fromPromise } from 'neverthrow';
|
|
5
|
+
import { toError } from '../helpers.js';
|
|
6
|
+
const POLLING_INTERVAL = 1500;
|
|
7
|
+
function createKey(topics) {
|
|
8
|
+
return topics.map(toHex).sort().join('');
|
|
9
|
+
}
|
|
10
|
+
export function createPapiStatementStoreAdapter(lazyClient) {
|
|
11
|
+
const sdk = createStatementSdk((method, params) => {
|
|
12
|
+
const client = lazyClient.getClient();
|
|
13
|
+
return client._request(method, params);
|
|
14
|
+
});
|
|
15
|
+
const pollings = new Map();
|
|
16
|
+
const subscriptions = new Map();
|
|
17
|
+
function addSubscription(key, subscription) {
|
|
18
|
+
let subs = subscriptions.get(key);
|
|
19
|
+
if (!subs) {
|
|
20
|
+
subs = [];
|
|
21
|
+
subscriptions.set(key, subs);
|
|
22
|
+
}
|
|
23
|
+
subs.push(subscription);
|
|
24
|
+
return subs;
|
|
25
|
+
}
|
|
26
|
+
function removeSubscription(key, subscription) {
|
|
27
|
+
let subs = subscriptions.get(key);
|
|
28
|
+
if (!subs) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
subs = subs.filter(x => x !== subscription);
|
|
32
|
+
return subs;
|
|
33
|
+
}
|
|
34
|
+
const transportProvider = {
|
|
35
|
+
queryStatements(topics, destination) {
|
|
36
|
+
return fromPromise(sdk.getStatements({
|
|
37
|
+
topics: topics.map(t => Binary.fromBytes(t)),
|
|
38
|
+
dest: destination ? Binary.fromBytes(destination) : null,
|
|
39
|
+
}), toError);
|
|
40
|
+
},
|
|
41
|
+
subscribeStatements(topics, callback) {
|
|
42
|
+
const key = createKey(topics);
|
|
43
|
+
const callbacks = addSubscription(key, callback);
|
|
44
|
+
if (callbacks.length === 1) {
|
|
45
|
+
const unsub = polling(POLLING_INTERVAL, () => transportProvider.queryStatements(topics), statements => {
|
|
46
|
+
const list = subscriptions.get(key);
|
|
47
|
+
if (list) {
|
|
48
|
+
for (const fn of list) {
|
|
49
|
+
fn(statements);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
pollings.set(key, unsub);
|
|
54
|
+
}
|
|
55
|
+
return () => {
|
|
56
|
+
const callbacks = removeSubscription(key, callback);
|
|
57
|
+
if (callbacks.length === 0) {
|
|
58
|
+
const stopPolling = pollings.get(key);
|
|
59
|
+
stopPolling?.();
|
|
60
|
+
pollings.delete(key);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
submitStatement(statement) {
|
|
65
|
+
return fromPromise(sdk.submit(statement), toError);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
return transportProvider;
|
|
69
|
+
}
|
|
70
|
+
function polling(interval, request, callback) {
|
|
71
|
+
let active = true;
|
|
72
|
+
let tm = null;
|
|
73
|
+
function createCycle() {
|
|
74
|
+
tm = setTimeout(() => {
|
|
75
|
+
if (!active) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
request().match(data => {
|
|
79
|
+
callback(data);
|
|
80
|
+
createCycle();
|
|
81
|
+
}, () => {
|
|
82
|
+
createCycle();
|
|
83
|
+
});
|
|
84
|
+
}, interval);
|
|
85
|
+
}
|
|
86
|
+
createCycle();
|
|
87
|
+
return () => {
|
|
88
|
+
active = false;
|
|
89
|
+
if (tm !== null) {
|
|
90
|
+
clearTimeout(tm);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SignedStatement, Statement } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import type { ResultAsync } from 'neverthrow';
|
|
3
|
+
export type StatementStoreAdapter = {
|
|
4
|
+
queryStatements(topics: Uint8Array[], destination?: Uint8Array): ResultAsync<Statement[], Error>;
|
|
5
|
+
subscribeStatements(topics: Uint8Array[], callback: (statements: Statement[]) => unknown): VoidFunction;
|
|
6
|
+
submitStatement(statement: SignedStatement): ResultAsync<void, Error>;
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Codec } from 'scale-ts';
|
|
2
|
+
export declare function BrandedBytesCodec<T extends Uint8Array>(length?: number): Codec<T>;
|
|
3
|
+
export declare function stringToBytes(str: string): Uint8Array<ArrayBuffer>;
|
|
4
|
+
/**
|
|
5
|
+
* blake2b_256 with key
|
|
6
|
+
*/
|
|
7
|
+
export declare function khash(secret: Uint8Array, message: Uint8Array): Uint8Array<ArrayBufferLike>;
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { blake2b } from '@noble/hashes/blake2.js';
|
|
2
|
+
import { Bytes } from 'scale-ts';
|
|
3
|
+
export function BrandedBytesCodec(length) {
|
|
4
|
+
return Bytes(length);
|
|
5
|
+
}
|
|
6
|
+
// helpers
|
|
7
|
+
const textEncoder = new TextEncoder();
|
|
8
|
+
export function stringToBytes(str) {
|
|
9
|
+
return textEncoder.encode(str);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* blake2b_256 with key
|
|
13
|
+
*/
|
|
14
|
+
export function khash(secret, message) {
|
|
15
|
+
return blake2b(message, { dkLen: 32, key: secret });
|
|
16
|
+
}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function toError(err) {
|
|
2
|
+
if (err instanceof Error) {
|
|
3
|
+
return err;
|
|
4
|
+
}
|
|
5
|
+
if (err) {
|
|
6
|
+
return new Error(err.toString());
|
|
7
|
+
}
|
|
8
|
+
return new Error('Unknown error occurred.');
|
|
9
|
+
}
|
|
10
|
+
export function nonNullable(value) {
|
|
11
|
+
return value !== null && value !== undefined;
|
|
12
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type { Statement } from '@polkadot-api/sdk-statement';
|
|
2
|
+
export type { SessionId } from './model/session.js';
|
|
3
|
+
export { SessionIdCodec, createSessionId } from './model/session.js';
|
|
4
|
+
export type { AccountId, LocalSessionAccount, RemoteSessionAccount, SessionAccount } from './model/sessionAccount.js';
|
|
5
|
+
export { AccountIdCodec, LocalSessionAccountCodec, RemoteSessionAccountCodec, createAccountId, createLocalSessionAccount, createRemoteSessionAccount, } from './model/sessionAccount.js';
|
|
6
|
+
export type { Session } from './session/types.js';
|
|
7
|
+
export { createSession } from './session/session.js';
|
|
8
|
+
export type { StatementProver } from './session/statementProver.js';
|
|
9
|
+
export type { Encryption } from './session/encyption.js';
|
|
10
|
+
export { createEncryption } from './session/encyption.js';
|
|
11
|
+
export { DecodingError, DecryptionError, UnknownError } from './session/error.js';
|
|
12
|
+
export type { LazyClient } from './adapter/lazyClient.js';
|
|
13
|
+
export { createLazyClient } from './adapter/lazyClient.js';
|
|
14
|
+
export type { StatementStoreAdapter } from './adapter/types.js';
|
|
15
|
+
export { createPapiStatementStoreAdapter } from './adapter/rpc.js';
|
|
16
|
+
export { khash } from './crypto.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { SessionIdCodec, createSessionId } from './model/session.js';
|
|
2
|
+
export { AccountIdCodec, LocalSessionAccountCodec, RemoteSessionAccountCodec, createAccountId, createLocalSessionAccount, createRemoteSessionAccount, } from './model/sessionAccount.js';
|
|
3
|
+
export { createSession } from './session/session.js';
|
|
4
|
+
export { createEncryption } from './session/encyption.js';
|
|
5
|
+
export { DecodingError, DecryptionError, UnknownError } from './session/error.js';
|
|
6
|
+
export { createLazyClient } from './adapter/lazyClient.js';
|
|
7
|
+
export { createPapiStatementStoreAdapter } from './adapter/rpc.js';
|
|
8
|
+
export { khash } from './crypto.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Branded } from '../types.js';
|
|
2
|
+
import type { SessionAccount } from './sessionAccount.js';
|
|
3
|
+
export type SessionId = Branded<Uint8Array, 'SessionId'>;
|
|
4
|
+
export declare const SessionIdCodec: import("scale-ts").Codec<Uint8Array<ArrayBufferLike>>;
|
|
5
|
+
export declare function createSessionId(sharedSecret: Uint8Array, accountA: SessionAccount, accountB: SessionAccount): SessionId;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { mergeUint8 } from '@polkadot-api/utils';
|
|
2
|
+
import { Bytes } from 'scale-ts';
|
|
3
|
+
import { khash, stringToBytes } from '../crypto.js';
|
|
4
|
+
export const SessionIdCodec = Bytes(32);
|
|
5
|
+
export function createSessionId(sharedSecret, accountA, accountB) {
|
|
6
|
+
const sessionPrefix = stringToBytes('session');
|
|
7
|
+
const pinSeparator = stringToBytes('/');
|
|
8
|
+
function makePin(pin) {
|
|
9
|
+
return pin ? mergeUint8([pinSeparator, stringToBytes(pin)]) : pinSeparator;
|
|
10
|
+
}
|
|
11
|
+
const accountSessionParams = mergeUint8([
|
|
12
|
+
accountA.accountId,
|
|
13
|
+
accountB.accountId,
|
|
14
|
+
makePin(accountA.pin),
|
|
15
|
+
makePin(accountB.pin),
|
|
16
|
+
]);
|
|
17
|
+
return khash(sharedSecret, mergeUint8([sessionPrefix, accountSessionParams]));
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Branded } from '../types.js';
|
|
2
|
+
export type AccountId = Branded<Uint8Array, 'AccountId'>;
|
|
3
|
+
export declare const AccountIdCodec: import("scale-ts").Codec<AccountId>;
|
|
4
|
+
export declare function createAccountId(value: Uint8Array): AccountId;
|
|
5
|
+
export type SessionAccount = {
|
|
6
|
+
accountId: AccountId;
|
|
7
|
+
pin: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
export type LocalSessionAccount = SessionAccount;
|
|
10
|
+
export declare const LocalSessionAccountCodec: import("scale-ts").Codec<{
|
|
11
|
+
accountId: AccountId;
|
|
12
|
+
pin: string | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function createLocalSessionAccount(accountId: AccountId, pin?: string): LocalSessionAccount;
|
|
15
|
+
export type RemoteSessionAccount = SessionAccount & {
|
|
16
|
+
publicKey: Uint8Array;
|
|
17
|
+
};
|
|
18
|
+
export declare const RemoteSessionAccountCodec: import("scale-ts").Codec<{
|
|
19
|
+
accountId: AccountId;
|
|
20
|
+
publicKey: Uint8Array<ArrayBufferLike>;
|
|
21
|
+
pin: string | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function createRemoteSessionAccount(accountId: AccountId, publicKey: Uint8Array, pin?: string): RemoteSessionAccount;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Bytes, Option, Struct, str } from 'scale-ts';
|
|
2
|
+
import { BrandedBytesCodec } from '../crypto.js';
|
|
3
|
+
export const AccountIdCodec = BrandedBytesCodec(32);
|
|
4
|
+
export function createAccountId(value) {
|
|
5
|
+
return value.slice(0, 32);
|
|
6
|
+
}
|
|
7
|
+
export const LocalSessionAccountCodec = Struct({
|
|
8
|
+
accountId: AccountIdCodec,
|
|
9
|
+
pin: Option(str),
|
|
10
|
+
});
|
|
11
|
+
export function createLocalSessionAccount(accountId, pin) {
|
|
12
|
+
return {
|
|
13
|
+
accountId,
|
|
14
|
+
pin,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export const RemoteSessionAccountCodec = Struct({
|
|
18
|
+
accountId: AccountIdCodec,
|
|
19
|
+
publicKey: Bytes(32),
|
|
20
|
+
pin: Option(str),
|
|
21
|
+
});
|
|
22
|
+
export function createRemoteSessionAccount(accountId, publicKey, pin) {
|
|
23
|
+
return {
|
|
24
|
+
accountId,
|
|
25
|
+
publicKey,
|
|
26
|
+
pin,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Result } from 'neverthrow';
|
|
2
|
+
export type Encryption = {
|
|
3
|
+
encrypt(cipherText: Uint8Array): Result<Uint8Array, Error>;
|
|
4
|
+
decrypt(encryptedMessage: Uint8Array): Result<Uint8Array, Error>;
|
|
5
|
+
};
|
|
6
|
+
export declare function createEncryption(sharedSecret: Uint8Array): Encryption;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { gcm } from '@noble/ciphers/aes.js';
|
|
2
|
+
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
3
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
4
|
+
import { randomBytes } from '@noble/hashes/utils.js';
|
|
5
|
+
import { mergeUint8 } from '@polkadot-api/utils';
|
|
6
|
+
import { Result, fromThrowable } from 'neverthrow';
|
|
7
|
+
export function createEncryption(sharedSecret) {
|
|
8
|
+
const salt = new Uint8Array(); // secure enough since P256 random keys provide enough entropy
|
|
9
|
+
const info = new Uint8Array(); // no need to introduce any context
|
|
10
|
+
const aesKey = hkdf(sha256, sharedSecret, salt, info, 32);
|
|
11
|
+
return {
|
|
12
|
+
encrypt: fromThrowable(cipherText => {
|
|
13
|
+
const nonce = randomBytes(12);
|
|
14
|
+
const aes = gcm(aesKey, nonce);
|
|
15
|
+
return mergeUint8([nonce, aes.encrypt(cipherText)]);
|
|
16
|
+
}),
|
|
17
|
+
decrypt: fromThrowable(encryptedMessage => {
|
|
18
|
+
const nonce = encryptedMessage.slice(0, 12);
|
|
19
|
+
const cipherText = encryptedMessage.slice(12);
|
|
20
|
+
const aes = gcm(aesKey, nonce);
|
|
21
|
+
return aes.decrypt(cipherText);
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class DecryptionError extends Error {
|
|
2
|
+
constructor() {
|
|
3
|
+
super('Decryption error: failed to decrypt the request');
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
export class DecodingError extends Error {
|
|
7
|
+
constructor() {
|
|
8
|
+
super('Decoding error: failed to decode the request');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class UnknownError extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super('Unknown error during request.');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function toMessage(statementData) {
|
|
2
|
+
switch (statementData.tag) {
|
|
3
|
+
case 'request':
|
|
4
|
+
return statementData.value.data.map((payload, index) => ({
|
|
5
|
+
type: 'request',
|
|
6
|
+
localId: `${statementData.value.requestId}-${index.toString()}`,
|
|
7
|
+
requestId: statementData.value.requestId,
|
|
8
|
+
payload,
|
|
9
|
+
}));
|
|
10
|
+
case 'response':
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
type: 'response',
|
|
14
|
+
localId: statementData.value.requestId,
|
|
15
|
+
requestId: statementData.value.requestId,
|
|
16
|
+
responseCode: statementData.value.responseCode,
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Codec } from 'scale-ts';
|
|
2
|
+
export type ResponseCode = 'success' | 'decryptionFailed' | 'decodingFailed' | 'unknown';
|
|
3
|
+
export declare const ResponseCodeCodec: Codec<ResponseCode>;
|
|
4
|
+
export declare const Request: <T>(data: Codec<T>) => Codec<{
|
|
5
|
+
requestId: string;
|
|
6
|
+
data: T[];
|
|
7
|
+
}>;
|
|
8
|
+
export declare const Response: Codec<{
|
|
9
|
+
requestId: string;
|
|
10
|
+
responseCode: ResponseCode;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const StatementData: <T>(data: Codec<T>) => Codec<{
|
|
13
|
+
tag: "request";
|
|
14
|
+
value: {
|
|
15
|
+
requestId: string;
|
|
16
|
+
data: T[];
|
|
17
|
+
};
|
|
18
|
+
} | {
|
|
19
|
+
tag: "response";
|
|
20
|
+
value: {
|
|
21
|
+
requestId: string;
|
|
22
|
+
responseCode: ResponseCode;
|
|
23
|
+
};
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Enum, Struct, Vector, enhanceCodec, str, u8 } from 'scale-ts';
|
|
2
|
+
export const ResponseCodeCodec = enhanceCodec(u8, error => {
|
|
3
|
+
switch (error) {
|
|
4
|
+
case 'success':
|
|
5
|
+
return 0;
|
|
6
|
+
case 'decryptionFailed':
|
|
7
|
+
return 1;
|
|
8
|
+
case 'decodingFailed':
|
|
9
|
+
return 2;
|
|
10
|
+
case 'unknown':
|
|
11
|
+
return 255;
|
|
12
|
+
}
|
|
13
|
+
}, code => {
|
|
14
|
+
switch (code) {
|
|
15
|
+
case 0:
|
|
16
|
+
return 'success';
|
|
17
|
+
case 1:
|
|
18
|
+
return 'decryptionFailed';
|
|
19
|
+
case 2:
|
|
20
|
+
return 'decodingFailed';
|
|
21
|
+
default:
|
|
22
|
+
return 'unknown';
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
export const Request = (data) => {
|
|
26
|
+
return Struct({
|
|
27
|
+
requestId: str,
|
|
28
|
+
data: Vector(data),
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
export const Response = Struct({
|
|
32
|
+
requestId: str,
|
|
33
|
+
responseCode: ResponseCodeCodec,
|
|
34
|
+
});
|
|
35
|
+
export const StatementData = (data) => {
|
|
36
|
+
return Enum({
|
|
37
|
+
request: Request(data),
|
|
38
|
+
response: Response,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StatementStoreAdapter } from '../adapter/types.js';
|
|
2
|
+
import type { LocalSessionAccount, RemoteSessionAccount } from '../model/sessionAccount.js';
|
|
3
|
+
import type { Encryption } from './encyption.js';
|
|
4
|
+
import type { StatementProver } from './statementProver.js';
|
|
5
|
+
import type { Session } from './types.js';
|
|
6
|
+
export type SessionParams = {
|
|
7
|
+
localAccount: LocalSessionAccount;
|
|
8
|
+
remoteAccount: RemoteSessionAccount;
|
|
9
|
+
statementStore: StatementStoreAdapter;
|
|
10
|
+
encryption: Encryption;
|
|
11
|
+
prover: StatementProver;
|
|
12
|
+
};
|
|
13
|
+
export declare function createSession({ localAccount, remoteAccount, statementStore, encryption, prover, }: SessionParams): Session;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Binary } from '@polkadot-api/substrate-bindings';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { ResultAsync, err, fromPromise, fromThrowable, ok, okAsync } from 'neverthrow';
|
|
4
|
+
import { Bytes } from 'scale-ts';
|
|
5
|
+
import { khash, stringToBytes } from '../crypto.js';
|
|
6
|
+
import { nonNullable, toError } from '../helpers.js';
|
|
7
|
+
import { createSessionId } from '../model/session.js';
|
|
8
|
+
import { DecodingError, DecryptionError, UnknownError } from './error.js';
|
|
9
|
+
import { toMessage } from './messageMapper.js';
|
|
10
|
+
import { StatementData } from './scale/statementData.js';
|
|
11
|
+
export function createSession({ localAccount, remoteAccount, statementStore, encryption, prover, }) {
|
|
12
|
+
let subscriptions = [];
|
|
13
|
+
function submit(sessionId, channel, data) {
|
|
14
|
+
return encryption
|
|
15
|
+
.encrypt(data)
|
|
16
|
+
.map(data => ({
|
|
17
|
+
priority: getPriority(now()),
|
|
18
|
+
channel: Binary.fromBytes(channel),
|
|
19
|
+
topics: [Binary.fromBytes(sessionId)],
|
|
20
|
+
data: Binary.fromBytes(data),
|
|
21
|
+
}))
|
|
22
|
+
.asyncAndThen(prover.generateMessageProof)
|
|
23
|
+
.andThen(statementStore.submitStatement);
|
|
24
|
+
}
|
|
25
|
+
const session = {
|
|
26
|
+
request(codec, data) {
|
|
27
|
+
return session.submitRequestMessage(codec, data).andThen(({ requestId }) => {
|
|
28
|
+
return session.waitForResponseMessage(requestId).andThen(({ responseCode }) => mapResponseCode(responseCode));
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
submitRequestMessage(codec, message) {
|
|
32
|
+
const requestId = nanoid();
|
|
33
|
+
const sessionId = createSessionId(remoteAccount.publicKey, localAccount, remoteAccount);
|
|
34
|
+
const statementDataCodec = StatementData(codec);
|
|
35
|
+
const encode = fromThrowable(statementDataCodec.enc, toError);
|
|
36
|
+
const rawData = encode({
|
|
37
|
+
tag: 'request',
|
|
38
|
+
value: { requestId, data: [message] },
|
|
39
|
+
});
|
|
40
|
+
return rawData
|
|
41
|
+
.asyncAndThen(data => submit(sessionId, createRequestChannel(sessionId), data))
|
|
42
|
+
.map(() => ({ requestId }));
|
|
43
|
+
},
|
|
44
|
+
submitResponseMessage(requestId, responseCode) {
|
|
45
|
+
const sessionId = createSessionId(remoteAccount.publicKey, localAccount, remoteAccount);
|
|
46
|
+
const statementDataCodec = StatementData(Bytes());
|
|
47
|
+
const encode = fromThrowable(statementDataCodec.enc, toError);
|
|
48
|
+
const rawData = encode({
|
|
49
|
+
tag: 'response',
|
|
50
|
+
value: { requestId, responseCode },
|
|
51
|
+
});
|
|
52
|
+
return rawData.asyncAndThen(data => submit(sessionId, createResponseChannel(sessionId), data));
|
|
53
|
+
},
|
|
54
|
+
waitForRequestMessage(codec, filter) {
|
|
55
|
+
const promise = new Promise(resolve => {
|
|
56
|
+
const unsubscribe = session.subscribe(codec, messages => {
|
|
57
|
+
for (const message of messages) {
|
|
58
|
+
if (message.type === 'request' && filter(message.payload)) {
|
|
59
|
+
unsubscribe();
|
|
60
|
+
resolve({
|
|
61
|
+
type: 'request',
|
|
62
|
+
localId: message.localId,
|
|
63
|
+
requestId: message.requestId,
|
|
64
|
+
payload: message.payload,
|
|
65
|
+
});
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
return fromPromise(promise, toError);
|
|
72
|
+
},
|
|
73
|
+
waitForResponseMessage(requestId) {
|
|
74
|
+
const promise = new Promise(resolve => {
|
|
75
|
+
const unsub = session.subscribe(Bytes(), messages => {
|
|
76
|
+
const response = messages.filter(m => m.type === 'response').find(m => m.requestId === requestId);
|
|
77
|
+
if (response) {
|
|
78
|
+
unsub();
|
|
79
|
+
resolve(response);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return fromPromise(promise, toError);
|
|
84
|
+
},
|
|
85
|
+
subscribe(codec, callback) {
|
|
86
|
+
const statementDataCodec = StatementData(codec);
|
|
87
|
+
const sessionId = createSessionId(remoteAccount.publicKey, remoteAccount, localAccount);
|
|
88
|
+
function processStatement(statement) {
|
|
89
|
+
if (!statement.data)
|
|
90
|
+
return okAsync(null);
|
|
91
|
+
const data = statement.data.asBytes();
|
|
92
|
+
return prover
|
|
93
|
+
.verifyMessageProof(statement)
|
|
94
|
+
.andThen(verified => (verified ? ok() : err(new Error('Statement proof is not valid'))))
|
|
95
|
+
.andThen(() => encryption.decrypt(data))
|
|
96
|
+
.map(statementDataCodec.dec)
|
|
97
|
+
.orElse(() => ok(null));
|
|
98
|
+
}
|
|
99
|
+
return statementStore.subscribeStatements([sessionId], statements => {
|
|
100
|
+
ResultAsync.combine(statements.map(processStatement))
|
|
101
|
+
.map(messages => messages.filter(nonNullable).flatMap(toMessage))
|
|
102
|
+
.andTee(messages => {
|
|
103
|
+
if (messages.length > 0) {
|
|
104
|
+
callback(messages);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
dispose() {
|
|
110
|
+
for (const unsub of subscriptions) {
|
|
111
|
+
unsub();
|
|
112
|
+
}
|
|
113
|
+
subscriptions = [];
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
return session;
|
|
117
|
+
}
|
|
118
|
+
function mapResponseCode(responseCode) {
|
|
119
|
+
switch (responseCode) {
|
|
120
|
+
case 'success':
|
|
121
|
+
return ok();
|
|
122
|
+
case 'decodingFailed':
|
|
123
|
+
return err(new DecodingError());
|
|
124
|
+
case 'decryptionFailed':
|
|
125
|
+
return err(new DecryptionError());
|
|
126
|
+
case 'unknown':
|
|
127
|
+
return err(new UnknownError());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function now() {
|
|
131
|
+
const d1 = new Date();
|
|
132
|
+
const d2 = new Date(d1.getUTCFullYear(), d1.getUTCMonth(), d1.getUTCDate(), d1.getUTCHours(), d1.getUTCMinutes(), d1.getUTCSeconds());
|
|
133
|
+
return d2.getTime();
|
|
134
|
+
}
|
|
135
|
+
function getPriority(timestamp) {
|
|
136
|
+
// time - (November 15, 2025)
|
|
137
|
+
return Math.floor((timestamp - 1763154000000) / 1000);
|
|
138
|
+
}
|
|
139
|
+
function createRequestChannel(sessionId) {
|
|
140
|
+
return khash(sessionId, stringToBytes('request'));
|
|
141
|
+
}
|
|
142
|
+
function createResponseChannel(sessionId) {
|
|
143
|
+
return khash(sessionId, stringToBytes('response'));
|
|
144
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SignedStatement, Statement } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import type { ResultAsync } from 'neverthrow';
|
|
3
|
+
export type StatementProver = {
|
|
4
|
+
generateMessageProof(statement: Statement): ResultAsync<SignedStatement, Error>;
|
|
5
|
+
verifyMessageProof(statement: Statement): ResultAsync<boolean, Error>;
|
|
6
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ResultAsync } from 'neverthrow';
|
|
2
|
+
import type { Codec } from 'scale-ts';
|
|
3
|
+
import type { Callback } from '../types.js';
|
|
4
|
+
import type { DecodingError } from './error.js';
|
|
5
|
+
import { DecryptionError, UnknownError } from './error.js';
|
|
6
|
+
import type { ResponseCode } from './scale/statementData.js';
|
|
7
|
+
export type RequestMessage<T> = {
|
|
8
|
+
type: 'request';
|
|
9
|
+
localId: string;
|
|
10
|
+
requestId: string;
|
|
11
|
+
payload: T;
|
|
12
|
+
};
|
|
13
|
+
export type ResponseMessage = {
|
|
14
|
+
type: 'response';
|
|
15
|
+
localId: string;
|
|
16
|
+
requestId: string;
|
|
17
|
+
responseCode: ResponseCode;
|
|
18
|
+
};
|
|
19
|
+
export type Message<T> = RequestMessage<T> | ResponseMessage;
|
|
20
|
+
export type Session = {
|
|
21
|
+
request<T>(codec: Codec<T>, payload: T): ResultAsync<void, DecodingError | DecryptionError | UnknownError | Error>;
|
|
22
|
+
submitRequestMessage<T>(codec: Codec<T>, payload: T): ResultAsync<{
|
|
23
|
+
requestId: string;
|
|
24
|
+
}, Error>;
|
|
25
|
+
submitResponseMessage(requestId: string, responseCode: ResponseCode): ResultAsync<void, Error>;
|
|
26
|
+
waitForRequestMessage<T>(codec: Codec<T>, filter: (message: T) => boolean): ResultAsync<RequestMessage<T>, Error>;
|
|
27
|
+
waitForResponseMessage(requestId: string): ResultAsync<ResponseMessage, Error>;
|
|
28
|
+
subscribe<T>(codec: Codec<T>, callback: Callback<Message<T>[]>): VoidFunction;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { DecryptionError, UnknownError } from './error.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SignedStatement, Statement } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import type { ResultAsync } from 'neverthrow';
|
|
3
|
+
import type { Codec } from 'scale-ts';
|
|
4
|
+
import type { StatementAdapter } from '../adapter/types.js';
|
|
5
|
+
import type { SessionId } from '../model/session.js';
|
|
6
|
+
import type { Callback } from '../types.js';
|
|
7
|
+
import type { TransportError } from './scale/statementData.js';
|
|
8
|
+
export type Transport = ReturnType<typeof createTransport>;
|
|
9
|
+
type RequestMessage<T> = {
|
|
10
|
+
type: 'request';
|
|
11
|
+
requestId: string;
|
|
12
|
+
data: T;
|
|
13
|
+
};
|
|
14
|
+
type ResponseMessage = {
|
|
15
|
+
type: 'response';
|
|
16
|
+
requestId: string;
|
|
17
|
+
code: TransportError;
|
|
18
|
+
};
|
|
19
|
+
type Message<T> = RequestMessage<T> | ResponseMessage;
|
|
20
|
+
type Params = {
|
|
21
|
+
adapter: StatementAdapter;
|
|
22
|
+
};
|
|
23
|
+
export declare function createTransport({ adapter }: Params): {
|
|
24
|
+
subscribeStatements(topic: Uint8Array, callback: Callback<Statement[]>): VoidFunction;
|
|
25
|
+
subscribe<T>({ sessionId, sharedSecret, codec, }: {
|
|
26
|
+
sessionId: SessionId;
|
|
27
|
+
sharedSecret: Uint8Array;
|
|
28
|
+
codec: Codec<T>;
|
|
29
|
+
}, callback: Callback<Message<T>[]>): VoidFunction;
|
|
30
|
+
submitRequest(statement: SignedStatement): ResultAsync<void, Error>;
|
|
31
|
+
};
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Result, fromThrowable, ok } from 'neverthrow';
|
|
2
|
+
import { decrypt } from '../crypto.js';
|
|
3
|
+
import { nonNullable, toError } from '../helpers.js';
|
|
4
|
+
import { StatementData } from './scale/statementData.js';
|
|
5
|
+
const decryptResults = fromThrowable(decrypt, toError);
|
|
6
|
+
function mapMessage(statementData) {
|
|
7
|
+
switch (statementData.tag) {
|
|
8
|
+
case 'request':
|
|
9
|
+
return statementData.value.data.map((data, index) => ({
|
|
10
|
+
type: 'request',
|
|
11
|
+
requestId: `${statementData.value.requestId}-${index.toString()}`,
|
|
12
|
+
data,
|
|
13
|
+
}));
|
|
14
|
+
case 'response':
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
type: 'response',
|
|
18
|
+
requestId: statementData.value.requestId,
|
|
19
|
+
code: statementData.value.responseCode,
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// function createRequestChannel(session: Uint8Array) {
|
|
25
|
+
// return khash(session, stringToBytes('request'));
|
|
26
|
+
// }
|
|
27
|
+
//
|
|
28
|
+
// export function createResponseChannel(session: Uint8Array) {
|
|
29
|
+
// return khash(session, stringToBytes('response'));
|
|
30
|
+
// }
|
|
31
|
+
export function createTransport({ adapter }) {
|
|
32
|
+
const transport = {
|
|
33
|
+
subscribeStatements(topic, callback) {
|
|
34
|
+
return adapter.subscribeStatements([topic], callback);
|
|
35
|
+
},
|
|
36
|
+
subscribe({ sessionId, sharedSecret, codec, }, callback) {
|
|
37
|
+
const statementDataCodec = StatementData(codec);
|
|
38
|
+
return adapter.subscribeStatements([sessionId], statements => {
|
|
39
|
+
Result.combine(statements.map(statement => {
|
|
40
|
+
if (!statement.data)
|
|
41
|
+
return ok(null);
|
|
42
|
+
return decryptResults(sharedSecret, statement.data.asBytes())
|
|
43
|
+
.map(statementDataCodec.dec)
|
|
44
|
+
.orElse(() => ok(null));
|
|
45
|
+
}))
|
|
46
|
+
.map(messages => messages.filter(nonNullable).flatMap(mapMessage))
|
|
47
|
+
.andTee(messages => {
|
|
48
|
+
if (messages.length > 0) {
|
|
49
|
+
callback(messages);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
submitRequest(statement) {
|
|
55
|
+
return adapter.submitStatement(statement);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
return transport;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Codec } from 'scale-ts';
|
|
2
|
+
export type TransportError = 'decryptionFailed' | 'decodingFailed' | 'unknown';
|
|
3
|
+
export declare const TransportErrorCodec: Codec<TransportError>;
|
|
4
|
+
export declare const Request: <T>(data: Codec<T>) => Codec<{
|
|
5
|
+
requestId: string;
|
|
6
|
+
data: T[];
|
|
7
|
+
}>;
|
|
8
|
+
export declare const Response: Codec<{
|
|
9
|
+
requestId: string;
|
|
10
|
+
responseCode: TransportError;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const StatementData: <T>(data: Codec<T>) => Codec<{
|
|
13
|
+
tag: "request";
|
|
14
|
+
value: {
|
|
15
|
+
requestId: string;
|
|
16
|
+
data: T[];
|
|
17
|
+
};
|
|
18
|
+
} | {
|
|
19
|
+
tag: "response";
|
|
20
|
+
value: {
|
|
21
|
+
requestId: string;
|
|
22
|
+
responseCode: TransportError;
|
|
23
|
+
};
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Enum, Struct, Vector, enhanceCodec, str, u8 } from 'scale-ts';
|
|
2
|
+
export const TransportErrorCodec = enhanceCodec(u8, error => {
|
|
3
|
+
switch (error) {
|
|
4
|
+
case 'decryptionFailed':
|
|
5
|
+
return 1;
|
|
6
|
+
case 'decodingFailed':
|
|
7
|
+
return 2;
|
|
8
|
+
case 'unknown':
|
|
9
|
+
return 255;
|
|
10
|
+
}
|
|
11
|
+
}, code => {
|
|
12
|
+
switch (code) {
|
|
13
|
+
case 1:
|
|
14
|
+
return 'decryptionFailed';
|
|
15
|
+
case 2:
|
|
16
|
+
return 'decodingFailed';
|
|
17
|
+
default:
|
|
18
|
+
return 'unknown';
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
export const Request = (data) => {
|
|
22
|
+
return Struct({
|
|
23
|
+
requestId: str,
|
|
24
|
+
data: Vector(data),
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
export const Response = Struct({
|
|
28
|
+
requestId: str,
|
|
29
|
+
responseCode: TransportErrorCodec,
|
|
30
|
+
});
|
|
31
|
+
export const StatementData = (data) => {
|
|
32
|
+
return Enum({
|
|
33
|
+
request: Request(data),
|
|
34
|
+
response: Response,
|
|
35
|
+
});
|
|
36
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SignedStatement } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import type { ResultAsync } from 'neverthrow';
|
|
3
|
+
import type { Codec } from 'scale-ts';
|
|
4
|
+
import type { StatementAdapter } from '../adapter/types.js';
|
|
5
|
+
import type { SessionId } from '../model/session.js';
|
|
6
|
+
import type { Callback } from '../types.js';
|
|
7
|
+
import type { TransportError } from './scale/statementData.js';
|
|
8
|
+
export type Transport = ReturnType<typeof createTransport>;
|
|
9
|
+
type RequestMessage<T> = {
|
|
10
|
+
type: 'request';
|
|
11
|
+
requestId: string;
|
|
12
|
+
data: T;
|
|
13
|
+
};
|
|
14
|
+
type ResponseMessage = {
|
|
15
|
+
type: 'response';
|
|
16
|
+
requestId: string;
|
|
17
|
+
code: TransportError;
|
|
18
|
+
};
|
|
19
|
+
type Message<T> = RequestMessage<T> | ResponseMessage;
|
|
20
|
+
type Params = {
|
|
21
|
+
adapter: StatementAdapter;
|
|
22
|
+
};
|
|
23
|
+
export declare function createTransport({ adapter }: Params): {
|
|
24
|
+
subscribe<T>({ sessionId, sharedSecret, codec, }: {
|
|
25
|
+
sessionId: SessionId;
|
|
26
|
+
sharedSecret: Uint8Array;
|
|
27
|
+
codec: Codec<T>;
|
|
28
|
+
}, callback: Callback<Message<T>[]>): VoidFunction;
|
|
29
|
+
submitRequest(statement: SignedStatement): ResultAsync<void, Error>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Result, fromThrowable, ok } from 'neverthrow';
|
|
2
|
+
import { decrypt } from '../crypto.js';
|
|
3
|
+
import { nonNullable, toError } from '../helpers.js';
|
|
4
|
+
import { StatementData } from './scale/statementData.js';
|
|
5
|
+
const decryptResults = fromThrowable(decrypt, toError);
|
|
6
|
+
function mapMessage(statementData) {
|
|
7
|
+
switch (statementData.tag) {
|
|
8
|
+
case 'request':
|
|
9
|
+
return statementData.value.data.map((data, index) => ({
|
|
10
|
+
type: 'request',
|
|
11
|
+
requestId: `${statementData.value.requestId}-${index.toString()}`,
|
|
12
|
+
data,
|
|
13
|
+
}));
|
|
14
|
+
case 'response':
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
type: 'response',
|
|
18
|
+
requestId: statementData.value.requestId,
|
|
19
|
+
code: statementData.value.responseCode,
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// function createRequestChannel(session: Uint8Array) {
|
|
25
|
+
// return khash(session, stringToBytes('request'));
|
|
26
|
+
// }
|
|
27
|
+
//
|
|
28
|
+
// export function createResponseChannel(session: Uint8Array) {
|
|
29
|
+
// return khash(session, stringToBytes('response'));
|
|
30
|
+
// }
|
|
31
|
+
export function createTransport({ adapter }) {
|
|
32
|
+
const transport = {
|
|
33
|
+
subscribe({ sessionId, sharedSecret, codec, }, callback) {
|
|
34
|
+
const statementDataCodec = StatementData(codec);
|
|
35
|
+
return adapter.subscribeStatements([sessionId], statements => {
|
|
36
|
+
Result.combine(statements.map(statement => {
|
|
37
|
+
if (!statement.data)
|
|
38
|
+
return ok(null);
|
|
39
|
+
return decryptResults(sharedSecret, statement.data.asBytes())
|
|
40
|
+
.map(statementDataCodec.dec)
|
|
41
|
+
.orElse(() => ok(null));
|
|
42
|
+
}))
|
|
43
|
+
.map(messages => messages.filter(nonNullable).flatMap(mapMessage))
|
|
44
|
+
.andTee(messages => {
|
|
45
|
+
if (messages.length > 0) {
|
|
46
|
+
callback(messages);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
submitRequest(statement) {
|
|
52
|
+
return adapter.submitStatement(statement);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
return transport;
|
|
56
|
+
}
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@novasamatech/statement-store",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.5.0-10",
|
|
5
|
+
"description": "Statement store integration",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/novasamatech/spektr-sdk.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"polkadot"
|
|
13
|
+
],
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
"./package.json": "./package.json",
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@polkadot-api/sdk-statement": "^0.2.0",
|
|
28
|
+
"@polkadot-api/substrate-bindings": "^0.16.5",
|
|
29
|
+
"@noble/hashes": "2.0.1",
|
|
30
|
+
"@noble/ciphers": "2.1.1",
|
|
31
|
+
"polkadot-api": "^1.23.1",
|
|
32
|
+
"neverthrow": "^8.2.0",
|
|
33
|
+
"scale-ts": "^1.6.1"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
}
|
|
38
|
+
}
|