Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 2 additions & 20 deletions packages/cli/src/cli/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,12 @@ import type {
const DEFAULT_ACCOUNT_POINTER_FILE = ".default";
const KEYSTORE_FILE_EXTENSION = ".json";

import { getMergedOptions } from "./jsonHelpers";

const MNEMONIC_PROMPT = "mnemonic";
const KEY_URI_PROMPT = "key-uri";
const AUTH_TYPE_UNKNOWN: AuthType = "unknown";

function getMergedOptions(command: Command | undefined, fallback: CommandOptions): CommandOptions {
const mergedOptions: CommandOptions = { ...(fallback ?? {}) };

let currentCommand: Command | null | undefined = command?.parent;
while (currentCommand) {
if (typeof currentCommand.opts === "function") {
const parentOptions = currentCommand.opts() as CommandOptions;
for (const key in parentOptions) {
const optionKey = key as keyof CommandOptions;
if (!(optionKey in mergedOptions) && parentOptions[optionKey] !== undefined) {
mergedOptions[optionKey] = parentOptions[optionKey];
}
}
}
currentCommand = currentCommand.parent;
}

return mergedOptions;
}

function resolvePasswordForCreate(options: CommandOptions): Promise<string> | string {
const fromCli = String(options.password ?? "").trim();
if (fromCli) return fromCli;
Expand Down
77 changes: 1 addition & 76 deletions packages/cli/src/cli/commands/bulletin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type {
BulletinReporterMode,
BulletinRetryHandler,
BulletinUploadOptions,
CommandOptions,
UploadProfiler,
UploadProfilerOptions,
UploadProfileReport,
Expand Down Expand Up @@ -68,7 +67,7 @@ import {
DEFAULT_AUTHORIZATION_TRANSACTIONS,
DEFAULT_AUTHORIZATION_BYTES,
} from "../../utils/constants";
import { getJsonFlag } from "./lookup";
import { getJsonFlag, getMergedOptions, withCapturedConsole } from "./jsonHelpers";
import { clampChunkSizeBytes } from "../../bulletin/store";
import {
createCliReporter,
Expand All @@ -79,28 +78,6 @@ import {
type ResolvedReporterMode,
} from "../reporter";

function getMergedOptions(
command: Command | undefined,
fallback: BulletinUploadOptions,
): CommandOptions & BulletinUploadOptions {
const mergedOptions: any = { ...(fallback ?? {}) };

let currentCommand: Command | null | undefined = command?.parent;
while (currentCommand) {
if (typeof currentCommand.opts === "function") {
const parentOptions = currentCommand.opts();
for (const key in parentOptions) {
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
mergedOptions[key] = parentOptions[key];
}
}
}
currentCommand = currentCommand.parent;
}

return mergedOptions;
}

const PROFILE_SAMPLE_INTERVAL_MS = 2_000;

function addReporterOption(command: Command): Command {
Expand Down Expand Up @@ -236,58 +213,6 @@ export function createUploadProfiler(options: UploadProfilerOptions): UploadProf
};
}

export async function withCapturedConsole<T>(callback: () => Promise<T>): Promise<T> {
const MAX_CAPTURED_ENTRIES = 400;
const captured: string[] = [];
const pushCaptured = (value: string) => {
captured.push(value);
if (captured.length > MAX_CAPTURED_ENTRIES) {
captured.splice(0, captured.length - MAX_CAPTURED_ENTRIES);
}
};
const capture = (...args: any[]) => {
pushCaptured(args.map(String).join(" "));
};
const captureWrite = (chunk: any) => {
pushCaptured(String(chunk));
return true;
};

const saved = {
log: console.log,
error: console.error,
warn: console.warn,
info: console.info,
stdoutWrite: process.stdout.write.bind(process.stdout),
stderrWrite: process.stderr.write.bind(process.stderr),
};

console.log = capture;
console.error = capture;
console.warn = capture;
console.info = capture;
process.stdout.write = captureWrite as any;
process.stderr.write = captureWrite as any;

try {
return await callback();
} catch (error) {
saved.error("[captured output before failure]\n" + captured.join("\n"));
throw error;
} finally {
console.log = saved.log;
console.error = saved.error;
console.warn = saved.warn;
console.info = saved.info;
process.stdout.write = saved.stdoutWrite;
process.stderr.write = saved.stderrWrite;
}
}

export function maybeQuiet<T>(jsonOutput: boolean, callback: () => Promise<T>): Promise<T> {
return jsonOutput ? withCapturedConsole(callback) : callback();
}

async function withBulletinHumanOutput<T>(
reporterMode: ResolvedReporterMode,
callback: () => Promise<T>,
Expand Down
82 changes: 41 additions & 41 deletions packages/cli/src/cli/commands/content.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Command } from "commander";
import chalk from "chalk";
import type { CommandOptions } from "../../types/types";
import { viewDomainContentHash, setDomainContentHash } from "../../commands/contentHash";
import { addAuthOptions } from "./authOptions";
import { prepareContext } from "../context";
import { prepareReadOnlyContext } from "./lookup";
import { formatErrorMessage } from "../../utils/formatting";
import {
getMergedOptions,
getJsonFlag,
maybeQuiet,
emitJsonResult,
handleCommandError,
} from "./jsonHelpers";
import ora from "ora";

export interface ContentViewOptions {
Expand All @@ -16,86 +21,81 @@ export interface ContentSetOptions {
rpc?: string;
}

function getMergedOptions<T>(command: Command | undefined, fallback: T): CommandOptions & T {
const mergedOptions: any = { ...(fallback ?? {}) };

let currentCommand: Command | null | undefined = command?.parent;
while (currentCommand) {
if (typeof currentCommand.opts === "function") {
const parentOptions = currentCommand.opts();
for (const key in parentOptions) {
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
mergedOptions[key] = parentOptions[key];
}
}
}
currentCommand = currentCommand.parent;
}

return mergedOptions;
}

export function attachContentCommands(root: Command) {
const contentCommand = root.command("content").description("Manage domain content hashes");

addAuthOptions(contentCommand);

const viewContentCommand = contentCommand
.command("view <name>")
.description("View domain content hash");
.description("View domain content hash")
.option("--json", "Output result as JSON (suppresses all other output)", false);
addAuthOptions(viewContentCommand).action(
async (name: string, options: ContentViewOptions, command: Command) => {
const jsonOutput = getJsonFlag(command);
try {
const mergedOptions = getMergedOptions(command, options);

const context = await prepareReadOnlyContext(mergedOptions as any);
const context = await maybeQuiet(jsonOutput, () =>
prepareReadOnlyContext(mergedOptions as any),
);

console.log(chalk.bold("\n▶ Content View\n"));
if (!jsonOutput) console.log(chalk.bold("\n▶ Content View\n"));
const spinner = ora();

await viewDomainContentHash(context.clientWrapper!, context.account.address, name, spinner);
const result = await maybeQuiet(jsonOutput, () =>
viewDomainContentHash(context.clientWrapper!, context.account.address, name, spinner),
);

console.log(chalk.green("\n✓ Complete\n"));
if (!emitJsonResult(jsonOutput, result)) {
console.log(chalk.green("\n✓ Complete\n"));
}
process.exit(0);
} catch (error) {
console.error(chalk.red(`\n✗ Error: ${formatErrorMessage(error)}\n`));
process.exit(1);
handleCommandError(jsonOutput, error);
}
},
);

const setContentCommand = contentCommand
.command("set <name> <cid>")
.description("Set domain content hash (IPFS CID)");
.description("Set domain content hash (IPFS CID)")
.option("--json", "Output result as JSON (suppresses all other output)", false);

addAuthOptions(setContentCommand).action(
async (name: string, cid: string, options: ContentSetOptions, command: Command) => {
const jsonOutput = getJsonFlag(command);
try {
const mergedOptions = getMergedOptions(command, options);

if (mergedOptions.mnemonic && mergedOptions.keyUri) {
throw new Error("Cannot specify both --mnemonic and --key-uri");
}

const context = await prepareContext({ ...mergedOptions, useRevive: true });
const context = await maybeQuiet(jsonOutput, () =>
prepareContext({ ...mergedOptions, useRevive: true }),
);

console.log(chalk.bold("\n▶ Content Set\n"));
if (!jsonOutput) console.log(chalk.bold("\n▶ Content Set\n"));
const spinner = ora();

await setDomainContentHash(
context.clientWrapper!,
context.substrateAddress,
context.signer,
name,
cid,
spinner,
const result = await maybeQuiet(jsonOutput, () =>
setDomainContentHash(
context.clientWrapper!,
context.substrateAddress,
context.signer,
name,
cid,
spinner,
),
);

console.log(chalk.green("\n✓ Complete\n"));
if (!emitJsonResult(jsonOutput, result)) {
console.log(chalk.green("\n✓ Complete\n"));
}
process.exit(0);
} catch (error) {
console.error(chalk.red(`\n✗ Error: ${formatErrorMessage(error)}\n`));
process.exit(1);
handleCommandError(jsonOutput, error);
}
},
);
Expand Down
23 changes: 2 additions & 21 deletions packages/cli/src/cli/commands/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,14 @@ import { resolveRpc, resolveKeystorePath } from "../env";
import { formatErrorMessage } from "../../utils/formatting";
import { resolveAuthSource, createAccountFromSource } from "../../commands/auth";
import { step } from "../ui";
import { getJsonFlag, prepareReadOnlyContext } from "./lookup";
import { maybeQuiet } from "./bulletin";
import { prepareReadOnlyContext } from "./lookup";
import { getJsonFlag, getMergedOptions, maybeQuiet } from "./jsonHelpers";
import {
checkAccountMapped,
checkWhitelisted,
whitelistAddress,
} from "../../commands/accountChecks";

function getMergedOptions<T>(command: Command | undefined, fallback: T): CommandOptions & T {
const mergedOptions: any = { ...(fallback ?? {}) };

let currentCommand: Command | null | undefined = command?.parent;
while (currentCommand) {
if (typeof currentCommand.opts === "function") {
const parentOptions = currentCommand.opts();
for (const key in parentOptions) {
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
mergedOptions[key] = parentOptions[key];
}
}
}
currentCommand = currentCommand.parent;
}

return mergedOptions;
}

export function attachAccountCommands(root: Command) {
const accountCommand = root.command("account").description("Account management utilities");

Expand Down
Loading
Loading