@novasamatech/statement-store 0.5.0-17 → 0.5.0-18

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.
@@ -0,0 +1,6 @@
1
+ import type { Branded } from '../types.js';
2
+ import type { SessionId } from './session.js';
3
+ export type Channel = Branded<Uint8Array, 'Channel'>;
4
+ export declare const ChannelCodec: import("scale-ts").Codec<Uint8Array<ArrayBufferLike>>;
5
+ export declare function createRequestChannel(sessionId: SessionId): Channel;
6
+ export declare function createResponseChannel(sessionId: SessionId): Channel;
@@ -0,0 +1,9 @@
1
+ import { Bytes } from 'scale-ts';
2
+ import { khash, stringToBytes } from '../crypto.js';
3
+ export const ChannelCodec = Bytes(32);
4
+ export function createRequestChannel(sessionId) {
5
+ return khash(sessionId, stringToBytes('request'));
6
+ }
7
+ export function createResponseChannel(sessionId) {
8
+ return khash(sessionId, stringToBytes('response'));
9
+ }
@@ -0,0 +1,10 @@
1
+ import type { Statement } from '@polkadot-api/sdk-statement';
2
+ import type { CodecType } from 'scale-ts';
3
+ import type { Channel } from '../model/channel.js';
4
+ import type { SessionId } from '../model/session.js';
5
+ import { DecodingError } from './error.js';
6
+ import type { ResponseCode, StatementData } from './scale/statementData.js';
7
+ import type { SessionEvent } from './types.js';
8
+ export declare function toStatement(sessionId: SessionId, channel: Channel, priority: number, data: Uint8Array): Statement;
9
+ export declare function toEvent(statement: Statement, data: CodecType<typeof StatementData>): SessionEvent;
10
+ export declare function mapResponseCode(responseCode: ResponseCode): import("neverthrow").Ok<void, never> | import("neverthrow").Err<never, DecodingError>;
@@ -0,0 +1,41 @@
1
+ import { Binary } from '@polkadot-api/substrate-bindings';
2
+ import { err, ok } from 'neverthrow';
3
+ import { DecodingError, DecryptionError, UnknownError } from './error.js';
4
+ export function toStatement(sessionId, channel, priority, data) {
5
+ return {
6
+ priority: priority,
7
+ channel: Binary.fromBytes(channel),
8
+ topics: [Binary.fromBytes(sessionId)],
9
+ data: Binary.fromBytes(data),
10
+ };
11
+ }
12
+ export function toEvent(statement, data) {
13
+ switch (data.tag) {
14
+ case 'request':
15
+ return {
16
+ type: 'request',
17
+ requestId: data.value.requestId,
18
+ priority: statement.priority ?? 0,
19
+ messages: data.value.data,
20
+ };
21
+ case 'response':
22
+ return {
23
+ type: 'response',
24
+ requestId: data.value.requestId,
25
+ priority: statement.priority ?? 0,
26
+ responseCode: data.value.responseCode,
27
+ };
28
+ }
29
+ }
30
+ export function mapResponseCode(responseCode) {
31
+ switch (responseCode) {
32
+ case 'success':
33
+ return ok();
34
+ case 'decodingFailed':
35
+ return err(new DecodingError());
36
+ case 'decryptionFailed':
37
+ return err(new DecryptionError());
38
+ case 'unknown':
39
+ return err(new UnknownError());
40
+ }
41
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getDefaultPriority(): number;
2
+ export declare function getPriority(timestamp: number): number;
@@ -0,0 +1,13 @@
1
+ function now() {
2
+ const d1 = new Date();
3
+ const d2 = new Date(d1.getUTCFullYear(), d1.getUTCMonth(), d1.getUTCDate(), d1.getUTCHours(), d1.getUTCMinutes(), d1.getUTCSeconds());
4
+ return d2.getTime();
5
+ }
6
+ export function getDefaultPriority() {
7
+ return getPriority(now());
8
+ }
9
+ export function getPriority(timestamp) {
10
+ // (November 15, 2025) in seconds
11
+ const BASE_PRIORITY = 1763154000;
12
+ return Math.floor(timestamp / 1000) - BASE_PRIORITY;
13
+ }
@@ -0,0 +1 @@
1
+ export declare const createRequestId: () => string;
@@ -0,0 +1,2 @@
1
+ import { nanoid } from 'nanoid';
2
+ export const createRequestId = () => nanoid(16);
@@ -1,5 +1,4 @@
1
1
  import { Binary } from '@polkadot-api/substrate-bindings';
2
- import { toHex } from '@polkadot-api/utils';
3
2
  import { nanoid } from 'nanoid';
4
3
  import { ResultAsync, err, fromPromise, fromThrowable, ok, okAsync } from 'neverthrow';
5
4
  import { Bytes } from 'scale-ts';
@@ -12,7 +11,6 @@ import { StatementData } from './scale/statementData.js';
12
11
  export function createSession({ localAccount, remoteAccount, statementStore, encryption, prover, }) {
13
12
  let subscriptions = [];
14
13
  function submit(sessionId, channel, data) {
15
- console.log('data', toHex(data));
16
14
  return encryption
17
15
  .encrypt(data)
18
16
  .map(data => ({
@@ -0,0 +1,6 @@
1
+ import type { SessionEvent } from './types.js';
2
+ export type Tracker = {
3
+ track(payload: SessionEvent): void;
4
+ isTracked(payload: SessionEvent): boolean;
5
+ };
6
+ export declare const createTracker: () => Tracker;
@@ -0,0 +1,26 @@
1
+ import { toHex } from '@polkadot-api/utils';
2
+ export const createTracker = () => {
3
+ const tracked = new Set();
4
+ function toHash(payload) {
5
+ switch (payload.type) {
6
+ case 'request': {
7
+ let hash = `${payload.requestId}_${payload.priority}_`;
8
+ for (const message of payload.messages) {
9
+ hash += toHex(message);
10
+ }
11
+ return hash;
12
+ }
13
+ case 'response': {
14
+ return `${payload.requestId}_${payload.priority}_${payload.responseCode}`;
15
+ }
16
+ }
17
+ }
18
+ return {
19
+ track(payload) {
20
+ tracked.add(toHash(payload));
21
+ },
22
+ isTracked(payload) {
23
+ return tracked.has(toHash(payload));
24
+ },
25
+ };
26
+ };
@@ -0,0 +1,20 @@
1
+ import { ResultAsync } from 'neverthrow';
2
+ import type { StatementStoreAdapter } from '../adapter/types.js';
3
+ import type { SessionId } from '../model/session.js';
4
+ import type { Callback } from '../types.js';
5
+ import type { Encryption } from './encyption.js';
6
+ import type { StatementProver } from './statementProver.js';
7
+ import type { SessionEvent, SessionRequestEvent, SessionResponseEvent, Subscriber } from './types.js';
8
+ export type Transport = {
9
+ submitRequest(sessionId: SessionId, request: SessionRequestEvent): ResultAsync<void, Error>;
10
+ submitResponse(sessionId: SessionId, response: SessionResponseEvent): ResultAsync<void, Error>;
11
+ query(sessionId: SessionId): ResultAsync<SessionEvent[], Error>;
12
+ subscribe(sessionId: SessionId, callback: Callback<SessionEvent>): Subscriber;
13
+ };
14
+ type Params = {
15
+ statementStore: StatementStoreAdapter;
16
+ encryption: Encryption;
17
+ prover: StatementProver;
18
+ };
19
+ export declare function createTransport({ encryption, prover, statementStore }: Params): Transport;
20
+ export {};
@@ -0,0 +1,76 @@
1
+ import { statementCodec } from '@polkadot-api/sdk-statement';
2
+ import { ResultAsync, err, errAsync, fromThrowable, ok } from 'neverthrow';
3
+ import { toError } from '../helpers.js';
4
+ import { createRequestChannel, createResponseChannel } from '../model/channel.js';
5
+ import { DecodingError, DecryptionError, MessageTooLarge } from './error.js';
6
+ import { toEvent, toStatement } from './mappers.js';
7
+ import { StatementData } from './scale/statementData.js';
8
+ import { createTracker } from './tracker.js';
9
+ export function createTransport({ encryption, prover, statementStore }) {
10
+ const tracker = createTracker();
11
+ const encode = fromThrowable(StatementData.enc, toError);
12
+ const decode = fromThrowable(StatementData.dec, () => new DecodingError());
13
+ function validateStatementSize(statement) {
14
+ const MAX_REQUEST_SIZE = 1024;
15
+ const size = statementCodec.enc(statement).length;
16
+ return statementCodec.enc(statement).length > MAX_REQUEST_SIZE
17
+ ? err(new MessageTooLarge(size, MAX_REQUEST_SIZE))
18
+ : ok();
19
+ }
20
+ function processStatement(statement) {
21
+ if (!statement.data)
22
+ return errAsync(new Error('Statement.data is not presented'));
23
+ const data = statement.data.asBytes();
24
+ return prover
25
+ .verifyMessageProof(statement)
26
+ .andThen(() => encryption.decrypt(data))
27
+ .andThen(decode)
28
+ .map(statementData => toEvent(statement, statementData));
29
+ }
30
+ function submit(sessionId, channel, priority, data) {
31
+ return encryption
32
+ .encrypt(data)
33
+ .map(data => toStatement(sessionId, channel, priority, data))
34
+ .asyncAndThen(prover.generateMessageProof)
35
+ .andThrough(validateStatementSize)
36
+ .andThen(statementStore.submitStatement);
37
+ }
38
+ return {
39
+ submitRequest(sessionId, request) {
40
+ const rawData = encode({
41
+ tag: 'request',
42
+ value: { requestId: request.requestId, data: request.messages },
43
+ });
44
+ return rawData.asyncAndThen(data => submit(sessionId, createRequestChannel(sessionId), request.priority, data));
45
+ },
46
+ submitResponse(sessionId, response) {
47
+ const rawData = encode({
48
+ tag: 'response',
49
+ value: { requestId: response.requestId, responseCode: response.responseCode },
50
+ });
51
+ return rawData.asyncAndThen(data => submit(sessionId, createResponseChannel(sessionId), response.priority, data));
52
+ },
53
+ query(sessionId) {
54
+ return statementStore
55
+ .queryStatements([sessionId])
56
+ .andThen(statements => ResultAsync.combine(statements.map(processStatement)));
57
+ },
58
+ subscribe(sessionId, callback) {
59
+ const unsubscribe = statementStore.subscribeStatements([sessionId], statements => {
60
+ statements.map(processStatement).forEach(result => {
61
+ result.match(event => {
62
+ if (tracker.isTracked(event))
63
+ return;
64
+ tracker.track(event);
65
+ callback(event);
66
+ }, e => {
67
+ if (DecryptionError.isDecryptionError(e) || DecodingError.isDecodingError(e)) {
68
+ console.error(e);
69
+ }
70
+ });
71
+ });
72
+ });
73
+ return { unsubscribe };
74
+ },
75
+ };
76
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/statement-store",
3
3
  "type": "module",
4
- "version": "0.5.0-17",
4
+ "version": "0.5.0-18",
5
5
  "description": "Statement store integration",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {