Comparing version 1.2.4 to 1.4.0
@@ -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); |
@@ -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; |
215
CHANGELOG.md
# @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/", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
118713
47
2988