@chainsafe/lodestar 1.45.0-dev.0c3761f06f → 1.45.0-dev.2e1d834bb9

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 CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "branch": "unstable",
3
- "commit": "0c3761f06f73ea7951fab54274da03d71fb21da6"
3
+ "commit": "2e1d834bb9bdfbfc050628171153f6110931d2ca"
4
4
  }
@@ -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;AAoDrD,eAAO,MAAM,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAI5F,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAExD,eAAO,MAAM,aAAa;;;;;;;;;;;CAGzB,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;AAC1C,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;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,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;CAC/F,CAAC;AAIF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,mBAAmB;IACtB,GAAG,aAAa;CACjB,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"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/util/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAEjD;;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"}
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"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/util/object.ts"],"names":[],"mappings":"AAEA;;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"}
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.0c3761f06f",
3
+ "version": "1.45.0-dev.2e1d834bb9",
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.0c3761f06f",
72
- "@lodestar/beacon-node": "^1.45.0-dev.0c3761f06f",
73
- "@lodestar/config": "^1.45.0-dev.0c3761f06f",
74
- "@lodestar/db": "^1.45.0-dev.0c3761f06f",
75
- "@lodestar/logger": "^1.45.0-dev.0c3761f06f",
76
- "@lodestar/params": "^1.45.0-dev.0c3761f06f",
77
- "@lodestar/state-transition": "^1.45.0-dev.0c3761f06f",
78
- "@lodestar/types": "^1.45.0-dev.0c3761f06f",
79
- "@lodestar/utils": "^1.45.0-dev.0c3761f06f",
80
- "@lodestar/validator": "^1.45.0-dev.0c3761f06f",
71
+ "@lodestar/api": "^1.45.0-dev.2e1d834bb9",
72
+ "@lodestar/beacon-node": "^1.45.0-dev.2e1d834bb9",
73
+ "@lodestar/config": "^1.45.0-dev.2e1d834bb9",
74
+ "@lodestar/db": "^1.45.0-dev.2e1d834bb9",
75
+ "@lodestar/logger": "^1.45.0-dev.2e1d834bb9",
76
+ "@lodestar/params": "^1.45.0-dev.2e1d834bb9",
77
+ "@lodestar/state-transition": "^1.45.0-dev.2e1d834bb9",
78
+ "@lodestar/types": "^1.45.0-dev.2e1d834bb9",
79
+ "@lodestar/utils": "^1.45.0-dev.2e1d834bb9",
80
+ "@lodestar/validator": "^1.45.0-dev.2e1d834bb9",
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.0c3761f06f",
96
+ "@lodestar/test-utils": "^1.45.0-dev.2e1d834bb9",
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": "b87265e4e2ea599a715a551f4963e60a26b241b0"
110
+ "gitHead": "4bd0feebb55734a1ca3af92343f1cdf93d78fced"
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> => readFile(configPath, ["json", "yml", "yaml"]),
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;
@@ -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
+ }