mock-service-cli-ultra 4.9.1 → 4.9.2

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.
package/README.md CHANGED
@@ -97,6 +97,7 @@ npx mock-service-cli [options] [path]
97
97
  | `--watch-depth <n>` | 限制静态服务器文件监听递归深度(非负整数) | 无限 |
98
98
  | `--watch-interval <n>` | 设置静态服务器轮询间隔(毫秒;仅 Windows Node 24+ 轮询模式生效) | 250 |
99
99
  | `--no-watch` | 关闭静态服务器的文件监听与 live-reload(纯静态托管大目录) | false |
100
+ | `--no-os-hidden` | 跳过 Windows 系统隐藏属性判定(attrib/PowerShell) | false |
100
101
  | `-e` 或 `--explorer` | 启用文件浏览器服务器,指定要浏览的目录 | ./ |
101
102
  | `--edit` | 启用文件浏览器的新建、重命名、删除和上传操作 | false |
102
103
  | `--auth <password>` | 为文件浏览器启用密码认证(仅可搭配 `--explorer`) | - |
@@ -191,6 +192,10 @@ mock-service-cli -e ./ --host
191
192
  mock-service-cli -e ./ --host ./allowed-ips.txt
192
193
  ```
193
194
 
195
+ 静态服务器目录索引与文件浏览器默认把点号命名文件、以及(Windows 上)带系统隐藏属性的文件视为隐藏项。
196
+ 传入 `--no-os-hidden` 可跳过系统隐藏属性判定、仅按点号命名判定(利于规避个别属性误判与探测开销),
197
+ 对静态服务器目录索引与文件浏览器同时生效。
198
+
194
199
  默认情况下,Mock、SPA、Static 和 File Explorer 服务只监听 `127.0.0.1`。
195
200
  `--host` 会使这些服务监听所有 IPv4 网卡,请仅在可信网络中使用。传入白名单文件时,服务仍监听全部 IPv4 网卡,
196
201
  但仅允许 `localhost`、`127.0.0.1`、`::1` 及文件中的 IP/CIDR 访问;空行和行首 `#` 注释会忽略,非法或空白名单会阻止启动。
package/dist/meta.json CHANGED
@@ -1041,7 +1041,7 @@
1041
1041
  "format": "cjs"
1042
1042
  },
