mock-service-cli 4.3.2 → 4.5.0

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
@@ -37,6 +37,12 @@ npm install --global mock-service-cli
37
37
  brew install mock-service-cli
38
38
  ```
39
39
 
40
+ 需要 RAR、7z、bzip2、xz 等高级归档格式时,安装 Ultra 版。它与轻量版使用相同的命令,不能同时全局安装:
41
+
42
+ ```bash
43
+ npm install --global mock-service-cli-ultra
44
+ ```
45
+
40
46
  ### 局部安装
41
47
 
42
48
  ```bash
@@ -71,10 +77,12 @@ npx mock-service-cli [options] [path]
71
77
  | `-P` 或 `--web-port` | Web 服务器端口 | 9090 |
72
78
  | `-b` 或 `--web-baseurl` | 指定 SPA Web 服务器的公共路径 | - |
73
79
  | `-R` 或 `--static-server` | 启用静态服务器,指定静态资源目录 | - |
80
+ | `--static-config <file>` | 静态服务器的 JSON 配置:热更新、HTTPS、挂载、代理与 SPA 回退 | - |
74
81
  | `-w` 或 `--open` | 自动打开 API 概览页、文件浏览器页 | false |
75
82
  | `-e` 或 `--explorer` | 启用文件浏览器服务器,指定要浏览的目录 | ./ |
76
- | `--edit` | 启用文件浏览器的新建、重命名和删除操作 | false |
77
- | `--host` | 将全部 Web 服务暴露到所有 IPv4 网卡 | false |
83
+ | `--edit` | 启用文件浏览器的新建、重命名、删除和上传操作 | false |
84
+ | `--auth <password>` | 为文件浏览器启用密码认证(仅可搭配 `--explorer`) | - |
85
+ | `--host [allowlist-file]` | 暴露全部 IPv4 网卡;传入文件时仅允许白名单 IP 访问 | false |
78
86
 
79
87
  ## 📖 使用示例
80
88
 
@@ -99,8 +107,18 @@ mock-service-cli -f ./mock.js
99
107
  ```bash
100
108
  # 启动静态服务器
101
109
  mock-service-cli -R ./public
110
+
111
+ # 使用 Live Server 风格的热更新配置
112
+ mock-service-cli -R ./public --static-config ./static-server.json
102
113
  ```
103
114
 
115
+ 静态服务器会监听资源变化并向 HTML 页面注入热更新客户端:CSS 文件更新时替换样式表,其余变更刷新页面。
116
+ 默认不打开浏览器;在配置中设置 `"open": true` 或提供页面路径即可打开。完整配置字段和示例见
117
+ [`docs/static-server.config.example.json`](./docs/static-server.config.example.json):支持忽略规则、SPA 回退、挂载目录、代理、HTTPS、CORS、响应头和自定义浏览器命令。
118
+ `-p`、`--host`、`-A` 和 `--proxy-options` 仍可使用,且同名 CLI 配置优先。
119
+ 未设置 `spaFallback` 时,根目录和子目录会显示可点击的目录索引,不会自动加载 `index.html`;用户可直接访问该文件。
120
+ 只有显式设置 `"spaFallback": "/index.html"`(或其他入口)时,未命中的路由才会返回 SPA 入口页。
121
+
104
122
  ### Web 服务器 (SPA)
105
123
 
106
124
  ```bash
@@ -136,13 +154,32 @@ mock-service-cli -e ./ -p 9090
136
154
  # 启用文件编辑操作
137
155
  mock-service-cli -e ./ --edit
138
156
 
157
+ # 启用文件浏览器密码认证
158
+ mock-service-cli -e ./ --auth 'local-password'
159
+
139
160
  # 暴露到局域网(编辑操作仍需额外传入 --edit)
140
161
  mock-service-cli -e ./ --host
162
+
163
+ # 仅向白名单 IP 暴露服务
164
+ mock-service-cli -e ./ --host ./allowed-ips.txt
141
165
  ```
142
166
 
