This commit is contained in:
Thomas E Lackey 2024-03-14 15:54:05 -05:00
parent 6d5be18915
commit 8be899e012
13 changed files with 135 additions and 83 deletions

55
dist/src/cli.js vendored
View File

@ -1,11 +1,16 @@
#!/usr/bin/env ts-node
"use strict";
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-shadow */
import yargs from "yargs/yargs";
import { hideBin } from "yargs/helpers";
import { NitroRpcClient } from "./rpc-client";
import { compactJson, getLocalRPCUrl, logOutChannelUpdates } from "./utils";
yargs(hideBin(process.argv))
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const yargs_1 = __importDefault(require("yargs/yargs"));
const helpers_1 = require("yargs/helpers");
const rpc_client_1 = require("./rpc-client");
const utils_1 = require("./utils");
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
.scriptName("nitro-rpc-client")
.option({
p: { alias: "port", default: 4005, type: "number" },
@ -18,7 +23,7 @@ yargs(hideBin(process.argv))
})
.command("version", "Get the version of the Nitro RPC server", async () => { }, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
const version = await rpcClient.GetVersion();
console.log(version);
await rpcClient.Close();
@ -26,7 +31,7 @@ yargs(hideBin(process.argv))
})
.command("address", "Get the address of the Nitro RPC server", async () => { }, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
const address = await rpcClient.GetAddress();
console.log(address);
await rpcClient.Close();
@ -34,10 +39,10 @@ yargs(hideBin(process.argv))
})
.command("get-all-ledger-channels", "Get all ledger channels", async () => { }, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
const ledgers = await rpcClient.GetAllLedgerChannels();
for (const ledger of ledgers) {
console.log(`${compactJson(ledger)}`);
console.log(`${(0, utils_1.compactJson)(ledger)}`);
}
await rpcClient.Close();
process.exit(0);
@ -50,10 +55,10 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
const paymentChans = await rpcClient.GetPaymentChannelsByLedger(yargs.ledgerId);
for (const p of paymentChans) {
console.log(`${compactJson(p)}`);
console.log(`${(0, utils_1.compactJson)(p)}`);
}
await rpcClient.Close();
process.exit(0);
@ -72,9 +77,9 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
if (yargs.n)
logOutChannelUpdates(rpcClient);
(0, utils_1.logOutChannelUpdates)(rpcClient);
const dfObjective = await rpcClient.CreateLedgerChannel(yargs.counterparty, yargs.amount);
const { Id, ChannelId } = dfObjective;
console.log(`Objective started ${Id}`);
@ -91,9 +96,9 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
if (yargs.n)
logOutChannelUpdates(rpcClient);
(0, utils_1.logOutChannelUpdates)(rpcClient);
const id = await rpcClient.CloseLedgerChannel(yargs.channelId);
console.log(`Objective started ${id}`);
await rpcClient.WaitForPaymentChannelStatus(yargs.channelId, "Complete");
@ -116,9 +121,9 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
if (yargs.n)
logOutChannelUpdates(rpcClient);
(0, utils_1.logOutChannelUpdates)(rpcClient);
// Parse all intermediary args to strings
const intermediaries = yargs.intermediaries?.map((intermediary) => {
if (typeof intermediary === "string") {
@ -142,9 +147,9 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
if (yargs.n)
logOutChannelUpdates(rpcClient);
(0, utils_1.logOutChannelUpdates)(rpcClient);
const id = await rpcClient.ClosePaymentChannel(yargs.channelId);
console.log(`Objective started ${id}`);
await rpcClient.WaitForPaymentChannelStatus(yargs.channelId, "Complete");
@ -160,7 +165,7 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
const ledgerInfo = await rpcClient.GetLedgerChannel(yargs.channelId);
console.log(ledgerInfo);
await rpcClient.Close();
@ -174,7 +179,7 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
const paymentChannelInfo = await rpcClient.GetPaymentChannel(yargs.channelId);
console.log(paymentChannelInfo);
await rpcClient.Close();
@ -194,9 +199,9 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
if (yargs.n)
logOutChannelUpdates(rpcClient);
(0, utils_1.logOutChannelUpdates)(rpcClient);
const paymentChannelInfo = await rpcClient.Pay(yargs.channelId, yargs.amount);
console.log(paymentChannelInfo);
await rpcClient.Close();
@ -216,9 +221,9 @@ yargs(hideBin(process.argv))
});
}, async (yargs) => {
const rpcPort = yargs.p;
const rpcClient = await NitroRpcClient.CreateHttpNitroClient(getLocalRPCUrl(rpcPort));
const rpcClient = await rpc_client_1.NitroRpcClient.CreateHttpNitroClient((0, utils_1.getLocalRPCUrl)(rpcPort));
if (yargs.n)
logOutChannelUpdates(rpcClient);
(0, utils_1.logOutChannelUpdates)(rpcClient);
const voucher = await rpcClient.CreateVoucher(yargs.channelId, yargs.amount);
console.log(voucher);
await rpcClient.Close();

6
dist/src/index.js vendored
View File

@ -1 +1,5 @@
export { NitroRpcClient } from "./rpc-client";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NitroRpcClient = void 0;
var rpc_client_1 = require("./rpc-client");
Object.defineProperty(exports, "NitroRpcClient", { enumerable: true, get: function () { return rpc_client_1.NitroRpcClient; } });

View File

@ -1 +1,2 @@
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -1,7 +1,10 @@
import { createOutcome, generateRequest } from "./utils";
import { HttpTransport } from "./transport/http";
import { getAndValidateResult } from "./serde";
export class NitroRpcClient {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NitroRpcClient = void 0;
const utils_1 = require("./utils");
const http_1 = require("./transport/http");
const serde_1 = require("./serde");
class NitroRpcClient {
transport;
// We fetch the address from the RPC server on first use
myAddress;
@ -14,14 +17,14 @@ export class NitroRpcClient {
Amount: amount,
Channel: channelId,
};
const request = generateRequest("create_voucher", payload, this.authToken || "");
const request = (0, utils_1.generateRequest)("create_voucher", payload, this.authToken || "");
const res = await this.transport.sendRequest(request);
return getAndValidateResult(res, "create_voucher");
return (0, serde_1.getAndValidateResult)(res, "create_voucher");
}
async ReceiveVoucher(voucher) {
const request = generateRequest("receive_voucher", voucher, this.authToken || "");
const request = (0, utils_1.generateRequest)("receive_voucher", voucher, this.authToken || "");
const res = await this.transport.sendRequest(request);
return getAndValidateResult(res, "receive_voucher");
return (0, serde_1.getAndValidateResult)(res, "receive_voucher");
}
async WaitForLedgerChannelStatus(channelId, status) {
const promise = new Promise((resolve) => {
@ -71,7 +74,7 @@ export class NitroRpcClient {
const payload = {
CounterParty: counterParty,
ChallengeDuration: 0,
Outcome: createOutcome(asset, await this.GetAddress(), counterParty, amount),
Outcome: (0, utils_1.createOutcome)(asset, await this.GetAddress(), counterParty, amount),
AppDefinition: asset,
AppData: "0x00",
Nonce: Date.now(),
@ -84,7 +87,7 @@ export class NitroRpcClient {
CounterParty: counterParty,
Intermediaries: intermediaries,
ChallengeDuration: 0,
Outcome: createOutcome(asset, await this.GetAddress(), counterParty, amount),
Outcome: (0, utils_1.createOutcome)(asset, await this.GetAddress(), counterParty, amount),
AppDefinition: asset,
Nonce: Date.now(),
};
@ -95,9 +98,9 @@ export class NitroRpcClient {
Amount: amount,
Channel: channelId,
};
const request = generateRequest("pay", payload, this.authToken || "");
const request = (0, utils_1.generateRequest)("pay", payload, this.authToken || "");
const res = await this.transport.sendRequest(request);
return getAndValidateResult(res, "pay");
return (0, serde_1.getAndValidateResult)(res, "pay");
}
async CloseLedgerChannel(channelId) {
const payload = { ChannelId: channelId };
@ -135,9 +138,9 @@ export class NitroRpcClient {
return this.sendRequest("get_auth_token", {});
}
async sendRequest(method, payload) {
const request = generateRequest(method, payload, this.authToken || "");
const request = (0, utils_1.generateRequest)(method, payload, this.authToken || "");
const res = await this.transport.sendRequest(request);
return getAndValidateResult(res, method);
return (0, serde_1.getAndValidateResult)(res, method);
}
async Close() {
return this.transport.Close();
@ -152,9 +155,10 @@ export class NitroRpcClient {
* @returns A NitroRpcClient that uses WS as the transport
*/
static async CreateHttpNitroClient(url) {
const transport = await HttpTransport.createTransport(url);
const transport = await http_1.HttpTransport.createTransport(url);
const rpcClient = new NitroRpcClient(transport);
rpcClient.authToken = await rpcClient.getAuthToken();
return rpcClient;
}
}
exports.NitroRpcClient = NitroRpcClient;

16
dist/src/serde.js vendored
View File

@ -1,5 +1,11 @@
import Ajv from "ajv/dist/jtd";
const ajv = new Ajv();
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAndValidateNotification = exports.getAndValidateResult = void 0;
const jtd_1 = __importDefault(require("ajv/dist/jtd"));
const ajv = new jtd_1.default();
const jsonRpcSchema = {
properties: {
jsonrpc: { type: "string" },
@ -93,7 +99,7 @@ const receiveVoucherSchema = {
* @param method - JSON RPC method
* @returns The validated result of the JSON RPC response
*/
export function getAndValidateResult(response, method) {
function getAndValidateResult(response, method) {
const { result, error } = getJsonRpcResult(response);
if (error) {
throw new Error("jsonrpc response: " + error.message);
@ -133,7 +139,8 @@ export function getAndValidateResult(response, method) {
throw new Error(`Unknown method: ${method}`);
}
}
export function getAndValidateNotification(data, method) {
exports.getAndValidateResult = getAndValidateResult;
function getAndValidateNotification(data, method) {
switch (method) {
case "payment_channel_updated":
return convertToInternalPaymentChannelType(data);
@ -145,6 +152,7 @@ export function getAndValidateNotification(data, method) {
throw new Error(`Unknown method: ${method}`);
}
}
exports.getAndValidateNotification = getAndValidateNotification;
/**
* Validates that the response is a valid JSON RPC response and pulls out the result
* @param response - JSON RPC response

View File

@ -1,4 +1,6 @@
import { getAndValidateResult } from "./serde";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const serde_1 = require("./serde");
describe("get_address", () => {
it("success: validate response string", () => {
const getAddressResponse = {
@ -6,7 +8,7 @@ describe("get_address", () => {
id: 168513765,
result: "0x111A00868581f73AB42FEEF67D235Ca09ca1E8db",
};
const validatedResponse = getAndValidateResult(getAddressResponse, "get_address");
const validatedResponse = (0, serde_1.getAndValidateResult)(getAddressResponse, "get_address");
expect(validatedResponse).toEqual(getAddressResponse.result);
});
});
@ -38,7 +40,7 @@ describe("get_ledger_channel", () => {
MyBalance: 996998n,
},
};
const validatedResponse = getAndValidateResult(getLedgerChannelResponse, "get_ledger_channel");
const validatedResponse = (0, serde_1.getAndValidateResult)(getLedgerChannelResponse, "get_ledger_channel");
expect(validatedResponse).toEqual(validatedGetLedgerChannelResponse);
});
});
@ -53,7 +55,7 @@ describe("create_ledger_channel", () => {
},
};
try {
getAndValidateResult(failedCreateLedgerResponse, "create_ledger_channel");
(0, serde_1.getAndValidateResult)(failedCreateLedgerResponse, "create_ledger_channel");
}
catch (err) {
if (err instanceof Error) {
@ -73,7 +75,7 @@ describe("create_ledger_channel", () => {
ChannelId: "456",
},
};
const validatedResponse = getAndValidateResult(successCreateLedgerResponse, "create_ledger_channel");
const validatedResponse = (0, serde_1.getAndValidateResult)(successCreateLedgerResponse, "create_ledger_channel");
expect(validatedResponse).toEqual(successCreateLedgerResponse.result);
});
});

View File

@ -1,13 +1,19 @@
import https from "https";
import axios from "axios";
import { w3cwebsocket } from "websocket";
import { EventEmitter } from "eventemitter3";
import { getAndValidateNotification } from "../serde";
export class HttpTransport {
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.unsecureHttpsAgent = exports.HttpTransport = void 0;
const https_1 = __importDefault(require("https"));
const axios_1 = __importDefault(require("axios"));
const websocket_1 = require("websocket");
const eventemitter3_1 = require("eventemitter3");
const serde_1 = require("../serde");
class HttpTransport {
Notifications;
static async createTransport(server) {
// eslint-disable-next-line new-cap
const ws = new w3cwebsocket(`wss://${server}/subscribe`);
const ws = new websocket_1.w3cwebsocket(`wss://${server}/subscribe`);
// throw any websocket errors so we don't fail silently
ws.onerror = (e) => {
console.error("Error with websocket connection to server: " + e);
@ -20,7 +26,7 @@ export class HttpTransport {
}
async sendRequest(req) {
const url = new URL(`https://${this.server}`).toString();
const result = await axios.post(url.toString(), JSON.stringify(req));
const result = await axios_1.default.post(url.toString(), JSON.stringify(req));
return result.data;
}
async Close() {
@ -31,19 +37,21 @@ export class HttpTransport {
constructor(ws, server) {
this.ws = ws;
this.server = server;
this.Notifications = new EventEmitter();
this.Notifications = new eventemitter3_1.EventEmitter();
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data.toString());
const validatedResult = getAndValidateNotification(data.params.payload, data.method);
const validatedResult = (0, serde_1.getAndValidateNotification)(data.params.payload, data.method);
this.Notifications.emit(data.method, validatedResult);
};
}
}
exports.HttpTransport = HttpTransport;
// For testing with self-signed certs, ignore certificate errors. DO NOT use in production.
export function unsecureHttpsAgent() {
function unsecureHttpsAgent() {
// For testing with self-signed certs, ignore certificate errors. DO NOT use in production.
const httpsAgent = new https.Agent({
const httpsAgent = new https_1.default.Agent({
rejectUnauthorized: false,
});
return httpsAgent;
}
exports.unsecureHttpsAgent = unsecureHttpsAgent;

View File

@ -1,2 +1,7 @@
export { HttpTransport } from "./http";
export { NatsTransport } from "./nats";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NatsTransport = exports.HttpTransport = void 0;
var http_1 = require("./http");
Object.defineProperty(exports, "HttpTransport", { enumerable: true, get: function () { return http_1.HttpTransport; } });
var nats_1 = require("./nats");
Object.defineProperty(exports, "NatsTransport", { enumerable: true, get: function () { return nats_1.NatsTransport; } });

View File

@ -1,13 +1,16 @@
import { connect, JSONCodec } from "nats";
import { EventEmitter } from "eventemitter3";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NatsTransport = void 0;
const nats_1 = require("nats");
const eventemitter3_1 = require("eventemitter3");
const NITRO_REQUEST_TOPIC = "nitro-request";
const NITRO_NOTIFICATION_TOPIC = "nitro-notify";
export class NatsTransport {
class NatsTransport {
natsConn;
natsSub;
notifications = new EventEmitter();
notifications = new eventemitter3_1.EventEmitter();
static async createTransport(server) {
const natConn = await connect({ servers: server });
const natConn = await (0, nats_1.connect)({ servers: server });
const natsSub = natConn.subscribe(NITRO_NOTIFICATION_TOPIC);
const transport = new NatsTransport(natConn, natsSub);
// Start listening for messages without blocking
@ -24,7 +27,7 @@ export class NatsTransport {
async listenForMessages(sub) {
for await (const msg of sub) {
msg.data;
const notif = JSONCodec().decode(msg.data);
const notif = (0, nats_1.JSONCodec)().decode(msg.data);
switch (notif.method) {
case "objective_completed":
this.notifications.emit(notif.method, notif);
@ -39,11 +42,11 @@ export class NatsTransport {
}
}
async sendRequest(req) {
const natsRes = await this.natsConn?.request(NITRO_REQUEST_TOPIC, JSONCodec().encode(req));
const natsRes = await this.natsConn?.request(NITRO_REQUEST_TOPIC, (0, nats_1.JSONCodec)().encode(req));
if (!natsRes) {
throw new Error("No response");
}
const decoded = JSONCodec().decode(natsRes?.data);
const decoded = (0, nats_1.JSONCodec)().decode(natsRes?.data);
return decoded;
}
async Close() {
@ -51,3 +54,4 @@ export class NatsTransport {
await this.natsConn.close();
}
}
exports.NatsTransport = NatsTransport;

3
dist/src/types.js vendored
View File

@ -1 +1,2 @@
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

25
dist/src/utils.js vendored
View File

@ -1,4 +1,7 @@
export const RPC_PATH = "api/v1";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.compactJson = exports.logOutChannelUpdates = exports.getLocalRPCUrl = exports.generateRequest = exports.convertAddressToBytes32 = exports.createOutcome = exports.RPC_PATH = void 0;
exports.RPC_PATH = "api/v1";
/**
* createOutcome creates a basic outcome for a channel
*
@ -8,7 +11,7 @@ export const RPC_PATH = "api/v1";
* @param amount - The amount to allocate to each participant
* @returns An outcome for a directly funded channel with 100 wei allocated to each participant
*/
export function createOutcome(asset, alpha, beta, amount) {
function createOutcome(asset, alpha, beta, amount) {
return [
{
Asset: asset,
@ -33,6 +36,7 @@ export function createOutcome(asset, alpha, beta, amount) {
},
];
}
exports.createOutcome = createOutcome;
/**
* Left pads a 20 byte address hex string with zeros until it is a 32 byte hex string
* e.g.,
@ -42,10 +46,11 @@ export function createOutcome(asset, alpha, beta, amount) {
* @param address - 20 byte hex string
* @returns 32 byte padded hex string
*/
export function convertAddressToBytes32(address) {
function convertAddressToBytes32(address) {
const digits = address.startsWith("0x") ? address.substring(2) : address;
return `0x${digits.padStart(24, "0")}`;
}
exports.convertAddressToBytes32 = convertAddressToBytes32;
/**
* generateRequest is a helper function that generates a request object for the given method and payloads
*
@ -53,7 +58,7 @@ export function convertAddressToBytes32(address) {
* @param payload - The payloads to include in the request
* @returns A request object of the correct type
*/
export function generateRequest(method, payload, authToken) {
function generateRequest(method, payload, authToken) {
return {
jsonrpc: "2.0",
method,
@ -62,10 +67,12 @@ export function generateRequest(method, payload, authToken) {
id: Date.now() % 1_000_000_000,
}; // TODO: We shouldn't have to cast here
}
export function getLocalRPCUrl(port) {
return `127.0.0.1:${port}/${RPC_PATH}`;
exports.generateRequest = generateRequest;
function getLocalRPCUrl(port) {
return `127.0.0.1:${port}/${exports.RPC_PATH}`;
}
export async function logOutChannelUpdates(rpcClient) {
exports.getLocalRPCUrl = getLocalRPCUrl;
async function logOutChannelUpdates(rpcClient) {
const shortAddress = (await rpcClient.GetAddress()).slice(0, 8);
rpcClient.Notifications.on("ledger_channel_updated", (info) => {
console.log(`${shortAddress}: Ledger channel update\n${prettyJson(info)}`);
@ -74,9 +81,11 @@ export async function logOutChannelUpdates(rpcClient) {
console.log(`${shortAddress}: Payment channel update\n${prettyJson(info)}`);
});
}
exports.logOutChannelUpdates = logOutChannelUpdates;
function prettyJson(obj) {
return JSON.stringify(obj, null, 2);
}
export function compactJson(obj) {
function compactJson(obj) {
return JSON.stringify(obj, null, 0);
}
exports.compactJson = compactJson;

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,7 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,