Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@rpch/sdk

Package Overview
Dependencies
Maintainers
2
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rpch/sdk - npm Package Compare versions

Comparing version 1.2.4 to 1.4.0

build/result.d.ts

3

build/entry-data.d.ts

@@ -23,2 +23,3 @@ import * as PerfData from './perf-data';

requestsOngoing: number;
infoOngoing: number;
};

@@ -28,2 +29,4 @@ export declare function create(): EntryData;

export declare function removeOngoingReq(ed: EntryData): void;
export declare function addOngoingInfo(ed: EntryData): void;
export declare function removeOngoingInfo(ed: EntryData): void;
export declare function addOngoingSeg(ed: EntryData, seg: Segment.Segment): void;

@@ -30,0 +33,0 @@ export declare function recSuccessSeq(ed: EntryData, seg: Segment.Segment, dur: number): void;

@@ -26,3 +26,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.perf = exports.recFailureSeq = exports.recSuccessSeq = exports.addOngoingSeg = exports.removeOngoingReq = exports.addOngoingReq = exports.create = void 0;
exports.perf = exports.recFailureSeq = exports.recSuccessSeq = exports.addOngoingSeg = exports.removeOngoingInfo = exports.addOngoingInfo = exports.removeOngoingReq = exports.addOngoingReq = exports.create = void 0;
const NodeMatch = __importStar(require("./node-match"));

@@ -42,2 +42,3 @@ const PerfData = __importStar(require("./perf-data"));

requestsOngoing: 0,
infoOngoing: 0,
};

@@ -54,2 +55,10 @@ }

exports.removeOngoingReq = removeOngoingReq;
function addOngoingInfo(ed) {
ed.infoOngoing++;
}
exports.addOngoingInfo = addOngoingInfo;
function removeOngoingInfo(ed) {
ed.infoOngoing--;
}
exports.removeOngoingInfo = removeOngoingInfo;
function addOngoingSeg(ed, seg) {

@@ -56,0 +65,0 @@ const id = Segment.id(seg);

20

build/exit-data.d.ts

@@ -9,13 +9,17 @@ import * as PerfData from './perf-data';

avgLats: number;
infoFail: boolean;
version?: string;
infoLatSec: number;
counterOffset: number;
};
export type ExitData = {
requestsOngoing: number[];
requestsHistory: number[];
requests: Map<number, PerfData.PerfData>;
requestsOngoing: string[];
requestsHistory: string[];
requests: Map<string, PerfData.PerfData>;
infoFail?: boolean;
counterOffset?: number;
version?: string;
infoLatSec?: number;
};
export declare function create(): {
requestsOngoing: never[];
requestsHistory: never[];
requests: Map<any, any>;
};
export declare function create(): ExitData;
export declare function addOngoing(xd: ExitData, req: Request.Request): void;

@@ -22,0 +26,0 @@ export declare function recSuccess(xd: ExitData, req: Request.Request, dur: number): void;

@@ -77,2 +77,6 @@ "use strict";

const avgLats = (0, utils_1.average)(lats);
const infoLatSec = xd.infoLatSec || -1;
const infoFail = !!xd.infoFail;
const counterOffset = xd.counterOffset || 0;
const version = xd.version;
return {

@@ -84,4 +88,8 @@ ongoing,

avgLats,
infoLatSec,
infoFail,
version,
counterOffset,
};
}
exports.perf = perf;

@@ -5,1 +5,2 @@ export type ExitNode = {

};
export declare function prettyPrint(peerId: string, version: string, counter: number): string;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prettyPrint = void 0;
const utils = __importStar(require("./utils"));
function prettyPrint(peerId, version, counter) {
const shortPid = utils.shortPeerId(peerId);
return `ExitNode[${shortPid}(${peerId}),v${version},c:${counter}]`;
}
exports.prettyPrint = prettyPrint;
import * as JRPC from './jrpc';
import * as Response from './response';
export * as DPapi from './dp-api';
export * as EntryNode from './entry-node';
export * as ExitNode from './exit-node';
export * as JRPC from './jrpc';

@@ -10,2 +12,3 @@ export * as NodeAPI from './node-api';

export * as Response from './response';
export * as Result from './result';
export * as Segment from './segment';

@@ -57,6 +60,6 @@ export * as SegmentCache from './segment-cache';