143
167
  默认情况下,Mock、SPA、Static 和 File Explorer 服务只监听 `127.0.0.1`。
144
- `--host` 会使这些服务监听所有 IPv4 网卡,请仅在可信网络中使用。文件浏览器默认只读;
145
- 必须在启动时传入 `--edit` 才能创建、重命名或删除文件。
168
+ `--host` 会使这些服务监听所有 IPv4 网卡,请仅在可信网络中使用。传入白名单文件时,服务仍监听全部 IPv4 网卡,
169
+ 但仅允许 `localhost`、`127.0.0.1`、`::1` 及文件中的 IP/CIDR 访问;空行和行首 `#` 注释会忽略,非法或空白名单会阻止启动。
170
+ 该规则同时作用于 Mock、SPA、Static、File Explorer 和 Socket 服务。
171
+
172
+ 文件浏览器默认只读;必须在启动时传入 `--edit` 才能创建、重命名、删除或上传。上传文件支持多选,上传文件夹会保留目录层级;
173
+ 同名路径不会覆盖,其他无冲突文件仍会继续上传。单文件和单次请求最大 2GB,单次最多 100 个文件;
174
+ 文件夹上传会按最多 100 个文件且 1GB 自动分批,依次完成上传。大文件会先写入系统临时目录再复制到目标目录,
175
+ 上传时请确保临时目录和目标磁盘合计至少有文件大小两倍的可用空间。
176
+
177
+ 编辑模式下还可压缩选中项、预览压缩包目录和解压压缩包。轻量版创建压缩包支持 ZIP 和 TAR.GZ,预览和解压支持 ZIP、TAR 与 TAR.GZ;归档操作在后台执行,可取消;单个压缩包及解压后的总大小上限为 2GB,压缩包内最多 10,000 项,且会拒绝加密包、路径穿越、符号链接和目标冲突。
178
+
179
+ Ultra 版额外支持 RAR、7z、gzip、bzip2 与 xz 系列的预览和解压;RAR 为只读支持,不能创建。Ultra 包会额外安装约 12MB 的跨平台 7-Zip 二进制,RAR 通过只读解码器处理;轻量版不包含这些二进制。
180
+
181
+ `--auth` 会在文件浏览器中显示登录页,并在每次页面加载和每个 API 请求时验证密码。密码仅保存在当前浏览器标签页的
182
+ `sessionStorage` 中,但命令行参数仍可能暴露在 shell 历史和进程列表里,因此只适用于可信本机或局域网环境。
146
183
 
147
184
  ## 📝 编写 Mock 文件
148
185
 
@@ -4,6 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>API 概览 - Mock Service</title>
7
+ <link rel="icon" type="image/svg+xml" href="/favicon-api-overview.svg">
7
8
  <style>
