mirror of
https://github.com/glitternetwork/pinme.git
synced 2026-08-29 02:03:07 +08:00
feat: 2.0.4 version
This commit is contained in:
+61
-15
@@ -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
@@ -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
@@ -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
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pinme",
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.4",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user