@hile/cli 1.1.11 → 1.1.12

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.
@@ -0,0 +1,4 @@
1
+ export declare function listConfigs(): Promise<void>;
2
+ export declare function getConfig(namespace: string, json?: boolean): Promise<void>;
3
+ export declare function setConfig(namespace: string, keyvalue: string): Promise<void>;
4
+ export declare function delConfig(namespace: string, key?: string, yes?: boolean): Promise<void>;
@@ -0,0 +1,120 @@
1
+ import { getRegistryConfigsDir, namespaceToConfigFile, parseConfigFilename } from '@hile/micro';
2
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, rmSync } from 'node:fs';
3
+ import { createInterface } from 'node:readline';
4
+ import YAML from 'yaml';
5
+ function parseValue(raw) {
6
+ if (raw === 'true')
7
+ return true;
8
+ if (raw === 'false')
9
+ return false;
10
+ if (raw === 'null')
11
+ return null;
12
+ if (/^\d+$/.test(raw))
13
+ return Number(raw);
14
+ if (/^\d+\.\d+$/.test(raw))
15
+ return Number(raw);
16
+ return raw;
17
+ }
18
+ function confirm(message) {
19
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
20
+ return new Promise(resolve => {
21
+ rl.question(`${message} (y/N) `, answer => {
22
+ rl.close();
23
+ resolve(answer === 'y' || answer === 'Y');
24
+ });
25
+ });
26
+ }
27
+ export async function listConfigs() {
28
+ const dir = getRegistryConfigsDir();
29
+ if (!existsSync(dir)) {
30
+ console.log('No configs found.');
31
+ return;
32
+ }
33
+ const namespaces = readdirSync(dir)
34
+ .map(f => parseConfigFilename(f))
35
+ .filter((f) => f !== null);
36
+ if (namespaces.length === 0) {
37
+ console.log('No configs found.');
38
+ return;
39
+ }
40
+ console.log(`Configs in ${dir}:`);
41
+ for (const ns of namespaces) {
42
+ console.log(` ${ns}`);
43
+ }
44
+ }
45
+ export async function getConfig(namespace, json) {
46
+ const file = namespaceToConfigFile(namespace);
47
+ if (!existsSync(file)) {
48
+ console.error(`Config '${namespace}' not found.`);
49
+ process.exit(1);
50
+ }
51
+ const config = YAML.parse(readFileSync(file, 'utf8'));
52
+ if (json) {
53
+ console.log(JSON.stringify(config, null, 2));
54
+ }
55
+ else {
56
+ console.log(YAML.stringify(config));
57
+ }
58
+ }
59
+ export async function setConfig(namespace, keyvalue) {
60
+ const eqIdx = keyvalue.indexOf('=');
61
+ if (eqIdx <= 0) {
62
+ console.error('Invalid format. Use: set <namespace> <key>=<value>');
63
+ process.exit(1);
64
+ }
65
+ const key = keyvalue.slice(0, eqIdx);
66
+ const value = parseValue(keyvalue.slice(eqIdx + 1));
67
+ const file = namespaceToConfigFile(namespace);
68
+ mkdirSync(getRegistryConfigsDir(), { recursive: true });
69
+ let config = {};
70
+ if (existsSync(file)) {
71
+ const raw = YAML.parse(readFileSync(file, 'utf8'));
72
+ if (typeof raw === 'object' && raw !== null)
73
+ config = raw;
74
+ }
75
+ config[key] = value;
76
+ writeFileSync(file, YAML.stringify(config), 'utf8');
77
+ console.log(`Set ${namespace}.${key} = ${JSON.stringify(value)}`);
78
+ }
79
+ export async function delConfig(namespace, key, yes) {
80
+ const file = namespaceToConfigFile(namespace);
81
+ if (!existsSync(file)) {
82
+ console.error(`Config '${namespace}' not found.`);
83
+ process.exit(1);
84
+ }
85
+ if (key) {
86
+ if (!yes) {
87
+ const ok = await confirm(`Delete '${namespace}.${key}' from config?`);
88
+ if (!ok) {
89
+ console.log('Cancelled.');
90
+ return;
91
+ }
92
+ }
93
+ const raw = YAML.parse(readFileSync(file, 'utf8'));
94
+ const config = (typeof raw === 'object' && raw !== null) ? raw : {};
95
+ if (!(key in config)) {
96
+ console.error(`Key '${key}' not found in '${namespace}'.`);
97
+ process.exit(1);
98
+ }
99
+ delete config[key];
100
+ if (Object.keys(config).length === 0) {
101
+ rmSync(file);
102
+ console.log(`Deleted '${namespace}' (config is now empty).`);
103
+ }
104
+ else {
105
+ writeFileSync(file, YAML.stringify(config), 'utf8');
106
+ console.log(`Deleted ${namespace}.${key}`);
107
+ }
108
+ }
109
+ else {
110
+ if (!yes) {
111
+ const ok = await confirm(`Delete config '${namespace}' and all its values?`);
112
+ if (!ok) {
113
+ console.log('Cancelled.');
114
+ return;
115
+ }
116
+ }
117
+ rmSync(file);
118
+ console.log(`Deleted config '${namespace}'.`);
119
+ }
120
+ }
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import { dirname, join, resolve } from 'node:path';
8
8
  import { createRequire } from 'node:module';
