feat: sync full workspace including web modules, docs, and configurations to Gitea

Optimized the root .gitignore to exclude virtual environments, node modules,
and temp folders to ensure clean and lightweight version tracking.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
王冕
2026-06-09 18:12:25 +08:00
parent 351688006e
commit a27e3b8e43
1510 changed files with 162044 additions and 1517 deletions

View File

@@ -0,0 +1,125 @@
import { networkInterfaces } from 'os';
import archiver from 'archiver';
import { buildAttachmentContentDisposition } from './contentDisposition';
export function getLocalIP(): string {
const interfaces = networkInterfaces();
for (const name of Object.keys(interfaces)) {
const nets = interfaces[name];
if (!nets) continue;
for (const net of nets) {
if (net.family === 'IPv4' && !net.internal) {
return net.address;
}
}
}
return 'localhost';
}
export function getRequestPathname(req: any): string {
try {
return new URL(req.url || '/', `http://${req.headers.host}`).pathname;
} catch {
return (req.url || '/').split('?')[0];
}
}
export function readJsonBody(req: any): Promise<any> {
return new Promise((resolve, reject) => {
let body = '';
req.on('data', (chunk: Buffer) => {
body += chunk.toString('utf8');
});
req.on('end', () => {
if (!body) {
resolve({});
return;
}
try {
resolve(JSON.parse(body));
} catch (error) {
reject(error);
}
});
req.on('error', reject);
});
}
export function readRequestBody(req: any): Promise<string> {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = [];
req.on('data', (chunk: Buffer | string) => {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
});
req.on('end', () => {
resolve(Buffer.concat(chunks).toString('utf8'));
});
req.on('error', reject);
});
}
export function readErrorString(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
}
export function limitErrorText(value: string, maxLength: number = 500): string {
if (value.length <= maxLength) {
return value;
}
return `${value.slice(0, maxLength)}...`;
}
export function serializeErrorForLog(error: any) {
const cause = error?.cause;
const stack = readErrorString(error?.stack);
const causeStack = readErrorString(cause?.stack);
return {
name: readErrorString(error?.name) || undefined,
message: readErrorString(error?.message) || undefined,
code: readErrorString(error?.code) || undefined,
errno: readErrorString(error?.errno) || undefined,
syscall: readErrorString(error?.syscall) || undefined,
address: readErrorString(error?.address) || undefined,
port: typeof error?.port === 'number' ? error.port : undefined,
causeName: readErrorString(cause?.name) || undefined,
causeMessage: readErrorString(cause?.message) || undefined,
causeCode: readErrorString(cause?.code) || undefined,
causeErrno: readErrorString(cause?.errno) || undefined,
causeSyscall: readErrorString(cause?.syscall) || undefined,
causeAddress: readErrorString(cause?.address) || undefined,
causePort: typeof cause?.port === 'number' ? cause.port : undefined,
stack: stack ? limitErrorText(stack, 1200) : undefined,
causeStack: causeStack ? limitErrorText(causeStack, 1200) : undefined,
};
}
export function streamDirectoryAsZip(res: any, sourceDir: string, fileName: string) {
res.setHeader('Content-Type', 'application/zip');
res.setHeader('Content-Disposition', buildAttachmentContentDisposition(fileName));
const archive = archiver('zip', { zlib: { level: 9 } });
archive.on('warning', (warning: any) => {
console.warn('[download-dist-plugin] ZIP warning:', warning);
});
archive.on('error', (error: any) => {
console.error('[download-dist-plugin] ZIP error:', error);
if (!res.headersSent) {
res.statusCode = 500;
res.end(JSON.stringify({ error: `Failed to create zip: ${error.message}` }));
return;
}
res.destroy(error);
});
archive.pipe(res);
archive.directory(sourceDir, false);
void archive.finalize();
}