private readonly redoRequests;
private readonly counterStore;
private readonly nodesColl;
private readonly ops;
private readonly chainIds;
private readonly hops?;
/**

@@ -89,3 +92,2 @@ * Construct an SDK instance enabling RPCh requests.

private responseError;
private responseCounterFail;
private responseSuccess;

@@ -92,0 +94,0 @@ private removeRequest;

@@ -29,9 +29,11 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.Utils = exports.SegmentCache = exports.Segment = exports.Response = exports.Request = exports.ProviderAPI = exports.Payload = exports.NodeAPI = exports.JRPC = exports.DPapi = void 0;
exports.Utils = exports.SegmentCache = exports.Segment = exports.Result = exports.Response = exports.Request = exports.ProviderAPI = exports.Payload = exports.NodeAPI = exports.JRPC = exports.ExitNode = exports.EntryNode = exports.DPapi = void 0;
const ethers_1 = require("ethers");
const JRPC = __importStar(require("./jrpc"));
const NodeAPI = __importStar(require("./node-api"));
const Payload = __importStar(require("./payload"));
const ProviderAPI = __importStar(require("./provider-api"));
const Request = __importStar(require("./request"));
const RequestCache = __importStar(require("./request-cache"));
const Res = __importStar(require("./result"));
const Response = __importStar(require("./response"));

@@ -43,2 +45,4 @@ const Segment = __importStar(require("./segment"));

exports.DPapi = __importStar(require("./dp-api"));
exports.EntryNode = __importStar(require("./entry-node"));
exports.ExitNode = __importStar(require("./exit-node"));
exports.JRPC = __importStar(require("./jrpc"));

@@ -50,2 +54,3 @@ exports.NodeAPI = __importStar(require("./node-api"));

exports.Response = __importStar(require("./response"));
exports.Result = __importStar(require("./result"));
exports.Segment = __importStar(require("./segment"));

@@ -85,3 +90,2 @@ exports.SegmentCache = __importStar(require("./segment-cache"));

this.redoRequests = new Set();
this.counterStore = new Map();
this.chainIds = new Map();

@@ -146,7 +150,7 @@ /**

const segRes = Segment.fromMessage(body);
if (!segRes.success) {
if (Res.isErr(segRes)) {
log.info('cannot create segment', segRes.error);
return;
}
const segment = segRes.segment;
const segment = segRes.res;
if (!this.requestCache.has(segment.requestId)) {

@@ -183,44 +187,42 @@ log.info('dropping unrelated request segment', Segment.prettyPrint(segment));

}
const request = this.requestCache.get(firstSeg.requestId);
const reqEntry = this.requestCache.get(firstSeg.requestId);
const { request, session } = reqEntry;
RequestCache.remove(this.requestCache, request.id);
const hexResp = SegmentCache.toMessage(entry);
const respData = ethers_1.utils.arrayify(hexResp);
const counter = this.counterStore.get(request.exitPeerId) || BigInt(0);
const res = Response.messageToResp({
const resUnbox = Response.messageToResp({
respData,
request,
counter,
session,
});
switch (res.res) {
case 'error':
return this.responseError(res, request);
case 'counterfail':
return this.responseCounterFail(res, request, counter);
case 'success':
return this.responseSuccess(res, request);
if (Res.isOk(resUnbox)) {
return this.responseSuccess(resUnbox.res, reqEntry);
}
return this.responseError(resUnbox.error, reqEntry);
};
this.responseError = (res, request) => {
log.error('Error extracting message', res.reason);
this.nodesColl.requestFailed(request);
return request.reject('Unable to process response');
this.responseError = (error, reqEntry) => {
log.error('Error extracting message', error);
this.nodesColl.requestFailed(reqEntry.request);
return reqEntry.reject('Unable to process response');
};
this.responseCounterFail = (res, request, counter) => {
log.info('Counter mismatch extracting message: last counter %s, new counter %s', counter, res.counter);
this.nodesColl.requestFailed(request);
return request.reject(`Check your time settings! Out of order message from exit node - last counter: ${counter}, new counter ${res.counter}.`);
};
this.responseSuccess = (res, request) => {
this.counterStore.set(request.exitPeerId, res.counter);
this.responseSuccess = ({ resp }, reqEntry) => {
const { request, reject, resolve } = reqEntry;
const responseTime = Date.now() - request.createdAt;
log.verbose('response time for request %s: %s ms', request.id, responseTime);
this.nodesColl.requestSucceeded(request, responseTime);
const resp = res.resp;
switch (resp.type) {
case 'error':
return request.reject(`Error attempting JSON RPC call: ${resp.reason}`);
case 'counterfail':
return request.reject(`Out of order message. Exit node expected message counter between ${resp.min} and ${resp.max}. Check your time settings!`);
case 'httperror':
return request.resolve({
case Payload.RespType.Resp:
return resolve({
status: 200,
text: () => new Promise((r) => r(JSON.stringify(resp.resp))),
json: () => Promise.resolve(resp.resp),
});
case Payload.RespType.CounterFail: {
const counter = reqEntry.session.updatedTS;
return reject(`Message out of counter range. Exit node expected message counter near ${resp.now} - request got ${counter}.`);
}
case Payload.RespType.DuplicateFail:
return reject('Message duplicate error. Exit node rejected already processed message');
case Payload.RespType.HttpError:
return resolve({
status: resp.status,

@@ -230,8 +232,4 @@ text: () => Promise.resolve(resp.text),

});
case 'resp':
return request.resolve({
status: 200,
text: () => new Promise((r) => r(JSON.stringify(resp.resp))),
json: () => Promise.resolve(resp.resp),
});
case Payload.RespType.Error:
return reject(`Error attempting JSON RPC call: ${resp.reason}`);
}

@@ -301,3 +299,4 @@ };

this.segmentCache = SegmentCache.init();
this.nodesColl = new nodes_collector_1.default(this.ops.discoveryPlatformEndpoint, this.clientId, !!this.ops.forceZeroHop, ApplicationTag, this.onMessages);
this.hops = this.determineHops(!!this.ops.forceZeroHop);
this.nodesColl = new nodes_collector_1.default(this.ops.discoveryPlatformEndpoint, this.clientId, ApplicationTag, this.onMessages, this.hops);
this.fetchChainId(this.ops.provider);

@@ -341,9 +340,8 @@ }

if (!resNodes) {
return reject(`Unexpected code flow - should never be here`);
return reject('Unexpected code flow - should never be here');
}
const provider = this.determineProvider(reqOps, req);
const headers = this.determineHeaders(provider, this.ops.mevKickbackAddress);
const hops = this.determineHops(!!this.ops.forceZeroHop);
// create request
const { entryNode, exitNode } = resNodes;
const { entryNode, exitNode, counterOffset } = resNodes;
const id = RequestCache.generateId(this.requestCache);

@@ -358,6 +356,7 @@ const resReq = Request.create({

exitPublicKey: ethers_1.utils.arrayify(exitNode.pubKey),
counterOffset,
headers,
hops,
hops: this.hops,
});
if (!resReq.success) {
if (Res.isErr(resReq)) {
log.error('Error creating request', resReq.error);

@@ -367,4 +366,4 @@ return reject('Unable to create request object');

// split request to segments
const request = resReq.req;
const segments = Request.toSegments(request);
const { request, session } = resReq.res;
const segments = Request.toSegments(request, session);
const failMsg = this.checkSegmentLimit(segments.length);

@@ -381,6 +380,12 @@ if (failMsg) {

// track request
const entry = RequestCache.add(this.requestCache, request, resolve, reject, timer);
const entry = RequestCache.add(this.requestCache, {
request,
resolve,
reject,
timer,
session,
});
this.nodesColl.requestStarted(request);
// send request to hoprd
log.info('sending request %i', request.id);
log.info('sending request %s', request.id);
// queue segment sending for all of them

@@ -416,2 +421,3 @@ segments.forEach((s) => setTimeout(() => {

id,
originalId: origReq.id,
provider: origReq.provider,

@@ -423,6 +429,7 @@ req: origReq.req,

exitPublicKey: ethers_1.utils.arrayify(fallback.exitNode.pubKey),
counterOffset: fallback.counterOffset,
headers: origReq.headers,
hops: origReq.hops,
});
if (!resReq.success) {
if (Res.isErr(resReq)) {
log.info('Error creating fallback request', resReq.error);

@@ -432,4 +439,4 @@ return cacheEntry.reject('unable to create fallback request object');

// split request to segments
const request = resReq.req;
const segments = Request.toSegments(request);
const { request, session } = resReq.res;
const segments = Request.toSegments(request, session);
const failMsg = this.checkSegmentLimit(segments.length);

@@ -441,3 +448,9 @@ if (failMsg) {

// track request
const newCacheEntry = RequestCache.add(this.requestCache, request, cacheEntry.resolve, cacheEntry.reject, cacheEntry.timer);
const newCacheEntry = RequestCache.add(this.requestCache, {
request,
resolve: cacheEntry.resolve,
reject: cacheEntry.reject,
timer: cacheEntry.timer,
session,
});
this.nodesColl.requestStarted(request);

@@ -444,0 +457,0 @@ // send request to hoprd

@@ -12,2 +12,3 @@ import WebSocket = require('isomorphic-ws');

body: string;
receivedAt: number;
};

@@ -14,0 +15,0 @@ export type Heartbeats = {

@@ -10,2 +10,3 @@ import type { EntryNode } from './entry-node';

exitNode: ExitNode;
counterOffset: number;
};
import * as EntryData from './entry-data';
import * as ExitData from './exit-data';
import * as ExitNode from './exit-node';
import * as NodeAPI from './node-api';

@@ -8,3 +9,2 @@ import * as Request from './request';

import type { EntryNode } from './entry-node';
import type { ExitNode } from './exit-node';
export type MessageListener = (messages: NodeAPI.Message[]) => void;

@@ -14,5 +14,6 @@ export type NodePair = {

entryData: EntryData.EntryData;
exitNodes: Map<string, ExitNode>;
exitNodes: Map<string, ExitNode.ExitNode>;
exitDatas: Map<string, ExitData.ExitData>;
applicationTag: number;
hops?: number;
messageListener: MessageListener;

@@ -23,3 +24,3 @@ fetchInterval?: ReturnType<typeof setInterval>;

};
export declare function create(entryNode: EntryNode, exitNodesIt: Iterable<ExitNode>, applicationTag: number, messageListener: MessageListener): NodePair;
export declare function create(entryNode: EntryNode, exitNodesIt: Iterable<ExitNode.ExitNode>, applicationTag: number, messageListener: MessageListener, hops?: number): NodePair;
export declare function destruct(np: NodePair): void;

@@ -34,5 +35,7 @@ export declare function id(np: NodePair): string;

/**
* Run initial discovery steps.
* Ping entry node version.
* Request info msg from exit nodes.
*/
export declare function ping(np: NodePair): Promise<number>;
export declare function discover(np: NodePair): void;
export declare function prettyPrint(np: NodePair): string;