9
9
  import { Registry } from '@hile/micro';
10
10
  import { useExit } from './exitHook.js';
11
+ import { listConfigs, getConfig, setConfig, delConfig } from './configs.js';
11
12
  const requireCli = createRequire(import.meta.url);
12
13
  /** 从包入口文件路径向上找到 `package.json` 的 `name` 与 `packageName` 一致的目录 */
13
14
  function packageDirFromResolvedMain(resolvedMain, packageName) {
@@ -108,14 +109,41 @@ program
108
109
  silent: options.silent
109
110
  });
110
111
  });
111
- program.command('registry')
112
- .option('-p, --port <port>', '注册中心端口', '9876')
112
+ const registryCmd = program.command('registry');
113
+ registryCmd
114
+ .allowExcessArguments(true)
115
+ .option('--port <port>', '注册中心端口', '9876')
116
+ .option('--host <host>', '注册中心主机')
113
117
  .description('启动注册中心')
114
118
  .action(async (options) => {
115
119
  const port = options.port ? Number(options.port) : 9876;
116
- const registry = new Registry({ advertiseHost: process.env.HILE_ADVERTISE_HOST ?? '127.0.0.1' });
120
+ const registry = new Registry({ advertiseHost: options.host ?? undefined });
117
121
  useExit(await registry.listen(port));
118
122
  console.log(`+ [registry] started on port ${port}`);
119
123
  });
124
+ // Registry configs subcommands
125
+ const configs = registryCmd.command('configs');
126
+ configs
127
+ .description('管理注册中心配置')
128
+ .action(async () => {
129
+ await listConfigs();
130
+ });
131
+ configs.command('get <namespace>')
132
+ .option('--json', 'JSON 格式输出')
133
+ .description('查看配置')
134
+ .action(async (namespace, options) => {
135
+ await getConfig(namespace, options.json);
136
+ });
137
+ configs.command('set <namespace> <keyvalue>')
138
+ .description('设置配置项,如 hile registry configs set my-svc port=8080')
139
+ .action(async (namespace, keyvalue) => {
140
+ await setConfig(namespace, keyvalue);
141
+ });
142
+ configs.command('del <namespace> [key]')
143
+ .option('-y, --yes', '跳过确认')
144
+ .description('删除配置')
145
+ .action(async (namespace, key, options) => {
146
+ await delConfig(namespace, key, options.yes);
147
+ });
120
148
  program.parseAsync(process.argv);
121
149
  export * from './start.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hile/cli",
3
- "version": "1.1.11",
3
+ "version": "1.1.12",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -19,6 +19,9 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
+ "engines": {
23
+ "node": ">=20.12.0"
24
+ },
22
25
  "devDependencies": {
23
26
  "@types/async-exit-hook": "^2.0.2",
24
27
  "fix-esm-import-path": "^1.10.3",
@@ -26,11 +29,12 @@
26
29
  },
27
30
  "dependencies": {
28
31
  "@hile/core": "^1.1.2",
29
- "@hile/micro": "^1.0.5",
32
+ "@hile/micro": "^1.0.6",
30
33
  "async-exit-hook": "^2.0.1",
31
34
  "commander": "^14.0.3",
32
35
  "glob": "^13.0.6",
33
- "tsx": "^4.21.0"
36
+ "tsx": "^4.21.0",
37
+ "yaml": "^2.9.0"
34
38
  },
35
- "gitHead": "ddc82850295d26358cbffbb695e642cdb748339d"
39
+ "gitHead": "b2272b434848ff9d93a88796e25a66665afcaa0a"
36
40
  }