nuwax-file-server 1.2.4 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +131 -151
  2. package/dist/appConfig/index.js +1 -1
  3. package/dist/cli.js +1 -1
  4. package/dist/config/swagger.js +1 -1
  5. package/dist/routes/buildRoutes.js +1 -1
  6. package/dist/routes/codeRoutes.js +1 -1
  7. package/dist/routes/computerRoutes.js +1 -1
  8. package/dist/routes/projectRoutes.js +1 -1
  9. package/dist/scheduler/pnpmPruneScheduler.js +2 -2
  10. package/dist/server.js +1 -1
  11. package/dist/service/codeService.js +2 -2
  12. package/dist/service/projectService.js +1 -1
  13. package/dist/utils/build/buildProjectUtils.js +4 -4
  14. package/dist/utils/build/keepAliveDevUtils.js +1 -1
  15. package/dist/utils/build/processManager.js +9 -9
  16. package/dist/utils/build/restartDevUtils.js +1 -1
  17. package/dist/utils/build/startDevUtils.js +1 -1
  18. package/dist/utils/build/stopDevUtils.js +2 -2
  19. package/dist/utils/build/syntaxCheckUtils.js +7 -7
  20. package/dist/utils/buildArg/extraArgsUtils.js +1 -1
  21. package/dist/utils/buildArg/portPool.js +1 -1
  22. package/dist/utils/buildArg/portUtils.js +7 -7
  23. package/dist/utils/buildDependency/dependencyManager.js +17 -17
  24. package/dist/utils/buildJudge/aliveJudgeUtils.js +1 -1
  25. package/dist/utils/buildJudge/restartJudgeUtils.js +1 -1
  26. package/dist/utils/buildPermission/permissionManager.js +3 -3
  27. package/dist/utils/common/npmrcUtils.js +3 -3
  28. package/dist/utils/common/zipUtils.js +1 -1
  29. package/dist/utils/computer/computerFileUtils.js +1 -1
  30. package/dist/utils/computer/computerUtils.js +1 -1
  31. package/dist/utils/envUtils.js +3 -3
  32. package/dist/utils/error/buildErrorParser.js +18 -18
  33. package/dist/utils/error/errorHandler.js +1 -1
  34. package/dist/utils/log/getDevLogUtils.js +2 -2
  35. package/dist/utils/log/logCacheManager.js +2 -2
  36. package/dist/utils/log/logUtils.js +2 -2
  37. package/dist/utils/project/backupUtils.js +1 -1
  38. package/dist/utils/project/copyProjectUtils.js +1 -1
  39. package/dist/utils/project/frameworkDetectorUtils.js +1 -1
  40. package/dist/utils/project/getContentUtils.js +1 -1
  41. package/dist/utils/project/initProjectCleanupUtils.js +1 -1
  42. package/dist/utils/project/uploadAttachmentFileUtils.js +1 -1
  43. package/dist/utils/serviceManager.js +3 -3
  44. package/package.json +2 -2
