@blocklet/cli 1.16.52-beta-20250916-025146-35d976f4 → 1.16.52-beta-20250917-070942-7ee57044
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/lib/commands/server/command.js +7 -0
- package/lib/commands/server/nginx.js +356 -0
- package/package.json +17 -17
|
@@ -18,6 +18,7 @@ const logs = require('./logs');
|
|
|
18
18
|
const status = require('./status');
|
|
19
19
|
const upgrade = require('./upgrade');
|
|
20
20
|
const migrate = require('./migrate');
|
|
21
|
+
const nginx = require('./nginx');
|
|
21
22
|
const { printVersionTip } = require('../../util');
|
|
22
23
|
|
|
23
24
|
module.exports = (parentCommand = '') => {
|
|
@@ -127,6 +128,12 @@ module.exports = (parentCommand = '') => {
|
|
|
127
128
|
.description('Migrate database from sqlite to postgres')
|
|
128
129
|
.action(parseOptions(migrate.run));
|
|
129
130
|
|
|
131
|
+
program
|
|
132
|
+
.command('nginx')
|
|
133
|
+
.option('--setup', 'Setup nginx environment for Blocklet Server (requires sudo)')
|
|
134
|
+
.description('Configure nginx as reverse proxy for Blocklet Server')
|
|
135
|
+
.action(parseOptions(nginx.run));
|
|
136
|
+
|
|
130
137
|
program.command('upgrade').description('Self-Upgrade Blocklet Server').action(parseOptions(upgrade.run));
|
|
131
138
|
|
|
132
139
|
program.on('--help', () => {
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const shelljs = require('shelljs');
|
|
6
|
+
const yaml = require('js-yaml');
|
|
7
|
+
const { printError, printInfo, printWarning, printSuccess, print } = require('../../util');
|
|
8
|
+
|
|
9
|
+
exports.run = ({ setup }) => {
|
|
10
|
+
if (!setup) {
|
|
11
|
+
printError('Missing required --setup flag. Usage: blocklet router --setup to configure nginx environment');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof process.getuid === 'function' && process.getuid() !== 0) {
|
|
16
|
+
printError(`You need ${chalk.red('root / sudo')} privileges to setup nginx environment.`);
|
|
17
|
+
printInfo(`Try running again with: ${chalk.cyan('sudo blocklet server nginx --setup')}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
printInfo('Starting nginx environment setup...');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
setupNginxEnvironment();
|
|
25
|
+
printSuccess('Nginx environment setup completed successfully!');
|
|
26
|
+
} catch (error) {
|
|
27
|
+
printError(`Failed to setup nginx environment: ${error.message}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function detectPlatform() {
|
|
33
|
+
const platform = os.platform();
|
|
34
|
+
if (platform === 'linux') {
|
|
35
|
+
return 'linux';
|
|
36
|
+
}
|
|
37
|
+
if (platform === 'darwin') {
|
|
38
|
+
return 'macos';
|
|
39
|
+
}
|
|
40
|
+
return 'unknown';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function commandExists(command) {
|
|
44
|
+
return !!shelljs.which(command);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function safeExec(command, options = {}) {
|
|
48
|
+
const result = shelljs.exec(command, { silent: true, ...options });
|
|
49
|
+
return {
|
|
50
|
+
success: result.code === 0,
|
|
51
|
+
output: result.stdout?.trim() || '',
|
|
52
|
+
error: result.stderr?.trim() || '',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function installNginxIfNeeded() {
|
|
57
|
+
const nginxBinPath = shelljs.which('nginx')?.toString() || '';
|
|
58
|
+
if (nginxBinPath) {
|
|
59
|
+
printSuccess('Nginx found');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
printInfo('Installing nginx...');
|
|
64
|
+
const platform = detectPlatform();
|
|
65
|
+
|
|
66
|
+
if (platform === 'linux') {
|
|
67
|
+
if (commandExists('apt-get')) {
|
|
68
|
+
printInfo('Installing nginx-extras using apt...');
|
|
69
|
+
const updateResult = safeExec('sudo apt update');
|
|
70
|
+
if (!updateResult.success) {
|
|
71
|
+
printWarning('Failed to update package list, but continuing...');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const installResult = safeExec('sudo apt-get install -y nginx-extras');
|
|
75
|
+
if (!installResult.success) {
|
|
76
|
+
throw new Error(`Failed to install nginx: ${installResult.error}`);
|
|
77
|
+
}
|
|
78
|
+
} else if (commandExists('yum')) {
|
|
79
|
+
printInfo('Installing nginx using yum...');
|
|
80
|
+
const installResult = safeExec('sudo yum install -y nginx');
|
|
81
|
+
if (!installResult.success) {
|
|
82
|
+
throw new Error(`Failed to install nginx: ${installResult.error}`);
|
|
83
|
+
}
|
|
84
|
+
} else if (commandExists('dnf')) {
|
|
85
|
+
printInfo('Installing nginx using dnf...');
|
|
86
|
+
const installResult = safeExec('sudo dnf install -y nginx');
|
|
87
|
+
if (!installResult.success) {
|
|
88
|
+
throw new Error(`Failed to install nginx: ${installResult.error}`);
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error('No supported package manager found (apt, yum, dnf)');
|
|
92
|
+
}
|
|
93
|
+
} else if (platform === 'macos') {
|
|
94
|
+
if (!commandExists('brew')) {
|
|
95
|
+
throw new Error('Homebrew not found. Please install Homebrew first: https://brew.sh');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
printInfo('Installing nginx using homebrew...');
|
|
99
|
+
const installResult = safeExec('brew install nginx');
|
|
100
|
+
if (!installResult.success) {
|
|
101
|
+
throw new Error(`Failed to install nginx: ${installResult.error}`);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!commandExists('nginx')) {
|
|
108
|
+
throw new Error('Nginx installation failed - nginx command not found after installation');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
printSuccess('Nginx installed successfully');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function checkNginxStreamModule() {
|
|
115
|
+
const result = safeExec('nginx -V');
|
|
116
|
+
if (!result.success) {
|
|
117
|
+
throw new Error('Failed to check nginx version and modules');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const output = result.output + result.error;
|
|
121
|
+
return output.includes('--with-stream') || output.includes('stream_core_module');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function ensureNginxStreamModule() {
|
|
125
|
+
print();
|
|
126
|
+
printInfo('Checking nginx stream module...');
|
|
127
|
+
|
|
128
|
+
if (checkNginxStreamModule()) {
|
|
129
|
+
printSuccess('Nginx stream module is available');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const platform = detectPlatform();
|
|
134
|
+
|
|
135
|
+
if (platform === 'linux') {
|
|
136
|
+
if (commandExists('apt-get')) {
|
|
137
|
+
printInfo('Installing nginx stream module...');
|
|
138
|
+
const installResult = safeExec('sudo apt-get install -y libnginx-mod-stream');
|
|
139
|
+
if (!installResult.success) {
|
|
140
|
+
printWarning('Failed to install libnginx-mod-stream package. Stream module may not be available.');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
} else if (commandExists('yum')) {
|
|
144
|
+
printInfo('Installing nginx stream module using yum...');
|
|
145
|
+
const installResult = safeExec('sudo yum install -y nginx-mod-stream');
|
|
146
|
+
if (!installResult.success) {
|
|
147
|
+
printWarning('Failed to install nginx-mod-stream package. Stream module may not be available.');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
} else if (commandExists('dnf')) {
|
|
151
|
+
printInfo('Installing nginx stream module using dnf...');
|
|
152
|
+
const installResult = safeExec('sudo dnf install -y nginx-mod-stream');
|
|
153
|
+
if (!installResult.success) {
|
|
154
|
+
printWarning('Failed to install nginx-mod-stream package. Stream module may not be available.');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
printWarning('Cannot install stream module on this Linux distribution. Please install manually if needed.');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
} else if (platform === 'macos') {
|
|
162
|
+
if (!commandExists('brew')) {
|
|
163
|
+
printWarning('Homebrew not found. Please install Homebrew first to manage nginx with stream module.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
printInfo('Installing nginx with stream module using homebrew...');
|
|
168
|
+
// First try to install nginx-full which includes stream module
|
|
169
|
+
let installResult = safeExec('brew install nginx-full --with-stream');
|
|
170
|
+
|
|
171
|
+
if (!installResult.success) {
|
|
172
|
+
// If nginx-full is not available, try to reinstall regular nginx
|
|
173
|
+
// and check if stream module is available
|
|
174
|
+
printInfo('nginx-full not available, trying to reinstall nginx...');
|
|
175
|
+
safeExec('brew uninstall nginx');
|
|
176
|
+
installResult = safeExec('brew install nginx');
|
|
177
|
+
|
|
178
|
+
if (!installResult.success) {
|
|
179
|
+
printWarning('Failed to install nginx with stream module. Please install manually.');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (checkNginxStreamModule()) {
|
|
186
|
+
printSuccess('Nginx stream module installed successfully');
|
|
187
|
+
} else {
|
|
188
|
+
printWarning('Stream module installation may have failed. Please check manually.');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function configureNginxPortCapabilities() {
|
|
193
|
+
print();
|
|
194
|
+
printInfo('Configuring nginx port binding capabilities...');
|
|
195
|
+
|
|
196
|
+
const platform = detectPlatform();
|
|
197
|
+
|
|
198
|
+
if (platform === 'linux') {
|
|
199
|
+
const nginxPath = shelljs.which('nginx')?.toString();
|
|
200
|
+
if (!nginxPath) {
|
|
201
|
+
throw new Error('Nginx binary not found');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const capResult = safeExec(`sudo setcap 'cap_net_bind_service=+ep' ${nginxPath}`);
|
|
205
|
+
if (!capResult.success) {
|
|
206
|
+
printWarning('Failed to set port binding capabilities. Nginx may need to run as root for ports 80/443.');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
printSuccess('Nginx port binding capabilities configured');
|
|
211
|
+
} else if (platform === 'macos') {
|
|
212
|
+
printInfo('Port binding configuration not needed on macOS');
|
|
213
|
+
} else {
|
|
214
|
+
printWarning('Port binding configuration not supported on this platform');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function checkBlockletServerConfig() {
|
|
219
|
+
print();
|
|
220
|
+
printInfo('Checking blocklet server nginx port configuration...');
|
|
221
|
+
|
|
222
|
+
const configPath = path.join(process.cwd(), '.blocklet-server', 'config.yml');
|
|
223
|
+
|
|
224
|
+
if (!fs.existsSync(configPath)) {
|
|
225
|
+
printWarning('Blocklet server config file not found. Skipping port configuration check.');
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
231
|
+
const config = yaml.load(configContent);
|
|
232
|
+
|
|
233
|
+
const nginxConfig = config?.node?.routing || {};
|
|
234
|
+
const { httpPort, httpsPort } = nginxConfig;
|
|
235
|
+
|
|
236
|
+
let needsUpdate = false;
|
|
237
|
+
|
|
238
|
+
if (httpPort !== 80) {
|
|
239
|
+
printWarning(`HTTP port is set to ${httpPort}, consider changing to 80 for standard web access`);
|
|
240
|
+
needsUpdate = true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (httpsPort !== 443) {
|
|
244
|
+
printWarning(`HTTPS port is set to ${httpsPort}, consider changing to 443 for standard SSL access`);
|
|
245
|
+
needsUpdate = true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (needsUpdate) {
|
|
249
|
+
printInfo(`To update ports, modify ${configPath} and run: ${chalk.cyan('blocklet server start --update-db')}`);
|
|
250
|
+
} else {
|
|
251
|
+
printSuccess('Nginx port configuration looks good');
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
printWarning(`Failed to parse config file: ${error.message}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function ensureNginxServiceNotManaged() {
|
|
259
|
+
print();
|
|
260
|
+
printInfo('Checking nginx service management status...');
|
|
261
|
+
|
|
262
|
+
const platform = detectPlatform();
|
|
263
|
+
|
|
264
|
+
if (platform === 'linux') {
|
|
265
|
+
// Check if systemd is available
|
|
266
|
+
if (commandExists('systemctl')) {
|
|
267
|
+
// Check if nginx service is enabled
|
|
268
|
+
const enabledResult = safeExec('systemctl is-enabled nginx');
|
|
269
|
+
if (enabledResult.success && enabledResult.output === 'enabled') {
|
|
270
|
+
printInfo('Disabling nginx systemd service...');
|
|
271
|
+
const disableResult = safeExec('sudo systemctl disable nginx');
|
|
272
|
+
if (!disableResult.success) {
|
|
273
|
+
printWarning(
|
|
274
|
+
'Failed to disable nginx service. This may cause conflicts with blocklet server nginx management.'
|
|
275
|
+
);
|
|
276
|
+
} else {
|
|
277
|
+
printSuccess('Nginx systemd service disabled');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Check if nginx service is running
|
|
282
|
+
const activeResult = safeExec('systemctl is-active nginx');
|
|
283
|
+
if (activeResult.success && activeResult.output === 'active') {
|
|
284
|
+
printInfo('Stopping nginx systemd service...');
|
|
285
|
+
const stopResult = safeExec('sudo systemctl stop nginx');
|
|
286
|
+
if (!stopResult.success) {
|
|
287
|
+
printWarning('Failed to stop nginx service. This may cause conflicts with blocklet server nginx management.');
|
|
288
|
+
} else {
|
|
289
|
+
printSuccess('Nginx systemd service stopped');
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Check for other init systems if needed
|
|
295
|
+
if (commandExists('service')) {
|
|
296
|
+
const statusResult = safeExec('service nginx status');
|
|
297
|
+
if (statusResult.success) {
|
|
298
|
+
printInfo('Stopping nginx service...');
|
|
299
|
+
const stopResult = safeExec('sudo service nginx stop');
|
|
300
|
+
if (!stopResult.success) {
|
|
301
|
+
printWarning('Failed to stop nginx service using service command.');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} else if (platform === 'macos') {
|
|
306
|
+
// Check for homebrew services
|
|
307
|
+
if (commandExists('brew')) {
|
|
308
|
+
const servicesResult = safeExec('brew services list | grep nginx');
|
|
309
|
+
if (servicesResult.success && servicesResult.output.includes('started')) {
|
|
310
|
+
printInfo('Stopping nginx homebrew service...');
|
|
311
|
+
const stopResult = safeExec('brew services stop nginx');
|
|
312
|
+
if (!stopResult.success) {
|
|
313
|
+
printWarning('Failed to stop nginx homebrew service.');
|
|
314
|
+
} else {
|
|
315
|
+
printSuccess('Nginx homebrew service stopped');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Check for launchd services
|
|
321
|
+
if (commandExists('launchctl')) {
|
|
322
|
+
const listResult = safeExec('launchctl list | grep nginx');
|
|
323
|
+
if (listResult.success && listResult.output) {
|
|
324
|
+
printWarning('Found nginx launchd services. Please manually stop them if they conflict with blocklet server.');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
printSuccess('Nginx service management check completed');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function setupNginxEnvironment() {
|
|
333
|
+
// 确保 nginx 安装
|
|
334
|
+
installNginxIfNeeded();
|
|
335
|
+
// 确保 nginx 有 stream 模块
|
|
336
|
+
ensureNginxStreamModule();
|
|
337
|
+
// 确保 nginx 有低端口权限
|
|
338
|
+
configureNginxPortCapabilities();
|
|
339
|
+
// 确保 nginx 不被系统服务管理
|
|
340
|
+
ensureNginxServiceNotManaged();
|
|
341
|
+
// 确保 nginx 端口配置正确
|
|
342
|
+
checkBlockletServerConfig();
|
|
343
|
+
|
|
344
|
+
print();
|
|
345
|
+
printInfo('Testing nginx configuration...');
|
|
346
|
+
const testResult = safeExec('nginx -t');
|
|
347
|
+
if (!testResult.success) {
|
|
348
|
+
printWarning('Nginx configuration test failed. Please check your nginx configuration.');
|
|
349
|
+
printWarning(`Error: ${testResult.error}`);
|
|
350
|
+
} else {
|
|
351
|
+
printSuccess('Nginx configuration test passed');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
printInfo('Nginx environment setup workflow completed');
|
|
355
|
+
process.exit(0);
|
|
356
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/cli",
|
|
3
|
-
"version": "1.16.52-beta-
|
|
3
|
+
"version": "1.16.52-beta-20250917-070942-7ee57044",
|
|
4
4
|
"description": "Command line tools to manage Blocklet Server",
|
|
5
5
|
"homepage": "https://github.com/ArcBlock/blocklet-server#readme",
|
|
6
6
|
"bin": {
|
|
@@ -35,28 +35,28 @@
|
|
|
35
35
|
"url": "https://github.com/ArcBlock/blocklet-server/issues"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@abtnode/blocklet-services": "1.16.52-beta-
|
|
39
|
-
"@abtnode/constant": "1.16.52-beta-
|
|
40
|
-
"@abtnode/core": "1.16.52-beta-
|
|
41
|
-
"@abtnode/db-cache": "1.16.52-beta-
|
|
42
|
-
"@abtnode/logger": "1.16.52-beta-
|
|
43
|
-
"@abtnode/models": "1.16.52-beta-
|
|
44
|
-
"@abtnode/router-provider": "1.16.52-beta-
|
|
45
|
-
"@abtnode/util": "1.16.52-beta-
|
|
46
|
-
"@abtnode/webapp": "1.16.52-beta-
|
|
38
|
+
"@abtnode/blocklet-services": "1.16.52-beta-20250917-070942-7ee57044",
|
|
39
|
+
"@abtnode/constant": "1.16.52-beta-20250917-070942-7ee57044",
|
|
40
|
+
"@abtnode/core": "1.16.52-beta-20250917-070942-7ee57044",
|
|
41
|
+
"@abtnode/db-cache": "1.16.52-beta-20250917-070942-7ee57044",
|
|
42
|
+
"@abtnode/logger": "1.16.52-beta-20250917-070942-7ee57044",
|
|
43
|
+
"@abtnode/models": "1.16.52-beta-20250917-070942-7ee57044",
|
|
44
|
+
"@abtnode/router-provider": "1.16.52-beta-20250917-070942-7ee57044",
|
|
45
|
+
"@abtnode/util": "1.16.52-beta-20250917-070942-7ee57044",
|
|
46
|
+
"@abtnode/webapp": "1.16.52-beta-20250917-070942-7ee57044",
|
|
47
47
|
"@arcblock/did": "1.24.0",
|
|
48
48
|
"@arcblock/event-hub": "1.24.0",
|
|
49
49
|
"@arcblock/ipfs-only-hash": "^0.0.2",
|
|
50
50
|
"@arcblock/jwt": "1.24.0",
|
|
51
51
|
"@arcblock/ws": "1.24.0",
|
|
52
|
-
"@blocklet/constant": "1.16.52-beta-
|
|
52
|
+
"@blocklet/constant": "1.16.52-beta-20250917-070942-7ee57044",
|
|
53
53
|
"@blocklet/error": "^0.2.5",
|
|
54
54
|
"@blocklet/form-collector": "^0.1.8",
|
|
55
|
-
"@blocklet/images": "1.16.52-beta-
|
|
56
|
-
"@blocklet/meta": "1.16.52-beta-
|
|
57
|
-
"@blocklet/resolver": "1.16.52-beta-
|
|
58
|
-
"@blocklet/server-js": "1.16.52-beta-
|
|
59
|
-
"@blocklet/store": "1.16.52-beta-
|
|
55
|
+
"@blocklet/images": "1.16.52-beta-20250917-070942-7ee57044",
|
|
56
|
+
"@blocklet/meta": "1.16.52-beta-20250917-070942-7ee57044",
|
|
57
|
+
"@blocklet/resolver": "1.16.52-beta-20250917-070942-7ee57044",
|
|
58
|
+
"@blocklet/server-js": "1.16.52-beta-20250917-070942-7ee57044",
|
|
59
|
+
"@blocklet/store": "1.16.52-beta-20250917-070942-7ee57044",
|
|
60
60
|
"@blocklet/theme-builder": "^0.4.6",
|
|
61
61
|
"@ocap/client": "1.24.0",
|
|
62
62
|
"@ocap/mcrypto": "1.24.0",
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"engines": {
|
|
155
155
|
"node": ">=14"
|
|
156
156
|
},
|
|
157
|
-
"gitHead": "
|
|
157
|
+
"gitHead": "ac4ec647df35a480b28351b3bca6d3e59c64fff1",
|
|
158
158
|
"devDependencies": {
|
|
159
159
|
"@types/fs-extra": "^11.0.4",
|
|
160
160
|
"@types/jest": "^29.5.13"
|