nuwax-file-server 1.2.3 → 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 t from"fs";import m from"path";import A from"archiver";import C from"yauzl";import d from"../../appConfig/index.js";import{log as S}from"../log/logUtils.js";import{FileError as g}from"../error/errorHandler.js";import{sanitizeSensitivePaths as _}from"../common/sensitiveUtils.js";async function T(e,r){const n=new Set(d.TRAVERSE_EXCLUDE_DIRS||[]),u=new Set(d.BACKUP_TRAVERSE_EXCLUDE_FILES||[]),c=await t.promises.readdir(e,{withFileTypes:!0});for(const o of c){const f=m.join(e,o.name),i=m.join(r,o.name);if(o.isDirectory()){if(n.has(o.name))continue;await t.promises.mkdir(i,{recursive:!0}),await T(f,i)}else if(o.isFile()){if(u.has(o.name))continue;await t.promises.mkdir(m.dirname(i),{recursive:!0}),await t.promises.copyFile(f,i)}}}async function L(e,r,n){const u=Date.now(),c=m.join(d.UPLOAD_PROJECT_DIR,e);t.existsSync(c)||t.mkdirSync(c,{recursive:!0});const o=m.join(c,`backup_temp_${Date.now()}`);await t.promises.mkdir(o,{recursive:!0});try{return S(e,"DEBUG","\u5F00\u59CB\u590D\u5236\u9879\u76EE\u6587\u4EF6\u5230\u4E34\u65F6\u76EE\u5F55",{projectPath:r,tempDir:o}),await T(r,o),S(e,"DEBUG","\u9879\u76EE\u6587\u4EF6\u590D\u5236\u5B8C\u6210\uFF0C\u5F00\u59CB\u538B\u7F29",{tempDir:o,outZipPath:n}),await t.promises.mkdir(m.dirname(n),{recursive:!0}),await new Promise((f,i)=>{const a=t.createWriteStream(n),l=A("zip",{zlib:{level:9}});a.on("close",()=>f()),a.on("error",s=>i(new g("\u5907\u4EFDzip\u538B\u7F29\u5931\u8D25",{projectId:e,projectPath:r,outZipPath:n,originalError:s&&s.message}))),l.on("warning",s=>{s&&s.code==="ENOENT"?S(e,"WARN",`\u538B\u7F29\u544A\u8B66: ${s.message}`,{projectId:e,outZipPath:n}):s&&i(new g("\u5907\u4EFDzip\u538B\u7F29\u5931\u8D25",{projectId:e,projectPath:r,outZipPath:n,originalError:s&&s.message}))}),l.on("error",s=>i(new g("\u5907\u4EFDzip\u538B\u7F29\u5931\u8D25",{projectId:e,projectPath:r,outZipPath:n,originalError:s&&s.message}))),l.pipe(a),l.directory(o+"/",!1),l.finalize()}),S(e,"INFO",`\u9879\u76EE\u5DF2\u5907\u4EFD: ${n}`,{projectId:e,outZipPath:n,elapsedMs:Date.now()-u}),n}finally{try{await t.promises.rm(o,{recursive:!0,force:!0})}catch{}}}async function x(e,r,n){const u=Date.now(),c=new Set(d.TRAVERSE_EXCLUDE_DIRS||[]),o=new Set(d.BACKUP_TRAVERSE_EXCLUDE_FILES||[]);S(e,"DEBUG","\u5F00\u59CB\u6E05\u7A7A\u9879\u76EE\u76EE\u5F55\uFF08\u4FDD\u7559\u6392\u9664\u9879\uFF09",{projectPath:r});const f=await t.promises.readdir(r,{withFileTypes:!0});for(const i of f){const a=m.join(r,i.name);if(!(i.isDirectory()&&c.has(i.name))&&!(i.isFile()&&o.has(i.name)))try{await t.promises.rm(a,{recursive:!0,force:!0})}catch{}}S(e,"DEBUG","\u5F00\u59CB\u4ECE zip \u6062\u590D\u9879\u76EE\u6587\u4EF6",{zipPath:n,projectPath:r}),await new Promise((i,a)=>{C.open(n,{lazyEntries:!0},(l,s)=>{if(l||!s)return a(new g("\u56DE\u6EDA\u89E3\u538B\u5931\u8D25",{projectId:e,projectPath:r,zipPath:n,originalError:l&&l.message}));const R=m.resolve(r);s.readEntry(),s.on("entry",w=>{const U=m.normalize(w.fileName).replace(/^([/\\]+)+/,""),k=m.join(r,U),v=m.resolve(k);if(!v.startsWith(R+m.sep)&&v!==R){s.readEntry();return}if(/\\$|\/$/.test(w.fileName)||w.fileName.endsWith("/")){t.promises.mkdir(v,{recursive:!0}).then(()=>s.readEntry()).catch(E=>{s.close(),a(new g("\u56DE\u6EDA\u89E3\u538B\u5931\u8D25",{projectId:e,projectPath:r,zipPath:n,originalError:E&&E.message?_(E.message):E&&E.message}))});return}s.openReadStream(w,(E,N)=>{if(E||!N)return s.close(),a(new g("\u56DE\u6EDA\u89E3\u538B\u5931\u8D25",{projectId:e,projectPath:r,zipPath:n,originalError:E&&E.message}));t.promises.mkdir(m.dirname(v),{recursive:!0}).then(()=>{const y=t.createWriteStream(v);N.pipe(y),y.on("close",()=>s.readEntry()),y.on("error",D=>{s.close(),a(new g("\u56DE\u6EDA\u89E3\u538B\u5931\u8D25",{projectId:e,projectPath:r,zipPath:n,originalError:D&&D.message?_(D.message):D&&D.message}))})}).catch(y=>{s.close(),a(new g("\u56DE\u6EDA\u89E3\u538B\u5931\u8D25",{projectId:e,projectPath:r,zipPath:n,originalError:y&&y.message?_(y.message):y&&y.message}))})})}),s.on("end",()=>{s.close(),i()}),s.on("error",w=>{s.close(),a(new g("\u56DE\u6EDA\u89E3\u538B\u5931\u8D25",{projectId:e,projectPath:r,zipPath:n,originalError:w&&w.message?_(w.message):w&&w.message}))})})}),S(e,"INFO",`\u9879\u76EE\u5DF2\u4ECE\u5907\u4EFD\u6062\u590D: ${n}`,{projectId:e,projectPath:r,zipPath:n,elapsedMs:Date.now()-u})}async function B(e,r,n){const u=new Set(n||[]),c=new Set((d.CONTENT_TRAVERSE_EXCLUDE_FILES||[]).map(f=>String(f).trim()));async function o(f){const i=await t.promises.readdir(f,{withFileTypes:!0});for(const a of i){const l=m.join(f,a.name),s=m.relative(e,l);if(a.isDirectory()){if(u.has(a.name))continue;await o(l)}else if(a.isFile()){if(a.name.startsWith(".")||c.has(a.name))continue;if(!r.has(s))try{await t.promises.unlink(l)}catch{}}}}await o(e)}async function O(e,r){const n=new Set(r||[]);async function u(c){const o=await t.promises.readdir(c,{withFileTypes:!0});for(const i of o){const a=m.join(c,i.name);if(i.isDirectory()){if(n.has(i.name))continue;await u(a)}}if((await t.promises.readdir(c)).length===0&&m.resolve(c)!==m.resolve(e))try{await t.promises.rmdir(c)}catch{}}await u(e)}export{T as copyDirectoryFiltered,L as backupProjectToZip,x as restoreProjectFromZip,B as pruneMissingFiles,O as removeEmptyDirectories};
1
+ import t from"fs";import m from"path";import U from"archiver";import A from"yauzl";import S from"../../appConfig/index.js";import{log as d}from"../log/logUtils.js";import{FileError as y}from"../error/errorHandler.js";import{sanitizeSensitivePaths as D}from"../common/sensitiveUtils.js";async function _(e,r){const i=new Set(S.TRAVERSE_EXCLUDE_DIRS||[]),u=new Set(S.BACKUP_TRAVERSE_EXCLUDE_FILES||[]),c=await t.promises.readdir(e,{withFileTypes:!0});for(const a of c){const f=m.join(e,a.name),n=m.join(r,a.name);if(a.isDirectory()){if(i.has(a.name))continue;await t.promises.mkdir(n,{recursive:!0}),await _(f,n)}else if(a.isFile()){if(u.has(a.name))continue;await t.promises.mkdir(m.dirname(n),{recursive:!0}),await t.promises.copyFile(f,n)}}}async function B(e,r,i){const u=Date.now(),c=m.join(S.UPLOAD_PROJECT_DIR,e);t.existsSync(c)||t.mkdirSync(c,{recursive:!0});const a=m.join(c,`backup_temp_${Date.now()}`);await t.promises.mkdir(a,{recursive:!0});try{return d(e,"DEBUG","Start copying project files to temporary directory",{projectPath:r,tempDir:a}),await _(r,a),d(e,"DEBUG","Project files copied, start compressing",{tempDir:a,outZipPath:i}),await t.promises.mkdir(m.dirname(i),{recursive:!0}),await new Promise((f,n)=>{const o=t.createWriteStream(i),l=U("zip",{zlib:{level:9}});o.on("close",()=>f()),o.on("error",s=>n(new y("Backup zip compression failed",{projectId:e,projectPath:r,outZipPath:i,originalError:s&&s.message}))),l.on("warning",s=>{s&&s.code==="ENOENT"?d(e,"WARN",`Compression warning: ${s.message}`,{projectId:e,outZipPath:i}):s&&n(new y("Backup zip compression failed",{projectId:e,projectPath:r,outZipPath:i,originalError:s&&s.message}))}),l.on("error",s=>n(new y("Backup zip compression failed",{projectId:e,projectPath:r,outZipPath:i,originalError:s&&s.message}))),l.pipe(o),l.directory(a+"/",!1),l.finalize()}),d(e,"INFO",`Project backup completed: ${i}`,{projectId:e,outZipPath:i,elapsedMs:Date.now()-u}),i}finally{try{await t.promises.rm(a,{recursive:!0,force:!0})}catch{}}}async function C(e,r,i){const u=Date.now(),c=new Set(S.TRAVERSE_EXCLUDE_DIRS||[]),a=new Set(S.BACKUP_TRAVERSE_EXCLUDE_FILES||[]);d(e,"DEBUG","Start clearing project directory (keep excluded items)",{projectPath:r});const f=await t.promises.readdir(r,{withFileTypes:!0});for(const n of f){const o=m.join(r,n.name);if(!(n.isDirectory()&&c.has(n.name))&&!(n.isFile()&&a.has(n.name)))try{await t.promises.rm(o,{recursive:!0,force:!0})}catch{}}d(e,"DEBUG","Start restoring project files from zip",{zipPath:i,projectPath:r}),await new Promise((n,o)=>{A.open(i,{lazyEntries:!0},(l,s)=>{if(l||!s)return o(new y("Rollback unzip failed",{projectId:e,projectPath:r,zipPath:i,originalError:l&&l.message}));const R=m.resolve(r);s.readEntry(),s.on("entry",w=>{const p=m.normalize(w.fileName).replace(/^([/\\]+)+/,""),N=m.join(r,p),k=m.resolve(N);if(!k.startsWith(R+m.sep)&&k!==R){s.readEntry();return}if(/\\$|\/$/.test(w.fileName)||w.fileName.endsWith("/")){t.promises.mkdir(k,{recursive:!0}).then(()=>s.readEntry()).catch(E=>{s.close(),o(new y("Rollback unzip failed",{projectId:e,projectPath:r,zipPath:i,originalError:E&&E.message?D(E.message):E&&E.message}))});return}s.openReadStream(w,(E,T)=>{if(E||!T)return s.close(),o(new y("Rollback unzip failed",{projectId:e,projectPath:r,zipPath:i,originalError:E&&E.message}));t.promises.mkdir(m.dirname(k),{recursive:!0}).then(()=>{const g=t.createWriteStream(k);T.pipe(g),g.on("close",()=>s.readEntry()),g.on("error",v=>{s.close(),o(new y("Rollback unzip failed",{projectId:e,projectPath:r,zipPath:i,originalError:v&&v.message?D(v.message):v&&v.message}))})}).catch(g=>{s.close(),o(new y("Rollback unzip failed",{projectId:e,projectPath:r,zipPath:i,originalError:g&&g.message?D(g.message):g&&g.message}))})})}),s.on("end",()=>{s.close(),n()}),s.on("error",w=>{s.close(),o(new y("Rollback unzip failed",{projectId:e,projectPath:r,zipPath:i,originalError:w&&w.message?D(w.message):w&&w.message}))})})}),d(e,"INFO",`Project restored from backup: ${i}`,{projectId:e,projectPath:r,zipPath:i,elapsedMs:Date.now()-u})}async function b(e,r,i){const u=new Set(i||[]),c=new Set((S.CONTENT_TRAVERSE_EXCLUDE_FILES||[]).map(f=>String(f).trim()));async function a(f){const n=await t.promises.readdir(f,{withFileTypes:!0});for(const o of n){const l=m.join(f,o.name),s=m.relative(e,l);if(o.isDirectory()){if(u.has(o.name))continue;await a(l)}else if(o.isFile()){if(o.name.startsWith(".")||c.has(o.name))continue;if(!r.has(s))try{await t.promises.unlink(l)}catch{}}}}await a(e)}async function x(e,r){const i=new Set(r||[]);async function u(c){const a=await t.promises.readdir(c,{withFileTypes:!0});for(const n of a){const o=m.join(c,n.name);if(n.isDirectory()){if(i.has(n.name))continue;await u(o)}}if((await t.promises.readdir(c)).length===0&&m.resolve(c)!==m.resolve(e))try{await t.promises.rmdir(c)}catch{}}await u(e)}export{_ as copyDirectoryFiltered,B as backupProjectToZip,C as restoreProjectFromZip,b as pruneMissingFiles,x as removeEmptyDirectories};
@@ -1 +1 @@
1
- import n from"fs";import a from"path";import $ from"../../appConfig/index.js";import{log as f}from"../log/logUtils.js";import{copyDirectoryFiltered as E}from"./backupUtils.js";import{ValidationError as h,BusinessError as l,SystemError as u}from"../error/errorHandler.js";import{createPnpmNpmrc as O}from"../common/npmrcUtils.js";async function R(s,i){if(!s)throw new h("\u6E90\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"sourceProjectId"});if(!i)throw new h("\u76EE\u6807\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"targetProjectId"});const w=$.PROJECT_SOURCE_DIR,p=a.join(w,s),r=a.join(w,i);if(!n.existsSync(p))throw new l(`\u6E90\u9879\u76EE ${s} \u4E0D\u5B58\u5728`,{sourceProjectId:s,sourceProjectPath:p});if(n.existsSync(r))throw new l(`\u76EE\u6807\u9879\u76EE ${i} \u5DF2\u5B58\u5728`,{targetProjectId:i,targetProjectPath:r});try{f(i,"INFO",`\u5F00\u59CB\u590D\u5236\u9879\u76EE\u4ECE ${s} \u5230 ${i}`,{sourceProjectId:s,targetProjectId:i}),n.mkdirSync(r,{recursive:!0}),f(i,"INFO",`\u76EE\u6807\u9879\u76EE\u76EE\u5F55\u521B\u5EFA\u6210\u529F: ${r}`,{targetProjectId:i});const m=await n.promises.readdir(p,{withFileTypes:!0});for(const o of m){const y=a.join(p,o.name),e=a.join(r,o.name);o.isDirectory()?(await n.promises.mkdir(e,{recursive:!0}),await E(y,e)):o.isFile()&&(await n.promises.mkdir(a.dirname(e),{recursive:!0}),await n.promises.copyFile(y,e))}return f(i,"INFO",`\u9879\u76EE\u590D\u5236\u6210\u529F: ${i}`,{sourceProjectId:s,targetProjectId:i}),await O(r,i),{success:!0,message:`\u9879\u76EE ${s} \u5DF2\u6210\u529F\u590D\u5236\u5230 ${i}`,sourceProjectId:s,targetProjectId:i,targetProjectPath:r}}catch(m){if(f(i,"ERROR",`\u590D\u5236\u9879\u76EE\u5931\u8D25: ${m.message}`,{sourceProjectId:s,targetProjectId:i}),n.existsSync(r))try{await n.promises.rm(r,{recursive:!0,force:!0}),f(i,"INFO","\u590D\u5236\u5931\u8D25\uFF0C\u76EE\u6807\u9879\u76EE\u76EE\u5F55\u5DF2\u6E05\u7406",{targetProjectId:i})}catch(o){f(i,"ERROR",`\u6E05\u7406\u76EE\u6807\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${o.message}`,{targetProjectId:i,originalError:o.message})}throw m.isOperational?m:new u(`\u590D\u5236\u9879\u76EE\u5931\u8D25: ${m.message}`,{sourceProjectId:s,targetProjectId:i,sourceProjectPath:p,targetProjectPath:r,originalError:m.message})}}export{R as copyProject};
1
+ import s from"fs";import m from"path";import w from"../../appConfig/index.js";import{log as p}from"../log/logUtils.js";import{copyDirectoryFiltered as u}from"./backupUtils.js";import{ValidationError as y,BusinessError as l,SystemError as h}from"../error/errorHandler.js";import{createPnpmNpmrc as $}from"../common/npmrcUtils.js";async function E(r,i){if(!r)throw new y("Source project ID cannot be empty",{field:"sourceProjectId"});if(!i)throw new y("Target project ID cannot be empty",{field:"targetProjectId"});const f=w.PROJECT_SOURCE_DIR,a=m.join(f,r),e=m.join(f,i);if(!s.existsSync(a))throw new l(`Source project ${r} does not exist`,{sourceProjectId:r,sourceProjectPath:a});if(s.existsSync(e))throw new l(`Target project ${i} already exists`,{targetProjectId:i,targetProjectPath:e});try{p(i,"INFO",`Start copying project from ${r} to ${i}`,{sourceProjectId:r,targetProjectId:i}),s.mkdirSync(e,{recursive:!0}),p(i,"INFO",`Target project directory created successfully: ${e}`,{targetProjectId:i});const o=await s.promises.readdir(a,{withFileTypes:!0});for(const n of o){const t=m.join(a,n.name),c=m.join(e,n.name);n.isDirectory()?(await s.promises.mkdir(c,{recursive:!0}),await u(t,c)):n.isFile()&&(await s.promises.mkdir(m.dirname(c),{recursive:!0}),await s.promises.copyFile(t,c))}return p(i,"INFO",`Project copied successfully: ${i}`,{sourceProjectId:r,targetProjectId:i}),await $(e,i),{success:!0,message:`Project ${r} successfully copied to ${i}`,sourceProjectId:r,targetProjectId:i,targetProjectPath:e}}catch(o){if(p(i,"ERROR",`Copy project failed: ${o.message}`,{sourceProjectId:r,targetProjectId:i}),s.existsSync(e))try{await s.promises.rm(e,{recursive:!0,force:!0}),p(i,"INFO","Copy failed, target project directory cleaned",{targetProjectId:i})}catch(n){p(i,"ERROR",`Clean target project directory failed: ${n.message}`,{targetProjectId:i,originalError:n.message})}throw o.isOperational?o:new h(`Copy project failed: ${o.message}`,{sourceProjectId:r,targetProjectId:i,sourceProjectPath:a,targetProjectPath:e,originalError:o.message})}}export{E as copyProject};
@@ -1 +1 @@
1
- import o from"fs";import i from"path";import{log as s}from"../log/logUtils.js";function f(n){try{const e=i.join(n,"package.json");if(o.existsSync(e)){const r=JSON.parse(o.readFileSync(e,"utf-8")),t={...r.dependencies,...r.devDependencies};if(t.react||t["react-dom"])return"react";if(t.vue||t["vue-router"]||t["@vue/cli-service"])return"vue"}return"other"}catch(e){return s(null,"WARN",`\u68C0\u6D4B\u524D\u7AEF\u6846\u67B6\u5931\u8D25: ${e.message}`,{projectPath:n,error:e.message}),"other"}}function a(n){try{const e=["next.config.js","next.config.ts","next.config.mjs","next.config.cjs"];for(const t of e){const c=i.join(n,t);if(o.existsSync(c))return"nextjs"}const r=["vite.config.js","vite.config.ts","vite.config.mjs","vite.config.cjs"];for(const t of r){const c=i.join(n,t);if(o.existsSync(c))return"vite"}return"other"}catch(e){return s(null,"WARN",`\u68C0\u6D4B\u5F00\u53D1\u6846\u67B6\u5931\u8D25: ${e.message}`,{projectPath:n,error:e.message}),"other"}}function g(n){const e=f(n),r=a(n);return{frontendFramework:e,devFramework:r}}export{f as detectFrontendFramework,a as detectDevFramework,g as getFrameworkInfo};
1
+ import o from"fs";import i from"path";import{log as s}from"../log/logUtils.js";function f(n){try{const e=i.join(n,"package.json");if(o.existsSync(e)){const r=JSON.parse(o.readFileSync(e,"utf-8")),t={...r.dependencies,...r.devDependencies};if(t.react||t["react-dom"])return"react";if(t.vue||t["vue-router"]||t["@vue/cli-service"])return"vue"}return"other"}catch(e){return s(null,"WARN",`Detect frontend framework failed: ${e.message}`,{projectPath:n,error:e.message}),"other"}}function a(n){try{const e=["next.config.js","next.config.ts","next.config.mjs","next.config.cjs"];for(const t of e){const c=i.join(n,t);if(o.existsSync(c))return"nextjs"}const r=["vite.config.js","vite.config.ts","vite.config.mjs","vite.config.cjs"];for(const t of r){const c=i.join(n,t);if(o.existsSync(c))return"vite"}return"other"}catch(e){return s(null,"WARN",`Detect development framework failed: ${e.message}`,{projectPath:n,error:e.message}),"other"}}function g(n){const e=f(n),r=a(n);return{frontendFramework:e,devFramework:r}}export{f as detectFrontendFramework,a as detectDevFramework,g as getFrameworkInfo};
@@ -1 +1 @@
1
- import u from"fs";import m from"path";import g from"../../appConfig/index.js";import{log as c}from"../log/logUtils.js";import{ValidationError as $,SystemError as h,ResourceError as x}from"../error/errorHandler.js";import{extractZip as N}from"../common/zipUtils.js";import{getFrameworkInfo as O}from"./frameworkDetectorUtils.js";async function _(e){try{const o=u.readFileSync(e);if(o.includes(0))return!0;const f=o.toString("utf-8");for(let l=0;l<f.length;l++){const n=f.charCodeAt(l);if(n<32&&n!==9&&n!==10&&n!==13)return!0}return!1}catch{return!1}}function C(e){const o=m.extname(e).toLowerCase();return[".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg"].includes(o)}async function D(e,o,f,l){const n=[],i=await u.promises.readdir(e,{withFileTypes:!0});i.sort((s,r)=>s.isDirectory()&&!r.isDirectory()?-1:!s.isDirectory()&&r.isDirectory()?1:s.name.toLowerCase().localeCompare(r.name.toLowerCase()));for(const s of i){const r=m.join(e,s.name);if(!(s.name.startsWith(".")||(g.CONTENT_TRAVERSE_EXCLUDE_FILES||[]).includes(s.name))&&!(s.isDirectory()&&g.TRAVERSE_EXCLUDE_DIRS.includes(s.name)))if(s.isDirectory()){const a=await D(r,o,f,l);n.push(...a)}else try{const a=await u.promises.stat(r),w=o||m.join(g.PROJECT_SOURCE_DIR,f),E=m.relative(w,r),F=await _(r),R=`${l}/${E}`,y={name:E,binary:F,sizeExceeded:a.size>g.MAX_INLINE_FILE_SIZE_BYTES,contents:"",fileProxyUrl:R};if(!y.sizeExceeded)if(y.binary){if(C(r)){const S=u.readFileSync(r);y.contents=S.toString("base64")}}else y.contents=u.readFileSync(r,"utf-8");n.push(y)}catch(a){c(f,"WARN",`\u5904\u7406\u6587\u4EF6\u5931\u8D25: ${r} - ${a.message}`,{filePath:r,error:a.message})}}return n}async function U(e,o,f){const l=Date.now(),n=m.basename(e);try{c(n,"INFO","\u5F00\u59CB\u83B7\u53D6\u9879\u76EE\u5185\u5BB9",{projectPath:e,command:o}),c(n,"DEBUG","\u5F00\u59CB\u904D\u5386\u9879\u76EE\u76EE\u5F55",{projectPath:e});const i=await D(e,null,n,f);c(n,"DEBUG","\u9879\u76EE\u76EE\u5F55\u904D\u5386\u5B8C\u6210",{projectPath:e,fileCount:i.length});let s=i;o!=="cpage_config"&&(s=i.filter(a=>a.name!=="cpage_config.json")),c(n,"DEBUG","\u5F00\u59CB\u68C0\u6D4B\u6846\u67B6\u4FE1\u606F",{projectPath:e});const r=O(e),t={files:s,...r};return c(n,"INFO",`\u9879\u76EE\u5185\u5BB9\u83B7\u53D6\u5B8C\u6210\uFF0C\u5171${s.length}\u4E2A\u6587\u4EF6`,{projectPath:e,fileCount:s.length,command:o,elapsedMs:Date.now()-l}),t}catch(i){throw c(n,"ERROR",`\u83B7\u53D6\u9879\u76EE\u5185\u5BB9\u5931\u8D25: ${i.message}`,{projectPath:e,originalError:i.message,elapsedMs:Date.now()-l}),new h(`\u83B7\u53D6\u9879\u76EE\u5185\u5BB9\u5931\u8D25: ${i.message}`,{projectPath:e,originalError:i.message})}}async function T(e,o,f,l){const n=Date.now(),i=Number(o);if(!Number.isFinite(i))throw new $("\u4EE3\u7801\u7248\u672C\u5FC5\u987B\u662F\u6570\u5B57",{field:"codeVersion"});const s=m.join(g.UPLOAD_PROJECT_DIR,e),r=m.join(s,`${e}-v${i}.zip`);if(!u.existsSync(r))throw new x(`\u7248\u672C ${i} \u7684\u5907\u4EFD\u6587\u4EF6\u4E0D\u5B58\u5728`,{projectId:e,codeVersion:i,backupZipPath:r});const t=m.join(g.PROJECT_SOURCE_DIR,"_his",e);try{u.existsSync(t)&&await u.promises.rm(t,{recursive:!0,force:!0}),await u.promises.mkdir(t,{recursive:!0}),c(e,"INFO",`\u5F00\u59CB\u89E3\u538B\u7248\u672C ${i} \u7684\u5907\u4EFD\u6587\u4EF6`,{projectId:e,codeVersion:i,backupZipPath:r,tempExtractDir:t}),c(e,"DEBUG","\u5F00\u59CB\u89E3\u538B\u7248\u672C\u5907\u4EFD\u6587\u4EF6",{projectId:e,backupZipPath:r,tempExtractDir:t}),await N(r,t),c(e,"DEBUG",`\u7248\u672C ${i} \u5907\u4EFD\u6587\u4EF6\u89E3\u538B\u5B8C\u6210`,{projectId:e,codeVersion:i,tempExtractDir:t}),c(e,"DEBUG","\u5F00\u59CB\u904D\u5386\u7248\u672C\u76EE\u5F55",{projectId:e,tempExtractDir:t});const a=await D(t,t,e,l);let w=a;f!=="cpage_config"&&(w=a.filter(F=>F.name!=="cpage_config.json"));const E={files:w};return c(e,"INFO",`\u7248\u672C ${i} \u9879\u76EE\u5185\u5BB9\u83B7\u53D6\u5B8C\u6210`,{projectId:e,codeVersion:i,fileCount:E.files?E.files.length:0,command:f,elapsedMs:Date.now()-n}),E}finally{try{u.existsSync(t)&&(await u.promises.rm(t,{recursive:!0,force:!0}),c(e,"INFO",`\u4E34\u65F6\u76EE\u5F55\u5DF2\u6E05\u7406: ${t}`,{projectId:e,codeVersion:i}))}catch(a){c(e,"WARN",`\u6E05\u7406\u4E34\u65F6\u76EE\u5F55\u5931\u8D25: ${a.message}`,{projectId:e,codeVersion:i,tempExtractDir:t,error:a.message})}}}export{U as getProjectContent,T as getProjectContentByVersion,D as traverseDirectory,_ as isBinaryFile,C as isImageFile};
1
+ import u from"fs";import m from"path";import y from"../../appConfig/index.js";import{log as c}from"../log/logUtils.js";import{ValidationError as _,SystemError as R,ResourceError as x}from"../error/errorHandler.js";import{extractZip as b}from"../common/zipUtils.js";import{getFrameworkInfo as v}from"./frameworkDetectorUtils.js";async function S(e){try{const s=u.readFileSync(e);if(s.includes(0))return!0;const f=s.toString("utf-8");for(let l=0;l<f.length;l++){const i=f.charCodeAt(l);if(i<32&&i!==9&&i!==10&&i!==13)return!0}return!1}catch{return!1}}function p(e){const s=m.extname(e).toLowerCase();return[".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg"].includes(s)}async function d(e,s,f,l){const i=[],r=await u.promises.readdir(e,{withFileTypes:!0});r.sort((n,t)=>n.isDirectory()&&!t.isDirectory()?-1:!n.isDirectory()&&t.isDirectory()?1:n.name.toLowerCase().localeCompare(t.name.toLowerCase()));for(const n of r){const t=m.join(e,n.name);if(!(n.name.startsWith(".")||(y.CONTENT_TRAVERSE_EXCLUDE_FILES||[]).includes(n.name))&&!(n.isDirectory()&&y.TRAVERSE_EXCLUDE_DIRS.includes(n.name)))if(n.isDirectory()){const a=await d(t,s,f,l);i.push(...a)}else try{const a=await u.promises.stat(t),w=s||m.join(y.PROJECT_SOURCE_DIR,f),g=m.relative(w,t),D=await S(t),C=`${l}/${g}`,E={name:g,binary:D,sizeExceeded:a.size>y.MAX_INLINE_FILE_SIZE_BYTES,contents:"",fileProxyUrl:C};if(!E.sizeExceeded)if(E.binary){if(p(t)){const F=u.readFileSync(t);E.contents=F.toString("base64")}}else E.contents=u.readFileSync(t,"utf-8");i.push(E)}catch(a){c(f,"WARN",`Process file failed: ${t} - ${a.message}`,{filePath:t,error:a.message})}}return i}async function $(e,s,f){const l=Date.now(),i=m.basename(e);try{c(i,"INFO","Start getting project content",{projectPath:e,command:s}),c(i,"DEBUG","Start traversing project directory",{projectPath:e});const r=await d(e,null,i,f);c(i,"DEBUG","Project directory traversal completed",{projectPath:e,fileCount:r.length});let n=r;s!=="cpage_config"&&(n=r.filter(a=>a.name!=="cpage_config.json")),c(i,"DEBUG","Start detecting framework information",{projectPath:e});const t=v(e),o={files:n,...t};return c(i,"INFO",`Project content obtained, total ${n.length} files`,{projectPath:e,fileCount:n.length,command:s,elapsedMs:Date.now()-l}),o}catch(r){throw c(i,"ERROR",`Get project content failed: ${r.message}`,{projectPath:e,originalError:r.message,elapsedMs:Date.now()-l}),new R(`Get project content failed: ${r.message}`,{projectPath:e,originalError:r.message})}}async function h(e,s,f,l){const i=Date.now(),r=Number(s);if(!Number.isFinite(r))throw new _("Code version must be a number",{field:"codeVersion"});const n=m.join(y.UPLOAD_PROJECT_DIR,e),t=m.join(n,`${e}-v${r}.zip`);if(!u.existsSync(t))throw new x(`Backup file for version ${r} does not exist`,{projectId:e,codeVersion:r,backupZipPath:t});const o=m.join(y.PROJECT_SOURCE_DIR,"_his",e);try{u.existsSync(o)&&await u.promises.rm(o,{recursive:!0,force:!0}),await u.promises.mkdir(o,{recursive:!0}),c(e,"INFO",`Start extracting backup file for version ${r}`,{projectId:e,codeVersion:r,backupZipPath:t,tempExtractDir:o}),c(e,"DEBUG","Start extracting version backup file",{projectId:e,backupZipPath:t,tempExtractDir:o}),await b(t,o),c(e,"DEBUG",`Version ${r} backup file extraction completed`,{projectId:e,codeVersion:r,tempExtractDir:o}),c(e,"DEBUG","Start traversing version directory",{projectId:e,tempExtractDir:o});const a=await d(o,o,e,l);let w=a;f!=="cpage_config"&&(w=a.filter(D=>D.name!=="cpage_config.json"));const g={files:w};return c(e,"INFO",`Version ${r} project content obtained`,{projectId:e,codeVersion:r,fileCount:g.files?g.files.length:0,command:f,elapsedMs:Date.now()-i}),g}finally{try{u.existsSync(o)&&(await u.promises.rm(o,{recursive:!0,force:!0}),c(e,"INFO",`Temporary directory cleaned: ${o}`,{projectId:e,codeVersion:r}))}catch(a){c(e,"WARN",`Clean temporary directory failed: ${a.message}`,{projectId:e,codeVersion:r,tempExtractDir:o,error:a.message})}}}export{$ as getProjectContent,h as getProjectContentByVersion,d as traverseDirectory,S as isBinaryFile,p as isImageFile};
@@ -1 +1 @@
1
- import s from"fs";import f from"path";import{log as e}from"../log/logUtils.js";async function n(a,r){try{const t=f.join(a,r);return s.existsSync(t)?s.statSync(t).isDirectory()?(s.rmSync(t,{recursive:!0,force:!0}),e("default","INFO",`\u6210\u529F\u5220\u9664\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939: ${t}`),!0):(e("default","WARN",`\u76EE\u6807\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${t}`),!1):(e("default","INFO",`\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939\u4E0D\u5B58\u5728: ${t}`),!0)}catch(t){return e("default","ERROR",`\u5220\u9664\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939\u5931\u8D25: ${t.message}`),e("default","ERROR",`\u76EE\u6807\u8DEF\u5F84: ${f.join(a,r)}`),!1}}async function c(a){try{const{INIT_PROJECT_DIR:r,INIT_PROJECT_NAME:t}=a;if(!r||!t)return e("default","WARN","INIT_PROJECT_DIR \u6216 INIT_PROJECT_NAME \u914D\u7F6E\u7F3A\u5931"),!1;e("default","INFO","\u5F00\u59CB\u6E05\u7406\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939..."),e("default","INFO",`\u76EE\u6807\u76EE\u5F55: ${r}`),e("default","INFO",`\u9879\u76EE\u540D\u79F0: ${t}`);const u=await n(r,t);return u?e("default","INFO","\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939\u6E05\u7406\u5B8C\u6210"):e("default","ERROR","\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939\u6E05\u7406\u5931\u8D25"),u}catch(r){return e("default","ERROR",`\u6E05\u7406\u521D\u59CB\u5316\u9879\u76EE\u6587\u4EF6\u5939\u65F6\u53D1\u751F\u9519\u8BEF: ${r.message}`),!1}}export{n as deleteInitProjectFolder,c as cleanupInitProjectOnStartup};
1
+ import o from"fs";import n from"path";import{log as e}from"../log/logUtils.js";async function c(i,r){try{const t=n.join(i,r);return o.existsSync(t)?o.statSync(t).isDirectory()?(o.rmSync(t,{recursive:!0,force:!0}),e("default","INFO",`Successfully deleted initialization project directory: ${t}`),!0):(e("default","WARN",`Target path is not a directory: ${t}`),!1):(e("default","INFO",`Initialization project directory does not exist: ${t}`),!0)}catch(t){return e("default","ERROR",`Delete initialization project directory failed: ${t.message}`),e("default","ERROR",`Target path: ${n.join(i,r)}`),!1}}async function l(i){try{const{INIT_PROJECT_DIR:r,INIT_PROJECT_NAME:t}=i;if(!r||!t)return e("default","WARN","INIT_PROJECT_DIR or INIT_PROJECT_NAME configuration missing"),!1;e("default","INFO","Start cleaning initialization project directory..."),e("default","INFO",`Target directory: ${r}`),e("default","INFO",`Project name: ${t}`);const a=await c(r,t);return a?e("default","INFO","Initialization project directory cleanup completed"):e("default","ERROR","Initialization project directory cleanup failed"),a}catch(r){return e("default","ERROR",`Clean initialization project directory failed: ${r.message}`),!1}}export{c as deleteInitProjectFolder,l as cleanupInitProjectOnStartup};
@@ -1 +1 @@
1
- import n from"fs";import s from"path";import E from"../../appConfig/index.js";import{log as m}from"../log/logUtils.js";import{ValidationError as h,SystemError as f,FileError as N}from"../error/errorHandler.js";async function u(t,a,c=null){try{if(!t)throw new h("\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A",{field:"projectId"});if(!a)throw new h("\u6587\u4EF6\u4E0D\u80FD\u4E3A\u7A7A",{field:"file"});if(!a.path)throw new h("\u6587\u4EF6\u8DEF\u5F84\u65E0\u6548",{field:"file.path"});m(t,"INFO","\u5F00\u59CB\u4E0A\u4F20\u9644\u4EF6\u6587\u4EF6",{projectId:t,fileName:c,originalName:a.originalname,tempPath:a.path});const r=s.join(E.PROJECT_SOURCE_DIR,t);if(!n.existsSync(r))throw new h("\u9879\u76EE\u4E0D\u5B58\u5728",{field:"projectId"});const e=s.join(r,".attachments");n.existsSync(e)||(await n.promises.mkdir(e,{recursive:!0}),m(t,"INFO","\u521B\u5EFA\u9644\u4EF6\u76EE\u5F55",{attachmentsDir:e}));let i;c?i=c:i=a.originalname;let o=s.join(e,i);if(n.existsSync(o)){const p=Date.now(),g=Math.round(Math.random()*1e6),w=s.extname(i);i=`${s.basename(i,w)}_${p}_${g}${w}`,o=s.join(e,i)}try{await n.promises.rename(a.path,o)}catch(p){if(p.code==="EXDEV")m(t,"INFO","\u8DE8\u8BBE\u5907\u79FB\u52A8\uFF0C\u4F7F\u7528\u590D\u5236\u65B9\u5F0F",{tempPath:a.path,finalPath:o}),await n.promises.copyFile(a.path,o),await n.promises.unlink(a.path);else throw p}const l=s.relative(r,o);return m(t,"INFO","\u9644\u4EF6\u6587\u4EF6\u4E0A\u4F20\u6210\u529F",{projectId:t,originalName:a.originalname,fileName:i,relativePath:l,finalFilePath:o}),{fileName:i,relativePath:l}}catch(r){if(a&&a.path&&n.existsSync(a.path))try{await n.promises.unlink(a.path),m(t,"INFO","\u6E05\u7406\u4E34\u65F6\u6587\u4EF6",{tempPath:a.path})}catch(e){m(t,"WARN","\u6E05\u7406\u4E34\u65F6\u6587\u4EF6\u5931\u8D25",{tempPath:a.path,error:e.message})}throw m(t,"ERROR","\u4E0A\u4F20\u9644\u4EF6\u6587\u4EF6\u5931\u8D25",{projectId:t,originalName:a?.originalname,error:r.message}),r instanceof h||r instanceof f||r instanceof N?r:new f(`\u4E0A\u4F20\u9644\u4EF6\u6587\u4EF6\u5931\u8D25: ${r.message}`,{projectId:t,originalError:r.message})}}export{u as uploadAttachmentFile};
1
+ import n from"fs";import s from"path";import g from"../../appConfig/index.js";import{log as m}from"../log/logUtils.js";import{ValidationError as h,SystemError as w,FileError as u}from"../error/errorHandler.js";async function d(t,a,c=null){try{if(!t)throw new h("Project ID cannot be empty",{field:"projectId"});if(!a)throw new h("File cannot be empty",{field:"file"});if(!a.path)throw new h("File path is invalid",{field:"file.path"});m(t,"INFO","Start uploading attachment file",{projectId:t,fileName:c,originalName:a.originalname,tempPath:a.path});const e=s.join(g.PROJECT_SOURCE_DIR,t);if(!n.existsSync(e))throw new h("Project does not exist",{field:"projectId"});const r=s.join(e,".attachments");n.existsSync(r)||(await n.promises.mkdir(r,{recursive:!0}),m(t,"INFO","Create attachment directory",{attachmentsDir:r}));let i;c?i=c:i=a.originalname;let o=s.join(r,i);if(n.existsSync(o)){const l=Date.now(),y=Math.round(Math.random()*1e6),f=s.extname(i);i=`${s.basename(i,f)}_${l}_${y}${f}`,o=s.join(r,i)}try{await n.promises.rename(a.path,o)}catch(l){if(l.code==="EXDEV")m(t,"INFO","Cross-device move, using copy method",{tempPath:a.path,finalPath:o}),await n.promises.copyFile(a.path,o),await n.promises.unlink(a.path);else throw l}const p=s.relative(e,o);return m(t,"INFO","Attachment file uploaded successfully",{projectId:t,originalName:a.originalname,fileName:i,relativePath:p,finalFilePath:o}),{fileName:i,relativePath:p}}catch(e){if(a&&a.path&&n.existsSync(a.path))try{await n.promises.unlink(a.path),m(t,"INFO","Clean temporary file",{tempPath:a.path})}catch(r){m(t,"WARN","Clean temporary file failed",{tempPath:a.path,error:r.message})}throw m(t,"ERROR","Upload attachment file failed",{projectId:t,originalName:a?.originalname,error:e.message}),e instanceof h||e instanceof w||e instanceof u?e:new w(`Upload attachment file failed: ${e.message}`,{projectId:t,originalError:e.message})}}export{d as uploadAttachmentFile};
@@ -1,3 +1,3 @@
1
- import g from"path";import T from"os";import f from"fs-extra";import{spawn as S}from"cross-spawn";import k from"tree-kill";import{fileURLToPath as E}from"url";const O=g.dirname(E(import.meta.url)),c={name:"nuwax-file-server",pidDir:g.join(T.tmpdir(),"nuwax-file-server"),pidFileName:"server.pid",defaultStopTimeout:3e4,checkInterval:500};function p(){return g.join(c.pidDir,c.pidFileName)}function m(){try{const e=p();if(!f.existsSync(e))return null;const s=f.readFileSync(e,"utf8"),o=JSON.parse(s);return!o||typeof o.pid!="number"?null:o}catch(e){return e.code!=="ENOENT"&&console.error(`\u8BFB\u53D6 PID \u6587\u4EF6\u5931\u8D25: ${e.message}`),null}}function h(e){try{const s=p();f.ensureDirSync(c.pidDir),f.writeFileSync(s,JSON.stringify(e,null,2)),console.debug(`PID \u6587\u4EF6\u5DF2\u5199\u5165: ${s}`)}catch(s){throw console.error(`\u5199\u5165 PID \u6587\u4EF6\u5931\u8D25: ${s.message}`),s}}function $(){try{const e=p();f.existsSync(e)&&(f.removeSync(e),console.debug(`PID \u6587\u4EF6\u5DF2\u5220\u9664: ${e}`))}catch(e){console.error(`\u5220\u9664 PID \u6587\u4EF6\u5931\u8D25: ${e.message}`)}}function u(e){try{return process.kill(e,0),!0}catch(s){return s.code!=="ESRCH"}}function I(){return process.platform==="win32"}async function w(e,s=!1){return new Promise(o=>{if(!u(e)){console.debug(`\u8FDB\u7A0B ${e} \u4E0D\u5B58\u5728\uFF0C\u89C6\u4E3A\u5DF2\u505C\u6B62`),o(!0);return}const n=s?"SIGKILL":"SIGTERM",i=I()?"taskkill":"tree-kill";if(console.debug(`\u4F7F\u7528 ${i} \u505C\u6B62\u8FDB\u7A0B ${e} (\u4FE1\u53F7: ${n})`),I()){const r=s?["/F","/PID",String(e)]:["/PID",String(e)],a=S("taskkill",r,{stdio:["ignore","pipe","pipe"],windowsHide:!0});let d="";a.stdout.on("data",t=>{d+=t.toString()}),a.stderr.on("data",t=>{d+=t.toString()}),a.on("error",t=>{console.error(`\u505C\u6B62\u8FDB\u7A0B\u5931\u8D25: ${t.message}`),o(!1)}),a.on("close",t=>{t===0?(console.debug(`\u8FDB\u7A0B ${e} \u5DF2\u505C\u6B62`),o(!0)):(console.warn(`taskkill \u9000\u51FA\u7801: ${t}, \u8F93\u51FA: ${d}`),s?o(!1):w(e,!0).then(o))})}else k(e,n,r=>{r?r.code==="ESRCH"?(console.debug(`\u8FDB\u7A0B ${e} \u4E0D\u5B58\u5728`),o(!0)):(console.error(`\u505C\u6B62\u8FDB\u7A0B\u5931\u8D25: ${r.message}`),o(!1)):(console.debug(`\u8FDB\u7A0B ${e} \u5DF2\u505C\u6B62`),o(!0))})})}async function D(e,s=c.defaultStopTimeout){const o=Date.now();for(;u(e);){if(Date.now()-o>s)return console.warn(`\u7B49\u5F85\u8FDB\u7A0B ${e} \u505C\u6B62\u8D85\u65F6 (${s}ms)`),!1;await new Promise(i=>setTimeout(i,c.checkInterval))}const n=Date.now()-o;return console.debug(`\u8FDB\u7A0B ${e} \u5DF2\u5728 ${n}ms \u540E\u505C\u6B62`),!0}async function v(e={}){const{env:s,port:o,config:n}=e;console.log(`\u542F\u52A8\u670D\u52A1 ${c.name}...`);const i=m();if(i&&u(i.pid))return{success:!1,pid:i.pid,message:`\u670D\u52A1\u5DF2\u5728\u8FD0\u884C\u4E2D (PID: ${i.pid})`};const r={...process.env};s&&(r.NODE_ENV=s,console.log(`\u73AF\u5883: ${s}`)),o&&(r.PORT=o,console.log(`\u7AEF\u53E3: ${o}`)),n&&(r.CONFIG_FILE=n,console.log(`\u914D\u7F6E\u6587\u4EF6: ${n}`));const a=g.join(O,"..","server.js"),t=S("node",[a,...[]],{env:r,stdio:["pipe","pipe","pipe"],detached:!0,cwd:process.cwd()});if(t.stdout.on("data",l=>{process.stdout.write(l)}),t.stderr.on("data",l=>{process.stderr.write(l)}),t.on("error",l=>{console.error(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${l.message}`)}),await new Promise(l=>setTimeout(l,2e3)),!u(t.pid))return{success:!1,pid:null,message:"\u670D\u52A1\u542F\u52A8\u5931\u8D25"};const P={pid:t.pid,startedAt:new Date().toISOString(),env:s||process.env.NODE_ENV||"production",port:o||process.env.PORT||"60000",version:require("../../package.json").version,platform:process.platform};return h(P),t.unref(),console.log(`\u670D\u52A1\u5DF2\u542F\u52A8 (PID: ${t.pid})`),console.log(`\u8FD0\u884C\u5730\u5740: http://localhost:${P.port}`),{success:!0,pid:t.pid,message:"\u670D\u52A1\u542F\u52A8\u6210\u529F"}}async function y(e={}){const{force:s=!1,timeout:o=c.defaultStopTimeout}=e;console.log(`\u505C\u6B62\u670D\u52A1 ${c.name}...`);const n=m();if(!n)return{success:!1,message:"\u672A\u627E\u5230\u8FD0\u884C\u4E2D\u7684\u670D\u52A1"};if(!u(n.pid))return console.log("\u670D\u52A1\u8FDB\u7A0B\u5DF2\u505C\u6B62\uFF0C\u6E05\u7406 PID \u6587\u4EF6..."),$(),{success:!0,message:"\u670D\u52A1\u5DF2\u505C\u6B62\uFF08\u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF09"};if(!await w(n.pid,s))return{success:!1,message:"\u505C\u6B62\u670D\u52A1\u5931\u8D25"};const r=await D(n.pid,o);return $(),r?{success:!0,message:"\u670D\u52A1\u5DF2\u505C\u6B62"}:{success:!1,message:"\u670D\u52A1\u505C\u6B62\u8D85\u65F6"}}async function R(e={}){console.log(`\u91CD\u542F\u670D\u52A1 ${c.name}...`);const s=await y(e);!s.success&&s.message!=="\u672A\u627E\u5230\u8FD0\u884C\u4E2D\u7684\u670D\u52A1"&&console.warn(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${s.message}`),await new Promise(n=>setTimeout(n,2e3));const o=await v(e);return o.success?{success:!0,pid:o.pid,message:"\u670D\u52A1\u5DF2\u91CD\u542F"}:{success:!1,pid:null,message:`\u91CD\u542F\u5931\u8D25: ${o.message}`}}function N(){const e=m();return e?u(e.pid)?{running:!0,pidInfo:e,message:"\u670D\u52A1\u8FD0\u884C\u4E2D"}:{running:!1,pidInfo:e,message:"\u670D\u52A1\u8FDB\u7A0B\u4E0D\u5B58\u5728"}:{running:!1,pidInfo:null,message:"\u670D\u52A1\u672A\u8FD0\u884C"}}function F(e){try{const s=new Date(e),o=new Date;if(isNaN(s.getTime()))return"\u672A\u77E5";const n=Math.floor((o-s)/1e3),i=Math.floor(n/3600),r=Math.floor(n%3600/60),a=n%60;return i>0?`${i}\u5C0F\u65F6 ${r}\u5206 ${a}\u79D2`:r>0?`${r}\u5206 ${a}\u79D2`:`${a}\u79D2`}catch{return"\u672A\u77E5"}}export{c as SERVICE_CONFIG,p as getPidFilePath,m as readPidFile,h as writePidFile,$ as deletePidFile,u as isProcessRunning,w as stopProcess,D as waitForProcessStop,v as startService,y as stopService,R as restartService,N as getServiceStatus,I as isWindows,F as formatUptime};if(process.argv[1]&&import.meta.url.endsWith(process.argv[1].replace(/\\/g,"/").replace(/^.*[\/\\]/,""))){const e=N();console.log(`
2
- ${c.name} \u670D\u52A1\u72B6\u6001:
3
- `),console.log(` \u8FD0\u884C\u72B6\u6001: ${e.running?"\u8FD0\u884C\u4E2D":"\u5DF2\u505C\u6B62"}`),e.pidInfo&&(console.log(` \u8FDB\u7A0B ID: ${e.pidInfo.pid}`),console.log(` \u73AF\u5883: ${e.pidInfo.env||"\u672A\u77E5"}`),console.log(` \u7AEF\u53E3: ${e.pidInfo.port||"\u672A\u77E5"}`),console.log(` \u7248\u672C: ${e.pidInfo.version||"\u672A\u77E5"}`),console.log(` \u5E73\u53F0: ${e.pidInfo.platform||"\u672A\u77E5"}`),console.log(` \u542F\u52A8\u65F6\u95F4: ${e.pidInfo.startedAt||"\u672A\u77E5"}`),console.log(` \u8FD0\u884C\u65F6\u95F4: ${F(e.pidInfo.startedAt)}`)),console.log(` PID \u6587\u4EF6: ${p()}`),console.log(""),process.exit(e.running?0:1)}
1
+ import g from"path";import E from"os";import p from"fs-extra";import{spawn as P}from"cross-spawn";import N from"tree-kill";import{fileURLToPath as x}from"url";const F=g.dirname(x(import.meta.url)),c={name:"nuwax-file-server",pidDir:g.join(E.tmpdir(),"nuwax-file-server"),pidFileName:"server.pid",defaultStopTimeout:3e4,checkInterval:500};function d(){return g.join(c.pidDir,c.pidFileName)}function m(){try{const e=d();if(!p.existsSync(e))return null;const s=p.readFileSync(e,"utf8"),o=JSON.parse(s);return!o||typeof o.pid!="number"?null:o}catch(e){return e.code!=="ENOENT"&&console.error(`Read PID file failed: ${e.message}`),null}}function I(e){try{const s=d();p.ensureDirSync(c.pidDir),p.writeFileSync(s,JSON.stringify(e,null,2)),console.debug(`PID file written: ${s}`)}catch(s){throw console.error(`Write PID file failed: ${s.message}`),s}}function S(){try{const e=d();p.existsSync(e)&&(p.removeSync(e),console.debug(`PID file deleted: ${e}`))}catch(e){console.error(`Delete PID file failed: ${e.message}`)}}function u(e){try{return process.kill(e,0),!0}catch(s){return s.code!=="ESRCH"}}function $(){return process.platform==="win32"}async function w(e,s=!1){return new Promise(o=>{if(!u(e)){console.debug(`Process ${e} does not exist, already stopped`),o(!0);return}const t=s?"SIGKILL":"SIGTERM",i=$()?"taskkill":"tree-kill";if(console.debug(`Use ${i} to stop process ${e} (signal: ${t})`),$()){const r=s?["/F","/PID",String(e)]:["/PID",String(e)],a=P("taskkill",r,{stdio:["ignore","pipe","pipe"],windowsHide:!0});let f="";a.stdout.on("data",n=>{f+=n.toString()}),a.stderr.on("data",n=>{f+=n.toString()}),a.on("error",n=>{console.error(`Stop process failed: ${n.message}`),o(!1)}),a.on("close",n=>{n===0?(console.debug(`Process ${e} stopped`),o(!0)):(console.warn(`taskkill exit code: ${n}, output: ${f}`),s?o(!1):w(e,!0).then(o))})}else N(e,t,r=>{r?r.code==="ESRCH"?(console.debug(`Process ${e} does not exist`),o(!0)):(console.error(`Stop process failed: ${r.message}`),o(!1)):(console.debug(`Process ${e} stopped`),o(!0))})})}async function h(e,s=c.defaultStopTimeout){const o=Date.now();for(;u(e);){if(Date.now()-o>s)return console.warn(`Wait for process ${e} to stop timeout (${s}ms)`),!1;await new Promise(i=>setTimeout(i,c.checkInterval))}const t=Date.now()-o;return console.debug(`Process ${e} stopped after ${t}ms`),!0}async function D(e={}){const{env:s,port:o,config:t}=e;console.log(`Start service ${c.name}...`);const i=m();if(i&&u(i.pid))return{success:!1,pid:i.pid,message:`Service is already running (PID: ${i.pid})`};const r={...process.env};s&&(r.NODE_ENV=s,console.log(`Environment: ${s}`)),o&&(r.PORT=o,console.log(`Port: ${o}`)),t&&(r.CONFIG_FILE=t,console.log(`Configuration file: ${t}`));const a=g.join(F,"..","server.js"),n=P("node",[a,...[]],{env:r,stdio:["pipe","pipe","pipe"],detached:!0,cwd:process.cwd()});if(n.stdout.on("data",l=>{process.stdout.write(l)}),n.stderr.on("data",l=>{process.stderr.write(l)}),n.on("error",l=>{console.error(`Start service failed: ${l.message}`)}),await new Promise(l=>setTimeout(l,2e3)),!u(n.pid))return{success:!1,pid:null,message:"Service start failed"};const v={pid:n.pid,startedAt:new Date().toISOString(),env:s||process.env.NODE_ENV||"production",port:o||process.env.PORT||"60000",version:require("../../package.json").version,platform:process.platform};return I(v),n.unref(),console.log(`Service started (PID: ${n.pid})`),console.log(`Service address: http://localhost:${v.port}`),{success:!0,pid:n.pid,message:"Service started successfully"}}async function y(e={}){const{force:s=!1,timeout:o=c.defaultStopTimeout}=e;console.log(`Stop service ${c.name}...`);const t=m();if(!t)return{success:!1,message:"Service not found"};if(!u(t.pid))return console.log("Service process has stopped, clean PID file..."),S(),{success:!0,message:"Service has stopped (process has exited)"};if(!await w(t.pid,s))return{success:!1,message:"Stop service failed"};const r=await h(t.pid,o);return S(),r?{success:!0,message:"Service has stopped"}:{success:!1,message:"Service stop timeout"}}async function T(e={}){console.log(`Restart service ${c.name}...`);const s=await y(e);!s.success&&s.message!=="Service not found"&&console.warn(`Stop service failed: ${s.message}`),await new Promise(t=>setTimeout(t,2e3));const o=await D(e);return o.success?{success:!0,pid:o.pid,message:"Service has restarted"}:{success:!1,pid:null,message:`Restart failed: ${o.message}`}}function k(){const e=m();return e?u(e.pid)?{running:!0,pidInfo:e,message:"Service running"}:{running:!1,pidInfo:e,message:"Service process does not exist"}:{running:!1,pidInfo:null,message:"Service not running"}}function R(e){try{const s=new Date(e),o=new Date;if(isNaN(s.getTime()))return"unknown";const t=Math.floor((o-s)/1e3),i=Math.floor(t/3600),r=Math.floor(t%3600/60),a=t%60;return i>0?`${i} hours ${r} minutes ${a} seconds`:r>0?`${r} minutes ${a} seconds`:`${a} seconds`}catch{return"unknown"}}export{c as SERVICE_CONFIG,d as getPidFilePath,m as readPidFile,I as writePidFile,S as deletePidFile,u as isProcessRunning,w as stopProcess,h as waitForProcessStop,D as startService,y as stopService,T as restartService,k as getServiceStatus,$ as isWindows,R as formatUptime};if(process.argv[1]&&import.meta.url.endsWith(process.argv[1].replace(/\\/g,"/").replace(/^.*[\/\\]/,""))){const e=k();console.log(`
2
+ ${c.name} Service status:
3
+ `),console.log(` Running status: ${e.running?"Running":"Stopped"}`),e.pidInfo&&(console.log(` Process ID: ${e.pidInfo.pid}`),console.log(` Environment: ${e.pidInfo.env||"Unknown"}`),console.log(` Port: ${e.pidInfo.port||"Unknown"}`),console.log(` Version: ${e.pidInfo.version||"Unknown"}`),console.log(` Platform: ${e.pidInfo.platform||"Unknown"}`),console.log(` Started at: ${e.pidInfo.startedAt||"Unknown"}`),console.log(` Uptime: ${R(e.pidInfo.startedAt)}`)),console.log(` PID file: ${d()}`),console.log(""),process.exit(e.running?0:1)}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "nuwax-file-server",
3
3
  "displayName": "nuwax-file-server",
4
- "version": "1.2.3",
5
- "description": "跨平台的文件服务部署工具,支持 start/stop/restart 命令行操作",
4
+ "version": "1.2.5",
5
+ "description": "Cross-platform file service deployment tool with start/stop/restart CLI commands",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "bin": {