feat: 2.0.4 version

This commit is contained in:
junchi.zhang
2026-04-29 01:13:42 +08:00
parent 0dc770a6b1
commit cc99955b72
4 changed files with 122 additions and 28 deletions
+61 -15
View File
@@ -1,11 +1,21 @@
import path from 'path';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { checkDomainAvailable, bindPinmeDomain, bindDnsDomainV4, getRootDomain, getWalletBalance } from './utils/pinmeApi';
import {
checkDomainAvailable,
bindPinmeDomain,
bindDnsDomainV4,
getRootDomain,
getWalletBalance,
} from './utils/pinmeApi';
import { printCliError, printRechargeUrl } from './utils/cliError';
import { getWalletRechargeUrl } from './utils/config';
import { getAuthConfig } from './utils/webLogin';
import { isDnsDomain, normalizeDomain, validateDnsDomain } from './utils/domainValidator';
import {
isDnsDomain,
normalizeDomain,
validateDnsDomain,
} from './utils/domainValidator';
import { uploadPath } from './services/uploadService';
interface Args {
@@ -14,7 +24,6 @@ interface Args {
dns?: boolean;
}
function parseArgs(): Args {
// Usage: pinme bind <path> --domain <name> [--dns]
const args = process.argv.slice(2);
@@ -35,15 +44,23 @@ function parseArgs(): Args {
return res;
}
async function checkWalletBalanceStatus(authConfig: { address: string; token: string }): Promise<boolean> {
async function checkWalletBalanceStatus(authConfig: {
address: string;
token: string;
}): Promise<boolean> {
console.log(chalk.blue('Checking wallet balance...'));
try {
const balanceResult = await getWalletBalance(authConfig.address, authConfig.token);
const balanceResult = await getWalletBalance(
authConfig.address,
authConfig.token,
);
const balance = Number(balanceResult.data?.wallet_balance_usd ?? 0);
if (!Number.isFinite(balance) || balance <= 0) {
return false;
}
console.log(chalk.green(`Wallet balance available: $${balance.toFixed(2)}`));
console.log(
chalk.green(`Wallet balance available: $${balance.toFixed(2)}`),
);
return true;
} catch (e: any) {
if (e.message === 'Token expired' || e?.name === 'CliError') {
@@ -61,24 +78,36 @@ export default async function bindCmd(): Promise<void> {
// Check auth
const authConfig = getAuthConfig();
if (!authConfig) {
console.log(chalk.red('Please login first. Run: pinme set-appkey <AppKey>'));
console.log(
chalk.red('Please login first. Run: pinme set-appkey <AppKey>'),
);
return;
}
if (!targetPath) {
const ans = await inquirer.prompt([
{ type: 'input', name: 'path', message: 'Enter the path to upload and bind: ' },
{
type: 'input',
name: 'path',
message: 'Enter the path to upload and bind: ',
},
]);
targetPath = ans.path;
}
if (!domain) {
const ans = await inquirer.prompt([
{ type: 'input', name: 'domain', message: 'Enter the domain to bind (e.g., my-site or example.com): ' },
{
type: 'input',
name: 'domain',
message: 'Enter the domain to bind (e.g., my-site or example.com): ',
},
]);
domain = ans.domain?.trim();
}
if (!targetPath || !domain) {
console.log(chalk.red('Missing parameters. Path and domain are required.'));
console.log(
chalk.red('Missing parameters. Path and domain are required.'),
);
return;
}
@@ -99,7 +128,11 @@ export default async function bindCmd(): Promise<void> {
try {
const hasWalletBalance = await checkWalletBalanceStatus(authConfig);
if (!hasWalletBalance) {
console.log(chalk.red('Insufficient wallet balance. Please recharge your wallet first.'));
console.log(
chalk.red(
'Insufficient wallet balance. Please recharge your wallet first.',
),
);
printRechargeUrl(getWalletRechargeUrl());
return;
}
@@ -114,7 +147,9 @@ export default async function bindCmd(): Promise<void> {
try {
const check = await checkDomainAvailable(displayDomain);
if (!check.is_valid) {
console.log(chalk.red(`Domain not available: ${check.error || 'unknown reason'}`));
console.log(
chalk.red(`Domain not available: ${check.error || 'unknown reason'}`),
);
return;
}
console.log(chalk.green(`Domain available: ${displayDomain}`));
@@ -140,14 +175,23 @@ export default async function bindCmd(): Promise<void> {
if (isDns) {
// DNS domain binding
console.log(chalk.blue('Binding DNS domain...'));
const dnsResult = await bindDnsDomainV4(displayDomain, up.contentHash, authConfig.address, authConfig.token);
const dnsResult = await bindDnsDomainV4(
displayDomain,
up.contentHash,
authConfig.address,
authConfig.token,
);
if (dnsResult.code !== 200) {
console.log(chalk.red(`DNS binding failed: ${dnsResult.msg}`));
return;
}
console.log(chalk.green(`DNS bind success: ${displayDomain}`));
console.log(chalk.white(`Visit: https://${displayDomain}`));
console.log(chalk.cyan('\n📚 DNS Setup Guide: https://pinme.eth.limo/#/docs?id=custom-domain'));
console.log(
chalk.cyan(
'\n📚 DNS Setup Guide: https://pinme.eth.limo/#/docs?id=custom-domain',
),
);
} else {
// Pinme subdomain binding
console.log(chalk.blue('Binding Pinme subdomain...'));
@@ -158,7 +202,9 @@ export default async function bindCmd(): Promise<void> {
}
console.log(chalk.green(`Bind success: ${displayDomain}`));
const rootDomain = await getRootDomain();
console.log(chalk.white(`Visit: https://${displayDomain}.${rootDomain}`));
console.log(
chalk.white(`Visit: https://${displayDomain}.${rootDomain}`),
);
}
} catch (e: any) {
if (e.message === 'Token expired') {
+50 -10
View File
@@ -4,7 +4,11 @@ import inquirer from 'inquirer';
import figlet from 'figlet';
import fs from 'fs';
import CryptoJS from 'crypto-js';
import { checkDomainAvailable, bindPinmeDomain, getRootDomain } from './utils/pinmeApi';
import {
checkDomainAvailable,
bindPinmeDomain,
getRootDomain,
} from './utils/pinmeApi';
import { printCliError } from './utils/cliError';
import { getAuthConfig } from './utils/webLogin';
import { APP_CONFIG } from './utils/config';
@@ -16,7 +20,11 @@ import { checkNodeVersion } from './utils/checkNodeVersion';
checkNodeVersion();
// encrypt the hash with optional uid (device id)
function encryptHash(contentHash: string, key: string | undefined, uid?: string): string {
function encryptHash(
contentHash: string,
key: string | undefined,
uid?: string,
): string {
try {
if (!key) {
throw new Error('Secret key not found');
@@ -108,7 +116,11 @@ export default async (options?: ImportOptions): Promise<void> => {
if (domainArg) {
const check = await checkDomainAvailable(domainArg);
if (!check.is_valid) {
console.log(chalk.red(`Domain not available: ${check.error || 'unknown reason'}`));
console.log(
chalk.red(
`Domain not available: ${check.error || 'unknown reason'}`,
),
);
return;
}
console.log(chalk.green(`Domain available: ${domainArg}`));
@@ -122,7 +134,11 @@ export default async (options?: ImportOptions): Promise<void> => {
});
if (result) {
const uid = getUid();
const encryptedCID = encryptHash(result.contentHash, APP_CONFIG.secretKey, uid);
const encryptedCID = encryptHash(
result.contentHash,
APP_CONFIG.secretKey,
uid,
);
console.log(
chalk.cyan(
figlet.textSync('Successful', { horizontalLayout: 'full' }),
@@ -135,12 +151,20 @@ export default async (options?: ImportOptions): Promise<void> => {
);
// optional: bind domain after import
if (domainArg) {
console.log(chalk.blue(`Binding domain: ${domainArg} with CID: ${result.contentHash}`));
console.log(
chalk.blue(
`Binding domain: ${domainArg} with CID: ${result.contentHash}`,
),
);
const ok = await bindPinmeDomain(domainArg, result.contentHash);
if (ok) {
console.log(chalk.green(`Bind success: ${domainArg}`));
const rootDomain = await getRootDomain();
console.log(chalk.white(`Visit (Pinme subdomain example): https://${domainArg}.${rootDomain}`));
console.log(
chalk.white(
`Visit (Pinme subdomain example): https://${domainArg}.${rootDomain}`,
),
);
} else {
console.log(chalk.red('Binding failed. Please try again later.'));
}
@@ -173,7 +197,11 @@ export default async (options?: ImportOptions): Promise<void> => {
if (domainArg) {
const check = await checkDomainAvailable(domainArg);
if (!check.is_valid) {
console.log(chalk.red(`Domain not available: ${check.error || 'unknown reason'}`));
console.log(
chalk.red(
`Domain not available: ${check.error || 'unknown reason'}`,
),
);
return;
}
console.log(chalk.green(`Domain available: ${domainArg}`));
@@ -188,7 +216,11 @@ export default async (options?: ImportOptions): Promise<void> => {
if (result) {
const uid = getUid();
const encryptedCID = encryptHash(result.contentHash, APP_CONFIG.secretKey, uid);
const encryptedCID = encryptHash(
result.contentHash,
APP_CONFIG.secretKey,
uid,
);
console.log(
chalk.cyan(
figlet.textSync('Successful', { horizontalLayout: 'full' }),
@@ -200,12 +232,20 @@ export default async (options?: ImportOptions): Promise<void> => {
'primary',
);
if (domainArg) {
console.log(chalk.blue(`Binding domain: ${domainArg} with CID: ${result.contentHash}`));
console.log(
chalk.blue(
`Binding domain: ${domainArg} with CID: ${result.contentHash}`,
),
);
const ok = await bindPinmeDomain(domainArg, result.contentHash);
if (ok) {
console.log(chalk.green(`Bind success: ${domainArg}`));
const rootDomain = await getRootDomain();
console.log(chalk.white(`Visit (Pinme subdomain example): https://${domainArg}.${rootDomain}`));
console.log(
chalk.white(
`Visit (Pinme subdomain example): https://${domainArg}.${rootDomain}`,
),
);
} else {
console.log(chalk.red('Binding failed. Please try again later.'));
}
+10 -2
View File
@@ -1,6 +1,7 @@
import chalk from 'chalk';
import { createCarApiClient, createPinmeApiClient } from './apiClient';
import { APP_CONFIG } from './config';
import { isDnsDomain } from './domainValidator';
// Token expired error codes
const TOKEN_EXPIRED_CODES = [
@@ -86,7 +87,9 @@ export interface GetRootDomainResponse {
let rootDomainCache: string | null = null;
export async function getRootDomain(forceRefresh: boolean = false): Promise<string> {
export async function getRootDomain(
forceRefresh: boolean = false,
): Promise<string> {
if (!forceRefresh && rootDomainCache) {
return rootDomainCache;
}
@@ -105,10 +108,15 @@ export async function getRootDomain(forceRefresh: boolean = false): Promise<stri
export async function checkDomainAvailable(
domainName: string,
): Promise<CheckDomainResult> {
if (isDnsDomain(domainName)) {
return await {
is_valid: true,
};
}
const client = createPinmeApiClient();
// Endpoint may not be fixed, prioritize environment variable, then try two common paths
const configured = APP_CONFIG.pinmeCheckDomainPath;
const fallbacks = [configured, '/check_domain_available'];
const fallbacks = [configured];
let lastRecoverableError: any;
for (const p of fallbacks) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "pinme",
"version": "2.0.2",
"version": "2.0.4",
"publishConfig": {
"access": "public"
},