@@ -1 +1 @@
1
- import y from"express";import g from"multer";import f from"path";import c from"fs";import S from"iconv-lite";import p from"../service/projectService.js";import{getProjectContent as E,getProjectContentByVersion as I}from"../utils/project/getContentUtils.js";import{uploadAttachmentFile as P}from"../utils/project/uploadAttachmentFileUtils.js";import{copyProject as x}from"../utils/project/copyProjectUtils.js";import m from"../appConfig/index.js";import{log as u}from"../utils/log/logUtils.js";import{ValidationError as r,SystemError as D,asyncHandler as d}from"../utils/error/errorHandler.js";const w=y.Router(),R=g.diskStorage({destination:function(e,n,t){const o=f.join(m.UPLOAD_PROJECT_DIR,"temp");c.existsSync(o)||c.mkdirSync(o,{recursive:!0}),t(null,o)},filename:function(e,n,t){const o=Date.now()+"-"+Math.round(Math.random()*1e6);t(null,n.fieldname+"-"+o+f.extname(n.originalname))}}),O=g({storage:R,fileFilter:function(e,n,t){const o=f.extname(n.originalname).toLowerCase();m.UPLOAD_ALLOWED_EXTENSIONS.includes(o)?t(null,!0):t(new r("\u6587\u4EF6\u7C7B\u578B\u4E0D\u88AB\u5141\u8BB8",{fileExtension:o,allowedExtensions:m.UPLOAD_ALLOWED_EXTENSIONS}),!1)},limits:{fileSize:m.UPLOAD_MAX_FILE_SIZE_BYTES}}),_=g.diskStorage({destination:function(e,n,t){const o=f.join(m.UPLOAD_PROJECT_DIR,"temp");c.existsSync(o)||c.mkdirSync(o,{recursive:!0}),t(null,o)},filename:function(e,n,t){const o=Date.now()+"-"+Math.round(Math.random()*1e6);t(null,n.fieldname+"-"+o+f.extname(n.originalname))}}),j=[".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".txt",".md",".csv",".json",".xml",".png",".jpg",".jpeg",".gif",".bmp",".svg",".ico",".webp",".avif",".zip",".rar",".7z",".tar",".gz",".mp4",".avi",".mov",".wmv",".flv",".mp3",".wav",".ogg",".m4a"],z=g({storage:_,fileFilter:function(e,n,t){const o=f.extname(n.originalname).toLowerCase();j.includes(o)?t(null,!0):t(new r("\u9644\u4EF6\u6587\u4EF6\u7C7B\u578B\u4E0D\u88AB\u5141\u8BB8",{fileExtension:o,allowedExtensions:j}),!1)},limits:{fileSize:m.UPLOAD_MAX_FILE_SIZE_BYTES}});function A(e,n,t){if(e.file&&e.file.originalname)try{const o=e.file.originalname,i=S.decode(Buffer.from(e.file.originalname,"latin1"),"utf8");e.file.originalname=i,u("system","INFO","\u6587\u4EF6\u540D\u89E3\u7801\u6210\u529F",{before:o,after:i})}catch(o){u("system","WARN","\u6587\u4EF6\u540D\u89E3\u7801\u5931\u8D25",{originalName:e.file.originalname,error:o.message})}t()}const L=[{path:"/create-project",method:"post",handler:d(async(e,n)=>{const{projectId:t}=e.body;if(!t)throw new r("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const o=await p.createProject(String(t));n.status(200).json(o)})},{path:"/upload-project",method:"post",handler:O.single("file"),customHandler:d(async(e,n)=>{const{projectId:t,codeVersion:o,pid:i,basePath:s}=e.body;if(!t)throw new r("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(!o)throw new r("\u4EE3\u7801\u7248\u672C\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});if(!e.file)throw new r("\u8BF7\u4E0A\u4F20\u538B\u7F29\u5305\u6587\u4EF6",{field:"zipFile"});const a=await p.handleFileUpload(String(t),o,e.file);e.file.path=a.filePath;try{const l=await p.uploadProject(String(t),e.file.path,e,o,i,s);n.status(200).json(l)}catch(l){try{await p.cleanupProjectDirectory(String(t))}catch(h){u(t,"ERROR","\u8DEF\u7531\u5C42\u6E05\u7406\u9879\u76EE\u76EE\u5F55\u5931\u8D25",{projectId:t,error:h.message})}if(e.file&&c.existsSync(e.file.path))try{c.unlinkSync(e.file.path)}catch(h){u(t,"ERROR","\u6E05\u7406\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25",{projectId:t,error:h.message})}throw l}})},{path:"/get-project-content",method:"get",handler:d(async(e,n)=>{const{projectId:t,command:o,proxyPath:i}=e.query;if(!t)throw new r("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const s=f.join(m.PROJECT_SOURCE_DIR,t);if(!c.existsSync(s))throw new r("\u9879\u76EE\u4E0D\u5B58\u5728",{field:"projectId"});try{const a=await E(s,o,i);n.status(200).json({success:!0,...a})}catch(a){const l=a?.message||"\u67E5\u8BE2\u5931\u8D25";n.status(500).json({success:!1,message:l})}})},{path:"/get-project-content-by-version",method:"get",handler:d(async(e,n)=>{const{projectId:t,codeVersion:o,command:i,proxyPath:s}=e.query;if(!t)throw new r("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(!o)throw new r("\u4EE3\u7801\u7248\u672C\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});try{const a=await I(String(t),o,i,s);n.status(200).json({success:!0,...a})}catch(a){const l=a?.message||"\u67E5\u8BE2\u5931\u8D25";n.status(500).json({success:!1,message:l})}})},{path:"/backup-current-version",method:"post",handler:d(async(e,n)=>{const{projectId:t,codeVersion:o}=e.body,i=await p.backupCurrentVersion(String(t),o);n.status(200).json({success:!0,...i})})},{path:"/export-project",method:"post",handler:d(async(e,n)=>{const{projectId:t,codeVersion:o,exportType:i,config:s}=e.body,a=await p.exportProject(String(t),o,i,s);if(!c.existsSync(a.zipPath))throw new D("\u5BFC\u51FA\u7684zip\u6587\u4EF6\u4E0D\u5B58\u5728",{zipPath:a.zipPath});const l=f.basename(a.zipPath);n.setHeader("Content-Type","application/zip"),n.setHeader("Content-Disposition",`attachment; filename="${l}"`),n.sendFile(a.zipPath,h=>{h?(u(t,"ERROR","\u53D1\u9001zip\u6587\u4EF6\u5931\u8D25",{projectId:t,error:h.message}),n.headersSent||n.status(500).json({success:!1,message:"\u6587\u4EF6\u53D1\u9001\u5931\u8D25"})):u(t,"INFO","zip\u6587\u4EF6\u53D1\u9001\u6210\u529F",{projectId:t,zipPath:a.zipPath})})})},{path:"/delete-project",method:"get",handler:d(async(e,n)=>{const{projectId:t,pid:o}=e.query;if(!t)throw new r("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const i=await p.deleteProject(String(t),o,e);n.status(200).json(i)})},{path:"/upload-attachment-file",method:"post",handler:z.single("file"),decodeMiddleware:A,customHandler:d(async(e,n)=>{const{projectId:t,fileName:o}=e.body;if(!t)throw new r("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(!e.file)throw new r("\u8BF7\u4E0A\u4F20\u6587\u4EF6",{field:"file"});try{const i=await P(String(t),e.file,o);n.status(200).json({success:!0,...i})}catch(i){if(e.file&&c.existsSync(e.file.path))try{c.unlinkSync(e.file.path)}catch(s){u(t,"ERROR","\u6E05\u7406\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25",{projectId:t,error:s.message})}throw i}})},{path:"/copy-project",method:"post",handler:d(async(e,n)=>{const{sourceProjectId:t,targetProjectId:o}=e.body;if(!t)throw new r("\u6E90\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"sourceProjectId"});if(!o)throw new r("\u76EE\u6807\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"targetProjectId"});const i=await x(String(t),String(o));n.status(200).json(i)})}];function N(e,n,t,o){if(e instanceof g.MulterError||e.name==="ValidationError"||e instanceof r)return o(e);o(e)}L.forEach(e=>{if(e.customHandler){const n=[];e.handler&&n.push(e.handler),e.decodeMiddleware&&n.push(e.decodeMiddleware),n.push(N),n.push(e.customHandler),w[e.method](e.path,...n)}else w[e.method](e.path,e.handler)});export default w;
1
+ import w from"express";import y from"multer";import p from"path";import c from"fs";import S from"iconv-lite";import f from"../service/projectService.js";import{getProjectContent as P,getProjectContentByVersion as E}from"../utils/project/getContentUtils.js";import{uploadAttachmentFile as I}from"../utils/project/uploadAttachmentFileUtils.js";import{copyProject as x}from"../utils/project/copyProjectUtils.js";import m from"../appConfig/index.js";import{log as u}from"../utils/log/logUtils.js";import{ValidationError as a,SystemError as D,asyncHandler as d}from"../utils/error/errorHandler.js";const j=w.Router(),R=y.diskStorage({destination:function(e,n,t){const o=p.join(m.UPLOAD_PROJECT_DIR,"temp");c.existsSync(o)||c.mkdirSync(o,{recursive:!0}),t(null,o)},filename:function(e,n,t){const o=Date.now()+"-"+Math.round(Math.random()*1e6);t(null,n.fieldname+"-"+o+p.extname(n.originalname))}}),b=y({storage:R,fileFilter:function(e,n,t){const o=p.extname(n.originalname).toLowerCase();m.UPLOAD_ALLOWED_EXTENSIONS.includes(o)?t(null,!0):t(new a("File type not allowed",{fileExtension:o,allowedExtensions:m.UPLOAD_ALLOWED_EXTENSIONS}),!1)},limits:{fileSize:m.UPLOAD_MAX_FILE_SIZE_BYTES}}),O=y.diskStorage({destination:function(e,n,t){const o=p.join(m.UPLOAD_PROJECT_DIR,"temp");c.existsSync(o)||c.mkdirSync(o,{recursive:!0}),t(null,o)},filename:function(e,n,t){const o=Date.now()+"-"+Math.round(Math.random()*1e6);t(null,n.fieldname+"-"+o+p.extname(n.originalname))}}),g=[".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".txt",".md",".csv",".json",".xml",".png",".jpg",".jpeg",".gif",".bmp",".svg",".ico",".webp",".avif",".zip",".rar",".7z",".tar",".gz",".mp4",".avi",".mov",".wmv",".flv",".mp3",".wav",".ogg",".m4a"],_=y({storage:O,fileFilter:function(e,n,t){const o=p.extname(n.originalname).toLowerCase();g.includes(o)?t(null,!0):t(new a("\u9644\u4EF6\u6587\u4EF6\u7C7B\u578B\u4E0D\u88AB\u5141\u8BB8",{fileExtension:o,allowedExtensions:g}),!1)},limits:{fileSize:m.UPLOAD_MAX_FILE_SIZE_BYTES}});function z(e,n,t){if(e.file&&e.file.originalname)try{const o=e.file.originalname,i=S.decode(Buffer.from(e.file.originalname,"latin1"),"utf8");e.file.originalname=i,u("system","INFO","File name decoded successfully",{before:o,after:i})}catch(o){u("system","WARN","File name decoded failed",{originalName:e.file.originalname,error:o.message})}t()}const v=[{path:"/create-project",method:"post",handler:d(async(e,n)=>{const{projectId:t}=e.body;if(!t)throw new a("Project ID cannot be empty",{field:"projectId"});const o=await f.createProject(String(t));n.status(200).json(o)})},{path:"/upload-project",method:"post",handler:b.single("file"),customHandler:d(async(e,n)=>{const{projectId:t,codeVersion:o,pid:i,basePath:s}=e.body;if(!t)throw new a("Project ID cannot be empty",{field:"projectId"});if(!o)throw new a("Code version cannot be empty",{field:"codeVersion"});if(!e.file)throw new a("Please upload a zip file",{field:"zipFile"});const r=await f.handleFileUpload(String(t),o,e.file);e.file.path=r.filePath;try{const l=await f.uploadProject(String(t),e.file.path,e,o,i,s);n.status(200).json(l)}catch(l){try{await f.cleanupProjectDirectory(String(t))}catch(h){u(t,"ERROR","Route layer cleanup project directory failed",{projectId:t,error:h.message})}if(e.file&&c.existsSync(e.file.path))try{c.unlinkSync(e.file.path)}catch(h){u(t,"ERROR","Clean upload file failed",{projectId:t,error:h.message})}throw l}})},{path:"/get-project-content",method:"get",handler:d(async(e,n)=>{const{projectId:t,command:o,proxyPath:i}=e.query;if(!t)throw new a("Project ID cannot be empty",{field:"projectId"});const s=p.join(m.PROJECT_SOURCE_DIR,t);if(!c.existsSync(s))throw new a("Project does not exist",{field:"projectId"});try{const r=await P(s,o,i);n.status(200).json({success:!0,...r})}catch(r){const l=r?.message||"Query failed";n.status(500).json({success:!1,message:l})}})},{path:"/get-project-content-by-version",method:"get",handler:d(async(e,n)=>{const{projectId:t,codeVersion:o,command:i,proxyPath:s}=e.query;if(!t)throw new a("Project ID cannot be empty",{field:"projectId"});if(!o)throw new a("Code version cannot be empty",{field:"codeVersion"});try{const r=await E(String(t),o,i,s);n.status(200).json({success:!0,...r})}catch(r){const l=r?.message||"Query failed";n.status(500).json({success:!1,message:l})}})},{path:"/backup-current-version",method:"post",handler:d(async(e,n)=>{const{projectId:t,codeVersion:o}=e.body,i=await f.backupCurrentVersion(String(t),o);n.status(200).json({success:!0,...i})})},{path:"/export-project",method:"post",handler:d(async(e,n)=>{const{projectId:t,codeVersion:o,exportType:i,config:s}=e.body,r=await f.exportProject(String(t),o,i,s);if(!c.existsSync(r.zipPath))throw new D("Exported zip file does not exist",{zipPath:r.zipPath});const l=p.basename(r.zipPath);n.setHeader("Content-Type","application/zip"),n.setHeader("Content-Disposition",`attachment; filename="${l}"`),n.sendFile(r.zipPath,h=>{h?(u(t,"ERROR","Send zip file failed",{projectId:t,error:h.message}),n.headersSent||n.status(500).json({success:!1,message:"File send failed"})):u(t,"INFO","Zip file send successfully",{projectId:t,zipPath:r.zipPath})})})},{path:"/delete-project",method:"get",handler:d(async(e,n)=>{const{projectId:t,pid:o}=e.query;if(!t)throw new a("Project ID cannot be empty",{field:"projectId"});const i=await f.deleteProject(String(t),o,e);n.status(200).json(i)})},{path:"/upload-attachment-file",method:"post",handler:_.single("file"),decodeMiddleware:z,customHandler:d(async(e,n)=>{const{projectId:t,fileName:o}=e.body;if(!t)throw new a("Project ID cannot be empty",{field:"projectId"});if(!e.file)throw new a("Please upload a file",{field:"file"});try{const i=await I(String(t),e.file,o);n.status(200).json({success:!0,...i})}catch(i){if(e.file&&c.existsSync(e.file.path))try{c.unlinkSync(e.file.path)}catch(s){u(t,"ERROR","Clean upload file failed",{projectId:t,error:s.message})}throw i}})},{path:"/copy-project",method:"post",handler:d(async(e,n)=>{const{sourceProjectId:t,targetProjectId:o}=e.body;if(!t)throw new a("Source project ID cannot be empty",{field:"sourceProjectId"});if(!o)throw new a("Target project ID cannot be empty",{field:"targetProjectId"});const i=await x(String(t),String(o));n.status(200).json(i)})}];function A(e,n,t,o){if(e instanceof y.MulterError||e.name==="ValidationError"||e instanceof a)return o(e);o(e)}v.forEach(e=>{if(e.customHandler){const n=[];e.handler&&n.push(e.handler),e.decodeMiddleware&&n.push(e.decodeMiddleware),n.push(A),n.push(e.customHandler),j[e.method](e.path,...n)}else j[e.method](e.path,e.handler)});export default j;
@@ -1,2 +1,2 @@
1
- import o from"node-cron";import{exec as a}from"child_process";import"fs";import"path";import{log as e}from"../utils/log/logUtils.js";class h{constructor(t={}){this.config={enabled:process.env.PNPM_PRUNE_ENABLED!=="false",schedule:process.env.PNPM_PRUNE_SCHEDULE||"0 2 * * 0",timezone:process.env.PNPM_PRUNE_TIMEZONE||"Asia/Shanghai",runOnStart:process.env.PNPM_PRUNE_RUN_ON_START==="true",...t},this.task=null,this.isRunning=!1}start(){if(!this.config.enabled){e("scheduler","INFO","pnpm prune \u5B9A\u65F6\u4EFB\u52A1\u5DF2\u7981\u7528\uFF08PNPM_PRUNE_ENABLED=false\uFF09");return}if(!o.validate(this.config.schedule)){e("scheduler","ERROR",`\u65E0\u6548\u7684 cron \u8868\u8FBE\u5F0F: ${this.config.schedule}`);return}e("scheduler","INFO","pnpm prune \u5B9A\u65F6\u4EFB\u52A1\u5DF2\u542F\u52A8",{schedule:this.config.schedule,timezone:this.config.timezone}),this.task=o.schedule(this.config.schedule,()=>{this.executePrune()},{scheduled:!0,timezone:this.config.timezone}),this.config.runOnStart&&(e("scheduler","INFO","\u542F\u52A8\u65F6\u7ACB\u5373\u6267\u884C\u4E00\u6B21 pnpm prune"),setTimeout(()=>{this.executePrune()},5e3))}stop(){this.task&&(this.task.stop(),e("scheduler","INFO","pnpm prune \u5B9A\u65F6\u4EFB\u52A1\u5DF2\u505C\u6B62"))}async executePrune(){if(this.isRunning){e("scheduler","WARN","pnpm prune \u6B63\u5728\u6267\u884C\u4E2D\uFF0C\u8DF3\u8FC7\u672C\u6B21\u8C03\u5EA6");return}this.isRunning=!0,e("scheduler","INFO","===================================="),e("scheduler","INFO","\u5F00\u59CB\u6267\u884C pnpm store prune"),e("scheduler","INFO","====================================");try{const t=await this.getStoreStatus();t&&e("scheduler","INFO","\u6E05\u7406\u524D\u72B6\u6001",t);const s=await this.runCommand("pnpm store prune");if(s.success){e("scheduler","INFO","\u2705 pnpm store prune \u6267\u884C\u6210\u529F"),s.stdout&&e("scheduler","INFO",s.stdout);const r=await this.getStoreStatus();r&&e("scheduler","INFO","\u6E05\u7406\u540E\u72B6\u6001",r)}else e("scheduler","ERROR","\u274C pnpm store prune \u6267\u884C\u5931\u8D25",{error:s.error})}catch(t){e("scheduler","ERROR","pnpm prune \u6267\u884C\u5F02\u5E38",{error:t.message})}finally{this.isRunning=!1,e("scheduler","INFO","===================================="),e("scheduler","INFO","pnpm store prune \u6267\u884C\u5B8C\u6210"),e("scheduler","INFO",`====================================
2
- `)}}async getStoreStatus(){try{const t=await this.runCommand("pnpm store path");if(!t.success)return null;const s=t.stdout.trim(),r=await this.runCommand(`du -sh "${s}"`),c=r.success?r.stdout.trim().split(" ")[0]:"unknown";return{path:s,size:c}}catch{return null}}runCommand(t){return new Promise(s=>{a(t,{maxBuffer:10*1024*1024,env:process.env},(r,c,l)=>{s(r?{success:!1,error:r.message,stderr:l}:{success:!0,stdout:c})})})}getNextRun(){return{schedule:this.config.schedule,timezone:this.config.timezone}}}let u=null;function i(n){return u||(u=new h(n)),u}function p(n){const t=i(n);return t.start(),t}function d(){u&&u.stop()}async function m(n={}){await i(n).executePrune()}export{h as PnpmPruneScheduler,i as getScheduler,p as startScheduler,d as stopScheduler,m as executePruneManually};
1
+ import o from"node-cron";import{exec as a}from"child_process";import"fs";import"path";import{log as e}from"../utils/log/logUtils.js";class h{constructor(s={}){this.config={enabled:process.env.PNPM_PRUNE_ENABLED!=="false",schedule:process.env.PNPM_PRUNE_SCHEDULE||"0 2 * * 0",timezone:process.env.PNPM_PRUNE_TIMEZONE||"Asia/Shanghai",runOnStart:process.env.PNPM_PRUNE_RUN_ON_START==="true",...s},this.task=null,this.isRunning=!1}start(){if(!this.config.enabled){e("scheduler","INFO","pnpm prune scheduler is disabled (PNPM_PRUNE_ENABLED=false)");return}if(!o.validate(this.config.schedule)){e("scheduler","ERROR",`Invalid cron expression: ${this.config.schedule}`);return}e("scheduler","INFO","pnpm prune scheduler is started",{schedule:this.config.schedule,timezone:this.config.timezone}),this.task=o.schedule(this.config.schedule,()=>{this.executePrune()},{scheduled:!0,timezone:this.config.timezone}),this.config.runOnStart&&(e("scheduler","INFO","Immediately execute pnpm prune on startup"),setTimeout(()=>{this.executePrune()},5e3))}stop(){this.task&&(this.task.stop(),e("scheduler","INFO","pnpm prune scheduler is stopped"))}async executePrune(){if(this.isRunning){e("scheduler","WARN","pnpm prune is running, skipping this schedule");return}this.isRunning=!0,e("scheduler","INFO","===================================="),e("scheduler","INFO","Start executing pnpm store prune"),e("scheduler","INFO","====================================");try{const s=await this.getStoreStatus();s&&e("scheduler","INFO","Before status",s);const t=await this.runCommand("pnpm store prune");if(t.success){e("scheduler","INFO","\u2705 pnpm store prune executed successfully"),t.stdout&&e("scheduler","INFO",t.stdout);const r=await this.getStoreStatus();r&&e("scheduler","INFO","After status",r)}else e("scheduler","ERROR","\u274C pnpm store prune executed failed",{error:t.error})}catch(s){e("scheduler","ERROR","pnpm prune executed exception",{error:s.message})}finally{this.isRunning=!1,e("scheduler","INFO","===================================="),e("scheduler","INFO","pnpm store prune executed successfully"),e("scheduler","INFO",`====================================
2
+ `)}}async getStoreStatus(){try{const s=await this.runCommand("pnpm store path");if(!s.success)return null;const t=s.stdout.trim(),r=await this.runCommand(`du -sh "${t}"`),c=r.success?r.stdout.trim().split(" ")[0]:"unknown";return{path:t,size:c}}catch{return null}}runCommand(s){return new Promise(t=>{a(s,{maxBuffer:10*1024*1024,env:process.env},(r,c,l)=>{t(r?{success:!1,error:r.message,stderr:l}:{success:!0,stdout:c})})})}getNextRun(){return{schedule:this.config.schedule,timezone:this.config.timezone}}}let u=null;function i(n){return u||(u=new h(n)),u}function d(n){const s=i(n);return s.start(),s}function p(){u&&u.stop()}async function f(n={}){await i(n).executePrune()}export{h as PnpmPruneScheduler,i as getScheduler,d as startScheduler,p as stopScheduler,f as executePruneManually};
package/dist/server.js CHANGED
@@ -1 +1 @@
1
- import O from"express";import"json-bigint";import m from"swagger-ui-express";import E from"./config/swagger.js";import s from"./appConfig/index.js";import{log as c,logger as I}from"./utils/log/logUtils.js";import S from"./utils/log/logCacheManager.js";import{errorHandler as P,notFoundHandler as w}from"./utils/error/errorHandler.js";import R from"./routes/router.js";import{cleanupInitProjectOnStartup as y}from"./utils/project/initProjectCleanupUtils.js";import{startScheduler as N,stopScheduler as D}from"./scheduler/pnpmPruneScheduler.js";import T from"path";const o=O();o.use(O.json({limit:s.REQUEST_BODY_LIMIT,reviver:(t,e)=>typeof e=="number"&&!Number.isSafeInteger(e)?e.toString():e})),o.use(O.urlencoded({extended:!0,limit:s.REQUEST_BODY_LIMIT})),o.use(I);const f=t=>{let e=t;try{for(;;){const n=decodeURIComponent(e);if(n===e)break;e=n}}catch{}return e};o.use("/api/page/static/:projectId",(t,e,n)=>{const{projectId:l}=t.params;let i=t.path||"/";if(!l||i==="/")return e.status(404).send("Not Found");const r=t.headers.origin,a=r||"*";if(e.header("Access-Control-Allow-Origin",a),e.header("Access-Control-Allow-Methods","HEAD,GET,POST,PUT,DELETE,OPTIONS"),e.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control, Fragment"),e.header("Access-Control-Expose-Headers","Content-Type"),r&&(e.header("Access-Control-Allow-Credentials","true"),e.header("Vary","Origin")),t.method==="OPTIONS")return e.sendStatus(200);i=i.replace(/^\/+/,"");const p=f(i),A=T.join(s.PROJECT_SOURCE_DIR,l,p),d={"Access-Control-Allow-Origin":a,"Access-Control-Allow-Methods":"HEAD,GET,POST,PUT,DELETE,OPTIONS","Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control, Fragment"};return r&&(d["Access-Control-Allow-Credentials"]="true",d.Vary="Origin"),e.sendFile(A,{dotfiles:"allow",headers:d},u=>{if(u)return n()})}),o.use("/api/computer/static/:userId/:cId",(t,e,n)=>{const{userId:l,cId:i}=t.params;let r=t.path||"/";if(!l||!i||r==="/")return e.status(404).send("Not Found");const a=t.headers.origin,p=a||"*";if(e.header("Access-Control-Allow-Origin",p),e.header("Access-Control-Allow-Methods","HEAD,GET,POST,PUT,DELETE,OPTIONS"),e.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control"),e.header("Access-Control-Expose-Headers","Content-Type"),a&&(e.header("Access-Control-Allow-Credentials","true"),e.header("Vary","Origin")),t.method==="OPTIONS")return e.sendStatus(200);r=r.replace(/^\/+/,"");const A=f(r),d=T.join(s.COMPUTER_WORKSPACE_DIR,l,i,A),u={"Access-Control-Allow-Origin":p,"Access-Control-Allow-Methods":"HEAD,GET,POST,PUT,DELETE,OPTIONS","Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control"};return a&&(u["Access-Control-Allow-Credentials"]="true",u.Vary="Origin"),e.sendFile(d,{dotfiles:"allow",headers:u},g=>{if(g)return n()})}),o.use("/api-docs",m.serve,m.setup(E,{customCss:".swagger-ui .topbar { display: none }",customSiteTitle:"nuwax-file-server API \u6587\u6863"})),o.use(R),o.use(w),o.use(P);const h=o.listen(s.PORT,async()=>{c("default","INFO",`Server is running on port ${s.PORT} (${s.NODE_ENV} mode)`),await y(s);try{N()}catch(t){c("default","ERROR",`pnpm prune \u5B9A\u65F6\u4EFB\u52A1\u542F\u52A8\u5931\u8D25: ${t.message}`)}});h.timeout=6e5,h.keepAliveTimeout=61e4,h.headersTimeout=62e4;const C=t=>{c("default","INFO",`\u6536\u5230 ${t} \u4FE1\u53F7\uFF0C\u51C6\u5907\u4F18\u96C5\u9000\u51FA...`),D();try{S.destroy(),c("default","INFO","\u65E5\u5FD7\u7F13\u5B58\u7BA1\u7406\u5668\u5DF2\u6E05\u7406")}catch(e){c("default","ERROR",`\u6E05\u7406\u65E5\u5FD7\u7F13\u5B58\u7BA1\u7406\u5668\u5931\u8D25: ${e.message}`)}h.close(()=>{c("default","INFO","\u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(0)}),setTimeout(()=>{c("default","ERROR","\u5F3A\u5236\u9000\u51FA\uFF08\u8D85\u65F6\uFF09"),process.exit(1)},3e4)};process.on("SIGTERM",()=>C("SIGTERM")),process.on("SIGINT",()=>C("SIGINT"));
1
+ import A from"express";import"json-bigint";import O from"swagger-ui-express";import E from"./config/swagger.js";import s from"./appConfig/index.js";import{log as a,logger as I}from"./utils/log/logUtils.js";import S from"./utils/log/logCacheManager.js";import{errorHandler as P,notFoundHandler as w}from"./utils/error/errorHandler.js";import R from"./routes/router.js";import{cleanupInitProjectOnStartup as y}from"./utils/project/initProjectCleanupUtils.js";import{startScheduler as N,stopScheduler as D}from"./scheduler/pnpmPruneScheduler.js";import g from"path";const o=A();o.use(A.json({limit:s.REQUEST_BODY_LIMIT,reviver:(t,e)=>typeof e=="number"&&!Number.isSafeInteger(e)?e.toString():e})),o.use(A.urlencoded({extended:!0,limit:s.REQUEST_BODY_LIMIT})),o.use(I);const f=t=>{let e=t;try{for(;;){const n=decodeURIComponent(e);if(n===e)break;e=n}}catch{}return e};o.use("/api/page/static/:projectId",(t,e,n)=>{const{projectId:l}=t.params;let i=t.path||"/";if(!l||i==="/")return e.status(404).send("Not Found");const r=t.headers.origin,c=r||"*";if(e.header("Access-Control-Allow-Origin",c),e.header("Access-Control-Allow-Methods","HEAD,GET,POST,PUT,DELETE,OPTIONS"),e.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control, Fragment"),e.header("Access-Control-Expose-Headers","Content-Type"),r&&(e.header("Access-Control-Allow-Credentials","true"),e.header("Vary","Origin")),t.method==="OPTIONS")return e.sendStatus(200);i=i.replace(/^\/+/,"");const p=f(i),m=g.join(s.PROJECT_SOURCE_DIR,l,p),d={"Access-Control-Allow-Origin":c,"Access-Control-Allow-Methods":"HEAD,GET,POST,PUT,DELETE,OPTIONS","Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control, Fragment"};return r&&(d["Access-Control-Allow-Credentials"]="true",d.Vary="Origin"),e.sendFile(m,{dotfiles:"allow",headers:d},u=>{if(u)return n()})}),o.use("/api/computer/static/:userId/:cId",(t,e,n)=>{const{userId:l,cId:i}=t.params;let r=t.path||"/";if(!l||!i||r==="/")return e.status(404).send("Not Found");const c=t.headers.origin,p=c||"*";if(e.header("Access-Control-Allow-Origin",p),e.header("Access-Control-Allow-Methods","HEAD,GET,POST,PUT,DELETE,OPTIONS"),e.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control"),e.header("Access-Control-Expose-Headers","Content-Type"),c&&(e.header("Access-Control-Allow-Credentials","true"),e.header("Vary","Origin")),t.method==="OPTIONS")return e.sendStatus(200);r=r.replace(/^\/+/,"");const m=f(r),d=g.join(s.COMPUTER_WORKSPACE_DIR,l,i,m),u={"Access-Control-Allow-Origin":p,"Access-Control-Allow-Methods":"HEAD,GET,POST,PUT,DELETE,OPTIONS","Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control"};return c&&(u["Access-Control-Allow-Credentials"]="true",u.Vary="Origin"),e.sendFile(d,{dotfiles:"allow",headers:u},C=>{if(C)return n()})}),o.use("/api-docs",O.serve,O.setup(E,{customCss:".swagger-ui .topbar { display: none }",customSiteTitle:"nuwax-file-server API Documentation"})),o.use(R),o.use(w),o.use(P);const h=o.listen(s.PORT,async()=>{a("default","INFO",`Server is running on port ${s.PORT} (${s.NODE_ENV} mode)`),await y(s);try{N()}catch(t){a("default","ERROR",`pnpm prune scheduled task failed to start: ${t.message}`)}});h.timeout=6e5,h.keepAliveTimeout=61e4,h.headersTimeout=62e4;const T=t=>{a("default","INFO",`Received ${t} signal, preparing graceful exit...`),D();try{S.destroy(),a("default","INFO","Log cache manager cleared")}catch(e){a("default","ERROR",`Failed to clear log cache manager: ${e.message}`)}h.close(()=>{a("default","INFO","Server closed"),process.exit(0)}),setTimeout(()=>{a("default","ERROR","Force exit (timeout)"),process.exit(1)},3e4)};process.on("SIGTERM",()=>T("SIGTERM")),process.on("SIGINT",()=>T("SIGINT"));
@@ -1,4 +1,4 @@
1
- import r from"path";import a from"fs";import F from"../appConfig/index.js";import{restartDevServer as A}from"../utils/build/restartDevUtils.js";import{log as n}from"../utils/log/logUtils.js";import{ValidationError as h,SystemError as v,ResourceError as S}from"../utils/error/errorHandler.js";import"../utils/common/sensitiveUtils.js";import{backupProjectToZip as C,restoreProjectFromZip as T,pruneMissingFiles as V,removeEmptyDirectories as z}from"../utils/project/backupUtils.js";import"../utils/common/zipUtils.js";import"../utils/buildJudge/restartJudgeUtils.js";function p(e,g){const s=e.split(/\r?\n/),E=g.split(/\r?\n/),R=s.length,u=E.length,o=Math.min(R,u);let f=0;for(let i=0;i<o;i++)s[i]!==E[i]&&(s[i]=E[i],f++);if(R>u)for(let i=R-1;i>=u;i--)s.splice(i,1),f++;if(u>R)for(let i=R;i<u;i++)s.push(E[i]),f++;const t=e.includes(`\r
1
+ import r from"path";import a from"fs";import d from"../appConfig/index.js";import{restartDevServer as _}from"../utils/build/restartDevUtils.js";import{log as i}from"../utils/log/logUtils.js";import{ValidationError as u,SystemError as S,ResourceError as O}from"../utils/error/errorHandler.js";import"../utils/common/sensitiveUtils.js";import{backupProjectToZip as D,restoreProjectFromZip as N,pruneMissingFiles as $,removeEmptyDirectories as x}from"../utils/project/backupUtils.js";import"../utils/common/zipUtils.js";import"../utils/buildJudge/restartJudgeUtils.js";function A(e,P){const n=e.split(/\r?\n/),F=P.split(/\r?\n/),b=n.length,m=F.length,o=Math.min(b,m);let f=0;for(let t=0;t<o;t++)n[t]!==F[t]&&(n[t]=F[t],f++);if(b>m)for(let t=b-1;t>=m;t--)n.splice(t,1),f++;if(m>b)for(let t=b;t<m;t++)n.push(F[t]),f++;const s=e.includes(`\r
2
2
  `)?`\r
3
3
  `:`
4
- `;return{finalContent:s.join(t),changesCount:f}}function j(e,g){return e===g?{finalContent:e,changesCount:0}:{finalContent:g,changesCount:-1}}async function x(e,g,s,E){const R=Date.now();if(!e)throw new h("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(g==null)throw new h("codeVersion\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});const u=Number(g);if(!Number.isFinite(u))throw new h("codeVersion\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});if(!Array.isArray(s))throw new h("files\u5FC5\u987B\u662F\u6570\u7EC4",{field:"files"});for(let t=0;t<s.length;t++){const w=s[t];if(!w||typeof w.operation!="string")throw new h(`files[${t}].operation \u4E0D\u80FD\u4E3A\u7A7A`,{field:`files[${t}].operation`});if(!w.name||typeof w.name!="string")throw new h(`files[${t}].name \u4E0D\u80FD\u4E3A\u7A7A`,{field:`files[${t}].name`});const i=w.operation.toLowerCase();if(!["create","delete","rename","modify"].includes(i))throw new h(`files[${t}].operation \u5FC5\u987B\u662F create\u3001delete\u3001rename \u6216 modify \u4E4B\u4E00`,{field:`files[${t}].operation`});if(i==="rename"&&!w.renameFrom)throw new h(`files[${t}].renameFrom \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u91CD\u547D\u540D\u64CD\u4F5C\u9700\u8981\uFF09`,{field:`files[${t}].renameFrom`});if(i==="modify"&&typeof w.contents!="string")throw new h(`files[${t}].contents \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\uFF08\u4FEE\u6539\u64CD\u4F5C\u9700\u8981\uFF09`,{field:`files[${t}].contents`})}const o=r.join(F.PROJECT_SOURCE_DIR,e);if(!a.existsSync(o))throw n(e,"ERROR","\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e,projectPath:o}),new S("\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e});let f="";try{const t=r.join(F.UPLOAD_PROJECT_DIR,e);a.existsSync(t)||a.mkdirSync(t,{recursive:!0});const w=`${e}-v${u}.zip`;f=r.join(t,w),n(e,"DEBUG","\u5F00\u59CB\u5907\u4EFD\u9879\u76EE",{projectId:e,backupZipPath:f}),await C(e,o,f),n(e,"INFO","\u9879\u76EE\u5DF2\u5907\u4EFD",{projectId:e,zipPath:f});try{n(e,"DEBUG","\u5F00\u59CB\u5904\u7406\u6587\u4EF6\u64CD\u4F5C",{projectId:e,filesCount:s.length});for(const i of s){const l=i.operation.toLowerCase(),c=i.name,m=r.normalize(c).replace(/^[\/\\]+/,""),P=r.join(o,m),O=r.resolve(P),y=r.resolve(o);if(!O.startsWith(y+r.sep)&&O!==y){n(e,"WARN","\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5B89\u5168\uFF0C\u8DF3\u8FC7",{filePath:m,resolvedPath:O});continue}switch(l){case"create":{await a.promises.mkdir(r.dirname(P),{recursive:!0});const b=i.contents||"";await a.promises.writeFile(P,b,"utf8"),n(e,"INFO","\u6587\u4EF6\u521B\u5EFA\u6210\u529F",{filePath:m});break}case"delete":{a.existsSync(P)?(await a.promises.unlink(P),n(e,"INFO","\u6587\u4EF6\u5220\u9664\u6210\u529F",{filePath:m})):n(e,"WARN","\u8981\u5220\u9664\u7684\u6587\u4EF6\u4E0D\u5B58\u5728",{filePath:m});break}case"rename":{const b=i.renameFrom;if(!b||typeof b!="string"){n(e,"WARN","\u91CD\u547D\u540D\u64CD\u4F5C\u7F3A\u5C11 renameFrom",{filePath:m});break}const D=r.normalize(b).replace(/^[\/\\]+/,""),k=r.join(o,D),N=r.resolve(k);if(!N.startsWith(y+r.sep)&&N!==y){n(e,"WARN","\u91CD\u547D\u540D\u6E90\u8DEF\u5F84\u4E0D\u5B89\u5168\uFF0C\u8DF3\u8FC7",{renameFrom:D,resolvedPath:N});break}a.existsSync(k)?(await a.promises.mkdir(r.dirname(P),{recursive:!0}),await a.promises.rename(k,P),n(e,"INFO","\u6587\u4EF6\u91CD\u547D\u540D\u6210\u529F",{oldPath:D,newPath:m})):n(e,"WARN","\u8981\u91CD\u547D\u540D\u7684\u6587\u4EF6\u4E0D\u5B58\u5728",{renameFrom:D});break}case"modify":{if(!a.existsSync(P)){n(e,"WARN","\u8981\u4FEE\u6539\u7684\u6587\u4EF6\u4E0D\u5B58\u5728",{filePath:m});break}const b=await a.promises.readFile(P,"utf8"),D=typeof i.contents=="string"?i.contents:"",{finalContent:k,changesCount:N}=p(b,D);if(N===0){n(e,"INFO","\u6587\u4EF6\u5185\u5BB9\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u5199\u5165",{filePath:m});break}await a.promises.writeFile(P,k,"utf8"),n(e,"INFO","\u6587\u4EF6\u4FEE\u6539\u6210\u529F",{filePath:m,changesCount:N});break}default:{n(e,"WARN","\u4E0D\u652F\u6301\u7684\u64CD\u4F5C\u7C7B\u578B",{operation:l,filePath:m});break}}}n(e,"DEBUG","\u5F00\u59CB\u6E05\u7406\u7A7A\u76EE\u5F55",{projectId:e});try{await z(o,F.TRAVERSE_EXCLUDE_DIRS||[])}catch(i){n(e,"WARN","\u6E05\u7406\u7A7A\u76EE\u5F55\u5931\u8D25",{projectId:e,error:i&&i.message})}return n(e,"INFO","\u90E8\u5206\u6587\u4EF6\u66F4\u65B0\u6210\u529F",{projectId:e,filesCount:s.length,elapsedMs:Date.now()-R}),{success:!0,message:"\u90E8\u5206\u6587\u4EF6\u66F4\u65B0\u6210\u529F",projectId:e,filesCount:s.length}}catch(i){throw n(e,"ERROR","\u5904\u7406\u6587\u4EF6\u64CD\u4F5C\u5931\u8D25",{projectId:e,error:i&&i.message,elapsedMs:Date.now()-R}),i}}catch(t){throw t.isOperational?t:new v("\u5907\u4EFD\u9879\u76EE\u5931\u8D25",{projectId:e,originalError:t&&t.message})}}async function U(e,g,s,E){const R=Date.now();if(!e)throw new h("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const u=Number(g);if(!Number.isFinite(u))throw new h("codeVersion\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});if(!Array.isArray(s))throw new h("files\u5FC5\u987B\u662F\u6570\u7EC4",{field:"files"});const o=r.join(F.PROJECT_SOURCE_DIR,e);if(!a.existsSync(o))throw n(e,"ERROR","\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e,projectPath:o}),new S("\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e});let f="";try{const t=r.join(F.UPLOAD_PROJECT_DIR,e);a.existsSync(t)||a.mkdirSync(t,{recursive:!0});const w=`${e}-v${u}.zip`;f=r.join(t,w),n(e,"DEBUG","\u5F00\u59CB\u5907\u4EFD\u9879\u76EE",{projectId:e,backupZipPath:f}),await C(e,o,f);try{n(e,"DEBUG","\u5F00\u59CB\u5199\u5165\u6587\u4EF6",{projectId:e,filesCount:s.length});for(const i of s){if(!i||typeof i.name!="string")continue;const l=r.join(o,i.name);if(i.renameFrom&&typeof i.renameFrom=="string"){const b=r.join(o,i.renameFrom);if(a.existsSync(b)){await a.promises.mkdir(r.dirname(l),{recursive:!0}),await a.promises.rename(b,l),n(e,"INFO","\u6587\u4EF6\u91CD\u547D\u540D\u6210\u529F",{projectId:e,oldPath:i.renameFrom,newPath:i.name});continue}}const c=i.binary===!0,m=i.binary===!1,P=!!i.sizeExceeded,O=typeof i.contents=="string"&&i.contents.length>0;if(c){if(a.existsSync(l)){n(e,"INFO","\u4E8C\u8FDB\u5236\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5199\u5165",{filePath:i.name});continue}if(O)try{await a.promises.mkdir(r.dirname(l),{recursive:!0});const b=Buffer.from(i.contents,"base64");await a.promises.writeFile(l,b),n(e,"INFO","\u4E8C\u8FDB\u5236\u6587\u4EF6\u5199\u5165\u6210\u529F",{filePath:i.name})}catch(b){n(e,"ERROR","\u4E8C\u8FDB\u5236\u6587\u4EF6\u5199\u5165\u5931\u8D25",{filePath:i.name,error:b&&b.message})}else n(e,"WARN","\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u5B58\u5728\u4E14\u65E0\u5185\u5BB9\uFF0C\u8DF3\u8FC7",{filePath:i.name});continue}m&&(!P||P&&O)&&(await a.promises.mkdir(r.dirname(l),{recursive:!0}),await a.promises.writeFile(l,i.contents||"","utf8"))}}catch(i){throw n(e,"ERROR","\u5199\u5165\u6587\u4EF6\u5931\u8D25",{projectId:e,error:i&&i.message,elapsedMs:Date.now()-R}),i}try{n(e,"DEBUG","\u5F00\u59CB\u6E05\u7406\u7F3A\u5931\u6587\u4EF6\u4E0E\u7A7A\u76EE\u5F55",{projectId:e});const i=new Set(s.filter(l=>l&&typeof l.name=="string").map(l=>r.normalize(l.name)));await V(o,i,F.TRAVERSE_EXCLUDE_DIRS||[]),await z(o,F.TRAVERSE_EXCLUDE_DIRS||[])}catch(i){throw n(e,"ERROR","\u6E05\u7406\u7F3A\u5931\u6587\u4EF6\u5931\u8D25\uFF0C\u5F00\u59CB\u56DE\u6EDA",{projectId:e,error:i&&i.message,elapsedMs:Date.now()-R}),i}return n(e,"INFO","\u6587\u4EF6\u63D0\u4EA4\u6210\u529F",{projectId:e,filesCount:s.length,elapsedMs:Date.now()-R}),{success:!0,message:"\u6587\u4EF6\u63D0\u4EA4\u6210\u529F",projectId:e,restarted:!1}}catch(t){throw t.isOperational?t:new v("\u5907\u4EFD\u65E7\u7248\u672C\u5931\u8D25",{projectId:e,originalError:t&&t.message})}}async function _(e,g,s,E,R){const u=Date.now();if(!e)throw new h("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const o=Number(g);if(!Number.isFinite(o))throw new h("codeVersion\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});if(!s)throw new h("\u6587\u4EF6\u4E0D\u80FD\u4E3A\u7A7A",{field:"file"});if(!E||typeof E!="string")throw new h("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A",{field:"filePath"});const f=r.join(F.PROJECT_SOURCE_DIR,e);if(!a.existsSync(f))throw n(e,"ERROR","\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e,projectPath:f}),new S("\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e});const t=r.normalize(E).replace(/^[\/\\]+/,""),w=r.join(f,t),i=r.resolve(w),l=r.resolve(f);if(!i.startsWith(l))throw new h("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5B89\u5168\uFF0C\u4E0D\u80FD\u8D85\u51FA\u9879\u76EE\u76EE\u5F55",{field:"filePath",providedPath:E,resolvedPath:i});let c="";try{const m=r.join(F.UPLOAD_PROJECT_DIR,e);a.existsSync(m)||a.mkdirSync(m,{recursive:!0});const P=`${e}-v${o}.zip`;c=r.join(m,P),n(e,"DEBUG","\u5F00\u59CB\u5907\u4EFD\u9879\u76EE",{projectId:e,backupZipPath:c}),await C(e,f,c),n(e,"INFO",`\u9879\u76EE\u5DF2\u5907\u4EFD: ${c}`,{projectId:e,zipPath:c});try{if(n(e,"DEBUG","\u5F00\u59CB\u5199\u5165\u4E0A\u4F20\u6587\u4EF6",{projectId:e,filePath:t}),await a.promises.mkdir(r.dirname(w),{recursive:!0}),!s.buffer)throw new h("\u6587\u4EF6\u5185\u5BB9\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u7F3A\u5C11buffer",{field:"file"});if(n(e,"INFO","\u51C6\u5907\u5199\u5165\u6587\u4EF6",{targetPath:w,bufferLength:s.buffer.length,expectedSize:s.size,bufferIsBuffer:Buffer.isBuffer(s.buffer),sizeMatch:s.buffer.length===s.size}),await a.promises.writeFile(w,s.buffer),n(e,"INFO","\u6587\u4EF6\u4E0A\u4F20\u6210\u529F",{projectId:e,filePath:t,targetPath:i,fileSize:s.buffer?s.buffer.length:0,elapsedMs:Date.now()-u}),!1)try{const y=await A(R,e);return n(e,"INFO","\u91CD\u542F\u5F00\u53D1\u670D\u52A1\u5668\u6210\u529F",{projectId:e,pid:y.pid,port:y.port}),{success:!0,message:"\u6587\u4EF6\u4E0A\u4F20\u5E76\u91CD\u542F\u5F00\u53D1\u670D\u52A1\u5668\u6210\u529F",projectId:e,filePath:t,targetPath:i,fileSize:s.buffer?s.buffer.length:0,pid:y.pid,port:y.port,restarted:!0}}catch(y){n(e,"ERROR","\u91CD\u542F\u5F00\u53D1\u670D\u52A1\u5668\u5931\u8D25",{projectId:e,filePath:t,error:y&&y.message})}else return n(e,"INFO","\u6587\u4EF6\u4FEE\u6539\u4E0D\u9700\u8981\u91CD\u542F\u5F00\u53D1\u670D\u52A1\u5668",{projectId:e,filePath:t}),{success:!0,message:"\u6587\u4EF6\u4E0A\u4F20\u6210\u529F\uFF0C\u65E0\u9700\u91CD\u542F\u5F00\u53D1\u670D\u52A1\u5668",projectId:e,restarted:!1}}catch(O){throw n(e,"ERROR","\u5199\u5165\u6587\u4EF6\u5931\u8D25",{projectId:e,filePath:t,error:O&&O.message,elapsedMs:Date.now()-u}),O}}catch(m){throw m.isOperational?m:new v("\u5907\u4EFD\u9879\u76EE\u5931\u8D25",{projectId:e,filePath:t,originalError:m&&m.message})}}async function $(e,g,s,E){const R=Date.now();if(!e)throw new h("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const u=Number(g);if(!Number.isFinite(u))throw new h("codeVersion\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});const o=Number(s);if(!Number.isFinite(o))throw new h("rollbackTo\u5FC5\u987B\u662F\u6570\u5B57",{field:"rollbackTo"});if(o<0)throw new h("rollbackTo\u4E0D\u80FD\u5C0F\u4E8E0",{field:"rollbackTo"});if(o>=u)throw new h("rollbackTo\u5FC5\u987B\u5C0F\u4E8E\u5F53\u524DcodeVersion",{field:"rollbackTo"});const f=r.join(F.PROJECT_SOURCE_DIR,e);if(!a.existsSync(f))throw n(e,"ERROR","\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e,projectPath:f}),new S("\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e});const t=r.join(F.UPLOAD_PROJECT_DIR,e),w=`${e}-v${o}.zip`,i=r.join(t,w);if(!a.existsSync(i))throw n(e,"ERROR","\u56DE\u6EDA\u7248\u672C\u5907\u4EFD\u6587\u4EF6\u4E0D\u5B58\u5728",{projectId:e,rollbackTo:o,zipPath:i}),new S("\u56DE\u6EDA\u7248\u672C\u5907\u4EFD\u6587\u4EF6\u4E0D\u5B58\u5728",{projectId:e,rollbackTo:o});let l="";try{a.existsSync(t)||a.mkdirSync(t,{recursive:!0});const c=`${e}-v${u}.zip`;return l=r.join(t,c),a.existsSync(l)?n(e,"INFO","\u5F53\u524D\u7248\u672C\u5907\u4EFD\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5907\u4EFD",{projectId:e,zipPath:l}):(await C(e,f,l),n(e,"INFO","\u5F53\u524D\u7248\u672C\u5DF2\u5907\u4EFD",{projectId:e,zipPath:l})),n(e,"DEBUG","\u5F00\u59CB\u4ECE\u5907\u4EFD\u6062\u590D\u9879\u76EE",{projectId:e,rollbackToNum:o,rollbackZipPath:i}),await T(e,f,i),n(e,"INFO","\u9879\u76EE\u56DE\u6EDA\u6210\u529F",{projectId:e,newVersion:u,toVersion:o,rollbackZipPath:i,elapsedMs:Date.now()-R}),{success:!0,message:"\u9879\u76EE\u56DE\u6EDA\u6210\u529F",newVersion:u,rollbackTo:o}}catch(c){if(n(e,"ERROR","\u56DE\u6EDA\u9879\u76EE\u5931\u8D25",{projectId:e,rollbackTo:o,error:c&&c.message,elapsedMs:Date.now()-R}),l&&a.existsSync(l))try{n(e,"INFO","\u56DE\u6EDA\u5931\u8D25\uFF0C\u5C1D\u8BD5\u6062\u590D\u5F53\u524D\u7248\u672C",{projectId:e,backupPath:l}),await T(e,f,l),n(e,"INFO","\u5DF2\u6062\u590D\u5F53\u524D\u7248\u672C",{projectId:e})}catch(m){n(e,"ERROR","\u6062\u590D\u5F53\u524D\u7248\u672C\u5931\u8D25",{projectId:e,error:m&&m.message})}throw c.isOperational?c:new v("\u56DE\u6EDA\u9879\u76EE\u5931\u8D25",{projectId:e,rollbackTo:o,originalError:c&&c.message})}}export{x as specifiedFilesUpdate,U as allFilesUpdate,_ as uploadSingleFile,$ as rollbackVersion};export default{specifiedFilesUpdate:x,allFilesUpdate:U,uploadSingleFile:_,rollbackVersion:$};
4
+ `;return{finalContent:n.join(s),changesCount:f}}function I(e,P){return e===P?{finalContent:e,changesCount:0}:{finalContent:P,changesCount:-1}}async function C(e,P,n,F){const b=Date.now();if(!e)throw new u("Project ID cannot be empty",{field:"projectId"});if(P==null)throw new u("codeVersion cannot be empty",{field:"codeVersion"});const m=Number(P);if(!Number.isFinite(m))throw new u("codeVersion must be a number",{field:"codeVersion"});if(!Array.isArray(n))throw new u("files must be an array",{field:"files"});for(let s=0;s<n.length;s++){const h=n[s];if(!h||typeof h.operation!="string")throw new u(`files[${s}].operation cannot be empty`,{field:`files[${s}].operation`});if(!h.name||typeof h.name!="string")throw new u(`files[${s}].name cannot be empty`,{field:`files[${s}].name`});const t=h.operation.toLowerCase();if(!["create","delete","rename","modify"].includes(t))throw new u(`files[${s}].operation must be one of create, delete, rename or modify`,{field:`files[${s}].operation`});if(t==="rename"&&!h.renameFrom)throw new u(`files[${s}].renameFrom cannot be empty (rename operation requires)`,{field:`files[${s}].renameFrom`});if(t==="modify"&&typeof h.contents!="string")throw new u(`files[${s}].contents must be a string (modify operation requires)`,{field:`files[${s}].contents`})}const o=r.join(d.PROJECT_SOURCE_DIR,e);if(!a.existsSync(o))throw i(e,"ERROR","Project does not exist",{projectId:e,projectPath:o}),new O("Project does not exist",{projectId:e});let f="";try{const s=r.join(d.UPLOAD_PROJECT_DIR,e);a.existsSync(s)||a.mkdirSync(s,{recursive:!0});const h=`${e}-v${m}.zip`;f=r.join(s,h),i(e,"DEBUG","Start backing up project",{projectId:e,backupZipPath:f}),await D(e,o,f),i(e,"INFO","Project backed up successfully",{projectId:e,zipPath:f});try{i(e,"DEBUG","Start processing file operations",{projectId:e,filesCount:n.length});for(const t of n){const l=t.operation.toLowerCase(),w=t.name,c=r.normalize(w).replace(/^[\/\\]+/,""),y=r.join(o,c),g=r.resolve(y),R=r.resolve(o);if(!g.startsWith(R+r.sep)&&g!==R){i(e,"WARN","Unsafe file path, skipping",{filePath:c,resolvedPath:g});continue}switch(l){case"create":{await a.promises.mkdir(r.dirname(y),{recursive:!0});const p=t.contents||"";await a.promises.writeFile(y,p,"utf8"),i(e,"INFO","File created successfully",{filePath:c});break}case"delete":{a.existsSync(y)?(await a.promises.unlink(y),i(e,"INFO","File deleted successfully",{filePath:c})):i(e,"WARN","File to delete does not exist",{filePath:c});break}case"rename":{const p=t.renameFrom;if(!p||typeof p!="string"){i(e,"WARN","Rename operation missing renameFrom",{filePath:c});break}const k=r.normalize(p).replace(/^[\/\\]+/,""),v=r.join(o,k),E=r.resolve(v);if(!E.startsWith(R+r.sep)&&E!==R){i(e,"WARN","Unsafe rename source path, skipping",{renameFrom:k,resolvedPath:E});break}a.existsSync(v)?(await a.promises.mkdir(r.dirname(y),{recursive:!0}),await a.promises.rename(v,y),i(e,"INFO","File renamed successfully",{oldPath:k,newPath:c})):i(e,"WARN","File to rename does not exist",{renameFrom:k});break}case"modify":{if(!a.existsSync(y)){i(e,"WARN","File to modify does not exist",{filePath:c});break}const p=await a.promises.readFile(y,"utf8"),k=typeof t.contents=="string"?t.contents:"",{finalContent:v,changesCount:E}=A(p,k);if(E===0){i(e,"INFO","File content unchanged, skipping write",{filePath:c});break}await a.promises.writeFile(y,v,"utf8"),i(e,"INFO","File modified successfully",{filePath:c,changesCount:E});break}default:{i(e,"WARN","Unsupported operation type",{operation:l,filePath:c});break}}}i(e,"DEBUG","Start cleaning empty directories",{projectId:e});try{await x(o,d.TRAVERSE_EXCLUDE_DIRS||[])}catch(t){i(e,"WARN","Failed to clean empty directories",{projectId:e,error:t&&t.message})}return i(e,"INFO","Specified files updated successfully",{projectId:e,filesCount:n.length,elapsedMs:Date.now()-b}),{success:!0,message:"Specified files updated successfully",projectId:e,filesCount:n.length}}catch(t){throw i(e,"ERROR","Failed to process file operations",{projectId:e,error:t&&t.message,elapsedMs:Date.now()-b}),t}}catch(s){throw s.isOperational?s:new S("Failed to backup project",{projectId:e,originalError:s&&s.message})}}async function T(e,P,n,F){const b=Date.now();if(!e)throw new u("Project ID cannot be empty",{field:"projectId"});const m=Number(P);if(!Number.isFinite(m))throw new u("codeVersion must be a number",{field:"codeVersion"});if(!Array.isArray(n))throw new u("files must be an array",{field:"files"});const o=r.join(d.PROJECT_SOURCE_DIR,e);if(!a.existsSync(o))throw i(e,"ERROR","Project does not exist",{projectId:e,projectPath:o}),new O("Project does not exist",{projectId:e});let f="";try{const s=r.join(d.UPLOAD_PROJECT_DIR,e);a.existsSync(s)||a.mkdirSync(s,{recursive:!0});const h=`${e}-v${m}.zip`;f=r.join(s,h),i(e,"DEBUG","Start backing up project",{projectId:e,backupZipPath:f}),await D(e,o,f);try{i(e,"DEBUG","Start writing files",{projectId:e,filesCount:n.length});for(const t of n){if(!t||typeof t.name!="string")continue;const l=r.join(o,t.name);if(t.renameFrom&&typeof t.renameFrom=="string"){const p=r.join(o,t.renameFrom);if(a.existsSync(p)){await a.promises.mkdir(r.dirname(l),{recursive:!0}),await a.promises.rename(p,l),i(e,"INFO","File renamed successfully",{projectId:e,oldPath:t.renameFrom,newPath:t.name});continue}}const w=t.binary===!0,c=t.binary===!1,y=!!t.sizeExceeded,g=typeof t.contents=="string"&&t.contents.length>0;if(w){if(a.existsSync(l)){i(e,"INFO","Binary file already exists, skipping write",{filePath:t.name});continue}if(g)try{await a.promises.mkdir(r.dirname(l),{recursive:!0});const p=Buffer.from(t.contents,"base64");await a.promises.writeFile(l,p),i(e,"INFO","Binary file written successfully",{filePath:t.name})}catch(p){i(e,"ERROR","Failed to write binary file",{filePath:t.name,error:p&&p.message})}else i(e,"WARN","Binary file does not exist and has no content, skipping",{filePath:t.name});continue}c&&(!y||y&&g)&&(await a.promises.mkdir(r.dirname(l),{recursive:!0}),await a.promises.writeFile(l,t.contents||"","utf8"))}}catch(t){throw i(e,"ERROR","Failed to write files",{projectId:e,error:t&&t.message,elapsedMs:Date.now()-b}),t}try{i(e,"DEBUG","Start cleaning missing files and empty directories",{projectId:e});const t=new Set(n.filter(l=>l&&typeof l.name=="string").map(l=>r.normalize(l.name)));await $(o,t,d.TRAVERSE_EXCLUDE_DIRS||[]),await x(o,d.TRAVERSE_EXCLUDE_DIRS||[])}catch(t){throw i(e,"ERROR","Failed to clean missing files, starting rollback",{projectId:e,error:t&&t.message,elapsedMs:Date.now()-b}),t}return i(e,"INFO","Files submitted successfully",{projectId:e,filesCount:n.length,elapsedMs:Date.now()-b}),{success:!0,message:"Files submitted successfully",projectId:e,restarted:!1}}catch(s){throw s.isOperational?s:new S("Failed to backup old version",{projectId:e,originalError:s&&s.message})}}async function z(e,P,n,F,b){const m=Date.now();if(!e)throw new u("Project ID cannot be empty",{field:"projectId"});const o=Number(P);if(!Number.isFinite(o))throw new u("codeVersion must be a number",{field:"codeVersion"});if(!n)throw new u("File cannot be empty",{field:"file"});if(!F||typeof F!="string")throw new u("File path cannot be empty",{field:"filePath"});const f=r.join(d.PROJECT_SOURCE_DIR,e);if(!a.existsSync(f))throw i(e,"ERROR","Project does not exist",{projectId:e,projectPath:f}),new O("Project does not exist",{projectId:e});const s=r.normalize(F).replace(/^[\/\\]+/,""),h=r.join(f,s),t=r.resolve(h),l=r.resolve(f);if(!t.startsWith(l))throw new u("File path is not safe, cannot exceed project directory",{field:"filePath",providedPath:F,resolvedPath:t});let w="";try{const c=r.join(d.UPLOAD_PROJECT_DIR,e);a.existsSync(c)||a.mkdirSync(c,{recursive:!0});const y=`${e}-v${o}.zip`;w=r.join(c,y),i(e,"DEBUG","Start backing up project",{projectId:e,backupZipPath:w}),await D(e,f,w),i(e,"INFO",`Project backed up: ${w}`,{projectId:e,zipPath:w});try{if(i(e,"DEBUG","Start writing uploaded file",{projectId:e,filePath:s}),await a.promises.mkdir(r.dirname(h),{recursive:!0}),!n.buffer)throw new u("File content format is incorrect, missing buffer",{field:"file"});if(i(e,"INFO","Prepare to write file",{targetPath:h,bufferLength:n.buffer.length,expectedSize:n.size,bufferIsBuffer:Buffer.isBuffer(n.buffer),sizeMatch:n.buffer.length===n.size}),await a.promises.writeFile(h,n.buffer),i(e,"INFO","File uploaded successfully",{projectId:e,filePath:s,targetPath:t,fileSize:n.buffer?n.buffer.length:0,elapsedMs:Date.now()-m}),!1)try{const R=await _(b,e);return i(e,"INFO","Restart development server successfully",{projectId:e,pid:R.pid,port:R.port}),{success:!0,message:"File uploaded and restarted development server successfully",projectId:e,filePath:s,targetPath:t,fileSize:n.buffer?n.buffer.length:0,pid:R.pid,port:R.port,restarted:!0}}catch(R){i(e,"ERROR","Failed to restart development server",{projectId:e,filePath:s,error:R&&R.message})}else return i(e,"INFO","File modification does not require restarting development server",{projectId:e,filePath:s}),{success:!0,message:"File uploaded successfully, no need to restart development server",projectId:e,restarted:!1}}catch(g){throw i(e,"ERROR","Failed to write file",{projectId:e,filePath:s,error:g&&g.message,elapsedMs:Date.now()-m}),g}}catch(c){throw c.isOperational?c:new S("Failed to backup project",{projectId:e,filePath:s,originalError:c&&c.message})}}async function U(e,P,n,F){const b=Date.now();if(!e)throw new u("Project ID cannot be empty",{field:"projectId"});const m=Number(P);if(!Number.isFinite(m))throw new u("codeVersion must be a number",{field:"codeVersion"});const o=Number(n);if(!Number.isFinite(o))throw new u("rollbackTo must be a number",{field:"rollbackTo"});if(o<0)throw new u("rollbackTo cannot be less than 0",{field:"rollbackTo"});if(o>=m)throw new u("rollbackTo must be less than current codeVersion",{field:"rollbackTo"});const f=r.join(d.PROJECT_SOURCE_DIR,e);if(!a.existsSync(f))throw i(e,"ERROR","Project does not exist",{projectId:e,projectPath:f}),new O("Project does not exist",{projectId:e});const s=r.join(d.UPLOAD_PROJECT_DIR,e),h=`${e}-v${o}.zip`,t=r.join(s,h);if(!a.existsSync(t))throw i(e,"ERROR","Rollback version backup file does not exist",{projectId:e,rollbackTo:o,zipPath:t}),new O("Rollback version backup file does not exist",{projectId:e,rollbackTo:o});let l="";try{a.existsSync(s)||a.mkdirSync(s,{recursive:!0});const w=`${e}-v${m}.zip`;return l=r.join(s,w),a.existsSync(l)?i(e,"INFO","Current version backup already exists, skipping backup",{projectId:e,zipPath:l}):(await D(e,f,l),i(e,"INFO","Current version backed up",{projectId:e,zipPath:l})),i(e,"DEBUG","Start restoring project from backup",{projectId:e,rollbackToNum:o,rollbackZipPath:t}),await N(e,f,t),i(e,"INFO","Project rolled back successfully",{projectId:e,newVersion:m,toVersion:o,rollbackZipPath:t,elapsedMs:Date.now()-b}),{success:!0,message:"Project rolled back successfully",newVersion:m,rollbackTo:o}}catch(w){if(i(e,"ERROR","Failed to rollback project",{projectId:e,rollbackTo:o,error:w&&w.message,elapsedMs:Date.now()-b}),l&&a.existsSync(l))try{i(e,"INFO","Failed to rollback, trying to restore current version",{projectId:e,backupPath:l}),await N(e,f,l),i(e,"INFO","Current version restored",{projectId:e})}catch(c){i(e,"ERROR","Failed to restore current version",{projectId:e,error:c&&c.message})}throw w.isOperational?w:new S("Failed to rollback project",{projectId:e,rollbackTo:o,originalError:w&&w.message})}}export{C as specifiedFilesUpdate,T as allFilesUpdate,z as uploadSingleFile,U as rollbackVersion};export default{specifiedFilesUpdate:C,allFilesUpdate:T,uploadSingleFile:z,rollbackVersion:U};
@@ -1 +1 @@
1
- import{log as s}from"../utils/log/logUtils.js";import h from"../appConfig/index.js";import l from"path";import n from"fs";import{extractZip as P}from"../utils/common/zipUtils.js";import"../utils/build/startDevUtils.js";import"../utils/build/restartDevUtils.js";import{stopDevServer as F}from"../utils/build/stopDevUtils.js";import{ValidationError as c,BusinessError as J,SystemError as O,FileError as A,ResourceError as N}from"../utils/error/errorHandler.js";import{sanitizeSensitivePaths as S}from"../utils/common/sensitiveUtils.js";import{removeNodeModules as z}from"../utils/buildDependency/dependencyManager.js";import{backupProjectToZip as M,copyDirectoryFiltered as B}from"../utils/project/backupUtils.js";import{createPnpmNpmrc as _}from"../utils/common/npmrcUtils.js";async function T(e){const r=Date.now();if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const u=h.PROJECT_SOURCE_DIR,i=l.join(u,e);if(n.existsSync(i))throw new J(`\u9879\u76EE\u76EE\u5F55 ${e} \u5DF2\u5B58\u5728`,{projectId:e,projectPath:i});try{n.mkdirSync(i,{recursive:!0}),s(e,"INFO",`\u9879\u76EE\u76EE\u5F55\u521B\u5EFA\u6210\u529F: ${i}`,{projectId:e});const t=h.INIT_PROJECT_DIR,a=l.join(t,`${h.INIT_PROJECT_NAME}.zip`),m=l.join(t,h.INIT_PROJECT_NAME);if(s(e,"DEBUG","\u5F00\u59CB\u68C0\u67E5\u6A21\u677F\u76EE\u5F55",{templateDir:m,templateZipPath:a}),!n.existsSync(m)){if(!n.existsSync(a))throw s(e,"ERROR",`\u521D\u59CB\u5316\u6A21\u677F\u4E0D\u5B58\u5728: ${a}`,{projectId:e,templateZipPath:a}),new N("\u521D\u59CB\u5316\u6A21\u677F\u4E0D\u5B58\u5728",{});if(s(e,"INFO",`\u6A21\u677F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u5F00\u59CB\u89E3\u538B\u6A21\u677F: ${a}`,{projectId:e,templateZipPath:a}),await P(a,m),s(e,"INFO","\u6A21\u677F\u89E3\u538B\u5B8C\u6210",{projectId:e}),!n.existsSync(m))throw new O("\u6A21\u677F\u89E3\u538B\u540E\u76EE\u5F55\u4ECD\u4E0D\u5B58\u5728",{})}s(e,"DEBUG","\u5F00\u59CB\u590D\u5236\u6A21\u677F\u5185\u5BB9\u5230\u9879\u76EE\u76EE\u5F55",{templateDir:m,projectPath:i});const R=await n.promises.readdir(m,{withFileTypes:!0});for(const w of R){const o=l.join(m,w.name),f=l.join(i,w.name);w.isDirectory()?(await n.promises.mkdir(f,{recursive:!0}),await B(o,f)):w.isFile()&&(await n.promises.mkdir(l.dirname(f),{recursive:!0}),await n.promises.copyFile(o,f))}return s(e,"DEBUG","\u5F00\u59CB\u521B\u5EFA .npmrc \u914D\u7F6E\u6587\u4EF6",{projectPath:i}),await _(i,e),s(e,"INFO",`\u9879\u76EE ${e} \u521D\u59CB\u5316\u6210\u529F`,{projectId:e,elapsedMs:Date.now()-r}),{success:!0,message:`\u9879\u76EE ${e} \u521B\u5EFA\u6210\u529F`,projectPath:i}}catch(t){throw s(e,"ERROR",`\u9879\u76EE ${e} \u521D\u59CB\u5316\u5931\u8D25: ${t.message}`,{projectId:e,elapsedMs:Date.now()-r}),new O(`\u9879\u76EE ${e} \u521D\u59CB\u5316\u5931\u8D25: ${t.message}`,{projectId:e,projectPath:i,originalError:t.message})}}async function G(e){const r=await n.promises.readdir(e,{withFileTypes:!0}),u=h.TOP_LEVEL_NOISE_PATTERNS,i=r.filter(t=>{const a=t.name;return a.startsWith(".")?!1:!u.some(m=>m.endsWith("*")?a.startsWith(m.slice(0,-1)):a===m)});if(i.length===1&&i[0].isDirectory()){const t=l.join(e,i[0].name),a=l.join(e,"..",`temp_${Date.now()}`);await n.promises.rename(t,a);const m=await n.promises.readdir(a);for(const R of m){const w=l.join(a,R),o=l.join(e,R);await n.promises.rename(w,o)}await n.promises.rmdir(a)}}async function $(e){if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const r=l.join(h.PROJECT_SOURCE_DIR,e);if(n.existsSync(r))try{s(e,"INFO",`\u5F00\u59CB\u6E05\u7406\u9879\u76EE\u76EE\u5F55: ${r}`,{projectId:e}),await n.promises.rm(r,{recursive:!0,force:!0}),s(e,"INFO",`\u9879\u76EE\u76EE\u5F55\u6E05\u7406\u5B8C\u6210: ${r}`,{projectId:e})}catch(u){throw s(e,"ERROR",`\u6E05\u7406\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${u.message}`,{projectId:e,projectPath:r,originalError:u.message}),new O(`\u6E05\u7406\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${u.message}`,{projectId:e,projectPath:r,originalError:u.message})}else s(e,"INFO",`\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u65E0\u9700\u6E05\u7406: ${r}`,{projectId:e})}function L(e){if(!n.existsSync(e))return!0;try{return n.readdirSync(e).filter(i=>!i.startsWith(".")&&i!=="node_modules").length===0}catch(r){const u=l.basename(e);return s(u,"ERROR",`\u68C0\u67E5\u76EE\u5F55\u662F\u5426\u4E3A\u7A7A\u5931\u8D25: ${r.message}`,{dirPath:e}),!0}}async function v(e,r,u,i,t,a){const m=Date.now(),R=h.PROJECT_SOURCE_DIR,w=l.join(R,e);try{if(L(w))s(e,"INFO","\u9879\u76EE\u76EE\u5F55\u4E3A\u7A7A\uFF0C\u76F4\u63A5\u90E8\u7F72\u65B0\u9879\u76EE",{projectId:e});else{s(e,"INFO","\u9879\u76EE\u76EE\u5F55\u975E\u7A7A\uFF0C\u5F00\u59CB\u5907\u4EFD\u5F53\u524D\u7248\u672C",{projectId:e});const f=parseInt(i)-1,y=l.join(h.UPLOAD_PROJECT_DIR,e),E=l.join(y,`${e}-v${f}.zip`);if(n.existsSync(E))s(e,"INFO",`\u5907\u4EFD\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5907\u4EFD: ${E}`,{projectId:e});else try{await g(e,f),s(e,"INFO",`\u5F53\u524D\u7248\u672C\u5DF2\u5907\u4EFD: ${E}`,{projectId:e})}catch(D){throw s(e,"ERROR",`\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5931\u8D25: ${D.message}`,{projectId:e}),new O(`\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5931\u8D25: ${D.message}`,{projectId:e,originalError:D.message})}if(t&&!isNaN(Number(t))){const D=Number(t);s(e,"INFO",`\u6B63\u5728\u505C\u6B62\u65E7\u7248\u672Cdev\u670D\u52A1\u5668\uFF0CPID: ${D}`,{projectId:e});try{await F(u,e,D,{strict:!0}),s(e,"INFO","\u65E7\u7248\u672Cdev\u670D\u52A1\u5668\u5DF2\u505C\u6B62",{projectId:e})}catch(k){s(e,"WARN",`\u505C\u6B62\u65E7\u7248\u672Cdev\u670D\u52A1\u5668\u5931\u8D25: ${k.message}`,{projectId:e,pid:D})}}n.existsSync(w)&&(s(e,"INFO",`\u6B63\u5728\u6E05\u7A7A\u9879\u76EE\u76EE\u5F55: ${w}`,{projectId:e}),await n.promises.rm(w,{recursive:!0,force:!0}))}return n.mkdirSync(w,{recursive:!0}),s(e,"INFO",`\u9879\u76EE\u76EE\u5F55\u521B\u5EFA\u6210\u529F: ${w}`,{projectId:e}),s(e,"DEBUG","\u5F00\u59CB\u89E3\u538B\u538B\u7F29\u5305",{projectId:e,zipFilePath:r}),await P(r,w),s(e,"DEBUG","\u538B\u7F29\u5305\u89E3\u538B\u5B8C\u6210",{projectId:e}),s(e,"DEBUG","\u68C0\u67E5\u5E76\u5904\u7406\u9876\u5C42\u6587\u4EF6\u5939",{projectId:e}),await G(w),s(e,"DEBUG","\u68C0\u67E5\u5E76\u5220\u9664 node_modules \u6587\u4EF6\u5939",{projectId:e}),await z(w),s(e,"DEBUG","\u5F00\u59CB\u521B\u5EFA .npmrc \u914D\u7F6E\u6587\u4EF6",{projectId:e}),await _(w,e),s(e,"INFO",`\u9879\u76EE ${e} \u4E0A\u4F20\u6210\u529F`,{projectId:e,codeVersion:i,elapsedMs:Date.now()-m}),{success:!0,message:`\u9879\u76EE ${e} \u4E0A\u4F20\u6210\u529F`,projectId:e,codeVersion:i}}catch(o){s(e,"ERROR",`\u4E0A\u4F20\u9879\u76EE\u5931\u8D25: ${o.message}`,{projectId:e,elapsedMs:Date.now()-m});try{await $(e),s(e,"INFO","\u4E0A\u4F20\u5931\u8D25\uFF0C\u9879\u76EE\u76EE\u5F55\u5DF2\u6E05\u7406",{projectId:e})}catch(f){s(e,"ERROR",`\u6E05\u7406\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${f.message}`,{projectId:e,originalError:f.message})}throw o.isOperational?o:new O(`\u4E0A\u4F20\u9879\u76EE\u5931\u8D25: ${o.message}`,{projectId:e,projectPath:w,zipFilePath:r,originalError:o.message})}}async function g(e,r){if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(r==null)throw new c("codeVersion\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});const u=Number(r);if(!Number.isFinite(u))throw new c("codeVersion\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});const i=l.join(h.PROJECT_SOURCE_DIR,e);if(!n.existsSync(i))throw new N("\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e});const t=l.join(h.UPLOAD_PROJECT_DIR,e);n.existsSync(t)||n.mkdirSync(t,{recursive:!0});const a=`${e}-v${u}.zip`,m=l.join(t,a);return s(e,"DEBUG","\u5F00\u59CB\u5907\u4EFD\u9879\u76EE\u4E3Azip",{projectId:e,versionNum:u,outZipPath:m}),await M(e,i,m)}async function C(e,r,u){if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(!r)throw new c("\u4EE3\u7801\u7248\u672C\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});if(!u)throw new c("\u8BF7\u4E0A\u4F20\u538B\u7F29\u5305\u6587\u4EF6",{field:"zipFile"});const i=l.join(h.UPLOAD_PROJECT_DIR,e);n.existsSync(i)||n.mkdirSync(i,{recursive:!0});const t=u.path,a=l.join(i,`${e}-v${r}.zip`);try{return n.renameSync(t,a),s(e,"INFO","\u6587\u4EF6\u4FDD\u5B58\u6210\u529F",{projectId:e,codeVersion:r,filePath:a}),{success:!0,filePath:a}}catch(m){if(s(e,"ERROR","\u79FB\u52A8\u6587\u4EF6\u5931\u8D25",{projectId:e,codeVersion:r,error:m.message}),n.existsSync(t))try{n.unlinkSync(t)}catch(R){s(e,"ERROR","\u6E05\u7406\u4E34\u65F6\u6587\u4EF6\u5931\u8D25",{projectId:e,error:R.message})}throw new O("\u6587\u4EF6\u4FDD\u5B58\u5931\u8D25",{projectId:e,codeVersion:r,originalError:m.message})}}async function U(e,r,u){const i=Date.now();if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});const t=null;try{if(r&&!isNaN(Number(r))){const o=Number(r);s(t,"INFO",`[delete-project] \u6B63\u5728\u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668\uFF0CPID: ${o}`,{projectId:e,pid:o});try{await F(u,e,o,{strict:!0}),s(t,"INFO","[delete-project] \u5F00\u53D1\u670D\u52A1\u5668\u5DF2\u505C\u6B62",{projectId:e})}catch(f){s(t,"WARN",`[delete-project] \u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668\u5931\u8D25: ${f.message}`,{projectId:e,pid:o})}}const a=[l.join(h.UPLOAD_PROJECT_DIR,e),l.join(h.PROJECT_SOURCE_DIR,e),l.join(h.DIST_TARGET_DIR,e),l.join(h.LOG_BASE_DIR,e)],m=[],R=[];for(const o of a)if(n.existsSync(o))try{await n.promises.rm(o,{recursive:!0,force:!0}),m.push(o),s(t,"INFO",`[delete-project] \u76EE\u5F55\u5220\u9664\u6210\u529F: ${o}`,{projectId:e})}catch(f){R.push({path:o,error:f.message}),s(t,"ERROR",`[delete-project] \u76EE\u5F55\u5220\u9664\u5931\u8D25: ${o}`,{projectId:e,error:f.message})}else s(t,"INFO",`[delete-project] \u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664: ${o}`,{projectId:e});const w={success:!0,message:`\u9879\u76EE ${e} \u5220\u9664\u5B8C\u6210`,projectId:e,deletedDirectories:m,failedDirectories:R};return R.length>0&&(w.message+=`\uFF0C\u4F46\u6709 ${R.length} \u4E2A\u76EE\u5F55\u5220\u9664\u5931\u8D25`,s(t,"WARN","[delete-project] \u90E8\u5206\u76EE\u5F55\u5220\u9664\u5931\u8D25",{projectId:e,failedDirs:R})),s(t,"INFO",`[delete-project] \u9879\u76EE\u5220\u9664\u5B8C\u6210: ${e}`,{projectId:e,elapsedMs:Date.now()-i}),w}catch(a){throw s(t,"ERROR",`[delete-project] \u5220\u9664\u9879\u76EE\u5931\u8D25: ${a.message}`,{projectId:e,originalError:a.message,elapsedMs:Date.now()-i}),a.isOperational?a:new O(`\u5220\u9664\u9879\u76EE\u5931\u8D25: ${a.message}`,{projectId:e,originalError:a.message})}}async function x(e,r,u,i){const t=Date.now();if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(r==null)throw new c("codeVersion\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});const a=Number(r);if(!Number.isFinite(a))throw new c("codeVersion\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});const m=l.join(h.PROJECT_SOURCE_DIR,e);if(!n.existsSync(m))throw new N("\u9879\u76EE\u4E0D\u5B58\u5728",{projectId:e});const R=l.join(h.UPLOAD_PROJECT_DIR,e),w=`${e}-v${a}.zip`,o=l.join(R,w);if(u!=="LATEST"){if(n.existsSync(o))return s(e,"INFO",`\u4F7F\u7528\u5DF2\u5B58\u5728\u7684\u5BFC\u51FA\u6587\u4EF6: ${o}`,{projectId:e,zipPath:o}),{success:!0,projectId:e,zipPath:o};throw new N(`\u6307\u5B9A\u7248\u672C\u7684zip\u5305\u4E0D\u5B58\u5728: ${o}`,{projectId:e,zipPath:o})}const f=l.join(m,"cpage_config.json");let y=!1;try{if(i)try{const D=JSON.stringify(i,null,2);await n.promises.writeFile(f,D,"utf8"),y=!0,s(e,"INFO",`\u5DF2\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6: ${f}`,{projectId:e,configFilePath:f})}catch(D){throw s(e,"ERROR",`\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${D.message}`,{projectId:e,error:D.message}),new A("\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6\u5931\u8D25",{projectId:e,configFilePath:f,originalError:D.message})}s(e,"DEBUG","\u5F00\u59CB\u6267\u884C\u5BFC\u51FA\u6253\u5305",{projectId:e,codeVersion:r});const E=await g(e,r);return s(e,"INFO",`\u9879\u76EE\u5DF2\u5BFC\u51FA: ${E}`,{projectId:e,zipPath:E,elapsedMs:Date.now()-t}),{success:!0,projectId:e,zipPath:E}}catch(E){throw s(e,"ERROR",`\u5BFC\u51FA\u9879\u76EE\u5931\u8D25: ${E?.message}`,{projectId:e,elapsedMs:Date.now()-t}),E.isOperational?E:new O("\u5BFC\u51FA\u9879\u76EE\u5931\u8D25",{projectId:e,originalError:E&&E.message?S(E.message):E&&E.message})}finally{if(y&&n.existsSync(f))try{await n.promises.unlink(f),s(e,"INFO",`\u5DF2\u5220\u9664\u4E34\u65F6\u914D\u7F6E\u6587\u4EF6: ${f}`,{projectId:e,configFilePath:f})}catch(E){s(e,"WARN",`\u5220\u9664\u4E34\u65F6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${E.message}`,{projectId:e,error:E.message})}}}async function b(e,r){const u=Date.now();if(!e)throw new c("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(r==null)throw new c("codeVersion\u4E0D\u80FD\u4E3A\u7A7A",{field:"codeVersion"});try{const i=await g(e,r);return s(e,"INFO",`\u5F53\u524D\u7248\u672C\u5DF2\u5907\u4EFD: ${i}`,{projectId:e,zipPath:i,elapsedMs:Date.now()-u}),{success:!0,projectId:e,zipPath:i}}catch(i){throw s(e,"ERROR",`\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5931\u8D25: ${i?.message}`,{projectId:e,elapsedMs:Date.now()-u}),i.isOperational?i:new O("\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5931\u8D25",{projectId:e,originalError:i&&i.message?S(i.message):i&&i.message})}}export{T as createProject,v as uploadProject,b as backupCurrentVersion,x as exportProject,g as backupProjectOfVersion,$ as cleanupProjectDirectory,C as handleFileUpload,U as deleteProject};export default{createProject:T,uploadProject:v,backupCurrentVersion:b,exportProject:x,backupProjectOfVersion:g,cleanupProjectDirectory:$,handleFileUpload:C,deleteProject:U};
1
+ import{log as t}from"../utils/log/logUtils.js";import w from"../appConfig/index.js";import c from"path";import s from"fs";import{extractZip as F}from"../utils/common/zipUtils.js";import"../utils/build/startDevUtils.js";import"../utils/build/restartDevUtils.js";import{stopDevServer as d}from"../utils/build/stopDevUtils.js";import{ValidationError as h,BusinessError as C,SystemError as R,FileError as z,ResourceError as P}from"../utils/error/errorHandler.js";import{sanitizeSensitivePaths as N}from"../utils/common/sensitiveUtils.js";import{removeNodeModules as U}from"../utils/buildDependency/dependencyManager.js";import{backupProjectToZip as J,copyDirectoryFiltered as A}from"../utils/project/backupUtils.js";import{createPnpmNpmrc as $}from"../utils/common/npmrcUtils.js";async function v(e){const r=Date.now();if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});const u=w.PROJECT_SOURCE_DIR,i=c.join(u,e);if(s.existsSync(i))throw new C(`Project directory ${e} already exists`,{projectId:e,projectPath:i});try{s.mkdirSync(i,{recursive:!0}),t(e,"INFO",`Project directory created successfully: ${i}`,{projectId:e});const n=w.INIT_PROJECT_DIR,a=c.join(n,`${w.INIT_PROJECT_NAME}.zip`),l=c.join(n,w.INIT_PROJECT_NAME);if(t(e,"DEBUG","Start checking template directory",{templateDir:l,templateZipPath:a}),!s.existsSync(l)){if(!s.existsSync(a))throw t(e,"ERROR",`Initialization template does not exist: ${a}`,{projectId:e,templateZipPath:a}),new P("Initialization template does not exist",{});if(t(e,"INFO",`Template directory does not exist, starting to unzip template: ${a}`,{projectId:e,templateZipPath:a}),await F(a,l),t(e,"INFO","Template unzip completed",{projectId:e}),!s.existsSync(l))throw new R("Template unzip directory still does not exist",{})}t(e,"DEBUG","Start copying template content to project directory",{templateDir:l,projectPath:i});const g=await s.promises.readdir(l,{withFileTypes:!0});for(const f of g){const o=c.join(l,f.name),m=c.join(i,f.name);f.isDirectory()?(await s.promises.mkdir(m,{recursive:!0}),await A(o,m)):f.isFile()&&(await s.promises.mkdir(c.dirname(m),{recursive:!0}),await s.promises.copyFile(o,m))}return t(e,"DEBUG","Start creating .npmrc configuration file",{projectPath:i}),await $(i,e),t(e,"INFO",`Project ${e} initialized successfully`,{projectId:e,elapsedMs:Date.now()-r}),{success:!0,message:`Project ${e} created successfully`,projectPath:i}}catch(n){throw t(e,"ERROR",`Project ${e} initialization failed: ${n.message}`,{projectId:e,elapsedMs:Date.now()-r}),new R(`Project ${e} initialization failed: ${n.message}`,{projectId:e,projectPath:i,originalError:n.message})}}async function B(e){const r=await s.promises.readdir(e,{withFileTypes:!0}),u=w.TOP_LEVEL_NOISE_PATTERNS,i=r.filter(n=>{const a=n.name;return a.startsWith(".")?!1:!u.some(l=>l.endsWith("*")?a.startsWith(l.slice(0,-1)):a===l)});if(i.length===1&&i[0].isDirectory()){const n=c.join(e,i[0].name),a=c.join(e,"..",`temp_${Date.now()}`);await s.promises.rename(n,a);const l=await s.promises.readdir(a);for(const g of l){const f=c.join(a,g),o=c.join(e,g);await s.promises.rename(f,o)}await s.promises.rmdir(a)}}async function p(e){if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});const r=c.join(w.PROJECT_SOURCE_DIR,e);if(s.existsSync(r))try{t(e,"INFO",`Start cleaning project directory: ${r}`,{projectId:e}),await s.promises.rm(r,{recursive:!0,force:!0}),t(e,"INFO",`Project directory cleaned up: ${r}`,{projectId:e})}catch(u){throw t(e,"ERROR",`Failed to clean project directory: ${u.message}`,{projectId:e,projectPath:r,originalError:u.message}),new R(`Failed to clean project directory: ${u.message}`,{projectId:e,projectPath:r,originalError:u.message})}else t(e,"INFO",`Project directory does not exist, no need to clean: ${r}`,{projectId:e})}function M(e){if(!s.existsSync(e))return!0;try{return s.readdirSync(e).filter(i=>!i.startsWith(".")&&i!=="node_modules").length===0}catch(r){const u=c.basename(e);return t(u,"ERROR",`Failed to check if directory is empty: ${r.message}`,{dirPath:e}),!0}}async function S(e,r,u,i,n,a){const l=Date.now(),g=w.PROJECT_SOURCE_DIR,f=c.join(g,e);try{if(M(f))t(e,"INFO","Project directory is empty, directly deploying new project",{projectId:e});else{t(e,"INFO","Project directory is not empty, starting to backup current version",{projectId:e});const m=parseInt(i)-1,O=c.join(w.UPLOAD_PROJECT_DIR,e),y=c.join(O,`${e}-v${m}.zip`);if(s.existsSync(y))t(e,"INFO",`Backup file already exists, skipping backup: ${y}`,{projectId:e});else try{await D(e,m),t(e,"INFO",`Current version backed up: ${y}`,{projectId:e})}catch(E){throw t(e,"ERROR",`Failed to backup current version: ${E.message}`,{projectId:e}),new R(`Failed to backup current version: ${E.message}`,{projectId:e,originalError:E.message})}if(n&&!isNaN(Number(n))){const E=Number(n);t(e,"INFO",`Stopping old version dev server, PID: ${E}`,{projectId:e});try{await d(u,e,E,{strict:!0}),t(e,"INFO","Old version dev server stopped",{projectId:e})}catch(k){t(e,"WARN",`Failed to stop old version dev server: ${k.message}`,{projectId:e,pid:E})}}s.existsSync(f)&&(t(e,"INFO",`Cleaning project directory: ${f}`,{projectId:e}),await s.promises.rm(f,{recursive:!0,force:!0}))}return s.mkdirSync(f,{recursive:!0}),t(e,"INFO",`Project directory created successfully: ${f}`,{projectId:e}),t(e,"DEBUG","Start extracting zip file to project directory",{projectId:e,zipFilePath:r}),await F(r,f),t(e,"DEBUG","Zip file extracted successfully",{projectId:e}),t(e,"DEBUG","Check and remove top level folder",{projectId:e}),await B(f),t(e,"DEBUG","Check and remove node_modules folder",{projectId:e}),await U(f),t(e,"DEBUG","Start creating .npmrc configuration file",{projectId:e}),await $(f,e),t(e,"INFO",`Project ${e} uploaded successfully`,{projectId:e,codeVersion:i,elapsedMs:Date.now()-l}),{success:!0,message:`Project ${e} uploaded successfully`,projectId:e,codeVersion:i}}catch(o){t(e,"ERROR",`Failed to upload project: ${o.message}`,{projectId:e,elapsedMs:Date.now()-l});try{await p(e),t(e,"INFO","Failed to upload project, project directory cleaned up",{projectId:e})}catch(m){t(e,"ERROR",`Failed to clean project directory: ${m.message}`,{projectId:e,originalError:m.message})}throw o.isOperational?o:new R(`Failed to upload project: ${o.message}`,{projectId:e,projectPath:f,zipFilePath:r,originalError:o.message})}}async function D(e,r){if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});if(r==null)throw new h("codeVersion cannot be empty",{field:"codeVersion"});const u=Number(r);if(!Number.isFinite(u))throw new h("codeVersion must be a number",{field:"codeVersion"});const i=c.join(w.PROJECT_SOURCE_DIR,e);if(!s.existsSync(i))throw new P("Project does not exist",{projectId:e});const n=c.join(w.UPLOAD_PROJECT_DIR,e);s.existsSync(n)||s.mkdirSync(n,{recursive:!0});const a=`${e}-v${u}.zip`,l=c.join(n,a);return t(e,"DEBUG","Start backing up project to zip",{projectId:e,versionNum:u,outZipPath:l}),await J(e,i,l)}async function b(e,r,u){if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});if(!r)throw new h("codeVersion cannot be empty",{field:"codeVersion"});if(!u)throw new h("Please upload a zip file",{field:"zipFile"});const i=c.join(w.UPLOAD_PROJECT_DIR,e);s.existsSync(i)||s.mkdirSync(i,{recursive:!0});const n=u.path,a=c.join(i,`${e}-v${r}.zip`);try{return s.renameSync(n,a),t(e,"INFO","File saved successfully",{projectId:e,codeVersion:r,filePath:a}),{success:!0,filePath:a}}catch(l){if(t(e,"ERROR","Failed to move file",{projectId:e,codeVersion:r,error:l.message}),s.existsSync(n))try{s.unlinkSync(n)}catch(g){t(e,"ERROR","Failed to clean temporary file",{projectId:e,error:g.message})}throw new R("Failed to save file",{projectId:e,codeVersion:r,originalError:l.message})}}async function x(e,r,u){const i=Date.now();if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});const n=null;try{if(r&&!isNaN(Number(r))){const o=Number(r);t(n,"INFO",`[delete-project] Stopping development server, PID: ${o}`,{projectId:e,pid:o});try{await d(u,e,o,{strict:!0}),t(n,"INFO","[delete-project] Development server stopped",{projectId:e})}catch(m){t(n,"WARN",`[delete-project] Failed to stop development server: ${m.message}`,{projectId:e,pid:o})}}const a=[c.join(w.UPLOAD_PROJECT_DIR,e),c.join(w.PROJECT_SOURCE_DIR,e),c.join(w.DIST_TARGET_DIR,e),c.join(w.LOG_BASE_DIR,e)],l=[],g=[];for(const o of a)if(s.existsSync(o))try{await s.promises.rm(o,{recursive:!0,force:!0}),l.push(o),t(n,"INFO",`[delete-project] Directory deleted successfully: ${o}`,{projectId:e})}catch(m){g.push({path:o,error:m.message}),t(n,"ERROR",`[delete-project] Directory deleted failed: ${o}`,{projectId:e,error:m.message})}else t(n,"INFO",`[delete-project] Directory does not exist, skipping deletion: ${o}`,{projectId:e});const f={success:!0,message:`Project ${e} deleted successfully`,projectId:e,deletedDirectories:l,failedDirectories:g};return g.length>0&&(f.message+=`, but ${g.length} directories deleted failed`,t(n,"WARN","[delete-project] Some directories deleted failed",{projectId:e,failedDirs:g})),t(n,"INFO",`[delete-project] Project deleted successfully: ${e}`,{projectId:e,elapsedMs:Date.now()-i}),f}catch(a){throw t(n,"ERROR",`[delete-project] Failed to delete project: ${a.message}`,{projectId:e,originalError:a.message,elapsedMs:Date.now()-i}),a.isOperational?a:new R(`Failed to delete project: ${a.message}`,{projectId:e,originalError:a.message})}}async function T(e,r,u,i){const n=Date.now();if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});if(r==null)throw new h("codeVersion cannot be empty",{field:"codeVersion"});const a=Number(r);if(!Number.isFinite(a))throw new h("codeVersion must be a number",{field:"codeVersion"});const l=c.join(w.PROJECT_SOURCE_DIR,e);if(!s.existsSync(l))throw new P("Project does not exist",{projectId:e});const g=c.join(w.UPLOAD_PROJECT_DIR,e),f=`${e}-v${a}.zip`,o=c.join(g,f);if(u!=="LATEST"){if(s.existsSync(o))return t(e,"INFO",`Using existing export file: ${o}`,{projectId:e,zipPath:o}),{success:!0,projectId:e,zipPath:o};throw new P(`Specified version zip file does not exist: ${o}`,{projectId:e,zipPath:o})}const m=c.join(l,"cpage_config.json");let O=!1;try{if(i)try{const E=JSON.stringify(i,null,2);await s.promises.writeFile(m,E,"utf8"),O=!0,t(e,"INFO",`Configuration file created successfully: ${m}`,{projectId:e,configFilePath:m})}catch(E){throw t(e,"ERROR",`Failed to create configuration file: ${E.message}`,{projectId:e,error:E.message}),new z("Failed to create configuration file",{projectId:e,configFilePath:m,originalError:E.message})}t(e,"DEBUG","Start executing export and packaging",{projectId:e,codeVersion:r});const y=await D(e,r);return t(e,"INFO",`Project exported successfully: ${y}`,{projectId:e,zipPath:y,elapsedMs:Date.now()-n}),{success:!0,projectId:e,zipPath:y}}catch(y){throw t(e,"ERROR",`Failed to export project: ${y?.message}`,{projectId:e,elapsedMs:Date.now()-n}),y.isOperational?y:new R("Failed to export project",{projectId:e,originalError:y&&y.message?N(y.message):y&&y.message})}finally{if(O&&s.existsSync(m))try{await s.promises.unlink(m),t(e,"INFO",`Temporary configuration file deleted successfully: ${m}`,{projectId:e,configFilePath:m})}catch(y){t(e,"WARN",`Failed to delete temporary configuration file: ${y.message}`,{projectId:e,error:y.message})}}}async function _(e,r){const u=Date.now();if(!e)throw new h("Project ID cannot be empty",{field:"projectId"});if(r==null)throw new h("codeVersion cannot be empty",{field:"codeVersion"});try{const i=await D(e,r);return t(e,"INFO",`Current version backed up successfully: ${i}`,{projectId:e,zipPath:i,elapsedMs:Date.now()-u}),{success:!0,projectId:e,zipPath:i}}catch(i){throw t(e,"ERROR",`Failed to backup current version: ${i?.message}`,{projectId:e,elapsedMs:Date.now()-u}),i.isOperational?i:new R("Failed to backup current version",{projectId:e,originalError:i&&i.message?N(i.message):i&&i.message})}}export{v as createProject,S as uploadProject,_ as backupCurrentVersion,T as exportProject,D as backupProjectOfVersion,p as cleanupProjectDirectory,b as handleFileUpload,x as deleteProject};export default{createProject:v,uploadProject:S,backupCurrentVersion:_,exportProject:T,backupProjectOfVersion:D,cleanupProjectDirectory:p,handleFileUpload:b,deleteProject:x};
@@ -1,4 +1,4 @@
1
- import{exec as d}from"child_process";import y from"path";import a from"fs";import{log as g,logBuild as w}from"../log/logUtils.js";import p from"../error/buildErrorParser.js";import b from"../../appConfig/index.js";import{BusinessError as N,SystemError as x,FileError as A,ResourceError as T}from"../error/errorHandler.js";import{installDependencies as k}from"../buildDependency/dependencyManager.js";const U=b.PROJECT_SOURCE_DIR,W=b.DIST_TARGET_DIR,F=new Set;let O=0;async function B({req:t,projectPath:s,projectId:r,outStream:o}){try{const l=y.join(s,"dist"),u=W,m=y.join(u,r,"dist");if(!a.existsSync(l)){const e=`\u672A\u627E\u5230dist\u76EE\u5F55: ${l}`;g(r,"WARN",e,{projectId:r}),o&&o.write(`${e}
2
- `);return}if(a.existsSync(u)||a.mkdirSync(u,{recursive:!0}),a.existsSync(m)&&await a.promises.rm(m,{recursive:!0,force:!0}),a.promises.cp)await a.promises.cp(l,m,{recursive:!0});else{const e=(i,c)=>{if(a.statSync(i).isDirectory()){a.existsSync(c)||a.mkdirSync(c,{recursive:!0});for(const f of a.readdirSync(i))e(y.join(i,f),y.join(c,f))}else a.copyFileSync(i,c)};e(l,m)}const n=`dist\u76EE\u5F55\u5DF2\u62F7\u8D1D\u5230: ${m}`;g(r,"INFO",n,{projectId:r}),o&&o.write(`${n}
3
- `)}catch(l){const u=`\u62F7\u8D1Ddist\u76EE\u5F55\u5931\u8D25: ${l.message}`;throw g(r,"ERROR",u,{projectId:r}),o&&o.write(`${u}
4
- `),l}}function D(t,s,r,o=[]){return new Promise((l,u)=>{const m=Array.isArray(o)&&o.length>0?" -- "+o.map(e=>String(e)).join(" "):"",n=`cd ${s} && pnpm run ${r}${m}`;w(t,"INFO","\u6267\u884C\u547D\u4EE4",{command:n});try{g(t,"INFO","\u6267\u884C\u6784\u5EFA\u811A\u672C",{command:n,cwd:s})}catch{}d(n,{env:process.env,maxBuffer:10*1024*1024},(e,i,c)=>{if(e){w(t,"ERROR","\u6267\u884C\u9519\u8BEF",{error:e.message,stderr:c});const R=new p,f=c||e.message,h=R.parseBuildError(f,t),S=new x(h,{originalError:e.message,command:n});return u(S)}w(t,"INFO","\u811A\u672C\u6267\u884C\u5B8C\u6210",{stdout:i}),l(i)})})}async function J(t,s){const r=y.join(U,s),o=y.join(r,"package.json");if(!a.existsSync(o))throw new T("\u9879\u76EE\u7F3A\u5C11package.json\u6587\u4EF6",{projectId:s,projectPath:r});let u;try{u=JSON.parse(a.readFileSync(o,"utf8"))}catch(i){throw new A("package.json\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF",{projectId:s,jsonFilePath:o,originalError:i.message})}const n=u.scripts.build;if(!n)throw g(s,"WARN","\u9879\u76EE\u7F3A\u5C11build\u811A\u672C",{projectId:s,requestId:t.requestId}),new N("\u9879\u76EE\u7F3A\u5C11build\u811A\u672C",{projectId:s});if(F.has(s))throw new N("\u8BE5\u9879\u76EE\u6B63\u5728\u6784\u5EFA\u4E2D",{projectId:s});const e=Number.isFinite(b.MAX_BUILD_CONCURRENCY)?b.MAX_BUILD_CONCURRENCY:20;if(O>=e)throw new N("\u5E76\u53D1\u5DF2\u6EE1\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",{currentBuilds:O,maxConcurrency:e});F.add(s),O+=1;try{let i="";t&&t.query&&typeof t.query.basePath=="string"&&(i=t.query.basePath),i&&(i.startsWith("/")||(i="/"+i),i.endsWith("/")||(i=i+"/"));const c=[];if(typeof n=="string"&&n.includes("vite")&&i&&c.push("--base",i),typeof n=="string"&&n.includes("vite")&&c.push("--debug"),g(s,"INFO","\u5F00\u59CB\u5B89\u88C5\u4F9D\u8D56",{projectId:s}),await k(t,s,r),typeof n=="string"&&n.includes("vite")){const R=["exec","vite","build",...c,"--debug"],f=`cd ${r} && pnpm ${R.join(" ")}`;w(s,"INFO","\u6267\u884C\u547D\u4EE4(\u76F4\u63A5vite)",{command:f});try{g(s,"INFO","\u6267\u884C\u6784\u5EFA\u811A\u672C(\u76F4\u63A5vite)",{command:f,cwd:r})}catch{}await new Promise((h,S)=>{d(f,(E,v,P)=>{if(E){w(s,"ERROR","\u6267\u884C\u9519\u8BEF",{error:E.message,stderr:P});const $=new p,C=P||E.message,_=$.parseBuildError(C,s),M=new x(_,{originalError:E.message,command:f});return S(M)}w(s,"INFO","\u811A\u672C\u6267\u884C\u5B8C\u6210",{stdout:v}),h(v)})})}else g(s,"INFO","\u5F00\u59CB\u540C\u6B65\u6267\u884C build \u811A\u672C",{projectId:s}),await D(s,r,"build",c);return await B({req:t,projectPath:r,projectId:s}),{success:!0,message:"\u6784\u5EFA\u5B8C\u6210",projectId:s}}finally{F.delete(s),O-=1}}export{J as buildProject,B as copyBuildOutputToTarget,D as runBuildScript};
1
+ import{exec as N}from"child_process";import y from"path";import c from"fs";import{log as g,logBuild as d}from"../log/logUtils.js";import P from"../error/buildErrorParser.js";import b from"../../appConfig/index.js";import{BusinessError as S,SystemError as v,FileError as T,ResourceError as A}from"../error/errorHandler.js";import{installDependencies as k}from"../buildDependency/dependencyManager.js";const U=b.PROJECT_SOURCE_DIR,W=b.DIST_TARGET_DIR,x=new Set;let h=0;async function B({req:t,projectPath:i,projectId:s,outStream:o}){try{const l=y.join(i,"dist"),u=W,f=y.join(u,s,"dist");if(!c.existsSync(l)){const r=`dist directory not found: ${l}`;g(s,"WARN",r,{projectId:s}),o&&o.write(`${r}
2
+ `);return}if(c.existsSync(u)||c.mkdirSync(u,{recursive:!0}),c.existsSync(f)&&await c.promises.rm(f,{recursive:!0,force:!0}),c.promises.cp)await c.promises.cp(l,f,{recursive:!0});else{const r=(e,a)=>{if(c.statSync(e).isDirectory()){c.existsSync(a)||c.mkdirSync(a,{recursive:!0});for(const m of c.readdirSync(e))r(y.join(e,m),y.join(a,m))}else c.copyFileSync(e,a)};r(l,f)}const n=`dist directory copied to: ${f}`;g(s,"INFO",n,{projectId:s}),o&&o.write(`${n}
3
+ `)}catch(l){const u=`Failed to copy dist directory: ${l.message}`;throw g(s,"ERROR",u,{projectId:s}),o&&o.write(`${u}
4
+ `),l}}function C(t,i,s,o=[]){return new Promise((l,u)=>{const f=Array.isArray(o)&&o.length>0?" -- "+o.map(r=>String(r)).join(" "):"",n=`cd ${i} && pnpm run ${s}${f}`;d(t,"INFO","Execute command",{command:n});try{g(t,"INFO","Execute build script",{command:n,cwd:i})}catch{}N(n,{env:process.env,maxBuffer:10*1024*1024},(r,e,a)=>{if(r){d(t,"ERROR","Execution error",{error:r.message,stderr:a});const w=new P,m=a||r.message,p=w.parseBuildError(m,t),R=new v(p,{originalError:r.message,command:n});return u(R)}d(t,"INFO","Script execution completed",{stdout:e}),l(e)})})}async function J(t,i){const s=y.join(U,i),o=y.join(s,"package.json");if(!c.existsSync(o))throw new A("Project missing package.json file",{projectId:i,projectPath:s});let u;try{u=JSON.parse(c.readFileSync(o,"utf8"))}catch(e){throw new T("package.json file format error",{projectId:i,jsonFilePath:o,originalError:e.message})}const n=u.scripts.build;if(!n)throw g(i,"WARN","Project missing build script",{projectId:i,requestId:t.requestId}),new S("Project missing build script",{projectId:i});if(x.has(i))throw new S("This project is being built",{projectId:i});const r=Number.isFinite(b.MAX_BUILD_CONCURRENCY)?b.MAX_BUILD_CONCURRENCY:20;if(h>=r)throw new S("Concurrency is full, please try again later",{currentBuilds:h,maxConcurrency:r});x.add(i),h+=1;try{let e="";t&&t.query&&typeof t.query.basePath=="string"&&(e=t.query.basePath),e&&(e.startsWith("/")||(e="/"+e),e.endsWith("/")||(e=e+"/"));const a=[];if(typeof n=="string"&&n.includes("vite")&&e&&a.push("--base",e),typeof n=="string"&&n.includes("vite")&&a.push("--debug"),g(i,"INFO","Start installing dependencies",{projectId:i}),await k(t,i,s),typeof n=="string"&&n.includes("vite")){const w=["exec","vite","build",...a,"--debug"],m=`cd ${s} && pnpm ${w.join(" ")}`;d(i,"INFO","Execute command(direct vite)",{command:m});try{g(i,"INFO","Execute build script(direct vite)",{command:m,cwd:s})}catch{}await new Promise((p,R)=>{N(m,(E,O,F)=>{if(E){d(i,"ERROR","Execution error",{error:E.message,stderr:F});const D=new P,$=F||E.message,_=D.parseBuildError($,i),M=new v(_,{originalError:E.message,command:m});return R(M)}d(i,"INFO","Script execution completed",{stdout:O}),p(O)})})}else g(i,"INFO","Start synchronously executing build script",{projectId:i}),await C(i,s,"build",a);return await B({req:t,projectPath:s,projectId:i}),{success:!0,message:"Build completed",projectId:i}}finally{x.delete(i),h-=1}}export{J as buildProject,B as copyBuildOutputToTarget,C as runBuildScript};
@@ -1 +1 @@
1
- import"../buildArg/portUtils.js";import{log as s}from"../log/logUtils.js";import{deleteRunningProcess as n}from"./processManager.js";import{isProjectAlive as a}from"../buildJudge/aliveJudgeUtils.js";import"./restartDevUtils.js";import{startDevServer as v}from"./startDevUtils.js";import{stopDevServer as p}from"./stopDevUtils.js";async function f(t,r,o,u,m){const e=Number(o),i=Number(u);return s(r,"INFO","\u5F00\u59CB\u68C0\u67E5\u5F00\u53D1\u670D\u52A1\u5668\u72B6\u6001",{projectId:r,pid:e,port:i,requestId:t.requestId}),await a(r,i,m)?(s(r,"INFO","dev\u670D\u52A1\u5668\u5B58\u6D3B\uFF0C\u76F4\u63A5\u8FD4\u56DE\u6210\u529F",{projectId:r,pid:e,port:i,requestId:t.requestId}),{success:!0,message:"\u5F00\u53D1\u670D\u52A1\u5668\u5B58\u6D3B",projectId:r,pid:e,port:i}):(s(r,"INFO","dev\u670D\u52A1\u5668\u4E0D\u5B58\u6D3B\uFF0C\u91CD\u65B0\u542F\u52A8",{projectId:r,pid:e,port:i,requestId:t.requestId}),n(r),e>0&&await p(t,r,e,{strict:!1,waitForStop:!0}),{...await v(t,r),action:"start"})}export{f as keepAliveDevServer};
1
+ import"../buildArg/portUtils.js";import{log as i}from"../log/logUtils.js";import{deleteRunningProcess as u}from"./processManager.js";import{isProjectAlive as v}from"../buildJudge/aliveJudgeUtils.js";import"./restartDevUtils.js";import{startDevServer as a}from"./startDevUtils.js";import{stopDevServer as p}from"./stopDevUtils.js";async function l(t,e,o,n,m){const r=Number(o),s=Number(n);return i(e,"INFO","Start checking development server status",{projectId:e,pid:r,port:s,requestId:t.requestId}),await v(e,s,m)?(i(e,"INFO","Development server is alive, returning success",{projectId:e,pid:r,port:s,requestId:t.requestId}),{success:!0,message:"Development server is alive",projectId:e,pid:r,port:s}):(i(e,"INFO","Development server is not alive, restarting",{projectId:e,pid:r,port:s,requestId:t.requestId}),u(e),r>0&&await p(t,e,r,{strict:!1,waitForStop:!0}),{...await a(t,e),action:"start"})}export{l as keepAliveDevServer};
@@ -1,9 +1,9 @@
1
- import{spawn as q}from"child_process";import b from"fs";import I from"path";import{log as n,getLogDir as oe,getCSTDateString as ae,getCSTTimestampString as le}from"../log/logUtils.js";import j from"../log/logCacheManager.js";import{BusinessError as ce}from"../error/errorHandler.js";import de from"../error/errorCodes.js";import{sanitizeSensitivePaths as ue}from"../common/sensitiveUtils.js";import ee from"../../appConfig/index.js";import"../buildArg/portUtils.js";import me from"../buildArg/extraArgsUtils.js";import{ensureDevBinariesExecutable as fe}from"../buildPermission/permissionManager.js";import{installDependencies as ge}from"../buildDependency/dependencyManager.js";import pe from"../buildArg/portPool.js";import{isProjectAlive as Ee}from"../buildJudge/aliveJudgeUtils.js";function Qe(s,e,i){let o="\u5F00\u53D1\u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25";try{if(b.existsSync(s)){const E=b.readFileSync(s,"utf8"),l=E.split(`
2
- `);let h=-1;for(let p=0;p<l.length;p++){const r=l[p].trim();if(r.match(/^>\s*(vite|webpack|next|nuxt|rollup|parcel|esbuild|tsc|ts-node|astro|svelte|remix)/)||r.match(/^>\s*(pnpm|npm|yarn|bun)\s+(run\s+)?(dev|start|serve|build|watch|start:dev)/)||r.match(/^>\s*node\s+\S+\.(js|ts|mjs)$/)||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: dev")||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: start")||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: serve")||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: build")){h=p;break}}if(h===-1)for(let p=0;p<l.length;p++){const r=l[p].trim();if(r.includes("VITE")||r.includes("Webpack")||r.includes("Next.js")||r.includes("Nuxt")||r.includes("Rollup")||r.includes("Parcel")||r.includes("Astro")||r.includes("Svelte")||r.includes("Remix")||r.includes("Local:")||r.includes("Network:")||r.includes("ready in")||r.includes("compiled successfully")||r.includes("dev server running")||r.includes("server started")){h=p;break}}if(h===-1)for(let p=0;p<l.length;p++){const r=l[p].trim();if(r.includes("Error")||r.includes("error")||r.includes("failed")||r.includes("Cannot find")||r.includes("ERR_")||r.includes("Command failed")||r.includes("ELIFECYCLE")||r.includes("npm ERR!")||r.includes("pnpm ERR!")){h=p;break}}h>=0?(o=l.slice(h).join(`
3
- `).trim(),o||(o="\u547D\u4EE4\u5DF2\u6267\u884C\uFF0C\u4F46\u65E0\u8F93\u51FA\u4FE1\u606F")):o=E.trim(),o=ue(o),o.length>1e3&&(o=o.substring(o.length-1e3))}}catch(E){n(e,"WARN","\u8BFB\u53D6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25",{projectId:e,pid:i,error:E.message})}return o}const w=new Map,H=new Set;function Re(s){return w.get(s)||null}function ye(s,e){w.set(s,e)}function he(s){w.delete(s)}function xe(s){return H.has(s)}function Pe(s){H.add(s)}function we(s){H.delete(s)}async function Ne({req:s,projectId:e,projectPath:i,devScript:o}){const E=(o||"").toLowerCase(),l=E.includes("vite"),h=E.includes("next");if(!l&&!h)throw new ce("\u4E0D\u652F\u6301\u7684\u811A\u672C\u7C7B\u578B"+o+"\uFF0C\u8BF7\u4F7F\u7528vite\u6216next\u811A\u672C",{projectId:e,code:de.INVALID_SCRIPT_TYPE});const p=oe(e);b.existsSync(p)||b.mkdirSync(p,{recursive:!0});const r=ae(),_=I.join(p,`dev-${r}.log`),U=I.join(p,`dev-temp-${Date.now().toString()}.log`);let m,f,c,k=!1,F=!1,M=null,z=!1;const g=(d,N,x,$=!1)=>{if(!d||d.destroyed)return d&&d.destroyed&&n(e,"DEBUG",`${x}\u6D41\u5DF2\u9500\u6BC1\uFF0C\u8DF3\u8FC7\u5199\u5165`,{destroyed:!0}),!1;if(k)return!1;try{const y=`[${le()}] `+N,L=d.write(y);return $&&typeof d.cork=="function"&&typeof d.uncork=="function"&&(d.cork(),setImmediate(()=>{try{d.destroyed||d.uncork()}catch{}})),j.isEnabled()&&!z&&(j.delete(String(e)),z=!0),L}catch(A){if(n(e,"WARN",`${x}\u5199\u5165\u9519\u8BEF`,{error:A.message,code:A.code,streamName:x}),A.code==="ERR_STREAM_WRITE_AFTER_END"||A.code==="EPIPE")try{d&&!d.destroyed&&d.end()}catch(y){n(e,"WARN",`\u5173\u95ED${x}\u6D41\u65F6\u51FA\u9519`,{error:y.message})}return!1}},T=()=>{if(!k){k=!0;try{m&&!m.destroyed&&m.end()}catch(d){n(e,"WARN","\u5173\u95ED\u4E3B\u65E5\u5FD7\u6D41\u65F6\u51FA\u9519",{error:d.message})}try{f&&!f.destroyed&&f.end()}catch(d){n(e,"WARN","\u5173\u95ED\u4E34\u65F6\u65E5\u5FD7\u6D41\u65F6\u51FA\u9519",{error:d.message})}}},G=(d,N)=>{n(e,"WARN",`${d}\u6D41\u9519\u8BEF`,{error:N.message}),(N.code==="ERR_STREAM_WRITE_AFTER_END"||N.code==="EPIPE")&&F&&T()};try{try{await fe(i)}catch{}m=b.createWriteStream(_,{flags:"a"}),f=b.createWriteStream(U,{flags:"a"});const d="set +e ; pnpm dlx @xagi/dev-inject@latest install --framework ; pnpm dlx @xagi/vite-plugin-design-mode@latest install ; set -e";await new Promise(t=>{try{const a=q("bash",["-lc",d],{cwd:i,env:{...process.env},stdio:["ignore","pipe","pipe"]});a.stdout.on("data",u=>{const R=u.toString();g(m,R,"\u4E3B\u65E5\u5FD7"),g(f,R,"\u4E34\u65F6\u65E5\u5FD7")}),a.stderr.on("data",u=>{const R=u.toString();g(m,R,"\u4E3B\u65E5\u5FD7"),g(f,R,"\u4E34\u65F6\u65E5\u5FD7")}),a.on("error",u=>{const R=`\u9884\u5904\u7406\u547D\u4EE4\u6267\u884C\u51FA\u9519\uFF08\u5FFD\u7565\u5E76\u7EE7\u7EED\u540E\u7EED\u6D41\u7A0B\uFF09: ${u.message}
4
- `;g(m,R,"\u4E3B\u65E5\u5FD7",!0),g(f,R,"\u4E34\u65F6\u65E5\u5FD7",!0),t()}),a.on("close",u=>{if(u!==0){const R=`\u9884\u5904\u7406\u547D\u4EE4\u9000\u51FA\u7801\u4E3A ${u}\uFF08\u5FFD\u7565\u5E76\u7EE7\u7EED\u540E\u7EED\u6D41\u7A0B\uFF09
5
- `;g(m,R,"\u4E3B\u65E5\u5FD7",!0),g(f,R,"\u4E34\u65F6\u65E5\u5FD7",!0)}t()})}catch(a){const u=`\u9884\u5904\u7406\u547D\u4EE4\u542F\u52A8\u5931\u8D25\uFF08\u5FFD\u7565\u5E76\u7EE7\u7EED\u540E\u7EED\u6D41\u7A0B\uFF09: ${a.message}
6
- `;g(m,u,"\u4E3B\u65E5\u5FD7",!0),g(f,u,"\u4E34\u65F6\u65E5\u5FD7",!0),t()}});try{await ge(s,e,i,{outStream:m,tempOutStream:f,safeWrite:g})}catch(t){const a=`\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25: ${t.message}
7
- `;throw g(m,a,"\u4E3B\u65E5\u5FD7",!0),g(f,a,"\u4E34\u65F6\u65E5\u5FD7",!0),t}const N=`\u5F00\u59CB\u6267\u884C\u811A\u672C: dev
8
- `;g(m,N,"\u4E3B\u65E5\u5FD7"),g(f,N,"\u4E34\u65F6\u65E5\u5FD7");const x=[],{extraArgs:$,envExtra:A,port:y}=await me.processExtraArgs({devScript:o,projectId:e,req:s});M=y,$&&$.length>0&&x.push(...$);const L=t=>`'${String(t).replace(/'/g,"'\\''")}'`,P=x&&x.length>0?x.map(L).join(" "):"";P&&n(e,"INFO","\u751F\u6210\u7684\u989D\u5916\u53C2\u6570",{extraArgs:$,npmArgs:x,extraArgsEscaped:P});const K=t=>{if(!t||typeof t!="string")return!1;const a=t.trim();if(a.includes("/")||a.includes("\\"))return!1;const u=a.split(/\s+/)[0];return["vite","next","webpack","rollup","parcel","esbuild","tsc","ts-node","astro","svelte","remix","nuxt"].includes(u)};let v,S="";if(l){const a=((W,se)=>{if(!W||typeof W!="string")return W;let O=W;for(const B of se){const re=new RegExp(`${B.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}=\\S+`,"g");O=O.replace(re,"");const ne=new RegExp(`${B.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}s+([^s-][^s]*)`,"g");O=O.replace(ne,"");const ie=new RegExp(`${B.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}\b`,"g");O=O.replace(ie,"")}return O.replace(/\s{2,}/g," ").trim()})(o,["--host","--base"]),u=P?` ${P}`:"",R=K(a)?"npx":"";S=R?`${R} ${a}${u}`:`${a}${u}`,v=`exec ${S}`}else if(h){const t=P?` ${P}`:"",a=K(o)?"npx":"";S=a?`${a} ${o}${t}`:`${o}${t}`,v=`exec ${S}`}else S=`pnpm run dev${P?` -- ${P}`:""}`,v=`exec ${S}`;if(S){const t=`> ${S}
9
- `;g(m,t,"\u4E3B\u65E5\u5FD7"),g(f,t,"\u4E34\u65F6\u65E5\u5FD7")}try{n(e,"INFO","\u5F00\u542F\u5B50\u8FDB\u7A0B,\u4E32\u884C\u6267\u884C\u9884\u5904\u7406\u5E76\u542F\u52A8 dev:",{command:v,cwd:i,devScript:o,extraArgs:$,envExtraKeys:Object.keys(A||{})})}catch{}c=q("sh",["-c",v],{cwd:i,env:{PATH:process.env.PATH,NODE_ENV:"development",...A},detached:!0,stdio:["ignore","pipe","pipe"]}),m.on("error",t=>{n(e,"ERROR","\u4E3B\u65E5\u5FD7\u6D41\u9519\u8BEF",{error:t.message,code:t.code,path:_,destroyed:m.destroyed}),G("\u4E3B\u65E5\u5FD7",t)}),f.on("error",t=>{n(e,"ERROR","\u4E34\u65F6\u65E5\u5FD7\u6D41\u9519\u8BEF",{error:t.message,code:t.code,path:U,destroyed:f.destroyed}),G("\u4E34\u65F6\u65E5\u5FD7",t)}),c.stdout&&(c.stdout.on("data",t=>{const a=g(m,t,"\u4E3B\u65E5\u5FD7"),u=g(f,t,"\u4E34\u65F6\u65E5\u5FD7");(!a||!u)&&n(e,"DEBUG","\u65E5\u5FD7\u5199\u5165\u72B6\u6001",{mainWriteOk:a,tempWriteOk:u,mainDestroyed:m?m.destroyed:null,tempDestroyed:f?f.destroyed:null,streamsClosed:k})}),c.stdout.on("error",t=>{n(e,"WARN","\u5B50\u8FDB\u7A0Bstdout\u9519\u8BEF",{error:t.message})}),c.stdout.on("end",()=>{n(e,"INFO","\u5B50\u8FDB\u7A0Bstdout\u6D41\u5DF2\u7ED3\u675F",{pid:c.pid})})),c.stderr&&(c.stderr.on("data",t=>{const a=g(m,t,"\u4E3B\u65E5\u5FD7"),u=g(f,t,"\u4E34\u65F6\u65E5\u5FD7");(!a||!u)&&n(e,"DEBUG","\u65E5\u5FD7\u5199\u5165\u72B6\u6001(stderr)",{mainWriteOk:a,tempWriteOk:u,mainDestroyed:m?m.destroyed:null,tempDestroyed:f?f.destroyed:null,streamsClosed:k})}),c.stderr.on("error",t=>{n(e,"WARN","\u5B50\u8FDB\u7A0Bstderr\u9519\u8BEF",{error:t.message})}),c.stderr.on("end",()=>{n(e,"INFO","\u5B50\u8FDB\u7A0Bstderr\u6D41\u5DF2\u7ED3\u675F",{pid:c.pid})})),c.on("exit",(t,a)=>{F=!0,n(e,"INFO","\u5B50\u8FDB\u7A0B\u5DF2\u9000\u51FA",{pid:c.pid,code:t,signal:a}),setTimeout(()=>{T()},200)}),c.on("error",t=>{n(e,"WARN","\u5B50\u8FDB\u7A0B\u9519\u8BEF",{error:t.message}),F=!0,n(e,"ERROR","\u5B50\u8FDB\u7A0B\u542F\u52A8\u5931\u8D25",{pid:c.pid,error:t.message}),T()}),w.set(e,{pid:c.pid,logPath:_,startedAt:Date.now()}),c.unref(),v&&v.includes("exec ")&&await new Promise(t=>setTimeout(t,200)),n(e,"INFO","\u4F7F\u7528\u7AEF\u53E3\u6C60\u5206\u914D\u7684\u7AEF\u53E3\u548C\u5F53\u524D\u8FDB\u7A0BID",{projectId:e,pid:c.pid,port:y});const Y=s&&s.query&&s.query.basePath||s&&s.body&&s.body.basePath||void 0,X=Y||"/",J=3e4,Q=1e3,te=1500;let V=!1;const Z=Date.now();for(await new Promise(t=>setTimeout(t,Q));Date.now()-Z<J&&(V=await Ee(e,y,Y,{timeoutMs:te}),!V);)await new Promise(t=>setTimeout(t,Q));if(V)n(e,"INFO","\u9879\u76EE\u53EF\u8BBF\u95EE\u6821\u9A8C\u901A\u8FC7",{port:y,basePath:X,elapsedMs:Date.now()-Z});else{const t=Math.round(J/1e3);n(e,"WARN","\u5F00\u53D1\u670D\u52A1\u5668\u5728\u9650\u5B9A\u65F6\u95F4\u5185\u4ECD\u4E0D\u53EF\u8BBF\u95EE",{port:y,pid:c.pid,basePath:X,waitSeconds:t})}const D=w.get(e);return D&&(D.port=y,D.pid=c.pid,w.set(e,D)),n(e,"INFO","\u5F00\u53D1\u670D\u52A1\u5668\u542F\u52A8\u6210\u529F",{projectId:e,pid:c.pid,port:y}),{pid:c.pid,port:y}}catch(d){throw M&&(pe.release(String(e)),n(e,"INFO","\u542F\u52A8\u5931\u8D25\uFF0C\u5DF2\u91CA\u653E\u7AEF\u53E3",{port:M,error:d.message})),d}finally{(F||!c||!c.pid)&&T()}}async function Ae(s,e){const i=Number(e);if(!Number.isFinite(i))return!1;if(!C(i))return n(s,"INFO","\u8FDB\u7A0B\u5DF2\u4E0D\u5B58\u5728",{pid:i}),w.delete(s),!0;let o=!1,E="";try{process.kill(-i),o=!0,E="\u8FDB\u7A0B\u7EC4",n(s,"INFO","\u901A\u8FC7\u8FDB\u7A0B\u7EC4\u6740\u6B7B\u8FDB\u7A0B",{pid:i})}catch(l){l&&(l.code==="ESRCH"||l.errno==="ESRCH")?(o=!1,E="\u8FDB\u7A0B\u7EC4(\u4E0D\u5B58\u5728)",n(s,"INFO","\u8FDB\u7A0B\u7EC4\u4E0D\u5B58\u5728\uFF0C\u56DE\u9000\u5C1D\u8BD5\u5355\u4E2A\u8FDB\u7A0Bkill",{pid:i})):n(s,"WARN","\u6740\u6B7B\u8FDB\u7A0B\u7EC4\u5931\u8D25",{pid:i,error:l.message})}if(!o)try{process.kill(i),o=!0,E="\u5355\u4E2A\u8FDB\u7A0B",n(s,"INFO","\u901A\u8FC7\u5355\u4E2A\u8FDB\u7A0B\u6740\u6B7B\u8FDB\u7A0B",{pid:i})}catch(l){l&&(l.code==="ESRCH"||l.errno==="ESRCH")?(o=!0,E="\u5355\u4E2A\u8FDB\u7A0B(\u4E0D\u5B58\u5728)",n(s,"INFO","\u8FDB\u7A0B\u4E0D\u5B58\u5728\uFF0C\u89C6\u4E3A\u5DF2\u505C\u6B62",{pid:i})):n(s,"ERROR","\u6740\u6B7B\u8FDB\u7A0B\u5931\u8D25",{pid:i,error:l.message})}return o&&(await new Promise(l=>setTimeout(l,100)),C(i)?(n(s,"WARN","\u8FDB\u7A0B\u4ECD\u7136\u5B58\u5728\uFF0Ckill\u53EF\u80FD\u5931\u8D25",{pid:i,method:E}),!1):(n(s,"INFO","\u8FDB\u7A0B\u5DF2\u6210\u529F\u505C\u6B62",{pid:i,method:E}),w.delete(s),!0))}function C(s){try{return process.kill(s,0),!0}catch(e){return e&&(e.code==="EPERM"||e.code==="EACCES")?!0:(e&&e.code==="ESRCH",!1)}}async function Se(s,e){let i=0;const o=ee.DEV_SERVER_STOP_MAX_ATTEMPTS;for(;C(e)&&i<o;)await new Promise(l=>setTimeout(l,ee.DEV_SERVER_STOP_CHECK_INTERVAL)),i++;return{stopped:!C(e),attempts:i}}function $e(){return Array.from(w.entries()).map(([e,i])=>({projectId:e,pid:i.pid,type:i.type,startedAt:i.startedAt,port:i.port}))}export{Re as getRunningProcess,ye as setRunningProcess,he as deleteRunningProcess,xe as isProjectStarting,Pe as addStartingProject,we as removeStartingProject,Ne as startDev_NonBlocking,Ae as killProcess,C as isProcessRunning,Se as waitForProcessStop,$e as listRunningProcesses};
1
+ import{spawn as Z}from"child_process";import C from"fs";import I from"path";import{log as n,getLogDir as oe,getCSTDateString as ae,getCSTTimestampString as le}from"../log/logUtils.js";import j from"../log/logCacheManager.js";import{BusinessError as ce}from"../error/errorHandler.js";import de from"../error/errorCodes.js";import{sanitizeSensitivePaths as ue}from"../common/sensitiveUtils.js";import ee from"../../appConfig/index.js";import"../buildArg/portUtils.js";import me from"../buildArg/extraArgsUtils.js";import{ensureDevBinariesExecutable as pe}from"../buildPermission/permissionManager.js";import{installDependencies as ge}from"../buildDependency/dependencyManager.js";import fe from"../buildArg/portPool.js";import{isProjectAlive as Ee}from"../buildJudge/aliveJudgeUtils.js";function Je(s,e,i){let o="\u5F00\u53D1\u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25";try{if(C.existsSync(s)){const E=C.readFileSync(s,"utf8"),l=E.split(`
2
+ `);let y=-1;for(let f=0;f<l.length;f++){const r=l[f].trim();if(r.match(/^>\s*(vite|webpack|next|nuxt|rollup|parcel|esbuild|tsc|ts-node|astro|svelte|remix)/)||r.match(/^>\s*(pnpm|npm|yarn|bun)\s+(run\s+)?(dev|start|serve|build|watch|start:dev)/)||r.match(/^>\s*node\s+\S+\.(js|ts|mjs)$/)||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: dev")||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: start")||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: serve")||r.includes("\u5F00\u59CB\u6267\u884C\u811A\u672C: build")){y=f;break}}if(y===-1)for(let f=0;f<l.length;f++){const r=l[f].trim();if(r.includes("VITE")||r.includes("Webpack")||r.includes("Next.js")||r.includes("Nuxt")||r.includes("Rollup")||r.includes("Parcel")||r.includes("Astro")||r.includes("Svelte")||r.includes("Remix")||r.includes("Local:")||r.includes("Network:")||r.includes("ready in")||r.includes("compiled successfully")||r.includes("dev server running")||r.includes("server started")){y=f;break}}if(y===-1)for(let f=0;f<l.length;f++){const r=l[f].trim();if(r.includes("Error")||r.includes("error")||r.includes("failed")||r.includes("Cannot find")||r.includes("ERR_")||r.includes("Command failed")||r.includes("ELIFECYCLE")||r.includes("npm ERR!")||r.includes("pnpm ERR!")){y=f;break}}y>=0?(o=l.slice(y).join(`
3
+ `).trim(),o||(o="\u547D\u4EE4\u5DF2\u6267\u884C\uFF0C\u4F46\u65E0\u8F93\u51FA\u4FE1\u606F")):o=E.trim(),o=ue(o),o.length>1e3&&(o=o.substring(o.length-1e3))}}catch(E){n(e,"WARN","\u8BFB\u53D6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25",{projectId:e,pid:i,error:E.message})}return o}const w=new Map,H=new Set;function Re(s){return w.get(s)||null}function he(s,e){w.set(s,e)}function ye(s){w.delete(s)}function xe(s){return H.has(s)}function Pe(s){H.add(s)}function we(s){H.delete(s)}async function Ne({req:s,projectId:e,projectPath:i,devScript:o}){const E=(o||"").toLowerCase(),l=E.includes("vite"),y=E.includes("next");if(!l&&!y)throw new ce("\u4E0D\u652F\u6301\u7684\u811A\u672C\u7C7B\u578B"+o+"\uFF0C\u8BF7\u4F7F\u7528vite\u6216next\u811A\u672C",{projectId:e,code:de.INVALID_SCRIPT_TYPE});const f=oe(e);C.existsSync(f)||C.mkdirSync(f,{recursive:!0});const r=ae(),W=I.join(f,`dev-${r}.log`),U=I.join(f,`dev-temp-${Date.now().toString()}.log`);let m,p,c,b=!1,O=!1,_=null,G=!1;const g=(d,N,x,v=!1)=>{if(!d||d.destroyed)return d&&d.destroyed&&n(e,"DEBUG",`${x}\u6D41\u5DF2\u9500\u6BC1\uFF0C\u8DF3\u8FC7\u5199\u5165`,{destroyed:!0}),!1;if(b)return!1;try{const h=`[${le()}] `+N,L=d.write(h);return v&&typeof d.cork=="function"&&typeof d.uncork=="function"&&(d.cork(),setImmediate(()=>{try{d.destroyed||d.uncork()}catch{}})),j.isEnabled()&&!G&&(j.delete(String(e)),G=!0),L}catch(S){if(n(e,"WARN",`${x}\u5199\u5165\u9519\u8BEF`,{error:S.message,code:S.code,streamName:x}),S.code==="ERR_STREAM_WRITE_AFTER_END"||S.code==="EPIPE")try{d&&!d.destroyed&&d.end()}catch(h){n(e,"WARN",`\u5173\u95ED${x}\u6D41\u65F6\u51FA\u9519`,{error:h.message})}return!1}},F=()=>{if(!b){b=!0;try{m&&!m.destroyed&&m.end()}catch(d){n(e,"WARN","\u5173\u95ED\u4E3B\u65E5\u5FD7\u6D41\u65F6\u51FA\u9519",{error:d.message})}try{p&&!p.destroyed&&p.end()}catch(d){n(e,"WARN","\u5173\u95ED\u4E34\u65F6\u65E5\u5FD7\u6D41\u65F6\u51FA\u9519",{error:d.message})}}},z=(d,N)=>{n(e,"WARN",`${d}\u6D41\u9519\u8BEF`,{error:N.message}),(N.code==="ERR_STREAM_WRITE_AFTER_END"||N.code==="EPIPE")&&O&&F()};try{try{await pe(i)}catch{}m=C.createWriteStream(W,{flags:"a"}),p=C.createWriteStream(U,{flags:"a"});const d="set +e ; pnpm dlx @xagi/dev-inject@latest install --framework ; pnpm dlx @xagi/vite-plugin-design-mode@latest install ; set -e";await new Promise(t=>{try{const a=Z("bash",["-lc",d],{cwd:i,env:{...process.env},stdio:["ignore","pipe","pipe"]});a.stdout.on("data",u=>{const R=u.toString();g(m,R,"Main log"),g(p,R,"Temp log")}),a.stderr.on("data",u=>{const R=u.toString();g(m,R,"Main log"),g(p,R,"Temp log")}),a.on("error",u=>{const R=`\u9884\u5904\u7406\u547D\u4EE4\u6267\u884C\u51FA\u9519\uFF08\u5FFD\u7565\u5E76\u7EE7\u7EED\u540E\u7EED\u6D41\u7A0B\uFF09: ${u.message}
4
+ `;g(m,R,"Main log",!0),g(p,R,"Temp log",!0),t()}),a.on("close",u=>{if(u!==0){const R=`Preprocessing command exit code is ${u} (ignore and continue subsequent process)
5
+ `;g(m,R,"\u4E3B\u65E5\u5FD7",!0),g(p,R,"\u4E34\u65F6\u65E5\u5FD7",!0)}t()})}catch(a){const u=`\u9884\u5904\u7406\u547D\u4EE4\u542F\u52A8\u5931\u8D25\uFF08\u5FFD\u7565\u5E76\u7EE7\u7EED\u540E\u7EED\u6D41\u7A0B\uFF09: ${a.message}
6
+ `;g(m,u,"Main log",!0),g(p,u,"Temp log",!0),t()}});try{await ge(s,e,i,{outStream:m,tempOutStream:p,safeWrite:g})}catch(t){const a=`Dependency installation failed: ${t.message}
7
+ `;throw g(m,a,"Main log",!0),g(p,a,"Temp log",!0),t}const N=`Start executing script: dev
8
+ `;g(m,N,"Main log"),g(p,N,"Temp log");const x=[],{extraArgs:v,envExtra:S,port:h}=await me.processExtraArgs({devScript:o,projectId:e,req:s});_=h,v&&v.length>0&&x.push(...v);const L=t=>`'${String(t).replace(/'/g,"'\\''")}'`,P=x&&x.length>0?x.map(L).join(" "):"";P&&n(e,"INFO","Generated extra arguments",{extraArgs:v,npmArgs:x,extraArgsEscaped:P});const K=t=>{if(!t||typeof t!="string")return!1;const a=t.trim();if(a.includes("/")||a.includes("\\"))return!1;const u=a.split(/\s+/)[0];return["vite","next","webpack","rollup","parcel","esbuild","tsc","ts-node","astro","svelte","remix","nuxt"].includes(u)};let $,A="";if(l){const a=((M,se)=>{if(!M||typeof M!="string")return M;let T=M;for(const B of se){const re=new RegExp(`${B.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}=\\S+`,"g");T=T.replace(re,"");const ne=new RegExp(`${B.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}s+([^s-][^s]*)`,"g");T=T.replace(ne,"");const ie=new RegExp(`${B.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}\b`,"g");T=T.replace(ie,"")}return T.replace(/\s{2,}/g," ").trim()})(o,["--host","--base"]),u=P?` ${P}`:"",R=K(a)?"npx":"";A=R?`${R} ${a}${u}`:`${a}${u}`,$=`exec ${A}`}else if(y){const t=P?` ${P}`:"",a=K(o)?"npx":"";A=a?`${a} ${o}${t}`:`${o}${t}`,$=`exec ${A}`}else A=`pnpm run dev${P?` -- ${P}`:""}`,$=`exec ${A}`;if(A){const t=`> ${A}
9
+ `;g(m,t,"Main log"),g(p,t,"Temp log")}try{n(e,"INFO","Start child process, sequentially execute preprocessing and start dev:",{command:$,cwd:i,devScript:o,extraArgs:v,envExtraKeys:Object.keys(S||{})})}catch{}c=Z("sh",["-c",$],{cwd:i,env:{PATH:process.env.PATH,NODE_ENV:"development",...S},detached:!0,stdio:["ignore","pipe","pipe"]}),m.on("error",t=>{n(e,"ERROR","Main log stream error",{error:t.message,code:t.code,path:W,destroyed:m.destroyed}),z("Main log",t)}),p.on("error",t=>{n(e,"ERROR","Temp log stream error",{error:t.message,code:t.code,path:U,destroyed:p.destroyed}),z("Temp log",t)}),c.stdout&&(c.stdout.on("data",t=>{const a=g(m,t,"Main log"),u=g(p,t,"Temp log");(!a||!u)&&n(e,"DEBUG","Log writing status",{mainWriteOk:a,tempWriteOk:u,mainDestroyed:m?m.destroyed:null,tempDestroyed:p?p.destroyed:null,streamsClosed:b})}),c.stdout.on("error",t=>{n(e,"WARN","Child process stdout error",{error:t.message})}),c.stdout.on("end",()=>{n(e,"INFO","\u5B50\u8FDB\u7A0Bstdout\u6D41\u5DF2\u7ED3\u675F",{pid:c.pid})})),c.stderr&&(c.stderr.on("data",t=>{const a=g(m,t,"Main log"),u=g(p,t,"Temp log");(!a||!u)&&n(e,"DEBUG","Log writing status(stderr)",{mainWriteOk:a,tempWriteOk:u,mainDestroyed:m?m.destroyed:null,tempDestroyed:p?p.destroyed:null,streamsClosed:b})}),c.stderr.on("error",t=>{n(e,"WARN","Child process stderr error",{error:t.message})}),c.stderr.on("end",()=>{n(e,"INFO","Child process stderr stream ended",{pid:c.pid})})),c.on("exit",(t,a)=>{O=!0,n(e,"INFO","Child process exited",{pid:c.pid,code:t,signal:a}),setTimeout(()=>{F()},200)}),c.on("error",t=>{n(e,"WARN","Child process error",{error:t.message}),O=!0,n(e,"ERROR","Child process startup failed",{pid:c.pid,error:t.message}),F()}),w.set(e,{pid:c.pid,logPath:W,startedAt:Date.now()}),c.unref(),$&&$.includes("exec ")&&await new Promise(t=>setTimeout(t,200)),n(e,"INFO","Using port pool allocated port and current process ID",{projectId:e,pid:c.pid,port:h});const Y=s&&s.query&&s.query.basePath||s&&s.body&&s.body.basePath||void 0,X=Y||"/",q=3e4,J=1e3,te=1500;let V=!1;const Q=Date.now();for(await new Promise(t=>setTimeout(t,J));Date.now()-Q<q&&(V=await Ee(e,h,Y,{timeoutMs:te}),!V);)await new Promise(t=>setTimeout(t,J));if(V)n(e,"INFO","Project accessibility verification passed",{port:h,basePath:X,elapsedMs:Date.now()-Q});else{const t=Math.round(q/1e3);n(e,"WARN","Development server is not accessible within the limited time",{port:h,pid:c.pid,basePath:X,waitSeconds:t})}const D=w.get(e);return D&&(D.port=h,D.pid=c.pid,w.set(e,D)),n(e,"INFO","Development server startup successfully",{projectId:e,pid:c.pid,port:h}),{pid:c.pid,port:h}}catch(d){throw _&&(fe.release(String(e)),n(e,"INFO","Startup failed, port released",{port:_,error:d.message})),d}finally{(O||!c||!c.pid)&&F()}}async function Se(s,e){const i=Number(e);if(!Number.isFinite(i))return!1;if(!k(i))return n(s,"INFO","Process does not exist",{pid:i}),w.delete(s),!0;let o=!1,E="";try{process.kill(-i),o=!0,E="Process group",n(s,"INFO","\u901A\u8FC7\u8FDB\u7A0B\u7EC4\u6740\u6B7B\u8FDB\u7A0B",{pid:i})}catch(l){l&&(l.code==="ESRCH"||l.errno==="ESRCH")?(o=!1,E="Process group(not exist)",n(s,"INFO","Process group does not exist, back to try single process kill",{pid:i})):n(s,"WARN","Failed to kill process group",{pid:i,error:l.message})}if(!o)try{process.kill(i),o=!0,E="\u5355\u4E2A\u8FDB\u7A0B",n(s,"INFO","Kill process through single process",{pid:i})}catch(l){l&&(l.code==="ESRCH"||l.errno==="ESRCH")?(o=!0,E="Single process(not exist)",n(s,"INFO","Process does not exist,\u89C6\u4E3A\u5DF2\u505C\u6B62",{pid:i})):n(s,"ERROR","Failed to kill process",{pid:i,error:l.message})}return o&&(await new Promise(l=>setTimeout(l,100)),k(i)?(n(s,"WARN","Process still exists, kill may have failed",{pid:i,method:E}),!1):(n(s,"INFO","Process stopped successfully",{pid:i,method:E}),w.delete(s),!0))}function k(s){try{return process.kill(s,0),!0}catch(e){return e&&(e.code==="EPERM"||e.code==="EACCES")?!0:(e&&e.code==="ESRCH",!1)}}async function Ae(s,e){let i=0;const o=ee.DEV_SERVER_STOP_MAX_ATTEMPTS;for(;k(e)&&i<o;)await new Promise(l=>setTimeout(l,ee.DEV_SERVER_STOP_CHECK_INTERVAL)),i++;return{stopped:!k(e),attempts:i}}function ve(){return Array.from(w.entries()).map(([e,i])=>({projectId:e,pid:i.pid,type:i.type,startedAt:i.startedAt,port:i.port}))}export{Re as getRunningProcess,he as setRunningProcess,ye as deleteRunningProcess,xe as isProjectStarting,Pe as addStartingProject,we as removeStartingProject,Ne as startDev_NonBlocking,Se as killProcess,k as isProcessRunning,Ae as waitForProcessStop,ve as listRunningProcesses};
@@ -1 +1 @@
1
- import f from"path";import c from"fs";import{log as s}from"../log/logUtils.js";import S from"../../appConfig/index.js";import{BusinessError as l,FileError as g,ResourceError as v}from"../error/errorHandler.js";import{addStartingProject as w,removeStartingProject as N,startDev_NonBlocking as p}from"./processManager.js";import"../error/errorCodes.js";import{stopDevServer as F}from"./stopDevUtils.js";import{removeNodeModules as O}from"../buildDependency/dependencyManager.js";import{createPnpmNpmrc as R}from"../common/npmrcUtils.js";const y=S.PROJECT_SOURCE_DIR;async function E(t,r){s(r,"INFO","\u5F00\u59CB\u91CD\u542F\u5F00\u53D1\u670D\u52A1\u5668",{projectId:r,requestId:t.requestId});const e=f.join(y,r),o=f.join(e,"package.json");if(!c.existsSync(o))throw s(r,"WARN","\u9879\u76EE\u7F3A\u5C11package.json\u6587\u4EF6",{projectId:r,requestId:t.requestId}),new v("\u9879\u76EE\u7F3A\u5C11package.json\u6587\u4EF6",{projectId:r,projectPath:e});let n;try{n=JSON.parse(c.readFileSync(o,"utf8"))}catch(i){throw new g("package.json\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF",{projectId:r,jsonFilePath:o,originalError:i.message})}const a=n.scripts.dev;if(!a)throw s(r,"WARN","\u9879\u76EE\u7F3A\u5C11dev\u811A\u672C",{projectId:r,requestId:t.requestId}),new l("\u9879\u76EE\u7F3A\u5C11dev\u811A\u672C",{projectId:r});w(r);try{const i=t.query.pid;await F(t,r,i,{strict:!1,waitForStop:!0}),s(r,"INFO","\u5F00\u59CB\u5220\u9664node_modules\u548Clock\u6587\u4EF6",{projectId:r,requestId:t.requestId}),await O(e,r),s(r,"INFO","\u521B\u5EFA.npmrc\u6587\u4EF6",{projectId:r,requestId:t.requestId}),await R(e,r),s(r,"INFO","\u5F00\u59CB\u542F\u52A8dev\u670D\u52A1\u5668",{projectId:r,requestId:t.requestId});const{pid:m,port:u}=await p({req:t,projectId:r,projectPath:e,devScript:a});return s(r,"INFO","dev\u670D\u52A1\u5668\u91CD\u542F\u5B8C\u6210",{projectId:r,pid:m,port:u,requestId:t.requestId}),{success:!0,message:"\u5F00\u53D1\u670D\u52A1\u5668\u91CD\u542F\u6210\u529F",projectId:r,pid:m,port:u}}finally{N(r)}}export{E as restartDevServer};
1
+ import f from"path";import l from"fs";import{log as t}from"../log/logUtils.js";import c from"../../appConfig/index.js";import{BusinessError as g,FileError as v,ResourceError as S}from"../error/errorHandler.js";import{addStartingProject as p,removeStartingProject as P,startDev_NonBlocking as w}from"./processManager.js";import"../error/errorCodes.js";import{stopDevServer as N}from"./stopDevUtils.js";import{removeNodeModules as F}from"../buildDependency/dependencyManager.js";import{createPnpmNpmrc as O}from"../common/npmrcUtils.js";const d=c.PROJECT_SOURCE_DIR;async function y(e,r){t(r,"INFO","Start restarting development server",{projectId:r,requestId:e.requestId});const s=f.join(d,r),i=f.join(s,"package.json");if(!l.existsSync(i))throw t(r,"WARN","Project missing package.json file",{projectId:r,requestId:e.requestId}),new S("Project missing package.json file",{projectId:r,projectPath:s});let n;try{n=JSON.parse(l.readFileSync(i,"utf8"))}catch(o){throw new v("package.json file format error",{projectId:r,jsonFilePath:i,originalError:o.message})}const a=n.scripts.dev;if(!a)throw t(r,"WARN","Project missing dev script",{projectId:r,requestId:e.requestId}),new g("Project missing dev script",{projectId:r});p(r);try{const o=e.query.pid;await N(e,r,o,{strict:!1,waitForStop:!0}),t(r,"INFO","Start deleting node_modules and lock file",{projectId:r,requestId:e.requestId}),await F(s,r),t(r,"INFO","Create .npmrc file",{projectId:r,requestId:e.requestId}),await O(s,r),t(r,"INFO","Start starting dev server",{projectId:r,requestId:e.requestId});const{pid:m,port:u}=await w({req:e,projectId:r,projectPath:s,devScript:a});return t(r,"INFO","Dev server restart completed",{projectId:r,pid:m,port:u,requestId:e.requestId}),{success:!0,message:"Development server restart successfully",projectId:r,pid:m,port:u}}finally{P(r)}}export{y as restartDevServer};
@@ -1 +1 @@
1
- import l from"path";import i from"fs";import{log as r}from"../log/logUtils.js";import y from"../../appConfig/index.js";import{BusinessError as L,FileError as E,ResourceError as P}from"../error/errorHandler.js";import"../error/errorCodes.js";import{addStartingProject as _,removeStartingProject as N,startDev_NonBlocking as O}from"./processManager.js";import{removeNodeModules as w}from"../buildDependency/dependencyManager.js";const A=y.PROJECT_SOURCE_DIR;async function D(o,s){_(s);try{r(s,"INFO","\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668",{projectId:s,requestId:o.requestId});const t=l.join(A,s),a=l.join(t,"package.json");if(!i.existsSync(a))throw r(s,"WARN","\u9879\u76EE\u7F3A\u5C11package.json\u6587\u4EF6",{projectId:s,requestId:o.requestId}),new P("\u9879\u76EE\u7F3A\u5C11package.json\u6587\u4EF6",{projectId:s,projectPath:t});let m;try{m=JSON.parse(i.readFileSync(a,"utf8"))}catch(e){throw new E("package.json\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF",{projectId:s,jsonFilePath:a,originalError:e.message})}const p=m.scripts.dev;if(!p)throw r(s,"WARN","\u9879\u76EE\u7F3A\u5C11dev\u811A\u672C",{projectId:s,requestId:o.requestId}),new L("\u7F3A\u5C11dev\u811A\u672C\uFF0C\u8BF7\u5728package.json\u4E2D\u6DFB\u52A0dev\u811A\u672C",{projectId:s});try{if(process.platform==="linux"){const c=typeof process.report?.getReport=="function"?process.report.getReport():null,g=c&&c.header&&c.header.glibcVersionRuntime,u=!g,R=l.join(t,"node_modules",".pnpm");if(i.existsSync(R)){const f=await i.promises.readdir(R,{withFileTypes:!0}),v=f.some(n=>n.isDirectory()&&(n.name||"").includes("@rollup+rollup-linux-x64-gnu")),x=f.some(n=>n.isDirectory()&&(n.name||"").includes("@rollup+rollup-linux-x64-musl"));(u&&v||!u&&x)&&(r(s,"WARN","\u68C0\u6D4B\u5230 Rollup \u539F\u751F\u5305\u4E0E libc \u4E0D\u5339\u914D\uFF0C\u6E05\u7406\u4F9D\u8D56\u540E\u91CD\u88C5",{projectId:s,isMusl:u,glibcVersion:g||null}),await w(t,s))}}}catch(e){r(s,"WARN","Linux \u539F\u751F\u5305\u5339\u914D\u68C0\u6D4B\u5931\u8D25\uFF08\u5FFD\u7565\u7EE7\u7EED\uFF09",{error:e&&e.message})}try{process.env.ROLLUP_WASM=process.env.ROLLUP_WASM||"1",process.env.ROLLUP_DISABLE_NATIVE=process.env.ROLLUP_DISABLE_NATIVE||"1"}catch{}r(s,"INFO","\u5F00\u59CB\u4EE5\u975E\u963B\u585E\u65B9\u5F0F\u6267\u884C dev \u811A\u672C",{projectId:s,requestId:o.requestId});const{pid:S,port:h}=await O({req:o,projectId:s,projectPath:t,devScript:p});return{success:!0,message:"\u5F00\u53D1\u670D\u52A1\u5668\u5DF2\u542F\u52A8",projectId:s,pid:S,port:h}}finally{N(s)}}export{D as startDevServer};
1
+ import u from"path";import n from"fs";import{log as r}from"../log/logUtils.js";import P from"../../appConfig/index.js";import{BusinessError as x,FileError as y,ResourceError as L}from"../error/errorHandler.js";import"../error/errorCodes.js";import{addStartingProject as D,removeStartingProject as E,startDev_NonBlocking as _}from"./processManager.js";import{removeNodeModules as N}from"../buildDependency/dependencyManager.js";const O=P.PROJECT_SOURCE_DIR;async function w(t,e){D(e);try{r(e,"INFO","Start starting development server",{projectId:e,requestId:t.requestId});const i=u.join(O,e),a=u.join(i,"package.json");if(!n.existsSync(a))throw r(e,"WARN","Project missing package.json file",{projectId:e,requestId:t.requestId}),new L("Project missing package.json file",{projectId:e,projectPath:i});let m;try{m=JSON.parse(n.readFileSync(a,"utf8"))}catch(s){throw new y("package.json file format error",{projectId:e,jsonFilePath:a,originalError:s.message})}const p=m.scripts.dev;if(!p)throw r(e,"WARN","Project missing dev script",{projectId:e,requestId:t.requestId}),new x("Project missing dev script, please add dev script in package.json",{projectId:e});try{if(process.platform==="linux"){const c=typeof process.report?.getReport=="function"?process.report.getReport():null,g=c&&c.header&&c.header.glibcVersionRuntime,l=!g,f=u.join(i,"node_modules",".pnpm");if(n.existsSync(f)){const R=await n.promises.readdir(f,{withFileTypes:!0}),S=R.some(o=>o.isDirectory()&&(o.name||"").includes("@rollup+rollup-linux-x64-gnu")),h=R.some(o=>o.isDirectory()&&(o.name||"").includes("@rollup+rollup-linux-x64-musl"));(l&&S||!l&&h)&&(r(e,"WARN","Detected Rollup native package does not match libc, clean dependencies and reinstall",{projectId:e,isMusl:l,glibcVersion:g||null}),await N(i,e))}}}catch(s){r(e,"WARN","Linux native package matching detection failed (ignore continue)",{error:s&&s.message})}try{process.env.ROLLUP_WASM=process.env.ROLLUP_WASM||"1",process.env.ROLLUP_DISABLE_NATIVE=process.env.ROLLUP_DISABLE_NATIVE||"1"}catch{}r(e,"INFO","Start executing dev script in non-blocking mode",{projectId:e,requestId:t.requestId});const{pid:d,port:v}=await _({req:t,projectId:e,projectPath:i,devScript:p});return{success:!0,message:"Development server started",projectId:e,pid:d,port:v}}finally{E(e)}}export{w as startDevServer};
@@ -1,2 +1,2 @@
1
- import{ValidationError as W,ProcessError as q}from"../error/errorHandler.js";import{killProcess as w,getRunningProcess as A,waitForProcessStop as y}from"./processManager.js";import{log as i,getLogDir as O}from"../log/logUtils.js";import c from"../log/logCacheManager.js";import S from"../buildArg/portPool.js";import h from"fs";import P from"path";import{execSync as v}from"child_process";function R(t){try{const o=v("ps -Ao pid,command -ww",{encoding:"utf8"}).split(`
2
- `),f=[],N="/"+String(t);for(const n of o)if(n&&n.includes(N)){const u=n.trim(),a=u.indexOf(" "),s=a>0?u.slice(0,a):u,r=Number(s);Number.isFinite(r)&&f.push(r)}if(f.length===0){for(const n of o)if(n&&n.includes(String(t))){const u=n.trim(),a=u.indexOf(" "),s=a>0?u.slice(0,a):u,r=Number(s);Number.isFinite(r)&&f.push(r)}}return Array.from(new Set(f))}catch{return[]}}async function M(t,e,d,o={}){const{strict:f=!0,waitForStop:N=!1}=o;i(e,"INFO","\u5F00\u59CB\u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668",{projectId:e,pid:d,strict:f,waitForStop:N,requestId:t.requestId});let n=null,u=null;if(d!=null){const s=Number(d);if(Number.isFinite(s))n=s,i(e,"INFO","\u4F7F\u7528\u4F20\u5165\u7684pid\u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668",{projectId:e,pid:n,requestId:t.requestId});else if(i(e,"WARN","\u4F20\u5165\u7684pid\u65E0\u6548",{projectId:e,invalidPid:d,requestId:t.requestId}),f)throw new W("\u8FDB\u7A0BID\u65E0\u6548",{field:"pid",value:d})}if(!n)if(u=A(e),u)n=u.pid,i(e,"INFO","\u4ECE\u8FD0\u884C\u8868\u4E2D\u83B7\u53D6pid\u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668",{projectId:e,pid:n,requestId:t.requestId});else{if(i(e,"INFO","\u672A\u627E\u5230\u9700\u8981\u505C\u6B62\u7684\u5F00\u53D1\u670D\u52A1\u5668\u8FDB\u7A0B",{projectId:e,requestId:t.requestId}),f)throw new q("\u672A\u627E\u5230\u8FD0\u884C\u4E2D\u7684\u5F00\u53D1\u670D\u52A1\u5668\u8FDB\u7A0B",{projectId:e});return S.release(String(e)),i(e,"INFO","\u7AEF\u53E3\u5DF2\u91CA\u653E\uFF08\u8FDB\u7A0B\u672A\u8FD0\u884C\uFF09",{projectId:e,requestId:t.requestId}),{success:!0,message:"\u672A\u627E\u5230\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B",projectId:e,pid:null}}const a=await w(e,n);if(a)i(e,"INFO","\u5F00\u53D1\u670D\u52A1\u5668\u5DF2\u505C\u6B62",{projectId:e,pid:n,requestId:t.requestId});else if(i(e,"WARN","\u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668\u5931\u8D25",{projectId:e,pid:n,requestId:t.requestId}),f)throw new q("\u505C\u6B62\u8FDB\u7A0B\u5931\u8D25",{projectId:e,pid:n});if(N&&a){const{stopped:s,attempts:r}=await y(e,n);if(s)i(e,"INFO","\u8FDB\u7A0B\u5DF2\u786E\u8BA4\u505C\u6B62",{projectId:e,pid:n,attempts:r,requestId:t.requestId});else if(i(e,"WARN","\u8FDB\u7A0B\u505C\u6B62\u8D85\u65F6",{projectId:e,pid:n,attempts:r,requestId:t.requestId}),f)throw new q("\u8FDB\u7A0B\u505C\u6B62\u8D85\u65F6",{projectId:e,pid:n,attempts:r})}try{const s=O(e);if(h.existsSync(s)){const m=h.readdirSync(s).filter(l=>l.startsWith("dev-temp-")&&l.endsWith(".log"));if(m.length>0){let l=0;for(const F of m)try{const g=P.join(s,F);h.unlinkSync(g),l++}catch(g){i(e,"WARN","\u5220\u9664\u4E34\u65F6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25",{projectId:e,tempFile:F,error:g.message,requestId:t.requestId})}i(e,"INFO","\u4E34\u65F6\u65E5\u5FD7\u6587\u4EF6\u6E05\u7406\u5B8C\u6210",{projectId:e,deletedCount:l,totalTempFiles:m.length,requestId:t.requestId})}}}catch(s){i(e,"WARN","\u6E05\u7406\u4E34\u65F6\u65E5\u5FD7\u6587\u4EF6\u65F6\u51FA\u9519",{projectId:e,error:s.message,requestId:t.requestId})}try{c.isEnabled()&&(c.delete(e),i(e,"INFO","\u65E5\u5FD7\u7F13\u5B58\u5DF2\u6E05\u7406",{projectId:e,requestId:t.requestId}))}catch(s){i(e,"WARN","\u6E05\u7406\u65E5\u5FD7\u7F13\u5B58\u65F6\u51FA\u9519",{projectId:e,error:s.message,requestId:t.requestId})}return a&&(S.release(String(e)),i(e,"INFO","\u7AEF\u53E3\u5DF2\u91CA\u653E",{projectId:e,requestId:t.requestId})),{success:!0,message:a?"\u5DF2\u505C\u6B62":"\u505C\u6B62\u5931\u8D25\u4F46\u7EE7\u7EED\u6267\u884C",projectId:e,pid:n}}async function b(t,e,d={}){const{strict:o=!0,waitForStop:f=!1}=d;i(e,"INFO","\u5F00\u59CB\u505C\u6B62\u5F00\u53D1\u670D\u52A1\u5668(\u6309projectId\u5168\u91CF\u505C\u6B62)",{projectId:e,strict:o,waitForStop:f,requestId:t.requestId});const N=R(e),n=N.map(s=>({pid:s}));if(!n||n.length===0)return i(e,"INFO","\u672A\u627E\u5230\u9700\u8981\u505C\u6B62\u7684\u5F00\u53D1\u670D\u52A1\u5668\u8FDB\u7A0B",{projectId:e,requestId:t.requestId}),S.release(String(e)),i(e,"INFO","\u7AEF\u53E3\u5DF2\u91CA\u653E\uFF08\u8FDB\u7A0B\u672A\u8FD0\u884C\uFF09",{projectId:e,requestId:t.requestId}),{success:!0,message:"\u672A\u627E\u5230\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B",projectId:e,pid:null};const u=[];for(const s of N){const r=await w(e,s);if(u.push({pid:s,killed:r}),f&&r){const{stopped:m,attempts:l}=await y(e,s);if(i(e,m?"INFO":"WARN",m?"\u8FDB\u7A0B\u5DF2\u786E\u8BA4\u505C\u6B62":"\u8FDB\u7A0B\u505C\u6B62\u8D85\u65F6",{projectId:e,pid:s,attempts:l,requestId:t.requestId}),!m&&o)throw new q("\u8FDB\u7A0B\u505C\u6B62\u8D85\u65F6",{projectId:e,pid:s,attempts:l})}else if(!r&&o)throw new q("\u505C\u6B62\u8FDB\u7A0B\u5931\u8D25",{projectId:e,pid:s})}try{const s=O(e);if(h.existsSync(s)){const m=h.readdirSync(s).filter(l=>l.startsWith("dev-temp-")&&l.endsWith(".log"));if(m.length>0){let l=0;for(const F of m)try{const g=P.join(s,F);h.unlinkSync(g),l++}catch(g){i(e,"WARN","\u5220\u9664\u4E34\u65F6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25",{projectId:e,tempFile:F,error:g.message,requestId:t.requestId})}i(e,"INFO","\u4E34\u65F6\u65E5\u5FD7\u6587\u4EF6\u6E05\u7406\u5B8C\u6210",{projectId:e,deletedCount:l,totalTempFiles:m.length,requestId:t.requestId})}}}catch(s){i(e,"WARN","\u6E05\u7406\u4E34\u65F6\u65E5\u5FD7\u6587\u4EF6\u65F6\u51FA\u9519",{projectId:e,error:s.message,requestId:t.requestId})}try{c.isEnabled()&&(c.delete(e),i(e,"INFO","\u65E5\u5FD7\u7F13\u5B58\u5DF2\u6E05\u7406",{projectId:e,requestId:t.requestId}))}catch(s){i(e,"WARN","\u6E05\u7406\u65E5\u5FD7\u7F13\u5B58\u65F6\u51FA\u9519",{projectId:e,error:s.message,requestId:t.requestId})}const a=u.every(s=>s.killed===!0);return a&&u.length>0&&(S.release(String(e)),i(e,"INFO","\u7AEF\u53E3\u5DF2\u91CA\u653E",{projectId:e,requestId:t.requestId})),{success:!0,message:a?"\u5DF2\u505C\u6B62":"\u90E8\u5206\u505C\u6B62\u5931\u8D25\u4F46\u7EE7\u7EED\u6267\u884C",projectId:e,pid:null,killedPids:u}}async function k(t,e,d,o={}){return await b(t,e,o)}export{k as stopDevServer};
1
+ import{ValidationError as w,ProcessError as F}from"../error/errorHandler.js";import{killProcess as y,getRunningProcess as O,waitForProcessStop as q}from"./processManager.js";import{log as i,getLogDir as S}from"../log/logUtils.js";import h from"../log/logCacheManager.js";import v from"../buildArg/portPool.js";import p from"fs";import P from"path";import{execSync as W}from"child_process";function b(t){try{const f=W("ps -Ao pid,command -ww",{encoding:"utf8"}).split(`
2
+ `),u=[],c="/"+String(t);for(const n of f)if(n&&n.includes(c)){const r=n.trim(),a=r.indexOf(" "),s=a>0?r.slice(0,a):r,o=Number(s);Number.isFinite(o)&&u.push(o)}if(u.length===0){for(const n of f)if(n&&n.includes(String(t))){const r=n.trim(),a=r.indexOf(" "),s=a>0?r.slice(0,a):r,o=Number(s);Number.isFinite(o)&&u.push(o)}}return Array.from(new Set(u))}catch{return[]}}async function K(t,e,m,f={}){const{strict:u=!0,waitForStop:c=!1}=f;i(e,"INFO","Start stopping development server",{projectId:e,pid:m,strict:u,waitForStop:c,requestId:t.requestId});let n=null,r=null;if(m!=null){const s=Number(m);if(Number.isFinite(s))n=s,i(e,"INFO","Stop development server using incoming pid",{projectId:e,pid:n,requestId:t.requestId});else if(i(e,"WARN","Incoming pid is invalid",{projectId:e,invalidPid:m,requestId:t.requestId}),u)throw new w("Process ID is invalid",{field:"pid",value:m})}if(!n)if(r=O(e),r)n=r.pid,i(e,"INFO","Get pid to stop development server from running table",{projectId:e,pid:n,requestId:t.requestId});else{if(i(e,"INFO","No development server process found to stop",{projectId:e,requestId:t.requestId}),u)throw new F("No running development server process found",{projectId:e});return v.release(String(e)),i(e,"INFO","Port released (process not running)",{projectId:e,requestId:t.requestId}),{success:!0,message:"No running process found",projectId:e,pid:null}}const a=await y(e,n);if(a)i(e,"INFO","Development server stopped",{projectId:e,pid:n,requestId:t.requestId});else if(i(e,"WARN","Failed to stop development server",{projectId:e,pid:n,requestId:t.requestId}),u)throw new F("Failed to stop process",{projectId:e,pid:n});if(c&&a){const{stopped:s,attempts:o}=await q(e,n);if(s)i(e,"INFO","Process confirmed stopped",{projectId:e,pid:n,attempts:o,requestId:t.requestId});else if(i(e,"WARN","Process stop timeout",{projectId:e,pid:n,attempts:o,requestId:t.requestId}),u)throw new F("Process stop timeout",{projectId:e,pid:n,attempts:o})}try{const s=S(e);if(p.existsSync(s)){const d=p.readdirSync(s).filter(l=>l.startsWith("dev-temp-")&&l.endsWith(".log"));if(d.length>0){let l=0;for(const N of d)try{const g=P.join(s,N);p.unlinkSync(g),l++}catch(g){i(e,"WARN","Failed to delete temporary log file",{projectId:e,tempFile:N,error:g.message,requestId:t.requestId})}i(e,"INFO","Temporary log file cleanup completed",{projectId:e,deletedCount:l,totalTempFiles:d.length,requestId:t.requestId})}}}catch(s){i(e,"WARN","Error cleaning temporary log files",{projectId:e,error:s.message,requestId:t.requestId})}try{h.isEnabled()&&(h.delete(e),i(e,"INFO","Log cache cleaned",{projectId:e,requestId:t.requestId}))}catch(s){i(e,"WARN","Error cleaning log cache",{projectId:e,error:s.message,requestId:t.requestId})}return a&&(v.release(String(e)),i(e,"INFO","Port released",{projectId:e,requestId:t.requestId})),{success:!0,message:a?"Stopped":"Failed to stop but continue execution",projectId:e,pid:n}}async function A(t,e,m={}){const{strict:f=!0,waitForStop:u=!1}=m;i(e,"INFO","Start stopping development server(stop all by projectId)",{projectId:e,strict:f,waitForStop:u,requestId:t.requestId});const c=b(e),n=c.map(s=>({pid:s}));if(!n||n.length===0)return i(e,"INFO","No development server process found to stop",{projectId:e,requestId:t.requestId}),v.release(String(e)),i(e,"INFO","Port released (process not running)",{projectId:e,requestId:t.requestId}),{success:!0,message:"No running process found",projectId:e,pid:null};const r=[];for(const s of c){const o=await y(e,s);if(r.push({pid:s,killed:o}),u&&o){const{stopped:d,attempts:l}=await q(e,s);if(i(e,d?"INFO":"WARN",d?"Process confirmed stopped":"Process stop timeout",{projectId:e,pid:s,attempts:l,requestId:t.requestId}),!d&&f)throw new F("Process stop timeout",{projectId:e,pid:s,attempts:l})}else if(!o&&f)throw new F("Failed to stop process",{projectId:e,pid:s})}try{const s=S(e);if(p.existsSync(s)){const d=p.readdirSync(s).filter(l=>l.startsWith("dev-temp-")&&l.endsWith(".log"));if(d.length>0){let l=0;for(const N of d)try{const g=P.join(s,N);p.unlinkSync(g),l++}catch(g){i(e,"WARN","Failed to delete temporary log file",{projectId:e,tempFile:N,error:g.message,requestId:t.requestId})}i(e,"INFO","Temporary log file cleanup completed",{projectId:e,deletedCount:l,totalTempFiles:d.length,requestId:t.requestId})}}}catch(s){i(e,"WARN","Error cleaning temporary log files",{projectId:e,error:s.message,requestId:t.requestId})}try{h.isEnabled()&&(h.delete(e),i(e,"INFO","Log cache cleaned",{projectId:e,requestId:t.requestId}))}catch(s){i(e,"WARN","Error cleaning log cache",{projectId:e,error:s.message,requestId:t.requestId})}const a=r.every(s=>s.killed===!0);return a&&r.length>0&&(v.release(String(e)),i(e,"INFO","Port released",{projectId:e,requestId:t.requestId})),{success:!0,message:a?"Stopped":"Partially stopped but continue execution",projectId:e,pid:null,killedPids:r}}async function R(t,e,m,f={}){return await A(t,e,f)}export{R as stopDevServer};
@@ -1,7 +1,7 @@
1
- import{spawn as N}from"child_process";import d from"fs";import g from"path";import{log as r}from"../log/logUtils.js";async function A(t,e,n=15e3){try{const s=C(e);r(t,"INFO","\u5F00\u59CB\u8BED\u6CD5\u68C0\u67E5",{projectId:t,projectType:s,timeoutMs:n});const o=[];if(s==="typescript"){const i=await D(t,e,n);if(o.push(i),!i.passed)return i}else if(s==="javascript"){const i=await H(t,e,n);if(o.push(i),!i.passed)return i}const c=await v(t,e,n);if(o.push(c),!c.passed)return c;if(o.length===0)return r(t,"INFO","\u8DF3\u8FC7\u8BED\u6CD5\u68C0\u67E5\uFF1A\u672A\u68C0\u6D4B\u5230\u6E90\u4EE3\u7801\u6587\u4EF6",{projectId:t}),{passed:!0,method:"skipped"};const h=o.map(i=>i.method).filter(Boolean).join(", "),f=o.reduce((i,m)=>i+(m.duration||0),0);return r(t,"INFO","\u6240\u6709\u8BED\u6CD5\u68C0\u67E5\u901A\u8FC7",{projectId:t,methods:h,totalDuration:f}),{passed:!0,method:h,duration:f}}catch(s){return r(t,"WARN","\u8BED\u6CD5\u68C0\u67E5\u6267\u884C\u5931\u8D25",{projectId:t,error:s.message}),{passed:!0,method:"error",error:s.message}}}function C(t){const e=g.join(t,"tsconfig.json");return d.existsSync(e)&&E(t,[".ts",".tsx"])?"typescript":E(t,[".js",".jsx"])?"javascript":"unknown"}function E(t,e,n=3){try{let o=function(c,h){if(h>n)return!1;const f=d.readdirSync(c,{withFileTypes:!0});for(const i of f){const m=g.join(c,i.name);if(i.isDirectory()){if(!s.includes(i.name)&&o(m,h+1))return!0}else if(i.isFile()){const a=g.extname(i.name);if(e.includes(a))return!0}}return!1};const s=["node_modules",".git","dist","build",".next",".nuxt"];return o(t,0)}catch{return!1}}async function D(t,e,n){return new Promise(s=>{const o=Date.now(),c=g.join(e,"tsconfig.json"),h=g.join(e,"tsconfig.check.json");let f=!1,i=!1;const m=u=>{const x={include:["src/**/*.ts","src/**/*.tsx","src/**/*.js","src/**/*.jsx","*.ts","*.tsx"],exclude:["node_modules","dist","build",".next",".nuxt","**/*.spec.ts","**/*.test.ts"]};return u?(x.extends="./tsconfig.json",r(t,"INFO","\u68C0\u67E5\u914D\u7F6E\u5C06\u7EE7\u627F\u7528\u6237\u7684 tsconfig.json",{projectId:t})):x.compilerOptions={target:"ESNext",lib:["ESNext","DOM"],jsx:"react-jsx",module:"ESNext",moduleResolution:"bundler",esModuleInterop:!0,allowSyntheticDefaultImports:!0,strict:!1,skipLibCheck:!0,noEmit:!0,allowJs:!0,checkJs:!1},x},a=d.existsSync(c);try{const u=m(a);d.writeFileSync(h,JSON.stringify(u,null,2),"utf8"),f=!0,r(t,"INFO","\u521B\u5EFA\u4E34\u65F6 tsconfig.check.json \u7528\u4E8E\u8BED\u6CD5\u68C0\u67E5",{projectId:t,hasTsconfig:a,extends:u.extends||"\u65E0",include:u.include})}catch(u){if(r(t,"WARN","\u65E0\u6CD5\u521B\u5EFA tsconfig.check.json",{projectId:t,error:u.message}),!a)try{d.writeFileSync(c,JSON.stringify(m(!1),null,2),"utf8"),i=!0,r(t,"INFO","\u521B\u5EFA\u4E34\u65F6 tsconfig.json \u4F5C\u4E3A\u964D\u7EA7\u65B9\u6848",{projectId:t})}catch(x){r(t,"ERROR","\u65E0\u6CD5\u521B\u5EFA\u4EFB\u4F55 TypeScript \u914D\u7F6E\u6587\u4EF6",{projectId:t,error:x.message})}}const l=g.join(e,"node_modules",".bin","tsc"),y=d.existsSync(l),p=y?l:"npx",S=f?"tsconfig.check.json":"tsconfig.json",k=y?["--project",S,"--noEmit","--skipLibCheck"]:["--yes","tsc","--project",S,"--noEmit","--skipLibCheck"];r(t,"INFO","\u8FD0\u884C TypeScript \u7C7B\u578B\u68C0\u67E5",{projectId:t,command:p,args:k.join(" "),usesLocalTsc:y,configFile:S});const F=N(p,k,{cwd:e,shell:!0,timeout:n});let O="",w="";F.stdout?.on("data",u=>{O+=u.toString()}),F.stderr?.on("data",u=>{w+=u.toString()});const T=()=>{if(f)try{d.existsSync(h)&&(d.unlinkSync(h),r(t,"INFO","\u5DF2\u6E05\u7406\u4E34\u65F6 tsconfig.check.json",{projectId:t}))}catch(u){r(t,"WARN","\u6E05\u7406 tsconfig.check.json \u5931\u8D25",{projectId:t,error:u.message})}if(i)try{d.existsSync(c)&&(d.unlinkSync(c),r(t,"INFO","\u5DF2\u6E05\u7406\u4E34\u65F6 tsconfig.json",{projectId:t}))}catch(u){r(t,"WARN","\u6E05\u7406 tsconfig.json \u5931\u8D25",{projectId:t,error:u.message})}};F.on("close",u=>{const x=Date.now()-o;if(T(),u===0)r(t,"INFO","TypeScript \u7C7B\u578B\u68C0\u67E5\u901A\u8FC7",{projectId:t,duration:x}),s({passed:!0,method:"typescript",duration:x});else{const R=w||O,b=q(R);r(t,"ERROR","TypeScript \u7C7B\u578B\u68C0\u67E5\u5931\u8D25",{projectId:t,code:u,duration:x,errorSummary:b}),s({passed:!1,method:"typescript",error:b,fullOutput:R.substring(0,2e3),duration:x})}}),F.on("error",u=>{T(),r(t,"WARN","TypeScript \u68C0\u67E5\u6267\u884C\u5931\u8D25",{projectId:t,error:u.message}),s({passed:!0,method:"typescript-error",error:u.message})}),setTimeout(()=>{try{F.kill(),T(),r(t,"WARN","TypeScript \u68C0\u67E5\u8D85\u65F6",{projectId:t,timeoutMs:n}),s({passed:!0,method:"typescript-timeout"})}catch{T(),s({passed:!0,method:"typescript-timeout-error"})}},n)})}async function H(t,e,n){return new Promise(s=>{const o=Date.now(),c=W(e);if(c.length===0){r(t,"INFO","\u8DF3\u8FC7 JavaScript \u8BED\u6CD5\u68C0\u67E5\uFF1A\u672A\u627E\u5230\u5165\u53E3\u6587\u4EF6",{projectId:t}),s({passed:!0,method:"javascript-skipped"});return}const h=["--yes","esbuild",...c,"--bundle","--write=false","--outdir=/tmp","--format=esm"];r(t,"INFO","\u8FD0\u884C JavaScript \u8BED\u6CD5\u68C0\u67E5",{projectId:t,entryFiles:c});const f=N("npx",h,{cwd:e,shell:!0,timeout:n});let i="",m="";f.stdout?.on("data",a=>{i+=a.toString()}),f.stderr?.on("data",a=>{m+=a.toString()}),f.on("close",a=>{const l=Date.now()-o;if(a===0)r(t,"INFO","JavaScript \u8BED\u6CD5\u68C0\u67E5\u901A\u8FC7",{projectId:t,duration:l}),s({passed:!0,method:"javascript",duration:l});else{const y=m||i,p=y.substring(0,1e3);r(t,"ERROR","JavaScript \u8BED\u6CD5\u68C0\u67E5\u5931\u8D25",{projectId:t,code:a,duration:l,errorSummary:p}),s({passed:!1,method:"javascript",error:p,fullOutput:y.substring(0,2e3),duration:l})}}),f.on("error",a=>{r(t,"WARN","JavaScript \u68C0\u67E5\u6267\u884C\u5931\u8D25",{projectId:t,error:a.message}),s({passed:!0,method:"javascript-error",error:a.message})}),setTimeout(()=>{try{f.kill(),r(t,"WARN","JavaScript \u68C0\u67E5\u8D85\u65F6",{projectId:t,timeoutMs:n}),s({passed:!0,method:"javascript-timeout"})}catch{s({passed:!0,method:"javascript-timeout-error"})}},n)})}function W(t){const e=["src/main.js","src/main.jsx","src/main.ts","src/main.tsx","src/index.js","src/index.jsx","src/index.ts","src/index.tsx","src/app.js","src/app.jsx","src/App.js","src/App.jsx","index.js","index.jsx","index.ts","index.tsx"],n=[];for(const s of e){const o=g.join(t,s);d.existsSync(o)&&n.push(s)}return n}function L(t){const e=g.join(t,".htmlvalidate.json");if(d.existsSync(e))return!1;const n={extends:["html-validate:recommended"],rules:{"void-style":"off","require-sri":"off","no-trailing-whitespace":"off","no-inline-style":"off","no-dup-id":"warn","no-unused-disable":"off"}};try{return d.writeFileSync(e,JSON.stringify(n,null,2),"utf8"),!0}catch{return!1}}async function v(t,e,n){return new Promise(s=>{const o=Date.now(),c=J(e);if(c.length===0){r(t,"INFO","\u8DF3\u8FC7 HTML \u8BED\u6CD5\u68C0\u67E5\uFF1A\u672A\u627E\u5230 HTML \u6587\u4EF6",{projectId:t}),s({passed:!0,method:"html-skipped"});return}L(e)&&r(t,"INFO","\u81EA\u52A8\u521B\u5EFA\u5BBD\u677E\u7684 HTML \u9A8C\u8BC1\u914D\u7F6E",{projectId:t,configPath:".htmlvalidate.json"});const f=["--yes","html-validate",...c,"--formatter=text"];r(t,"INFO","\u8FD0\u884C HTML \u8BED\u6CD5\u68C0\u67E5",{projectId:t,htmlFiles:c,fileCount:c.length});const i=N("npx",f,{cwd:e,shell:!0,timeout:n});let m="",a="";i.stdout?.on("data",l=>{m+=l.toString()}),i.stderr?.on("data",l=>{a+=l.toString()}),i.on("close",l=>{const y=Date.now()-o;if(l===0)r(t,"INFO","HTML \u8BED\u6CD5\u68C0\u67E5\u901A\u8FC7",{projectId:t,duration:y,fileCount:c.length}),s({passed:!0,method:"html",duration:y});else{const p=m||a,S=P(p);r(t,"ERROR","HTML \u8BED\u6CD5\u68C0\u67E5\u5931\u8D25",{projectId:t,code:l,duration:y,errorSummary:S}),s({passed:!1,method:"html",error:S,fullOutput:p.substring(0,2e3),duration:y})}}),i.on("error",l=>{r(t,"WARN","HTML \u68C0\u67E5\u6267\u884C\u5931\u8D25",{projectId:t,error:l.message}),s({passed:!0,method:"html-error",error:l.message})}),setTimeout(()=>{try{i.kill(),r(t,"WARN","HTML \u68C0\u67E5\u8D85\u65F6",{projectId:t,timeoutMs:n}),s({passed:!0,method:"html-timeout"})}catch{s({passed:!0,method:"html-timeout-error"})}},n)})}function J(t){const e=[],n=["index.html","public/index.html","src/index.html","dist/index.html"];for(const s of n){const o=g.join(t,s);d.existsSync(o)&&e.push(s)}if(e.length===0){const s=["public","src","."];for(const o of s){const c=g.join(t,o);if(d.existsSync(c)){const h=_(c,t,2);e.push(...h)}}}return[...new Set(e)]}function _(t,e,n=2){const s=[],o=["node_modules",".git","dist","build",".next",".nuxt"];function c(h,f){if(!(f>n))try{const i=d.readdirSync(h,{withFileTypes:!0});for(const m of i){const a=g.join(h,m.name);if(m.isDirectory())o.includes(m.name)||c(a,f+1);else if(m.isFile()&&m.name.endsWith(".html")){const l=g.relative(e,a);s.push(l)}}}catch{}}return c(t,0),s}function P(t){if(!t)return"\u672A\u77E5\u9519\u8BEF";const e=t.split(`
2
- `),n=[];for(const s of e){const o=s.trim();if((o.includes("error:")||o.includes("\u2716")||/\.html:\d+:\d+/.test(o)||o.includes("Element")||o.includes("Attribute"))&&(n.push(o),n.length>=10))break}return n.length>0?n.join(`
3
- `):e.slice(0,15).join(`
4
- `).trim().substring(0,800)}function q(t){if(!t)return"\u672A\u77E5\u9519\u8BEF";const e=t.split(`
5
- `),n=[];for(const s of e)if((s.includes("error TS")||s.includes("): error"))&&(n.push(s.trim()),n.length>=5))break;return n.length>0?n.join(`
6
- `):e.slice(0,10).join(`
7
- `).trim().substring(0,500)}module.exports={runSyntaxCheck:A,detectProjectType:C,findHtmlFiles:J,ensureHtmlValidateConfig:L};
1
+ import{spawn as T}from"child_process";import d from"fs";import y from"path";import{log as r}from"../log/logUtils.js";async function J(t,s,n=15e3){try{const e=C(s);r(t,"INFO","Start syntax check",{projectId:t,projectType:e,timeoutMs:n});const o=[];if(e==="typescript"){const i=await D(t,s,n);if(o.push(i),!i.passed)return i}else if(e==="javascript"){const i=await H(t,s,n);if(o.push(i),!i.passed)return i}const c=await v(t,s,n);if(o.push(c),!c.passed)return c;if(o.length===0)return r(t,"INFO","Skip syntax check: no source code files detected",{projectId:t}),{passed:!0,method:"skipped"};const m=o.map(i=>i.method).filter(Boolean).join(", "),f=o.reduce((i,h)=>i+(h.duration||0),0);return r(t,"INFO","All syntax checks passed",{projectId:t,methods:m,totalDuration:f}),{passed:!0,method:m,duration:f}}catch(e){return r(t,"WARN","Syntax check execution failed",{projectId:t,error:e.message}),{passed:!0,method:"error",error:e.message}}}function C(t){const s=y.join(t,"tsconfig.json");return d.existsSync(s)&&E(t,[".ts",".tsx"])?"typescript":E(t,[".js",".jsx"])?"javascript":"unknown"}function E(t,s,n=3){try{let o=function(c,m){if(m>n)return!1;const f=d.readdirSync(c,{withFileTypes:!0});for(const i of f){const h=y.join(c,i.name);if(i.isDirectory()){if(!e.includes(i.name)&&o(h,m+1))return!0}else if(i.isFile()){const a=y.extname(i.name);if(s.includes(a))return!0}}return!1};const e=["node_modules",".git","dist","build",".next",".nuxt"];return o(t,0)}catch{return!1}}async function D(t,s,n){return new Promise(e=>{const o=Date.now(),c=y.join(s,"tsconfig.json"),m=y.join(s,"tsconfig.check.json");let f=!1,i=!1;const h=l=>{const x={include:["src/**/*.ts","src/**/*.tsx","src/**/*.js","src/**/*.jsx","*.ts","*.tsx"],exclude:["node_modules","dist","build",".next",".nuxt","**/*.spec.ts","**/*.test.ts"]};return l?(x.extends="./tsconfig.json",r(t,"INFO","Check configuration will inherit user's tsconfig.json",{projectId:t})):x.compilerOptions={target:"ESNext",lib:["ESNext","DOM"],jsx:"react-jsx",module:"ESNext",moduleResolution:"bundler",esModuleInterop:!0,allowSyntheticDefaultImports:!0,strict:!1,skipLibCheck:!0,noEmit:!0,allowJs:!0,checkJs:!1},x},a=d.existsSync(c);try{const l=h(a);d.writeFileSync(m,JSON.stringify(l,null,2),"utf8"),f=!0,r(t,"INFO","Create temporary tsconfig.check.json for syntax check",{projectId:t,hasTsconfig:a,extends:l.extends||"\u65E0",include:l.include})}catch(l){if(r(t,"WARN","Failed to create tsconfig.check.json",{projectId:t,error:l.message}),!a)try{d.writeFileSync(c,JSON.stringify(h(!1),null,2),"utf8"),i=!0,r(t,"INFO","Create temporary tsconfig.json as fallback",{projectId:t})}catch(x){r(t,"ERROR","Failed to create any TypeScript configuration file",{projectId:t,error:x.message})}}const u=y.join(s,"node_modules",".bin","tsc"),g=d.existsSync(u),p=g?u:"npx",k=f?"tsconfig.check.json":"tsconfig.json",N=g?["--project",k,"--noEmit","--skipLibCheck"]:["--yes","tsc","--project",k,"--noEmit","--skipLibCheck"];r(t,"INFO","Run TypeScript type check",{projectId:t,command:p,args:N.join(" "),usesLocalTsc:g,configFile:k});const S=T(p,N,{cwd:s,shell:!0,timeout:n});let O="",w="";S.stdout?.on("data",l=>{O+=l.toString()}),S.stderr?.on("data",l=>{w+=l.toString()});const F=()=>{if(f)try{d.existsSync(m)&&(d.unlinkSync(m),r(t,"INFO","Cleaned temporary tsconfig.check.json",{projectId:t}))}catch(l){r(t,"WARN","Failed to clean tsconfig.check.json",{projectId:t,error:l.message})}if(i)try{d.existsSync(c)&&(d.unlinkSync(c),r(t,"INFO","Cleaned temporary tsconfig.json",{projectId:t}))}catch(l){r(t,"WARN","Failed to clean tsconfig.json",{projectId:t,error:l.message})}};S.on("close",l=>{const x=Date.now()-o;if(F(),l===0)r(t,"INFO","TypeScript type check passed",{projectId:t,duration:x}),e({passed:!0,method:"typescript",duration:x});else{const R=w||O,b=U(R);r(t,"ERROR","TypeScript type check failed",{projectId:t,code:l,duration:x,errorSummary:b}),e({passed:!1,method:"typescript",error:b,fullOutput:R.substring(0,2e3),duration:x})}}),S.on("error",l=>{F(),r(t,"WARN","TypeScript check execution failed",{projectId:t,error:l.message}),e({passed:!0,method:"typescript-error",error:l.message})}),setTimeout(()=>{try{S.kill(),F(),r(t,"WARN","TypeScript check timeout",{projectId:t,timeoutMs:n}),e({passed:!0,method:"typescript-timeout"})}catch{F(),e({passed:!0,method:"typescript-timeout-error"})}},n)})}async function H(t,s,n){return new Promise(e=>{const o=Date.now(),c=W(s);if(c.length===0){r(t,"INFO","Skip JavaScript syntax check: no entry files found",{projectId:t}),e({passed:!0,method:"javascript-skipped"});return}const m=["--yes","esbuild",...c,"--bundle","--write=false","--outdir=/tmp","--format=esm"];r(t,"INFO","Run JavaScript syntax check",{projectId:t,entryFiles:c});const f=T("npx",m,{cwd:s,shell:!0,timeout:n});let i="",h="";f.stdout?.on("data",a=>{i+=a.toString()}),f.stderr?.on("data",a=>{h+=a.toString()}),f.on("close",a=>{const u=Date.now()-o;if(a===0)r(t,"INFO","JavaScript syntax check passed",{projectId:t,duration:u}),e({passed:!0,method:"javascript",duration:u});else{const g=h||i,p=g.substring(0,1e3);r(t,"ERROR","JavaScript syntax check failed",{projectId:t,code:a,duration:u,errorSummary:p}),e({passed:!1,method:"javascript",error:p,fullOutput:g.substring(0,2e3),duration:u})}}),f.on("error",a=>{r(t,"WARN","JavaScript check execution failed",{projectId:t,error:a.message}),e({passed:!0,method:"javascript-error",error:a.message})}),setTimeout(()=>{try{f.kill(),r(t,"WARN","JavaScript check timeout",{projectId:t,timeoutMs:n}),e({passed:!0,method:"javascript-timeout"})}catch{e({passed:!0,method:"javascript-timeout-error"})}},n)})}function W(t){const s=["src/main.js","src/main.jsx","src/main.ts","src/main.tsx","src/index.js","src/index.jsx","src/index.ts","src/index.tsx","src/app.js","src/app.jsx","src/App.js","src/App.jsx","index.js","index.jsx","index.ts","index.tsx"],n=[];for(const e of s){const o=y.join(t,e);d.existsSync(o)&&n.push(e)}return n}function A(t){const s=y.join(t,".htmlvalidate.json");if(d.existsSync(s))return!1;const n={extends:["html-validate:recommended"],rules:{"void-style":"off","require-sri":"off","no-trailing-whitespace":"off","no-inline-style":"off","no-dup-id":"warn","no-unused-disable":"off"}};try{return d.writeFileSync(s,JSON.stringify(n,null,2),"utf8"),!0}catch{return!1}}async function v(t,s,n){return new Promise(e=>{const o=Date.now(),c=L(s);if(c.length===0){r(t,"INFO","Skip HTML syntax check: no HTML files found",{projectId:t}),e({passed:!0,method:"html-skipped"});return}A(s)&&r(t,"INFO","Automatically create\u5BBD\u677E\u7684 HTML \u9A8C\u8BC1\u914D\u7F6E",{projectId:t,configPath:".htmlvalidate.json"});const f=["--yes","html-validate",...c,"--formatter=text"];r(t,"INFO","Run HTML syntax check",{projectId:t,htmlFiles:c,fileCount:c.length});const i=T("npx",f,{cwd:s,shell:!0,timeout:n});let h="",a="";i.stdout?.on("data",u=>{h+=u.toString()}),i.stderr?.on("data",u=>{a+=u.toString()}),i.on("close",u=>{const g=Date.now()-o;if(u===0)r(t,"INFO","HTML syntax check passed",{projectId:t,duration:g,fileCount:c.length}),e({passed:!0,method:"html",duration:g});else{const p=h||a,k=P(p);r(t,"ERROR","HTML syntax check failed",{projectId:t,code:u,duration:g,errorSummary:k}),e({passed:!1,method:"html",error:k,fullOutput:p.substring(0,2e3),duration:g})}}),i.on("error",u=>{r(t,"WARN","HTML check execution failed",{projectId:t,error:u.message}),e({passed:!0,method:"html-error",error:u.message})}),setTimeout(()=>{try{i.kill(),r(t,"WARN","HTML check timeout",{projectId:t,timeoutMs:n}),e({passed:!0,method:"html-timeout"})}catch{e({passed:!0,method:"html-timeout-error"})}},n)})}function L(t){const s=[],n=["index.html","public/index.html","src/index.html","dist/index.html"];for(const e of n){const o=y.join(t,e);d.existsSync(o)&&s.push(e)}if(s.length===0){const e=["public","src","."];for(const o of e){const c=y.join(t,o);if(d.existsSync(c)){const m=_(c,t,2);s.push(...m)}}}return[...new Set(s)]}function _(t,s,n=2){const e=[],o=["node_modules",".git","dist","build",".next",".nuxt"];function c(m,f){if(!(f>n))try{const i=d.readdirSync(m,{withFileTypes:!0});for(const h of i){const a=y.join(m,h.name);if(h.isDirectory())o.includes(h.name)||c(a,f+1);else if(h.isFile()&&h.name.endsWith(".html")){const u=y.relative(s,a);e.push(u)}}}catch{}}return c(t,0),e}function P(t){if(!t)return"Unknown error";const s=t.split(`
2
+ `),n=[];for(const e of s){const o=e.trim();if((o.includes("error:")||o.includes("\u2716")||/\.html:\d+:\d+/.test(o)||o.includes("Element")||o.includes("Attribute"))&&(n.push(o),n.length>=10))break}return n.length>0?n.join(`
3
+ `):s.slice(0,15).join(`
4
+ `).trim().substring(0,800)}function U(t){if(!t)return"Unknown error";const s=t.split(`
5
+ `),n=[];for(const e of s)if((e.includes("error TS")||e.includes("): error"))&&(n.push(e.trim()),n.length>=5))break;return n.length>0?n.join(`
6
+ `):s.slice(0,10).join(`
7
+ `).trim().substring(0,500)}module.exports={runSyntaxCheck:J,detectProjectType:C,findHtmlFiles:L,ensureHtmlValidateConfig:A};
@@ -1 +1 @@
1
- import{buildPortArgsForScript as u}from"./portUtils.js";import{log as d}from"../log/logUtils.js";import"../error/errorHandler.js";import l from"./portPool.js";class p{static async processExtraArgs({devScript:a,projectId:f,req:o}){const s=[],r={},e=(a||"").toLowerCase(),i=e.includes("vite"),n=e.includes("next");if(!i&&!n)return{extraArgs:s,envExtra:r};if(o){let t="";o.body&&o.body.basePath?t=String(o.body.basePath):o.query&&o.query.basePath&&(t=String(o.query.basePath));const h=o.query&&o.query.projectId||o.body&&o.body.projectId||"unknown";t&&d(h,"INFO","\u8BFB\u53D6\u5230 basePath",{basePath:t,source:o.body&&o.body.basePath?"body":"query"}),t&&t.trim()&&(t=t.trim(),t.startsWith("/")||(t="/"+t),t.endsWith("/")||(t=t+"/"),i?s.push("--base",t):n&&(r.NEXT_PUBLIC_BASE_PATH=t,r.BASE_PATH=t))}const c=l.allocate(String(f)),b=u(a,c);return b.length>0&&s.push(...b),i&&s.push("--host","0.0.0.0"),{extraArgs:s,envExtra:r,port:c}}}export default p;
1
+ import{buildPortArgsForScript as h}from"./portUtils.js";import{log as u}from"../log/logUtils.js";import"../error/errorHandler.js";import l from"./portPool.js";class p{static async processExtraArgs({devScript:a,projectId:d,req:o}){const s=[],r={},e=(a||"").toLowerCase(),i=e.includes("vite"),n=e.includes("next");if(!i&&!n)return{extraArgs:s,envExtra:r};if(o){let t="";o.body&&o.body.basePath?t=String(o.body.basePath):o.query&&o.query.basePath&&(t=String(o.query.basePath));const f=o.query&&o.query.projectId||o.body&&o.body.projectId||"unknown";t&&u(f,"INFO","Read basePath",{basePath:t,source:o.body&&o.body.basePath?"body":"query"}),t&&t.trim()&&(t=t.trim(),t.startsWith("/")||(t="/"+t),t.endsWith("/")||(t=t+"/"),i?s.push("--base",t):n&&(r.NEXT_PUBLIC_BASE_PATH=t,r.BASE_PATH=t))}const c=l.allocate(String(d)),b=h(a,c);return b.length>0&&s.push(...b),i&&s.push("--host","0.0.0.0"),{extraArgs:s,envExtra:r,port:c}}}export default p;
@@ -1 +1 @@
1
- import{log as e}from"../log/logUtils.js";class o{constructor(){this.portRangeStart=4e3,this.portRangeEnd=55e3,this.reservedRangeStart=8e3,this.reservedRangeEnd=9e3,this.availablePorts=new Set,this.allocatedPorts=new Map,this._initializePortPool()}_initializePortPool(){for(let a=this.portRangeStart;a<=this.portRangeEnd;a++)a>=this.reservedRangeStart&&a<=this.reservedRangeEnd||this.availablePorts.add(a);const t=this.reservedRangeEnd-this.reservedRangeStart+1;e("SYSTEM","INFO","\u7AEF\u53E3\u6C60\u521D\u59CB\u5316\u5B8C\u6210",{portRange:`${this.portRangeStart}-${this.portRangeEnd}`,totalPorts:this.availablePorts.size,reservedCount:t})}allocate(t){if(this.allocatedPorts.has(t)){const s=this.allocatedPorts.get(t);return e(t,"INFO","\u9879\u76EE\u5DF2\u6709\u5206\u914D\u7AEF\u53E3\uFF0C\u590D\u7528",{port:s}),s}if(this.availablePorts.size===0)throw new Error(`\u7AEF\u53E3\u6C60\u8017\u5C3D\uFF1A\u8303\u56F4 ${this.portRangeStart}-${this.portRangeEnd} \u5185\u65E0\u53EF\u7528\u7AEF\u53E3`);const a=this.availablePorts.values().next().value;return this.availablePorts.delete(a),this.allocatedPorts.set(t,a),e(t,"INFO","\u7AEF\u53E3\u6C60\u5206\u914D\u7AEF\u53E3",{port:a,totalAllocated:this.allocatedPorts.size,remainingAvailable:this.availablePorts.size}),a}release(t){const a=this.allocatedPorts.get(t);a&&(this.allocatedPorts.delete(t),this.availablePorts.add(a),e(t,"INFO","\u7AEF\u53E3\u6C60\u91CA\u653E\u7AEF\u53E3",{port:a,totalAllocated:this.allocatedPorts.size,remainingAvailable:this.availablePorts.size}))}getPort(t){return this.allocatedPorts.get(t)||null}getStatus(){return{portRange:`${this.portRangeStart}-${this.portRangeEnd}`,totalAllocated:this.allocatedPorts.size,allocations:Array.from(this.allocatedPorts.entries()).map(([t,a])=>({projectId:t,port:a}))}}clear(){for(const t of this.allocatedPorts.values())this.availablePorts.add(t);this.allocatedPorts.clear(),e("SYSTEM","INFO","\u7AEF\u53E3\u6C60\u5DF2\u6E05\u7A7A\u5E76\u91CD\u7F6E",{availablePorts:this.availablePorts.size,allocatedPorts:this.allocatedPorts.size})}}const r=new o;export default r;
1
+ import{log as e}from"../log/logUtils.js";class r{constructor(){this.portRangeStart=4e3,this.portRangeEnd=55e3,this.reservedRangeStart=8e3,this.reservedRangeEnd=9e3,this.availablePorts=new Set,this.allocatedPorts=new Map,this._initializePortPool()}_initializePortPool(){for(let a=this.portRangeStart;a<=this.portRangeEnd;a++)a>=this.reservedRangeStart&&a<=this.reservedRangeEnd||this.availablePorts.add(a);const t=this.reservedRangeEnd-this.reservedRangeStart+1;e("SYSTEM","INFO","Port pool initialized",{portRange:`${this.portRangeStart}-${this.portRangeEnd}`,totalPorts:this.availablePorts.size,reservedCount:t})}allocate(t){if(this.allocatedPorts.has(t)){const o=this.allocatedPorts.get(t);return e(t,"INFO","Project already has allocated port, reuse",{port:o}),o}if(this.availablePorts.size===0)throw new Error(`Port pool exhausted: no available ports in range ${this.portRangeStart}-${this.portRangeEnd}`);const a=this.availablePorts.values().next().value;return this.availablePorts.delete(a),this.allocatedPorts.set(t,a),e(t,"INFO","Port pool allocated port",{port:a,totalAllocated:this.allocatedPorts.size,remainingAvailable:this.availablePorts.size}),a}release(t){const a=this.allocatedPorts.get(t);a&&(this.allocatedPorts.delete(t),this.availablePorts.add(a),e(t,"INFO","Port pool released port",{port:a,totalAllocated:this.allocatedPorts.size,remainingAvailable:this.availablePorts.size}))}getPort(t){return this.allocatedPorts.get(t)||null}getStatus(){return{portRange:`${this.portRangeStart}-${this.portRangeEnd}`,totalAllocated:this.allocatedPorts.size,allocations:Array.from(this.allocatedPorts.entries()).map(([t,a])=>({projectId:t,port:a}))}}clear(){for(const t of this.allocatedPorts.values())this.availablePorts.add(t);this.allocatedPorts.clear(),e("SYSTEM","INFO","Port pool cleared and reset",{availablePorts:this.availablePorts.size,allocatedPorts:this.allocatedPorts.size})}}const s=new r;export default s;