*Major refactor to swarm based DHT design, switch to protomux-rpc, merging core plugin into main daemon, and creating a new internal rpc plugin for cache and broadcast requests
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
This commit is contained in:
parent
b7a5d3a99f
commit
00fc999169
|
@ -15,8 +15,6 @@ contents:
|
|||
- src: ./systemd.service
|
||||
dst: /etc/systemd/system/lumeweb-relay.service
|
||||
type: config
|
||||
depends:
|
||||
- lumeweb-relay-plugin-core
|
||||
scripts:
|
||||
postinstall: ./pkg/scripts/postinstall.sh
|
||||
preremove: ./pkg/scripts/preremove.sh
|
||||
|
|
13
package.json
13
package.json
|
@ -21,6 +21,7 @@
|
|||
"@hyperswarm/dht": "^6.0.1",
|
||||
"@hyperswarm/dht-relay": "^0.3.0",
|
||||
"@lumeweb/cfg": "https://github.com/LumeWeb/bcfg.git",
|
||||
"@lumeweb/dht-cache": "https://git.lumeweb.com/LumeWeb/dht-cache.git",
|
||||
"@lumeweb/kernel-utils": "https://github.com/LumeWeb/kernel-utils.git",
|
||||
"@lumeweb/pokt-rpc-endpoints": "https://github.com/LumeWeb/pokt-rpc-endpoints.git",
|
||||
"@skynetlabs/skynet-nodejs": "^2.6.0",
|
||||
|
@ -31,11 +32,14 @@
|
|||
"@types/ws": "^8.5.3",
|
||||
"ajv": "^8.11.0",
|
||||
"async-mutex": "^0.3.2",
|
||||
"b4a": "^1.6.1",
|
||||
"compact-encoding": "^2.11.0",
|
||||
"date-fns": "^2.28.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"ethers": "^5.6.9",
|
||||
"express": "^4.18.1",
|
||||
"fetch-blob": "https://github.com/LumeWeb/fetch-blob.git",
|
||||
"hyperswarm": "^3.0.4",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
"libskynet": "https://github.com/LumeWeb/libskynet.git",
|
||||
"libskynetnode": "https://github.com/LumeWeb/libskynetnode.git",
|
||||
|
@ -45,13 +49,18 @@
|
|||
"node-cache": "^5.1.2",
|
||||
"node-cron": "^3.0.1",
|
||||
"node-fetch": "2",
|
||||
"ordered-json": "^0.1.1",
|
||||
"promise-retry": "^2.0.1",
|
||||
"protomux": "^3.4.0",
|
||||
"protomux-rpc": "^1.3.0",
|
||||
"random-access-memory": "^4.1.0",
|
||||
"random-key": "^0.3.2",
|
||||
"slugify": "^1.6.5"
|
||||
"slugify": "^1.6.5",
|
||||
"sodium-universal": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lumeweb/relay-types": "https://github.com/LumeWeb/relay-types.git",
|
||||
"@lumeweb/relay-types": "https://git.lumeweb.com/LumeWeb/relay-types.git",
|
||||
"@types/b4a": "^1.6.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/minimatch": "^3.0.5",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
|
|
|
@ -2,7 +2,7 @@ import express, { Express } from "express";
|
|||
import http from "http";
|
||||
import { AddressInfo } from "net";
|
||||
import log from "loglevel";
|
||||
import { getKeyPair } from "./dht";
|
||||
import { getKeyPair } from "./swarm.js";
|
||||
|
||||
let app: Express;
|
||||
let router = express.Router();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import cron from "node-cron";
|
||||
import { get as getDHT } from "./dht.js";
|
||||
import { get as getSwarm } from "./swarm.js";
|
||||
import { Buffer } from "buffer";
|
||||
import { pack } from "msgpackr";
|
||||
import config from "../config.js";
|
||||
|
@ -36,19 +36,19 @@ async function ipUpdate() {
|
|||
}
|
||||
|
||||
export async function start() {
|
||||
const dht = (await getDHT()) as any;
|
||||
const swarm = (await getSwarm()) as any;
|
||||
|
||||
await ipUpdate();
|
||||
|
||||
await overwriteRegistryEntry(
|
||||
dht.defaultKeyPair,
|
||||
swarm.dht.defaultKeyPair,
|
||||
hashDataKey(REGISTRY_NODE_KEY),
|
||||
pack(`${config.str("domain")}:${config.uint("port")}`)
|
||||
);
|
||||
|
||||
log.info(
|
||||
"Relay Identity is",
|
||||
Buffer.from(dht.defaultKeyPair.publicKey).toString("hex")
|
||||
Buffer.from(swarm.dht.defaultKeyPair.publicKey).toString("hex")
|
||||
);
|
||||
|
||||
cron.schedule("0 * * * *", ipUpdate);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import config from "../config.js";
|
||||
import { getRpcServer } from "../rpc/server.js";
|
||||
import { getRpcServer } from "./rpc/server.js";
|
||||
import type { PluginAPI, RPCMethod, Plugin } from "@lumeweb/relay-types";
|
||||
import slugify from "slugify";
|
||||
import * as fs from "fs";
|
||||
|
@ -22,6 +22,8 @@ import {
|
|||
overwriteIndependentFileSmall,
|
||||
} from "../lib/file";
|
||||
import { setDnsProvider } from "./dns";
|
||||
import pluginRpc from "./plugins/rpc";
|
||||
import pluginCore from "./plugins/core";
|
||||
|
||||
let pluginApi: PluginApiManager;
|
||||
|
||||
|
@ -57,6 +59,11 @@ export class PluginApiManager {
|
|||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return this.loadPluginInstance(plugin);
|
||||
}
|
||||
|
||||
public async loadPluginInstance(plugin: Plugin): Promise<Plugin> {
|
||||
if ("default" in plugin) {
|
||||
plugin = plugin?.default as Plugin;
|
||||
}
|
||||
|
@ -81,8 +88,7 @@ export class PluginApiManager {
|
|||
getRpcServer().registerMethod(pluginName, methodName, method);
|
||||
},
|
||||
loadPlugin: getPluginAPI().loadPlugin.bind(getPluginAPI()),
|
||||
getMethods: getRpcServer().getMethods.bind(getRpcServer()),
|
||||
|
||||
getRpcServer,
|
||||
ssl: {
|
||||
setContext: setSslContext,
|
||||
getContext: getSslContext,
|
||||
|
@ -120,7 +126,12 @@ export function getPluginAPI(): PluginApiManager {
|
|||
}
|
||||
|
||||
export async function loadPlugins() {
|
||||
const api = await getPluginAPI();
|
||||
|
||||
api.loadPluginInstance(pluginCore);
|
||||
api.loadPluginInstance(pluginRpc);
|
||||
|
||||
for (const plugin of [...new Set(config.array("plugins", []))] as []) {
|
||||
await getPluginAPI().loadPlugin(plugin);
|
||||
api.loadPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { Plugin, PluginAPI } from "@lumeweb/relay-types";
|
||||
import { getRpcServer } from "../rpc/server";
|
||||
|
||||
const plugin: Plugin = {
|
||||
name: "core",
|
||||
async plugin(api: PluginAPI): Promise<void> {
|
||||
api.registerMethod("ping", {
|
||||
cacheable: false,
|
||||
async handler(): Promise<any> {
|
||||
return "pong";
|
||||
},
|
||||
});
|
||||
|
||||
api.registerMethod("get_methods", {
|
||||
cacheable: false,
|
||||
async handler(): Promise<any> {
|
||||
return api.getRpcServer().getMethods();
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default plugin;
|
|
@ -0,0 +1,132 @@
|
|||
import { getRpcServer } from "../rpc/server";
|
||||
import {
|
||||
Plugin,
|
||||
PluginAPI,
|
||||
RPCBroadcastRequest,
|
||||
RPCBroadcastResponse,
|
||||
RPCClearCacheRequest,
|
||||
RPCClearCacheResponse,
|
||||
RPCClearCacheResponseRelayList,
|
||||
RPCRequest,
|
||||
RPCResponse,
|
||||
} from "@lumeweb/relay-types";
|
||||
import { getRpcByPeer } from "../rpc";
|
||||
|
||||
async function broadcastRequest(
|
||||
request: RPCRequest,
|
||||
relays: string[]
|
||||
): Promise<Map<string, Promise<any>>> {
|
||||
const makeRequest = async (relay: string) => {
|
||||
const rpc = await getRpcByPeer(relay);
|
||||
return rpc.request(`${request.module}.${request.method}`, request.data);
|
||||
};
|
||||
|
||||
let relayMap = new Map<string, Promise<any>>();
|
||||
|
||||
for (const relay of relays) {
|
||||
relayMap.set(relay, makeRequest(relay));
|
||||
}
|
||||
|
||||
await Promise.allSettled([...relays.values()]);
|
||||
return relayMap;
|
||||
}
|
||||
|
||||
const plugin: Plugin = {
|
||||
name: "rpc",
|
||||
async plugin(api: PluginAPI): Promise<void> {
|
||||
api.registerMethod("get_cached_item", {
|
||||
cacheable: false,
|
||||
async handler(req: string): Promise<RPCResponse> {
|
||||
if (typeof req !== "string") {
|
||||
throw new Error("item must be a string");
|
||||
}
|
||||
|
||||
const cache = getRpcServer().cache.data;
|
||||
|
||||
if (!Object.keys(cache).includes(req)) {
|
||||
throw new Error("item does not exist");
|
||||
}
|
||||
|
||||
return {
|
||||
data: true,
|
||||
...cache[req]?.value,
|
||||
signature: cache[req]?.signature,
|
||||
};
|
||||
},
|
||||
});
|
||||
api.registerMethod("clear_cached_item", {
|
||||
cacheable: false,
|
||||
async handler(req: RPCClearCacheRequest): Promise<RPCClearCacheResponse> {
|
||||
if (req?.relays?.length) {
|
||||
let resp = await broadcastRequest(
|
||||
{
|
||||
module: "rpc",
|
||||
method: "clear_cached_item",
|
||||
data: req.request,
|
||||
},
|
||||
req?.relays
|
||||
);
|
||||
let results: RPCClearCacheResponse = {
|
||||
relays: {},
|
||||
data: true,
|
||||
signedField: "relays",
|
||||
};
|
||||
|
||||
for (const relay in resp) {
|
||||
let ret: RPCClearCacheResponse;
|
||||
try {
|
||||
ret = await resp.get(relay);
|
||||
} catch (e: any) {
|
||||
(results.relays as RPCClearCacheResponseRelayList)[relay] = {
|
||||
error: e.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
try {
|
||||
api.getRpcServer().cache.deleteItem(req.request);
|
||||
} catch (e: any) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return {
|
||||
data: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
api.registerMethod("broadcast_request", {
|
||||
cacheable: false,
|
||||
async handler(req: RPCBroadcastRequest): Promise<RPCBroadcastResponse> {
|
||||
if (!req?.request) {
|
||||
throw new Error("request required");
|
||||
}
|
||||
if (!req?.relays?.length) {
|
||||
throw new Error("relays required");
|
||||
}
|
||||
|
||||
let resp = await broadcastRequest(req.request, req.relays);
|
||||
|
||||
const result: RPCBroadcastResponse = {
|
||||
relays: {},
|
||||
data: true,
|
||||
signedField: "relays",
|
||||
};
|
||||
for (const relay in resp) {
|
||||
let ret: RPCClearCacheResponse;
|
||||
try {
|
||||
ret = await resp.get(relay);
|
||||
} catch (e: any) {
|
||||
result.relays[relay] = { error: e.message };
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default plugin;
|
|
@ -8,7 +8,7 @@ import express, { Express } from "express";
|
|||
import config from "../config.js";
|
||||
import * as http from "http";
|
||||
import * as https from "https";
|
||||
import { get as getDHT } from "./dht.js";
|
||||
import { get as getSwarm } from "./swarm.js";
|
||||
import WS from "ws";
|
||||
// @ts-ignore
|
||||
import log from "loglevel";
|
||||
|
@ -20,7 +20,7 @@ import { getSslContext } from "./ssl.js";
|
|||
export async function start() {
|
||||
const relayPort = config.uint("port");
|
||||
|
||||
const dht = await getDHT();
|
||||
const dht = await getSwarm();
|
||||
|
||||
const statusCodeServer = http.createServer(function (req, res) {
|
||||
// @ts-ignore
|
||||
|
|
|
@ -5,12 +5,35 @@ import config from "../config.js";
|
|||
import { errorExit } from "../lib/error.js";
|
||||
// @ts-ignore
|
||||
import stringify from "json-stable-stringify";
|
||||
import { getRpcServer } from "../rpc/server.js";
|
||||
import { getRpcServer, RPC_PROTOCOL_SYMBOL } from "./rpc/server.js";
|
||||
import { get as getSwarm, SecretStream } from "./swarm.js";
|
||||
|
||||
export async function start() {
|
||||
if (!config.str("pocket-app-id") || !config.str("pocket-app-key")) {
|
||||
errorExit("Please set pocket-app-id and pocket-app-key config options.");
|
||||
}
|
||||
|
||||
getRpcServer();
|
||||
(await getSwarm()).on("connection", (stream: SecretStream) =>
|
||||
getRpcServer().setup(stream)
|
||||
);
|
||||
}
|
||||
|
||||
export async function getRpcByPeer(peer: string) {
|
||||
const swarm = await getSwarm();
|
||||
|
||||
if (swarm._allConnections.has(peer)) {
|
||||
return swarm._allConnections.get(peer)[RPC_PROTOCOL_SYMBOL];
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const listener = () => {};
|
||||
swarm.on("connection", (peer: any, info: any) => {
|
||||
if (info.publicKey.toString("hex") !== peer) {
|
||||
return;
|
||||
}
|
||||
swarm.removeListener("connection", listener);
|
||||
|
||||
resolve(peer[RPC_PROTOCOL_SYMBOL]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
import EventEmitter from "events";
|
||||
import DHTCache from "@lumeweb/dht-cache";
|
||||
import {
|
||||
RPCCacheData,
|
||||
RPCCacheItem,
|
||||
RPCRequest,
|
||||
RPCResponse,
|
||||
} from "@lumeweb/relay-types";
|
||||
import { getRpcByPeer } from "../rpc";
|
||||
import b4a from "b4a";
|
||||
import { get as getSwarm } from "../swarm";
|
||||
import { RPCServer } from "./server";
|
||||
// @ts-ignore
|
||||
import orderedJSON from "ordered-json";
|
||||
// @ts-ignore
|
||||
import crypto from "hypercore-crypto";
|
||||
|
||||
export class RPCCache extends EventEmitter {
|
||||
private dhtCache?: DHTCache;
|
||||
private server: RPCServer;
|
||||
|
||||
private _swarm?: any;
|
||||
|
||||
get swarm(): any {
|
||||
return this._swarm;
|
||||
}
|
||||
|
||||
private _data: RPCCacheData = {};
|
||||
|
||||
get data(): RPCCacheData {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
constructor(server: RPCServer) {
|
||||
super();
|
||||
this.server = server;
|
||||
this.init();
|
||||
}
|
||||
|
||||
public async getNodeQuery(
|
||||
node: string,
|
||||
queryHash: string
|
||||
): Promise<boolean | RPCResponse> {
|
||||
if (!this.dhtCache?.peerHasItem(node, queryHash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rpc = await getRpcByPeer(node);
|
||||
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = rpc.request("rpc.get_cached_item", queryHash) as RPCCacheItem;
|
||||
} catch (e: any) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.verifyResponse(b4a.from(node, "hex") as Buffer, response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return { ...response?.value };
|
||||
}
|
||||
|
||||
public signResponse(item: RPCCacheItem): string {
|
||||
const field = item.value.signedField || "data";
|
||||
const updated = item.value.updated;
|
||||
// @ts-ignore
|
||||
const data = item.value[field];
|
||||
const json = orderedJSON.stringify(data);
|
||||
|
||||
return this.server.signData(`${updated}${json}`);
|
||||
}
|
||||
|
||||
public verifyResponse(pubkey: Buffer, item: RPCCacheItem): boolean | Buffer {
|
||||
const field = item.value.signedField || "data";
|
||||
const updated = item.value.updated;
|
||||
// @ts-ignore
|
||||
const data = item.value[field];
|
||||
const json = orderedJSON.stringify(data);
|
||||
|
||||
try {
|
||||
if (
|
||||
!crypto.verify(
|
||||
Buffer.from(`${updated}${json}`),
|
||||
Buffer.from(item?.signature as string, "hex"),
|
||||
pubkey
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public addItem(query: RPCRequest, response: RPCResponse) {
|
||||
const queryHash = RPCServer.hashQuery(query);
|
||||
|
||||
const clonedResponse = { ...response };
|
||||
|
||||
clonedResponse.updated = Date.now();
|
||||
|
||||
const item = {
|
||||
value: clonedResponse,
|
||||
signature: "",
|
||||
};
|
||||
|
||||
item.signature = this.signResponse(item);
|
||||
|
||||
this._data[queryHash] = item;
|
||||
}
|
||||
|
||||
public deleteItem(queryHash: string): boolean {
|
||||
const cache = this.dhtCache?.cache;
|
||||
|
||||
if (!cache?.includes(queryHash)) {
|
||||
throw Error("item does not exist");
|
||||
}
|
||||
|
||||
this.dhtCache?.removeItem(queryHash);
|
||||
delete this._data[queryHash];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async init() {
|
||||
this.dhtCache = new DHTCache(await getSwarm(), {
|
||||
protocol: "lumeweb.rpccache",
|
||||
});
|
||||
this._swarm = await getSwarm();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
import {
|
||||
RPCCacheData,
|
||||
RPCCacheItem,
|
||||
RPCMethod,
|
||||
RPCRequest,
|
||||
RPCResponse,
|
||||
} from "@lumeweb/relay-types";
|
||||
import EventEmitter from "events";
|
||||
// @ts-ignore
|
||||
import ProtomuxRPC from "protomux-rpc";
|
||||
import b4a from "b4a";
|
||||
import { get as getSwarm, SecretStream } from "../swarm";
|
||||
// @ts-ignore
|
||||
import c from "compact-encoding";
|
||||
import DHTCache from "@lumeweb/dht-cache";
|
||||
// @ts-ignore
|
||||
import crypto from "hypercore-crypto";
|
||||
// @ts-ignore
|
||||
import orderedJSON from "ordered-json";
|
||||
import { Mutex } from "async-mutex";
|
||||
import { RPCCache } from "./cache";
|
||||
|
||||
const sodium = require("sodium-universal");
|
||||
let server: RPCServer;
|
||||
|
||||
const RPC_PROTOCOL_ID = b4a.from("lumeweb");
|
||||
export const RPC_PROTOCOL_SYMBOL = Symbol.for(RPC_PROTOCOL_ID.toString());
|
||||
|
||||
export function getRpcServer(): RPCServer {
|
||||
if (!server) {
|
||||
server = new RPCServer();
|
||||
}
|
||||
|
||||
return server as RPCServer;
|
||||
}
|
||||
|
||||
export class RPCServer extends EventEmitter {
|
||||
private _modules: Map<string, Map<string, RPCMethod>> = new Map<
|
||||
string,
|
||||
Map<string, RPCMethod>
|
||||
>();
|
||||
private pendingRequests: Map<string, Mutex> = new Map<string, Mutex>();
|
||||
|
||||
private _cache: RPCCache = new RPCCache(this);
|
||||
|
||||
get cache(): RPCCache {
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
public static hashQuery(query: RPCRequest): string {
|
||||
const clonedQuery: RPCRequest = {
|
||||
module: query.module,
|
||||
method: query.method,
|
||||
data: query.data,
|
||||
};
|
||||
const queryHash = Buffer.allocUnsafe(32);
|
||||
sodium.crypto_generichash(
|
||||
queryHash,
|
||||
Buffer.from(orderedJSON.stringify(clonedQuery))
|
||||
);
|
||||
return queryHash.toString("hex");
|
||||
}
|
||||
|
||||
public registerMethod(
|
||||
moduleName: string,
|
||||
methodName: string,
|
||||
options: RPCMethod
|
||||
): void {
|
||||
const module = this._modules.get(moduleName);
|
||||
if (module && module.get(methodName)) {
|
||||
throw new Error(
|
||||
`Method ${methodName} already exists for module ${moduleName}`
|
||||
);
|
||||
}
|
||||
|
||||
let methodMap: Map<string, RPCMethod> | null = null;
|
||||
|
||||
if (!module) {
|
||||
methodMap = new Map<string, RPCMethod>();
|
||||
this._modules.set(moduleName, methodMap);
|
||||
}
|
||||
|
||||
if (!methodMap) {
|
||||
methodMap = this._modules.get(moduleName) as Map<string, RPCMethod>;
|
||||
}
|
||||
|
||||
methodMap.set(methodName, options);
|
||||
}
|
||||
|
||||
public getMethods(): string[] {
|
||||
const methods = [];
|
||||
|
||||
for (const module of this._modules.keys()) {
|
||||
for (const method of (
|
||||
this._modules.get(module) as Map<string, RPCMethod>
|
||||
).keys()) {
|
||||
methods.push(`${module}.${method}`);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
public setup(stream: SecretStream) {
|
||||
const existing = stream[RPC_PROTOCOL_SYMBOL];
|
||||
if (existing) return existing;
|
||||
|
||||
const options = {
|
||||
id: RPC_PROTOCOL_ID,
|
||||
valueEncoding: c.json,
|
||||
};
|
||||
const rpc = new ProtomuxRPC(stream, options);
|
||||
|
||||
stream[RPC_PROTOCOL_SYMBOL] = rpc;
|
||||
|
||||
for (const module of this._modules.keys()) {
|
||||
for (const method of (
|
||||
this._modules.get(module) as Map<string, RPCMethod>
|
||||
).keys()) {
|
||||
rpc.respond(`${module}.${method}`, {}, (data: any) =>
|
||||
this.handleRequest({ module, method, data })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return rpc;
|
||||
}
|
||||
|
||||
public signData(data: any): string {
|
||||
let raw = data;
|
||||
if (typeof data !== "string") {
|
||||
raw = orderedJSON.stringify(data);
|
||||
}
|
||||
|
||||
return crypto
|
||||
.sign(Buffer.from(raw, this._cache.swarm.keyPair.privateKey))
|
||||
.toString("hex");
|
||||
}
|
||||
|
||||
private async handleRequest(request: RPCRequest) {
|
||||
let lockedRequest = await this.waitOnRequestLock(request);
|
||||
|
||||
if (lockedRequest) {
|
||||
return lockedRequest;
|
||||
}
|
||||
|
||||
let cachedRequest = this.getCachedRequest(request) as RPCCacheItem;
|
||||
|
||||
if (cachedRequest) {
|
||||
return cachedRequest.value;
|
||||
}
|
||||
|
||||
let method = this.getMethodByRequest(request) as RPCMethod;
|
||||
|
||||
let ret;
|
||||
let error;
|
||||
|
||||
try {
|
||||
ret = (await method.handler(request.data)) as RPCResponse | any;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
let rpcResult: RPCResponse = {};
|
||||
|
||||
if (ret?.data) {
|
||||
rpcResult = { ...ret };
|
||||
|
||||
const field = rpcResult?.signedField || "data";
|
||||
|
||||
// @ts-ignore
|
||||
rpcResult.signature = this.signData(rpcResult[field]);
|
||||
} else {
|
||||
rpcResult = {
|
||||
data: ret,
|
||||
signature: this.signData(ret),
|
||||
};
|
||||
}
|
||||
|
||||
if (method.cacheable) {
|
||||
this.cache.addItem(request, rpcResult);
|
||||
}
|
||||
|
||||
return rpcResult;
|
||||
}
|
||||
|
||||
private getCachedRequest(request: RPCRequest): RPCCacheItem | boolean {
|
||||
const req = RPCServer.hashQuery(request);
|
||||
if (RPCServer.hashQuery(request) in this._cache.data) {
|
||||
this._cache.data[req];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private getMethodByRequest(request: RPCRequest): Error | RPCMethod {
|
||||
return this.getMethod(request.module, request.method);
|
||||
}
|
||||
|
||||
private getMethod(moduleName: string, method: string): Error | RPCMethod {
|
||||
let item: any = this._modules.get(moduleName);
|
||||
|
||||
if (!item) {
|
||||
return new Error("INVALID_MODULE");
|
||||
}
|
||||
|
||||
item = item.get(method);
|
||||
|
||||
if (!item) {
|
||||
return new Error("INVALID_METHOD");
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private async waitOnRequestLock(
|
||||
request: RPCRequest
|
||||
): Promise<RPCCacheItem | undefined> {
|
||||
let method = this.getMethodByRequest(request) as RPCMethod;
|
||||
if (!method.cacheable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reqId = RPCServer.hashQuery(request);
|
||||
|
||||
let lock: Mutex = this.pendingRequests.get(reqId) as Mutex;
|
||||
const lockExists = !!lock;
|
||||
|
||||
if (!lockExists) {
|
||||
lock = new Mutex();
|
||||
this.pendingRequests.set(reqId, lock);
|
||||
}
|
||||
|
||||
if (lock.isLocked()) {
|
||||
await lock.waitForUnlock();
|
||||
if (reqId in this._cache.data) {
|
||||
return this._cache.data[reqId] as RPCCacheItem;
|
||||
}
|
||||
}
|
||||
|
||||
await lock.acquire();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
//const require = createRequire(import.meta.url);
|
||||
//import { createRequire } from "module";
|
||||
|
||||
// @ts-ignore
|
||||
import Hyperswarm from "hyperswarm";
|
||||
// @ts-ignore
|
||||
import DHT from "@hyperswarm/dht";
|
||||
import config from "../config.js";
|
||||
|
@ -11,13 +13,15 @@ import {
|
|||
validSeedPhrase,
|
||||
} from "libskynet";
|
||||
|
||||
let node: {
|
||||
ready: () => any;
|
||||
createServer: () => any;
|
||||
defaultKeyPair: any;
|
||||
on: any;
|
||||
};
|
||||
let server: any;
|
||||
// @ts-ignore
|
||||
import sodium from "sodium-universal";
|
||||
import b4a from "b4a";
|
||||
|
||||
const LUMEWEB = b4a.from("lumeweb");
|
||||
|
||||
export type SecretStream = any;
|
||||
|
||||
let node: Hyperswarm;
|
||||
|
||||
export function getKeyPair() {
|
||||
const seed = config.str("seed");
|
||||
|
@ -33,26 +37,22 @@ export function getKeyPair() {
|
|||
async function start() {
|
||||
const keyPair = getKeyPair();
|
||||
|
||||
node = new DHT({ keyPair });
|
||||
node = new Hyperswarm({ keyPair, dht: new DHT({ keyPair }) });
|
||||
const topic = b4a.allocUnsafe(32);
|
||||
sodium.crypto_generichash(topic, LUMEWEB);
|
||||
|
||||
await node.ready();
|
||||
|
||||
server = node.createServer();
|
||||
await server.listen(keyPair);
|
||||
// @ts-ignore
|
||||
await node.dht.ready();
|
||||
await node.listen();
|
||||
node.join(topic);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
export async function get(
|
||||
ret: "server" | "dht" = "dht"
|
||||
): Promise<typeof server | typeof node> {
|
||||
export async function get(): Promise<Hyperswarm> {
|
||||
if (!node) {
|
||||
await start();
|
||||
}
|
||||
|
||||
if (ret == "server") {
|
||||
return server;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
import type {
|
||||
RPCRequest,
|
||||
RPCResponse,
|
||||
RPCStreamHandler,
|
||||
StreamFileResponse,
|
||||
} from "@lumeweb/relay-types";
|
||||
import { pack, unpack } from "msgpackr";
|
||||
import log from "loglevel";
|
||||
import { getRpcServer } from "./server";
|
||||
|
||||
interface CancelRequest {
|
||||
cancel: true;
|
||||
}
|
||||
|
||||
export default class RPCConnection {
|
||||
private _socket: any;
|
||||
private _canceled = false;
|
||||
constructor(socket: any) {
|
||||
this._socket = socket;
|
||||
socket.rawStream._ondestroy = () => false;
|
||||
socket.once("data", this.checkRpc.bind(this));
|
||||
}
|
||||
|
||||
private async checkRpc(data: Buffer) {
|
||||
if (data.toString() === "rpc") {
|
||||
this._socket.once("data", this.processRequest);
|
||||
this._socket.on("data", this.listenForCancel);
|
||||
}
|
||||
}
|
||||
private async listenForCancel(data: Buffer) {
|
||||
let request: any;
|
||||
try {
|
||||
request = unpack(data) as CancelRequest;
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.cancel) {
|
||||
this._canceled = true;
|
||||
}
|
||||
}
|
||||
private async processRequest(data: Buffer) {
|
||||
let request: RPCRequest;
|
||||
try {
|
||||
request = unpack(data) as RPCRequest;
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const that = this as any;
|
||||
let response;
|
||||
|
||||
const handleStream: RPCStreamHandler = async (
|
||||
stream: AsyncIterable<Uint8Array>
|
||||
): Promise<RPCResponse> => {
|
||||
const emptyData = Uint8Array.from([]);
|
||||
const streamResp = {
|
||||
data: {
|
||||
data: emptyData,
|
||||
done: false,
|
||||
} as StreamFileResponse,
|
||||
};
|
||||
for await (const chunk of stream) {
|
||||
if (this._canceled) {
|
||||
break;
|
||||
}
|
||||
streamResp.data.data = chunk as unknown as Uint8Array;
|
||||
await new Promise((resolve) => setTimeout(resolve, 15));
|
||||
that.write(pack(streamResp));
|
||||
}
|
||||
|
||||
streamResp.data.data = emptyData;
|
||||
streamResp.data.done = true;
|
||||
return streamResp;
|
||||
};
|
||||
|
||||
try {
|
||||
response = await getRpcServer().handleRequest(request, handleStream);
|
||||
} catch (error) {
|
||||
log.trace(error);
|
||||
that.write(pack({ error }));
|
||||
that.end();
|
||||
return;
|
||||
}
|
||||
if (!this._canceled) {
|
||||
that.write(pack(response));
|
||||
}
|
||||
that.end();
|
||||
}
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
import {
|
||||
RPCMethod,
|
||||
RPCRequest,
|
||||
RPCResponse,
|
||||
RPCStreamHandler,
|
||||
} from "@lumeweb/relay-types";
|
||||
import NodeCache from "node-cache";
|
||||
import { get as getDHT } from "../modules/dht.js";
|
||||
import { Mutex } from "async-mutex";
|
||||
import crypto from "crypto";
|
||||
|
||||
// @ts-ignore
|
||||
import stringify from "json-stable-stringify";
|
||||
import Ajv from "ajv";
|
||||
import RPCConnection from "./connection.js";
|
||||
import { RPC_REQUEST_SCHEMA } from "../types.js";
|
||||
|
||||
const ajv = new Ajv({ allowUnionTypes: true });
|
||||
const validateRpcRequest = ajv.compile(RPC_REQUEST_SCHEMA);
|
||||
|
||||
let server: RPCServer;
|
||||
|
||||
export function getRpcServer(): RPCServer {
|
||||
if (!server) {
|
||||
server = new RPCServer();
|
||||
}
|
||||
|
||||
return server as RPCServer;
|
||||
}
|
||||
export class RPCServer {
|
||||
private methods = new Map<string, Map<string, RPCMethod>>();
|
||||
private pendingRequests = new NodeCache();
|
||||
private processedRequests = new NodeCache({
|
||||
stdTTL: 60 * 60 * 12,
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
public registerMethod(
|
||||
moduleName: string,
|
||||
methodName: string,
|
||||
options: RPCMethod
|
||||
): void {
|
||||
const module = this.methods.get(moduleName);
|
||||
if (module && module.get(methodName)) {
|
||||
throw new Error(
|
||||
`Method ${methodName} already exists for module ${moduleName}`
|
||||
);
|
||||
}
|
||||
|
||||
let methodMap: Map<string, RPCMethod> | null = null;
|
||||
|
||||
if (!module) {
|
||||
methodMap = new Map<string, RPCMethod>();
|
||||
this.methods.set(moduleName, methodMap);
|
||||
}
|
||||
|
||||
if (!methodMap) {
|
||||
methodMap = this.methods.get(moduleName) as Map<string, RPCMethod>;
|
||||
}
|
||||
|
||||
methodMap.set(methodName, options);
|
||||
}
|
||||
|
||||
public getMethods(): string[] {
|
||||
const methods = [];
|
||||
|
||||
for (const module of this.methods.keys()) {
|
||||
for (const method of (
|
||||
this.methods.get(module) as Map<string, RPCMethod>
|
||||
).keys()) {
|
||||
methods.push(`${module}.${method}`);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
private async init(): Promise<void> {
|
||||
(await getDHT("server")).on(
|
||||
"connection",
|
||||
(socket: any) => new RPCConnection(socket)
|
||||
);
|
||||
}
|
||||
|
||||
public async handleRequest(
|
||||
request: RPCRequest,
|
||||
streamHandler: RPCStreamHandler
|
||||
): Promise<RPCResponse> {
|
||||
let valid = this.verifyRequest(request);
|
||||
|
||||
if (valid instanceof Error) {
|
||||
return {
|
||||
error: valid.message,
|
||||
};
|
||||
}
|
||||
|
||||
let lockedRequest = await this.waitOnRequestLock(request);
|
||||
|
||||
if (lockedRequest) {
|
||||
return lockedRequest;
|
||||
}
|
||||
|
||||
let cachedRequest = this.getCachedRequest(request);
|
||||
|
||||
if (cachedRequest) {
|
||||
return cachedRequest;
|
||||
}
|
||||
|
||||
let method = this.getMethodByRequest(request) as RPCMethod;
|
||||
|
||||
let result;
|
||||
let isStream: AsyncIterable<Uint8Array> | boolean = false;
|
||||
const flagIsStream = (stream: AsyncIterable<Uint8Array>) => {
|
||||
isStream = stream;
|
||||
};
|
||||
try {
|
||||
result = await method.handler(request, flagIsStream);
|
||||
} catch (e) {
|
||||
return {
|
||||
error: (e as Error).message,
|
||||
};
|
||||
}
|
||||
|
||||
if (isStream) {
|
||||
result = await streamHandler(isStream);
|
||||
} else {
|
||||
if (result && !result.error && !("data" in result)) {
|
||||
result = { data: result };
|
||||
}
|
||||
}
|
||||
|
||||
result = result as RPCResponse;
|
||||
|
||||
cachedRequest = this.getCachedRequest(request);
|
||||
|
||||
if (!cachedRequest && !isStream && method.cacheable) {
|
||||
this.cacheRequest(request, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async waitOnRequestLock(request: RPCRequest) {
|
||||
let method = this.getMethodByRequest(request) as RPCMethod;
|
||||
if (!method.cacheable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reqId = RPCServer.getRequestId(request);
|
||||
|
||||
let lock: Mutex = this.pendingRequests.get(reqId) as Mutex;
|
||||
const lockExists = !!lock;
|
||||
|
||||
if (!lockExists) {
|
||||
lock = new Mutex();
|
||||
this.pendingRequests.set(reqId, lock);
|
||||
}
|
||||
|
||||
if (lock.isLocked()) {
|
||||
await lock.waitForUnlock();
|
||||
return this.processedRequests.get(reqId) as RPCResponse;
|
||||
}
|
||||
|
||||
await lock.acquire();
|
||||
}
|
||||
|
||||
private getCachedRequest(request: RPCRequest): RPCResponse | undefined {
|
||||
let method = this.getMethodByRequest(request) as RPCMethod;
|
||||
if (!method.cacheable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reqId = RPCServer.getRequestId(request);
|
||||
|
||||
if (!request.bypassCache && this.processedRequests.get(reqId)) {
|
||||
return this.processedRequests.get(reqId) as RPCResponse;
|
||||
}
|
||||
}
|
||||
|
||||
private cacheRequest(request: RPCRequest, response: RPCResponse): void {
|
||||
const reqId = RPCServer.getRequestId(request);
|
||||
|
||||
response.updated = Date.now();
|
||||
|
||||
this.processedRequests.set(reqId, response);
|
||||
}
|
||||
|
||||
private static hash(data: string): string {
|
||||
return crypto.createHash("sha256").update(data).digest("hex");
|
||||
}
|
||||
|
||||
private static getRequestId(request: RPCRequest) {
|
||||
const clonedRequest = Object.assign({}, request) as RPCRequest;
|
||||
|
||||
delete clonedRequest.bypassCache;
|
||||
|
||||
return RPCServer.hash(stringify(clonedRequest));
|
||||
}
|
||||
|
||||
private verifyRequest(request: RPCRequest) {
|
||||
let valid: boolean | Error | RPCMethod = validateRpcRequest(request);
|
||||
|
||||
if (!valid) {
|
||||
return new Error(ajv.errorsText(validateRpcRequest.errors));
|
||||
}
|
||||
|
||||
valid = this.getMethodByRequest(request);
|
||||
|
||||
if (valid instanceof Error) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private getMethodByRequest(request: RPCRequest): Error | RPCMethod {
|
||||
return this.getMethod(request.module, request.method);
|
||||
}
|
||||
|
||||
private getMethod(moduleName: string, method: string): Error | RPCMethod {
|
||||
let item: any = this.methods.get(moduleName);
|
||||
|
||||
if (!item) {
|
||||
return new Error("INVALID_MODULE");
|
||||
}
|
||||
|
||||
item = item.get(method);
|
||||
|
||||
if (!item) {
|
||||
return new Error("INVALID_METHOD");
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
21
src/types.ts
21
src/types.ts
|
@ -1,21 +0,0 @@
|
|||
import { JSONSchemaType } from "ajv";
|
||||
|
||||
// @ts-ignore
|
||||
export const RPC_REQUEST_SCHEMA: JSONSchemaType<RPCRequest> = {
|
||||
type: "object",
|
||||
properties: {
|
||||
module: {
|
||||
type: "string",
|
||||
},
|
||||
method: {
|
||||
type: "string",
|
||||
},
|
||||
data: {
|
||||
type: ["number", "string", "boolean", "object", "array"],
|
||||
},
|
||||
bypassCache: {
|
||||
type: "boolean",
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
};
|
290
yarn.lock
290
yarn.lock
|
@ -436,6 +436,40 @@
|
|||
udx-native "^1.1.0"
|
||||
xache "^1.1.0"
|
||||
|
||||
"@hyperswarm/dht@next":
|
||||
version "5.0.25"
|
||||
resolved "https://registry.yarnpkg.com/@hyperswarm/dht/-/dht-5.0.25.tgz#eb9f4c314715723ed7e7dcec2b3dbe2722fddda2"
|
||||
integrity sha512-x8Fpvp96NSb3M/0Fap2rm70obpNd0fe8oJnwZxJfIvxQtItYFVCrD8URsI+0Fxt4tNINMxnE9h3MaKoaxePP2A==
|
||||
dependencies:
|
||||
"@hyperswarm/secret-stream" "^5.1.0"
|
||||
b4a "^1.3.1"
|
||||
bind-easy "^1.0.1"
|
||||
bogon "^1.0.0"
|
||||
compact-encoding "^2.4.1"
|
||||
compact-encoding-net "^1.0.1"
|
||||
debugging-stream "^2.0.0"
|
||||
dht-rpc "^5.0.1"
|
||||
noise-curve-ed "^1.0.2"
|
||||
noise-handshake "^2.1.0"
|
||||
record-cache "^1.1.1"
|
||||
safety-catch "^1.0.1"
|
||||
sodium-universal "^3.0.4"
|
||||
utp-native "^2.5.3"
|
||||
xache "^1.0.0"
|
||||
|
||||
"@hyperswarm/secret-stream@^5.1.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@hyperswarm/secret-stream/-/secret-stream-5.2.0.tgz#26621646d3f696e81a33a92f61db31b20be9bfd3"
|
||||
integrity sha512-GwgLlbJV0DgvdTm0hPfyM4IWcWqJXIPCgkZ/DAh5CJ0HX8WW/4pDw70h7fRK5zBU1XUT6IYO2QAOeqZS+e9Dvg==
|
||||
dependencies:
|
||||
b4a "^1.1.0"
|
||||
noise-curve-ed "^1.0.2"
|
||||
noise-handshake "^2.1.0"
|
||||
sodium-secretstream "^1.0.0"
|
||||
sodium-universal "^3.0.4"
|
||||
streamx "^2.10.2"
|
||||
timeout-refresh "^2.0.0"
|
||||
|
||||
"@hyperswarm/secret-stream@^6.0.0":
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@hyperswarm/secret-stream/-/secret-stream-6.0.0.tgz#67db820308cc9fed899cb8f5e9f47ae819d5a4e3"
|
||||
|
@ -488,6 +522,30 @@
|
|||
dependencies:
|
||||
bsert "~0.0.10"
|
||||
|
||||
"@lumeweb/dht-cache@https://git.lumeweb.com/LumeWeb/dht-cache.git":
|
||||
version "0.1.0"
|
||||
resolved "https://git.lumeweb.com/LumeWeb/dht-cache.git#323530c4bc136301b94699039452b483360e4c11"
|
||||
dependencies:
|
||||
"@lumeweb/dht-flood" "https://git.lumeweb.com/LumeWeb/dht-flood.git"
|
||||
"@protobuf-ts/plugin" "^2.8.1"
|
||||
b4a "^1.6.1"
|
||||
compact-encoding "^2.11.0"
|
||||
hypercore-crypto "^3.3.0"
|
||||
jsnetworkx "^0.3.4"
|
||||
lru "^3.1.0"
|
||||
ordered-json "^0.1.1"
|
||||
protocol-buffers-encodings "^1.2.0"
|
||||
protomux-rpc "^1.3.0"
|
||||
|
||||
"@lumeweb/dht-flood@https://git.lumeweb.com/LumeWeb/dht-flood.git":
|
||||
version "0.1.0"
|
||||
resolved "https://git.lumeweb.com/LumeWeb/dht-flood.git#21f7f2e67d41cbd0df2f637670d87fe9c827fc8a"
|
||||
dependencies:
|
||||
compact-encoding "^2.11.0"
|
||||
lru "^3.1.0"
|
||||
protocol-buffers-encodings "^1.2.0"
|
||||
protomux-rpc "^1.3.0"
|
||||
|
||||
"@lumeweb/kernel-utils@https://github.com/LumeWeb/kernel-utils.git":
|
||||
version "0.1.0"
|
||||
resolved "https://github.com/LumeWeb/kernel-utils.git#47a39d618e8278c1fff21bc74d7b091c8dc57224"
|
||||
|
@ -498,9 +556,12 @@
|
|||
version "0.1.0"
|
||||
resolved "https://github.com/LumeWeb/pokt-rpc-endpoints.git#0223b743f913aa46e914b1dc237ae2e12571d96d"
|
||||
|
||||
"@lumeweb/relay-types@https://github.com/LumeWeb/relay-types.git":
|
||||
"@lumeweb/relay-types@../relay-types/":
|
||||
version "0.1.0"
|
||||
resolved "https://github.com/LumeWeb/relay-types.git#83b831b62171a28a6d24dfae2df228c3849634f1"
|
||||
|
||||
"@lumeweb/relay-types@https://git.lumeweb.com/LumeWeb/relay-types.git":
|
||||
version "0.1.0"
|
||||
resolved "https://git.lumeweb.com/LumeWeb/relay-types.git#4c618a311dc31e036d3670a37df8f835a22b5e11"
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64@2.1.2":
|
||||
version "2.1.2"
|
||||
|
@ -584,6 +645,42 @@
|
|||
mkdirp "^1.0.4"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
"@protobuf-ts/plugin-framework@^2.8.2":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.2.tgz#8699938576f68d01a9a937aa383db8fdcef6f64d"
|
||||
integrity sha512-ivcJdNVB3Iee8044f8erZGBgmB6ZfQbbKyxRgDBXRVKYxsruLr432WcT5upw9autK9OnlSVLaebi8kDneFXd2g==
|
||||
dependencies:
|
||||
"@protobuf-ts/runtime" "^2.8.2"
|
||||
typescript "^3.9"
|
||||
|
||||
"@protobuf-ts/plugin@^2.8.1":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobuf-ts/plugin/-/plugin-2.8.2.tgz#f65f4362721e6a3bb3ce04f6d9760901e576eaa7"
|
||||
integrity sha512-rTPxaeKBfUar8ubKxbVdv4XL6AcGA0OOgHNHFyrfODP7Epy80omwuvgFJex1YpeNFJxm/FZXXj5Z+nHuhYEqJg==
|
||||
dependencies:
|
||||
"@protobuf-ts/plugin-framework" "^2.8.2"
|
||||
"@protobuf-ts/protoc" "^2.8.2"
|
||||
"@protobuf-ts/runtime" "^2.8.2"
|
||||
"@protobuf-ts/runtime-rpc" "^2.8.2"
|
||||
typescript "^3.9"
|
||||
|
||||
"@protobuf-ts/protoc@^2.8.2":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobuf-ts/protoc/-/protoc-2.8.2.tgz#45809eda3037caff300b9061262444ae7ad891ec"
|
||||
integrity sha512-1e+rOgp22ElyqRWunSc8bhatJcvRe90AGPceVn67IFYzybvfKl17vP1igHddeYkN0dzOucnOrwqn2v1jnDfE2w==
|
||||
|
||||
"@protobuf-ts/runtime-rpc@^2.8.2":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.2.tgz#8af6d5eab44e2fc92cfe9a83a5c351b5f2fcdfbe"
|
||||
integrity sha512-vum/Y7AXdUTWGFu7dke/jCSB9dV3Oo3iVPcce3j7KudpzzWarDkEGvXjKv3Y8zJPj5waToyxwBNSb7eo5Vw5WA==
|
||||
dependencies:
|
||||
"@protobuf-ts/runtime" "^2.8.2"
|
||||
|
||||
"@protobuf-ts/runtime@^2.8.2":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobuf-ts/runtime/-/runtime-2.8.2.tgz#5d5424a6ae7fb846c3f4d0f2dd6448db65bb69d6"
|
||||
integrity sha512-PVxsH81y9kEbHldxxG/8Y3z2mTXWQytRl8zNS0mTPUjkEC+8GUX6gj6LsA8EFp25fAs9V0ruh+aNWmPccEI9MA==
|
||||
|
||||
"@skynetlabs/skynet-nodejs@^2.6.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@skynetlabs/skynet-nodejs/-/skynet-nodejs-2.8.0.tgz#46972beca4a54bfaa87502663aa89baf828d8055"
|
||||
|
@ -649,6 +746,13 @@
|
|||
dependencies:
|
||||
acme-client "*"
|
||||
|
||||
"@types/b4a@^1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/b4a/-/b4a-1.6.0.tgz#91a22117b6c8d79963ed2eed3328143df77c2542"
|
||||
integrity sha512-rYU2r5nSUPyKyufWijxgTjsFp2kLCwydj2TmKU4StJeGPHS/Fs5KHgP89DNF0jddyeAbN5mdjNDqIrjIHca60g==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/body-parser@*":
|
||||
version "1.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
|
||||
|
@ -901,6 +1005,18 @@ b4a@^1.0.1, b4a@^1.1.0, b4a@^1.1.1, b4a@^1.1.4, b4a@^1.3.0, b4a@^1.3.1, b4a@^1.5
|
|||
resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.0.tgz#5430a9cac1af388910dd1a1c1aa9d3a0a796ed68"
|
||||
integrity sha512-fsTxXxj1081Yq5MOQ06gZ5+e2QcSyP2U6NofdOWyq+lrNI4IjkZ+fLVmoQ6uUCiNg1NWePMMVq93vOTdbJmErw==
|
||||
|
||||
b4a@^1.6.0, b4a@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.1.tgz#9effac93a469a868d024e16fd77162c653544cbd"
|
||||
integrity sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA==
|
||||
|
||||
babel-runtime@^5:
|
||||
version "5.8.38"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19"
|
||||
integrity sha512-KpgoA8VE/pMmNCrnEeeXqFG24TIH11Z3ZaimIhJWsin8EbfZy3WzFKUTIan10ZIDgRVvi9EkLbruJElJC9dRlg==
|
||||
dependencies:
|
||||
core-js "^1.0.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
|
@ -942,6 +1058,11 @@ bigint-buffer@^1.1.5:
|
|||
dependencies:
|
||||
bindings "^1.3.0"
|
||||
|
||||
bind-easy@^1.0.0, bind-easy@^1.0.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bind-easy/-/bind-easy-1.1.2.tgz#d10f9be896e53fb84f49465be5b1ab9b089dbcff"
|
||||
integrity sha512-2+VjZ87WFdOFnsH4tHnmtf0HF6D2T3ZNdU1t1FYIz2jt4N3tyqbg2J0bYbflXdBkVi3xfVc8Pm8NB062SPvVVA==
|
||||
|
||||
bindings@^1.3.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
|
||||
|
@ -949,6 +1070,13 @@ bindings@^1.3.0:
|
|||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bits-to-bytes@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/bits-to-bytes/-/bits-to-bytes-1.3.0.tgz#b6b0b547ff5747b0609a42e31a0b57212f09f4e7"
|
||||
integrity sha512-OJoHTpFXS9bXHBCekGTByf3MqM8CGblBDIduKQeeVVeiU9dDWywSSirXIBYGgg3d1zbVuvnMa1vD4r6PA0kOKg==
|
||||
dependencies:
|
||||
b4a "^1.5.0"
|
||||
|
||||
bl@^4.0.3:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
|
||||
|
@ -1222,6 +1350,13 @@ commander@^2.20.3:
|
|||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
compact-encoding-bitfield@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/compact-encoding-bitfield/-/compact-encoding-bitfield-1.0.0.tgz#39f923263dffb68b266b6cb9dc0bae2d42cf5c4a"
|
||||
integrity sha512-3nMVKUg+PF72UHfainmCL8uKvyWfxsjqOtUY+HiMPGLPCTjnwzoKfFAMo1Ad7nwTPdjBqtGK5b3BOFTFW4EBTg==
|
||||
dependencies:
|
||||
compact-encoding "^2.4.1"
|
||||
|
||||
compact-encoding-net@^1.0.1, compact-encoding-net@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/compact-encoding-net/-/compact-encoding-net-1.2.0.tgz#19d2efd55df10f2ee793576fc4483bf6d2218743"
|
||||
|
@ -1268,6 +1403,11 @@ cookie@0.5.0:
|
|||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
core-js@^1.0.0:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||
integrity sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
||||
|
@ -1356,6 +1496,22 @@ detect-libc@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
|
||||
|
||||
dht-rpc@^5.0.1:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/dht-rpc/-/dht-rpc-5.0.6.tgz#f37af2ae965d71d1034f852414673ed86286f7c4"
|
||||
integrity sha512-8NxLsJ3WFoM2D/kQDu/4SOMnsjm/0NmBm4cJgUS9Idj1u/AuvY0bKpTNzUsVR25SdHfSEcbjzDPq40z3I3AVwg==
|
||||
dependencies:
|
||||
b4a "^1.3.1"
|
||||
bind-easy "^1.0.0"
|
||||
compact-encoding "^2.1.0"
|
||||
compact-encoding-net "^1.0.1"
|
||||
fast-fifo "^1.0.0"
|
||||
kademlia-routing-table "^1.0.0"
|
||||
nat-sampler "^1.0.1"
|
||||
sodium-universal "^3.0.4"
|
||||
streamx "^2.10.3"
|
||||
time-ordered-set "^1.0.2"
|
||||
|
||||
dht-rpc@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/dht-rpc/-/dht-rpc-6.3.0.tgz#bd9fbdc0a558182af35eb9c4e92aad38e6a6e68a"
|
||||
|
@ -1918,6 +2074,16 @@ hypercore-crypto@^3.3.0:
|
|||
compact-encoding "^2.5.1"
|
||||
sodium-universal "^3.0.0"
|
||||
|
||||
hyperswarm@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/hyperswarm/-/hyperswarm-3.0.4.tgz#0b0b763bd7dd75dcd045746bd61d9cb5c38eac11"
|
||||
integrity sha512-+wNuhabxPpCRzrP98dtXV/Iwq7TnvcaKYx/yHXaMqZ7qqZOc8j/5aJcUyctT/5hSx0Uflwolit9BIx3L/F800w==
|
||||
dependencies:
|
||||
"@hyperswarm/dht" next
|
||||
b4a "^1.3.1"
|
||||
events "^3.3.0"
|
||||
shuffled-priority-queue "^2.1.0"
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
|
@ -2102,6 +2268,16 @@ jsesc@^2.5.1:
|
|||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
jsnetworkx@^0.3.4:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/jsnetworkx/-/jsnetworkx-0.3.4.tgz#1c0025df94208ceb5cc59e658f9a9bf5fef4f6f4"
|
||||
integrity sha512-3wLBxtTWsgMUADKiEXyVr6s0BNnXBtB+A13cYToatl65OFF9UG1BTOij1Jx7AhK7Q9fbrfFCNppDuSOmTFkB1Q==
|
||||
dependencies:
|
||||
babel-runtime "^5"
|
||||
lodash "^3.3.1"
|
||||
through "^2.3.6"
|
||||
tiny-sprintf "^0.3.0"
|
||||
|
||||
json-schema-traverse@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
|
||||
|
@ -2213,6 +2389,11 @@ lodash.uniqby@4.5.0:
|
|||
lodash._baseiteratee "~4.7.0"
|
||||
lodash._baseuniq "~4.6.0"
|
||||
|
||||
lodash@^3.3.1:
|
||||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
||||
integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==
|
||||
|
||||
lodash@^4.17.20:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
|
@ -2235,6 +2416,13 @@ lru-cache@^7.7.1:
|
|||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.0.tgz#21be64954a4680e303a09e9468f880b98a0b3c7f"
|
||||
integrity sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ==
|
||||
|
||||
lru@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5"
|
||||
integrity sha512-5OUtoiVIGU4VXBOshidmtOsvBIvcQR6FD/RzWSvaeHyxCGB+PCUCu+52lqMfdc0h/2CLvHhZS4TwUmMQrrMbBQ==
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
|
||||
make-fetch-happen@^10.0.3:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164"
|
||||
|
@ -2538,7 +2726,7 @@ node-gyp-build-optional-packages@5.0.3:
|
|||
resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17"
|
||||
integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==
|
||||
|
||||
node-gyp-build@^4.3.0, node-gyp-build@^4.4.0:
|
||||
node-gyp-build@^4.2.0, node-gyp-build@^4.3.0, node-gyp-build@^4.4.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"
|
||||
integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==
|
||||
|
@ -2641,6 +2829,18 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
|||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
ordered-json@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ordered-json/-/ordered-json-0.1.1.tgz#dd5392d6ef6e085fcef2a1ea57a478d30aceef6f"
|
||||
integrity sha512-qw4OYAxofa+WAZAP90eoXftAErUCjs8OII5ddDzKAZBsPMpQvWEIvuKCmUgGV22Cyd3/bT6i12KeuBBZixThDg==
|
||||
dependencies:
|
||||
ordered-object "^0.2.0"
|
||||
|
||||
ordered-object@^0.2.0:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/ordered-object/-/ordered-object-0.2.3.tgz#2e187a7d29f9dfdb2894b695f11899fdaa83a60c"
|
||||
integrity sha512-UKBtJiO7PsKqAAenewZ/moHQIRbcjZ4HE0J/+RyzgnpCTIn5ZLe3N2izno1kViTCXtHB4xuewjPgYLEiuS6t5A==
|
||||
|
||||
p-is-promise@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971"
|
||||
|
@ -2800,7 +3000,26 @@ proper-lockfile@^2.0.1:
|
|||
graceful-fs "^4.1.2"
|
||||
retry "^0.10.0"
|
||||
|
||||
protomux@^3.1.1:
|
||||
protocol-buffers-encodings@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/protocol-buffers-encodings/-/protocol-buffers-encodings-1.2.0.tgz#39900b85dcff3172a23f15bdf3fda70daa2b38d3"
|
||||
integrity sha512-daeNPuKh1NlLD1uDfbLpD+xyUTc07nEtfHwmBZmt/vH0B7VOM+JOCOpDcx9ZRpqHjAiIkGqyTDi+wfGSl17R9w==
|
||||
dependencies:
|
||||
b4a "^1.6.0"
|
||||
signed-varint "^2.0.1"
|
||||
varint "5.0.0"
|
||||
|
||||
protomux-rpc@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/protomux-rpc/-/protomux-rpc-1.3.0.tgz#ffc735f4b05d64b053a7568e64f2c65de948e056"
|
||||
integrity sha512-G+zCpEujLsW+lQ75YXVdPfXKzxnP5F7IceVyz2B1ypWdH4NDf2n2ObkoUjdUrEMWgn+3fjXdY7ehkXLac+mNPQ==
|
||||
dependencies:
|
||||
bits-to-bytes "^1.0.0"
|
||||
compact-encoding "^2.6.1"
|
||||
compact-encoding-bitfield "^1.0.0"
|
||||
protomux "^3.2.1"
|
||||
|
||||
protomux@^3.1.1, protomux@^3.2.1, protomux@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/protomux/-/protomux-3.4.0.tgz#b6269fc15c0bd22964acb6e8f68a002e1da9a370"
|
||||
integrity sha512-jZBytPrL5o+eZeSfIA+5OhPBwfS4A3DucHU4R6KkwFVr2sPqtNoKOX/xXdGzQzHzfVOqbsFfC7oFQ5FqZ6XKWw==
|
||||
|
@ -2922,7 +3141,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.4:
|
|||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
|
@ -3124,6 +3343,13 @@ sha512-wasm@^2.3.1:
|
|||
b4a "^1.0.1"
|
||||
nanoassert "^2.0.0"
|
||||
|
||||
shuffled-priority-queue@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/shuffled-priority-queue/-/shuffled-priority-queue-2.1.0.tgz#432bf14dd90f7c4dd1705752d81aadf454fd3af6"
|
||||
integrity sha512-xhdh7fHyMsr0m/w2kDfRJuBFRS96b9l8ZPNWGaQ+PMvnUnZ/Eh+gJJ9NsHBd7P9k0399WYlCLzsy18EaMfyadA==
|
||||
dependencies:
|
||||
unordered-set "^2.0.1"
|
||||
|
||||
side-channel@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
|
||||
|
@ -3138,6 +3364,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.7:
|
|||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
|
||||
signed-varint@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/signed-varint/-/signed-varint-2.0.1.tgz#50a9989da7c98c2c61dad119bc97470ef8528129"
|
||||
integrity sha512-abgDPg1106vuZZOvw7cFwdCABddfJRz5akcCcchzTbhyhYnsG31y4AlZEgp315T7W3nQq5P4xeOm186ZiPVFzw==
|
||||
dependencies:
|
||||
varint "~5.0.0"
|
||||
|
||||
simple-concat@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
|
||||
|
@ -3254,7 +3487,7 @@ sodium-secretstream@^1.0.0:
|
|||
b4a "^1.1.1"
|
||||
sodium-universal "^3.0.4"
|
||||
|
||||
sodium-universal@^3.0.0, sodium-universal@^3.0.4:
|
||||
sodium-universal@^3.0.0, sodium-universal@^3.0.4, sodium-universal@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/sodium-universal/-/sodium-universal-3.1.0.tgz#f2fa0384d16b7cb99b1c8551a39cc05391a3ed41"
|
||||
integrity sha512-N2gxk68Kg2qZLSJ4h0NffEhp4BjgWHCHXVlDi1aG1hA3y+ZeWEmHqnpml8Hy47QzfL1xLy5nwr9LcsWAg2Ep0A==
|
||||
|
@ -3407,7 +3640,7 @@ text-encoding-utf-8@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13"
|
||||
integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==
|
||||
|
||||
"through@>=2.2.7 <3":
|
||||
"through@>=2.2.7 <3", through@^2.3.6:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
|
||||
|
@ -3417,11 +3650,21 @@ time-ordered-set@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/time-ordered-set/-/time-ordered-set-1.0.2.tgz#3bd931fc048234147f8c2b8b1ebbebb0a3ecb96f"
|
||||
integrity sha512-vGO99JkxvgX+u+LtOKQEpYf31Kj3i/GNwVstfnh4dyINakMgeZCpew1e3Aj+06hEslhtHEd52g7m5IV+o1K8Mw==
|
||||
|
||||
timeout-refresh@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/timeout-refresh/-/timeout-refresh-1.0.3.tgz#7024a8ce0a09a57acc2ea86002048e6c0bff7375"
|
||||
integrity sha512-Mz0CX4vBGM5lj8ttbIFt7o4ZMxk/9rgudJRh76EvB7xXZMur7T/cjRiH2w4Fmkq0zxf2QpM8IFvOSRn8FEu3gA==
|
||||
|
||||
timeout-refresh@^2.0.0, timeout-refresh@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/timeout-refresh/-/timeout-refresh-2.0.1.tgz#f8ec7cf1f9d93b2635b7d4388cb820c5f6c16f98"
|
||||
integrity sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw==
|
||||
|
||||
tiny-sprintf@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/tiny-sprintf/-/tiny-sprintf-0.3.0.tgz#4272fd5c1d2f92807223fc16d728fdf30595a33e"
|
||||
integrity sha512-2GsAMPBTxDYKjJVsK3Do2nLAMV7hteGNTy3CuNbJwRtBGgbzuzlmYIehmzJPaPyj0IsjChgcGutBZcpCe76flg==
|
||||
|
||||
to-data-view@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/to-data-view/-/to-data-view-1.1.0.tgz#08d6492b0b8deb9b29bdf1f61c23eadfa8994d00"
|
||||
|
@ -3474,6 +3717,11 @@ type-is@~1.6.18:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
typescript@^3.9:
|
||||
version "3.9.10"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
|
||||
integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
|
||||
|
||||
typescript@^4.7.4:
|
||||
version "4.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88"
|
||||
|
@ -3509,6 +3757,11 @@ universalify@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
|
||||
unordered-set@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/unordered-set/-/unordered-set-2.0.1.tgz#4cd0fe27b8814bcf5d6073e5f0966ec7a50841e6"
|
||||
integrity sha512-eUmNTPzdx+q/WvOHW0bgGYLWvWHNT3PTKEQLg0MAQhc0AHASHVHoP/9YytYd4RBVariqno/mEUhVZN98CmD7bg==
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
|
@ -3556,11 +3809,32 @@ utils-merge@1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||
|
||||
utp-native@^2.5.3:
|
||||
version "2.5.3"
|
||||
resolved "https://registry.yarnpkg.com/utp-native/-/utp-native-2.5.3.tgz#7c04c2a8c2858716555a77d10adb9819e3119b25"
|
||||
integrity sha512-sWTrWYXPhhWJh+cS2baPzhaZc89zwlWCfwSthUjGhLkZztyPhcQllo+XVVCbNGi7dhyRlxkWxN4NKU6FbA9Y8w==
|
||||
dependencies:
|
||||
napi-macros "^2.0.0"
|
||||
node-gyp-build "^4.2.0"
|
||||
readable-stream "^3.0.2"
|
||||
timeout-refresh "^1.0.0"
|
||||
unordered-set "^2.0.1"
|
||||
|
||||
uuid@8.3.2, uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
varint@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf"
|
||||
integrity sha512-gC13b/bWrqQoKY2EmROCZ+AR0jitc6DnDGaQ6Ls9QpKmuSgJB1eQ7H3KETtQm7qSdMWMKCmsshyCmUwMLh3OAA==
|
||||
|
||||
varint@~5.0.0:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4"
|
||||
integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==
|
||||
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
|
@ -3627,7 +3901,7 @@ ws@^8.5.0:
|
|||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0"
|
||||
integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==
|
||||
|
||||
xache@^1.1.0:
|
||||
xache@^1.0.0, xache@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/xache/-/xache-1.1.0.tgz#afc20dec9ff8b2260eea03f5ad9422dc0200c6e9"
|
||||
integrity sha512-RQGZDHLy/uCvnIrAvaorZH/e6Dfrtxj16iVlGjkj4KD2/G/dNXNqhk5IdSucv5nSSnDK00y8Y/2csyRdHveJ+Q==
|
||||
|
|
Loading…
Reference in New Issue