1043
1043
  "src/lib/utils.js": {
1044
- "bytes": 20378,
1044
+ "bytes": 22595,
1045
1045
  "imports": [
1046
1046
  {
1047
1047
  "path": "fs",
@@ -1093,7 +1093,7 @@
1093
1093
  "format": "cjs"
1094
1094
  },
1095
1095
  "src/bin/mock-service-cli": {
1096
- "bytes": 14961,
1096
+ "bytes": 15146,
1097
1097
  "imports": [
1098
1098
  {
1099
1099
  "path": "node_modules/colors/safe.js",
@@ -7425,7 +7425,7 @@
7425
7425
  "format": "cjs"
7426
7426
  },
7427
7427
  "src/lib/staticServer.js": {
7428
- "bytes": 38819,
7428
+ "bytes": 39069,
7429
7429
  "imports": [
7430
7430
  {
7431
7431
  "path": "node_modules/express/index.js",
@@ -8215,7 +8215,7 @@
8215
8215
  "format": "cjs"
8216
8216
  },
8217
8217
  "src/lib/fileExplorerServer.js": {
8218
- "bytes": 26173,
8218
+ "bytes": 26437,
8219
8219
  "imports": [
8220
8220
  {
8221
8221
  "path": "node_modules/express/index.js",
@@ -9737,13 +9737,13 @@
9737
9737
  "bytesInOutput": 4540
9738
9738
  },
9739
9739
  "src/lib/utils.js": {
9740
- "bytesInOutput": 11114
9740
+ "bytesInOutput": 12197
9741
9741
  },
9742
9742
  "src/lib/packageInfo.js": {
9743
9743
  "bytesInOutput": 429
9744
9744
  },
9745
9745
  "src/bin/mock-service-cli": {
9746
- "bytesInOutput": 11642
9746
+ "bytesInOutput": 11804
9747
9747
  },
9748
9748
  "node_modules/depd/index.js": {
9749
9749
  "bytesInOutput": 6779
@@ -10859,7 +10859,7 @@
10859
10859
  "bytesInOutput": 11845
10860
10860
  },
10861
10861
  "src/lib/staticServer.js": {
10862
- "bytesInOutput": 29740
10862
+ "bytesInOutput": 29860
10863
10863
  },
10864
10864
  "node_modules/busboy/lib/utils.js": {
10865
10865
  "bytesInOutput": 8707
@@ -10982,13 +10982,13 @@
10982
10982
  "bytesInOutput": 7774
10983
10983
  },
10984
10984
  "src/lib/fileExplorerServer.js": {
10985
- "bytesInOutput": 19290
10985
+ "bytesInOutput": 19410
10986
10986
  },
10987
10987
  "src/runtime.js": {
10988
10988
  "bytesInOutput": 507
10989
10989
  }
10990
10990
  },
10991
- "bytes": 1745512
10991
+ "bytes": 1746997
10992
10992
  }
10993
10993
  }
10994
10994
  }
package/dist/runtime.js CHANGED
@@ -12,8 +12,8 @@ GFS4: `),console.error(m)});fs[gracefulQueue]||(queue=global[gracefulQueue]||[],
12
12
  see https://github.com/jprichardson/node-fs-extra/issues/269`,"Warning","fs-extra-WARN0001");let{srcStat,destStat}=await stat.checkPaths(src,dest,"copy",opts);if(await stat.checkParentPaths(src,srcStat,dest,"copy"),!await runFilter(src,dest,opts))return;let destParent=path.dirname(dest);await pathExists(destParent)||await mkdirs(destParent),await getStatsAndPerformCopy(destStat,src,dest,opts)}async function runFilter(src,dest,opts){return opts.filter?opts.filter(src,dest):!0}async function getStatsAndPerformCopy(destStat,src,dest,opts){let srcStat=await(opts.dereference?fs.stat:fs.lstat)(src);if(srcStat.isDirectory())return onDir(srcStat,destStat,src,dest,opts);if(srcStat.isFile()||srcStat.isCharacterDevice()||srcStat.isBlockDevice())return onFile(srcStat,destStat,src,dest,opts);if(srcStat.isSymbolicLink())return onLink(destStat,src,dest,opts);throw srcStat.isSocket()?new Error(`Cannot copy a socket file: ${src}`):srcStat.isFIFO()?new Error(`Cannot copy a FIFO pipe: ${src}`):new Error(`Unknown file: ${src}`)}async function onFile(srcStat,destStat,src,dest,opts){if(!destStat)return copyFile(srcStat,src,dest,opts);if(opts.overwrite)return await fs.unlink(dest),copyFile(srcStat,src,dest,opts);if(opts.errorOnExist)throw new Error(`'${dest}' already exists`)}async function copyFile(srcStat,src,dest,opts){if(await fs.copyFile(src,dest),opts.preserveTimestamps){fileIsNotWritable(srcStat.mode)&&await makeFileWritable(dest,srcStat.mode);let updatedSrcStat=await fs.stat(src);await utimesMillis(dest,updatedSrcStat.atime,updatedSrcStat.mtime)}return fs.chmod(dest,srcStat.mode)}function fileIsNotWritable(srcMode){return(srcMode&128)===0}function makeFileWritable(dest,srcMode){return fs.chmod(dest,srcMode|128)}async function onDir(srcStat,destStat,src,dest,opts){destStat||await fs.mkdir(dest),await asyncIteratorConcurrentProcess(await fs.opendir(src),async item=>{let srcItem=path.join(src,item.name),destItem=path.join(dest,item.name);if(await runFilter(srcItem,destItem,opts)){let{destStat:destStat2}=await stat.checkPaths(srcItem,destItem,"copy",opts);await getStatsAndPerformCopy(destStat2,srcItem,destItem,opts)}}),destStat||await fs.chmod(dest,srcStat.mode)}async function onLink(destStat,src,dest,opts){let resolvedSrc=await fs.readlink(src);if(opts.dereference&&(resolvedSrc=path.resolve(process.cwd(),resolvedSrc)),!destStat)return fs.symlink(resolvedSrc,dest);let resolvedDest=null;try{resolvedDest=await fs.readlink(dest)}catch(e){if(e.code==="EINVAL"||e.code==="UNKNOWN")return fs.symlink(resolvedSrc,dest);throw e}if(opts.dereference&&(resolvedDest=path.resolve(process.cwd(),resolvedDest)),resolvedSrc!==resolvedDest){if(stat.isSrcSubdir(resolvedSrc,resolvedDest))throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`);if(stat.isSrcSubdir(resolvedDest,resolvedSrc))throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)}return await fs.unlink(dest),fs.symlink(resolvedSrc,dest)}module2.exports=copy}});var require_copy_sync=__commonJS({"node_modules/fs-extra/lib/copy/copy-sync.js"(exports2,module2){"use strict";var fs=require_graceful_fs(),path=require("path"),mkdirsSync=require_mkdirs().mkdirsSync,utimesMillisSync=require_utimes().utimesMillisSync,stat=require_stat();function copySync(src,dest,opts){typeof opts=="function"&&(opts={filter:opts}),opts=opts||{},opts.clobber="clobber"in opts?!!opts.clobber:!0,opts.overwrite="overwrite"in opts?!!opts.overwrite:opts.clobber,opts.preserveTimestamps&&process.arch==="ia32"&&process.emitWarning(`Using the preserveTimestamps option in 32-bit node is not recommended;
13
13
 
14
14
  see https://github.com/jprichardson/node-fs-extra/issues/269`,"Warning","fs-extra-WARN0002");let{srcStat,destStat}=stat.checkPathsSync(src,dest,"copy",opts);if(stat.checkParentPathsSync(src,srcStat,dest,"copy"),opts.filter&&!opts.filter(src,dest))return;let destParent=path.dirname(dest);return fs.existsSync(destParent)||mkdirsSync(destParent),getStats(destStat,src,dest,opts)}function getStats(destStat,src,dest,opts){let srcStat=(opts.dereference?fs.statSync:fs.lstatSync)(src);if(srcStat.isDirectory())return onDir(srcStat,destStat,src,dest,opts);if(srcStat.isFile()||srcStat.isCharacterDevice()||srcStat.isBlockDevice())return onFile(srcStat,destStat,src,dest,opts);if(srcStat.isSymbolicLink())return onLink(destStat,src,dest,opts);throw srcStat.isSocket()?new Error(`Cannot copy a socket file: ${src}`):srcStat.isFIFO()?new Error(`Cannot copy a FIFO pipe: ${src}`):new Error(`Unknown file: ${src}`)}function onFile(srcStat,destStat,src,dest,opts){return destStat?mayCopyFile(srcStat,src,dest,opts):copyFile(srcStat,src,dest,opts)}function mayCopyFile(srcStat,src,dest,opts){if(opts.overwrite)return fs.unlinkSync(dest),copyFile(srcStat,src,dest,opts);if(opts.errorOnExist)throw new Error(`'${dest}' already exists`)}function copyFile(srcStat,src,dest,opts){return fs.copyFileSync(src,dest),opts.preserveTimestamps&&handleTimestamps(srcStat.mode,src,dest),setDestMode(dest,srcStat.mode)}function handleTimestamps(srcMode,src,dest){return fileIsNotWritable(srcMode)&&makeFileWritable(dest,srcMode),setDestTimestamps(src,dest)}function fileIsNotWritable(srcMode){return(srcMode&128)===0}function makeFileWritable(dest,srcMode){return setDestMode(dest,srcMode|128)}function setDestMode(dest,srcMode){return fs.chmodSync(dest,srcMode)}function setDestTimestamps(src,dest){let updatedSrcStat=fs.statSync(src);return utimesMillisSync(dest,updatedSrcStat.atime,updatedSrcStat.mtime)}function onDir(srcStat,destStat,src,dest,opts){return destStat?copyDir(src,dest,opts):mkDirAndCopy(srcStat.mode,src,dest,opts)}function mkDirAndCopy(srcMode,src,dest,opts){return fs.mkdirSync(dest),copyDir(src,dest,opts),setDestMode(dest,srcMode)}function copyDir(src,dest,opts){let dir=fs.opendirSync(src);try{let dirent;for(;(dirent=dir.readSync())!==null;)copyDirItem(dirent.name,src,dest,opts)}finally{dir.closeSync()}}function copyDirItem(item,src,dest,opts){let srcItem=path.join(src,item),destItem=path.join(dest,item);if(opts.filter&&!opts.filter(srcItem,destItem))return;let{destStat}=stat.checkPathsSync(srcItem,destItem,"copy",opts);return getStats(destStat,srcItem,destItem,opts)}function onLink(destStat,src,dest,opts){let resolvedSrc=fs.readlinkSync(src);if(opts.dereference&&(resolvedSrc=path.resolve(process.cwd(),resolvedSrc)),destStat){let resolvedDest;try{resolvedDest=fs.readlinkSync(dest)}catch(err){if(err.code==="EINVAL"||err.code==="UNKNOWN")return fs.symlinkSync(resolvedSrc,dest);throw err}if(opts.dereference&&(resolvedDest=path.resolve(process.cwd(),resolvedDest)),resolvedSrc!==resolvedDest){if(stat.isSrcSubdir(resolvedSrc,resolvedDest))throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`);if(stat.isSrcSubdir(resolvedDest,resolvedSrc))throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)}return copyLink(resolvedSrc,dest)}else return fs.symlinkSync(resolvedSrc,dest)}function copyLink(resolvedSrc,dest){return fs.unlinkSync(dest),fs.symlinkSync(resolvedSrc,dest)}module2.exports=copySync}});var require_copy2=__commonJS({"node_modules/fs-extra/lib/copy/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise;module2.exports={copy:u(require_copy()),copySync:require_copy_sync()}}});var require_remove=__commonJS({"node_modules/fs-extra/lib/remove/index.js"(exports2,module2){"use strict";var fs=require_graceful_fs(),u=require_universalify().fromCallback;function remove(path,callback){fs.rm(path,{recursive:!0,force:!0},callback)}function removeSync(path){fs.rmSync(path,{recursive:!0,force:!0})}module2.exports={remove:u(remove),removeSync}}});var require_empty=__commonJS({"node_modules/fs-extra/lib/empty/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,fs=require_fs(),path=require("path"),mkdir=require_mkdirs(),remove=require_remove(),emptyDir=u(async function(dir){let items;try{items=await fs.readdir(dir)}catch{return mkdir.mkdirs(dir)}return Promise.all(items.map(item=>remove.remove(path.join(dir,item))))});function emptyDirSync(dir){let items;try{items=fs.readdirSync(dir)}catch{return mkdir.mkdirsSync(dir)}items.forEach(item=>{item=path.join(dir,item),remove.removeSync(item)})}module2.exports={emptyDirSync,emptydirSync:emptyDirSync,emptyDir,emptydir:emptyDir}}});var require_file=__commonJS({"node_modules/fs-extra/lib/ensure/file.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,path=require("path"),fs=require_fs(),mkdir=require_mkdirs();async function createFile(file){let stats;try{stats=await fs.stat(file)}catch{}if(stats&&stats.isFile())return;let dir=path.dirname(file),dirStats=null;try{dirStats=await fs.stat(dir)}catch(err){if(err.code==="ENOENT"){await mkdir.mkdirs(dir),await fs.writeFile(file,"");return}else throw err}dirStats.isDirectory()?await fs.writeFile(file,""):await fs.readdir(dir)}function createFileSync(file){let stats;try{stats=fs.statSync(file)}catch{}if(stats&&stats.isFile())return;let dir=path.dirname(file);try{fs.statSync(dir).isDirectory()||fs.readdirSync(dir)}catch(err){if(err&&err.code==="ENOENT")mkdir.mkdirsSync(dir);else throw err}fs.writeFileSync(file,"")}module2.exports={createFile:u(createFile),createFileSync}}});var require_link=__commonJS({"node_modules/fs-extra/lib/ensure/link.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,path=require("path"),fs=require_fs(),mkdir=require_mkdirs(),{pathExists}=require_path_exists(),{areIdentical}=require_stat();async function createLink(srcpath,dstpath){let dstStat;try{dstStat=await fs.lstat(dstpath,{bigint:!0})}catch{}let srcStat;try{srcStat=await fs.lstat(srcpath,{bigint:!0})}catch(err){throw err.message=err.message.replace("lstat","ensureLink"),err}if(dstStat&&areIdentical(srcStat,dstStat))return;let dir=path.dirname(dstpath);await pathExists(dir)||await mkdir.mkdirs(dir),await fs.link(srcpath,dstpath)}function createLinkSync(srcpath,dstpath){let dstStat;try{dstStat=fs.lstatSync(dstpath,{bigint:!0})}catch{}try{let srcStat=fs.lstatSync(srcpath,{bigint:!0});if(dstStat&&areIdentical(srcStat,dstStat))return}catch(err){throw err.message=err.message.replace("lstat","ensureLink"),err}let dir=path.dirname(dstpath);return fs.existsSync(dir)||mkdir.mkdirsSync(dir),fs.linkSync(srcpath,dstpath)}module2.exports={createLink:u(createLink),createLinkSync}}});var require_symlink_paths=__commonJS({"node_modules/fs-extra/lib/ensure/symlink-paths.js"(exports2,module2){"use strict";var path=require("path"),fs=require_fs(),{pathExists}=require_path_exists(),u=require_universalify().fromPromise;async function symlinkPaths(srcpath,dstpath){if(path.isAbsolute(srcpath)){try{await fs.lstat(srcpath)}catch(err){throw err.message=err.message.replace("lstat","ensureSymlink"),err}return{toCwd:srcpath,toDst:srcpath}}let dstdir=path.dirname(dstpath),relativeToDst=path.join(dstdir,srcpath);if(await pathExists(relativeToDst))return{toCwd:relativeToDst,toDst:srcpath};try{await fs.lstat(srcpath)}catch(err){throw err.message=err.message.replace("lstat","ensureSymlink"),err}return{toCwd:srcpath,toDst:path.relative(dstdir,srcpath)}}function symlinkPathsSync(srcpath,dstpath){if(path.isAbsolute(srcpath)){if(!fs.existsSync(srcpath))throw new Error("absolute srcpath does not exist");return{toCwd:srcpath,toDst:srcpath}}let dstdir=path.dirname(dstpath),relativeToDst=path.join(dstdir,srcpath);if(fs.existsSync(relativeToDst))return{toCwd:relativeToDst,toDst:srcpath};if(!fs.existsSync(srcpath))throw new Error("relative srcpath does not exist");return{toCwd:srcpath,toDst:path.relative(dstdir,srcpath)}}module2.exports={symlinkPaths:u(symlinkPaths),symlinkPathsSync}}});var require_symlink_type=__commonJS({"node_modules/fs-extra/lib/ensure/symlink-type.js"(exports2,module2){"use strict";var fs=require_fs(),u=require_universalify().fromPromise;async function symlinkType(srcpath,type){if(type)return type;let stats;try{stats=await fs.lstat(srcpath)}catch{return"file"}return stats&&stats.isDirectory()?"dir":"file"}function symlinkTypeSync(srcpath,type){if(type)return type;let stats;try{stats=fs.lstatSync(srcpath)}catch{return"file"}return stats&&stats.isDirectory()?"dir":"file"}module2.exports={symlinkType:u(symlinkType),symlinkTypeSync}}});var require_symlink=__commonJS({"node_modules/fs-extra/lib/ensure/symlink.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,path=require("path"),fs=require_fs(),{mkdirs,mkdirsSync}=require_mkdirs(),{symlinkPaths,symlinkPathsSync}=require_symlink_paths(),{symlinkType,symlinkTypeSync}=require_symlink_type(),{pathExists}=require_path_exists(),{areIdentical}=require_stat();async function createSymlink(srcpath,dstpath,type){let stats;try{stats=await fs.lstat(dstpath)}catch{}if(stats&&stats.isSymbolicLink()){let srcStat;if(path.isAbsolute(srcpath))srcStat=await fs.stat(srcpath,{bigint:!0});else{let dstdir=path.dirname(dstpath),relativeToDst=path.join(dstdir,srcpath);try{srcStat=await fs.stat(relativeToDst,{bigint:!0})}catch{srcStat=await fs.stat(srcpath,{bigint:!0})}}let dstStat=await fs.stat(dstpath,{bigint:!0});if(areIdentical(srcStat,dstStat))return}let relative=await symlinkPaths(srcpath,dstpath);srcpath=relative.toDst;let toType=await symlinkType(relative.toCwd,type),dir=path.dirname(dstpath);return await pathExists(dir)||await mkdirs(dir),fs.symlink(srcpath,dstpath,toType)}function createSymlinkSync(srcpath,dstpath,type){let stats;try{stats=fs.lstatSync(dstpath)}catch{}if(stats&&stats.isSymbolicLink()){let srcStat;if(path.isAbsolute(srcpath))srcStat=fs.statSync(srcpath,{bigint:!0});else{let dstdir=path.dirname(dstpath),relativeToDst=path.join(dstdir,srcpath);try{srcStat=fs.statSync(relativeToDst,{bigint:!0})}catch{srcStat=fs.statSync(srcpath,{bigint:!0})}}let dstStat=fs.statSync(dstpath,{bigint:!0});if(areIdentical(srcStat,dstStat))return}let relative=symlinkPathsSync(srcpath,dstpath);srcpath=relative.toDst,type=symlinkTypeSync(relative.toCwd,type);let dir=path.dirname(dstpath);return fs.existsSync(dir)||mkdirsSync(dir),fs.symlinkSync(srcpath,dstpath,type)}module2.exports={createSymlink:u(createSymlink),createSymlinkSync}}});var require_ensure=__commonJS({"node_modules/fs-extra/lib/ensure/index.js"(exports2,module2){"use strict";var{createFile,createFileSync}=require_file(),{createLink,createLinkSync}=require_link(),{createSymlink,createSymlinkSync}=require_symlink();module2.exports={createFile,createFileSync,ensureFile:createFile,ensureFileSync:createFileSync,createLink,createLinkSync,ensureLink:createLink,ensureLinkSync:createLinkSync,createSymlink,createSymlinkSync,ensureSymlink:createSymlink,ensureSymlinkSync:createSymlinkSync}}});var require_utils2=__commonJS({"node_modules/jsonfile/utils.js"(exports2,module2){function stringify(obj,{EOL=`
15
- `,finalEOL=!0,replacer=null,spaces}={}){let EOF=finalEOL?EOL:"";return JSON.stringify(obj,replacer,spaces).replace(/\n/g,EOL)+EOF}function stripBom(content){return Buffer.isBuffer(content)&&(content=content.toString("utf8")),content.replace(/^\uFEFF/,"")}module2.exports={stringify,stripBom}}});var require_jsonfile=__commonJS({"node_modules/jsonfile/index.js"(exports2,module2){var _fs;try{_fs=require_graceful_fs()}catch{_fs=require("fs")}var universalify=require_universalify(),{stringify,stripBom}=require_utils2();async function _readFile(file,options={}){typeof options=="string"&&(options={encoding:options});let fs=options.fs||_fs,shouldThrow="throws"in options?options.throws:!0,data=await universalify.fromCallback(fs.readFile)(file,options);data=stripBom(data);let obj;try{obj=JSON.parse(data,options?options.reviver:null)}catch(err){if(shouldThrow)throw err.message=`${file}: ${err.message}`,err;return null}return obj}var readFile=universalify.fromPromise(_readFile);function readFileSync(file,options={}){typeof options=="string"&&(options={encoding:options});let fs=options.fs||_fs,shouldThrow="throws"in options?options.throws:!0;try{let content=fs.readFileSync(file,options);return content=stripBom(content),JSON.parse(content,options.reviver)}catch(err){if(shouldThrow)throw err.message=`${file}: ${err.message}`,err;return null}}async function _writeFile(file,obj,options={}){let fs=options.fs||_fs,str=stringify(obj,options);await universalify.fromCallback(fs.writeFile)(file,str,options)}var writeFile=universalify.fromPromise(_writeFile);function writeFileSync(file,obj,options={}){let fs=options.fs||_fs,str=stringify(obj,options);return fs.writeFileSync(file,str,options)}var jsonfile={readFile,readFileSync,writeFile,writeFileSync};module2.exports=jsonfile}});var require_jsonfile2=__commonJS({"node_modules/fs-extra/lib/json/jsonfile.js"(exports2,module2){"use strict";var jsonFile=require_jsonfile();module2.exports={readJson:jsonFile.readFile,readJsonSync:jsonFile.readFileSync,writeJson:jsonFile.writeFile,writeJsonSync:jsonFile.writeFileSync}}});var require_output_file=__commonJS({"node_modules/fs-extra/lib/output-file/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,fs=require_fs(),path=require("path"),mkdir=require_mkdirs(),pathExists=require_path_exists().pathExists;async function outputFile(file,data,encoding="utf-8"){let dir=path.dirname(file);return await pathExists(dir)||await mkdir.mkdirs(dir),fs.writeFile(file,data,encoding)}function outputFileSync(file,...args){let dir=path.dirname(file);fs.existsSync(dir)||mkdir.mkdirsSync(dir),fs.writeFileSync(file,...args)}module2.exports={outputFile:u(outputFile),outputFileSync}}});var require_output_json=__commonJS({"node_modules/fs-extra/lib/json/output-json.js"(exports2,module2){"use strict";var{stringify}=require_utils2(),{outputFile}=require_output_file();async function outputJson(file,data,options={}){let str=stringify(data,options);await outputFile(file,str,options)}module2.exports=outputJson}});var require_output_json_sync=__commonJS({"node_modules/fs-extra/lib/json/output-json-sync.js"(exports2,module2){"use strict";var{stringify}=require_utils2(),{outputFileSync}=require_output_file();function outputJsonSync(file,data,options){let str=stringify(data,options);outputFileSync(file,str,options)}module2.exports=outputJsonSync}});var require_json=__commonJS({"node_modules/fs-extra/lib/json/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,jsonFile=require_jsonfile2();jsonFile.outputJson=u(require_output_json());jsonFile.outputJsonSync=require_output_json_sync();jsonFile.outputJSON=jsonFile.outputJson;jsonFile.outputJSONSync=jsonFile.outputJsonSync;jsonFile.writeJSON=jsonFile.writeJson;jsonFile.writeJSONSync=jsonFile.writeJsonSync;jsonFile.readJSON=jsonFile.readJson;jsonFile.readJSONSync=jsonFile.readJsonSync;module2.exports=jsonFile}});var require_move=__commonJS({"node_modules/fs-extra/lib/move/move.js"(exports2,module2){"use strict";var fs=require_fs(),path=require("path"),{copy}=require_copy2(),{remove}=require_remove(),{mkdirp}=require_mkdirs(),{pathExists}=require_path_exists(),stat=require_stat();async function move(src,dest,opts={}){let overwrite=opts.overwrite||opts.clobber||!1,{srcStat,isChangingCase=!1}=await stat.checkPaths(src,dest,"move",opts);await stat.checkParentPaths(src,srcStat,dest,"move");let destParent=path.dirname(dest);return path.parse(destParent).root!==destParent&&await mkdirp(destParent),doRename(src,dest,overwrite,isChangingCase)}async function doRename(src,dest,overwrite,isChangingCase){if(!isChangingCase){if(overwrite)await remove(dest);else if(await pathExists(dest))throw new Error("dest already exists.")}try{await fs.rename(src,dest)}catch(err){if(err.code!=="EXDEV")throw err;await moveAcrossDevice(src,dest,overwrite)}}async function moveAcrossDevice(src,dest,overwrite){return await copy(src,dest,{overwrite,errorOnExist:!0,preserveTimestamps:!0}),remove(src)}module2.exports=move}});var require_move_sync=__commonJS({"node_modules/fs-extra/lib/move/move-sync.js"(exports2,module2){"use strict";var fs=require_graceful_fs(),path=require("path"),copySync=require_copy2().copySync,removeSync=require_remove().removeSync,mkdirpSync=require_mkdirs().mkdirpSync,stat=require_stat();function moveSync(src,dest,opts){opts=opts||{};let overwrite=opts.overwrite||opts.clobber||!1,{srcStat,isChangingCase=!1}=stat.checkPathsSync(src,dest,"move",opts);return stat.checkParentPathsSync(src,srcStat,dest,"move"),isParentRoot(dest)||mkdirpSync(path.dirname(dest)),doRename(src,dest,overwrite,isChangingCase)}function isParentRoot(dest){let parent=path.dirname(dest);return path.parse(parent).root===parent}function doRename(src,dest,overwrite,isChangingCase){if(isChangingCase)return rename(src,dest,overwrite);if(overwrite)return removeSync(dest),rename(src,dest,overwrite);if(fs.existsSync(dest))throw new Error("dest already exists.");return rename(src,dest,overwrite)}function rename(src,dest,overwrite){try{fs.renameSync(src,dest)}catch(err){if(err.code!=="EXDEV")throw err;return moveAcrossDevice(src,dest,overwrite)}}function moveAcrossDevice(src,dest,overwrite){return copySync(src,dest,{overwrite,errorOnExist:!0,preserveTimestamps:!0}),removeSync(src)}module2.exports=moveSync}});var require_move2=__commonJS({"node_modules/fs-extra/lib/move/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise;module2.exports={move:u(require_move()),moveSync:require_move_sync()}}});var require_lib=__commonJS({"node_modules/fs-extra/lib/index.js"(exports2,module2){"use strict";module2.exports={...require_fs(),...require_copy2(),...require_empty(),...require_ensure(),...require_json(),...require_mkdirs(),...require_move2(),...require_output_file(),...require_path_exists(),...require_remove()}}});var require_minimist=__commonJS({"node_modules/minimist/index.js"(exports2,module2){"use strict";function hasKey(obj,keys){var o=obj;keys.slice(0,-1).forEach(function(key2){o=o[key2]||{}});var key=keys[keys.length-1];return key in o}function isNumber(x){return typeof x=="number"||/^0x[0-9a-f]+$/i.test(x)?!0:/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)}function isConstructorOrProto(obj,key){return key==="constructor"&&typeof obj[key]=="function"||key==="__proto__"}module2.exports=function(args,opts){opts||(opts={});var flags={bools:{},strings:{},unknownFn:null};typeof opts.unknown=="function"&&(flags.unknownFn=opts.unknown),typeof opts.boolean=="boolean"&&opts.boolean?flags.allBools=!0:[].concat(opts.boolean).filter(Boolean).forEach(function(key2){flags.bools[key2]=!0});var aliases={};function aliasIsBoolean(key2){return aliases[key2].some(function(x){return flags.bools[x]})}Object.keys(opts.alias||{}).forEach(function(key2){aliases[key2]=[].concat(opts.alias[key2]),aliases[key2].forEach(function(x){aliases[x]=[key2].concat(aliases[key2].filter(function(y){return x!==y}))})}),[].concat(opts.string).filter(Boolean).forEach(function(key2){flags.strings[key2]=!0,aliases[key2]&&[].concat(aliases[key2]).forEach(function(k){flags.strings[k]=!0})});var defaults=opts.default||{},argv={_:[]};function argDefined(key2,arg2){return flags.allBools&&/^--[^=]+$/.test(arg2)||flags.strings[key2]||flags.bools[key2]||aliases[key2]}function setKey(obj,keys,value2){for(var o=obj,i2=0;i2<keys.length-1;i2++){var key2=keys[i2];if(isConstructorOrProto(o,key2))return;o[key2]===void 0&&(o[key2]={}),(o[key2]===Object.prototype||o[key2]===Number.prototype||o[key2]===String.prototype)&&(o[key2]={}),o[key2]===Array.prototype&&(o[key2]=[]),o=o[key2]}var lastKey=keys[keys.length-1];isConstructorOrProto(o,lastKey)||((o===Object.prototype||o===Number.prototype||o===String.prototype)&&(o={}),o===Array.prototype&&(o=[]),o[lastKey]===void 0||flags.bools[lastKey]||typeof o[lastKey]=="boolean"?o[lastKey]=value2:Array.isArray(o[lastKey])?o[lastKey].push(value2):o[lastKey]=[o[lastKey],value2])}function setArg(key2,val,arg2){if(!(arg2&&flags.unknownFn&&!argDefined(key2,arg2)&&flags.unknownFn(arg2)===!1)){var value2=!flags.strings[key2]&&isNumber(val)?Number(val):val;setKey(argv,key2.split("."),value2),(aliases[key2]||[]).forEach(function(x){setKey(argv,x.split("."),value2)})}}Object.keys(flags.bools).forEach(function(key2){setArg(key2,defaults[key2]===void 0?!1:defaults[key2])});var notFlags=[];args.indexOf("--")!==-1&&(notFlags=args.slice(args.indexOf("--")+1),args=args.slice(0,args.indexOf("--")));for(var i=0;i<args.length;i++){var arg=args[i],key,next;if(/^--.+=/.test(arg)){var m=arg.match(/^--([^=]+)=([\s\S]*)$/);key=m[1];var value=m[2];flags.bools[key]&&(value=value!=="false"),setArg(key,value,arg)}else if(/^--no-.+/.test(arg))key=arg.match(/^--no-(.+)/)[1],setArg(key,!1,arg);else if(/^--.+/.test(arg))key=arg.match(/^--(.+)/)[1],next=args[i+1],next!==void 0&&!/^(-|--)[^-]/.test(next)&&!flags.bools[key]&&!flags.allBools&&(!aliases[key]||!aliasIsBoolean(key))?(setArg(key,next,arg),i+=1):/^(true|false)$/.test(next)?(setArg(key,next==="true",arg),i+=1):setArg(key,flags.strings[key]?"":!0,arg);else if(/^-[^-]+/.test(arg)){for(var letters=arg.slice(1,-1).split(""),broken=!1,j=0;j<letters.length;j++){if(next=arg.slice(j+2),next==="-"){setArg(letters[j],next,arg);continue}if(/[A-Za-z]/.test(letters[j])&&next[0]==="="){setArg(letters[j],next.slice(1),arg),broken=!0;break}if(/[A-Za-z]/.test(letters[j])&&/-?\d+(\.\d*)?(e-?\d+)?$/.test(next)){setArg(letters[j],next,arg),broken=!0;break}if(letters[j+1]&&letters[j+1].match(/\W/)){setArg(letters[j],arg.slice(j+2),arg),broken=!0;break}else setArg(letters[j],flags.strings[letters[j]]?"":!0,arg)}key=arg.slice(-1)[0],!broken&&key!=="-"&&(args[i+1]&&!/^(-|--)[^-]/.test(args[i+1])&&!flags.bools[key]&&(!aliases[key]||!aliasIsBoolean(key))?(setArg(key,args[i+1],arg),i+=1):args[i+1]&&/^(true|false)$/.test(args[i+1])?(setArg(key,args[i+1]==="true",arg),i+=1):setArg(key,flags.strings[key]?"":!0,arg))}else if((!flags.unknownFn||flags.unknownFn(arg)!==!1)&&argv._.push(flags.strings._||!isNumber(arg)?arg:Number(arg)),opts.stopEarly){argv._.push.apply(argv._,args.slice(i+1));break}}return Object.keys(defaults).forEach(function(k){hasKey(argv,k.split("."))||(setKey(argv,k.split("."),defaults[k]),(aliases[k]||[]).forEach(function(x){setKey(argv,x.split("."),defaults[k])}))}),opts["--"]?argv["--"]=notFlags.slice():notFlags.forEach(function(k){argv._.push(k)}),argv}}});var require_utils3=__commonJS({"src/lib/utils.js"(exports2,module2){var fs=require("fs"),colors=require_safe(),path=require("path"),os=require("os"),net=require("net"),{spawnSync,spawn,execFile}=require("child_process"),getLogger=function(logFileDirPath){let options={flags:"a",encoding:"utf8"},output=fs.createWriteStream(path.resolve(logFileDirPath||path.resolve(process.cwd()),"./stdout.log"),options),errorOutput=fs.createWriteStream(path.resolve(logFileDirPath||path.resolve(process.cwd()),"./stderr.log"),options),logger2=new console.Console(output,errorOutput);return{log:(...args)=>logger2.log.call(null,`[${dateFormat("YYYY-mm-dd HH:MM:SS:fff")}] - `,...args),error:(...args)=>logger2.error.call(null,`[${dateFormat("YYYY-mm-dd HH:MM:SS:fff")}] - `,...args)}};function dateFormat(fmt,date=new Date){let ret,opt={"Y+":date.getFullYear().toString(),"m+":(date.getMonth()+1).toString(),"d+":date.getDate().toString(),"H+":date.getHours().toString(),"M+":date.getMinutes().toString(),"S+":date.getSeconds().toString(),"f+":date.getMilliseconds().toString()};for(let k in opt)ret=new RegExp("("+k+")").exec(fmt),ret&&(fmt=fmt.replace(ret[1],ret[1].length===1?opt[k]:opt[k].padStart(ret[1].length,"0")));return fmt}function logger(isSilent=!1){let logObj=null;return isSilent?logObj={info:function(){},assert:function(){}}:logObj={info:console.log,assert:console.assert},logObj}function isWindowsHiddenByAttrib(filePath){let result;try{result=spawnSync("attrib",[filePath],{encoding:"utf8",windowsHide:!0,timeout:5e3})}catch{return!1}if(result.error||result.status!==0)return!1;let line=String(result.stdout||"").split(/\r?\n/)[0]||"",pathStart=line.search(/[A-Za-z]:[\\/]|\\\\/);return(pathStart===-1?line:line.slice(0,pathStart)).toUpperCase().includes("H")}function isHiddenByNaming(filePath,platform){let name=path.basename(filePath);return name.startsWith(".")&&name!=="."&&name!==".."?!0:platform!=="win32"&&/(^|[\\/])\.[^\\/.]/.test(filePath)}function isHiddenPath(filePath){return typeof filePath!="string"||!filePath?!1:isHiddenByNaming(filePath,process.platform)?!0:process.platform==="win32"?isWindowsHiddenByAttrib(filePath):!1}var WINDOWS_HIDDEN_BULK_MIN=8,WINDOWS_HIDDEN_CACHE_TTL=5e3,windowsHiddenInFlight=new Map,windowsHiddenCache=new Map;function buildHiddenListingCommand(directory){return`[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;$d='${String(directory).replace(/'/g,"''")}';Get-ChildItem -LiteralPath $d -Force | ForEach-Object { $_.Name + [char]9 + [int](($_.Attributes -band [System.IO.FileAttributes]::Hidden) -ne 0) }`}function parseHiddenListingOutput(output){let hidden=new Set;for(let line of String(output||"").split(/\r?\n/)){if(!line)continue;let separator=line.indexOf(" ");separator<=0||line.slice(separator+1)==="1"&&hidden.add(line.slice(0,separator))}return hidden}function runWindowsHiddenListing(directory,execFileFn){return new Promise((resolve,reject)=>{execFileFn("powershell.exe",["-NoProfile","-NonInteractive","-Command",buildHiddenListingCommand(directory)],{encoding:"utf8",windowsHide:!0,timeout:15e3,maxBuffer:64*1024*1024},(error,stdout)=>error?reject(error):resolve(String(stdout||"")))})}async function getWindowsOsHiddenNames(directory,options){let cache=options.cache!==!1;if(cache){let cached=windowsHiddenCache.get(directory);if(cached&&cached.expires>Date.now())return cached.names;let inFlight=windowsHiddenInFlight.get(directory);if(inFlight)return inFlight}let execFileFn=options.execFile||execFile,promise=runWindowsHiddenListing(directory,execFileFn).then(output=>{let names=parseHiddenListingOutput(output);return cache&&windowsHiddenCache.set(directory,{names,expires:Date.now()+WINDOWS_HIDDEN_CACHE_TTL}),names}).finally(()=>{windowsHiddenInFlight.delete(directory)});return cache&&windowsHiddenInFlight.set(directory,promise),promise}async function getDirectoryHiddenNames(directory,names,options={}){let platform=options.platform||process.platform,hidden=new Set,candidates=[];for(let name of names){if(typeof name!="string"||!name)continue;let childPath=path.join(directory,name);isHiddenByNaming(childPath,platform)?hidden.add(name):candidates.push({name,childPath})}if(candidates.length===0||platform!=="win32")return hidden;if(candidates.length<=WINDOWS_HIDDEN_BULK_MIN){for(let{name,childPath}of candidates)isWindowsHiddenByAttrib(childPath)&&hidden.add(name);return hidden}let osHidden;try{osHidden=await getWindowsOsHiddenNames(directory,options)}catch{osHidden=null}if(osHidden)return osHidden.forEach(name=>hidden.add(name)),hidden;for(let{name,childPath}of candidates)isWindowsHiddenByAttrib(childPath)&&hidden.add(name);return hidden}function openPathInFileManager(fullPath,options={}){let platform=options.platform||process.platform,spawnFn=options.spawn||spawn,command,args;switch(platform){case"darwin":command="open",args=[fullPath];break;case"win32":command="explorer.exe",args=[fullPath];break;case"linux":command="xdg-open",args=[fullPath];break;default:return Promise.resolve({ok:!1,unsupported:!0,error:new Error("Unsupported platform")})}return new Promise(resolve=>{let child=spawnFn(command,args,{detached:!0,stdio:"ignore"}),settled=!1,done=result=>{settled||(settled=!0,resolve(result))};child.once("error",error=>done({ok:!1,unsupported:!1,error})),child.once("spawn",()=>{child.unref(),done({ok:!0,command,args})})})}var SupportMethods=["GET","POST","PUT","DELETE","HEAD","PATCH","OPTIONS","COPY","LINK","UNLINK","PURGE"],DefaultHeaders="Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Data-Type,X-Requested-With,X-Data-Type,X-Auth-Token,Token",isValidMethod=function(m){return SupportMethods.includes(String(m).toLocaleUpperCase())},getFileLatestContent=function(filePath){try{return delete require.cache[require.resolve(filePath)],require(path.resolve(process.cwd(),filePath))}catch(error){return console.error(colors.red("[error]:"),error),"getFileLatestContent_ERROR"}},filePath2ApiUrl=function(filePath){return filePath.split(path.sep).join("/")},getDataType=function(data){return Object.prototype.toString.call(data).slice(8,-1).toLowerCase()},isEmptyObj=function(obj){return getDataType(obj)==="object"&&Object.keys(obj).length===0},writeStream=function(filePath,data){return new Promise((resolve,reject)=>{let writerStream=fs.createWriteStream(filePath);writerStream.write(data,"utf-8"),writerStream.end(),writerStream.on("finish",()=>{}),writerStream.on("close",()=>{setTimeout(()=>{resolve(data)})}),writerStream.on("error",err=>{getLogger(path.resolve(process.cwd())).error(filePath,require.cache[require.resolve(filePath)],err),reject(err)})})},readStream=function(filePath){let data="";return new Promise((resovle,reject)=>{let readerStream=fs.createReadStream(filePath);readerStream.setEncoding("UTF8"),readerStream.on("data",function(chunk){data+=chunk}),readerStream.on("end",function(){resovle(data)}),readerStream.on("error",function(err){reject(err),console.log(err.stack)})})},debounce=(func,wait)=>{let timeout,canceled=!1,f=function(...args){canceled||(clearTimeout(timeout),timeout=setTimeout(()=>{func.call(this,...args)},wait))};return f.cancel=()=>{clearTimeout(timeout),canceled=!0},f},throttle=(func,wait,immediate)=>{let timeout,canceled=!1,lastCalledTime=0,f=function(...args){if(canceled)return;let now=Date.now(),call=()=>{lastCalledTime=now,func.call(this,...args)};if(lastCalledTime===0){if(immediate)return call();lastCalledTime=now;return}lastCalledTime+wait-now>0?(clearTimeout(timeout),timeout=setTimeout(()=>call(),wait)):call()};return f.cancel=()=>{clearTimeout(timeout),canceled=!0},f};function getServerHost(){return process.env.SERVER_HOST==="0.0.0.0"?"0.0.0.0":"127.0.0.1"}function normalizeRemoteAddress(address){let value=String(address||"").trim().replace(/^\[|\]$/g,"");return value.toLowerCase().startsWith("::ffff:")?value.slice(7):value}function ipToBigInt(address){let version=net.isIP(address);if(version===4)return address.split(".").reduce((value,part)=>(value<<8n)+BigInt(Number(part)),0n);if(version!==6)return null;let[head="",tail=""]=address.toLowerCase().split("::"),headParts=head?head.split(":"):[],tailParts=tail?tail.split(":"):[];return[...headParts,...Array(Math.max(0,8-headParts.length-tailParts.length)).fill("0"),...tailParts].reduce((value,part)=>(value<<16n)+BigInt(parseInt(part||"0",16)),0n)}function parseAllowlistRule(value){let[address,prefixValue]=value.split("/"),normalizedAddress=normalizeRemoteAddress(address),version=net.isIP(normalizedAddress),maxPrefix=version===4?32:128,prefix=prefixValue===void 0?maxPrefix:Number(prefixValue);return!version||!Number.isInteger(prefix)||prefix<0||prefix>maxPrefix?null:{address:normalizedAddress,version,prefix,value:ipToBigInt(normalizedAddress)}}function parseHostAllowlist(filePath){let content=fs.readFileSync(filePath,"utf8"),rules=[];if(content.split(/\r?\n/).forEach((rawLine,index)=>{let line=rawLine.trim();if(!line||line.startsWith("#"))return;let rule=parseAllowlistRule(line);if(!rule)throw new Error(`Invalid IP allowlist rule at line ${index+1}: ${rawLine}`);rules.push(rule)}),rules.length===0)throw new Error("IP allowlist must contain at least one valid IP or CIDR rule");return rules}function isLoopbackAddress(address){let normalized=normalizeRemoteAddress(address);return normalized==="127.0.0.1"||normalized==="::1"}function isAddressAllowed(address,rules=[]){let normalized=normalizeRemoteAddress(address);if(isLoopbackAddress(normalized))return!0;let version=net.isIP(normalized),value=ipToBigInt(normalized);return!version||value===null?!1:rules.some(rule=>{if(rule.version!==version)return!1;let remainingBits=BigInt((rule.version===4?32:128)-rule.prefix);return value>>remainingBits===rule.value>>remainingBits})}function getHostAllowlist(){if(!process.env.HOST_ALLOWLIST)return[];try{return JSON.parse(process.env.HOST_ALLOWLIST).map(rule=>typeof rule=="string"?parseAllowlistRule(rule):rule).filter(Boolean)}catch{return[]}}function hostAllowlistMiddleware(){let rules=getHostAllowlist();return rules.length===0?(req,res,next)=>next():(req,res,next)=>{if(!isAddressAllowed(req.socket&&req.socket.remoteAddress,rules))return res.status(403).send("Access denied by host allowlist");next()}}function getServerUrls(port,pathname=""){let normalizedPath=pathname&&pathname!=="/"?pathname:"",urls=[`http://localhost:${port}${normalizedPath}`,`http://127.0.0.1:${port}${normalizedPath}`];if(getServerHost()!=="0.0.0.0"||getHostAllowlist().length>0)return urls;let addresses=new Set(urls);return Object.values(os.networkInterfaces()).forEach(networkInterface=>{(networkInterface||[]).forEach(details=>{details.family==="IPv4"&&!details.internal&&addresses.add(`http://${details.address}:${port}${normalizedPath}`)})}),Array.from(addresses)}module2.exports={getLogger,dateFormat,logger,SupportMethods,DefaultHeaders,isValidMethod,getFileLatestContent,filePath2ApiUrl,getDataType,isEmptyObj,writeStream,readStream,debounce,throttle,getServerHost,getServerUrls,normalizeRemoteAddress,parseHostAllowlist,isAddressAllowed,getHostAllowlist,hostAllowlistMiddleware,isHiddenPath,getDirectoryHiddenNames,openPathInFileManager}}});var require_packageInfo=__commonJS({"src/lib/packageInfo.js"(exports2,module2){var{readFileSync}=require("fs"),path=require("path");function getPackageVersion(){let packagePaths=[path.resolve(__dirname,"../package.json"),path.resolve(__dirname,"../../package.json")];for(let packagePath of packagePaths)try{return JSON.parse(readFileSync(packagePath,"utf8")).version}catch{}return"unknown"}module2.exports={getPackageVersion}}});var require_mock_service_cli=__commonJS({"src/bin/mock-service-cli"(exports2){var colors=require_safe(),portfinder=require_portfinder(),{resolve}=require("path"),{existsSync}=require_lib(),argv=require_minimist()(process.argv.slice(2)),{logger,parseHostAllowlist}=require_utils3(),{getPackageVersion}=require_packageInfo(),spawn=require("child_process").spawn,node=process.execPath;process.title="mock-service-cli";(argv.h||argv.help)&&(console.log(["usage: mock-service-cli [options]","","PS: Mock File\u4EC5\u652F\u6301commonjs\u89C4\u8303\u7684js\u3001cjs\u6587\u4EF6\uFF0C\u4E0D\u652F\u6301ES Module","options:"," -p --port Mock server port to use. If 0, look for open port. [8090]"," -d Specify mock directory, default [./mock] directory,"," Also watch js files changes and support hot reload"," -f --file Specify the input data source, support javascript "," The priority is over the directory watches"," -s --silent Suppress log messages from output"," -S --socket-server Whether start socket server or not, default false."," -a --api-stat Whether print api url and file path or not, default false."," -t --track Whether record operation info by write file, default false."," -o --cors-origin Allow origin by cors, list separated by commas, must not be * when withCredential is true",' .If specified, cors-headers will be "Authorization,Content-Type,Accept,Origin,User-Agent,DNT',' ,Cache-Control,X-Mx-ReqToken,X-Data-Type,X-Requested-With,X-Data-Type,X-Auth-Token,Token", default *.'," -H --cors-headers When start Mock Server, optionally provide CORS headers list separated by commas. default *"," -A --append-headers When start Mock/Web/Static Server, optionally add response headers list separated by commas."," For example: X-Frame-options=DENY,content-security-policy=frame-ancestors",""," -O --proxy-options Optionally provide proxy options list separated by commas."," -r --rewrite rewrite http or https request url prefix of proxy, default false.",""," -D --web-dir Enable web server, specify web directory, default [./dist] directory"," -P --web-port Web server port to use. If 0, look for open port. [9090]"," -b --web-baseurl Specify website public path when enabled web server.",""," -R --static-server Specify static resource file directory when enabled static server."," --watch-depth <n> Limit static server watch recursion depth (non-negative integer)."," --watch-interval <n> Static server polling interval in milliseconds (Windows Node 24+ only)."," --no-watch Disable static server file watching and live reload."," --spa-fallback <path> Enable SPA fallback for -R mode using a root-relative HTML path."," --static-config <file> Self-contained static server configuration for root apps, mounts, proxy and fallback."," --host [file] Bind all web services to all IPv4 interfaces, or restrict them with an IP allowlist file."," --edit Enable file create, rename, and delete operations in file explorer."," --auth <password> Require a password for file explorer access.",""," -h --help Print this list and exit."," -v --version Print the version and exit."," -w --open Open the available web page/API overview automatically, default false."," -e --explorer Enable file explorer server, specify directory to browse, default [./]."].join(`
16
- `)),process.exit());argv.host!==void 0&&typeof argv.host!="boolean"&&typeof argv.host!="string"&&(console.error("--host must be a boolean flag or an IP allowlist file path"),process.exit(1));argv.edit!==void 0&&typeof argv.edit!="boolean"&&(console.error("--edit is a boolean flag"),process.exit(1));argv.auth!==void 0&&(typeof argv.auth!="string"||!argv.auth)&&(console.error("--auth requires a non-empty password string"),process.exit(1));argv.auth&&!(argv.e||argv.explorer)&&(console.error("--auth can only be used with --explorer"),process.exit(1));argv["static-config"]!==void 0&&(typeof argv["static-config"]!="string"||!argv["static-config"])&&(console.error("--static-config requires a JSON file path"),process.exit(1));var staticDirectoryArg=argv.R!==void 0?argv.R:argv["static-server"];staticDirectoryArg!==void 0&&staticDirectoryArg!==!0&&typeof staticDirectoryArg!="string"&&(console.error("-R/--static-server requires a directory path"),process.exit(1));argv["spa-fallback"]!==void 0&&(typeof argv["spa-fallback"]!="string"||!argv["spa-fallback"])&&(console.error("--spa-fallback requires a root-relative HTML path"),process.exit(1));if(argv["watch-depth"]!==void 0){let watchDepth=Number(argv["watch-depth"]);(!Number.isInteger(watchDepth)||watchDepth<0)&&(console.error("--watch-depth requires a non-negative integer"),process.exit(1)),process.env.WATCH_DEPTH=String(watchDepth)}if(argv["watch-interval"]!==void 0){let watchInterval=Number(argv["watch-interval"]);(typeof argv["watch-interval"]=="boolean"||!Number.isInteger(watchInterval)||watchInterval<1)&&(console.error("--watch-interval requires a positive integer"),process.exit(1)),process.env.WATCH_INTERVAL=String(watchInterval)}(argv.watch===!1||argv["no-watch"]===!0)&&(process.env.WATCH_ENABLED="false");argv["static-config"]&&typeof staticDirectoryArg=="string"&&(console.error("--static-config cannot be combined with -R <directory>"),process.exit(1));!argv["static-config"]&&staticDirectoryArg===!0&&(console.error("-R requires a directory path unless --static-config is provided"),process.exit(1));argv["static-config"]&&(argv.O||argv["proxy-options"]||argv.r||argv.rewrite)&&(console.error("--proxy-options/--rewrite cannot be used with --static-config"),process.exit(1));var hostAllowlist=[];if(typeof argv.host=="string"){let allowlistPath=resolve(process.cwd(),argv.host);existsSync(allowlistPath)||(console.error(`host allowlist file does not exist: ${allowlistPath}`),process.exit(1));try{hostAllowlist=parseHostAllowlist(allowlistPath).map(rule=>`${rule.address}/${rule.prefix}`)}catch(error){console.error(`Invalid host allowlist file: ${error.message}`),process.exit(1)}}var explorerAuthPassword=argv.auth;delete argv.auth;process.env.ARGV=JSON.stringify(argv);var port=argv.p||argv.port,watchDir=argv.d,specifiedFile=argv.f||argv.file,version=argv.v||argv.version,isStartSocketServer=argv.S||!1,rewrite=argv.r||argv.rewrite||!1,isOpenApiOverview=argv.w||argv.open||!1,explorerDir=argv.e||argv.explorer,log=null,managedServerProcess=null,managedServerShutdown=!1;!argv.s&&!argv.silent?log=logger(!1):colors&&(process.env.SILENT=!0,log=logger(!0));var injectEnvVariable=(envName,envArgs)=>{envArgs&&(process.env[envName]=envArgs)};function resolveServerEntry(fileName){let builtEntry=resolve(__dirname,`./${fileName}.js`);if(existsSync(builtEntry))return builtEntry;let sourceEntry=resolve(__dirname,`../lib/${fileName}.js`);return existsSync(sourceEntry)?sourceEntry:builtEntry}isStartSocketServer&&(process.env.SOCKET_SERVER=!0);isOpenApiOverview&&(process.env.OPEN_API_OVERVIEW=!0);version&&(log.info("v"+getPackageVersion()),process.exit());injectEnvVariable("PREFIX_REWRITE",rewrite);injectEnvVariable("CORS_ORIGIN",argv.o||argv["cors-origin"]);injectEnvVariable("CORS_HEADERS",argv.H||argv["cors-headers"]);injectEnvVariable("WEB_PUBLIC_PATH",argv.b||argv["web-baseurl"]);typeof staticDirectoryArg=="string"&&injectEnvVariable("STATIC_DIRECTORY",staticDirectoryArg);if(argv["static-config"]){let staticConfigPath=resolve(process.cwd(),argv["static-config"]);existsSync(staticConfigPath)||(console.error(`static-config: \u6587\u4EF6 ${staticConfigPath} \u4E0D\u5B58\u5728`),process.exit(1)),process.env.STATIC_CONFIG=staticConfigPath}injectEnvVariable("EXPLORER_DIRECTORY",explorerDir);process.env.SERVER_HOST=argv.host===!0||hostAllowlist.length>0?"0.0.0.0":"127.0.0.1";hostAllowlist.length>0&&(process.env.HOST_ALLOWLIST=JSON.stringify(hostAllowlist));process.env.EXPLORER_EDIT=argv.edit===!0?"true":"false";explorerAuthPassword&&(process.env.EXPLORER_AUTH=explorerAuthPassword);var proxyArg=argv.O||argv["proxy-options"];if(proxyArg){let proxyTable={};if(proxyArg.endsWith(".js")||proxyArg.endsWith(".json")){let proxyOptFile=resolve(process.cwd(),proxyArg);existsSync(proxyOptFile)||(console.error(`proxy-options: \u6587\u4EF6 ${proxyOptFile} \u4E0D\u5B58\u5728`),process.exit());let proxyObj=require(proxyOptFile);Object.keys(proxyObj).forEach(function(h){proxyTable[h]=proxyObj[h]},exports2)}else try{proxyArg.split(/\s*,\s*/).forEach(function(h){let[origin,target]=h.split("|");proxyTable[origin]=target},exports2)}catch(error){throw console.warn(colors.yellow(`
15
+ `,finalEOL=!0,replacer=null,spaces}={}){let EOF=finalEOL?EOL:"";return JSON.stringify(obj,replacer,spaces).replace(/\n/g,EOL)+EOF}function stripBom(content){return Buffer.isBuffer(content)&&(content=content.toString("utf8")),content.replace(/^\uFEFF/,"")}module2.exports={stringify,stripBom}}});var require_jsonfile=__commonJS({"node_modules/jsonfile/index.js"(exports2,module2){var _fs;try{_fs=require_graceful_fs()}catch{_fs=require("fs")}var universalify=require_universalify(),{stringify,stripBom}=require_utils2();async function _readFile(file,options={}){typeof options=="string"&&(options={encoding:options});let fs=options.fs||_fs,shouldThrow="throws"in options?options.throws:!0,data=await universalify.fromCallback(fs.readFile)(file,options);data=stripBom(data);let obj;try{obj=JSON.parse(data,options?options.reviver:null)}catch(err){if(shouldThrow)throw err.message=`${file}: ${err.message}`,err;return null}return obj}var readFile=universalify.fromPromise(_readFile);function readFileSync(file,options={}){typeof options=="string"&&(options={encoding:options});let fs=options.fs||_fs,shouldThrow="throws"in options?options.throws:!0;try{let content=fs.readFileSync(file,options);return content=stripBom(content),JSON.parse(content,options.reviver)}catch(err){if(shouldThrow)throw err.message=`${file}: ${err.message}`,err;return null}}async function _writeFile(file,obj,options={}){let fs=options.fs||_fs,str=stringify(obj,options);await universalify.fromCallback(fs.writeFile)(file,str,options)}var writeFile=universalify.fromPromise(_writeFile);function writeFileSync(file,obj,options={}){let fs=options.fs||_fs,str=stringify(obj,options);return fs.writeFileSync(file,str,options)}var jsonfile={readFile,readFileSync,writeFile,writeFileSync};module2.exports=jsonfile}});var require_jsonfile2=__commonJS({"node_modules/fs-extra/lib/json/jsonfile.js"(exports2,module2){"use strict";var jsonFile=require_jsonfile();module2.exports={readJson:jsonFile.readFile,readJsonSync:jsonFile.readFileSync,writeJson:jsonFile.writeFile,writeJsonSync:jsonFile.writeFileSync}}});var require_output_file=__commonJS({"node_modules/fs-extra/lib/output-file/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,fs=require_fs(),path=require("path"),mkdir=require_mkdirs(),pathExists=require_path_exists().pathExists;async function outputFile(file,data,encoding="utf-8"){let dir=path.dirname(file);return await pathExists(dir)||await mkdir.mkdirs(dir),fs.writeFile(file,data,encoding)}function outputFileSync(file,...args){let dir=path.dirname(file);fs.existsSync(dir)||mkdir.mkdirsSync(dir),fs.writeFileSync(file,...args)}module2.exports={outputFile:u(outputFile),outputFileSync}}});var require_output_json=__commonJS({"node_modules/fs-extra/lib/json/output-json.js"(exports2,module2){"use strict";var{stringify}=require_utils2(),{outputFile}=require_output_file();async function outputJson(file,data,options={}){let str=stringify(data,options);await outputFile(file,str,options)}module2.exports=outputJson}});var require_output_json_sync=__commonJS({"node_modules/fs-extra/lib/json/output-json-sync.js"(exports2,module2){"use strict";var{stringify}=require_utils2(),{outputFileSync}=require_output_file();function outputJsonSync(file,data,options){let str=stringify(data,options);outputFileSync(file,str,options)}module2.exports=outputJsonSync}});var require_json=__commonJS({"node_modules/fs-extra/lib/json/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise,jsonFile=require_jsonfile2();jsonFile.outputJson=u(require_output_json());jsonFile.outputJsonSync=require_output_json_sync();jsonFile.outputJSON=jsonFile.outputJson;jsonFile.outputJSONSync=jsonFile.outputJsonSync;jsonFile.writeJSON=jsonFile.writeJson;jsonFile.writeJSONSync=jsonFile.writeJsonSync;jsonFile.readJSON=jsonFile.readJson;jsonFile.readJSONSync=jsonFile.readJsonSync;module2.exports=jsonFile}});var require_move=__commonJS({"node_modules/fs-extra/lib/move/move.js"(exports2,module2){"use strict";var fs=require_fs(),path=require("path"),{copy}=require_copy2(),{remove}=require_remove(),{mkdirp}=require_mkdirs(),{pathExists}=require_path_exists(),stat=require_stat();async function move(src,dest,opts={}){let overwrite=opts.overwrite||opts.clobber||!1,{srcStat,isChangingCase=!1}=await stat.checkPaths(src,dest,"move",opts);await stat.checkParentPaths(src,srcStat,dest,"move");let destParent=path.dirname(dest);return path.parse(destParent).root!==destParent&&await mkdirp(destParent),doRename(src,dest,overwrite,isChangingCase)}async function doRename(src,dest,overwrite,isChangingCase){if(!isChangingCase){if(overwrite)await remove(dest);else if(await pathExists(dest))throw new Error("dest already exists.")}try{await fs.rename(src,dest)}catch(err){if(err.code!=="EXDEV")throw err;await moveAcrossDevice(src,dest,overwrite)}}async function moveAcrossDevice(src,dest,overwrite){return await copy(src,dest,{overwrite,errorOnExist:!0,preserveTimestamps:!0}),remove(src)}module2.exports=move}});var require_move_sync=__commonJS({"node_modules/fs-extra/lib/move/move-sync.js"(exports2,module2){"use strict";var fs=require_graceful_fs(),path=require("path"),copySync=require_copy2().copySync,removeSync=require_remove().removeSync,mkdirpSync=require_mkdirs().mkdirpSync,stat=require_stat();function moveSync(src,dest,opts){opts=opts||{};let overwrite=opts.overwrite||opts.clobber||!1,{srcStat,isChangingCase=!1}=stat.checkPathsSync(src,dest,"move",opts);return stat.checkParentPathsSync(src,srcStat,dest,"move"),isParentRoot(dest)||mkdirpSync(path.dirname(dest)),doRename(src,dest,overwrite,isChangingCase)}function isParentRoot(dest){let parent=path.dirname(dest);return path.parse(parent).root===parent}function doRename(src,dest,overwrite,isChangingCase){if(isChangingCase)return rename(src,dest,overwrite);if(overwrite)return removeSync(dest),rename(src,dest,overwrite);if(fs.existsSync(dest))throw new Error("dest already exists.");return rename(src,dest,overwrite)}function rename(src,dest,overwrite){try{fs.renameSync(src,dest)}catch(err){if(err.code!=="EXDEV")throw err;return moveAcrossDevice(src,dest,overwrite)}}function moveAcrossDevice(src,dest,overwrite){return copySync(src,dest,{overwrite,errorOnExist:!0,preserveTimestamps:!0}),removeSync(src)}module2.exports=moveSync}});var require_move2=__commonJS({"node_modules/fs-extra/lib/move/index.js"(exports2,module2){"use strict";var u=require_universalify().fromPromise;module2.exports={move:u(require_move()),moveSync:require_move_sync()}}});var require_lib=__commonJS({"node_modules/fs-extra/lib/index.js"(exports2,module2){"use strict";module2.exports={...require_fs(),...require_copy2(),...require_empty(),...require_ensure(),...require_json(),...require_mkdirs(),...require_move2(),...require_output_file(),...require_path_exists(),...require_remove()}}});var require_minimist=__commonJS({"node_modules/minimist/index.js"(exports2,module2){"use strict";function hasKey(obj,keys){var o=obj;keys.slice(0,-1).forEach(function(key2){o=o[key2]||{}});var key=keys[keys.length-1];return key in o}function isNumber(x){return typeof x=="number"||/^0x[0-9a-f]+$/i.test(x)?!0:/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)}function isConstructorOrProto(obj,key){return key==="constructor"&&typeof obj[key]=="function"||key==="__proto__"}module2.exports=function(args,opts){opts||(opts={});var flags={bools:{},strings:{},unknownFn:null};typeof opts.unknown=="function"&&(flags.unknownFn=opts.unknown),typeof opts.boolean=="boolean"&&opts.boolean?flags.allBools=!0:[].concat(opts.boolean).filter(Boolean).forEach(function(key2){flags.bools[key2]=!0});var aliases={};function aliasIsBoolean(key2){return aliases[key2].some(function(x){return flags.bools[x]})}Object.keys(opts.alias||{}).forEach(function(key2){aliases[key2]=[].concat(opts.alias[key2]),aliases[key2].forEach(function(x){aliases[x]=[key2].concat(aliases[key2].filter(function(y){return x!==y}))})}),[].concat(opts.string).filter(Boolean).forEach(function(key2){flags.strings[key2]=!0,aliases[key2]&&[].concat(aliases[key2]).forEach(function(k){flags.strings[k]=!0})});var defaults=opts.default||{},argv={_:[]};function argDefined(key2,arg2){return flags.allBools&&/^--[^=]+$/.test(arg2)||flags.strings[key2]||flags.bools[key2]||aliases[key2]}function setKey(obj,keys,value2){for(var o=obj,i2=0;i2<keys.length-1;i2++){var key2=keys[i2];if(isConstructorOrProto(o,key2))return;o[key2]===void 0&&(o[key2]={}),(o[key2]===Object.prototype||o[key2]===Number.prototype||o[key2]===String.prototype)&&(o[key2]={}),o[key2]===Array.prototype&&(o[key2]=[]),o=o[key2]}var lastKey=keys[keys.length-1];isConstructorOrProto(o,lastKey)||((o===Object.prototype||o===Number.prototype||o===String.prototype)&&(o={}),o===Array.prototype&&(o=[]),o[lastKey]===void 0||flags.bools[lastKey]||typeof o[lastKey]=="boolean"?o[lastKey]=value2:Array.isArray(o[lastKey])?o[lastKey].push(value2):o[lastKey]=[o[lastKey],value2])}function setArg(key2,val,arg2){if(!(arg2&&flags.unknownFn&&!argDefined(key2,arg2)&&flags.unknownFn(arg2)===!1)){var value2=!flags.strings[key2]&&isNumber(val)?Number(val):val;setKey(argv,key2.split("."),value2),(aliases[key2]||[]).forEach(function(x){setKey(argv,x.split("."),value2)})}}Object.keys(flags.bools).forEach(function(key2){setArg(key2,defaults[key2]===void 0?!1:defaults[key2])});var notFlags=[];args.indexOf("--")!==-1&&(notFlags=args.slice(args.indexOf("--")+1),args=args.slice(0,args.indexOf("--")));for(var i=0;i<args.length;i++){var arg=args[i],key,next;if(/^--.+=/.test(arg)){var m=arg.match(/^--([^=]+)=([\s\S]*)$/);key=m[1];var value=m[2];flags.bools[key]&&(value=value!=="false"),setArg(key,value,arg)}else if(/^--no-.+/.test(arg))key=arg.match(/^--no-(.+)/)[1],setArg(key,!1,arg);else if(/^--.+/.test(arg))key=arg.match(/^--(.+)/)[1],next=args[i+1],next!==void 0&&!/^(-|--)[^-]/.test(next)&&!flags.bools[key]&&!flags.allBools&&(!aliases[key]||!aliasIsBoolean(key))?(setArg(key,next,arg),i+=1):/^(true|false)$/.test(next)?(setArg(key,next==="true",arg),i+=1):setArg(key,flags.strings[key]?"":!0,arg);else if(/^-[^-]+/.test(arg)){for(var letters=arg.slice(1,-1).split(""),broken=!1,j=0;j<letters.length;j++){if(next=arg.slice(j+2),next==="-"){setArg(letters[j],next,arg);continue}if(/[A-Za-z]/.test(letters[j])&&next[0]==="="){setArg(letters[j],next.slice(1),arg),broken=!0;break}if(/[A-Za-z]/.test(letters[j])&&/-?\d+(\.\d*)?(e-?\d+)?$/.test(next)){setArg(letters[j],next,arg),broken=!0;break}if(letters[j+1]&&letters[j+1].match(/\W/)){setArg(letters[j],arg.slice(j+2),arg),broken=!0;break}else setArg(letters[j],flags.strings[letters[j]]?"":!0,arg)}key=arg.slice(-1)[0],!broken&&key!=="-"&&(args[i+1]&&!/^(-|--)[^-]/.test(args[i+1])&&!flags.bools[key]&&(!aliases[key]||!aliasIsBoolean(key))?(setArg(key,args[i+1],arg),i+=1):args[i+1]&&/^(true|false)$/.test(args[i+1])?(setArg(key,args[i+1]==="true",arg),i+=1):setArg(key,flags.strings[key]?"":!0,arg))}else if((!flags.unknownFn||flags.unknownFn(arg)!==!1)&&argv._.push(flags.strings._||!isNumber(arg)?arg:Number(arg)),opts.stopEarly){argv._.push.apply(argv._,args.slice(i+1));break}}return Object.keys(defaults).forEach(function(k){hasKey(argv,k.split("."))||(setKey(argv,k.split("."),defaults[k]),(aliases[k]||[]).forEach(function(x){setKey(argv,x.split("."),defaults[k])}))}),opts["--"]?argv["--"]=notFlags.slice():notFlags.forEach(function(k){argv._.push(k)}),argv}}});var require_utils3=__commonJS({"src/lib/utils.js"(exports2,module2){var fs=require("fs"),colors=require_safe(),path=require("path"),os=require("os"),net=require("net"),{spawnSync,spawn,execFile}=require("child_process"),getLogger=function(logFileDirPath){let options={flags:"a",encoding:"utf8"},output=fs.createWriteStream(path.resolve(logFileDirPath||path.resolve(process.cwd()),"./stdout.log"),options),errorOutput=fs.createWriteStream(path.resolve(logFileDirPath||path.resolve(process.cwd()),"./stderr.log"),options),logger2=new console.Console(output,errorOutput);return{log:(...args)=>logger2.log.call(null,`[${dateFormat("YYYY-mm-dd HH:MM:SS:fff")}] - `,...args),error:(...args)=>logger2.error.call(null,`[${dateFormat("YYYY-mm-dd HH:MM:SS:fff")}] - `,...args)}};function dateFormat(fmt,date=new Date){let ret,opt={"Y+":date.getFullYear().toString(),"m+":(date.getMonth()+1).toString(),"d+":date.getDate().toString(),"H+":date.getHours().toString(),"M+":date.getMinutes().toString(),"S+":date.getSeconds().toString(),"f+":date.getMilliseconds().toString()};for(let k in opt)ret=new RegExp("("+k+")").exec(fmt),ret&&(fmt=fmt.replace(ret[1],ret[1].length===1?opt[k]:opt[k].padStart(ret[1].length,"0")));return fmt}function logger(isSilent=!1){let logObj=null;return isSilent?logObj={info:function(){},assert:function(){}}:logObj={info:console.log,assert:console.assert},logObj}function parseAttribHidden(stdout){let line=String(stdout||"").split(/\r?\n/)[0]||"",pathStart=line.search(/[A-Za-z]:[\\/]|\\\\/);return(pathStart===-1?line:line.slice(0,pathStart)).toUpperCase().includes("H")}function isWindowsHiddenByAttrib(filePath){let result;try{result=spawnSync("attrib",[filePath],{encoding:"utf8",windowsHide:!0,timeout:5e3})}catch{return!1}return result.error||result.status!==0?!1:parseAttribHidden(result.stdout)}var WINDOWS_ATTRIB_CACHE_TTL=5e3,windowsAttribCache=new Map,windowsAttribInFlight=new Map;function isWindowsHiddenByAttribAsync(filePath,options){let cache=options.cache!==!1;if(cache){let cached=windowsAttribCache.get(filePath);if(cached&&cached.expires>Date.now())return Promise.resolve(cached.hidden);let inFlight=windowsAttribInFlight.get(filePath);if(inFlight)return inFlight}let execFileFn=options.attribExecFile||execFile,promise=new Promise(resolve=>{execFileFn("attrib",[filePath],{encoding:"utf8",windowsHide:!0,timeout:5e3},(error,stdout)=>resolve(!error&&parseAttribHidden(stdout)))}).then(hidden=>(cache&&windowsAttribCache.set(filePath,{hidden,expires:Date.now()+WINDOWS_ATTRIB_CACHE_TTL}),hidden));return promise.finally(()=>{windowsAttribInFlight.delete(filePath)}),cache&&windowsAttribInFlight.set(filePath,promise),promise}function isHiddenByNaming(filePath,platform){let name=path.basename(filePath);return name.startsWith(".")&&name!=="."&&name!==".."?!0:platform!=="win32"&&/(^|[\\/])\.[^\\/.]/.test(filePath)}function isHiddenPath(filePath){return typeof filePath!="string"||!filePath?!1:isHiddenByNaming(filePath,process.platform)?!0:process.platform==="win32"?isWindowsHiddenByAttrib(filePath):!1}var WINDOWS_HIDDEN_BULK_MIN=8,WINDOWS_HIDDEN_CACHE_TTL=5e3,windowsHiddenInFlight=new Map,windowsHiddenCache=new Map;function buildHiddenListingCommand(directory){return`[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;$d='${String(directory).replace(/'/g,"''")}';Get-ChildItem -LiteralPath $d -Force | ForEach-Object { $_.Name + [char]9 + [int](($_.Attributes -band [System.IO.FileAttributes]::Hidden) -ne 0) }`}function parseHiddenListingOutput(output){let hidden=new Set;for(let line of String(output||"").split(/\r?\n/)){if(!line)continue;let separator=line.indexOf(" ");separator<=0||line.slice(separator+1)==="1"&&hidden.add(line.slice(0,separator))}return hidden}function runWindowsHiddenListing(directory,execFileFn){return new Promise((resolve,reject)=>{execFileFn("powershell.exe",["-NoProfile","-NonInteractive","-Command",buildHiddenListingCommand(directory)],{encoding:"utf8",windowsHide:!0,timeout:15e3,maxBuffer:64*1024*1024},(error,stdout)=>error?reject(error):resolve(String(stdout||"")))})}async function getWindowsOsHiddenNames(directory,options){let cache=options.cache!==!1;if(cache){let cached=windowsHiddenCache.get(directory);if(cached&&cached.expires>Date.now())return cached.names;let inFlight=windowsHiddenInFlight.get(directory);if(inFlight)return inFlight}let execFileFn=options.execFile||execFile,promise=runWindowsHiddenListing(directory,execFileFn).then(output=>{let names=parseHiddenListingOutput(output);return cache&&windowsHiddenCache.set(directory,{names,expires:Date.now()+WINDOWS_HIDDEN_CACHE_TTL}),names}).finally(()=>{windowsHiddenInFlight.delete(directory)});return cache&&windowsHiddenInFlight.set(directory,promise),promise}async function getDirectoryHiddenNames(directory,names,options={}){let platform=options.platform||process.platform,hidden=new Set,candidates=[];for(let name of names){if(typeof name!="string"||!name)continue;let childPath=path.join(directory,name);isHiddenByNaming(childPath,platform)?hidden.add(name):candidates.push({name,childPath})}if(candidates.length===0||platform!=="win32"||options.osHidden===!1)return hidden;if(candidates.length<=WINDOWS_HIDDEN_BULK_MIN)return(await Promise.all(candidates.map(({childPath})=>isWindowsHiddenByAttribAsync(childPath,options)))).forEach((isHidden,index)=>{isHidden&&hidden.add(candidates[index].name)}),hidden;let osHidden;try{osHidden=await getWindowsOsHiddenNames(directory,options)}catch{osHidden=null}return osHidden?(osHidden.forEach(name=>hidden.add(name)),hidden):((await Promise.all(candidates.map(({childPath})=>isWindowsHiddenByAttribAsync(childPath,options)))).forEach((isHidden,index)=>{isHidden&&hidden.add(candidates[index].name)}),hidden)}function openPathInFileManager(fullPath,options={}){let platform=options.platform||process.platform,spawnFn=options.spawn||spawn,command,args;switch(platform){case"darwin":command="open",args=[fullPath];break;case"win32":command="explorer.exe",args=[fullPath];break;case"linux":command="xdg-open",args=[fullPath];break;default:return Promise.resolve({ok:!1,unsupported:!0,error:new Error("Unsupported platform")})}return new Promise(resolve=>{let child=spawnFn(command,args,{detached:!0,stdio:"ignore"}),settled=!1,done=result=>{settled||(settled=!0,resolve(result))};child.once("error",error=>done({ok:!1,unsupported:!1,error})),child.once("spawn",()=>{child.unref(),done({ok:!0,command,args})})})}var SupportMethods=["GET","POST","PUT","DELETE","HEAD","PATCH","OPTIONS","COPY","LINK","UNLINK","PURGE"],DefaultHeaders="Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Data-Type,X-Requested-With,X-Data-Type,X-Auth-Token,Token",isValidMethod=function(m){return SupportMethods.includes(String(m).toLocaleUpperCase())},getFileLatestContent=function(filePath){try{return delete require.cache[require.resolve(filePath)],require(path.resolve(process.cwd(),filePath))}catch(error){return console.error(colors.red("[error]:"),error),"getFileLatestContent_ERROR"}},filePath2ApiUrl=function(filePath){return filePath.split(path.sep).join("/")},getDataType=function(data){return Object.prototype.toString.call(data).slice(8,-1).toLowerCase()},isEmptyObj=function(obj){return getDataType(obj)==="object"&&Object.keys(obj).length===0},writeStream=function(filePath,data){return new Promise((resolve,reject)=>{let writerStream=fs.createWriteStream(filePath);writerStream.write(data,"utf-8"),writerStream.end(),writerStream.on("finish",()=>{}),writerStream.on("close",()=>{setTimeout(()=>{resolve(data)})}),writerStream.on("error",err=>{getLogger(path.resolve(process.cwd())).error(filePath,require.cache[require.resolve(filePath)],err),reject(err)})})},readStream=function(filePath){let data="";return new Promise((resovle,reject)=>{let readerStream=fs.createReadStream(filePath);readerStream.setEncoding("UTF8"),readerStream.on("data",function(chunk){data+=chunk}),readerStream.on("end",function(){resovle(data)}),readerStream.on("error",function(err){reject(err),console.log(err.stack)})})},debounce=(func,wait)=>{let timeout,canceled=!1,f=function(...args){canceled||(clearTimeout(timeout),timeout=setTimeout(()=>{func.call(this,...args)},wait))};return f.cancel=()=>{clearTimeout(timeout),canceled=!0},f},throttle=(func,wait,immediate)=>{let timeout,canceled=!1,lastCalledTime=0,f=function(...args){if(canceled)return;let now=Date.now(),call=()=>{lastCalledTime=now,func.call(this,...args)};if(lastCalledTime===0){if(immediate)return call();lastCalledTime=now;return}lastCalledTime+wait-now>0?(clearTimeout(timeout),timeout=setTimeout(()=>call(),wait)):call()};return f.cancel=()=>{clearTimeout(timeout),canceled=!0},f};function getServerHost(){return process.env.SERVER_HOST==="0.0.0.0"?"0.0.0.0":"127.0.0.1"}function normalizeRemoteAddress(address){let value=String(address||"").trim().replace(/^\[|\]$/g,"");return value.toLowerCase().startsWith("::ffff:")?value.slice(7):value}function ipToBigInt(address){let version=net.isIP(address);if(version===4)return address.split(".").reduce((value,part)=>(value<<8n)+BigInt(Number(part)),0n);if(version!==6)return null;let[head="",tail=""]=address.toLowerCase().split("::"),headParts=head?head.split(":"):[],tailParts=tail?tail.split(":"):[];return[...headParts,...Array(Math.max(0,8-headParts.length-tailParts.length)).fill("0"),...tailParts].reduce((value,part)=>(value<<16n)+BigInt(parseInt(part||"0",16)),0n)}function parseAllowlistRule(value){let[address,prefixValue]=value.split("/"),normalizedAddress=normalizeRemoteAddress(address),version=net.isIP(normalizedAddress),maxPrefix=version===4?32:128,prefix=prefixValue===void 0?maxPrefix:Number(prefixValue);return!version||!Number.isInteger(prefix)||prefix<0||prefix>maxPrefix?null:{address:normalizedAddress,version,prefix,value:ipToBigInt(normalizedAddress)}}function parseHostAllowlist(filePath){let content=fs.readFileSync(filePath,"utf8"),rules=[];if(content.split(/\r?\n/).forEach((rawLine,index)=>{let line=rawLine.trim();if(!line||line.startsWith("#"))return;let rule=parseAllowlistRule(line);if(!rule)throw new Error(`Invalid IP allowlist rule at line ${index+1}: ${rawLine}`);rules.push(rule)}),rules.length===0)throw new Error("IP allowlist must contain at least one valid IP or CIDR rule");return rules}function isLoopbackAddress(address){let normalized=normalizeRemoteAddress(address);return normalized==="127.0.0.1"||normalized==="::1"}function isAddressAllowed(address,rules=[]){let normalized=normalizeRemoteAddress(address);if(isLoopbackAddress(normalized))return!0;let version=net.isIP(normalized),value=ipToBigInt(normalized);return!version||value===null?!1:rules.some(rule=>{if(rule.version!==version)return!1;let remainingBits=BigInt((rule.version===4?32:128)-rule.prefix);return value>>remainingBits===rule.value>>remainingBits})}function getHostAllowlist(){if(!process.env.HOST_ALLOWLIST)return[];try{return JSON.parse(process.env.HOST_ALLOWLIST).map(rule=>typeof rule=="string"?parseAllowlistRule(rule):rule).filter(Boolean)}catch{return[]}}function hostAllowlistMiddleware(){let rules=getHostAllowlist();return rules.length===0?(req,res,next)=>next():(req,res,next)=>{if(!isAddressAllowed(req.socket&&req.socket.remoteAddress,rules))return res.status(403).send("Access denied by host allowlist");next()}}function getServerUrls(port,pathname=""){let normalizedPath=pathname&&pathname!=="/"?pathname:"",urls=[`http://localhost:${port}${normalizedPath}`,`http://127.0.0.1:${port}${normalizedPath}`];if(getServerHost()!=="0.0.0.0"||getHostAllowlist().length>0)return urls;let addresses=new Set(urls);return Object.values(os.networkInterfaces()).forEach(networkInterface=>{(networkInterface||[]).forEach(details=>{details.family==="IPv4"&&!details.internal&&addresses.add(`http://${details.address}:${port}${normalizedPath}`)})}),Array.from(addresses)}module2.exports={getLogger,dateFormat,logger,SupportMethods,DefaultHeaders,isValidMethod,getFileLatestContent,filePath2ApiUrl,getDataType,isEmptyObj,writeStream,readStream,debounce,throttle,getServerHost,getServerUrls,normalizeRemoteAddress,parseHostAllowlist,isAddressAllowed,getHostAllowlist,hostAllowlistMiddleware,isHiddenPath,getDirectoryHiddenNames,openPathInFileManager}}});var require_packageInfo=__commonJS({"src/lib/packageInfo.js"(exports2,module2){var{readFileSync}=require("fs"),path=require("path");function getPackageVersion(){let packagePaths=[path.resolve(__dirname,"../package.json"),path.resolve(__dirname,"../../package.json")];for(let packagePath of packagePaths)try{return JSON.parse(readFileSync(packagePath,"utf8")).version}catch{}return"unknown"}module2.exports={getPackageVersion}}});var require_mock_service_cli=__commonJS({"src/bin/mock-service-cli"(exports2){var colors=require_safe(),portfinder=require_portfinder(),{resolve}=require("path"),{existsSync}=require_lib(),argv=require_minimist()(process.argv.slice(2)),{logger,parseHostAllowlist}=require_utils3(),{getPackageVersion}=require_packageInfo(),spawn=require("child_process").spawn,node=process.execPath;process.title="mock-service-cli";(argv.h||argv.help)&&(console.log(["usage: mock-service-cli [options]","","PS: Mock File\u4EC5\u652F\u6301commonjs\u89C4\u8303\u7684js\u3001cjs\u6587\u4EF6\uFF0C\u4E0D\u652F\u6301ES Module","options:"," -p --port Mock server port to use. If 0, look for open port. [8090]"," -d Specify mock directory, default [./mock] directory,"," Also watch js files changes and support hot reload"," -f --file Specify the input data source, support javascript "," The priority is over the directory watches"," -s --silent Suppress log messages from output"," -S --socket-server Whether start socket server or not, default false."," -a --api-stat Whether print api url and file path or not, default false."," -t --track Whether record operation info by write file, default false."," -o --cors-origin Allow origin by cors, list separated by commas, must not be * when withCredential is true",' .If specified, cors-headers will be "Authorization,Content-Type,Accept,Origin,User-Agent,DNT',' ,Cache-Control,X-Mx-ReqToken,X-Data-Type,X-Requested-With,X-Data-Type,X-Auth-Token,Token", default *.'," -H --cors-headers When start Mock Server, optionally provide CORS headers list separated by commas. default *"," -A --append-headers When start Mock/Web/Static Server, optionally add response headers list separated by commas."," For example: X-Frame-options=DENY,content-security-policy=frame-ancestors",""," -O --proxy-options Optionally provide proxy options list separated by commas."," -r --rewrite rewrite http or https request url prefix of proxy, default false.",""," -D --web-dir Enable web server, specify web directory, default [./dist] directory"," -P --web-port Web server port to use. If 0, look for open port. [9090]"," -b --web-baseurl Specify website public path when enabled web server.",""," -R --static-server Specify static resource file directory when enabled static server."," --watch-depth <n> Limit static server watch recursion depth (non-negative integer)."," --watch-interval <n> Static server polling interval in milliseconds (Windows Node 24+ only)."," --no-watch Disable static server file watching and live reload."," --no-os-hidden Skip Windows OS hidden-attribute detection (dotfile names still hidden)."," --spa-fallback <path> Enable SPA fallback for -R mode using a root-relative HTML path."," --static-config <file> Self-contained static server configuration for root apps, mounts, proxy and fallback."," --host [file] Bind all web services to all IPv4 interfaces, or restrict them with an IP allowlist file."," --edit Enable file create, rename, and delete operations in file explorer."," --auth <password> Require a password for file explorer access.",""," -h --help Print this list and exit."," -v --version Print the version and exit."," -w --open Open the available web page/API overview automatically, default false."," -e --explorer Enable file explorer server, specify directory to browse, default [./]."].join(`
16
+ `)),process.exit());argv.host!==void 0&&typeof argv.host!="boolean"&&typeof argv.host!="string"&&(console.error("--host must be a boolean flag or an IP allowlist file path"),process.exit(1));argv.edit!==void 0&&typeof argv.edit!="boolean"&&(console.error("--edit is a boolean flag"),process.exit(1));argv.auth!==void 0&&(typeof argv.auth!="string"||!argv.auth)&&(console.error("--auth requires a non-empty password string"),process.exit(1));argv.auth&&!(argv.e||argv.explorer)&&(console.error("--auth can only be used with --explorer"),process.exit(1));argv["static-config"]!==void 0&&(typeof argv["static-config"]!="string"||!argv["static-config"])&&(console.error("--static-config requires a JSON file path"),process.exit(1));var staticDirectoryArg=argv.R!==void 0?argv.R:argv["static-server"];staticDirectoryArg!==void 0&&staticDirectoryArg!==!0&&typeof staticDirectoryArg!="string"&&(console.error("-R/--static-server requires a directory path"),process.exit(1));argv["spa-fallback"]!==void 0&&(typeof argv["spa-fallback"]!="string"||!argv["spa-fallback"])&&(console.error("--spa-fallback requires a root-relative HTML path"),process.exit(1));if(argv["watch-depth"]!==void 0){let watchDepth=Number(argv["watch-depth"]);(!Number.isInteger(watchDepth)||watchDepth<0)&&(console.error("--watch-depth requires a non-negative integer"),process.exit(1)),process.env.WATCH_DEPTH=String(watchDepth)}if(argv["watch-interval"]!==void 0){let watchInterval=Number(argv["watch-interval"]);(typeof argv["watch-interval"]=="boolean"||!Number.isInteger(watchInterval)||watchInterval<1)&&(console.error("--watch-interval requires a positive integer"),process.exit(1)),process.env.WATCH_INTERVAL=String(watchInterval)}(argv.watch===!1||argv["no-watch"]===!0)&&(process.env.WATCH_ENABLED="false");argv["os-hidden"]===!1&&(process.env.OS_HIDDEN_ENABLED="false");argv["static-config"]&&typeof staticDirectoryArg=="string"&&(console.error("--static-config cannot be combined with -R <directory>"),process.exit(1));!argv["static-config"]&&staticDirectoryArg===!0&&(console.error("-R requires a directory path unless --static-config is provided"),process.exit(1));argv["static-config"]&&(argv.O||argv["proxy-options"]||argv.r||argv.rewrite)&&(console.error("--proxy-options/--rewrite cannot be used with --static-config"),process.exit(1));var hostAllowlist=[];if(typeof argv.host=="string"){let allowlistPath=resolve(process.cwd(),argv.host);existsSync(allowlistPath)||(console.error(`host allowlist file does not exist: ${allowlistPath}`),process.exit(1));try{hostAllowlist=parseHostAllowlist(allowlistPath).map(rule=>`${rule.address}/${rule.prefix}`)}catch(error){console.error(`Invalid host allowlist file: ${error.message}`),process.exit(1)}}var explorerAuthPassword=argv.auth;delete argv.auth;process.env.ARGV=JSON.stringify(argv);var port=argv.p||argv.port,watchDir=argv.d,specifiedFile=argv.f||argv.file,version=argv.v||argv.version,isStartSocketServer=argv.S||!1,rewrite=argv.r||argv.rewrite||!1,isOpenApiOverview=argv.w||argv.open||!1,explorerDir=argv.e||argv.explorer,log=null,managedServerProcess=null,managedServerShutdown=!1;!argv.s&&!argv.silent?log=logger(!1):colors&&(process.env.SILENT=!0,log=logger(!0));var injectEnvVariable=(envName,envArgs)=>{envArgs&&(process.env[envName]=envArgs)};function resolveServerEntry(fileName){let builtEntry=resolve(__dirname,`./${fileName}.js`);if(existsSync(builtEntry))return builtEntry;let sourceEntry=resolve(__dirname,`../lib/${fileName}.js`);return existsSync(sourceEntry)?sourceEntry:builtEntry}isStartSocketServer&&(process.env.SOCKET_SERVER=!0);isOpenApiOverview&&(process.env.OPEN_API_OVERVIEW=!0);version&&(log.info("v"+getPackageVersion()),process.exit());injectEnvVariable("PREFIX_REWRITE",rewrite);injectEnvVariable("CORS_ORIGIN",argv.o||argv["cors-origin"]);injectEnvVariable("CORS_HEADERS",argv.H||argv["cors-headers"]);injectEnvVariable("WEB_PUBLIC_PATH",argv.b||argv["web-baseurl"]);typeof staticDirectoryArg=="string"&&injectEnvVariable("STATIC_DIRECTORY",staticDirectoryArg);if(argv["static-config"]){let staticConfigPath=resolve(process.cwd(),argv["static-config"]);existsSync(staticConfigPath)||(console.error(`static-config: \u6587\u4EF6 ${staticConfigPath} \u4E0D\u5B58\u5728`),process.exit(1)),process.env.STATIC_CONFIG=staticConfigPath}injectEnvVariable("EXPLORER_DIRECTORY",explorerDir);process.env.SERVER_HOST=argv.host===!0||hostAllowlist.length>0?"0.0.0.0":"127.0.0.1";hostAllowlist.length>0&&(process.env.HOST_ALLOWLIST=JSON.stringify(hostAllowlist));process.env.EXPLORER_EDIT=argv.edit===!0?"true":"false";explorerAuthPassword&&(process.env.EXPLORER_AUTH=explorerAuthPassword);var proxyArg=argv.O||argv["proxy-options"];if(proxyArg){let proxyTable={};if(proxyArg.endsWith(".js")||proxyArg.endsWith(".json")){let proxyOptFile=resolve(process.cwd(),proxyArg);existsSync(proxyOptFile)||(console.error(`proxy-options: \u6587\u4EF6 ${proxyOptFile} \u4E0D\u5B58\u5728`),process.exit());let proxyObj=require(proxyOptFile);Object.keys(proxyObj).forEach(function(h){proxyTable[h]=proxyObj[h]},exports2)}else try{proxyArg.split(/\s*,\s*/).forEach(function(h){let[origin,target]=h.split("|");proxyTable[origin]=target},exports2)}catch(error){throw console.warn(colors.yellow(`
17
17
  Parse web proxy options Failed:`,error)),error}process.env.PROXY_OPTIONS=JSON.stringify(proxyTable)}argv.D||argv["web-dir"]?(process.env.WEB_ROOT=resolve(process.cwd(),argv.D||argv["web-dir"]),existsSync(process.env.WEB_ROOT)||(console.error(`web-dir: \u76EE\u5F55 ${process.env.WEB_ROOT} \u4E0D\u5B58\u5728`),process.exit()),portfinder.basePort=argv.P||argv["web-port"]||9090,portfinder.getPort(function(err,webPort){if(err)throw err;process.env.WEB_PORT=webPort,portfinder.basePort=port||8090,portfinder.getPort(function(err2,port2){if(err2)throw err2;process.env.PORT=port2,initServe()})})):(portfinder.basePort=port||8090,portfinder.getPort(function(err,port2){if(err)throw err;process.env.PORT=port2,initServe()}));function watchMockFiles(watchDir2){let nodemon=require("nodemon");nodemon({script:resolveServerEntry("mockServer"),watch:[watchDir2],ext:"cjs,js,json"}),nodemon.on("start",function(){}).on("quit",function(){process.exit()}).on("restart",function(files){process.env.RESTARTED=!0,log.info([colors.green(`
18
18
  nodemon: mockServer restarted due to: `),files,colors.green(" have changed"),`
19
19
  `].join(""))})}function startManagedServer(fileName){managedServerProcess=spawn(node,[resolveServerEntry(fileName)],{stdio:"inherit"});let shutdown=signal=>{managedServerShutdown||(managedServerShutdown=!0,managedServerProcess.kill(signal))};process.once("SIGINT",()=>shutdown("SIGINT")),process.once("SIGTERM",()=>shutdown("SIGTERM")),managedServerProcess.once("exit",(code,signal)=>{managedServerShutdown&&process.exit(signal?1:code||0)}),managedServerProcess.once("error",error=>{console.error(colors.red(`Unable to start ${fileName}: ${error.message}`)),process.exit(1)})}function startMockServer(){startManagedServer("mockServer")}function startStaticServer(){startManagedServer("staticServer")}function startFileExplorerServer(){startManagedServer("fileExplorerServer")}function initServe(){explorerDir?(process.env.EXPLORER_DIRECTORY=resolve(process.cwd(),explorerDir),existsSync(process.env.EXPLORER_DIRECTORY)||(console.error(`explorer: \u76EE\u5F55 ${process.env.EXPLORER_DIRECTORY} \u4E0D\u5B58\u5728`),process.exit()),startFileExplorerServer()):specifiedFile?(process.env.SPECIFIED_FILE=resolve(process.cwd(),specifiedFile),isStartSocketServer?startMockServer():watchMockFiles(process.env.SPECIFIED_FILE)):watchDir?(process.env.SPECIFIED_DIR=resolve(process.cwd(),watchDir),isStartSocketServer?startMockServer():watchMockFiles(process.env.SPECIFIED_DIR)):process.env.STATIC_DIRECTORY||process.env.STATIC_CONFIG?(process.env.STATIC_DIRECTORY&&(process.env.STATIC_DIRECTORY=resolve(process.cwd(),process.env.STATIC_DIRECTORY)),startStaticServer()):(watchDir=process.env.SPECIFIED_DIR=resolve(process.cwd(),"./mock"),isStartSocketServer||(process.env.STATIC_DIRECTORY||process.env.WEB_ROOT)&&!existsSync(resolve(process.cwd(),watchDir))?startMockServer():watchMockFiles(watchDir))}}});var require_depd=__commonJS({"node_modules/depd/index.js"(exports2,module2){var relative=require("path").relative;module2.exports=depd;var basePath=process.cwd();function containsNamespace(str,namespace){for(var vals=str.split(/[ ,]+/),ns=String(namespace).toLowerCase(),i=0;i<vals.length;i++){var val=vals[i];if(val&&(val==="*"||val.toLowerCase()===ns))return!0}return!1}function convertDataDescriptorToAccessor(obj,prop,message){var descriptor=Object.getOwnPropertyDescriptor(obj,prop),value=descriptor.value;return descriptor.get=function(){return value},descriptor.writable&&(descriptor.set=function(val){return value=val}),delete descriptor.value,delete descriptor.writable,Object.defineProperty(obj,prop,descriptor),descriptor}function createArgumentsString(arity){for(var str="",i=0;i<arity;i++)str+=", arg"+i;return str.substr(2)}function createStackString(stack){var str=this.name+": "+this.namespace;this.message&&(str+=" deprecated "+this.message);for(var i=0;i<stack.length;i++)str+=`
@@ -132,7 +132,7 @@ ${process.env.RESTARTED?"Restarting":"Starting"} up mock-server, serving `),colo
132
132
  Opening API overview page...`));let openCommand;switch(process.platform){case"darwin":openCommand=`open ${apiOverviewUrl}`;break;case"win32":openCommand=`start ${apiOverviewUrl}`;break;case"linux":openCommand=`xdg-open ${apiOverviewUrl}`;break;default:console.warn(colors.yellow(`Could not automatically open browser. Please visit: ${apiOverviewUrl}`));return}exec(openCommand,error=>{error&&console.warn(colors.yellow(`Could not automatically open browser. Please visit: ${apiOverviewUrl}`))})}}),webApp&&!process.env.RESTARTED&&(webServer=webApp.listen(Number.parseInt(process.env.WEB_PORT,10),getServerHost(),()=>{if(console.info(colors.yellow(`
133
133
  Web server available on:
134
134
  `)),getServerUrls(process.env.WEB_PORT,webPublicPath).forEach(url=>{console.info(" "+url.replace(String(process.env.WEB_PORT),colors.green(process.env.WEB_PORT)))}),process.env.OPEN_API_OVERVIEW){let webUrl=`http://localhost:${process.env.WEB_PORT}${webPublicPath==="/"?"/":webPublicPath}`,command=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",args=process.platform==="win32"?["/c","start","",webUrl]:[webUrl],child=spawn(command,args,{detached:!0,stdio:"ignore"});child.once("error",()=>console.warn(colors.yellow(`Could not automatically open browser. Please visit: ${webUrl}`))),child.unref()}isEmptyObj(proxyTable)||(console.info(colors.yellow(`
135
- Enable proxy at web server on:`)),Object.keys(proxyTable).forEach(prefix=>{console.info(` ${prefix} -> ${proxyTable[prefix]}`)}))}))}function closeServer(server){return new Promise(resolve=>{if(!server||!server.listening)return resolve();server.close(()=>resolve()),typeof server.closeAllConnections=="function"&&server.closeAllConnections()})}async function shutdown(){if(!shuttingDown){shuttingDown=!0;try{socketServer?(await socketServer.close(),socketServer=null):await closeServer(httpServer),await closeServer(webServer)}finally{log.info(colors.red("mock-server process stopped.")),process.exit()}}}process.platform==="win32"&&require("readline").createInterface({input:process.stdin,output:process.stdout}).on("SIGINT",function(){process.emit("SIGINT")});process.once("SIGINT",shutdown);process.once("SIGTERM",shutdown);module2.exports={composeRouteFromJsFile,parseMockFiles}}});var require_staticServer=__commonJS({"src/lib/staticServer.js"(exports2,module2){var express=require_express2(),{closeSync,existsSync,lstatSync,openSync,promises:fsPromises,readFileSync,readSync}=require("fs"),path=require("path"),http=require("http"),https=require("https"),mime=require_mime(),{spawn}=require("child_process"),chokidar=require("chokidar"),{createProxyMiddleware}=require_dist(),colors=require_safe(),portfinder=require_portfinder(),{dateFormat,logger,getServerHost,getServerUrls,hostAllowlistMiddleware,getDirectoryHiddenNames}=require_utils3(),log=logger(process.env.SILENT),argv=JSON.parse(process.env.ARGV),LIVE_RELOAD_PATH="/__mock-service-cli/live-reload",LIVE_RELOAD_CLIENT_PATH="/__mock-service-cli/live-reload.js",STATIC_FAVICON_PATH="/__mock-service-cli/favicon.svg",TEXT_SAMPLE_SIZE=8192;function isPlainObject(value){return!!value&&typeof value=="object"&&!Array.isArray(value)}function detectTextCharset(filePath,stats){if(stats.size===0)return"utf-8";let buffer=Buffer.allocUnsafe(Math.min(stats.size,TEXT_SAMPLE_SIZE)),fileDescriptor;try{fileDescriptor=openSync(filePath,"r");let bytesRead=readSync(fileDescriptor,buffer,0,buffer.length,0),sample=buffer.subarray(0,bytesRead);if(sample[0]===255&&sample[1]===254)return"utf-16le";if(sample[0]===254&&sample[1]===255)return"utf-16be";for(let byte of sample)if(byte===0||byte<9||byte>13&&byte<32)return null;return new TextDecoder("utf-8",{fatal:!0}).decode(sample),"utf-8"}catch{return null}finally{fileDescriptor!==void 0&&closeSync(fileDescriptor)}}function setStaticHeaders(res,filePath,stats){res.setHeader("Content-Disposition","inline");let contentType=mime.lookup(filePath);if(!contentType||contentType==="application/octet-stream"){let charset=detectTextCharset(filePath,stats);charset&&res.setHeader("Content-Type",`text/plain; charset=${charset}`)}}function parseHeaderList(value){return typeof value!="string"?{}:value.split(/\s*,\s*/).reduce((headers,item)=>{let separator=item.indexOf("=");return separator<=0||(headers[item.slice(0,separator).trim()]=item.slice(separator+1).trim()),headers},{})}function parseProxyOptions(){if(!process.env.PROXY_OPTIONS)return{};try{let value=JSON.parse(process.env.PROXY_OPTIONS);return isPlainObject(value)?value:{}}catch(error){throw new Error(`Invalid proxy options: ${error.message}`)}}function normalizePublicPath(value,label,allowEmptyRoot){if(typeof value!="string")throw new Error(`${label} must be a path`);if(!value&&allowEmptyRoot)return"/";if(!value)throw new Error(`${label} must be a non-empty path`);let normalized="/"+value.replace(/^\/+|\/+$/g,"");if(normalized!=="/"&&(normalized.includes("..")||normalized.includes("?")||normalized.includes("#")))throw new Error(`${label} must be a root-relative path`);return normalized}function normalizeAccessLog(value,label,configDir){if(value===void 0)return null;if(!isPlainObject(value))throw new Error(`${label}.accessLog must be an object`);let accessLog={};if(["success","failure"].forEach(name=>{if(value[name]!==void 0){if(typeof value[name]!="string"||!value[name])throw new Error(`${label}.accessLog.${name} must be a file path`);accessLog[name]=path.resolve(configDir,value[name])}}),Object.keys(accessLog).length===0)throw new Error(`${label}.accessLog requires success or failure`);return accessLog}function normalizeRequestHeaders(value,label){if(value===void 0)return{};if(!isPlainObject(value))throw new Error(`${label} must be an object`);return Object.entries(value).reduce((headers,[name,headerValue])=>{if(!name||headerValue===null||typeof headerValue=="object")throw new Error(`${label}.${name} must be a primitive value`);return headers[name]=String(headerValue),headers},{})}function normalizeApplicationOptions(value,label,configDir){if(value.cors!==void 0&&typeof value.cors!="boolean")throw new Error(`${label}.cors must be boolean`);if(value.headers!==void 0&&!isPlainObject(value.headers))throw new Error(`${label}.headers must be an object`);if(value.secure!==void 0&&typeof value.secure!="boolean")throw new Error(`${label}.secure must be boolean`);return{cors:value.cors===!0,headers:isPlainObject(value.headers)?value.headers:{},secure:value.secure===!0,requestHeaders:normalizeRequestHeaders(value.requestHeaders,`${label}.requestHeaders`),accessLog:normalizeAccessLog(value.accessLog,label,configDir)}}function normalizeSpaFallback(value,directory,label){if(value===void 0||value===!1)return!1;if(typeof value!="string"||!value||!value.startsWith("/")||value.includes(".."))throw new Error(`${label} must be a root-relative path`);if(!directory)throw new Error(`${label} requires an application directory`);let fallbackPath=getStaticPath(directory,value);if(!fallbackPath||!/\.html?$/i.test(fallbackPath))throw new Error(`${label} does not exist: ${value}`);return value}function normalizeProxyTable(value,label,allowStringValues){if(value===void 0)return{};if(!isPlainObject(value))throw new Error(`${label} must be an object`);return Object.entries(value).reduce((table,[prefix,rule])=>{let normalizedPrefix=normalizePublicPath(prefix,`${label} route`);if(Object.prototype.hasOwnProperty.call(table,normalizedPrefix))throw new Error(`Duplicate proxy route: ${normalizedPrefix}`);let target=rule,rewrite=!1,requestHeaders={};if(isPlainObject(rule)){if(target=rule.target,rewrite=rule.rewrite===!0,requestHeaders=normalizeRequestHeaders(rule.requestHeaders,`${label}[${prefix}].requestHeaders`),rule.rewrite!==void 0&&typeof rule.rewrite!="boolean")throw new Error(`${label}[${prefix}].rewrite must be boolean`)}else if(!allowStringValues||typeof rule!="string")throw new Error(`${label}[${prefix}] must contain target and rewrite`);if(typeof target!="string"||!/^https?:\/\//.test(target))throw new Error(`Invalid proxy target for ${prefix}`);return table[normalizedPrefix]={target,rewrite,requestHeaders},table},{})}function hasPathPrefix(prefix,requestPath){return prefix==="/"||requestPath===prefix||requestPath.startsWith(`${prefix}/`)}function validateMountPaths(mounts){if(mounts.filter(mount=>mount.path==="/").length>1)throw new Error("mounts can only contain one root path");let nonRootMounts=mounts.filter(mount=>mount.path!=="/");nonRootMounts.forEach((mount,index)=>{nonRootMounts.forEach((other,otherIndex)=>{if(index!==otherIndex&&hasPathPrefix(mount.path,other.path))throw new Error(`mounts paths cannot overlap: ${mount.path} and ${other.path}`)})})}function isTransientWatchError(error){let code=error&&error.code;return["EBUSY","EPERM","EACCES","ENOENT","ENOTDIR"].includes(code)}function readWatchEnabledEnv(){if(process.env.WATCH_ENABLED!==void 0)return process.env.WATCH_ENABLED==="true"||process.env.WATCH_ENABLED==="1"}function normalizeConfig(){let defaults={open:!1,browser:"default",watch:{enabled:!0,ignore:["**/node_modules/**","**/.git/**"],delay:100,fullReload:!1,depth:void 0,interval:250},injectTag:"body",https:!1};if(process.env.WATCH_DEPTH!==void 0){let cliDepth=Number(process.env.WATCH_DEPTH);if(!Number.isInteger(cliDepth)||cliDepth<0)throw new Error("watch.depth must be a non-negative integer")}if(process.env.WATCH_INTERVAL!==void 0){let cliInterval=Number(process.env.WATCH_INTERVAL);if(!Number.isInteger(cliInterval)||cliInterval<1)throw new Error("watch.interval must be a positive integer")}let cliWatchEnabled=readWatchEnabledEnv(),cliWatchInterval=process.env.WATCH_INTERVAL===void 0?void 0:Number(process.env.WATCH_INTERVAL),cliDirectory=process.env.STATIC_DIRECTORY?path.resolve(process.env.STATIC_DIRECTORY):null;if(process.env.STATIC_CONFIG&&argv["spa-fallback"]!==void 0)throw new Error("--spa-fallback cannot be used with --static-config");let cliSpaFallback=process.env.STATIC_CONFIG?!1:normalizeSpaFallback(argv["spa-fallback"],cliDirectory,"spaFallback");if(!process.env.STATIC_CONFIG){if(!cliDirectory)throw new Error("Static server requires -R <directory> or --static-config <file>");if(!existsSync(cliDirectory)||!lstatSync(cliDirectory).isDirectory())throw new Error(`static-server: directory does not exist: ${cliDirectory}`);let cliProxy=normalizeProxyTable(parseProxyOptions(),"proxy",!0);return(argv.r||argv.rewrite)&&Object.values(cliProxy).forEach(rule=>rule.rewrite=!0),{...defaults,open:process.env.OPEN_API_OVERVIEW?!0:defaults.open,watch:{...defaults.watch,enabled:cliWatchEnabled===void 0?defaults.watch.enabled:cliWatchEnabled,interval:cliWatchInterval===void 0?defaults.watch.interval:cliWatchInterval,depth:process.env.WATCH_DEPTH===void 0?void 0:Number(process.env.WATCH_DEPTH)},configDir:process.cwd(),mounts:[{path:"/",directory:cliDirectory,spaFallback:cliSpaFallback,proxy:cliProxy,cors:!1,headers:{},secure:!1,requestHeaders:{},accessLog:null}]}}let configPath=path.resolve(process.env.STATIC_CONFIG),supplied;try{supplied=JSON.parse(readFileSync(configPath,"utf8"))}catch(error){throw new Error(`Unable to read static config: ${error.message}`)}if(!isPlainObject(supplied))throw new Error("Static config must contain a JSON object");let configDir=path.dirname(configPath),watch=isPlainObject(supplied.watch)?supplied.watch:{};if(watch.enabled!==void 0&&typeof watch.enabled!="boolean")throw new Error("watch.enabled must be boolean");if(watch.interval!==void 0&&(!Number.isInteger(watch.interval)||watch.interval<1))throw new Error("watch.interval must be a positive integer");let depthValue=process.env.WATCH_DEPTH!==void 0?Number(process.env.WATCH_DEPTH):watch.depth;if(depthValue!==void 0&&(!Number.isInteger(depthValue)||depthValue<0))throw new Error("watch.depth must be a non-negative integer");let enabledValue=cliWatchEnabled===void 0?watch.enabled===void 0?defaults.watch.enabled:watch.enabled:cliWatchEnabled,intervalValue=cliWatchInterval===void 0?watch.interval===void 0?defaults.watch.interval:watch.interval:cliWatchInterval;if(process.env.PROXY_OPTIONS)throw new Error("--proxy-options/--rewrite cannot be used with --static-config");let suppliedRootField=["directory","spaFallback","proxy","cors","headers","secure","requestHeaders","accessLog"].find(field=>supplied[field]!==void 0);if(suppliedRootField)throw new Error(`${suppliedRootField} must be declared on a mount in static config`);let mounts=supplied.mounts===void 0?[]:supplied.mounts;if(!Array.isArray(mounts))throw new Error("mounts must be an array");if(mounts.length===0)throw new Error("Static config requires at least one mount");let normalizedMounts=mounts.map((mount,index)=>{if(!isPlainObject(mount))throw new Error(`mounts[${index}] must be an object`);let mountPath=mount.path===void 0?"/":normalizePublicPath(mount.path,`mounts[${index}].path`,!0);if(mount.directory!==void 0&&typeof mount.directory!="string")throw new Error(`mounts[${index}].directory must be a string`);let directory=mount.directory===void 0?null:path.resolve(configDir,mount.directory);if(directory&&(!existsSync(directory)||!lstatSync(directory).isDirectory()))throw new Error(`Mount directory does not exist: ${directory}`);let normalizedMount={path:mountPath,directory,spaFallback:normalizeSpaFallback(mount.spaFallback,directory,`mounts[${index}].spaFallback`),proxy:normalizeProxyTable(mount.proxy,`mounts[${index}].proxy`,!1),...normalizeApplicationOptions(mount,`mounts[${index}]`,configDir)};if(!normalizedMount.directory&&Object.keys(normalizedMount.proxy).length===0)throw new Error(`mounts[${index}] requires directory or proxy`);if(normalizedMount.accessLog&&!normalizedMount.spaFallback)throw new Error(`mounts[${index}].accessLog requires spaFallback`);return normalizedMount});validateMountPaths(normalizedMounts);let httpsConfig=supplied.https,normalizedHttps=!1;if(httpsConfig===!0)throw new Error("https requires cert and key paths");if(isPlainObject(httpsConfig)&&httpsConfig.enable!==!1){if(typeof httpsConfig.cert!="string"||typeof httpsConfig.key!="string")throw new Error("https requires cert and key paths");normalizedHttps={cert:path.resolve(configDir,httpsConfig.cert),key:path.resolve(configDir,httpsConfig.key),passphrase:typeof httpsConfig.passphrase=="string"?httpsConfig.passphrase:void 0}}return{...defaults,open:process.env.OPEN_API_OVERVIEW?supplied.open||!0:supplied.open===void 0?defaults.open:supplied.open,browser:supplied.browser===void 0?defaults.browser:supplied.browser,configDir,watch:{enabled:enabledValue,ignore:Array.isArray(watch.ignore)?watch.ignore:defaults.watch.ignore,delay:Number.isFinite(watch.delay)&&watch.delay>=0?watch.delay:defaults.watch.delay,fullReload:watch.fullReload===!0,depth:depthValue,interval:intervalValue},injectTag:supplied.injectTag==="head"?"head":"body",mounts:normalizedMounts,https:normalizedHttps}}function getStaticPath(root,requestPath){let pathname;try{pathname=decodeURIComponent(requestPath)}catch{return null}let candidate=path.resolve(root,`.${pathname}`),relative=path.relative(root,candidate);return relative.startsWith("..")||path.isAbsolute(relative)||!existsSync(candidate)||lstatSync(candidate).isDirectory()?null:candidate}function getStaticDirectory(root,requestPath){let pathname;try{pathname=decodeURIComponent(requestPath)}catch{return null}let candidate=path.resolve(root,`.${pathname}`),relative=path.relative(root,candidate);return relative.startsWith("..")||path.isAbsolute(relative)||!existsSync(candidate)?null:lstatSync(candidate).isDirectory()?candidate:null}function escapeHtml(value){return String(value).replace(/[&<>"']/g,character=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[character])}function joinPublicPath(basePath,localPath){return basePath==="/"?localPath:`${basePath}${localPath==="/"?"/":localPath}`.replace(/\/+/g,"/")}async function getDirectoryIndexData(directoryPath,requestPath,showHidden,basePath){let entries=await fsPromises.readdir(directoryPath,{withFileTypes:!0}),hiddenNames=await getDirectoryHiddenNames(directoryPath,entries.map(entry=>entry.name)),visibleEntries=entries.map(entry=>({entry,hidden:hiddenNames.has(entry.name)})).filter(item=>showHidden||!item.hidden);visibleEntries.sort((left,right)=>left.entry.isDirectory()!==right.entry.isDirectory()?left.entry.isDirectory()?-1:1:left.entry.name.localeCompare(right.entry.name));let decodedPath=decodeURIComponent(requestPath),normalizedPath=decodedPath==="/"?"/":`/${decodedPath.replace(/^\/+|\/+$/g,"")}/`,parentPath=normalizedPath==="/"?null:normalizedPath.split("/").slice(0,-2).join("/")||"/";return{currentPath:normalizedPath,parentPath,basePath,showHidden,entries:visibleEntries.map(({entry,hidden})=>({name:entry.name,isDirectory:entry.isDirectory(),isHidden:hidden}))}}function encodeDirectoryPath(directoryPath){return directoryPath==="/"?"/":`/${directoryPath.split("/").filter(Boolean).map(segment=>encodeURIComponent(segment)).join("/")}/`}function renderDirectoryIndex(data){let normalizedPath=data.currentPath,publicCurrentPath=joinPublicPath(data.basePath,normalizedPath),publicParentPath=data.parentPath?joinPublicPath(data.basePath,data.parentPath):null,encodedDirectoryPath=encodeDirectoryPath(publicCurrentPath),encodedApplicationRootPath=encodeDirectoryPath(joinPublicPath(data.basePath,"/")),withVisibility=url=>data.showHidden?`${url}?showHidden=1`:url,breadcrumbParts=normalizedPath.split("/").filter(Boolean),breadcrumbPath="",breadcrumb=[`<a href="${withVisibility(encodedApplicationRootPath)}">\u6839\u76EE\u5F55</a>`,...breadcrumbParts.map(part=>(breadcrumbPath+=`/${part}`,`<a href="${withVisibility(encodeDirectoryPath(joinPublicPath(data.basePath,breadcrumbPath)))}">${escapeHtml(part)}</a>`))].join('<span aria-hidden="true"> / </span>'),items=data.entries.map(entry=>{let suffix=entry.isDirectory?"/":"",href=`${encodedDirectoryPath}${encodeURIComponent(entry.name)}${suffix}`.replace(/\/+/g,"/"),target=entry.isDirectory?withVisibility(href):href;return`<li${entry.isHidden?' class="is-hidden"':""}><a href="${target}">${entry.isDirectory?"\u{1F4C1}":"\u{1F4C4}"} ${escapeHtml(entry.name)}${suffix}</a></li>`}).join(""),parent=data.parentPath?`<p id="directoryParent"><a href="${withVisibility(encodeDirectoryPath(publicParentPath))}">\u2190 \u8FD4\u56DE\u4E0A\u7EA7</a></p>`:'<p id="directoryParent" hidden></p>',visibilityToggle=`<a class="visibility-toggle" href="${data.showHidden?encodedDirectoryPath:`${encodedDirectoryPath}?showHidden=1`}">${data.showHidden?"\u9690\u85CF\u9690\u85CF\u9879\u76EE":"\u663E\u793A\u9690\u85CF\u9879\u76EE"}</a>`;return`<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><link rel="icon" type="image/svg+xml" href="${STATIC_FAVICON_PATH}"><title>\u76EE\u5F55\u7D22\u5F15 ${escapeHtml(publicCurrentPath)}</title><style>body{font:14px system-ui,sans-serif;margin:32px;max-width:900px}a{color:#2563eb;text-decoration:none}a:hover{text-decoration:underline}.directory-header{display:flex;align-items:center;gap:12px;margin:12px 0;flex-wrap:wrap}.directory-header h1{font-size:20px;margin:0}.directory-header nav{color:#4b5563;min-width:0;flex:1;overflow-wrap:anywhere}.directory-header nav span{padding:0 5px;color:#9ca3af}.visibility-toggle{color:#374151;border:1px solid #d1d5db;border-radius:4px;background:#f9fafb;padding:5px 8px;white-space:nowrap}.visibility-toggle:hover{background:#f3f4f6;text-decoration:none}.is-hidden{opacity:.55}ul{list-style:none;padding:0}li{padding:7px 0;border-bottom:1px solid #eee}</style></head><body><header class="directory-header"><h1>\u76EE\u5F55\u7D22\u5F15</h1><nav aria-label="\u8DEF\u5F84\u5BFC\u822A">${breadcrumb}</nav>${visibilityToggle}</header>${parent}<ul>${items||"<li>\uFF08\u7A7A\u76EE\u5F55\uFF09</li>"}</ul></body></html>`}function getLiveReloadClient(config){let delay=JSON.stringify(config.watch.delay),fullReload=JSON.stringify(config.watch.fullReload);return`(function(){const delay=${delay};const fullReload=${fullReload};let source;let timer;const dispose=function(){clearTimeout(timer);if(source){source.close();source=null}};const connect=function(){if(source)return;source=new EventSource('${LIVE_RELOAD_PATH}');source.onmessage=function(event){let change;try{change=JSON.parse(event.data)}catch(_){return}clearTimeout(timer);timer=setTimeout(function(){if(!fullReload&&change.type==='css'){const target=new URL(change.path,location.href).pathname;let updated=false;document.querySelectorAll('link[rel~="stylesheet"][href]').forEach(function(link){if(new URL(link.href,location.href).pathname===target){const url=new URL(link.href,location.href);url.searchParams.set('mock-service-cli-reload',Date.now());link.href=url.href;updated=true}});if(updated)return}location.reload()},delay)}};window.addEventListener('pagehide',dispose);window.addEventListener('pageshow',connect);connect()})();`}function injectLiveReload(html,config){if(!/<link\b[^>]*\brel\s*=\s*["'][^"']*\bicon\b[^"']*["'][^>]*>/i.test(html)){let favicon=`<link rel="icon" type="image/svg+xml" href="${STATIC_FAVICON_PATH}">`,headIndex=html.toLowerCase().lastIndexOf("</head>");html=headIndex===-1?`${favicon}${html}`:`${html.slice(0,headIndex)}${favicon}${html.slice(headIndex)}`}if(config.watch.enabled===!1)return html;let script=`<script src="${LIVE_RELOAD_CLIENT_PATH}" data-mock-service-cli-live-reload="true"></script>`,closingTag=config.injectTag==="head"?"</head>":"</body>",index=html.toLowerCase().lastIndexOf(closingTag);return index===-1?`${html}${script}`:`${html.slice(0,index)}${script}${html.slice(index)}`}function openBrowser(url,browser){if(!browser||browser===!1)return;let command,args;if(isPlainObject(browser)){if(typeof browser.command!="string"||!browser.command)return;command=browser.command,args=Array.isArray(browser.args)?browser.args.map(String):[],args.push(url)}else browser!=="default"?(command=String(browser),args=[url]):process.platform==="darwin"?(command="open",args=[url]):process.platform==="win32"?(command="cmd",args=["/c","start","",url]):(command="xdg-open",args=[url]);spawn(command,args,{detached:!0,stdio:"ignore"}).unref()}function createStaticServer(config){let app=express(),cliHeaders=parseHeaderList(argv.A||argv["append-headers"]),clients=new Set,watchers=[],pendingChanges=[],reloadTimer=null,closing=!1,pendingLogWrites=new Set,applications=config.mounts.map(mount=>({...mount,basePath:mount.path})),rootApplication=applications.find(application=>application.basePath==="/"&&application.directory),root=rootApplication?rootApplication.directory:null;app.use(hostAllowlistMiddleware()),app.use((req,res,next)=>{Object.entries(cliHeaders).forEach(([key,value])=>res.setHeader(key,String(value))),next()});function applyApplicationOptions(application){return(req,res,next)=>(Object.entries({...application.headers,...cliHeaders}).forEach(([key,value])=>res.setHeader(key,String(value))),application.cors&&(res.setHeader("Access-Control-Allow-Origin","*"),res.setHeader("Access-Control-Allow-Methods","GET,HEAD,OPTIONS"),res.setHeader("Access-Control-Allow-Headers","*"),req.method==="OPTIONS")?res.status(204).end():next())}function writeAccessLog(application,req,res){if(!application.accessLog)return;let logFile=res.statusCode>=400?application.accessLog.failure:application.accessLog.success;if(!logFile)return;let entry=`${JSON.stringify({timestamp:new Date().toISOString(),application:application.basePath,method:req.method,url:req.originalUrl||req.url,status:res.statusCode})}
135
+ Enable proxy at web server on:`)),Object.keys(proxyTable).forEach(prefix=>{console.info(` ${prefix} -> ${proxyTable[prefix]}`)}))}))}function closeServer(server){return new Promise(resolve=>{if(!server||!server.listening)return resolve();server.close(()=>resolve()),typeof server.closeAllConnections=="function"&&server.closeAllConnections()})}async function shutdown(){if(!shuttingDown){shuttingDown=!0;try{socketServer?(await socketServer.close(),socketServer=null):await closeServer(httpServer),await closeServer(webServer)}finally{log.info(colors.red("mock-server process stopped.")),process.exit()}}}process.platform==="win32"&&require("readline").createInterface({input:process.stdin,output:process.stdout}).on("SIGINT",function(){process.emit("SIGINT")});process.once("SIGINT",shutdown);process.once("SIGTERM",shutdown);module2.exports={composeRouteFromJsFile,parseMockFiles}}});var require_staticServer=__commonJS({"src/lib/staticServer.js"(exports2,module2){var express=require_express2(),{closeSync,existsSync,lstatSync,openSync,promises:fsPromises,readFileSync,readSync}=require("fs"),path=require("path"),http=require("http"),https=require("https"),mime=require_mime(),{spawn}=require("child_process"),chokidar=require("chokidar"),{createProxyMiddleware}=require_dist(),colors=require_safe(),portfinder=require_portfinder(),{dateFormat,logger,getServerHost,getServerUrls,hostAllowlistMiddleware,getDirectoryHiddenNames}=require_utils3(),log=logger(process.env.SILENT),argv=JSON.parse(process.env.ARGV),osHiddenEnabled=process.env.OS_HIDDEN_ENABLED!=="false"&&process.env.OS_HIDDEN_ENABLED!=="0",LIVE_RELOAD_PATH="/__mock-service-cli/live-reload",LIVE_RELOAD_CLIENT_PATH="/__mock-service-cli/live-reload.js",STATIC_FAVICON_PATH="/__mock-service-cli/favicon.svg",TEXT_SAMPLE_SIZE=8192;function isPlainObject(value){return!!value&&typeof value=="object"&&!Array.isArray(value)}function detectTextCharset(filePath,stats){if(stats.size===0)return"utf-8";let buffer=Buffer.allocUnsafe(Math.min(stats.size,TEXT_SAMPLE_SIZE)),fileDescriptor;try{fileDescriptor=openSync(filePath,"r");let bytesRead=readSync(fileDescriptor,buffer,0,buffer.length,0),sample=buffer.subarray(0,bytesRead);if(sample[0]===255&&sample[1]===254)return"utf-16le";if(sample[0]===254&&sample[1]===255)return"utf-16be";for(let byte of sample)if(byte===0||byte<9||byte>13&&byte<32)return null;return new TextDecoder("utf-8",{fatal:!0}).decode(sample),"utf-8"}catch{return null}finally{fileDescriptor!==void 0&&closeSync(fileDescriptor)}}function setStaticHeaders(res,filePath,stats){res.setHeader("Content-Disposition","inline");let contentType=mime.lookup(filePath);if(!contentType||contentType==="application/octet-stream"){let charset=detectTextCharset(filePath,stats);charset&&res.setHeader("Content-Type",`text/plain; charset=${charset}`)}}function parseHeaderList(value){return typeof value!="string"?{}:value.split(/\s*,\s*/).reduce((headers,item)=>{let separator=item.indexOf("=");return separator<=0||(headers[item.slice(0,separator).trim()]=item.slice(separator+1).trim()),headers},{})}function parseProxyOptions(){if(!process.env.PROXY_OPTIONS)return{};try{let value=JSON.parse(process.env.PROXY_OPTIONS);return isPlainObject(value)?value:{}}catch(error){throw new Error(`Invalid proxy options: ${error.message}`)}}function normalizePublicPath(value,label,allowEmptyRoot){if(typeof value!="string")throw new Error(`${label} must be a path`);if(!value&&allowEmptyRoot)return"/";if(!value)throw new Error(`${label} must be a non-empty path`);let normalized="/"+value.replace(/^\/+|\/+$/g,"");if(normalized!=="/"&&(normalized.includes("..")||normalized.includes("?")||normalized.includes("#")))throw new Error(`${label} must be a root-relative path`);return normalized}function normalizeAccessLog(value,label,configDir){if(value===void 0)return null;if(!isPlainObject(value))throw new Error(`${label}.accessLog must be an object`);let accessLog={};if(["success","failure"].forEach(name=>{if(value[name]!==void 0){if(typeof value[name]!="string"||!value[name])throw new Error(`${label}.accessLog.${name} must be a file path`);accessLog[name]=path.resolve(configDir,value[name])}}),Object.keys(accessLog).length===0)throw new Error(`${label}.accessLog requires success or failure`);return accessLog}function normalizeRequestHeaders(value,label){if(value===void 0)return{};if(!isPlainObject(value))throw new Error(`${label} must be an object`);return Object.entries(value).reduce((headers,[name,headerValue])=>{if(!name||headerValue===null||typeof headerValue=="object")throw new Error(`${label}.${name} must be a primitive value`);return headers[name]=String(headerValue),headers},{})}function normalizeApplicationOptions(value,label,configDir){if(value.cors!==void 0&&typeof value.cors!="boolean")throw new Error(`${label}.cors must be boolean`);if(value.headers!==void 0&&!isPlainObject(value.headers))throw new Error(`${label}.headers must be an object`);if(value.secure!==void 0&&typeof value.secure!="boolean")throw new Error(`${label}.secure must be boolean`);return{cors:value.cors===!0,headers:isPlainObject(value.headers)?value.headers:{},secure:value.secure===!0,requestHeaders:normalizeRequestHeaders(value.requestHeaders,`${label}.requestHeaders`),accessLog:normalizeAccessLog(value.accessLog,label,configDir)}}function normalizeSpaFallback(value,directory,label){if(value===void 0||value===!1)return!1;if(typeof value!="string"||!value||!value.startsWith("/")||value.includes(".."))throw new Error(`${label} must be a root-relative path`);if(!directory)throw new Error(`${label} requires an application directory`);let fallbackPath=getStaticPath(directory,value);if(!fallbackPath||!/\.html?$/i.test(fallbackPath))throw new Error(`${label} does not exist: ${value}`);return value}function normalizeProxyTable(value,label,allowStringValues){if(value===void 0)return{};if(!isPlainObject(value))throw new Error(`${label} must be an object`);return Object.entries(value).reduce((table,[prefix,rule])=>{let normalizedPrefix=normalizePublicPath(prefix,`${label} route`);if(Object.prototype.hasOwnProperty.call(table,normalizedPrefix))throw new Error(`Duplicate proxy route: ${normalizedPrefix}`);let target=rule,rewrite=!1,requestHeaders={};if(isPlainObject(rule)){if(target=rule.target,rewrite=rule.rewrite===!0,requestHeaders=normalizeRequestHeaders(rule.requestHeaders,`${label}[${prefix}].requestHeaders`),rule.rewrite!==void 0&&typeof rule.rewrite!="boolean")throw new Error(`${label}[${prefix}].rewrite must be boolean`)}else if(!allowStringValues||typeof rule!="string")throw new Error(`${label}[${prefix}] must contain target and rewrite`);if(typeof target!="string"||!/^https?:\/\//.test(target))throw new Error(`Invalid proxy target for ${prefix}`);return table[normalizedPrefix]={target,rewrite,requestHeaders},table},{})}function hasPathPrefix(prefix,requestPath){return prefix==="/"||requestPath===prefix||requestPath.startsWith(`${prefix}/`)}function validateMountPaths(mounts){if(mounts.filter(mount=>mount.path==="/").length>1)throw new Error("mounts can only contain one root path");let nonRootMounts=mounts.filter(mount=>mount.path!=="/");nonRootMounts.forEach((mount,index)=>{nonRootMounts.forEach((other,otherIndex)=>{if(index!==otherIndex&&hasPathPrefix(mount.path,other.path))throw new Error(`mounts paths cannot overlap: ${mount.path} and ${other.path}`)})})}function isTransientWatchError(error){let code=error&&error.code;return["EBUSY","EPERM","EACCES","ENOENT","ENOTDIR"].includes(code)}function readWatchEnabledEnv(){if(process.env.WATCH_ENABLED!==void 0)return process.env.WATCH_ENABLED==="true"||process.env.WATCH_ENABLED==="1"}function normalizeConfig(){let defaults={open:!1,browser:"default",watch:{enabled:!0,ignore:["**/node_modules/**","**/.git/**"],delay:100,fullReload:!1,depth:void 0,interval:250},injectTag:"body",https:!1};if(process.env.WATCH_DEPTH!==void 0){let cliDepth=Number(process.env.WATCH_DEPTH);if(!Number.isInteger(cliDepth)||cliDepth<0)throw new Error("watch.depth must be a non-negative integer")}if(process.env.WATCH_INTERVAL!==void 0){let cliInterval=Number(process.env.WATCH_INTERVAL);if(!Number.isInteger(cliInterval)||cliInterval<1)throw new Error("watch.interval must be a positive integer")}let cliWatchEnabled=readWatchEnabledEnv(),cliWatchInterval=process.env.WATCH_INTERVAL===void 0?void 0:Number(process.env.WATCH_INTERVAL),cliDirectory=process.env.STATIC_DIRECTORY?path.resolve(process.env.STATIC_DIRECTORY):null;if(process.env.STATIC_CONFIG&&argv["spa-fallback"]!==void 0)throw new Error("--spa-fallback cannot be used with --static-config");let cliSpaFallback=process.env.STATIC_CONFIG?!1:normalizeSpaFallback(argv["spa-fallback"],cliDirectory,"spaFallback");if(!process.env.STATIC_CONFIG){if(!cliDirectory)throw new Error("Static server requires -R <directory> or --static-config <file>");if(!existsSync(cliDirectory)||!lstatSync(cliDirectory).isDirectory())throw new Error(`static-server: directory does not exist: ${cliDirectory}`);let cliProxy=normalizeProxyTable(parseProxyOptions(),"proxy",!0);return(argv.r||argv.rewrite)&&Object.values(cliProxy).forEach(rule=>rule.rewrite=!0),{...defaults,open:process.env.OPEN_API_OVERVIEW?!0:defaults.open,watch:{...defaults.watch,enabled:cliWatchEnabled===void 0?defaults.watch.enabled:cliWatchEnabled,interval:cliWatchInterval===void 0?defaults.watch.interval:cliWatchInterval,depth:process.env.WATCH_DEPTH===void 0?void 0:Number(process.env.WATCH_DEPTH)},configDir:process.cwd(),mounts:[{path:"/",directory:cliDirectory,spaFallback:cliSpaFallback,proxy:cliProxy,cors:!1,headers:{},secure:!1,requestHeaders:{},accessLog:null}]}}let configPath=path.resolve(process.env.STATIC_CONFIG),supplied;try{supplied=JSON.parse(readFileSync(configPath,"utf8"))}catch(error){throw new Error(`Unable to read static config: ${error.message}`)}if(!isPlainObject(supplied))throw new Error("Static config must contain a JSON object");let configDir=path.dirname(configPath),watch=isPlainObject(supplied.watch)?supplied.watch:{};if(watch.enabled!==void 0&&typeof watch.enabled!="boolean")throw new Error("watch.enabled must be boolean");if(watch.interval!==void 0&&(!Number.isInteger(watch.interval)||watch.interval<1))throw new Error("watch.interval must be a positive integer");let depthValue=process.env.WATCH_DEPTH!==void 0?Number(process.env.WATCH_DEPTH):watch.depth;if(depthValue!==void 0&&(!Number.isInteger(depthValue)||depthValue<0))throw new Error("watch.depth must be a non-negative integer");let enabledValue=cliWatchEnabled===void 0?watch.enabled===void 0?defaults.watch.enabled:watch.enabled:cliWatchEnabled,intervalValue=cliWatchInterval===void 0?watch.interval===void 0?defaults.watch.interval:watch.interval:cliWatchInterval;if(process.env.PROXY_OPTIONS)throw new Error("--proxy-options/--rewrite cannot be used with --static-config");let suppliedRootField=["directory","spaFallback","proxy","cors","headers","secure","requestHeaders","accessLog"].find(field=>supplied[field]!==void 0);if(suppliedRootField)throw new Error(`${suppliedRootField} must be declared on a mount in static config`);let mounts=supplied.mounts===void 0?[]:supplied.mounts;if(!Array.isArray(mounts))throw new Error("mounts must be an array");if(mounts.length===0)throw new Error("Static config requires at least one mount");let normalizedMounts=mounts.map((mount,index)=>{if(!isPlainObject(mount))throw new Error(`mounts[${index}] must be an object`);let mountPath=mount.path===void 0?"/":normalizePublicPath(mount.path,`mounts[${index}].path`,!0);if(mount.directory!==void 0&&typeof mount.directory!="string")throw new Error(`mounts[${index}].directory must be a string`);let directory=mount.directory===void 0?null:path.resolve(configDir,mount.directory);if(directory&&(!existsSync(directory)||!lstatSync(directory).isDirectory()))throw new Error(`Mount directory does not exist: ${directory}`);let normalizedMount={path:mountPath,directory,spaFallback:normalizeSpaFallback(mount.spaFallback,directory,`mounts[${index}].spaFallback`),proxy:normalizeProxyTable(mount.proxy,`mounts[${index}].proxy`,!1),...normalizeApplicationOptions(mount,`mounts[${index}]`,configDir)};if(!normalizedMount.directory&&Object.keys(normalizedMount.proxy).length===0)throw new Error(`mounts[${index}] requires directory or proxy`);if(normalizedMount.accessLog&&!normalizedMount.spaFallback)throw new Error(`mounts[${index}].accessLog requires spaFallback`);return normalizedMount});validateMountPaths(normalizedMounts);let httpsConfig=supplied.https,normalizedHttps=!1;if(httpsConfig===!0)throw new Error("https requires cert and key paths");if(isPlainObject(httpsConfig)&&httpsConfig.enable!==!1){if(typeof httpsConfig.cert!="string"||typeof httpsConfig.key!="string")throw new Error("https requires cert and key paths");normalizedHttps={cert:path.resolve(configDir,httpsConfig.cert),key:path.resolve(configDir,httpsConfig.key),passphrase:typeof httpsConfig.passphrase=="string"?httpsConfig.passphrase:void 0}}return{...defaults,open:process.env.OPEN_API_OVERVIEW?supplied.open||!0:supplied.open===void 0?defaults.open:supplied.open,browser:supplied.browser===void 0?defaults.browser:supplied.browser,configDir,watch:{enabled:enabledValue,ignore:Array.isArray(watch.ignore)?watch.ignore:defaults.watch.ignore,delay:Number.isFinite(watch.delay)&&watch.delay>=0?watch.delay:defaults.watch.delay,fullReload:watch.fullReload===!0,depth:depthValue,interval:intervalValue},injectTag:supplied.injectTag==="head"?"head":"body",mounts:normalizedMounts,https:normalizedHttps}}function getStaticPath(root,requestPath){let pathname;try{pathname=decodeURIComponent(requestPath)}catch{return null}let candidate=path.resolve(root,`.${pathname}`),relative=path.relative(root,candidate);return relative.startsWith("..")||path.isAbsolute(relative)||!existsSync(candidate)||lstatSync(candidate).isDirectory()?null:candidate}function getStaticDirectory(root,requestPath){let pathname;try{pathname=decodeURIComponent(requestPath)}catch{return null}let candidate=path.resolve(root,`.${pathname}`),relative=path.relative(root,candidate);return relative.startsWith("..")||path.isAbsolute(relative)||!existsSync(candidate)?null:lstatSync(candidate).isDirectory()?candidate:null}function escapeHtml(value){return String(value).replace(/[&<>"']/g,character=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[character])}function joinPublicPath(basePath,localPath){return basePath==="/"?localPath:`${basePath}${localPath==="/"?"/":localPath}`.replace(/\/+/g,"/")}async function getDirectoryIndexData(directoryPath,requestPath,showHidden,basePath){let entries=await fsPromises.readdir(directoryPath,{withFileTypes:!0}),hiddenNames=await getDirectoryHiddenNames(directoryPath,entries.map(entry=>entry.name),{osHidden:osHiddenEnabled}),visibleEntries=entries.map(entry=>({entry,hidden:hiddenNames.has(entry.name)})).filter(item=>showHidden||!item.hidden);visibleEntries.sort((left,right)=>left.entry.isDirectory()!==right.entry.isDirectory()?left.entry.isDirectory()?-1:1:left.entry.name.localeCompare(right.entry.name));let decodedPath=decodeURIComponent(requestPath),normalizedPath=decodedPath==="/"?"/":`/${decodedPath.replace(/^\/+|\/+$/g,"")}/`,parentPath=normalizedPath==="/"?null:normalizedPath.split("/").slice(0,-2).join("/")||"/";return{currentPath:normalizedPath,parentPath,basePath,showHidden,entries:visibleEntries.map(({entry,hidden})=>({name:entry.name,isDirectory:entry.isDirectory(),isHidden:hidden}))}}function encodeDirectoryPath(directoryPath){return directoryPath==="/"?"/":`/${directoryPath.split("/").filter(Boolean).map(segment=>encodeURIComponent(segment)).join("/")}/`}function renderDirectoryIndex(data){let normalizedPath=data.currentPath,publicCurrentPath=joinPublicPath(data.basePath,normalizedPath),publicParentPath=data.parentPath?joinPublicPath(data.basePath,data.parentPath):null,encodedDirectoryPath=encodeDirectoryPath(publicCurrentPath),encodedApplicationRootPath=encodeDirectoryPath(joinPublicPath(data.basePath,"/")),withVisibility=url=>data.showHidden?`${url}?showHidden=1`:url,breadcrumbParts=normalizedPath.split("/").filter(Boolean),breadcrumbPath="",breadcrumb=[`<a href="${withVisibility(encodedApplicationRootPath)}">\u6839\u76EE\u5F55</a>`,...breadcrumbParts.map(part=>(breadcrumbPath+=`/${part}`,`<a href="${withVisibility(encodeDirectoryPath(joinPublicPath(data.basePath,breadcrumbPath)))}">${escapeHtml(part)}</a>`))].join('<span aria-hidden="true"> / </span>'),items=data.entries.map(entry=>{let suffix=entry.isDirectory?"/":"",href=`${encodedDirectoryPath}${encodeURIComponent(entry.name)}${suffix}`.replace(/\/+/g,"/"),target=entry.isDirectory?withVisibility(href):href;return`<li${entry.isHidden?' class="is-hidden"':""}><a href="${target}">${entry.isDirectory?"\u{1F4C1}":"\u{1F4C4}"} ${escapeHtml(entry.name)}${suffix}</a></li>`}).join(""),parent=data.parentPath?`<p id="directoryParent"><a href="${withVisibility(encodeDirectoryPath(publicParentPath))}">\u2190 \u8FD4\u56DE\u4E0A\u7EA7</a></p>`:'<p id="directoryParent" hidden></p>',visibilityToggle=`<a class="visibility-toggle" href="${data.showHidden?encodedDirectoryPath:`${encodedDirectoryPath}?showHidden=1`}">${data.showHidden?"\u9690\u85CF\u9690\u85CF\u9879\u76EE":"\u663E\u793A\u9690\u85CF\u9879\u76EE"}</a>`;return`<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><link rel="icon" type="image/svg+xml" href="${STATIC_FAVICON_PATH}"><title>\u76EE\u5F55\u7D22\u5F15 ${escapeHtml(publicCurrentPath)}</title><style>body{font:14px system-ui,sans-serif;margin:32px;max-width:900px}a{color:#2563eb;text-decoration:none}a:hover{text-decoration:underline}.directory-header{display:flex;align-items:center;gap:12px;margin:12px 0;flex-wrap:wrap}.directory-header h1{font-size:20px;margin:0}.directory-header nav{color:#4b5563;min-width:0;flex:1;overflow-wrap:anywhere}.directory-header nav span{padding:0 5px;color:#9ca3af}.visibility-toggle{color:#374151;border:1px solid #d1d5db;border-radius:4px;background:#f9fafb;padding:5px 8px;white-space:nowrap}.visibility-toggle:hover{background:#f3f4f6;text-decoration:none}.is-hidden{opacity:.55}ul{list-style:none;padding:0}li{padding:7px 0;border-bottom:1px solid #eee}</style></head><body><header class="directory-header"><h1>\u76EE\u5F55\u7D22\u5F15</h1><nav aria-label="\u8DEF\u5F84\u5BFC\u822A">${breadcrumb}</nav>${visibilityToggle}</header>${parent}<ul>${items||"<li>\uFF08\u7A7A\u76EE\u5F55\uFF09</li>"}</ul></body></html>`}function getLiveReloadClient(config){let delay=JSON.stringify(config.watch.delay),fullReload=JSON.stringify(config.watch.fullReload);return`(function(){const delay=${delay};const fullReload=${fullReload};let source;let timer;const dispose=function(){clearTimeout(timer);if(source){source.close();source=null}};const connect=function(){if(source)return;source=new EventSource('${LIVE_RELOAD_PATH}');source.onmessage=function(event){let change;try{change=JSON.parse(event.data)}catch(_){return}clearTimeout(timer);timer=setTimeout(function(){if(!fullReload&&change.type==='css'){const target=new URL(change.path,location.href).pathname;let updated=false;document.querySelectorAll('link[rel~="stylesheet"][href]').forEach(function(link){if(new URL(link.href,location.href).pathname===target){const url=new URL(link.href,location.href);url.searchParams.set('mock-service-cli-reload',Date.now());link.href=url.href;updated=true}});if(updated)return}location.reload()},delay)}};window.addEventListener('pagehide',dispose);window.addEventListener('pageshow',connect);connect()})();`}function injectLiveReload(html,config){if(!/<link\b[^>]*\brel\s*=\s*["'][^"']*\bicon\b[^"']*["'][^>]*>/i.test(html)){let favicon=`<link rel="icon" type="image/svg+xml" href="${STATIC_FAVICON_PATH}">`,headIndex=html.toLowerCase().lastIndexOf("</head>");html=headIndex===-1?`${favicon}${html}`:`${html.slice(0,headIndex)}${favicon}${html.slice(headIndex)}`}if(config.watch.enabled===!1)return html;let script=`<script src="${LIVE_RELOAD_CLIENT_PATH}" data-mock-service-cli-live-reload="true"></script>`,closingTag=config.injectTag==="head"?"</head>":"</body>",index=html.toLowerCase().lastIndexOf(closingTag);return index===-1?`${html}${script}`:`${html.slice(0,index)}${script}${html.slice(index)}`}function openBrowser(url,browser){if(!browser||browser===!1)return;let command,args;if(isPlainObject(browser)){if(typeof browser.command!="string"||!browser.command)return;command=browser.command,args=Array.isArray(browser.args)?browser.args.map(String):[],args.push(url)}else browser!=="default"?(command=String(browser),args=[url]):process.platform==="darwin"?(command="open",args=[url]):process.platform==="win32"?(command="cmd",args=["/c","start","",url]):(command="xdg-open",args=[url]);spawn(command,args,{detached:!0,stdio:"ignore"}).unref()}function createStaticServer(config){let app=express(),cliHeaders=parseHeaderList(argv.A||argv["append-headers"]),clients=new Set,watchers=[],pendingChanges=[],reloadTimer=null,closing=!1,pendingLogWrites=new Set,applications=config.mounts.map(mount=>({...mount,basePath:mount.path})),rootApplication=applications.find(application=>application.basePath==="/"&&application.directory),root=rootApplication?rootApplication.directory:null;app.use(hostAllowlistMiddleware()),app.use((req,res,next)=>{Object.entries(cliHeaders).forEach(([key,value])=>res.setHeader(key,String(value))),next()});function applyApplicationOptions(application){return(req,res,next)=>(Object.entries({...application.headers,...cliHeaders}).forEach(([key,value])=>res.setHeader(key,String(value))),application.cors&&(res.setHeader("Access-Control-Allow-Origin","*"),res.setHeader("Access-Control-Allow-Methods","GET,HEAD,OPTIONS"),res.setHeader("Access-Control-Allow-Headers","*"),req.method==="OPTIONS")?res.status(204).end():next())}function writeAccessLog(application,req,res){if(!application.accessLog)return;let logFile=res.statusCode>=400?application.accessLog.failure:application.accessLog.success;if(!logFile)return;let entry=`${JSON.stringify({timestamp:new Date().toISOString(),application:application.basePath,method:req.method,url:req.originalUrl||req.url,status:res.statusCode})}
136
136
  `,write=fsPromises.mkdir(path.dirname(logFile),{recursive:!0}).then(()=>fsPromises.appendFile(logFile,entry,"utf8")).catch(error=>log.info(colors.red(`static-server access log failed: ${error.message}`)));pendingLogWrites.add(write),write.finally(()=>pendingLogWrites.delete(write))}function createAccessLogMiddleware(application){return application.accessLog?(req,res,next)=>{res.once("finish",()=>writeAccessLog(application,req,res)),next()}:(_req,_res,next)=>next()}app.get(LIVE_RELOAD_PATH,(req,res)=>{res.status(200).set({"Content-Type":"text/event-stream","Cache-Control":"no-cache, no-transform",Connection:"keep-alive"}),res.flushHeaders(),res.write(`retry: 1000
137
137
 
138
138
  `),clients.add(res);let removeClient=()=>clients.delete(res);req.once("close",removeClient),res.once("close",removeClient)}),app.get(LIVE_RELOAD_CLIENT_PATH,(req,res)=>{res.type("application/javascript").set("Cache-Control","no-store").send(getLiveReloadClient(config))}),app.get(STATIC_FAVICON_PATH,(req,res)=>{res.sendFile(path.resolve(__dirname,"./favicon-static-server.svg"))});let proxyRoutes=[],proxyOwners=new Map;applications.forEach(application=>{Object.entries(application.proxy||{}).forEach(([prefix,rule])=>{if(proxyOwners.has(prefix))throw new Error(`Duplicate proxy route: ${prefix}`);proxyOwners.set(prefix,application.basePath),proxyRoutes.push({prefix,application,...rule})})}),proxyRoutes.sort((left,right)=>right.prefix.length-left.prefix.length),proxyRoutes.forEach(route=>{let pathRewrite=route.rewrite?requestPath=>route.prefix==="/"?requestPath:requestPath===route.prefix?"/":requestPath.startsWith(`${route.prefix}/`)?requestPath.slice(route.prefix.length)||"/":requestPath:void 0;app.use(route.prefix,applyApplicationOptions(route.application),createAccessLogMiddleware(route.application),createProxyMiddleware({target:route.target,changeOrigin:!0,ws:!0,secure:route.application.secure,headers:{...route.application.requestHeaders,...route.requestHeaders},pathRewrite}))});let sendHtml=async(filePath,res,next)=>{try{let html=await fsPromises.readFile(filePath,"utf8");res.type("html").send(injectLiveReload(html,config))}catch(error){next(error)}};function createApplicationRouter(application){let router=express.Router();if(router.use(applyApplicationOptions(application)),router.use(createAccessLogMiddleware(application)),router.get("*",async(req,res,next)=>{if(req.path.startsWith("/__mock-service-cli/"))return next();let filePath=getStaticPath(application.directory,req.path);if(filePath&&/\.html?$/i.test(filePath))return sendHtml(filePath,res,next);if(!application.spaFallback){let directoryPath=getStaticDirectory(application.directory,req.path);if(directoryPath)try{let data=await getDirectoryIndexData(directoryPath,req.path,req.query.showHidden==="1",application.basePath);return res.type("html").set("Cache-Control","no-store").send(injectLiveReload(renderDirectoryIndex(data),config))}catch(error){return next(error)}}next()}),router.use(express.static(application.directory,{dotfiles:"allow",index:!1,redirect:!1,setHeaders:setStaticHeaders})),application.spaFallback){let fallbackPath=getStaticPath(application.directory,application.spaFallback);if(!fallbackPath||!/\.html?$/i.test(fallbackPath))throw new Error(`SPA fallback does not exist: ${application.spaFallback}`);router.get("*",(req,res,next)=>{if(req.path.startsWith("/__mock-service-cli/"))return next();sendHtml(fallbackPath,res,next)})}return router}applications.filter(application=>application.basePath!=="/"&&application.directory).forEach(application=>{let router=createApplicationRouter(application);app.use(application.basePath,(req,res,next)=>{router.handle(req,res,error=>{if(error)return next(error);if(!res.headersSent)return res.status(404).send("Not Found")})})}),rootApplication&&app.use(createApplicationRouter(rootApplication)),app.use((req,res)=>res.status(404).send("Not Found")),app.use((error,req,res,_next)=>{log.info(colors.red(`static-server request failed: ${error.message}`)),res.status(500).send("Static server request failed")});function toUrlPath(changedPath){let mount=config.mounts.find(item=>{if(!item.directory)return!1;let relative=path.relative(item.directory,changedPath);return!relative.startsWith("..")&&!path.isAbsolute(relative)});if(mount){let relative=path.relative(mount.directory,changedPath).split(path.sep).join("/");return`${mount.path.replace(/\/$/,"")}/${relative}`.replace(/\/+/g,"/")}if(root){let rootRelative=path.relative(root,changedPath);if(!rootRelative.startsWith("..")&&!path.isAbsolute(rootRelative))return`/${rootRelative.split(path.sep).join("/")}`}return"/"}function notifyClients(){let changes=pendingChanges;pendingChanges=[];let cssOnly=changes.length>0&&changes.every(change=>/\.css$/i.test(change)),payload=JSON.stringify({type:!config.watch.fullReload&&cssOnly?"css":"reload",path:changes[0]||"/"});clients.forEach(client=>client.write(`data: ${payload}
@@ -153,8 +153,8 @@ Starting up Static Server, serving `),colors.cyan(instance.root||config.configDi
153
153
  [...extracted.files];
154
154
  parentPort.postMessage({ success: true });
155
155
  })().catch(error => parentPort.postMessage({ error: error.message }));
156
- `;function isArchivePath(filePath){return hasArchiveExtension(filePath,extensions)}function isCompressedTar(filePath){return/\.(tar\.gz|tgz|tar\.bz2|tbz|tbz2|tar\.xz|txz)$/i.test(filePath)}function parse7ZipList(output){let separator=output.indexOf("----------");return separator<0?[]:output.slice(separator+10).split(/\r?\n\r?\n/).map(block=>{let values={};return block.split(/\r?\n/).forEach(line=>{let index=line.indexOf(" = ");index>0&&(values[line.slice(0,index)]=line.slice(index+3))}),values}).filter(values=>values.Path).map(values=>({path:values.Path.replace(/\\/g,"/"),isDirectory:values.Folder==="+"||String(values.Attributes||"").startsWith("D"),size:Number(values.Size||0),packedSize:Number(values["Packed Size"]||0),encrypted:values.Encrypted==="+",modified:values.Modified||null,attributes:values.Attributes||""}))}function run7Zip(args,onProcess){return new Promise((resolve,reject)=>{try{process.platform!=="win32"&&chmodSync(path7za,493)}catch(error){return reject(createArchiveError(`Unable to prepare bundled 7-Zip binary: ${error.message}`,500))}let child=spawn(path7za,args,{stdio:["ignore","pipe","pipe"]}),stderr="",stdout="";onProcess&&onProcess(child),child.stdout.on("data",chunk=>{stdout+=chunk.toString()}),child.stderr.on("data",chunk=>{stderr+=chunk.toString()}),child.once("error",reject),child.once("close",code=>{if(code===0)return resolve(stdout);reject(createArchiveError(stderr.trim()||`7-Zip exited with code ${code}`,422))})})}async function list7Zip(fullPath){let output=await run7Zip(["l","-slt","--",fullPath]),entries=parse7ZipList(output);if(!isCompressedTar(fullPath))return entries;let tempRoot=await fsPromises.mkdtemp(path.join(os.tmpdir(),"mock-service-cli-archive-list-"));try{await run7Zip(["e","-y",`-o${tempRoot}`,"--",fullPath]);let tarName=(await fsPromises.readdir(tempRoot)).find(name=>/\.tar$/i.test(name));return tarName?await list7Zip(path.join(tempRoot,tarName)):entries}finally{rmSync(tempRoot,{recursive:!0,force:!0})}}async function listRar(fullPath){let list=(await createExtractorFromFile({filepath:fullPath})).getFileList();if(list.arcHeader.flags&&list.arcHeader.flags.headerEncrypted)throw createArchiveError("Encrypted archives are not supported",422);return[...list.fileHeaders].map(header=>({path:header.name.replace(/\\/g,"/"),isDirectory:!!(header.flags&&header.flags.directory),size:Number(header.unpSize||0),packedSize:Number(header.packSize||0),encrypted:!!(header.flags&&header.flags.encrypted),modified:header.time||null,attributes:""}))}async function listEntries(fullPath){return path.extname(fullPath).toLowerCase()===".rar"?listRar(fullPath):list7Zip(fullPath)}async function extractRar(job,sourcePath,targetPath){await new Promise((resolve,reject)=>{let worker=new Worker(RAR_EXTRACT_WORKER,{eval:!0,workerData:{sourcePath,targetPath}}),settled=!1,finish=(callback,value)=>{settled||(settled=!0,job.child=null,callback(value))};job.child={kill:()=>worker.terminate()},worker.on("message",message=>{message&&message.success?finish(resolve):finish(reject,createArchiveError(message&&message.error||"RAR extraction failed",422))}),worker.on("error",error=>finish(reject,error)),worker.on("exit",code=>{if(!settled&&code!==0){let message=job.cancelled?"Archive job cancelled":"RAR extraction stopped";finish(reject,createArchiveError(message,499))}})})}async function extract(job,sourcePath,targetPath){if(path.extname(sourcePath).toLowerCase()===".rar")return extractRar(job,sourcePath,targetPath);await run7Zip(["x","-y",`-o${targetPath}`,"--",sourcePath],child=>{job.child=child})}module2.exports={capabilities,extract,isArchivePath,listEntries}}});var require_archiveService=__commonJS({"src/lib/archiveService.js"(exports2,module2){var{createWriteStream,existsSync,lstatSync,mkdirSync,promises:fsPromises,realpathSync,renameSync,rmSync}=require("fs"),path=require("path"),crypto=require("crypto"),archiver=require("archiver"),archiveProvider=require_ultra(),{createArchiveError,isInside,isSafeArchiveEntry}=require_archiveShared(),MAX_ARCHIVE_SIZE=2*1024*1024*1024,MAX_ARCHIVE_ENTRIES=1e4,MAX_COMPRESSION_RATIO=100,ArchiveService=class{constructor({rootPath,resolvePath,getChildPath}){this.rootPath=rootPath,this.resolvePath=resolvePath,this.getChildPath=getChildPath,this.jobs=new Map}resolveExistingFile(inputPath){let fullPath=this.resolvePath(inputPath);if(!existsSync(fullPath))throw createArchiveError("Path not found",404);let stats=lstatSync(fullPath);if(!stats.isFile())throw createArchiveError("Archive path must be a file");if(!archiveProvider.isArchivePath(fullPath))throw createArchiveError("Unsupported archive format");if(stats.size>MAX_ARCHIVE_SIZE)throw createArchiveError("Archive exceeds 2GB limit",413);return fullPath}async listArchive(inputPath){let fullPath=this.resolveExistingFile(inputPath),entries=await archiveProvider.listEntries(fullPath);return this.assertEntriesSafe(entries,fullPath),{path:inputPath,name:path.basename(fullPath),entries,totalEntries:entries.length,totalSize:entries.reduce((total,entry)=>total+entry.size,0),totalPackedSize:entries.reduce((total,entry)=>total+entry.packedSize,0)}}assertEntriesSafe(entries,fullPath){if(!entries.length)throw createArchiveError("Archive contains no entries",422);if(entries.length>MAX_ARCHIVE_ENTRIES)throw createArchiveError("Archive contains too many entries",413);if(entries.some(entry=>entry.encrypted))throw createArchiveError("Encrypted archives are not supported",422);if(entries.some(entry=>entry.isSymbolicLink||!isSafeArchiveEntry(entry.path)))throw createArchiveError("Archive contains an unsafe entry path",422);let totalSize=entries.reduce((total,entry)=>total+entry.size,0),packedSize=Math.max(lstatSync(fullPath).size,1);if(totalSize>MAX_ARCHIVE_SIZE)throw createArchiveError("Archive expands beyond 2GB limit",413);if(totalSize/packedSize>MAX_COMPRESSION_RATIO)throw createArchiveError("Archive compression ratio exceeds limit",413)}startJob(type,payload){let id=crypto.randomUUID(),job={id,type,status:"queued",progress:{processedEntries:0,totalEntries:0},createdAt:new Date().toISOString(),result:null,error:null,cancelled:!1,child:null,archive:null};return this.jobs.set(id,job),setImmediate(async()=>{if(!job.cancelled){job.status="running";try{job.result=type==="create"?await this.createArchive(job,payload):await this.extractArchive(job,payload),job.status=job.cancelled?"cancelled":"completed"}catch(error){job.status=job.cancelled?"cancelled":"failed",job.error=error.message}finally{job.child=null,job.archive=null,job.finishedAt=new Date().toISOString()}}}),job}getJob(id){return this.jobs.get(id)}getCapabilities(){return archiveProvider.capabilities}cancelJob(id){let job=this.getJob(id);if(!job)throw createArchiveError("Archive job not found",404);return["completed","failed","cancelled"].includes(job.status)||(job.cancelled=!0,job.status="cancelled",job.child&&job.child.kill("SIGTERM"),job.archive&&job.archive.abort()),job}async createArchive(job,payload){let format=payload.format==="tar.gz"?"tar.gz":payload.format;if(!archiveProvider.capabilities.createFormats.includes(format)){let formats=archiveProvider.capabilities.createFormats.join(" and ");throw createArchiveError(`Supported creation formats are ${formats}`)}if(!Array.isArray(payload.sources)||payload.sources.length===0)throw createArchiveError("Sources must be a non-empty array");let sourcePaths=payload.sources.map(source=>this.resolvePath(source));sourcePaths.forEach(source=>{if(!existsSync(source))throw createArchiveError("Source path not found",404);if(lstatSync(source).isSymbolicLink())throw createArchiveError("Symbolic links cannot be archived");let realPath=realpathSync(source);if(!isInside(this.rootPath,realPath))throw createArchiveError("Access denied",403)}),await Promise.all(sourcePaths.map(source=>this.assertSourceTreeSafe(source)));let destinationPath=payload.destinationPath||path.posix.dirname(payload.sources[0]),archiveName=String(payload.name||"").trim(),requiredExtension=format==="zip"?".zip":".tar.gz",safeName=archiveName.endsWith(requiredExtension)?archiveName:`${archiveName}${requiredExtension}`,outputPath=this.getChildPath(destinationPath,safeName);if(existsSync(outputPath))throw createArchiveError("Archive path already exists",409);if(job.progress.totalEntries=sourcePaths.length,await new Promise((resolve,reject)=>{let output=createWriteStream(outputPath,{flags:"wx"}),archive=format==="zip"?archiver("zip",{zlib:{level:9}}):archiver("tar",{gzip:!0,gzipOptions:{level:9}});job.archive=archive,output.on("close",resolve),output.on("error",reject),archive.on("error",reject),archive.on("progress",progress=>{job.progress.processedEntries=progress.entries.processed,job.progress.totalEntries=progress.entries.total}),archive.pipe(output),sourcePaths.forEach(source=>{lstatSync(source).isDirectory()?archive.directory(source,path.basename(source)):archive.file(source,{name:path.basename(source)})}),archive.finalize()}).catch(error=>{throw rmSync(outputPath,{force:!0}),error}),job.cancelled)throw rmSync(outputPath,{force:!0}),createArchiveError("Archive job cancelled",499);return{path:outputPath,name:path.basename(outputPath)}}async extractArchive(job,payload){let sourcePath=this.resolveExistingFile(payload.path),destinationPath=this.resolvePath(payload.destinationPath||"/");if(!existsSync(destinationPath)||!lstatSync(destinationPath).isDirectory())throw createArchiveError("Extraction destination must be an existing directory",404);let listing=await this.listArchive(payload.path);job.progress.totalEntries=listing.totalEntries;let tempRoot=await fsPromises.mkdtemp(path.join(destinationPath,".mock-service-cli-archive-")),tempOutput=path.join(tempRoot,"output");mkdirSync(tempOutput);try{if(await archiveProvider.extract(job,sourcePath,tempOutput),job.cancelled)throw createArchiveError("Archive job cancelled",499);await this.assertExtractedTreeSafe(tempOutput);let outputEntries=await fsPromises.readdir(tempOutput);if(!outputEntries.length)throw createArchiveError("Archive produced no files",422);outputEntries.forEach(name=>{if(existsSync(path.join(destinationPath,name)))throw createArchiveError(`Destination already contains ${name}`,409)});for(let name of outputEntries)renameSync(path.join(tempOutput,name),path.join(destinationPath,name));return job.progress.processedEntries=job.progress.totalEntries,{destinationPath,entries:outputEntries}}finally{rmSync(tempRoot,{recursive:!0,force:!0})}}async assertExtractedTreeSafe(root){let rootRealPath=realpathSync(root),walk=async current=>{let entries=await fsPromises.readdir(current,{withFileTypes:!0});for(let entry of entries){let child=path.join(current,entry.name),stats=await fsPromises.lstat(child);if(stats.isSymbolicLink())throw createArchiveError("Archive contains symbolic links",422);let realPath=realpathSync(child);if(!isInside(rootRealPath,realPath))throw createArchiveError("Archive extracted outside its destination",422);stats.isDirectory()&&await walk(child)}};await walk(root)}async assertSourceTreeSafe(source){let stats=await fsPromises.lstat(source);if(stats.isSymbolicLink())throw createArchiveError("Symbolic links cannot be archived");if(!stats.isDirectory())return;let entries=await fsPromises.readdir(source,{withFileTypes:!0});await Promise.all(entries.map(entry=>this.assertSourceTreeSafe(path.join(source,entry.name))))}};module2.exports={ArchiveService,isArchivePath:archiveProvider.isArchivePath}}});var require_fileExplorerServer=__commonJS({"src/lib/fileExplorerServer.js"(){var express=require_express2(),{existsSync,readFileSync,statSync,lstatSync,rmSync,mkdirSync,writeFileSync,renameSync,realpathSync,copyFileSync,unlinkSync,constants:fsConstants,promises:fsPromises}=require("fs"),path=require("path"),os=require("os"),crypto=require("crypto"),multer=require_multer(),{UAParser}=require_ua_parser(),colors=require_safe(),portfinder=require_portfinder(),{exec}=require("child_process"),{dateFormat,logger,getServerHost,getServerUrls,hostAllowlistMiddleware,getDirectoryHiddenNames,normalizeRemoteAddress,openPathInFileManager}=require_utils3(),{getPackageVersion}=require_packageInfo(),{ArchiveService}=require_archiveService(),app=express(),log=logger(process.env.SILENT),argv=JSON.parse(process.env.ARGV),explorerRoot=path.resolve(process.env.EXPLORER_DIRECTORY||process.cwd()),explorerRootRealPath=realpathSync(explorerRoot),explorerRootId=crypto.createHash("sha256").update(explorerRootRealPath).digest("hex"),port=argv.p||argv.port,isEditMode=process.env.EXPLORER_EDIT==="true",explorerPassword=process.env.EXPLORER_AUTH||"",isAuthEnabled=!!explorerPassword,visitorKeys=new Set,httpServer=null,shuttingDown=!1,MAX_UPLOAD_FILE_SIZE=2*1024*1024*1024,MAX_UPLOAD_TOTAL_SIZE=2*1024*1024*1024,MAX_UPLOAD_FILE_COUNT=100,MAX_MULTIPART_OVERHEAD_SIZE=2*1024*1024,upload=multer({dest:path.join(os.tmpdir(),"mock-service-cli-upload"),preservePath:!0,limits:{fileSize:MAX_UPLOAD_FILE_SIZE,files:MAX_UPLOAD_FILE_COUNT,fields:10}}),archiveService=new ArchiveService({rootPath:explorerRootRealPath,resolvePath:resolveExplorerPath,getChildPath});function isPathInsideRoot(fullPath,resolvedRoot=explorerRootRealPath){let relativePath=path.relative(resolvedRoot,fullPath);return relativePath===""||!relativePath.startsWith("..")&&!path.isAbsolute(relativePath)}function normalizeExplorerInputPath(inputPath){let decodedPath=decodeURIComponent(String(inputPath||"/")).replace(/\\/g,"/");return!decodedPath||decodedPath==="."?"/":decodedPath.startsWith("/")?decodedPath:`/${decodedPath}`}function resolveExplorerPath(inputPath){let relativePath=normalizeExplorerInputPath(inputPath).replace(/^\/+/,""),fullPath=path.resolve(explorerRoot,relativePath);if(!isPathInsideRoot(fullPath,explorerRoot)){let error=new Error("Access denied");throw error.statusCode=403,error}if(!existsSync(fullPath))return fullPath;let realPath=realpathSync(fullPath);if(!isPathInsideRoot(realPath)){let error=new Error("Access denied");throw error.statusCode=403,error}return realPath}function validateEntryName(name){if(typeof name!="string")return"Name must be a string";let normalizedName=name.trim();if(!normalizedName||normalizedName==="."||normalizedName==="..")return"Invalid name";if(/[/\\\0<>:"|?*]/.test(normalizedName))return"Name contains invalid characters";if(process.platform==="win32"){let upperName=normalizedName.replace(/[. ]+$/g,"").split(".")[0].toUpperCase();if(new Set(["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"]).has(upperName)||normalizedName.endsWith(" ")||normalizedName.endsWith("."))return"Name is not supported on Windows"}return null}function getChildPath(parentPath,name){let nameError=validateEntryName(name);if(nameError){let error=new Error(nameError);throw error.statusCode=400,error}let parentFullPath=resolveExplorerPath(parentPath||"/");if(!existsSync(parentFullPath)||!statSync(parentFullPath).isDirectory()){let error=new Error("Parent directory not found");throw error.statusCode=404,error}let childPath=path.resolve(parentFullPath,name.trim());if(!isPathInsideRoot(childPath)){let error=new Error("Access denied");throw error.statusCode=403,error}return childPath}function requireEditMode(req,res,next){if(!isEditMode)return res.status(403).json({error:"File explorer is read-only. Restart with --edit to modify files."});next()}function isValidExplorerPassword(value){if(!isAuthEnabled)return!0;let provided=Buffer.from(String(value||"")),expected=Buffer.from(explorerPassword);return provided.length===expected.length&&crypto.timingSafeEqual(provided,expected)}function getExplorerPassword(req){return req.get("x-file-explorer-password")||req.body&&req.body.password}function requireExplorerAuth(req,res,next){if(!isValidExplorerPassword(getExplorerPassword(req)))return res.status(401).json({error:"Authentication required"});next()}function logExplorerVisit(req){let userAgent=req.get("user-agent")||"",ip=normalizeRemoteAddress(req.socket&&req.socket.remoteAddress),visitorKey=`${ip}
157
- ${userAgent}`;if(visitorKeys.has(visitorKey))return;visitorKeys.add(visitorKey);let parsed=new UAParser(userAgent).getResult(),browser=[parsed.browser.name,parsed.browser.version].filter(Boolean).join(" ")||"Unknown",operatingSystem=[parsed.os.name,parsed.os.version].filter(Boolean).join(" ")||"Unknown";log.info(`File explorer visitor: ip=${ip}, os=${operatingSystem}, browser=${browser}, userAgent=${userAgent}`)}function getUploadTargetPath(parentPath,originalName){let normalizedName=String(originalName||"").replace(/\\/g,"/").replace(/^\/+/,""),parts=normalizedName.split("/").filter(Boolean);if(parts.length===0||normalizedName!==parts.join("/")){let error=new Error("Invalid upload path");throw error.statusCode=400,error}parts.forEach(part=>{let nameError=validateEntryName(part);if(nameError){let error=new Error(nameError);throw error.statusCode=400,error}});let parentFullPath=resolveExplorerPath(parentPath||"/");if(!existsSync(parentFullPath)||!statSync(parentFullPath).isDirectory()){let error=new Error("Parent directory not found");throw error.statusCode=404,error}let targetPath=path.resolve(parentFullPath,...parts);if(!isPathInsideRoot(targetPath)){let error=new Error("Access denied");throw error.statusCode=403,error}return{targetPath,parentFullPath,parts}}function ensureUploadParent(parentFullPath,parts){let current=parentFullPath;parts.slice(0,-1).forEach(part=>{if(current=path.join(current,part),existsSync(current)){let stats=lstatSync(current);if(!stats.isDirectory()||stats.isSymbolicLink()||!isPathInsideRoot(realpathSync(current))){let error=new Error("Upload path is not a safe directory");throw error.statusCode=403,error}}else mkdirSync(current)})}function moveUploadedFile(sourcePath,targetPath){copyFileSync(sourcePath,targetPath,fsConstants.COPYFILE_EXCL),unlinkSync(sourcePath)}function cleanupUploadedTempFiles(files=[]){files.forEach(file=>{file&&file.path&&existsSync(file.path)&&rmSync(file.path,{force:!0})})}function enforceUploadRequestSize(req,res,next){let contentLength=Number(req.get("content-length"));if(Number.isFinite(contentLength)&&contentLength>MAX_UPLOAD_TOTAL_SIZE+MAX_MULTIPART_OVERHEAD_SIZE)return res.status(413).json({error:"Total upload size exceeds 2GB limit"});next()}function deleteExplorerPath(targetPath){let fullPath=resolveExplorerPath(targetPath);if(path.resolve(fullPath)===explorerRootRealPath){let error=new Error("Cannot delete explorer root");throw error.statusCode=400,error}if(!existsSync(fullPath)){let error=new Error("Path not found");throw error.statusCode=404,error}rmSync(fullPath,{recursive:!0,force:!1})}process.env.PORT?init():(portfinder.basePort=port||8090,portfinder.getPort(function(err,foundPort){if(err)throw err;process.env.PORT=foundPort,init()}));function init(){app.use(hostAllowlistMiddleware()),app.use(express.json());let faviconInstanceId=crypto.randomUUID(),explorerFaviconUrl=`/favicon-file-explorer.svg?instance=${faviconInstanceId}`,loginFaviconUrl=`/favicon-file-explorer-login.svg?instance=${faviconInstanceId}`,sendFavicon=(filename,res)=>{res.type("image/svg+xml").set("Cache-Control","no-store").sendFile(path.resolve(__dirname,filename))},sendExplorerPage=(filename,faviconUrl,res)=>{let htmlPath=path.resolve(__dirname,filename);if(!existsSync(htmlPath))return res.status(404).send("File explorer page not found");res.type("html").send(readFileSync(htmlPath,"utf8").replace("__FILE_EXPLORER_FAVICON_URL__",faviconUrl))};app.get("/favicon-file-explorer.svg",(req,res)=>sendFavicon("./favicon-file-explorer.svg",res)),app.get("/favicon-file-explorer-login.svg",(req,res)=>sendFavicon("./favicon-file-explorer-login.svg",res)),app.get("/",(req,res)=>sendExplorerPage("./file-explorer.html",explorerFaviconUrl,res)),app.get("/__login",(req,res)=>sendExplorerPage("./file-explorer-login.html",loginFaviconUrl,res)),app.post("/__api/auth/verify",(req,res)=>{if(!isValidExplorerPassword(getExplorerPassword(req)))return res.status(401).json({error:"Invalid password"});res.json({success:!0,authEnabled:isAuthEnabled})}),app.use("/__api",requireExplorerAuth),app.get("/__api/config",(req,res)=>{logExplorerVisit(req),res.json({editMode:isEditMode,authEnabled:isAuthEnabled,rootId:explorerRootId})}),app.get("/__api/archive/capabilities",requireEditMode,(req,res)=>{res.json(archiveService.getCapabilities())}),app.get("/__api/health",(req,res)=>{res.json({success:!0})}),app.get("/__api/list",async(req,res)=>{let dirPath=normalizeExplorerInputPath(req.query.path||"/"),fullPath;try{fullPath=resolveExplorerPath(dirPath)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(!existsSync(fullPath))return res.status(404).json({error:"Path not found"});try{if(!(await fsPromises.lstat(fullPath)).isDirectory())return res.status(400).json({error:"Not a directory"});let files=await fsPromises.readdir(fullPath,{withFileTypes:!0}),hiddenNames=await getDirectoryHiddenNames(fullPath,files.map(file=>file.name)),result=await Promise.all(files.map(async file=>{let filePath=path.join(fullPath,file.name),fileStats,hasError=!1;try{fileStats=await fsPromises.lstat(filePath)}catch{hasError=!0}let relativePath=path.posix.join(dirPath,file.name),isDirectory=hasError?file.isDirectory():fileStats.isDirectory();return{name:file.name,path:relativePath.replace(/\\/g,"/"),isDirectory,size:hasError?0:fileStats.size,mtime:hasError?new Date:fileStats.mtime,birthtime:hasError?new Date:fileStats.birthtime,isHidden:hiddenNames.has(file.name),error:hasError?"Cannot access file":null}}));result.sort((a,b)=>a.isDirectory!==b.isDirectory?a.isDirectory?-1:1:a.name.localeCompare(b.name)),res.json({currentPath:dirPath,parentPath:dirPath==="/"?null:path.posix.dirname(dirPath),files:result})}catch(error){res.status(500).json({error:error.message})}}),app.get("/__api/file",(req,res)=>{let filePath=normalizeExplorerInputPath(req.query.path||"/"),fullPath;try{fullPath=resolveExplorerPath(filePath)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(!existsSync(fullPath))return res.status(404).json({error:"File not found"});let stats=statSync(fullPath);if(stats.isDirectory())return res.status(400).json({error:"Is a directory"});if(req.query.download==="1")return res.download(fullPath,path.basename(filePath));let ext=path.extname(filePath).toLowerCase(),imageExts=[".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg",".ico"],textExts=[".txt",".json",".js",".css",".html",".xml",".md",".csv",".yaml",".yml",".log"];if(imageExts.includes(ext))res.sendFile(fullPath);else if(textExts.includes(ext)||stats.size<1024*1024)try{let content=readFileSync(fullPath,"utf-8");res.json({name:path.basename(filePath),type:"text",content,size:stats.size})}catch{res.download(fullPath)}else res.download(fullPath)}),app.post("/__api/open-in-explorer",async(req,res)=>{let filePath=normalizeExplorerInputPath(req.body.path||"/"),fullPath;try{fullPath=resolveExplorerPath(filePath)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(!existsSync(fullPath))return res.status(404).json({error:"Path not found"});let result=await openPathInFileManager(fullPath);if(!result.ok)return result.unsupported?res.status(400).json({error:"Unsupported platform"}):(console.error(colors.red(`Failed to open in explorer: ${result.error.message}`)),res.status(500).json({error:"Failed to open in explorer"}));res.json({success:!0,path:fullPath})}),app.post("/__api/path",requireEditMode,(req,res)=>{let parentPath=req.body&&req.body.parentPath||"/",name=req.body&&req.body.name,type=req.body&&req.body.type||"file";if(type!=="file"&&type!=="directory")return res.status(400).json({error:"Invalid type"});let fullPath;try{fullPath=getChildPath(parentPath,name)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(existsSync(fullPath))return res.status(409).json({error:"Path already exists"});try{type==="directory"?mkdirSync(fullPath):writeFileSync(fullPath,""),res.json({success:!0,path:fullPath})}catch(error){console.error(colors.red(`Failed to create path: ${error.message}`)),res.status(500).json({error:"Failed to create path"})}}),app.patch("/__api/path",requireEditMode,(req,res)=>{let sourcePath=req.body&&req.body.path,name=req.body&&req.body.name,fullPath,nextPath;try{if(fullPath=resolveExplorerPath(sourcePath),path.resolve(fullPath)===explorerRootRealPath)return res.status(400).json({error:"Cannot rename explorer root"});if(!existsSync(fullPath))return res.status(404).json({error:"Path not found"});nextPath=getChildPath(path.posix.dirname(normalizeExplorerInputPath(sourcePath||"/")),name)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(existsSync(nextPath))return res.status(409).json({error:"Path already exists"});try{renameSync(fullPath,nextPath),res.json({success:!0,path:sourcePath,nextPath})}catch(error){console.error(colors.red(`Failed to rename path: ${error.message}`)),res.status(500).json({error:"Failed to rename path"})}}),app.delete("/__api/path",requireEditMode,(req,res)=>{let targetPath=req.body&&req.body.path||"/";try{deleteExplorerPath(targetPath),res.json({success:!0,path:targetPath})}catch(error){console.error(colors.red(`Failed to delete path: ${error.message}`)),res.status(error.statusCode||500).json({error:error.statusCode?error.message:"Failed to delete path"})}}),app.delete("/__api/paths",requireEditMode,(req,res)=>{let paths=req.body&&req.body.paths||[];if(!Array.isArray(paths)||paths.length===0)return res.status(400).json({error:"Paths must be a non-empty array"});let deleted=[];try{paths.forEach(targetPath=>{deleteExplorerPath(targetPath),deleted.push(targetPath)}),res.json({success:!0,deleted})}catch(error){console.error(colors.red(`Failed to delete paths: ${error.message}`)),res.status(error.statusCode||500).json({error:error.statusCode?error.message:"Failed to delete paths",deleted})}}),app.post("/__api/upload",requireEditMode,enforceUploadRequestSize,upload.any(),(req,res)=>{let parentPath=req.body&&req.body.parentPath||"/",files=req.files||[];if(!files.length)return res.status(400).json({error:"No files uploaded"});if(files.reduce((sum,file)=>sum+file.size,0)>MAX_UPLOAD_TOTAL_SIZE)return cleanupUploadedTempFiles(files),res.status(413).json({error:"Total upload size exceeds 2GB limit"});let uploaded=[],failed=[];files.forEach(file=>{try{let{targetPath,parentFullPath,parts}=getUploadTargetPath(parentPath,file.originalname);if(existsSync(targetPath)){failed.push({name:file.originalname,error:"Path already exists",statusCode:409});return}if(ensureUploadParent(parentFullPath,parts),existsSync(targetPath)){failed.push({name:file.originalname,error:"Path already exists",statusCode:409});return}moveUploadedFile(file.path,targetPath),uploaded.push({name:file.originalname,path:path.posix.join(normalizeExplorerInputPath(parentPath),...parts)})}catch(error){failed.push({name:file.originalname,error:error.message,statusCode:error.statusCode||500})}finally{existsSync(file.path)&&rmSync(file.path,{force:!0})}}),res.status(failed.length?207:200).json({success:failed.length===0,uploaded,failed})}),app.get("/__api/archive/preview",requireEditMode,async(req,res)=>{try{let preview=await archiveService.listArchive(normalizeExplorerInputPath(req.query.path||"/"));res.json(preview)}catch(error){res.status(error.statusCode||500).json({error:error.message})}}),app.post("/__api/archive/jobs",requireEditMode,(req,res)=>{let payload=req.body||{},operation=payload.operation;if(operation!=="create"&&operation!=="extract")return res.status(400).json({error:"Archive operation must be create or extract"});try{let job=archiveService.startJob(operation,payload);res.status(202).json({id:job.id,status:job.status,type:job.type})}catch(error){res.status(error.statusCode||500).json({error:error.message})}}),app.get("/__api/archive/jobs/:id",requireEditMode,(req,res)=>{let job=archiveService.getJob(req.params.id);if(!job)return res.status(404).json({error:"Archive job not found"});res.json({id:job.id,type:job.type,status:job.status,progress:job.progress,result:job.result,error:job.error,createdAt:job.createdAt,finishedAt:job.finishedAt||null})}),app.delete("/__api/archive/jobs/:id",requireEditMode,(req,res)=>{try{let job=archiveService.cancelJob(req.params.id);res.json({id:job.id,status:job.status})}catch(error){res.status(error.statusCode||500).json({error:error.message})}}),app.use((error,req,res,next)=>{if(error instanceof multer.MulterError){cleanupUploadedTempFiles(req.files);let statusCode=error.code==="LIMIT_FILE_SIZE"||error.code==="LIMIT_FILE_COUNT"?413:400;return res.status(statusCode).json({error:error.message})}if(error)return console.error(colors.red(`File explorer request failed: ${error.message}`)),res.status(error.statusCode||500).json({error:error.message||"Request failed"});next()}),startServer()}function startServer(){httpServer=require("http").createServer(app),httpServer.requestTimeout=0,httpServer.listen(Number.parseInt(process.env.PORT,10),getServerHost(),()=>{if(console.info([colors.yellow(`
156
+ `;function isArchivePath(filePath){return hasArchiveExtension(filePath,extensions)}function isCompressedTar(filePath){return/\.(tar\.gz|tgz|tar\.bz2|tbz|tbz2|tar\.xz|txz)$/i.test(filePath)}function parse7ZipList(output){let separator=output.indexOf("----------");return separator<0?[]:output.slice(separator+10).split(/\r?\n\r?\n/).map(block=>{let values={};return block.split(/\r?\n/).forEach(line=>{let index=line.indexOf(" = ");index>0&&(values[line.slice(0,index)]=line.slice(index+3))}),values}).filter(values=>values.Path).map(values=>({path:values.Path.replace(/\\/g,"/"),isDirectory:values.Folder==="+"||String(values.Attributes||"").startsWith("D"),size:Number(values.Size||0),packedSize:Number(values["Packed Size"]||0),encrypted:values.Encrypted==="+",modified:values.Modified||null,attributes:values.Attributes||""}))}function run7Zip(args,onProcess){return new Promise((resolve,reject)=>{try{process.platform!=="win32"&&chmodSync(path7za,493)}catch(error){return reject(createArchiveError(`Unable to prepare bundled 7-Zip binary: ${error.message}`,500))}let child=spawn(path7za,args,{stdio:["ignore","pipe","pipe"]}),stderr="",stdout="";onProcess&&onProcess(child),child.stdout.on("data",chunk=>{stdout+=chunk.toString()}),child.stderr.on("data",chunk=>{stderr+=chunk.toString()}),child.once("error",reject),child.once("close",code=>{if(code===0)return resolve(stdout);reject(createArchiveError(stderr.trim()||`7-Zip exited with code ${code}`,422))})})}async function list7Zip(fullPath){let output=await run7Zip(["l","-slt","--",fullPath]),entries=parse7ZipList(output);if(!isCompressedTar(fullPath))return entries;let tempRoot=await fsPromises.mkdtemp(path.join(os.tmpdir(),"mock-service-cli-archive-list-"));try{await run7Zip(["e","-y",`-o${tempRoot}`,"--",fullPath]);let tarName=(await fsPromises.readdir(tempRoot)).find(name=>/\.tar$/i.test(name));return tarName?await list7Zip(path.join(tempRoot,tarName)):entries}finally{rmSync(tempRoot,{recursive:!0,force:!0})}}async function listRar(fullPath){let list=(await createExtractorFromFile({filepath:fullPath})).getFileList();if(list.arcHeader.flags&&list.arcHeader.flags.headerEncrypted)throw createArchiveError("Encrypted archives are not supported",422);return[...list.fileHeaders].map(header=>({path:header.name.replace(/\\/g,"/"),isDirectory:!!(header.flags&&header.flags.directory),size:Number(header.unpSize||0),packedSize:Number(header.packSize||0),encrypted:!!(header.flags&&header.flags.encrypted),modified:header.time||null,attributes:""}))}async function listEntries(fullPath){return path.extname(fullPath).toLowerCase()===".rar"?listRar(fullPath):list7Zip(fullPath)}async function extractRar(job,sourcePath,targetPath){await new Promise((resolve,reject)=>{let worker=new Worker(RAR_EXTRACT_WORKER,{eval:!0,workerData:{sourcePath,targetPath}}),settled=!1,finish=(callback,value)=>{settled||(settled=!0,job.child=null,callback(value))};job.child={kill:()=>worker.terminate()},worker.on("message",message=>{message&&message.success?finish(resolve):finish(reject,createArchiveError(message&&message.error||"RAR extraction failed",422))}),worker.on("error",error=>finish(reject,error)),worker.on("exit",code=>{if(!settled&&code!==0){let message=job.cancelled?"Archive job cancelled":"RAR extraction stopped";finish(reject,createArchiveError(message,499))}})})}async function extract(job,sourcePath,targetPath){if(path.extname(sourcePath).toLowerCase()===".rar")return extractRar(job,sourcePath,targetPath);await run7Zip(["x","-y",`-o${targetPath}`,"--",sourcePath],child=>{job.child=child})}module2.exports={capabilities,extract,isArchivePath,listEntries}}});var require_archiveService=__commonJS({"src/lib/archiveService.js"(exports2,module2){var{createWriteStream,existsSync,lstatSync,mkdirSync,promises:fsPromises,realpathSync,renameSync,rmSync}=require("fs"),path=require("path"),crypto=require("crypto"),archiver=require("archiver"),archiveProvider=require_ultra(),{createArchiveError,isInside,isSafeArchiveEntry}=require_archiveShared(),MAX_ARCHIVE_SIZE=2*1024*1024*1024,MAX_ARCHIVE_ENTRIES=1e4,MAX_COMPRESSION_RATIO=100,ArchiveService=class{constructor({rootPath,resolvePath,getChildPath}){this.rootPath=rootPath,this.resolvePath=resolvePath,this.getChildPath=getChildPath,this.jobs=new Map}resolveExistingFile(inputPath){let fullPath=this.resolvePath(inputPath);if(!existsSync(fullPath))throw createArchiveError("Path not found",404);let stats=lstatSync(fullPath);if(!stats.isFile())throw createArchiveError("Archive path must be a file");if(!archiveProvider.isArchivePath(fullPath))throw createArchiveError("Unsupported archive format");if(stats.size>MAX_ARCHIVE_SIZE)throw createArchiveError("Archive exceeds 2GB limit",413);return fullPath}async listArchive(inputPath){let fullPath=this.resolveExistingFile(inputPath),entries=await archiveProvider.listEntries(fullPath);return this.assertEntriesSafe(entries,fullPath),{path:inputPath,name:path.basename(fullPath),entries,totalEntries:entries.length,totalSize:entries.reduce((total,entry)=>total+entry.size,0),totalPackedSize:entries.reduce((total,entry)=>total+entry.packedSize,0)}}assertEntriesSafe(entries,fullPath){if(!entries.length)throw createArchiveError("Archive contains no entries",422);if(entries.length>MAX_ARCHIVE_ENTRIES)throw createArchiveError("Archive contains too many entries",413);if(entries.some(entry=>entry.encrypted))throw createArchiveError("Encrypted archives are not supported",422);if(entries.some(entry=>entry.isSymbolicLink||!isSafeArchiveEntry(entry.path)))throw createArchiveError("Archive contains an unsafe entry path",422);let totalSize=entries.reduce((total,entry)=>total+entry.size,0),packedSize=Math.max(lstatSync(fullPath).size,1);if(totalSize>MAX_ARCHIVE_SIZE)throw createArchiveError("Archive expands beyond 2GB limit",413);if(totalSize/packedSize>MAX_COMPRESSION_RATIO)throw createArchiveError("Archive compression ratio exceeds limit",413)}startJob(type,payload){let id=crypto.randomUUID(),job={id,type,status:"queued",progress:{processedEntries:0,totalEntries:0},createdAt:new Date().toISOString(),result:null,error:null,cancelled:!1,child:null,archive:null};return this.jobs.set(id,job),setImmediate(async()=>{if(!job.cancelled){job.status="running";try{job.result=type==="create"?await this.createArchive(job,payload):await this.extractArchive(job,payload),job.status=job.cancelled?"cancelled":"completed"}catch(error){job.status=job.cancelled?"cancelled":"failed",job.error=error.message}finally{job.child=null,job.archive=null,job.finishedAt=new Date().toISOString()}}}),job}getJob(id){return this.jobs.get(id)}getCapabilities(){return archiveProvider.capabilities}cancelJob(id){let job=this.getJob(id);if(!job)throw createArchiveError("Archive job not found",404);return["completed","failed","cancelled"].includes(job.status)||(job.cancelled=!0,job.status="cancelled",job.child&&job.child.kill("SIGTERM"),job.archive&&job.archive.abort()),job}async createArchive(job,payload){let format=payload.format==="tar.gz"?"tar.gz":payload.format;if(!archiveProvider.capabilities.createFormats.includes(format)){let formats=archiveProvider.capabilities.createFormats.join(" and ");throw createArchiveError(`Supported creation formats are ${formats}`)}if(!Array.isArray(payload.sources)||payload.sources.length===0)throw createArchiveError("Sources must be a non-empty array");let sourcePaths=payload.sources.map(source=>this.resolvePath(source));sourcePaths.forEach(source=>{if(!existsSync(source))throw createArchiveError("Source path not found",404);if(lstatSync(source).isSymbolicLink())throw createArchiveError("Symbolic links cannot be archived");let realPath=realpathSync(source);if(!isInside(this.rootPath,realPath))throw createArchiveError("Access denied",403)}),await Promise.all(sourcePaths.map(source=>this.assertSourceTreeSafe(source)));let destinationPath=payload.destinationPath||path.posix.dirname(payload.sources[0]),archiveName=String(payload.name||"").trim(),requiredExtension=format==="zip"?".zip":".tar.gz",safeName=archiveName.endsWith(requiredExtension)?archiveName:`${archiveName}${requiredExtension}`,outputPath=this.getChildPath(destinationPath,safeName);if(existsSync(outputPath))throw createArchiveError("Archive path already exists",409);if(job.progress.totalEntries=sourcePaths.length,await new Promise((resolve,reject)=>{let output=createWriteStream(outputPath,{flags:"wx"}),archive=format==="zip"?archiver("zip",{zlib:{level:9}}):archiver("tar",{gzip:!0,gzipOptions:{level:9}});job.archive=archive,output.on("close",resolve),output.on("error",reject),archive.on("error",reject),archive.on("progress",progress=>{job.progress.processedEntries=progress.entries.processed,job.progress.totalEntries=progress.entries.total}),archive.pipe(output),sourcePaths.forEach(source=>{lstatSync(source).isDirectory()?archive.directory(source,path.basename(source)):archive.file(source,{name:path.basename(source)})}),archive.finalize()}).catch(error=>{throw rmSync(outputPath,{force:!0}),error}),job.cancelled)throw rmSync(outputPath,{force:!0}),createArchiveError("Archive job cancelled",499);return{path:outputPath,name:path.basename(outputPath)}}async extractArchive(job,payload){let sourcePath=this.resolveExistingFile(payload.path),destinationPath=this.resolvePath(payload.destinationPath||"/");if(!existsSync(destinationPath)||!lstatSync(destinationPath).isDirectory())throw createArchiveError("Extraction destination must be an existing directory",404);let listing=await this.listArchive(payload.path);job.progress.totalEntries=listing.totalEntries;let tempRoot=await fsPromises.mkdtemp(path.join(destinationPath,".mock-service-cli-archive-")),tempOutput=path.join(tempRoot,"output");mkdirSync(tempOutput);try{if(await archiveProvider.extract(job,sourcePath,tempOutput),job.cancelled)throw createArchiveError("Archive job cancelled",499);await this.assertExtractedTreeSafe(tempOutput);let outputEntries=await fsPromises.readdir(tempOutput);if(!outputEntries.length)throw createArchiveError("Archive produced no files",422);outputEntries.forEach(name=>{if(existsSync(path.join(destinationPath,name)))throw createArchiveError(`Destination already contains ${name}`,409)});for(let name of outputEntries)renameSync(path.join(tempOutput,name),path.join(destinationPath,name));return job.progress.processedEntries=job.progress.totalEntries,{destinationPath,entries:outputEntries}}finally{rmSync(tempRoot,{recursive:!0,force:!0})}}async assertExtractedTreeSafe(root){let rootRealPath=realpathSync(root),walk=async current=>{let entries=await fsPromises.readdir(current,{withFileTypes:!0});for(let entry of entries){let child=path.join(current,entry.name),stats=await fsPromises.lstat(child);if(stats.isSymbolicLink())throw createArchiveError("Archive contains symbolic links",422);let realPath=realpathSync(child);if(!isInside(rootRealPath,realPath))throw createArchiveError("Archive extracted outside its destination",422);stats.isDirectory()&&await walk(child)}};await walk(root)}async assertSourceTreeSafe(source){let stats=await fsPromises.lstat(source);if(stats.isSymbolicLink())throw createArchiveError("Symbolic links cannot be archived");if(!stats.isDirectory())return;let entries=await fsPromises.readdir(source,{withFileTypes:!0});await Promise.all(entries.map(entry=>this.assertSourceTreeSafe(path.join(source,entry.name))))}};module2.exports={ArchiveService,isArchivePath:archiveProvider.isArchivePath}}});var require_fileExplorerServer=__commonJS({"src/lib/fileExplorerServer.js"(){var express=require_express2(),{existsSync,readFileSync,statSync,lstatSync,rmSync,mkdirSync,writeFileSync,renameSync,realpathSync,copyFileSync,unlinkSync,constants:fsConstants,promises:fsPromises}=require("fs"),path=require("path"),os=require("os"),crypto=require("crypto"),multer=require_multer(),{UAParser}=require_ua_parser(),colors=require_safe(),portfinder=require_portfinder(),{exec}=require("child_process"),{dateFormat,logger,getServerHost,getServerUrls,hostAllowlistMiddleware,getDirectoryHiddenNames,normalizeRemoteAddress,openPathInFileManager}=require_utils3(),{getPackageVersion}=require_packageInfo(),{ArchiveService}=require_archiveService(),app=express(),log=logger(process.env.SILENT),argv=JSON.parse(process.env.ARGV),explorerRoot=path.resolve(process.env.EXPLORER_DIRECTORY||process.cwd()),explorerRootRealPath=realpathSync(explorerRoot),explorerRootId=crypto.createHash("sha256").update(explorerRootRealPath).digest("hex"),port=argv.p||argv.port,isEditMode=process.env.EXPLORER_EDIT==="true",explorerPassword=process.env.EXPLORER_AUTH||"",isAuthEnabled=!!explorerPassword,osHiddenEnabled=process.env.OS_HIDDEN_ENABLED!=="false"&&process.env.OS_HIDDEN_ENABLED!=="0",visitorKeys=new Set,httpServer=null,shuttingDown=!1,MAX_UPLOAD_FILE_SIZE=2*1024*1024*1024,MAX_UPLOAD_TOTAL_SIZE=2*1024*1024*1024,MAX_UPLOAD_FILE_COUNT=100,MAX_MULTIPART_OVERHEAD_SIZE=2*1024*1024,upload=multer({dest:path.join(os.tmpdir(),"mock-service-cli-upload"),preservePath:!0,limits:{fileSize:MAX_UPLOAD_FILE_SIZE,files:MAX_UPLOAD_FILE_COUNT,fields:10}}),archiveService=new ArchiveService({rootPath:explorerRootRealPath,resolvePath:resolveExplorerPath,getChildPath});function isPathInsideRoot(fullPath,resolvedRoot=explorerRootRealPath){let relativePath=path.relative(resolvedRoot,fullPath);return relativePath===""||!relativePath.startsWith("..")&&!path.isAbsolute(relativePath)}function normalizeExplorerInputPath(inputPath){let decodedPath=decodeURIComponent(String(inputPath||"/")).replace(/\\/g,"/");return!decodedPath||decodedPath==="."?"/":decodedPath.startsWith("/")?decodedPath:`/${decodedPath}`}function resolveExplorerPath(inputPath){let relativePath=normalizeExplorerInputPath(inputPath).replace(/^\/+/,""),fullPath=path.resolve(explorerRoot,relativePath);if(!isPathInsideRoot(fullPath,explorerRoot)){let error=new Error("Access denied");throw error.statusCode=403,error}if(!existsSync(fullPath))return fullPath;let realPath=realpathSync(fullPath);if(!isPathInsideRoot(realPath)){let error=new Error("Access denied");throw error.statusCode=403,error}return realPath}function validateEntryName(name){if(typeof name!="string")return"Name must be a string";let normalizedName=name.trim();if(!normalizedName||normalizedName==="."||normalizedName==="..")return"Invalid name";if(/[/\\\0<>:"|?*]/.test(normalizedName))return"Name contains invalid characters";if(process.platform==="win32"){let upperName=normalizedName.replace(/[. ]+$/g,"").split(".")[0].toUpperCase();if(new Set(["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"]).has(upperName)||normalizedName.endsWith(" ")||normalizedName.endsWith("."))return"Name is not supported on Windows"}return null}function getChildPath(parentPath,name){let nameError=validateEntryName(name);if(nameError){let error=new Error(nameError);throw error.statusCode=400,error}let parentFullPath=resolveExplorerPath(parentPath||"/");if(!existsSync(parentFullPath)||!statSync(parentFullPath).isDirectory()){let error=new Error("Parent directory not found");throw error.statusCode=404,error}let childPath=path.resolve(parentFullPath,name.trim());if(!isPathInsideRoot(childPath)){let error=new Error("Access denied");throw error.statusCode=403,error}return childPath}function requireEditMode(req,res,next){if(!isEditMode)return res.status(403).json({error:"File explorer is read-only. Restart with --edit to modify files."});next()}function isValidExplorerPassword(value){if(!isAuthEnabled)return!0;let provided=Buffer.from(String(value||"")),expected=Buffer.from(explorerPassword);return provided.length===expected.length&&crypto.timingSafeEqual(provided,expected)}function getExplorerPassword(req){return req.get("x-file-explorer-password")||req.body&&req.body.password}function requireExplorerAuth(req,res,next){if(!isValidExplorerPassword(getExplorerPassword(req)))return res.status(401).json({error:"Authentication required"});next()}function logExplorerVisit(req){let userAgent=req.get("user-agent")||"",ip=normalizeRemoteAddress(req.socket&&req.socket.remoteAddress),visitorKey=`${ip}
157
+ ${userAgent}`;if(visitorKeys.has(visitorKey))return;visitorKeys.add(visitorKey);let parsed=new UAParser(userAgent).getResult(),browser=[parsed.browser.name,parsed.browser.version].filter(Boolean).join(" ")||"Unknown",operatingSystem=[parsed.os.name,parsed.os.version].filter(Boolean).join(" ")||"Unknown";log.info(`File explorer visitor: ip=${ip}, os=${operatingSystem}, browser=${browser}, userAgent=${userAgent}`)}function getUploadTargetPath(parentPath,originalName){let normalizedName=String(originalName||"").replace(/\\/g,"/").replace(/^\/+/,""),parts=normalizedName.split("/").filter(Boolean);if(parts.length===0||normalizedName!==parts.join("/")){let error=new Error("Invalid upload path");throw error.statusCode=400,error}parts.forEach(part=>{let nameError=validateEntryName(part);if(nameError){let error=new Error(nameError);throw error.statusCode=400,error}});let parentFullPath=resolveExplorerPath(parentPath||"/");if(!existsSync(parentFullPath)||!statSync(parentFullPath).isDirectory()){let error=new Error("Parent directory not found");throw error.statusCode=404,error}let targetPath=path.resolve(parentFullPath,...parts);if(!isPathInsideRoot(targetPath)){let error=new Error("Access denied");throw error.statusCode=403,error}return{targetPath,parentFullPath,parts}}function ensureUploadParent(parentFullPath,parts){let current=parentFullPath;parts.slice(0,-1).forEach(part=>{if(current=path.join(current,part),existsSync(current)){let stats=lstatSync(current);if(!stats.isDirectory()||stats.isSymbolicLink()||!isPathInsideRoot(realpathSync(current))){let error=new Error("Upload path is not a safe directory");throw error.statusCode=403,error}}else mkdirSync(current)})}function moveUploadedFile(sourcePath,targetPath){copyFileSync(sourcePath,targetPath,fsConstants.COPYFILE_EXCL),unlinkSync(sourcePath)}function cleanupUploadedTempFiles(files=[]){files.forEach(file=>{file&&file.path&&existsSync(file.path)&&rmSync(file.path,{force:!0})})}function enforceUploadRequestSize(req,res,next){let contentLength=Number(req.get("content-length"));if(Number.isFinite(contentLength)&&contentLength>MAX_UPLOAD_TOTAL_SIZE+MAX_MULTIPART_OVERHEAD_SIZE)return res.status(413).json({error:"Total upload size exceeds 2GB limit"});next()}function deleteExplorerPath(targetPath){let fullPath=resolveExplorerPath(targetPath);if(path.resolve(fullPath)===explorerRootRealPath){let error=new Error("Cannot delete explorer root");throw error.statusCode=400,error}if(!existsSync(fullPath)){let error=new Error("Path not found");throw error.statusCode=404,error}rmSync(fullPath,{recursive:!0,force:!1})}process.env.PORT?init():(portfinder.basePort=port||8090,portfinder.getPort(function(err,foundPort){if(err)throw err;process.env.PORT=foundPort,init()}));function init(){app.use(hostAllowlistMiddleware()),app.use(express.json());let faviconInstanceId=crypto.randomUUID(),explorerFaviconUrl=`/favicon-file-explorer.svg?instance=${faviconInstanceId}`,loginFaviconUrl=`/favicon-file-explorer-login.svg?instance=${faviconInstanceId}`,sendFavicon=(filename,res)=>{res.type("image/svg+xml").set("Cache-Control","no-store").sendFile(path.resolve(__dirname,filename))},sendExplorerPage=(filename,faviconUrl,res)=>{let htmlPath=path.resolve(__dirname,filename);if(!existsSync(htmlPath))return res.status(404).send("File explorer page not found");res.type("html").send(readFileSync(htmlPath,"utf8").replace("__FILE_EXPLORER_FAVICON_URL__",faviconUrl))};app.get("/favicon-file-explorer.svg",(req,res)=>sendFavicon("./favicon-file-explorer.svg",res)),app.get("/favicon-file-explorer-login.svg",(req,res)=>sendFavicon("./favicon-file-explorer-login.svg",res)),app.get("/",(req,res)=>sendExplorerPage("./file-explorer.html",explorerFaviconUrl,res)),app.get("/__login",(req,res)=>sendExplorerPage("./file-explorer-login.html",loginFaviconUrl,res)),app.post("/__api/auth/verify",(req,res)=>{if(!isValidExplorerPassword(getExplorerPassword(req)))return res.status(401).json({error:"Invalid password"});res.json({success:!0,authEnabled:isAuthEnabled})}),app.use("/__api",requireExplorerAuth),app.get("/__api/config",(req,res)=>{logExplorerVisit(req),res.json({editMode:isEditMode,authEnabled:isAuthEnabled,rootId:explorerRootId})}),app.get("/__api/archive/capabilities",requireEditMode,(req,res)=>{res.json(archiveService.getCapabilities())}),app.get("/__api/health",(req,res)=>{res.json({success:!0})}),app.get("/__api/list",async(req,res)=>{let dirPath=normalizeExplorerInputPath(req.query.path||"/"),fullPath;try{fullPath=resolveExplorerPath(dirPath)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(!existsSync(fullPath))return res.status(404).json({error:"Path not found"});try{if(!(await fsPromises.lstat(fullPath)).isDirectory())return res.status(400).json({error:"Not a directory"});let files=await fsPromises.readdir(fullPath,{withFileTypes:!0}),hiddenNames=await getDirectoryHiddenNames(fullPath,files.map(file=>file.name),{osHidden:osHiddenEnabled}),result=await Promise.all(files.map(async file=>{let filePath=path.join(fullPath,file.name),fileStats,hasError=!1;try{fileStats=await fsPromises.lstat(filePath)}catch{hasError=!0}let relativePath=path.posix.join(dirPath,file.name),isDirectory=hasError?file.isDirectory():fileStats.isDirectory();return{name:file.name,path:relativePath.replace(/\\/g,"/"),isDirectory,size:hasError?0:fileStats.size,mtime:hasError?new Date:fileStats.mtime,birthtime:hasError?new Date:fileStats.birthtime,isHidden:hiddenNames.has(file.name),error:hasError?"Cannot access file":null}}));result.sort((a,b)=>a.isDirectory!==b.isDirectory?a.isDirectory?-1:1:a.name.localeCompare(b.name)),res.json({currentPath:dirPath,parentPath:dirPath==="/"?null:path.posix.dirname(dirPath),files:result})}catch(error){res.status(500).json({error:error.message})}}),app.get("/__api/file",(req,res)=>{let filePath=normalizeExplorerInputPath(req.query.path||"/"),fullPath;try{fullPath=resolveExplorerPath(filePath)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(!existsSync(fullPath))return res.status(404).json({error:"File not found"});let stats=statSync(fullPath);if(stats.isDirectory())return res.status(400).json({error:"Is a directory"});if(req.query.download==="1")return res.download(fullPath,path.basename(filePath));let ext=path.extname(filePath).toLowerCase(),imageExts=[".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg",".ico"],textExts=[".txt",".json",".js",".css",".html",".xml",".md",".csv",".yaml",".yml",".log"];if(imageExts.includes(ext))res.sendFile(fullPath);else if(textExts.includes(ext)||stats.size<1024*1024)try{let content=readFileSync(fullPath,"utf-8");res.json({name:path.basename(filePath),type:"text",content,size:stats.size})}catch{res.download(fullPath)}else res.download(fullPath)}),app.post("/__api/open-in-explorer",async(req,res)=>{let filePath=normalizeExplorerInputPath(req.body.path||"/"),fullPath;try{fullPath=resolveExplorerPath(filePath)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(!existsSync(fullPath))return res.status(404).json({error:"Path not found"});let result=await openPathInFileManager(fullPath);if(!result.ok)return result.unsupported?res.status(400).json({error:"Unsupported platform"}):(console.error(colors.red(`Failed to open in explorer: ${result.error.message}`)),res.status(500).json({error:"Failed to open in explorer"}));res.json({success:!0,path:fullPath})}),app.post("/__api/path",requireEditMode,(req,res)=>{let parentPath=req.body&&req.body.parentPath||"/",name=req.body&&req.body.name,type=req.body&&req.body.type||"file";if(type!=="file"&&type!=="directory")return res.status(400).json({error:"Invalid type"});let fullPath;try{fullPath=getChildPath(parentPath,name)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(existsSync(fullPath))return res.status(409).json({error:"Path already exists"});try{type==="directory"?mkdirSync(fullPath):writeFileSync(fullPath,""),res.json({success:!0,path:fullPath})}catch(error){console.error(colors.red(`Failed to create path: ${error.message}`)),res.status(500).json({error:"Failed to create path"})}}),app.patch("/__api/path",requireEditMode,(req,res)=>{let sourcePath=req.body&&req.body.path,name=req.body&&req.body.name,fullPath,nextPath;try{if(fullPath=resolveExplorerPath(sourcePath),path.resolve(fullPath)===explorerRootRealPath)return res.status(400).json({error:"Cannot rename explorer root"});if(!existsSync(fullPath))return res.status(404).json({error:"Path not found"});nextPath=getChildPath(path.posix.dirname(normalizeExplorerInputPath(sourcePath||"/")),name)}catch(error){return res.status(error.statusCode||500).json({error:error.message})}if(existsSync(nextPath))return res.status(409).json({error:"Path already exists"});try{renameSync(fullPath,nextPath),res.json({success:!0,path:sourcePath,nextPath})}catch(error){console.error(colors.red(`Failed to rename path: ${error.message}`)),res.status(500).json({error:"Failed to rename path"})}}),app.delete("/__api/path",requireEditMode,(req,res)=>{let targetPath=req.body&&req.body.path||"/";try{deleteExplorerPath(targetPath),res.json({success:!0,path:targetPath})}catch(error){console.error(colors.red(`Failed to delete path: ${error.message}`)),res.status(error.statusCode||500).json({error:error.statusCode?error.message:"Failed to delete path"})}}),app.delete("/__api/paths",requireEditMode,(req,res)=>{let paths=req.body&&req.body.paths||[];if(!Array.isArray(paths)||paths.length===0)return res.status(400).json({error:"Paths must be a non-empty array"});let deleted=[];try{paths.forEach(targetPath=>{deleteExplorerPath(targetPath),deleted.push(targetPath)}),res.json({success:!0,deleted})}catch(error){console.error(colors.red(`Failed to delete paths: ${error.message}`)),res.status(error.statusCode||500).json({error:error.statusCode?error.message:"Failed to delete paths",deleted})}}),app.post("/__api/upload",requireEditMode,enforceUploadRequestSize,upload.any(),(req,res)=>{let parentPath=req.body&&req.body.parentPath||"/",files=req.files||[];if(!files.length)return res.status(400).json({error:"No files uploaded"});if(files.reduce((sum,file)=>sum+file.size,0)>MAX_UPLOAD_TOTAL_SIZE)return cleanupUploadedTempFiles(files),res.status(413).json({error:"Total upload size exceeds 2GB limit"});let uploaded=[],failed=[];files.forEach(file=>{try{let{targetPath,parentFullPath,parts}=getUploadTargetPath(parentPath,file.originalname);if(existsSync(targetPath)){failed.push({name:file.originalname,error:"Path already exists",statusCode:409});return}if(ensureUploadParent(parentFullPath,parts),existsSync(targetPath)){failed.push({name:file.originalname,error:"Path already exists",statusCode:409});return}moveUploadedFile(file.path,targetPath),uploaded.push({name:file.originalname,path:path.posix.join(normalizeExplorerInputPath(parentPath),...parts)})}catch(error){failed.push({name:file.originalname,error:error.message,statusCode:error.statusCode||500})}finally{existsSync(file.path)&&rmSync(file.path,{force:!0})}}),res.status(failed.length?207:200).json({success:failed.length===0,uploaded,failed})}),app.get("/__api/archive/preview",requireEditMode,async(req,res)=>{try{let preview=await archiveService.listArchive(normalizeExplorerInputPath(req.query.path||"/"));res.json(preview)}catch(error){res.status(error.statusCode||500).json({error:error.message})}}),app.post("/__api/archive/jobs",requireEditMode,(req,res)=>{let payload=req.body||{},operation=payload.operation;if(operation!=="create"&&operation!=="extract")return res.status(400).json({error:"Archive operation must be create or extract"});try{let job=archiveService.startJob(operation,payload);res.status(202).json({id:job.id,status:job.status,type:job.type})}catch(error){res.status(error.statusCode||500).json({error:error.message})}}),app.get("/__api/archive/jobs/:id",requireEditMode,(req,res)=>{let job=archiveService.getJob(req.params.id);if(!job)return res.status(404).json({error:"Archive job not found"});res.json({id:job.id,type:job.type,status:job.status,progress:job.progress,result:job.result,error:job.error,createdAt:job.createdAt,finishedAt:job.finishedAt||null})}),app.delete("/__api/archive/jobs/:id",requireEditMode,(req,res)=>{try{let job=archiveService.cancelJob(req.params.id);res.json({id:job.id,status:job.status})}catch(error){res.status(error.statusCode||500).json({error:error.message})}}),app.use((error,req,res,next)=>{if(error instanceof multer.MulterError){cleanupUploadedTempFiles(req.files);let statusCode=error.code==="LIMIT_FILE_SIZE"||error.code==="LIMIT_FILE_COUNT"?413:400;return res.status(statusCode).json({error:error.message})}if(error)return console.error(colors.red(`File explorer request failed: ${error.message}`)),res.status(error.statusCode||500).json({error:error.message||"Request failed"});next()}),startServer()}function startServer(){httpServer=require("http").createServer(app),httpServer.requestTimeout=0,httpServer.listen(Number.parseInt(process.env.PORT,10),getServerHost(),()=>{if(console.info([colors.yellow(`
158
158
  Starting up file-explorer-server, serving `),colors.cyan(explorerRoot),colors.yellow(` ${dateFormat("YYYY-mm-dd HH:MM:SS",new Date)}`)].join("")),console.info([colors.yellow(`
159
159
  \u{1F30D} file-explorer-server version: `),colors.cyan(getPackageVersion()),`
160
160
  `].join("")),console.info(colors.yellow(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mock-service-cli-ultra",
3
- "version": "4.9.1",
3
+ "version": "4.9.2",
4
4
  "description": "🦅 Local Mock/Static/SPA server, Http?s request proxy, API overview page, File explorer (Ultra archive formats)",
5
5
  "main": "./dist/mockServer.js",
6
6
  "bin": {