@@ -26,12 +26,15 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.prettyPrint = exports.ping = exports.segmentFailed = exports.segmentSucceeded = exports.segmentStarted = exports.requestFailed = exports.requestSucceeded = exports.requestStarted = exports.id = exports.destruct = exports.create = void 0;
exports.prettyPrint = exports.discover = exports.segmentFailed = exports.segmentSucceeded = exports.segmentStarted = exports.requestFailed = exports.requestSucceeded = exports.requestStarted = exports.id = exports.destruct = exports.create = void 0;
const EntryData = __importStar(require("./entry-data"));
const ExitData = __importStar(require("./exit-data"));
const ExitNode = __importStar(require("./exit-node"));
const NodeAPI = __importStar(require("./node-api"));
const NodeMatch = __importStar(require("./node-match"));
const Payload = __importStar(require("./payload"));
const PerfData = __importStar(require("./perf-data"));
const Request = __importStar(require("./request"));
const Res = __importStar(require("./result"));
const utils_1 = require("./utils");
const MessagesFetchInterval = 333; // ms
function create(entryNode, exitNodesIt, applicationTag, messageListener) {
function create(entryNode, exitNodesIt, applicationTag, messageListener, hops) {
const entryData = EntryData.create();

@@ -53,2 +56,3 @@ const shortId = (0, utils_1.shortPeerId)(entryNode.id);

log,
hops,
};

@@ -102,3 +106,3 @@ }

