项目名批量更新

This commit is contained in:
moux1024 2025-10-27 15:48:42 +08:00
parent a6c654d596
commit ce6a6d84d4
18 changed files with 97 additions and 187 deletions

View File

@ -17,7 +17,7 @@ npm run dev
## 生产部署
```shellscript
cd video-flow
cd video-flow-b
./compile.sh
登入服务器:

View File

@ -1,4 +1,4 @@
## Video-Flow API 使用指南(方案一:保持现状,统一规范与示例)
## video-flow-b API 使用指南(方案一:保持现状,统一规范与示例)
> 目标:在不改动现有代码结构与签名的前提下,提供清晰的一致性用法、错误处理约定与多场景接入示例。
@ -54,7 +54,7 @@ await del<ApiResponse<null>>('/user/remove?id=1');
import { stream } from '@/api/request';
await stream<{ type: string; message?: string; progress?: number }>({
url: '/api/video-flow/export/ai-clips',
url: '/api/video-flow-b/export/ai-clips',
method: 'POST',
data: { /* your body */ },
onMessage: (evt) => {

View File

@ -1,8 +1,6 @@
/**
* API适配器 - OpenCut的导出API适配到Video-Flow项目
* 文件路径: video-flow/api/export-adapter.ts
* 作者: 资深全栈开发工程师
* 创建时间: 2025-01-08
* API适配器 - OpenCut的导出API适配到video-flow-b项目
* 文件路径: video-flow-b/api/export-adapter.ts
*/
import { NextRequest, NextResponse } from "next/server";
@ -39,7 +37,7 @@ interface AIExportRequest {
}
/**
* Video-Flow AI剪辑导出API
* video-flow-b AI剪辑导出API
* OpenCut项目的 /api/export/ai-clips
*/
export async function POST(req: NextRequest) {
@ -49,11 +47,11 @@ export async function POST(req: NextRequest) {
const stream = new ReadableStream({
async start(controller) {
try {
console.log('🚀 Video-Flow AI剪辑导出API启动');
console.log('🚀 video-flow-b AI剪辑导出API启动');
const requestData: AIExportRequest = await req.json();
const { clips, subtitles, totalDuration, options } = requestData;
console.log('=== Video-Flow AI剪辑导出开始 ===');
console.log('=== video-flow-b AI剪辑导出开始 ===');
console.log('Clips count:', clips.length);
console.log('Total duration:', totalDuration, 'seconds');
console.log('Quality:', options.quality);
@ -64,7 +62,7 @@ export async function POST(req: NextRequest) {
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
type: 'progress',
stage: 'starting',
message: '开始Video-Flow AI剪辑导出...',
message: '开始video-flow-b AI剪辑导出...',
progress: 0,
})}\n\n`));
} catch (controllerError) {
@ -72,7 +70,7 @@ export async function POST(req: NextRequest) {
}
// 创建工作目录
workDir = await fs.mkdtemp(join(tmpdir(), 'video-flow-ai-export-'));
workDir = await fs.mkdtemp(join(tmpdir(), 'video-flow-b-ai-export-'));
console.log('Work directory:', workDir);
// 执行AI剪辑导出
@ -83,14 +81,14 @@ export async function POST(req: NextRequest) {
const stats = await fs.stat(outputPath);
// 提取导出ID
const exportId = workDir.split('/').pop()?.replace('video-flow-ai-export-', '') || '';
const exportId = workDir.split('/').pop()?.replace('video-flow-b-ai-export-', '') || '';
console.log('🎉 Video-Flow AI剪辑导出完成:', {
console.log('🎉 video-flow-b AI剪辑导出完成:', {
outputPath,
fileSize: stats.size,
exportId,
workDir,
downloadUrl: `/api/video-flow/export/download/${exportId}`,
downloadUrl: `/api/video-flow-b/export/download/${exportId}`,
});
// 🚀 新增上传到七牛云复用OpenCut逻辑
@ -110,7 +108,7 @@ export async function POST(req: NextRequest) {
// 这里可以调用七牛云上传逻辑
// const qiniuResult = await uploadToQiniu(outputPath, exportId);
// 暂时使用本地URL
qiniuUrl = `/api/video-flow/export/download/${exportId}`;
qiniuUrl = `/api/video-flow-b/export/download/${exportId}`;
console.log('✅ 视频上传完成:', qiniuUrl);
} catch (error) {
console.warn('⚠️ 视频上传失败:', error);
@ -119,17 +117,17 @@ export async function POST(req: NextRequest) {
try {
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
type: 'completed',
downloadUrl: qiniuUrl || `/api/video-flow/export/download/${exportId}`,
downloadUrl: qiniuUrl || `/api/video-flow-b/export/download/${exportId}`,
fileSize: stats.size,
exportId: exportId,
message: 'Video-Flow AI剪辑导出完成!'
message: 'video-flow-b AI剪辑导出完成!'
})}\n\n`));
} catch (controllerError) {
console.warn('⚠️ 控制器已关闭,无法发送完成通知:', controllerError);
}
} catch (error) {
console.error('Video-Flow AI剪辑导出失败:', error);
console.error('video-flow-b AI剪辑导出失败:', error);
try {
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
type: 'error',
@ -154,7 +152,7 @@ export async function POST(req: NextRequest) {
}
/**
* Video-Flow AI剪辑导出
* video-flow-b AI剪辑导出
* OpenCut的核心导出逻辑
*/
async function executeVideoFlowAIExport(
@ -189,7 +187,7 @@ async function executeVideoFlowAIExport(
controller.enqueue(encoder.encode(`data: ${JSON.stringify({
type: 'progress',
stage: 'downloading',
message: '下载Video-Flow视频片段...',
message: '下载video-flow-b视频片段...',
progress: 0.2,
})}\n\n`));
} catch (controllerError) {
@ -212,7 +210,7 @@ async function executeVideoFlowAIExport(
const ffmpegArgs = await buildVideoFlowFFmpegCommand(processedClips, subtitles, totalDuration, options, workDir);
console.log('=== Video-Flow AI剪辑导出调试信息 ===');
console.log('=== video-flow-b AI剪辑导出调试信息 ===');
console.log('Processed clips:', processedClips.length);
console.log('Total duration:', totalDuration);
console.log('FFmpeg合成命令: ffmpeg', ffmpegArgs.join(' '));
@ -234,7 +232,7 @@ async function executeVideoFlowAIExport(
}
/**
* Video-Flow视频片段
* video-flow-b视频片段
*/
async function downloadAndProcessVideoFlowClips(
clips: AIClipData[],
@ -297,7 +295,7 @@ async function downloadAndProcessVideoFlowClips(
}
/**
* Video-Flow FFmpeg命令
* video-flow-b FFmpeg命令
*/
async function buildVideoFlowFFmpegCommand(
processedClips: Array<{ clipPath: string; duration: number; startTime: number }>,

View File

@ -1,11 +1,10 @@
/**
* Video-Flow AI剪辑导出API路由
* 文件路径: video-flow/app/api/export/ai-clips/route.ts
* 作者: 资深全栈开发工程师
* 创建时间: 2025-01-08
* video-flow-b AI剪辑导出API路由
* 文件路径: video-flow-b/app/api/export/ai-clips/route.ts
*
* API端点专门为Video-Flow项目提供AI剪辑导出功能
* OpenCut项目的核心导出逻辑Video-Flow的数据结构
* API端点专门为video-flow-b项目提供AI剪辑导出功能
* OpenCut项目的核心导出逻辑video-flow-b的数据结构
*/
// 直接导出适配器中的POST函数

View File

@ -1,8 +1,7 @@
/**
* Video-Flow API
* 文件路径: video-flow/app/api/export/download/[exportId]/route.ts
* 作者: 资深全栈开发工程师
* 创建时间: 2025-01-08
* video-flow-b API
* 文件路径: video-flow-b/app/api/export/download/[exportId]/route.ts
*/
import { NextRequest, NextResponse } from "next/server";
@ -24,10 +23,10 @@ export async function GET(
);
}
console.log('📥 Video-Flow 导出视频下载请求:', exportId);
console.log('📥 video-flow-b 导出视频下载请求:', exportId);
// 构建文件路径
const workDir = join(tmpdir(), `video-flow-ai-export-${exportId}`);
const workDir = join(tmpdir(), `video-flow-b-ai-export-${exportId}`);
const filePath = join(workDir, 'output.mp4');
// 检查文件是否存在
@ -45,7 +44,7 @@ export async function GET(
const fileBuffer = await fs.readFile(filePath);
const stats = await fs.stat(filePath);
console.log('✅ Video-Flow 导出视频下载成功:', {
console.log('✅ video-flow-b 导出视频下载成功:', {
exportId,
fileSize: stats.size,
filePath
@ -56,13 +55,13 @@ export async function GET(
headers: {
'Content-Type': 'video/mp4',
'Content-Length': stats.size.toString(),
'Content-Disposition': `attachment; filename="video-flow-ai-edited-${exportId}.mp4"`,
'Content-Disposition': `attachment; filename="video-flow-b-ai-edited-${exportId}.mp4"`,
'Cache-Control': 'public, max-age=3600', // 缓存1小时
},
});
} catch (error) {
console.error('❌ Video-Flow 导出视频下载失败:', error);
console.error('❌ video-flow-b 导出视频下载失败:', error);
return NextResponse.json(
{
@ -92,7 +91,7 @@ export async function DELETE(
);
}
const workDir = join(tmpdir(), `video-flow-ai-export-${exportId}`);
const workDir = join(tmpdir(), `video-flow-b-ai-export-${exportId}`);
try {
await fs.rm(workDir, { recursive: true, force: true });

View File

@ -1,101 +0,0 @@
# Windows PowerShell deployment script
$BRANCH_NAME = "dev"
# Project name
$PROJECT_NAME = "video-flow-$BRANCH_NAME-frontend"
# Log file path
$LOGFILE = "build_and_copy.log"
# Record start time
$startMessage = "Build process started at $(Get-Date)"
$startMessage | Tee-Object -FilePath $LOGFILE
# Get current branch name
$current_branch = git rev-parse --abbrev-ref HEAD
# Check if on dev branch, working directory is clean, and in sync with remote
if ($current_branch -ne $BRANCH_NAME) {
Write-Host "Current branch is not dev branch" -ForegroundColor Red
exit 1
}
# Check if working directory is clean
$gitStatus = git status --porcelain
if ($gitStatus) {
Write-Host "Working directory is not clean" -ForegroundColor Red
exit 1
}
# Check if local branch is in sync with remote
$localHead = git rev-parse HEAD
$remoteHead = git rev-parse origin/$BRANCH_NAME
if ($localHead -ne $remoteHead) {
Write-Host "Local branch is not in sync with remote branch" -ForegroundColor Red
exit 1
}
# Check current branch and run corresponding build command
if ($current_branch -eq $BRANCH_NAME) {
$buildMessage = "On dev branch, building project..."
$buildMessage | Tee-Object -FilePath $LOGFILE -Append
$PROFILE_ENV = $BRANCH_NAME
# Install dependencies and build (production mode with development environment variables)
yarn install
$env:NODE_ENV = "production"
npx --yes env-cmd -f .env.development yarn build
# Prepare dist directory
if (Test-Path "dist") {
Remove-Item -Path "dist" -Recurse -Force
}
New-Item -ItemType Directory -Path "dist" -Force | Out-Null
if (Test-Path ".next\cache") {
Remove-Item -Path ".next\cache" -Recurse -Force
}
Copy-Item -Path ".next" -Destination "dist\.next" -Recurse -Force
Copy-Item -Path "public" -Destination "dist\public" -Recurse -Force
Copy-Item -Path "package.json" -Destination "dist\package.json" -Force
Copy-Item -Path "package-lock.json" -Destination "dist\package-lock.json" -Force
} else {
Write-Host "On non-dev branch ($current_branch), exiting" -ForegroundColor Yellow
exit 1
}
# Create tar package
$tarFileName = "$PROJECT_NAME-$PROFILE_ENV.tar.gz"
tar -czvf $tarFileName dist
# Record end time
$endMessage = "Build process completed at $(Get-Date)"
$endMessage | Tee-Object -FilePath $LOGFILE -Append
# Upload to nexus
$uploadMessage = "upload to nexus at $(Get-Date)"
$uploadMessage | Tee-Object -FilePath $LOGFILE -Append
$nexusUrl = "https://repo.qikongjian.com/repository/frontend-tar-files/$tarFileName"
$credentials = 'admin:YZ9Gq6=8\*G|?:,'
$encodedCredentials = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($credentials))
try {
Invoke-WebRequest -Uri $nexusUrl -Method Put -InFile $tarFileName -Headers @{
Authorization = "Basic $encodedCredentials"
}
Write-Host "Upload successful" -ForegroundColor Green
} catch {
Write-Host "Upload failed: $_" -ForegroundColor Red
exit 1
}
# Clean up build files
Remove-Item -Path "dist" -Recurse -Force
Remove-Item -Path $tarFileName -Force
Write-Host "Deployment completed" -ForegroundColor Green

View File

@ -3,7 +3,7 @@
BRANCH_NAME="dev"
# 修改项目名称
PROJECT_NAME="video-flow-$BRANCH_NAME-frontend"
PROJECT_NAME="video-flow-b-$BRANCH_NAME-frontend"
# 设置日志文件路径
LOGFILE="build_and_copy.log"

View File

@ -3,7 +3,7 @@
BRANCH_NAME="prod"
# 修改项目名称
PROJECT_NAME="video-flow-$BRANCH_NAME-frontend"
PROJECT_NAME="video-flow-b-$BRANCH_NAME-frontend"
# 设置日志文件路径
LOGFILE="build_and_copy.log"

View File

@ -1,8 +1,7 @@
/**
* AI剪辑适配器 - OpenCut的AI剪辑逻辑适配到Video-Flow
* 文件路径: video-flow/components/pages/work-flow/ai-editing-adapter.ts
* 作者: 资深全栈开发工程师
* 创建时间: 2025-01-08
* AI剪辑适配器 - OpenCut的AI剪辑逻辑适配到video-flow-b
* 文件路径: video-flow-b/components/pages/work-flow/ai-editing-adapter.ts
*/
// 从OpenCut项目导入的类型定义
@ -40,7 +39,7 @@ interface ExportOptions {
}
/**
* Video-Flow项目的任务对象类型
* video-flow-b项目的任务对象类型
*/
interface VideoFlowTaskObject {
title: string;
@ -61,7 +60,7 @@ interface VideoFlowTaskObject {
/**
* AI剪辑适配器类
* Video-Flow的视频数据转换为OpenCut的AI剪辑格式
* video-flow-b的视频数据转换为OpenCut的AI剪辑格式
*/
export class AIEditingAdapter {
private projectId: string;
@ -87,12 +86,12 @@ export class AIEditingAdapter {
}
/**
* Video-Flow的视频数据转换为AI剪辑计划格式
* video-flow-b的视频数据转换为AI剪辑计划格式
*/
private convertToAIEditingPlan(): AIEditingPlan {
const clips: AIClipData[] = [];
// 遍历Video-Flow的视频数据转换为AI剪辑格式
// 遍历video-flow-b的视频数据转换为AI剪辑格式
this.taskObject.videos.data.forEach((video, index) => {
if (video.video_status === 1 && video.urls && video.urls.length > 0) {
// 只处理生成成功的视频
@ -172,7 +171,7 @@ export class AIEditingAdapter {
this.onProgress?.(90, "剪辑完成,正在生成最终视频...");
// 第四步:更新Video-Flow项目状态
// 第四步:更新video-flow-b项目状态
await this.updateVideoFlowProject(finalVideoUrl);
this.onProgress?.(100, "AI剪辑流程完成");
@ -197,7 +196,7 @@ export class AIEditingAdapter {
}
/**
* Video-Flow的导出API
* video-flow-b的导出API
* OpenCut项目中的 /api/export/ai-clips
*/
private async callExportAPI(exportRequest: any): Promise<string> {
@ -263,12 +262,12 @@ export class AIEditingAdapter {
}
/**
* Video-Flow项目状态
* AI剪辑结果更新到Video-Flow的数据结构中
* video-flow-b项目状态
* AI剪辑结果更新到video-flow-b的数据结构中
*/
private async updateVideoFlowProject(finalVideoUrl: string): Promise<void> {
try {
// 构建任务结果数据,模拟Video-Flow的粗剪接口调用
// 构建任务结果数据,模拟video-flow-b的粗剪接口调用
const taskResult = {
task_result: JSON.stringify({
video: finalVideoUrl
@ -277,16 +276,16 @@ export class AIEditingAdapter {
project_id: this.projectId
};
console.log('🎬 更新Video-Flow项目状态:');
console.log('🎬 更新video-flow-b项目状态:');
console.log(' - 项目ID:', this.projectId);
console.log(' - 最终视频URL:', finalVideoUrl);
console.log(' - 任务结果:', taskResult);
// 这里可以调用Video-Flow的API来更新项目状态
// 这里可以调用video-flow-b的API来更新项目状态
// 或者直接更新本地状态(取决于具体需求)
} catch (error) {
console.warn("更新Video-Flow项目状态失败:", error);
console.warn("更新video-flow-b项目状态失败:", error);
// 不抛出错误,避免影响主流程
}
}

View File

@ -1,8 +1,7 @@
/**
* AI剪辑按钮组件 - Video-Flow集成OpenCut AI剪辑功能
* 文件路径: video-flow/components/pages/work-flow/ai-editing-button.tsx
* 作者: 资深全栈开发工程师
* 创建时间: 2025-01-08
* AI剪辑按钮组件 - video-flow-b集成OpenCut AI剪辑功能
* 文件路径: video-flow-b/components/pages/work-flow/ai-editing-button.tsx
*/
"use client";
@ -25,7 +24,7 @@ import { createAIEditingAdapter, VideoFlowTaskObject, AIEditingAdapter } from '.
interface AIEditingButtonProps {
/** 项目ID */
projectId: string;
/** Video-Flow任务对象 */
/** video-flow-b任务对象 */
taskObject: VideoFlowTaskObject;
/** 是否禁用按钮 */
disabled?: boolean;

View File

@ -1,8 +1,7 @@
/**
* AI剪辑iframe组件 - work-flow页面
* 文件路径: video-flow/components/pages/work-flow/ai-editing-iframe.tsx
* 作者: 资深全栈开发工程师
* 创建时间: 2025-01-08
* 文件路径: video-flow-b/components/pages/work-flow/ai-editing-iframe.tsx
*/
"use client";

View File

@ -1,12 +1,12 @@
# Video-Flow AI 剪辑集成技术文档
# video-flow-b AI 剪辑集成技术文档
## 📋 项目概述
本文档详细记录了将 OpenCut 项目的 AI 智能剪辑功能集成到 Video-Flow 工作流系统中的完整技术方案。该集成实现了从剧本生成的视频片段到最终成片的自动化 AI 剪辑流程。
本文档详细记录了将 OpenCut 项目的 AI 智能剪辑功能集成到 video-flow-b 工作流系统中的完整技术方案。该集成实现了从剧本生成的视频片段到最终成片的自动化 AI 剪辑流程。
### 🎯 集成目标
- **自动化剪辑**: 在 Video-Flow 工作流中实现一键 AI 剪辑功能
- **自动化剪辑**: 在 video-flow-b 工作流中实现一键 AI 剪辑功能
- **无缝集成**: 复用 OpenCut 的核心 AI 剪辑逻辑,无需重复开发
- **流程优化**: 简化从视频片段到最终成片的处理流程
- **用户体验**: 提供直观的进度反馈和错误处理机制
@ -17,7 +17,7 @@
```mermaid
graph TB
subgraph "Video-Flow 前端层"
subgraph "video-flow-b 前端层"
A[work-flow.tsx] --> B[ai-editing-button.tsx]
B --> C[ai-editing-adapter.ts]
end
@ -33,7 +33,7 @@ graph TB
G --> H[云存储上传]
end
subgraph "Video-Flow 后端"
subgraph "video-flow-b 后端"
H --> I[任务状态更新]
I --> J[最终成片展示]
end
@ -75,7 +75,7 @@ classDiagram
## 📁 文件结构
```
video-flow/
video-flow-b/
├── components/pages/work-flow/
│ ├── ai-editing-adapter.ts # AI剪辑逻辑适配器
│ ├── ai-editing-button.tsx # AI剪辑按钮组件
@ -93,7 +93,7 @@ video-flow/
### 1. AI 剪辑适配器 (`ai-editing-adapter.ts`)
**职责**: 将 Video-Flow 的数据结构转换为 OpenCut 兼容格式,并管理整个 AI 剪辑流程。
**职责**: 将 video-flow-b 的数据结构转换为 OpenCut 兼容格式,并管理整个 AI 剪辑流程。
**核心功能**:
@ -116,7 +116,7 @@ class AIEditingAdapter {
**数据转换逻辑**:
```typescript
// Video-Flow格式 -> OpenCut AI剪辑格式
// video-flow-b格式 -> OpenCut AI剪辑格式
{
videos: VideoFlowVideoData[]
}
@ -168,7 +168,7 @@ class AIEditingAdapter {
### 1. 触发条件
```typescript
// 当Video-Flow工作流进入video阶段且有视频片段时
// 当video-flow-b工作流进入video阶段且有视频片段时
if (taskObject.currentStage === "video" && taskObject.videos.data.length > 0) {
// 显示AI剪辑按钮
showAIEditingButton = true;
@ -213,7 +213,7 @@ sequenceDiagram
**输入数据结构**:
```typescript
// Video-Flow视频数据
// video-flow-b视频数据
interface VideoFlowVideoData {
id: string;
url: string;
@ -355,7 +355,7 @@ FFMPEG_PATH=/usr/local/bin/ffmpeg
```typescript
describe("AIEditingAdapter", () => {
test("应该正确转换Video-Flow数据格式", () => {
test("应该正确转换video-flow-b数据格式", () => {
const adapter = new AIEditingAdapter(mockTaskObject);
const result = adapter.convertVideoFlowToAIClips();
expect(result).toHaveLength(mockTaskObject.videos.data.length);
@ -451,7 +451,7 @@ console.log("✅ 处理完成:", finalVideoUrl);
## 📚 参考资料
- [OpenCut 项目文档](../apps/web/README.md)
- [Video-Flow 项目文档](./README.md)
- [video-flow-b 项目文档](./README.md)
- [FFmpeg 官方文档](https://ffmpeg.org/documentation.html)
- [Next.js API Routes 文档](https://nextjs.org/docs/api-routes/introduction)
- [Server-Sent Events 规范](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)

View File

@ -2,7 +2,7 @@
## 📋 概述
本文档详细记录了 Video-Flow 项目中 Google OAuth2 登录功能的完整实现,包括前端 UI 集成、后端 API 对接、错误处理和安全机制等。
本文档详细记录了 video-flow-b 项目中 Google OAuth2 登录功能的完整实现,包括前端 UI 集成、后端 API 对接、错误处理和安全机制等。
**实现日期:** 2024 年 12 月
@ -770,4 +770,4 @@ const signInWithGoogleRetry = async (maxRetries = 3) => {
**最后更新**: 2024 年 12 月 19 日
**版本**: v1.0.0
**维护者**: Video-Flow 开发团队
**维护者**: video-flow-b 开发团队

View File

@ -118,4 +118,4 @@ if (result.success) {
文档版本v4.0
更新时间2025-09-23
适用范围video-flow 前端项目
适用范围video-flow-b 前端项目

View File

@ -2,7 +2,7 @@
## 📋 概述
本文档为Video-Flow视频编辑功能的后端API提供完整的实现规范包括RESTful API设计、数据结构定义、认证机制、数据库设计等为后端开发团队提供详细的实现指南。
本文档为video-flow-b视频编辑功能的后端API提供完整的实现规范包括RESTful API设计、数据结构定义、认证机制、数据库设计等为后端开发团队提供详细的实现指南。
## 🏗️ 系统架构
@ -622,4 +622,4 @@ def test_create_edit_point():
**文档版本**: v1.0.0
**最后更新**: 2024-09-19
**维护者**: Video-Flow 开发团队
**维护者**: video-flow-b 开发团队

View File

@ -1,8 +1,8 @@
# Video-Flow 自动下载功能禁用说明
# video-flow-b 自动下载功能禁用说明
## 📋 修改概述
根据需求,已将 Video-Flow 工作流中的自动下载视频功能暂时禁用,用户需要手动下载生成的视频。
根据需求,已将 video-flow-b 工作流中的自动下载视频功能暂时禁用,用户需要手动下载生成的视频。
## 🔍 工作流程梳理

View File

@ -1,4 +1,4 @@
# ⚡ Video-Flow 性能优化快速实施指南
# ⚡ video-flow-b 性能优化快速实施指南
> **紧急修复清单** - 可在1-2天内完成立即提升50%+性能

18
package-lock.json generated
View File

@ -91,6 +91,7 @@
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.19",
"env-cmd": "^10.1.0",
"jest": "^29.7.0",
"ts-jest": "^29.1.2"
}
@ -10247,6 +10248,23 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/env-cmd": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz",
"integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==",
"dev": true,
"license": "MIT",
"dependencies": {
"commander": "^4.0.0",
"cross-spawn": "^7.0.0"
},
"bin": {
"env-cmd": "bin/env-cmd.js"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz",