Skip to content

Commit a8d4ace

Browse files
authored
chore: initial commit (#186)
## Description resolves paritytech/dotns#136 ## Type - [ ] Bug fix - [x] Feature - [ ] Breaking change - [ ] Documentation - [ ] Chore ## Package - [ ] `@parity/dotns-cli` - [ ] Root/monorepo - [ ] Documentation ## Related Issues ## Fixes ## Checklist ### Code - [x] Follows project style - [x] `bun run lint` passes - [x] `bun run format` passes - [x] `bun run typecheck` passes ### Documentation - [ ] README updated if needed - [ ] Types updated if needed ### Breaking Changes - [ ] No breaking changes - [ ] Breaking changes documented below **Breaking changes:** ## Testing How to test: 1. 2. ## Notes
1 parent 5d635a8 commit a8d4ace

68 files changed

Lines changed: 2432 additions & 3797 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/cli/package.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"benchmark": "bun benchmarks/benchmark.ts",
2323
"benchmark:dashboard": "bun benchmarks/generate-dashboard.ts",
2424
"build": "bun build src/cli/index.ts --outfile dist/cli.tmp.js --target node --format esm && echo '#!/usr/bin/env node' | cat - dist/cli.tmp.js > dist/cli.js && rm dist/cli.tmp.js && chmod +x dist/cli.js",
25-
"prepublishOnly": "bun run build",
25+
"build:lib": "bun build src/core/index.ts --outfile dist/core/index.js --target node --format esm && bun build src/core/keyring.ts --outfile dist/core/keyring.js --target node --format esm && bunx tsc -p tsconfig.build.json --emitDeclarationOnly",
26+
"prepublishOnly": "bun run build && bun run build:lib",
2627
"prepare": "bunx papi generate"
2728
},
2829
"engines": {
@@ -35,7 +36,15 @@
3536
"dotns": "./dist/cli.js"
3637
},
3738
"exports": {
38-
".": "./dist/cli.js"
39+
".": "./dist/cli.js",
40+
"./core": {
41+
"types": "./dist/src/core/index.d.ts",
42+
"import": "./dist/core/index.js"
43+
},
44+
"./core/keyring": {
45+
"types": "./dist/src/core/keyring.d.ts",
46+
"import": "./dist/core/keyring.js"
47+
}
3948
},
4049
"devDependencies": {
4150
"@polkadot-api/descriptors": "file:.papi/descriptors",

packages/cli/src/bulletin/cid.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ export const HASH = {
1414
BLAKE2B_256: 0xb220,
1515
} as const;
1616

17-
export const HASH_LENGTH = 32;
17+
const HASH_LENGTH = 32;
1818

19-
export function computeHash(data: Uint8Array, hashCode: number): Uint8Array {
19+
function computeHash(data: Uint8Array, hashCode: number): Uint8Array {
2020
switch (hashCode) {
2121
case HASH.SHA2_256:
2222
return sha256(data);

packages/cli/src/bulletin/cidHistory.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { promises as fs } from "node:fs";
22
import path from "node:path";
33
import os from "node:os";
4-
import { PREVIEW_BASE_URL } from "../utils/constants";
4+
import { getActiveDotnsEnvironment } from "../utils/constants";
55
import type { UploadRecord } from "../types/types";
66

77
const HISTORY_DIR = path.join(os.homedir(), ".dotns");
88
const HISTORY_FILE = path.join(HISTORY_DIR, "uploads.json");
99

10-
export function formatLocalTimestamp(date: Date): string {
10+
function formatLocalTimestamp(date: Date): string {
1111
const months = [
1212
"January",
1313
"February",
@@ -55,7 +55,7 @@ export async function readHistory(): Promise<UploadRecord[]> {
5555
}
5656
}
5757

58-
export async function writeHistory(records: UploadRecord[]): Promise<void> {
58+
async function writeHistory(records: UploadRecord[]): Promise<void> {
5959
await ensureHistoryDir();
6060
await fs.writeFile(HISTORY_FILE, JSON.stringify(records, null, 2));
6161
}
@@ -107,7 +107,11 @@ function encodeForPreview(cid: string): string {
107107
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
108108
}
109109

110-
export function getPreviewUrl(record: UploadRecord): string {
110+
// Null when the active environment has no web app (e.g. previewnet): callers omit
111+
// the preview link rather than emit a wrong-network or broken URL.
112+
export function getPreviewUrl(record: UploadRecord): string | null {
113+
const { previewBaseUrl } = getActiveDotnsEnvironment();
114+
if (!previewBaseUrl) return null;
111115
const encoded = encodeForPreview(record.cid);
112-
return `${PREVIEW_BASE_URL}/${encoded}`;
116+
return `${previewBaseUrl}/${encoded}`;
113117
}

packages/cli/src/bulletin/uploadManifest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ async function listManifestFiles(): Promise<string[]> {
164164
}
165165
}
166166

167-
export async function loadManifest(
167+
async function loadManifest(
168168
target: string | UploadManifestIdentity,
169169
): Promise<UploadManifest | null> {
170170
if (typeof target === "string") {

packages/cli/src/bulletin/uploadRetry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const RECONNECT_REQUIRED_UPLOAD_ERROR_MARKERS = [
5151
"aborted",
5252
] as const;
5353

54-
export type UploadRetryAttemptContext = {
54+
type UploadRetryAttemptContext = {
5555
retry: number;
5656
nextAttempt: number;
5757
totalAttempts: number;

packages/cli/src/cli/commands/bulletin.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ export function attachBulletinCommands(root: Command): void {
984984
writeBulletinJson({
985985
cid,
986986
contenthash: `0x${contenthash}`,
987-
preview: previewUrl,
987+
preview: previewUrl ?? undefined,
988988
path: resolvedPath,
989989
type: isDirectory ? "directory" : "file",
990990
size: uploadSize,
@@ -996,7 +996,9 @@ export function attachBulletinCommands(root: Command): void {
996996
});
997997
} else {
998998
console.log(chalk.gray("\n cid: ") + chalk.cyan(cid));
999-
console.log(chalk.gray(" preview: ") + chalk.blue(previewUrl));
999+
if (previewUrl) {
1000+
console.log(chalk.gray(" preview: ") + chalk.blue(previewUrl));
1001+
}
10001002
console.log(
10011003
chalk.gray(" total time: ") + chalk.white(formatDuration(totalUploadTimeSeconds)),
10021004
);
@@ -1227,7 +1229,10 @@ export function attachBulletinCommands(root: Command): void {
12271229
if (record.size > 0) {
12281230
console.log(chalk.gray(" size: ") + chalk.white(formatBytes(record.size)));
12291231
}
1230-
console.log(chalk.gray(" preview: ") + chalk.blue(getPreviewUrl(record)));
1232+
const recordPreviewUrl = getPreviewUrl(record);
1233+
if (recordPreviewUrl) {
1234+
console.log(chalk.gray(" preview: ") + chalk.blue(recordPreviewUrl));
1235+
}
12311236
console.log();
12321237
});
12331238

packages/cli/src/cli/commands/content.ts

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { printCommandHeader } from "../ui";
12
import { Command } from "commander";
23
import chalk from "chalk";
3-
import { viewDomainContentHash, setDomainContentHash } from "../../commands/contentHash";
4+
import { getContentHash, setContentHash } from "../../commands/contentHash";
45
import { addAuthOptions } from "./authOptions";
5-
import { prepareContext } from "../context";
6+
import { buildDotnsContext, prepareContext } from "../context";
67
import { prepareReadOnlyContext } from "./lookup";
8+
import { makeOnStatus } from "../txStatus";
79
import { dotliViewUrls } from "../../utils/constants";
810
import {
911
getMergedOptions,
@@ -14,11 +16,11 @@ import {
1416
} from "./jsonHelpers";
1517
import ora from "ora";
1618

17-
export interface ContentViewOptions {
19+
interface ContentViewOptions {
1820
rpc?: string;
1921
}
2022

21-
export interface ContentSetOptions {
23+
interface ContentSetOptions {
2224
rpc?: string;
2325
}
2426

@@ -41,14 +43,25 @@ export function attachContentCommands(root: Command) {
4143
prepareReadOnlyContext(mergedOptions as any),
4244
);
4345

44-
if (!jsonOutput) console.log(chalk.bold("\n▶ Content View\n"));
46+
if (!jsonOutput) printCommandHeader("Content View");
4547
const spinner = ora();
46-
47-
const result = await maybeQuiet(jsonOutput, () =>
48-
viewDomainContentHash(context.clientWrapper!, context.account.address, name, spinner),
48+
const ctx = buildDotnsContext(
49+
{ ...context, substrateAddress: context.account.address, signer: undefined } as any,
50+
{ onStatus: makeOnStatus(spinner, "content hash") },
4951
);
5052

53+
const result = await maybeQuiet(jsonOutput, () => getContentHash(ctx, name));
54+
5155
if (!emitJsonResult(jsonOutput, result)) {
56+
console.log(chalk.gray(" domain: ") + chalk.cyan(result.domain));
57+
console.log(
58+
chalk.gray(" contenthash: ") +
59+
(result.contenthash ? chalk.white(result.contenthash) : chalk.yellow("(not set)")),
60+
);
61+
console.log(
62+
chalk.gray(" cid: ") +
63+
(result.cid ? chalk.cyan(result.cid) : chalk.yellow("(not set)")),
64+
);
5265
console.log(chalk.green("\n✓ Complete\n"));
5366
}
5467
process.exit(0);
@@ -77,21 +90,18 @@ export function attachContentCommands(root: Command) {
7790
prepareContext({ ...mergedOptions, useRevive: true }),
7891
);
7992

80-
if (!jsonOutput) console.log(chalk.bold("\n▶ Content Set\n"));
93+
if (!jsonOutput) printCommandHeader("Content Set");
8194
const spinner = ora();
95+
const ctx = buildDotnsContext(context as any, {
96+
onStatus: makeOnStatus(spinner, "content hash"),
97+
});
8298

83-
const result = await maybeQuiet(jsonOutput, () =>
84-
setDomainContentHash(
85-
context.clientWrapper!,
86-
context.substrateAddress,
87-
context.signer,
88-
name,
89-
cid,
90-
spinner,
91-
),
92-
);
99+
const result = await maybeQuiet(jsonOutput, () => setContentHash(ctx, name, cid));
93100

94101
if (!emitJsonResult(jsonOutput, result)) {
102+
console.log(chalk.gray(" domain: ") + chalk.cyan(result.domain));
103+
console.log(chalk.gray(" cid: ") + chalk.cyan(result.cid));
104+
console.log(chalk.gray(" tx: ") + chalk.blue(result.txHash));
95105
console.log(chalk.green("\n✓ Complete\n"));
96106
console.log(chalk.gray(" View on dot.li:"));
97107
for (const url of dotliViewUrls(name)) {

packages/cli/src/cli/commands/delegate.ts

Lines changed: 28 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { printCommandHeader } from "../ui";
12
import { Command } from "commander";
23
import chalk from "chalk";
34
import ora from "ora";
@@ -11,7 +12,8 @@ import {
1112
} from "../../commands/delegate";
1213
import { resolveTransferRecipient } from "../transfer";
1314
import { addAuthOptions } from "./authOptions";
14-
import { prepareContext } from "../context";
15+
import { prepareAssetHubContext, buildDotnsContext, buildReadOnlyDotnsContext } from "../context";
16+
import { makeOnStatus } from "../txStatus";
1517
import { prepareReadOnlyContext } from "./lookup";
1618
import {
1719
getMergedOptions,
@@ -44,15 +46,14 @@ export function attachDelegateCommands(root: Command) {
4446
const jsonOutput = getJsonFlag(command);
4547
try {
4648
const mergedOptions = getMergedOptions(command, options);
47-
const context = await maybeQuiet(jsonOutput, () =>
48-
prepareContext({ ...mergedOptions, useRevive: true }),
49-
);
49+
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(mergedOptions));
5050

51-
if (!jsonOutput) console.log(chalk.bold("\n▶ Delegate name\n"));
51+
if (!jsonOutput) printCommandHeader("Delegate name");
5252
const spinner = ora();
53+
const ctx = buildDotnsContext(context, { onStatus: makeOnStatus(spinner, "Delegating") });
5354

5455
const delegateAddress = await maybeQuiet(jsonOutput, () =>
55-
resolveTransferRecipient(context.clientWrapper!, context.substrateAddress, delegate),
56+
resolveTransferRecipient(ctx, delegate),
5657
);
5758

5859
if (!jsonOutput) {
@@ -61,14 +62,7 @@ export function attachDelegateCommands(root: Command) {
6162
}
6263

6364
const result = await maybeQuiet(jsonOutput, () =>
64-
setNameDelegate(
65-
context.clientWrapper!,
66-
context.substrateAddress,
67-
context.signer,
68-
name,
69-
delegateAddress as Address,
70-
spinner,
71-
),
65+
setNameDelegate(ctx, name, delegateAddress as Address),
7266
);
7367

7468
if (!emitJsonResult(jsonOutput, result)) {
@@ -91,22 +85,15 @@ export function attachDelegateCommands(root: Command) {
9185
const jsonOutput = getJsonFlag(command);
9286
try {
9387
const mergedOptions = getMergedOptions(command, options);
94-
const context = await maybeQuiet(jsonOutput, () =>
95-
prepareContext({ ...mergedOptions, useRevive: true }),
96-
);
88+
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(mergedOptions));
9789

98-
if (!jsonOutput) console.log(chalk.bold("\n▶ Revoke delegate\n"));
90+
if (!jsonOutput) printCommandHeader("Revoke delegate");
9991
const spinner = ora();
92+
const ctx = buildDotnsContext(context, {
93+
onStatus: makeOnStatus(spinner, "Revoking delegate on"),
94+
});
10095

101-
const result = await maybeQuiet(jsonOutput, () =>
102-
revokeNameDelegate(
103-
context.clientWrapper!,
104-
context.substrateAddress,
105-
context.signer,
106-
name,
107-
spinner,
108-
),
109-
);
96+
const result = await maybeQuiet(jsonOutput, () => revokeNameDelegate(ctx, name));
11097

11198
if (!emitJsonResult(jsonOutput, result)) {
11299
console.log(chalk.gray(" name: ") + chalk.cyan(result.name));
@@ -133,12 +120,11 @@ export function attachDelegateCommands(root: Command) {
133120
prepareReadOnlyContext(mergedOptions as never),
134121
);
135122

136-
if (!jsonOutput) console.log(chalk.bold("\n▶ Delegate status\n"));
123+
if (!jsonOutput) printCommandHeader("Delegate status");
137124
const spinner = ora();
125+
const ctx = buildReadOnlyDotnsContext(context, { onStatus: makeOnStatus(spinner) });
138126

139-
const delegate = await maybeQuiet(jsonOutput, () =>
140-
getNameDelegate(context.clientWrapper!, context.account.address, name, spinner),
141-
);
127+
const delegate = await maybeQuiet(jsonOutput, () => getNameDelegate(ctx, name));
142128

143129
if (!emitJsonResult(jsonOutput, { name, delegate })) {
144130
if (delegate === null) {
@@ -167,35 +153,27 @@ export function attachDelegateCommands(root: Command) {
167153
const jsonOutput = getJsonFlag(command);
168154
try {
169155
const mergedOptions = getMergedOptions(command, options);
170-
const context = await maybeQuiet(jsonOutput, () =>
171-
prepareContext({ ...mergedOptions, useRevive: true }),
172-
);
156+
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(mergedOptions));
173157

174158
const approved = !options.revoke;
175159
if (!jsonOutput) {
176-
console.log(
177-
chalk.bold(approved ? "\n▶ Delegate records\n" : "\n▶ Revoke record delegate\n"),
178-
);
160+
printCommandHeader(approved ? "Delegate records" : "Revoke record delegate");
179161
}
180162
const spinner = ora();
163+
const ctx = buildDotnsContext(context, {
164+
onStatus: makeOnStatus(spinner, "Delegating record control to"),
165+
});
181166

182167
const operatorAddress = await maybeQuiet(jsonOutput, () =>
183-
resolveTransferRecipient(context.clientWrapper!, context.substrateAddress, operator),
168+
resolveTransferRecipient(ctx, operator),
184169
);
185170

186171
if (!jsonOutput) {
187172
console.log(chalk.gray(" operator: ") + chalk.white(operatorAddress));
188173
}
189174

190175
const result = await maybeQuiet(jsonOutput, () =>
191-
setRecordDelegate(
192-
context.clientWrapper!,
193-
context.substrateAddress,
194-
context.signer,
195-
operatorAddress as Address,
196-
approved,
197-
spinner,
198-
),
176+
setRecordDelegate(ctx, operatorAddress as Address, approved),
199177
);
200178

201179
if (!emitJsonResult(jsonOutput, result)) {
@@ -222,20 +200,16 @@ export function attachDelegateCommands(root: Command) {
222200
prepareReadOnlyContext(mergedOptions as never),
223201
);
224202

225-
if (!jsonOutput) console.log(chalk.bold("\n▶ Record delegate status\n"));
203+
if (!jsonOutput) printCommandHeader("Record delegate status");
226204
const spinner = ora();
205+
const ctx = buildReadOnlyDotnsContext(context, { onStatus: makeOnStatus(spinner) });
227206

228207
const operatorAddress = await maybeQuiet(jsonOutput, () =>
229-
resolveTransferRecipient(context.clientWrapper!, context.account.address, operator),
208+
resolveTransferRecipient(ctx, operator),
230209
);
231210

232211
const approved = await maybeQuiet(jsonOutput, () =>
233-
getRecordDelegate(
234-
context.clientWrapper!,
235-
context.account.address,
236-
operatorAddress as Address,
237-
spinner,
238-
),
212+
getRecordDelegate(ctx, operatorAddress as Address),
239213
);
240214

241215
if (!emitJsonResult(jsonOutput, { operator: operatorAddress, approved })) {

0 commit comments

Comments
 (0)