yxorp 0.2.0 → 0.2.1
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
|
@@ -341,7 +341,15 @@ Here's a complete config showing all features in action:
|
|
|
341
341
|
|
|
342
342
|
---
|
|
343
343
|
|
|
344
|
-
##
|
|
344
|
+
## Hot-Reload
|
|
345
|
+
|
|
346
|
+
### Config
|
|
347
|
+
|
|
348
|
+
Yxorp watches its config file at runtime. **Save the file — changes take effect on the next request.** No restart needed.
|
|
349
|
+
|
|
350
|
+
This works for all config fields: mock rules, rewrite rules, remote rules, static rules, and headers. The proxy server keeps running and the new config is applied immediately.
|
|
351
|
+
|
|
352
|
+
### Scripts
|
|
345
353
|
|
|
346
354
|
Mock and rewrite scripts are reloaded on every request — **just save the file and the next request uses the new code**. No need to restart Yxorp.
|
|
347
355
|
|
package/dist/index.js
CHANGED
|
@@ -12,12 +12,15 @@ const rewrite_rules_matcher_service_1 = require("./services/rules-matchers/rewri
|
|
|
12
12
|
const mock_rules_matcher_service_1 = require("./services/rules-matchers/mock-rules-matcher.service");
|
|
13
13
|
const yxorp_server_service_1 = require("./services/yxorp-server.service");
|
|
14
14
|
const config_resolver_1 = require("./services/config-resolver");
|
|
15
|
+
const config_watcher_1 = require("./services/config-watcher");
|
|
15
16
|
// --- Config resolution ---
|
|
16
17
|
let configDir;
|
|
18
|
+
let configPath;
|
|
17
19
|
let config;
|
|
18
20
|
try {
|
|
19
21
|
const resolved = (0, config_resolver_1.resolveConfig)(process.cwd(), process.argv);
|
|
20
22
|
configDir = resolved.configDir;
|
|
23
|
+
configPath = resolved.configPath;
|
|
21
24
|
config = resolved.config;
|
|
22
25
|
}
|
|
23
26
|
catch (e) {
|
|
@@ -28,28 +31,27 @@ catch (e) {
|
|
|
28
31
|
if (configDir !== process.cwd()) {
|
|
29
32
|
process.chdir(configDir);
|
|
30
33
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
function buildProxyConfig(cfg) {
|
|
35
|
+
const proxyOptions = {
|
|
36
|
+
target: cfg.target,
|
|
37
|
+
changeOrigin: true,
|
|
38
|
+
followRedirects: true,
|
|
39
|
+
secure: false,
|
|
40
|
+
ws: true,
|
|
41
|
+
selfHandleResponse: true,
|
|
42
|
+
};
|
|
43
|
+
if (cfg.proxyHeaders) {
|
|
44
|
+
proxyOptions.headers = cfg.proxyHeaders;
|
|
45
|
+
}
|
|
46
|
+
return { ...cfg, proxyOptions };
|
|
41
47
|
}
|
|
42
|
-
const proxyConfig = {
|
|
43
|
-
...config,
|
|
44
|
-
proxyOptions,
|
|
45
|
-
};
|
|
46
48
|
(_a = config === null || config === void 0 ? void 0 : config.scripts) === null || _a === void 0 ? void 0 : _a.forEach(script => {
|
|
47
49
|
require(path_1.default.resolve(script));
|
|
48
50
|
});
|
|
49
51
|
// Manual composition — no DI container
|
|
50
52
|
const logger = new logger_service_1.LoggerService();
|
|
51
53
|
const appConfig = new config_service_1.Config();
|
|
52
|
-
appConfig.set(
|
|
54
|
+
appConfig.set(buildProxyConfig(config));
|
|
53
55
|
const mockRulesMatcher = new mock_rules_matcher_service_1.MockRulesMatcher(appConfig);
|
|
54
56
|
const rewriteRulesMatcher = new rewrite_rules_matcher_service_1.RewriteRulesMatcher(appConfig);
|
|
55
57
|
const remoteRulesMatcher = new remote_rules_matcher_service_1.RemoteRulesMatcher(appConfig);
|
|
@@ -57,3 +59,8 @@ const { listen } = (0, yxorp_server_service_1.createServer)(appConfig, logger, r
|
|
|
57
59
|
listen(config.proxyPort, () => {
|
|
58
60
|
console.log(`Yxorp server started successfully on http://localhost:${config.proxyPort}`);
|
|
59
61
|
});
|
|
62
|
+
// --- Config hot-reload ---
|
|
63
|
+
(0, config_watcher_1.watchConfig)(configPath, (newConfig) => {
|
|
64
|
+
appConfig.set(buildProxyConfig(newConfig));
|
|
65
|
+
logger.info('Config reloaded');
|
|
66
|
+
}, (e) => logger.error(`Config reload failed: ${e.message || e}`));
|
|
@@ -20,6 +20,7 @@ function resolveConfig(cwd, argv) {
|
|
|
20
20
|
}
|
|
21
21
|
return {
|
|
22
22
|
configDir: path_1.default.dirname(resolved),
|
|
23
|
+
configPath: resolved,
|
|
23
24
|
config: JSON.parse(fs_1.default.readFileSync(resolved, 'utf-8')),
|
|
24
25
|
};
|
|
25
26
|
}
|
|
@@ -28,6 +29,7 @@ function resolveConfig(cwd, argv) {
|
|
|
28
29
|
if (fs_1.default.existsSync(rootConfig)) {
|
|
29
30
|
return {
|
|
30
31
|
configDir: cwd,
|
|
32
|
+
configPath: rootConfig,
|
|
31
33
|
config: JSON.parse(fs_1.default.readFileSync(rootConfig, 'utf-8')),
|
|
32
34
|
};
|
|
33
35
|
}
|
|
@@ -36,6 +38,7 @@ function resolveConfig(cwd, argv) {
|
|
|
36
38
|
if (fs_1.default.existsSync(dotConfig)) {
|
|
37
39
|
return {
|
|
38
40
|
configDir: dotDir,
|
|
41
|
+
configPath: dotConfig,
|
|
39
42
|
config: JSON.parse(fs_1.default.readFileSync(dotConfig, 'utf-8')),
|
|
40
43
|
};
|
|
41
44
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.watchConfig = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
function watchConfig(configPath, onReload, onError) {
|
|
9
|
+
let debounceTimer = null;
|
|
10
|
+
return fs_1.default.watch(configPath, () => {
|
|
11
|
+
if (debounceTimer)
|
|
12
|
+
return;
|
|
13
|
+
debounceTimer = setTimeout(() => {
|
|
14
|
+
debounceTimer = null;
|
|
15
|
+
try {
|
|
16
|
+
const raw = fs_1.default.readFileSync(configPath, 'utf-8');
|
|
17
|
+
if (!raw.trim())
|
|
18
|
+
return;
|
|
19
|
+
onReload(JSON.parse(raw));
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
onError(e);
|
|
23
|
+
}
|
|
24
|
+
}, 100);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.watchConfig = watchConfig;
|