Files
2026-07-13 12:30:28 +08:00

156 lines
4.7 KiB
TypeScript

import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
import { execSync } from 'child_process';
import { getAuthHeaders } from './utils/webLogin';
import {
createCommandError,
createConfigError,
printCliError,
} from './utils/cliError';
import { APP_CONFIG } from './utils/config';
import { uploadPath } from './services/uploadService';
import { printHighlightedUrl } from './utils/urlDisplay';
import tracker, { getTrackErrorReason } from './utils/tracker';
import {
TRACK_EVENTS,
TRACK_PAGES,
resolveTrackAction,
} from './utils/trackerEvents';
const PROJECT_DIR = process.cwd();
interface UpdateWebOptions {
projectName?: string;
name?: string;
}
// ============ 工具函数 ============
function loadConfig() {
const configPath = path.join(PROJECT_DIR, 'pinme.toml');
if (!fs.existsSync(configPath)) {
throw createConfigError('`pinme.toml` not found in the current directory.', [
'Run this command from the Pinme project root.',
]);
}
const configContent = fs.readFileSync(configPath, 'utf-8');
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
return {
project_name: projectNameMatch?.[1] || '',
};
}
function getProjectManagementUrl(projectName: string): string {
return `${APP_CONFIG.projectPeviewUrl}${projectName}`;
}
// ============ 前端构建和部署 ============
function buildFrontend() {
console.log(chalk.blue('Building frontend...'));
try {
execSync('npm run build:frontend', {
cwd: PROJECT_DIR,
stdio: 'inherit',
});
console.log(chalk.green('Frontend built'));
} catch (error: any) {
throw createCommandError('frontend build', 'npm run build:frontend', error, [
'Fix the frontend build error shown above, then rerun `pinme update-web`.',
]);
}
}
async function deployFrontend(projectName: string): Promise<void> {
console.log(chalk.blue('Deploying frontend to IPFS...'));
try {
const headers = getAuthHeaders();
const uploadResult = await uploadPath(path.join(PROJECT_DIR, 'frontend', 'dist'), {
action: 'project_update_web',
projectName,
uid: headers['token-address'],
});
printHighlightedUrl('Frontend URL', uploadResult.publicUrl, 'primary');
printHighlightedUrl(
'Project Management URL',
getProjectManagementUrl(projectName),
'management',
);
} catch (error: any) {
throw createCommandError('frontend deploy', 'upload frontend/dist', error, [
'Make sure `frontend/dist` exists and the upload API is reachable.',
]);
}
}
// ============ 主函数 ============
/**
* Update web: build + upload frontend only (no worker, no SQL)
*/
export default async function updateWebCmd(options?: UpdateWebOptions): Promise<void> {
try {
// Check if user is logged in
const headers = getAuthHeaders();
if (!headers['authentication-tokens'] || !headers['token-address']) {
throw createConfigError('No valid local login session was found.', [
'Run `pinme login` and retry.',
]);
}
// Copy token to project directory for sub-commands
const projectDir = options?.projectName || options?.name ? path.join(PROJECT_DIR, options.projectName || options.name!) : PROJECT_DIR;
const tokenFileSrc = path.join(PROJECT_DIR, '.token.json');
const tokenFileDst = path.join(projectDir, '.token.json');
if (fs.existsSync(tokenFileSrc) && !fs.existsSync(tokenFileDst)) {
fs.copySync(tokenFileSrc, tokenFileDst);
}
console.log(chalk.blue('Updating web (frontend)...\n'));
console.log(chalk.gray(`Project dir: ${PROJECT_DIR}`));
const config = loadConfig();
const projectName = config.project_name;
if (!projectName) {
throw createConfigError('`project_name` is missing in `pinme.toml`.', [
'Set `project_name = "your-project-name"` in `pinme.toml`.',
]);
}
console.log(chalk.gray(`Project: ${projectName}`));
// Frontend: build + deploy
console.log(chalk.blue('\n--- Frontend Update ---'));
buildFrontend();
await deployFrontend(projectName);
console.log(chalk.green('\nWeb update complete.'));
void tracker.trackEvent(
TRACK_EVENTS.projectUpdateWebSuccess,
TRACK_PAGES.deploy,
{
a: resolveTrackAction(TRACK_EVENTS.projectUpdateWebSuccess),
project_name: projectName,
},
);
process.exit(0);
} catch (error: any) {
void tracker.trackEvent(
TRACK_EVENTS.projectUpdateWebFailed,
TRACK_PAGES.deploy,
{
a: resolveTrackAction(TRACK_EVENTS.projectUpdateWebFailed),
project_name: options?.projectName || options?.name,
reason: getTrackErrorReason(error),
},
);
printCliError(error, 'Web update failed.');
process.exit(1);
}
}