@chainsafe/lodestar 1.45.0-dev.29704bdb26 → 1.45.0-dev.4d9beacde9
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/.git-data.json +1 -1
- package/lib/options/globalOptions.d.ts.map +1 -1
- package/lib/options/globalOptions.js +13 -2
- package/lib/options/globalOptions.js.map +1 -1
- package/lib/util/object.d.ts +34 -0
- package/lib/util/object.d.ts.map +1 -1
- package/lib/util/object.js +72 -0
- package/lib/util/object.js.map +1 -1
- package/package.json +13 -13
- package/src/options/globalOptions.ts +14 -2
- package/src/util/object.ts +72 -1
package/.git-data.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"globalOptions.d.ts","sourceRoot":"","sources":["../../src/options/globalOptions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,WAAW,EAAe,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAC,WAAW,EAAgB,MAAM,oBAAoB,CAAC;AAE9D,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"globalOptions.d.ts","sourceRoot":"","sources":["../../src/options/globalOptions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,WAAW,EAAe,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAC,WAAW,EAAgB,MAAM,oBAAoB,CAAC;AAE9D,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAuB,CAAC;AA+DrD,eAAO,MAAM,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAK5F,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAExD,eAAO,MAAM,aAAa;;;;;;;;;;;CAGzB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ACTIVE_PRESET } from "@lodestar/params";
|
|
2
2
|
import { networkNames } from "../networks/index.js";
|
|
3
|
-
import { readFile } from "../util/index.js";
|
|
3
|
+
import { flattenObject, readFile, translateEnabledKeys } from "../util/index.js";
|
|
4
4
|
import { paramsOptions } from "./paramsOptions.js";
|
|
5
5
|
export const defaultNetwork = "mainnet";
|
|
6
6
|
const globalSingleOptions = {
|
|
@@ -32,6 +32,17 @@ const globalSingleOptions = {
|
|
|
32
32
|
rcConfig: {
|
|
33
33
|
description: "RC file to supplement command line args, accepted formats: .yml, .yaml, .json",
|
|
34
34
|
type: "string",
|
|
35
|
+
example: {
|
|
36
|
+
description: `Options can be written as nested maps or dotted keys
|
|
37
|
+
|
|
38
|
+
\`\`\`yaml
|
|
39
|
+
network: hoodi
|
|
40
|
+
logLevel: debug
|
|
41
|
+
metrics:
|
|
42
|
+
enabled: true
|
|
43
|
+
port: 8008
|
|
44
|
+
\`\`\``,
|
|
45
|
+
},
|
|
35
46
|
},
|
|
36
47
|
supernode: {
|
|
37
48
|
description: "Subscribe to and custody all data column sidecar subnets",
|
|
@@ -47,7 +58,7 @@ const globalSingleOptions = {
|
|
|
47
58
|
export const rcConfigOption = [
|
|
48
59
|
"rcConfig",
|
|
49
60
|
globalSingleOptions.rcConfig.description,
|
|
50
|
-
(configPath) => readFile(configPath, ["json", "yml", "yaml"]),
|
|
61
|
+
(configPath) => translateEnabledKeys(flattenObject(readFile(configPath, ["json", "yml", "yaml"]))),
|
|
51
62
|
];
|
|
52
63
|
export const globalOptions = {
|
|
53
64
|
...globalSingleOptions,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"globalOptions.js","sourceRoot":"","sources":["../../src/options/globalOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAc,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"globalOptions.js","sourceRoot":"","sources":["../../src/options/globalOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAc,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAE,oBAAoB,EAAC,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAc,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAa9D,MAAM,CAAC,MAAM,cAAc,GAAgB,SAAS,CAAC;AAErD,MAAM,mBAAmB,GAAwC;IAC/D,OAAO,EAAE;QACP,WAAW,EAAE,8BAA8B;QAC3C,IAAI,EAAE,QAAQ;KACf;IAED,OAAO,EAAE;QACP,WAAW,EAAE,sDAAsD;QACnE,IAAI,EAAE,QAAQ;QACd,kBAAkB,EAAE,cAAc;QAClC,OAAO,EAAE,YAAY;KACtB;IAED,UAAU,EAAE;QACV,WAAW,EAAE,4BAA4B;QACzC,IAAI,EAAE,QAAQ;KACf;IAED,uDAAuD;IACvD,MAAM,EAAE;QACN,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,aAAa;KACvB;IAED,UAAU,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,4EAA4E;QACzF,IAAI,EAAE,QAAQ;KACf;IAED,QAAQ,EAAE;QACR,WAAW,EAAE,+EAA+E;QAC5F,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,WAAW,EAAE;;;;;;;;OAQZ;SACF;KACF;IAED,SAAS,EAAE;QACT,WAAW,EAAE,0DAA0D;QACvE,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,CAAC,eAAe,CAAC;KAC7B;IAED,aAAa,EAAE;QACb,WAAW,EACT,mNAAmN;QACrN,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,CAAC,WAAW,CAAC;KACzB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAsE;IAC/F,UAAU;IACV,mBAAmB,CAAC,QAAQ,CAAC,WAAqB;IAClD,CAAC,UAAkB,EAA2B,EAAE,CAC9C,oBAAoB,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACrF,CAAC;AAIF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,mBAAmB;IACtB,GAAG,aAAa;CACjB,CAAC"}
|
package/lib/util/object.d.ts
CHANGED
|
@@ -5,4 +5,38 @@ import { RecursivePartial } from "@lodestar/utils";
|
|
|
5
5
|
export declare function removeUndefinedRecursive<T extends {
|
|
6
6
|
[key: string]: any;
|
|
7
7
|
}>(obj: T): RecursivePartial<T>;
|
|
8
|
+
/**
|
|
9
|
+
* Flattens a nested object into a single-level object with dot-notation keys.
|
|
10
|
+
*
|
|
11
|
+
* Allows the rc config file to be written with either nested maps or dotted keys, e.g.
|
|
12
|
+
* `{rest: {address: "0.0.0.0"}}` and `{"rest.address": "0.0.0.0"}` both flatten to
|
|
13
|
+
* `{"rest.address": "0.0.0.0"}`, matching how CLI options are registered (`dot-notation`
|
|
14
|
+
* is disabled in yargs). Arrays are preserved as values (not flattened by index) so
|
|
15
|
+
* array options like `rest.namespace` or `bootnodes` keep working.
|
|
16
|
+
*
|
|
17
|
+
* If the same option is provided in both nested and dotted form, the value that appears
|
|
18
|
+
* last in the file wins.
|
|
19
|
+
*/
|
|
20
|
+
export declare function flattenObject(obj: Record<string, unknown>, parentKey?: string): Record<string, unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* Rewrites `{prefix}.enabled` keys to the bare `{prefix}` flag.
|
|
23
|
+
*
|
|
24
|
+
* Some options are exposed as an on/off boolean flag (`--metrics`, `--rest`, `--builder`) whose
|
|
25
|
+
* internal config shape nests the toggle under `.enabled` (e.g. `{metrics: {enabled, port}}`). This
|
|
26
|
+
* lets an rc config file be written in the natural nested form:
|
|
27
|
+
*
|
|
28
|
+
* ```yaml
|
|
29
|
+
* metrics:
|
|
30
|
+
* enabled: true
|
|
31
|
+
* port: 8008
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* which {@link flattenObject} turns into `{"metrics.enabled": true, "metrics.port": 8008}`. The CLI
|
|
35
|
+
* registers the toggle as the bare `metrics` flag (there is no `metrics.enabled` option), so rewrite
|
|
36
|
+
* `{prefix}.enabled` -> `{prefix}` to match a registered option. No CLI option is registered with an
|
|
37
|
+
* `.enabled` suffix, so this is unambiguous. If the bare `{prefix}` key is already set (e.g. mixed
|
|
38
|
+
* dotted and nested forms), the `.enabled` key is left untouched so the conflict surfaces as an
|
|
39
|
+
* "unknown argument" error rather than being silently overridden.
|
|
40
|
+
*/
|
|
41
|
+
export declare function translateEnabledKeys(flattened: Record<string, unknown>): Record<string, unknown>;
|
|
8
42
|
//# sourceMappingURL=object.d.ts.map
|
package/lib/util/object.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/util/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/util/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAgB,MAAM,iBAAiB,CAAC;AAEhE;;GAEG;AAGH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAOpG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBvG;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYhG"}
|
package/lib/util/object.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPlainObject } from "@lodestar/utils";
|
|
1
2
|
/**
|
|
2
3
|
* Removes (mutates) all properties with a value === undefined, recursively
|
|
3
4
|
*/
|
|
@@ -12,4 +13,75 @@ export function removeUndefinedRecursive(obj) {
|
|
|
12
13
|
}
|
|
13
14
|
return obj;
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Flattens a nested object into a single-level object with dot-notation keys.
|
|
18
|
+
*
|
|
19
|
+
* Allows the rc config file to be written with either nested maps or dotted keys, e.g.
|
|
20
|
+
* `{rest: {address: "0.0.0.0"}}` and `{"rest.address": "0.0.0.0"}` both flatten to
|
|
21
|
+
* `{"rest.address": "0.0.0.0"}`, matching how CLI options are registered (`dot-notation`
|
|
22
|
+
* is disabled in yargs). Arrays are preserved as values (not flattened by index) so
|
|
23
|
+
* array options like `rest.namespace` or `bootnodes` keep working.
|
|
24
|
+
*
|
|
25
|
+
* If the same option is provided in both nested and dotted form, the value that appears
|
|
26
|
+
* last in the file wins.
|
|
27
|
+
*/
|
|
28
|
+
export function flattenObject(obj, parentKey) {
|
|
29
|
+
// Guard non-plain input: an empty or scalar rc config file makes `readFile` return `undefined`
|
|
30
|
+
// or a primitive, which would otherwise throw on `Object.entries`. `isPlainObject` also rejects
|
|
31
|
+
// arrays and class instances (Date, Buffer, typed arrays); those are handled as leaf values below.
|
|
32
|
+
if (!isPlainObject(obj)) {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
const flattened = {};
|
|
36
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
37
|
+
// Skip prototype-polluting keys as defense-in-depth (config files can be semi-trusted).
|
|
38
|
+
if (key === "__proto__") {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const prefixedKey = parentKey ? `${parentKey}.${key}` : key;
|
|
42
|
+
// Only recurse into plain objects; arrays and class instances (e.g. Date) are kept as leaf
|
|
43
|
+
// values — recursing into them would silently drop or mis-flatten them.
|
|
44
|
+
if (isPlainObject(value)) {
|
|
45
|
+
Object.assign(flattened, flattenObject(value, prefixedKey));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
flattened[prefixedKey] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return flattened;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Rewrites `{prefix}.enabled` keys to the bare `{prefix}` flag.
|
|
55
|
+
*
|
|
56
|
+
* Some options are exposed as an on/off boolean flag (`--metrics`, `--rest`, `--builder`) whose
|
|
57
|
+
* internal config shape nests the toggle under `.enabled` (e.g. `{metrics: {enabled, port}}`). This
|
|
58
|
+
* lets an rc config file be written in the natural nested form:
|
|
59
|
+
*
|
|
60
|
+
* ```yaml
|
|
61
|
+
* metrics:
|
|
62
|
+
* enabled: true
|
|
63
|
+
* port: 8008
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* which {@link flattenObject} turns into `{"metrics.enabled": true, "metrics.port": 8008}`. The CLI
|
|
67
|
+
* registers the toggle as the bare `metrics` flag (there is no `metrics.enabled` option), so rewrite
|
|
68
|
+
* `{prefix}.enabled` -> `{prefix}` to match a registered option. No CLI option is registered with an
|
|
69
|
+
* `.enabled` suffix, so this is unambiguous. If the bare `{prefix}` key is already set (e.g. mixed
|
|
70
|
+
* dotted and nested forms), the `.enabled` key is left untouched so the conflict surfaces as an
|
|
71
|
+
* "unknown argument" error rather than being silently overridden.
|
|
72
|
+
*/
|
|
73
|
+
export function translateEnabledKeys(flattened) {
|
|
74
|
+
const suffix = ".enabled";
|
|
75
|
+
const translated = {};
|
|
76
|
+
for (const [key, value] of Object.entries(flattened)) {
|
|
77
|
+
const prefix = key.endsWith(suffix) ? key.slice(0, -suffix.length) : "";
|
|
78
|
+
if (prefix && !(prefix in flattened)) {
|
|
79
|
+
translated[prefix] = value;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
translated[key] = value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return translated;
|
|
86
|
+
}
|
|
15
87
|
//# sourceMappingURL=object.js.map
|
package/lib/util/object.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/util/object.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/util/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAEhE;;GAEG;AAEH,6EAA6E;AAC7E,MAAM,UAAU,wBAAwB,CAAiC,GAAM,EAAuB;IACpG,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,wBAAwB,CAAC,KAAK,CAAC,CAAC;aACnE,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,GAA0B,CAAC;AAAA,CACnC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,GAA4B,EAAE,SAAkB,EAA2B;IACvG,+FAA+F;IAC/F,gGAAgG;IAChG,mGAAmG;IACnG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,wFAAwF;QACxF,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,SAAS;QACX,CAAC;QACD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5D,2FAA2F;QAC3F,wEAAwE;QACxE,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,KAAgC,EAAE,WAAW,CAAC,CAAC,CAAC;QACzF,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CAClB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAkC,EAA2B;IAChG,MAAM,MAAM,GAAG,UAAU,CAAC;IAC1B,MAAM,UAAU,GAA4B,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC,EAAE,CAAC;YACrC,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AAAA,CACnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainsafe/lodestar",
|
|
3
|
-
"version": "1.45.0-dev.
|
|
3
|
+
"version": "1.45.0-dev.4d9beacde9",
|
|
4
4
|
"description": "Command line interface for lodestar",
|
|
5
5
|
"author": "ChainSafe Systems",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -68,16 +68,16 @@
|
|
|
68
68
|
"@libp2p/crypto": "^5.1.13",
|
|
69
69
|
"@libp2p/interface": "^3.1.0",
|
|
70
70
|
"@libp2p/peer-id": "^6.0.4",
|
|
71
|
-
"@lodestar/api": "^1.45.0-dev.
|
|
72
|
-
"@lodestar/beacon-node": "^1.45.0-dev.
|
|
73
|
-
"@lodestar/config": "^1.45.0-dev.
|
|
74
|
-
"@lodestar/db": "^1.45.0-dev.
|
|
75
|
-
"@lodestar/logger": "^1.45.0-dev.
|
|
76
|
-
"@lodestar/params": "^1.45.0-dev.
|
|
77
|
-
"@lodestar/state-transition": "^1.45.0-dev.
|
|
78
|
-
"@lodestar/types": "^1.45.0-dev.
|
|
79
|
-
"@lodestar/utils": "^1.45.0-dev.
|
|
80
|
-
"@lodestar/validator": "^1.45.0-dev.
|
|
71
|
+
"@lodestar/api": "^1.45.0-dev.4d9beacde9",
|
|
72
|
+
"@lodestar/beacon-node": "^1.45.0-dev.4d9beacde9",
|
|
73
|
+
"@lodestar/config": "^1.45.0-dev.4d9beacde9",
|
|
74
|
+
"@lodestar/db": "^1.45.0-dev.4d9beacde9",
|
|
75
|
+
"@lodestar/logger": "^1.45.0-dev.4d9beacde9",
|
|
76
|
+
"@lodestar/params": "^1.45.0-dev.4d9beacde9",
|
|
77
|
+
"@lodestar/state-transition": "^1.45.0-dev.4d9beacde9",
|
|
78
|
+
"@lodestar/types": "^1.45.0-dev.4d9beacde9",
|
|
79
|
+
"@lodestar/utils": "^1.45.0-dev.4d9beacde9",
|
|
80
|
+
"@lodestar/validator": "^1.45.0-dev.4d9beacde9",
|
|
81
81
|
"@multiformats/multiaddr": "^13.0.1",
|
|
82
82
|
"deepmerge": "^4.3.1",
|
|
83
83
|
"ethers": "^6.7.0",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@chainsafe/as-sha256": "^1.2.0",
|
|
95
95
|
"@ethereumjs/rlp": "^4.0.1",
|
|
96
|
-
"@lodestar/test-utils": "^1.45.0-dev.
|
|
96
|
+
"@lodestar/test-utils": "^1.45.0-dev.4d9beacde9",
|
|
97
97
|
"@types/debug": "^4.1.7",
|
|
98
98
|
"@types/inquirer": "^9.0.3",
|
|
99
99
|
"@types/js-yaml": "^4.0.5",
|
|
@@ -107,5 +107,5 @@
|
|
|
107
107
|
"web3": "^4.0.3",
|
|
108
108
|
"web3-eth-accounts": "^4.0.3"
|
|
109
109
|
},
|
|
110
|
-
"gitHead": "
|
|
110
|
+
"gitHead": "fc523cb9832753c411966a4b9f63bc4f8581d63c"
|
|
111
111
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {ACTIVE_PRESET} from "@lodestar/params";
|
|
2
2
|
import {CliCommandOptions} from "@lodestar/utils";
|
|
3
3
|
import {NetworkName, networkNames} from "../networks/index.js";
|
|
4
|
-
import {readFile} from "../util/index.js";
|
|
4
|
+
import {flattenObject, readFile, translateEnabledKeys} from "../util/index.js";
|
|
5
5
|
import {IParamsArgs, paramsOptions} from "./paramsOptions.js";
|
|
6
6
|
|
|
7
7
|
type GlobalSingleArgs = {
|
|
@@ -51,6 +51,17 @@ const globalSingleOptions: CliCommandOptions<GlobalSingleArgs> = {
|
|
|
51
51
|
rcConfig: {
|
|
52
52
|
description: "RC file to supplement command line args, accepted formats: .yml, .yaml, .json",
|
|
53
53
|
type: "string",
|
|
54
|
+
example: {
|
|
55
|
+
description: `Options can be written as nested maps or dotted keys
|
|
56
|
+
|
|
57
|
+
\`\`\`yaml
|
|
58
|
+
network: hoodi
|
|
59
|
+
logLevel: debug
|
|
60
|
+
metrics:
|
|
61
|
+
enabled: true
|
|
62
|
+
port: 8008
|
|
63
|
+
\`\`\``,
|
|
64
|
+
},
|
|
54
65
|
},
|
|
55
66
|
|
|
56
67
|
supernode: {
|
|
@@ -70,7 +81,8 @@ const globalSingleOptions: CliCommandOptions<GlobalSingleArgs> = {
|
|
|
70
81
|
export const rcConfigOption: [string, string, (configPath: string) => Record<string, unknown>] = [
|
|
71
82
|
"rcConfig",
|
|
72
83
|
globalSingleOptions.rcConfig.description as string,
|
|
73
|
-
(configPath: string): Record<string, unknown> =>
|
|
84
|
+
(configPath: string): Record<string, unknown> =>
|
|
85
|
+
translateEnabledKeys(flattenObject(readFile(configPath, ["json", "yml", "yaml"]))),
|
|
74
86
|
];
|
|
75
87
|
|
|
76
88
|
export type GlobalArgs = GlobalSingleArgs & IParamsArgs;
|
package/src/util/object.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {RecursivePartial} from "@lodestar/utils";
|
|
1
|
+
import {RecursivePartial, isPlainObject} from "@lodestar/utils";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Removes (mutates) all properties with a value === undefined, recursively
|
|
@@ -13,3 +13,74 @@ export function removeUndefinedRecursive<T extends {[key: string]: any}>(obj: T)
|
|
|
13
13
|
}
|
|
14
14
|
return obj as RecursivePartial<T>;
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Flattens a nested object into a single-level object with dot-notation keys.
|
|
19
|
+
*
|
|
20
|
+
* Allows the rc config file to be written with either nested maps or dotted keys, e.g.
|
|
21
|
+
* `{rest: {address: "0.0.0.0"}}` and `{"rest.address": "0.0.0.0"}` both flatten to
|
|
22
|
+
* `{"rest.address": "0.0.0.0"}`, matching how CLI options are registered (`dot-notation`
|
|
23
|
+
* is disabled in yargs). Arrays are preserved as values (not flattened by index) so
|
|
24
|
+
* array options like `rest.namespace` or `bootnodes` keep working.
|
|
25
|
+
*
|
|
26
|
+
* If the same option is provided in both nested and dotted form, the value that appears
|
|
27
|
+
* last in the file wins.
|
|
28
|
+
*/
|
|
29
|
+
export function flattenObject(obj: Record<string, unknown>, parentKey?: string): Record<string, unknown> {
|
|
30
|
+
// Guard non-plain input: an empty or scalar rc config file makes `readFile` return `undefined`
|
|
31
|
+
// or a primitive, which would otherwise throw on `Object.entries`. `isPlainObject` also rejects
|
|
32
|
+
// arrays and class instances (Date, Buffer, typed arrays); those are handled as leaf values below.
|
|
33
|
+
if (!isPlainObject(obj)) {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
const flattened: Record<string, unknown> = {};
|
|
37
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
38
|
+
// Skip prototype-polluting keys as defense-in-depth (config files can be semi-trusted).
|
|
39
|
+
if (key === "__proto__") {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const prefixedKey = parentKey ? `${parentKey}.${key}` : key;
|
|
43
|
+
// Only recurse into plain objects; arrays and class instances (e.g. Date) are kept as leaf
|
|
44
|
+
// values — recursing into them would silently drop or mis-flatten them.
|
|
45
|
+
if (isPlainObject(value)) {
|
|
46
|
+
Object.assign(flattened, flattenObject(value as Record<string, unknown>, prefixedKey));
|
|
47
|
+
} else {
|
|
48
|
+
flattened[prefixedKey] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return flattened;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Rewrites `{prefix}.enabled` keys to the bare `{prefix}` flag.
|
|
56
|
+
*
|
|
57
|
+
* Some options are exposed as an on/off boolean flag (`--metrics`, `--rest`, `--builder`) whose
|
|
58
|
+
* internal config shape nests the toggle under `.enabled` (e.g. `{metrics: {enabled, port}}`). This
|
|
59
|
+
* lets an rc config file be written in the natural nested form:
|
|
60
|
+
*
|
|
61
|
+
* ```yaml
|
|
62
|
+
* metrics:
|
|
63
|
+
* enabled: true
|
|
64
|
+
* port: 8008
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* which {@link flattenObject} turns into `{"metrics.enabled": true, "metrics.port": 8008}`. The CLI
|
|
68
|
+
* registers the toggle as the bare `metrics` flag (there is no `metrics.enabled` option), so rewrite
|
|
69
|
+
* `{prefix}.enabled` -> `{prefix}` to match a registered option. No CLI option is registered with an
|
|
70
|
+
* `.enabled` suffix, so this is unambiguous. If the bare `{prefix}` key is already set (e.g. mixed
|
|
71
|
+
* dotted and nested forms), the `.enabled` key is left untouched so the conflict surfaces as an
|
|
72
|
+
* "unknown argument" error rather than being silently overridden.
|
|
73
|
+
*/
|
|
74
|
+
export function translateEnabledKeys(flattened: Record<string, unknown>): Record<string, unknown> {
|
|
75
|
+
const suffix = ".enabled";
|
|
76
|
+
const translated: Record<string, unknown> = {};
|
|
77
|
+
for (const [key, value] of Object.entries(flattened)) {
|
|
78
|
+
const prefix = key.endsWith(suffix) ? key.slice(0, -suffix.length) : "";
|
|
79
|
+
if (prefix && !(prefix in flattened)) {
|
|
80
|
+
translated[prefix] = value;
|
|
81
|
+
} else {
|
|
82
|
+
translated[key] = value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return translated;
|
|
86
|
+
}
|