8
9
  * {
9
10
  margin: 0;
@@ -0,0 +1 @@
1
+ {"edition":"light"}
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="14" fill="#0f766e"/>
3
+ <path d="M21 23 32 17l11 6v13l-11 6-11-6V23z" fill="none" stroke="#99f6e4" stroke-width="4" stroke-linejoin="round"/>
4
+ <path d="M32 23v13M21 23l11 6 11-6" stroke="#99f6e4" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <circle cx="17" cy="45" r="5" fill="#fbbf24"/>
6
+ <circle cx="47" cy="45" r="5" fill="#fbbf24"/>
7
+ <path d="M21 43h22" stroke="#fbbf24" stroke-width="4" stroke-linecap="round"/>
8
+ </svg>
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="14" fill="#1e40af"/>
3
+ <path d="M14 20c0-3.3 2.7-6 6-6h11l5 6h8c3.3 0 6 2.7 6 6v8H14V20z" fill="#93c5fd"/>
4
+ <rect x="20" y="31" width="25" height="20" rx="4" fill="#f8fafc"/>
5
+ <path d="M26 31v-4a6.5 6.5 0 0 1 13 0v4" fill="none" stroke="#f8fafc" stroke-width="5" stroke-linecap="round"/>
6
+ <circle cx="32.5" cy="40" r="3" fill="#1e40af"/>
7
+ <path d="M32.5 43v3" stroke="#1e40af" stroke-width="3" stroke-linecap="round"/>
8
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="14" fill="#1d4ed8"/>
3
+ <path d="M12 22c0-3.3 2.7-6 6-6h11l5 6h12c3.3 0 6 2.7 6 6v17c0 3.3-2.7 6-6 6H18c-3.3 0-6-2.7-6-6V22z" fill="#fbbf24"/>
4
+ <path d="M12 29h40v16c0 3.3-2.7 6-6 6H18c-3.3 0-6-2.7-6-6V29z" fill="#fde68a"/>
5
+ <path d="M21 37h22" stroke="#1d4ed8" stroke-width="4" stroke-linecap="round"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="14" fill="#0f766e"/>
3
+ <path d="M17 19h30v26H17z" fill="none" stroke="#ccfbf1" stroke-width="4" stroke-linejoin="round"/>
4
+ <path d="M24 28h16M24 36h11" stroke="#ccfbf1" stroke-width="4" stroke-linecap="round"/>
5
+ <circle cx="47" cy="45" r="7" fill="#fbbf24"/>
6
+ </svg>
@@ -0,0 +1,60 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>文件浏览器登录</title>
7
+ <link rel="icon" type="image/svg+xml" href="/favicon-file-explorer-login.svg" />
8
+ <style>
9
+ * { box-sizing: border-box; }
10
+ body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: #f4f6f8; color: #202124; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
11
+ main { width: min(360px, calc(100vw - 32px)); padding: 28px; background: #fff; border: 1px solid #dde1e6; border-radius: 8px; box-shadow: 0 12px 28px rgba(0, 0, 0, 0.08); }
12
+ h1 { margin: 0 0 22px; font-size: 20px; }
13
+ label { display: block; margin-bottom: 8px; font-size: 14px; }
14
+ input { width: 100%; height: 38px; padding: 8px 10px; border: 1px solid #b9c1cb; border-radius: 4px; font: inherit; }
15
+ button { width: 100%; height: 38px; margin-top: 16px; border: 0; border-radius: 4px; background: #276ef1; color: #fff; cursor: pointer; font: inherit; }
16
+ button:disabled { opacity: 0.6; cursor: wait; }
17
+ #error { min-height: 20px; margin: 12px 0 0; color: #c62828; font-size: 13px; }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <main>
22
+ <h1>文件浏览器</h1>
23
+ <form id="loginForm">
24
+ <label for="password">访问密码</label>
25
+ <input id="password" type="password" autocomplete="current-password" required autofocus />
26
+ <button id="submitButton" type="submit">登录</button>
27
+ <p id="error" role="alert"></p>
28
+ </form>
29
+ </main>
30
+ <script>
31
+ const storageKey = 'mock-service-cli.file-explorer.password';
32
+ const form = document.getElementById('loginForm');
33
+ const passwordInput = document.getElementById('password');
34
+ const submitButton = document.getElementById('submitButton');
35
+ const errorElement = document.getElementById('error');
36
+
37
+ form.addEventListener('submit', async event => {
38
+ event.preventDefault();
39
+ const password = passwordInput.value;
40
+ submitButton.disabled = true;
41
+ errorElement.textContent = '';
42
+ try {
43
+ const response = await fetch('/__api/auth/verify', {
44
+ method: 'POST',
45
+ headers: { 'Content-Type': 'application/json', 'X-File-Explorer-Password': password },
46
+ body: JSON.stringify({ password })
47
+ });
48
+ if (!response.ok) throw new Error('密码不正确');
49
+ sessionStorage.setItem(storageKey, password);
50
+ window.location.replace('/');
51
+ } catch (error) {
52
+ errorElement.textContent = error.message || '登录失败';
53
+ passwordInput.select();
54
+ } finally {
55
+ submitButton.disabled = false;
56
+ }
57
+ });
58
+ </script>
59
+ </body>
60
+ </html>