// stop interval if applicable
if (np.entryData.requestsOngoing === 0) {
if (np.entryData.requestsOngoing === 0 && np.entryData.infoOngoing === 0) {
clearInterval(np.fetchInterval);

@@ -121,14 +125,30 @@ np.fetchInterval = undefined;

/**
* Run initial discovery steps.
* Ping entry node version.
* Request info msg from exit nodes.
*/
function ping(np) {
return new Promise((res) => {
const startPingTime = Date.now();
NodeAPI.version(np.entryNode).then((_) => {
np.entryData.pingDuration = Date.now() - startPingTime;
return res(np.entryData.pingDuration);
});
function discover(np) {
const startPingTime = Date.now();
NodeAPI.version(np.entryNode).then((_) => {
np.entryData.pingDuration = Date.now() - startPingTime;
});
Array.from(np.exitNodes.values()).map((x, idx) => {
setTimeout(() => requestInfo(np, x), idx);
});
}
exports.ping = ping;
exports.discover = discover;
function requestInfo(np, exitNode) {
NodeAPI.sendMessage({
...np.entryNode,
hops: np.hops,
}, {
recipient: exitNode.id,
tag: np.applicationTag,
message: `info-${np.entryNode.id}-${np.hops}`,
});
EntryData.addOngoingInfo(np.entryData);
if (!np.fetchInterval) {
np.fetchInterval = setInterval(() => fetchMessages(np), MessagesFetchInterval);
}
}
function prettyPrint(np) {

@@ -189,3 +209,13 @@ const segOngoing = np.entryData.segmentsOngoing.length;

}
np.messageListener(messages);
const { msgs, infoResps } = messages.reduce((acc, m) => {
if (m.body.startsWith('nfrp-')) {
acc.infoResps.push(m);
}
else {
acc.msgs.push(m);
}
return acc;
}, { infoResps: [], msgs: [] });
incInfoResps(np, infoResps);
np.messageListener(msgs);
})

@@ -197,1 +227,25 @@ .catch((err) => {

}
function incInfoResps(np, infoResps) {
infoResps.forEach(({ body, receivedAt }) => {
const [, payload] = body.split('-');
const resDec = Payload.decodeInfo(payload);
if (Res.isErr(resDec)) {
return np.log.error('Error decoding info payload:', resDec.error);
}
const { peerId, version, counter } = resDec.res;
const nodeLog = ExitNode.prettyPrint(peerId, version, counter);
const exitNode = np.exitNodes.get(peerId);
if (!exitNode) {
return np.log.info('Received untracked info from %s', nodeLog);
}
const exitData = np.exitDatas.get(peerId);
if (!exitData) {
return np.log.error('ExitData mismatch for %s', nodeLog);
}
exitData.version = version;
exitData.counterOffset = Date.now() - counter;
exitData.infoLatSec = Math.abs(receivedAt - Math.floor(counter / 1000));
EntryData.removeOngoingInfo(np.entryData);
});
checkStopInterval(np);
}

@@ -0,14 +1,9 @@

import * as NodeMatch from './node-match';
import * as NodePair from './node-pair';
import * as NodeMatch from './node-match';
import * as Res from './result';
import type { EntryNode } from './entry-node';
export type ResultOk = {
success: true;
export type NodeSelection = {
match: NodeMatch.NodeMatch;
via: string;
};
export type ResultErr = {
success: false;
error: string;
};
export type Result = ResultOk | ResultErr;
/**

@@ -18,3 +13,3 @@ * Try to distribute evenly with best route pairs preferred.

*/
export declare function routePair(nodePairs: Map<string, NodePair.NodePair>): Result;
export declare function routePair(nodePairs: Map<string, NodePair.NodePair>): Res.Result<NodeSelection>;
/**

@@ -25,4 +20,3 @@ * Try to distribute evenly with best route pairs preferred.

*/
export declare function fallbackRoutePair(nodePairs: Map<string, NodePair.NodePair>, exclude: EntryNode): Result;
export declare function isOk(res: Result): res is ResultOk;
export declare function prettyPrint(res: Result): string;
export declare function fallbackRoutePair(nodePairs: Map<string, NodePair.NodePair>, exclude: EntryNode): Res.Result<NodeSelection>;
export declare function prettyPrint(res: Res.Result<NodeSelection>): string;

@@ -26,6 +26,8 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.prettyPrint = exports.isOk = exports.fallbackRoutePair = exports.routePair = void 0;
const utils_1 = require("./utils");
exports.prettyPrint = exports.fallbackRoutePair = exports.routePair = void 0;
const EntryData = __importStar(require("./entry-data"));
const ExitData = __importStar(require("./exit-data"));
const Res = __importStar(require("./result"));
const utils_1 = require("./utils");
const ExitNodesCompatVersions = ['0.12'];
/**

@@ -51,11 +53,8 @@ * Try to distribute evenly with best route pairs preferred.

exports.fallbackRoutePair = fallbackRoutePair;
function isOk(res) {
return res.success;
}
exports.isOk = isOk;
function prettyPrint(res) {
if (isOk(res)) {
const eId = (0, utils_1.shortPeerId)(res.match.entryNode.id);
const xId = (0, utils_1.shortPeerId)(res.match.exitNode.id);
return `${eId} > ${xId} (via ${res.via})`;
if (Res.isOk(res)) {
const sel = res.res;
const eId = (0, utils_1.shortPeerId)(sel.match.entryNode.id);
const xId = (0, utils_1.shortPeerId)(sel.match.exitNode.id);
return `${eId} > ${xId} (via ${sel.via})`;
}

@@ -68,3 +67,3 @@ return `${res.error}`;

if (routePerfs.length === 0) {
return { success: false, error: 'no nodes' };
return Res.err('no nodes');
}

@@ -75,5 +74,17 @@ // special case only one route

}
// special case version mismatches
const xVersionMatches = versionMatches(routePerfs);
if (xVersionMatches.length === 1) {
return success(xVersionMatches[0], 'only (assumed) version match');
}
if (xVersionMatches.length === 0) {
return Res.err('no nodes matching required version');
}
////
// 1. compare exit node performances
const xLeastErrs = leastReqErrors(routePerfs);
const xNoInfoFails = noInfoFails(xVersionMatches);
if (xNoInfoFails.length === 1) {
return success(xNoInfoFails[0], 'only info req success');
}
const xLeastErrs = leastReqErrors(xNoInfoFails);
if (xLeastErrs.length === 1) {

@@ -90,2 +101,6 @@ return success(xLeastErrs[0], 'least request errors');

}
const xBestInfoLats = bestInfoLatencies(xLeastOngoing);
if (xBestInfoLats.length > 0) {
return success(xBestInfoLats[0], 'best info req latency');
}
const entryPerfs = createEntryPerfs(nodePairs, xLeastOngoing);

@@ -122,11 +137,7 @@ ////

}
function success({ entryNode, exitNode }, via) {
return {
success: true,
match: {
entryNode,
exitNode,
},
function success({ entryNode, exitNode, counterOffset }, via) {
return Res.ok({
match: { entryNode, exitNode, counterOffset },
via,
};
});
}

@@ -143,2 +154,28 @@ function createRoutePerfs(nodePairs) {

}
function noInfoFails(routePerfs) {
// boolean sort: false first
routePerfs.sort((l, r) => {
if (l.infoFail === r.infoFail) {
return 0;
}
if (l.infoFail) {
return 1;
}
return -1;
});
const idx = routePerfs.findIndex(({ infoFail }) => infoFail);
if (idx > 0) {
return routePerfs.slice(0, idx);
}
return routePerfs;
}
function versionMatches(routePerfs) {
return routePerfs.filter(({ version }) => {
if (version) {
return ExitNodesCompatVersions.some((v) => version.startsWith(v));
}
// do not exclude not yet determined ones
return true;
});
}
function leastReqErrors(routePerfs) {

@@ -158,2 +195,9 @@ routePerfs.sort((l, r) => l.failures - r.failures);

}
function bestInfoLatencies(routePerfs) {
// have some leeway here since info lat is in seconds and compared to ms
// treat 1 sec diff as 0 sec diff
const haveLats = routePerfs.filter(({ infoLatSec }) => infoLatSec > 1);
haveLats.sort((l, r) => Math.min(l.infoLatSec, 0) - Math.min(r.infoLatSec, 0));
return haveLats;
}
function leastReqOngoing(routePerfs) {

@@ -171,7 +215,6 @@ routePerfs.sort((l, r) => l.ongoing - r.ongoing);

const el = (0, utils_1.randomEl)(xPerfs);
return {
success: true,
match: { entryNode, exitNode: el.exitNode },
return Res.ok({
match: { entryNode, exitNode: el.exitNode, counterOffset: el.counterOffset },
via,
};
});
}

@@ -178,0 +221,0 @@ function createEntryPerfs(nodePairs, routePerfs) {

@@ -9,5 +9,5 @@ import * as Request from './request';

private readonly clientId;
private readonly forceZeroHop;
private readonly applicationTag;
private readonly messageListener;
private readonly hops?;
private readonly nodePairs;

@@ -17,3 +17,3 @@ private lastFetchNodePairs;

private ongoingFetchPairs;
constructor(discoveryPlatformEndpoint: string, clientId: string, forceZeroHop: boolean, applicationTag: number, messageListener: MessageListener);
constructor(discoveryPlatformEndpoint: string, clientId: string, applicationTag: number, messageListener: MessageListener, hops?: number | undefined);
destruct: () => void;

@@ -20,0 +20,0 @@ /**

@@ -27,6 +27,7 @@ "use strict";

const DPapi = __importStar(require("./dp-api"));
const NodePair = __importStar(require("./node-pair"));
const NodeSel = __importStar(require("./node-selector"));
const Request = __importStar(require("./request"));
const Res = __importStar(require("./result"));
const Segment = __importStar(require("./segment"));
const NodeSel = __importStar(require("./node-selector"));
const NodePair = __importStar(require("./node-pair"));
const utils_1 = require("./utils");

@@ -37,8 +38,8 @@ const log = (0, utils_1.logger)(['sdk', 'nodes-collector']);

class NodesCollector {
constructor(discoveryPlatformEndpoint, clientId, forceZeroHop, applicationTag, messageListener) {
constructor(discoveryPlatformEndpoint, clientId, applicationTag, messageListener, hops) {
this.discoveryPlatformEndpoint = discoveryPlatformEndpoint;
this.clientId = clientId;
this.forceZeroHop = forceZeroHop;
this.applicationTag = applicationTag;
this.messageListener = messageListener;
this.hops = hops;
this.nodePairs = new Map();

@@ -64,3 +65,3 @@ this.lastFetchNodePairs = 0;

const res = NodeSel.routePair(this.nodePairs);
if (NodeSel.isOk(res)) {
if (Res.isOk(res)) {
log.verbose('ready with route pair', NodeSel.prettyPrint(res));

@@ -88,5 +89,5 @@ return resolve(true);

const res = NodeSel.routePair(this.nodePairs);
if (NodeSel.isOk(res)) {
if (Res.isOk(res)) {
log.verbose('found route pair', NodeSel.prettyPrint(res));
return resolve(res.match);
return resolve(res.res.match);
}

@@ -107,5 +108,5 @@ if (elapsed > timeout) {

const res = NodeSel.fallbackRoutePair(this.nodePairs, exclude);
if (NodeSel.isOk(res)) {
if (Res.isOk(res)) {
log.verbose('found fallback route pair', NodeSel.prettyPrint(res));
return res.match;
return res.res.match;
}

@@ -181,3 +182,3 @@ };

clientId: this.clientId,
forceZeroHop: this.forceZeroHop,
forceZeroHop: this.hops === 0,
}, NodePairAmount, this.lastMatchedAt)

@@ -204,7 +205,8 @@ .then(this.initNodes)

const exitNodes = en.recommendedExits.map((id) => lookupExitNodes.get(id));
const np = NodePair.create(en, exitNodes, this.applicationTag, this.messageListener);
const np = NodePair.create(en, exitNodes, this.applicationTag, this.messageListener, this.hops);
this.nodePairs.set(NodePair.id(np), np);
});
// reping all nodes
this.nodePairs.forEach((np) => NodePair.ping(np));
this.nodePairs.forEach((np) => NodePair.discover(np));
log.verbose('Discovered %d node-pairs with %d exits', this.nodePairs.size, lookupExitNodes.size);
};

@@ -211,0 +213,0 @@ this.fetchNodePairs();

import * as JRPC from './jrpc';
import * as Res from './result';
export type ReqPayload = {

@@ -9,20 +10,35 @@ clientId: string;

};
export declare enum RespType {
Resp = 0,
CounterFail = 1,
DuplicateFail = 2,
HttpError = 3,
Error = 4
}
export type RespPayload = {
type: 'resp';
type: RespType.Resp;
resp: JRPC.Response;
} | {
type: 'counterfail';
min: bigint;
max: bigint;
type: RespType.CounterFail;
now: number;
} | {
type: 'httperror';
type: RespType.DuplicateFail;
} | {
type: RespType.HttpError;
status: number;
text: string;
} | {
type: 'error';
type: RespType.Error;
reason: string;
};
export declare function encodeReq(payload: ReqPayload): string;
export declare function decodeReq(payload: string): ReqPayload;
export declare function encodeResp(payload: RespPayload): string;
export declare function decodeResp(payload: string): RespPayload;
export type InfoPayload = {
peerId: string;
version: string;
counter: number;
};
export declare function encodeReq(payload: ReqPayload): Res.Result<string>;
export declare function decodeReq(payload: string): Res.Result<ReqPayload>;
export declare function encodeResp(payload: RespPayload): Res.Result<string>;
export declare function decodeResp(payload: string): Res.Result<RespPayload>;
export declare function encodeInfo(payload: InfoPayload): Res.Result<string>;
export declare function decodeInfo(payload: string): Res.Result<InfoPayload>;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -6,19 +29,72 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeResp = exports.encodeResp = exports.decodeReq = exports.encodeReq = void 0;
exports.decodeInfo = exports.encodeInfo = exports.decodeResp = exports.encodeResp = exports.decodeReq = exports.encodeReq = exports.RespType = void 0;
const lz_string_1 = __importDefault(require("lz-string"));
const Res = __importStar(require("./result"));
var RespType;
(function (RespType) {
RespType[RespType["Resp"] = 0] = "Resp";
RespType[RespType["CounterFail"] = 1] = "CounterFail";
RespType[RespType["DuplicateFail"] = 2] = "DuplicateFail";
RespType[RespType["HttpError"] = 3] = "HttpError";
RespType[RespType["Error"] = 4] = "Error";
})(RespType || (exports.RespType = RespType = {}));
function encodeReq(payload) {
return lz_string_1.default.compressToUTF16(JSON.stringify(payload));
try {
const res = lz_string_1.default.compressToUTF16(JSON.stringify(payload));
return Res.ok(res);
}
catch (ex) {
return Res.err(`Error encoding request payload: ${ex}`);
}
}
exports.encodeReq = encodeReq;
function decodeReq(payload) {
return JSON.parse(lz_string_1.default.decompressFromUTF16(payload));
try {
const res = JSON.parse(lz_string_1.default.decompressFromUTF16(payload));
return Res.ok(res);
}
catch (ex) {
return Res.err(`Error decoding request payload: ${ex}`);
}
}
exports.decodeReq = decodeReq;
function encodeResp(payload) {
return lz_string_1.default.compressToUTF16(JSON.stringify(payload));
try {
const res = lz_string_1.default.compressToUTF16(JSON.stringify(payload));
return Res.ok(res);
}
catch (ex) {
return Res.err(`Error encoding response payload: ${ex}`);
}
}
exports.encodeResp = encodeResp;
function decodeResp(payload) {
return JSON.parse(lz_string_1.default.decompressFromUTF16(payload));
try {
const res = JSON.parse(lz_string_1.default.decompressFromUTF16(payload));
return Res.ok(res);
}
catch (ex) {
return Res.err(`Error decoding response payload: ${ex}`);
}
}
exports.decodeResp = decodeResp;
function encodeInfo(payload) {
try {
const res = lz_string_1.default.compressToUTF16(JSON.stringify(payload));
return Res.ok(res);
}
catch (ex) {
return Res.err('Error encoding info payload');
}
}
exports.encodeInfo = encodeInfo;
function decodeInfo(payload) {
try {
const res = JSON.parse(lz_string_1.default.decompressFromUTF16(payload));
return Res.ok(res);
}
catch (ex) {
return Res.err('Error encoding info payload');
}
}
exports.decodeInfo = decodeInfo;
import * as JRPC from './jrpc';
export type RPCSuccess = JRPC.Response;
import * as Res from './result';
export type RPCFailure = {

@@ -7,4 +7,3 @@ status: number;

};
export type RPCResp = RPCSuccess | RPCFailure;
export declare function fetchChainId(provider: string): Promise<JRPC.Response>;
export declare function fetchRPC(provider: string, req: JRPC.Request, reqHeaders?: Record<string, string>): Promise<RPCResp>;
export declare function fetchRPC(provider: string, req: JRPC.Request, reqHeaders?: Record<string, string>): Promise<Res.Result<JRPC.Response, RPCFailure>>;

@@ -28,2 +28,3 @@ "use strict";

const JRPC = __importStar(require("./jrpc"));
const Res = __importStar(require("./result"));
function fetchChainId(provider) {

@@ -49,6 +50,6 @@ const url = new URL(provider);

if (res.status !== 200) {
return resolve({ status: res.status, message: await res.text() });
return resolve(Res.err({ status: res.status, message: await res.text() }));
}
const resp = (await res.json());
return resolve(resp);
return resolve(Res.ok(resp));
})

@@ -55,0 +56,0 @@ .catch(reject);

@@ -0,7 +1,10 @@

import * as compatCrypto from '@rpch/compat-crypto';
import type { Request } from './request';
import type { Response } from './response';
export type Cache = Map<number, Entry>;
export type Entry = Request & {
export type Cache = Map<string, Entry>;
export type Entry = {
request: Request;
resolve: (res: Response) => void;
reject: (error: string) => void;
session: compatCrypto.Session;
timer: ReturnType<typeof setTimeout>;

@@ -13,11 +16,16 @@ };

*/
export declare function add(cache: Cache, request: Request, resolve: (res: Response) => void, reject: (error: string) => void, timer: ReturnType<typeof setTimeout>): Entry;
export declare function add(cache: Cache, { request, resolve, reject, session, timer, }: {
request: Request;
resolve: (res: Response) => void;
reject: (error: string) => void;
session: compatCrypto.Session;
timer: ReturnType<typeof setTimeout>;
}): Entry;
/**
* Remove request id from cache.
*/
export declare function remove(cache: Cache, id: number): void;
export declare function remove(cache: Cache, id: string): void;
/**
* Generate an available request id.
* Will loop indefinitely if all request ids are taken (max ~1e7).
* Generate a sufficiently unique request id.
*/
export declare function generateId(cache: Cache): number;
export declare function generateId(_cache: Cache): string;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateId = exports.remove = exports.add = exports.init = void 0;
const crypto = __importStar(require("crypto"));
function init() {

@@ -11,7 +35,8 @@ return new Map();

*/
function add(cache, request, resolve, reject, timer) {
function add(cache, { request, resolve, reject, session, timer, }) {
const entry = {
...request,
request,
resolve,
reject,
session,
timer,

@@ -33,12 +58,7 @@ };

/**
* Generate an available request id.
* Will loop indefinitely if all request ids are taken (max ~1e7).
* Generate a sufficiently unique request id.
*/
function generateId(cache) {
let id = Math.floor(Math.random() * 1e6);
while (cache.has(id)) {
id = Math.floor(Math.random() * 1e6);
}
return id;
function generateId(_cache) {
return crypto.randomUUID();
}
exports.generateId = generateId;

@@ -1,2 +0,3 @@

import * as crypto from '@rpch/compat-crypto';
import * as compatCrypto from '@rpch/compat-crypto';
import * as Res from './result';
import * as JRPC from './jrpc';

@@ -6,4 +7,4 @@ import * as Payload from './payload';

export type Request = {
id: number;
originalId?: number;
id: string;
originalId?: string;
provider: string;

@@ -14,28 +15,15 @@ req: JRPC.Request;

exitPeerId: string;
exitPublicKey: Uint8Array;
session: crypto.Session;
headers?: Record<string, string>;
hops?: number;
};
export type ReqSuccess = {
res: 'success';
req: Payload.ReqPayload;
session: crypto.Session;
counter: bigint;
export type UnboxRequest = {
reqPayload: Payload.ReqPayload;
session: compatCrypto.Session;
};
export type ReqCounterFail = {
res: 'counterfail';
req: Payload.ReqPayload;
session: crypto.Session;
};
export type ReqError = {
res: 'error';
reason: string;
};
export type Req = ReqSuccess | ReqCounterFail | ReqError;
/**
* Creates a request and compresses its payload.
*/
export declare function create({ id, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, headers, hops, }: {
id: number;
export declare function create({ id, originalId, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, counterOffset, headers, hops, }: {
id: string;
originalId?: string;
provider: string;

@@ -47,21 +35,19 @@ req: JRPC.Request;

exitPublicKey: Uint8Array;
counterOffset: number;
headers?: Record<string, string>;
hops?: number;
}): {
success: true;
req: Request;
} | {
success: false;
error: string;
};
export declare function messageToReq({ counter, message, exitPeerId, exitPrivateKey, }: {
}): Res.Result<{
request: Request;
session: compatCrypto.Session;
}>;
export declare function messageToReq({ message, requestId, exitPeerId, exitPrivateKey, }: {
requestId: string;
message: Uint8Array;
exitPeerId: string;
exitPrivateKey: Uint8Array;
counter: bigint;
}): Req;
}): Res.Result<UnboxRequest>;
/**
* Convert request to segments.
*/
export declare function toSegments(req: Request): Segment.Segment[];
export declare function toSegments(req: Request, session: compatCrypto.Session): Segment.Segment[];
/**

@@ -71,2 +57,1 @@ * Pretty print request in human readable form.

export declare function prettyPrint(req: Request, id?: string): string;
export declare function reqSuccess(res: Req): res is ReqSuccess;

@@ -26,5 +26,6 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.reqSuccess = exports.prettyPrint = exports.toSegments = exports.messageToReq = exports.create = void 0;
const crypto = __importStar(require("@rpch/compat-crypto"));
exports.prettyPrint = exports.toSegments = exports.messageToReq = exports.create = void 0;
const compatCrypto = __importStar(require("@rpch/compat-crypto"));
const ethers_1 = require("ethers");
const Res = __importStar(require("./result"));
const Payload = __importStar(require("./payload"));

@@ -36,4 +37,4 @@ const Segment = __importStar(require("./segment"));

*/
function create({ id, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, headers, hops, }) {
const payload = Payload.encodeReq({
function create({ id, originalId, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, counterOffset, headers, hops, }) {
const resEncode = Payload.encodeReq({
provider,

@@ -45,15 +46,20 @@ clientId,

});
const data = ethers_1.utils.toUtf8Bytes(payload);
const res = crypto.boxRequest({
if (Res.isErr(resEncode)) {
return resEncode;
}
const data = ethers_1.utils.toUtf8Bytes(resEncode.res);
const resBox = compatCrypto.boxRequest({
message: data,
exitPeerId,
uuid: id,
exitPublicKey,
counterOffset,
});
if (crypto.isError(res)) {
return { success: false, error: res.error };
if (compatCrypto.isError(resBox)) {
return Res.err(resBox.error);
}
return {
success: true,
req: {
return Res.ok({
request: {
id,
originalId,
provider,

@@ -65,39 +71,31 @@ req,

exitPublicKey,
session: res.session,
headers,
hops,
},
};
session: resBox.session,
});
}
exports.create = create;
function messageToReq({ counter, message, exitPeerId, exitPrivateKey, }) {
const res = crypto.unboxRequest({ message, exitPeerId, exitPrivateKey }, counter);
if (res.res === crypto.ResState.Failed) {
return {
res: 'error',
reason: res.error,
};
function messageToReq({ message, requestId, exitPeerId, exitPrivateKey, }) {
const resUnbox = compatCrypto.unboxRequest({
message,
uuid: requestId,
exitPeerId,
exitPrivateKey,
});
if (compatCrypto.isError(resUnbox)) {
return Res.err(resUnbox.error);
}
if (!res.session.request) {
return {
res: 'error',
reason: 'crypto session without request object',
};
if (!resUnbox.session.request) {
return Res.err('Crypto session without request object');
}
const msg = ethers_1.utils.toUtf8String(res.session.request);
const req = Payload.decodeReq(msg);
if (res.res === crypto.ResState.OkFailedCounter) {
return {
res: 'counterfail',
req,
session: res.session,
};
const msg = ethers_1.utils.toUtf8String(resUnbox.session.request);
const resDecode = Payload.decodeReq(msg);
if (Res.isErr(resDecode)) {
return resDecode;
}
const newCount = res.session.updatedTS;
return {
res: 'success',
req,
session: res.session,
counter: newCount,
};
return Res.ok({
reqPayload: resDecode.res,
session: resUnbox.session,
});
}

@@ -108,6 +106,6 @@ exports.messageToReq = messageToReq;

*/
function toSegments(req) {
function toSegments(req, session) {
// we need the entry id ouside of of the actual encrypted payload
const entryIdData = ethers_1.utils.toUtf8Bytes(req.entryPeerId);
const reqData = req.session.request;
const reqData = session.request;
const hexEntryId = ethers_1.utils.hexlify(entryIdData);

@@ -134,5 +132,1 @@ const hexData = ethers_1.utils.hexlify(reqData);

exports.prettyPrint = prettyPrint;
function reqSuccess(res) {
return res.res === 'success';
}
exports.reqSuccess = reqSuccess;

@@ -1,4 +0,5 @@

import * as crypto from '@rpch/compat-crypto';
import * as compatCrypto from '@rpch/compat-crypto';
import * as JRPC from './jrpc';
import * as Payload from './payload';
import * as JRPC from './jrpc';
import * as Res from './result';
import type { Request } from './request';

@@ -10,37 +11,16 @@ export type Response = {

};
export type RespSuccess = {
res: 'success';
export type UnboxResponse = {
resp: Payload.RespPayload;
counter: bigint;
session: compatCrypto.Session;
};
export type RespCounterFail = {
res: 'counterfail';
counter: bigint;
};
export type RespError = {
res: 'error';
reason: string;
};
export type Resp = RespSuccess | RespCounterFail | RespError;
export type MsgSuccess = {
success: true;
hexData: string;
newCount: bigint;
};
export type MsgError = {
success: false;
error: string;
};
export type Msg = MsgSuccess | MsgError;
export declare function respToMessage({ entryPeerId, respPayload, unboxSession, }: {
export declare function respToMessage({ requestId, entryPeerId, respPayload, unboxSession, }: {
requestId: string;
entryPeerId: string;
respPayload: Payload.RespPayload;
unboxSession: crypto.Session;
}): Msg;
export declare function messageToResp({ respData, request, counter, }: {
unboxSession: compatCrypto.Session;
}): Res.Result<string>;
export declare function messageToResp({ respData, request, session, }: {
respData: Uint8Array;
request: Request;
counter: bigint;
}): Resp;
export declare function msgSuccess(res: Msg): res is MsgSuccess;
export declare function respSuccess(res: Resp): res is RespSuccess;
session: compatCrypto.Session;
}): Res.Result<UnboxResponse>;

@@ -26,61 +26,50 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.respSuccess = exports.msgSuccess = exports.messageToResp = exports.respToMessage = void 0;
const crypto = __importStar(require("@rpch/compat-crypto"));
exports.messageToResp = exports.respToMessage = void 0;
const compatCrypto = __importStar(require("@rpch/compat-crypto"));
const ethers_1 = require("ethers");
const Payload = __importStar(require("./payload"));
function respToMessage({ entryPeerId, respPayload, unboxSession, }) {
const payload = Payload.encodeResp(respPayload);
const data = ethers_1.utils.toUtf8Bytes(payload);
const res = crypto.boxResponse(unboxSession, {
const Res = __importStar(require("./result"));
function respToMessage({ requestId, entryPeerId, respPayload, unboxSession, }) {
const resEncode = Payload.encodeResp(respPayload);
if (Res.isErr(resEncode)) {
return resEncode;
}
const data = ethers_1.utils.toUtf8Bytes(resEncode.res);
const resBox = compatCrypto.boxResponse(unboxSession, {
uuid: requestId,
entryPeerId,
message: data,
});
if (crypto.isError(res)) {
return { success: false, error: res.error };
if (compatCrypto.isError(resBox)) {
return Res.err(resBox.error);
}
if (!unboxSession.response) {
return { success: false, error: 'crypto session without response object' };
if (!resBox.session.response) {
return Res.err('Crypto session without response object');
}
const hexData = ethers_1.utils.hexlify(unboxSession.response);
const newCount = unboxSession.updatedTS;
return { success: true, hexData, newCount };
const hexData = ethers_1.utils.hexlify(resBox.session.response);
return Res.ok(hexData);
}
exports.respToMessage = respToMessage;
function messageToResp({ respData, request, counter, }) {
const res = crypto.unboxResponse(request.session, { message: respData, entryPeerId: request.entryPeerId }, counter);
switch (res.res) {
case crypto.ResState.Failed:
return { res: 'error', reason: res.error };
case crypto.ResState.OkFailedCounter:
return {
res: 'counterfail',
counter: res.session.updatedTS,
};
case crypto.ResState.Ok:
default: {
if (!res.session.response) {
return {
res: 'error',
reason: 'crypto session without response object',
};
}
const msg = ethers_1.utils.toUtf8String(res.session.response);
const resp = Payload.decodeResp(msg);
const newCount = request.session.updatedTS;
return {
res: 'success',
resp,
counter: newCount,
};
}
function messageToResp({ respData, request, session, }) {
const resUnbox = compatCrypto.unboxResponse(session, {
uuid: request.id,
message: respData,
entryPeerId: request.entryPeerId,
});
if (compatCrypto.isError(resUnbox)) {
return Res.err(resUnbox.error);
}
if (!resUnbox.session.response) {
return Res.err('Crypto session without response object');
}
const msg = ethers_1.utils.toUtf8String(resUnbox.session.response);
const resDecode = Payload.decodeResp(msg);
if (Res.isErr(resDecode)) {
return resDecode;
}
return Res.ok({
session: resUnbox.session,
resp: resDecode.res,
});
}
exports.messageToResp = messageToResp;
function msgSuccess(res) {
return res.success;
}
exports.msgSuccess = msgSuccess;
function respSuccess(res) {
return res.res === 'success';
}
exports.respSuccess = respSuccess;
import type { Segment } from './segment';
export type Cache = Map<number, Entry>;
export type Cache = Map<string, Entry>;
export type Entry = {

@@ -37,2 +37,2 @@ segments: Map<number, Segment>;

*/
export declare function remove(cache: Cache, requestId: number): void;
export declare function remove(cache: Cache, requestId: string): void;

@@ -0,4 +1,5 @@

import * as Res from './result';
export declare const MaxSegmentBody: number;
export type Segment = {
requestId: number;
requestId: string;
nr: number;

@@ -11,13 +12,7 @@ totalCount: number;

*/
export declare function toSegments(requestId: number, hexData: string): Segment[];
export declare function toSegments(requestId: string, hexData: string): Segment[];
/**
* Create segment from string message.
*/
export declare function fromMessage(str: string): {
success: true;
segment: Segment;
} | {
success: false;
error: string;
};
export declare function fromMessage(str: string): Res.Result<Segment>;
/**

@@ -24,0 +19,0 @@ * Return request dependent segment id making it distinguishable to other segments from other requests.

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prettyPrint = exports.toMessage = exports.id = exports.fromMessage = exports.toSegments = exports.MaxSegmentBody = void 0;
const Res = __importStar(require("./result"));
// Maximum bytes we should be sending within the HOPR network.

@@ -30,21 +54,18 @@ const MaxBytes = 400;

if (parts.length === 0) {
return { success: false, error: 'empty string' };
return Res.err('empty string');
}
const count = parseInt(parts[0], 10);
if (count !== 4) {
return { success: false, error: `invalid segment parts: ${count}` };
return Res.err(`invalid segment parts: ${count}`);
}
const requestId = parseInt(parts[1], 10);
const requestId = parts[1];
const nr = parseInt(parts[2], 10);
const totalCount = parseInt(parts[3], 10);
const body = parts[4];
return {
success: true,
segment: {
requestId,
nr,
totalCount,
body,
},
};
return Res.ok({
requestId,
nr,
totalCount,
body,
});
}

@@ -51,0 +72,0 @@ exports.fromMessage = fromMessage;

# @rpch/sdk
## 1.4.0
### Minor Changes
- d1479ea: use request uuid inside crypto box
use determined exit node counter offset inside crypto counter as well
better version output log
### Patch Changes
- Updated dependencies [d1479ea]
- @rpch/compat-crypto@0.7.0
## 1.3.0
### Minor Changes
- 34e0d18: SDK now sends unique request id to adhere to updated crypto protocol
SDK will utilize new info request message from exit nodes to determine routes
### Patch Changes
- Updated dependencies [34e0d18]
- @rpch/compat-crypto@0.6.0
## 1.2.4

@@ -7,6 +32,6 @@

- 10eb627: making crypto module browser compatible
- fb64847: fix missing dependency resolution
- Updated dependencies [10eb627]
- @rpch/compat-crypto@0.5.3
- 10eb627: making crypto module browser compatible
- fb64847: fix missing dependency resolution
- Updated dependencies [10eb627]
- @rpch/compat-crypto@0.5.3

@@ -17,5 +42,5 @@ ## 1.2.3

- f3f9ee2: cleanup dependencies and consolidate formatting
- Updated dependencies [f3f9ee2]
- @rpch/compat-crypto@0.5.1
- f3f9ee2: cleanup dependencies and consolidate formatting
- Updated dependencies [f3f9ee2]
- @rpch/compat-crypto@0.5.1

@@ -26,3 +51,3 @@ ## 1.2.2

- c5ae645: consolidated NodeAPI functions here
- c5ae645: consolidated NodeAPI functions here

@@ -33,3 +58,3 @@ ## 1.2.1

- e6fed45: fix timestamp accuracy to ms
- e6fed45: fix timestamp accuracy to ms

@@ -40,3 +65,3 @@ ## 1.2.0

- 184fdaf: remove request limit
- 184fdaf: remove request limit

@@ -47,3 +72,3 @@ ## 1.1.1

- 827de28: Allow sender to determine return amount of hops
- 827de28: Allow sender to determine return amount of hops

@@ -54,8 +79,8 @@ ## 1.1.0

- eaa424c: Http errors and crypto counter errors are now correctly returned by SDK
- eaa424c: Http errors and crypto counter errors are now correctly returned by SDK
### Patch Changes
- Updated dependencies [eaa424c]
- @rpch/compat-crypto@0.5.0
- Updated dependencies [eaa424c]
- @rpch/compat-crypto@0.5.0

@@ -66,3 +91,3 @@ ## 1.0.0

- 0d4c37e: Implement one hop by default and hide zero hop behind feature flag
- 0d4c37e: Implement one hop by default and hide zero hop behind feature flag

@@ -73,3 +98,3 @@ ## 0.11.0

- afe2ab0: Integrate MEV kickback for propellorheads
- afe2ab0: Integrate MEV kickback for propellorheads

@@ -80,3 +105,3 @@ ## 0.10.0

- 26e5292: enhance segment and request counting as well as report segment sizes for future optimization
- 26e5292: enhance segment and request counting as well as report segment sizes for future optimization

@@ -87,4 +112,4 @@ ## 0.9.0

- 326a86e: Report quota usages to discovery platform
- d3728dc: Use LZ compression before sending requests
- 326a86e: Report quota usages to discovery platform
- d3728dc: Use LZ compression before sending requests

@@ -95,3 +120,3 @@ ## 0.8.0

- e65c12b: sdk used default compression
- e65c12b: sdk used default compression

@@ -102,5 +127,5 @@ ## 0.7.0

- e691140: - be more verbose about failing Discovery Platform requests
- handle MEV PROTECTION better by checking for correct chainId
- allow explicit MEV PROTECTION disable in SDK
- e691140: - be more verbose about failing Discovery Platform requests
- handle MEV PROTECTION better by checking for correct chainId
- allow explicit MEV PROTECTION disable in SDK

@@ -111,3 +136,3 @@ ## 0.6.2

- Change MEV_PROTECTION_PROVIDER logic and expose it to RPC_SERVER
- Change MEV_PROTECTION_PROVIDER logic and expose it to RPC_SERVER

@@ -118,3 +143,3 @@ ## 0.6.1

- distribute load evenly among available routes
- distribute load evenly among available routes

@@ -125,6 +150,6 @@ ## 0.6.0

- 333a830: Implemented new algorithm enabled by api v3.
The SDK no longer needs a websocket connection.
It will ping entry nodes that are received from the DP
for best initial route and keep tracking those entry exit pairs for perfomance.
- 333a830: Implemented new algorithm enabled by api v3.
The SDK no longer needs a websocket connection.
It will ping entry nodes that are received from the DP
for best initial route and keep tracking those entry exit pairs for perfomance.

@@ -135,3 +160,3 @@ ## 0.5.2

- 7633232: correctly handling msgpack unpack errors
- 7633232: correctly handling msgpack unpack errors

@@ -142,4 +167,4 @@ ## 0.5.1

- b9e964b: Minor bug fixes in the SDK
Update load tests with smaller values and different distributions
- b9e964b: Minor bug fixes in the SDK
Update load tests with smaller values and different distributions

@@ -150,19 +175,19 @@ ## 0.5.0

- ed54216: Rework node selection algorithm:
- ed54216: Rework node selection algorithm:
- query initial fixed amount of entry nodes (e.g. 10)
- open websockets to all, determine best connection
- close other connections
- use determined routes as long as feasible
- repeat
- query initial fixed amount of entry nodes (e.g. 10)
- open websockets to all, determine best connection
- close other connections
- use determined routes as long as feasible
- repeat
Resending requests on fallback route if possible:
Resending requests on fallback route if possible:
- if request on preferred entry-exit combination does not work,
we try resending it on the second best one
- if request on preferred entry-exit combination does not work,
we try resending it on the second best one
### Patch Changes
- Updated dependencies [23f842a]
- @rpch/common@0.4.0
- Updated dependencies [23f842a]
- @rpch/common@0.4.0

@@ -173,5 +198,5 @@ ## 0.4.0

- 6f9a67b: Changed the SDK approach to only have one websocket open to one entry node
- ae6ca99: Refactored send API to take and return structured data.
Change counter store to a per session store.
- 6f9a67b: Changed the SDK approach to only have one websocket open to one entry node
- ae6ca99: Refactored send API to take and return structured data.
Change counter store to a per session store.

@@ -182,14 +207,14 @@ ## 0.3.0

- 191b247: Updates to support nodejs v18 and native fetch
- fc83313: Refactored SDK for performance improvements specifically on incoming messages.
- 191b247: Updates to support nodejs v18 and native fetch
- fc83313: Refactored SDK for performance improvements specifically on incoming messages.
- removes needless array conversion on segment building
- correctly drops incoming segments that are not tied to a request
- remove needless async handling in compression module
- removes needless array conversion on segment building
- correctly drops incoming segments that are not tied to a request
- remove needless async handling in compression module
### Patch Changes
- Updated dependencies [191b247]
- Updated dependencies [fc83313]
- @rpch/common@0.3.0
- Updated dependencies [191b247]
- Updated dependencies [fc83313]
- @rpch/common@0.3.0

@@ -200,5 +225,5 @@ ## 0.2.3

- Introduce parallel entry nodes & improve reliability score
- Updated dependencies
- @rpch/common@0.2.3
- Introduce parallel entry nodes & improve reliability score
- Updated dependencies
- @rpch/common@0.2.3

@@ -209,5 +234,5 @@ ## 0.2.2

- Improved entry node re-selection
- Updated dependencies
- @rpch/common@0.2.2
- Improved entry node re-selection
- Updated dependencies
- @rpch/common@0.2.2

@@ -218,4 +243,4 @@ ## 0.2.1

- Updated dependencies
- @rpch/common@0.2.1
- Updated dependencies
- @rpch/common@0.2.1

@@ -226,8 +251,8 @@ ## 0.2.0

- Introduce compression and many stability improvements
- Introduce compression and many stability improvements
### Patch Changes
- Updated dependencies
- @rpch/common@0.2.0
- Updated dependencies
- @rpch/common@0.2.0

@@ -238,5 +263,5 @@ ## 0.1.7

- Use @rpch/crypto v0.3.4
- Updated dependencies
- @rpch/common@0.1.7
- Use @rpch/crypto v0.3.4
- Updated dependencies
- @rpch/common@0.1.7

@@ -247,6 +272,6 @@ ## 0.1.6

- Preparation release for Alpha
- Updated dependencies
- @rpch/crypto-bridge@0.1.6
- @rpch/common@0.1.6
- Preparation release for Alpha
- Updated dependencies
- @rpch/crypto-bridge@0.1.6
- @rpch/common@0.1.6

@@ -257,6 +282,6 @@ ## 0.1.5

- Fix publishing bug
- Updated dependencies
- @rpch/crypto-bridge@0.1.5
- @rpch/common@0.1.5
- Fix publishing bug
- Updated dependencies
- @rpch/crypto-bridge@0.1.5
- @rpch/common@0.1.5

@@ -267,6 +292,6 @@ ## 0.1.4

- Release of Sandbox v2
- Updated dependencies
- @rpch/crypto-bridge@0.1.4
- @rpch/common@0.1.4
- Release of Sandbox v2
- Updated dependencies
- @rpch/crypto-bridge@0.1.4
- @rpch/common@0.1.4

@@ -277,5 +302,5 @@ ## 0.1.3

- Updated dependencies
- @rpch/crypto-bridge@0.1.3
- @rpch/common@0.1.3
- Updated dependencies
- @rpch/crypto-bridge@0.1.3
- @rpch/common@0.1.3

@@ -286,6 +311,6 @@ ## 0.1.2

- Introduce web compatibility and various improvements.
- Updated dependencies
- @rpch/crypto-bridge@0.1.2
- @rpch/common@0.1.2
- Introduce web compatibility and various improvements.
- Updated dependencies
- @rpch/crypto-bridge@0.1.2
- @rpch/common@0.1.2

@@ -296,6 +321,6 @@ ## 0.1.1

- 43ba0b5: Minor patch to test publishing
- Updated dependencies [43ba0b5]
- @rpch/common@0.1.1
- @rpch/crypto-bridge@0.1.1
- 43ba0b5: Minor patch to test publishing
- Updated dependencies [43ba0b5]
- @rpch/common@0.1.1
- @rpch/crypto-bridge@0.1.1

@@ -306,8 +331,8 @@ ## 0.1.0

- 9d40520: Initial release of RPCh packages
- 9d40520: Initial release of RPCh packages
### Patch Changes
- Updated dependencies [9d40520]
- @rpch/common@0.1.0
- @rpch/crypto-bridge@0.1.0
- Updated dependencies [9d40520]
- @rpch/common@0.1.0
- @rpch/crypto-bridge@0.1.0
{
"name": "@rpch/sdk",
"version": "1.2.4",
"version": "1.4.0",
"license": "LGPL-3.0",

@@ -26,4 +26,4 @@ "main": "./build/index.js",

"dev": "tsc --watch",
"format": "prettier --write src/ .eslintrc.js jest.config.ts package.json .prettierrc.js tsconfig.json",
"format:ci": "prettier --check src/ .eslintrc.js jest.config.ts package.json .prettierrc.js tsconfig.json",
"format": "prettier --write src/ .eslintrc.js jest.config.ts package.json tsconfig.json",
"format:ci": "prettier --check src/ .eslintrc.js jest.config.ts package.json tsconfig.json",
"lint": "eslint --fix src/",

@@ -30,0 +30,0 @@ "lint:ci": "eslint --max-warnings 0 src/",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc