@voxgig/station 0.1.0 → 0.2.0

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.
Files changed (44) hide show
  1. package/dist/src/Station.d.ts +1 -118
  2. package/dist/src/Station.js +26 -412
  3. package/dist/src/Station.js.map +1 -1
  4. package/dist/src/adapter.js +0 -54
  5. package/dist/src/adapter.js.map +1 -1
  6. package/dist/src/config-shape.js +0 -11
  7. package/dist/src/config-shape.js.map +1 -1
  8. package/dist/src/descriptor.js +0 -38
  9. package/dist/src/descriptor.js.map +1 -1
  10. package/dist/src/error.js +0 -5
  11. package/dist/src/error.js.map +1 -1
  12. package/dist/src/factory.d.ts +0 -9
  13. package/dist/src/factory.js +0 -37
  14. package/dist/src/factory.js.map +1 -1
  15. package/dist/src/feature.d.ts +0 -75
  16. package/dist/src/feature.js +0 -87
  17. package/dist/src/feature.js.map +1 -1
  18. package/dist/src/index.js +0 -7
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/loader.d.ts +0 -29
  21. package/dist/src/loader.js +0 -66
  22. package/dist/src/loader.js.map +1 -1
  23. package/dist/src/profile.js +0 -91
  24. package/dist/src/profile.js.map +1 -1
  25. package/dist/src/secrets.d.ts +5 -0
  26. package/dist/src/secrets.js +106 -32
  27. package/dist/src/secrets.js.map +1 -1
  28. package/dist/src/shape.d.ts +0 -22
  29. package/dist/src/shape.js +0 -113
  30. package/dist/src/shape.js.map +1 -1
  31. package/package.json +3 -3
  32. package/src/Station.ts +28 -413
  33. package/src/adapter.ts +0 -57
  34. package/src/config-shape.ts +0 -11
  35. package/src/descriptor.ts +0 -38
  36. package/src/error.ts +0 -5
  37. package/src/factory.ts +0 -37
  38. package/src/feature.ts +0 -87
  39. package/src/index.ts +0 -7
  40. package/src/loader.ts +0 -66
  41. package/src/profile.ts +0 -95
  42. package/src/secrets.ts +104 -32
  43. package/src/shape.ts +0 -113
  44. package/src/types.ts +0 -59
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- /* Profile handling, whole: the pure half - selection, the ref grammar
3
- * and the §3.3 merge - and the file half that finds and reads
4
- * station.json plus the scope rule hanging off where it was found.
5
- *
6
- * These were two modules. `profilecore.ts` held the pure half so the
7
- * BROWSER ENTRY could reach it without pulling `node:fs`, and `Station`
8
- * reached the file half through a `ConfigFileIO` seam the node entry
9
- * registered. Station is server-side only, so the split, the seam and
10
- * the second entry are all gone and this is one module again. Every
11
- * import of `./profile` is unchanged - that path always re-exported the
12
- * pure half. */
13
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
4
  };
@@ -27,14 +16,6 @@ const sekreto_1 = require("@voxgig/sekreto");
27
16
  const descriptor_1 = require("./descriptor");
28
17
  const error_1 = require("./error");
29
18
  const shape_1 = require("./shape");
30
- // Profile selection: VOXGIG_STATION_PROFILE, else the open() option,
31
- // else 'default' (design §3.5 - env vars rank above station.json but
32
- // below open() opts; profile NAME selection follows the same order with
33
- // open() opts winning).
34
- //
35
- // `process` is read directly. It used to go through a `typeof` guard
36
- // because the browser entry reached this code and has no `process`;
37
- // station is server-side only, so the guard guarded nothing.
38
19
  function selectProfile(optProfile) {
39
20
  if (null != optProfile && '' !== optProfile) {
40
21
  return optProfile;
@@ -45,25 +26,10 @@ function selectProfile(optProfile) {
45
26
  }
46
27
  return 'default';
47
28
  }
48
- // The api half of a ref is the substring before the first `$`, and an
49
- // untagged ref IS an api slug (design §3.4) - which is why the whole
50
- // `plugin` -> `sdk` migration is a key rename and nothing else.
51
- //
52
- // LEXICAL, and that is the point: under the old free-form identity
53
- // which api an instance used was itself a merged value, so the merge
54
- // could not be a flat pass over both maps and a port that got the
55
- // phasing wrong silently picked another api's defaults (§3.3).
56
29
  function refapi(ref) {
57
30
  const at = String(ref).indexOf('$');
58
31
  return -1 === at ? String(ref) : String(ref).slice(0, at);
59
32
  }
60
- // Shallow merge, per key, left to right - each source over the one
61
- // before it. Declared rather than assumed: plugin's library default is
62
- // a deep map merge, and an allowlist that widens because two precedence
63
- // levels merged is the failure this rule exists to prevent
64
- // (station-and-plugin.md §2.5). The visible consequence: an overlay's
65
- // `policy` REPLACES the base's entirely rather than merging `hosts`
66
- // into it. That is also the safer reading for an allowlist.
67
33
  function shallow(...sources) {
68
34
  const out = {};
69
35
  for (const src of sources) {
@@ -76,29 +42,6 @@ function shallow(...sources) {
76
42
  }
77
43
  return out;
78
44
  }
79
- // Merge the base profile ('default') with the selected overlay.
80
- //
81
- // §3.3's total order, for the two block levels - lowest precedence
82
- // first:
83
- //
84
- // base.api[<api>] ⊕ base.sdk[<ref>] ⊕ overlay.api[<api>] ⊕ overlay.sdk[<ref>]
85
- //
86
- // PROFILE SPECIFICITY OUTRANKS BLOCK SPECIFICITY. A `prod` api-level
87
- // `base` beats a `default` instance-level `base`, because that is what
88
- // an environment overlay is for; within one profile the instance beats
89
- // the api default, because that is what an instance is for.
90
- //
91
- // THIS IS ONE FLAT LEFT-TO-RIGHT MERGE AND MUST NOT BE REORGANIZED INTO
92
- // "collapse each namespace, then put instance over api". Collapsing
93
- // first computes (base.api ⊕ overlay.api) and (base.sdk ⊕ overlay.sdk)
94
- // and then lets EVERY instance value beat EVERY api value - the exact
95
- // opposite. A production `api.stripe.policy` would then fail to
96
- // override a default profile's `sdk.stripe$test.policy`, silently
97
- // keeping the wider allowlist in production.
98
- //
99
- // `secrets.providers` replaces wholesale, never merges (§3.5, §5.2):
100
- // chain order decides which store wins, so a positional merge would be
101
- // actively dangerous.
102
45
  function resolveProfile(config, profileName) {
103
46
  const profiles = config?.profiles || {};
104
47
  const base = profiles['default'] || {};
@@ -116,13 +59,6 @@ function resolveProfile(config, profileName) {
116
59
  for (const ref of sortedkeys(base.sdk, overlay.sdk)) {
117
60
  const a = refapi(ref);
118
61
  const merged = shallow(base.api?.[a], base.sdk?.[ref], overlay.api?.[a], overlay.sdk?.[ref]);
119
- // Defaults are applied ONCE, to the fully merged instance, and this
120
- // is the rule §4.2's normalization must not be confused with. Had
121
- // the overlay block carried a synthesized `active: true` into the
122
- // merge, a one-key environment override would silently re-enable an
123
- // integration the base declared `active: false` - live in
124
- // production despite being declared inactive. The `instance` corpus
125
- // section carries exactly this case.
126
62
  for (const k of Object.keys(shape_1.BLOCK_DEFAULTS)) {
127
63
  if (undefined === merged[k]) {
128
64
  merged[k] = shape_1.BLOCK_DEFAULTS[k]();
@@ -133,23 +69,6 @@ function resolveProfile(config, profileName) {
133
69
  checksecrets(sdk, profileName);
134
70
  return { name: profileName, providers, api, sdk };
135
71
  }
136
- // A configured secret name sekreto would reject is caught at profile
137
- // load, not first request (§14 station_secret_name) - and then the
138
- // derived names are checked for uniqueness, because envtoken is LOSSY.
139
- //
140
- // It collapses any run of non-alphanumerics to `_`, so `$` and `-` are
141
- // indistinguishable downstream: the ref `stripe$test` and an untagged
142
- // instance of an api slugged `stripe-test` both derive
143
- // `stripe_test.apikey`. That pairing is the realistic one rather than a
144
- // contrived one, because api slugs are hyphenated by construction - so
145
- // a fleet with both a `stripe-test` api and a `test` instance of
146
- // `stripe` collides by default. Since the resolution cache is keyed by
147
- // secret name (§5.3), the second instance would silently receive the
148
- // first's value.
149
- //
150
- // Two instances that EXPLICITLY name the same secret are not a
151
- // collision - that is the shared-key case the api-level `secret` exists
152
- // for, and saying so out loud is how you ask for it.
153
72
  function checksecrets(sdk, profileName) {
154
73
  const refs = Object.keys(sdk).sort();
155
74
  for (const ref of refs) {
@@ -188,9 +107,6 @@ function sortedkeys(...maps) {
188
107
  }
189
108
  return Array.from(keys).sort();
190
109
  }
191
- // station.json lookup: cwd upward to the repo root, then
192
- // ~/.voxgig/station.json (design §3.5). A repo root is where .git lives;
193
- // with no repo the walk stops at the filesystem root.
194
110
  function findConfigFile(from) {
195
111
  let dir = node_path_1.default.resolve(from || process.cwd());
196
112
  for (;;) {
@@ -224,13 +140,6 @@ function loadConfig(from) {
224
140
  throw new error_1.StationError('station_config_invalid', 'station.json at ' + file + ' is not valid JSON: ' + err.message);
225
141
  }
226
142
  }
227
- // Which side of the review boundary the config came from (§6.3).
228
- //
229
- // `package` and `export` are honoured only from REPO-SCOPED config,
230
- // because a user-level file is outside the repo's review boundary and a
231
- // `package` key arriving from it names code to import. Everything else
232
- // in a user-level config still applies - this narrows one key rather
233
- // than distrusting the file.
234
143
  function configScope(from) {
235
144
  const file = findConfigFile(from);
236
145
  if (null == file) {
@@ -1 +1 @@
1
- {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/profile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/profile.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,9 @@
1
1
  export declare function placeholderFor(slug: string): string;
2
+ export declare function encodeQueryValue(value: string): string;
3
+ export declare function substitute(url: string, headers: Record<string, any> | null | undefined, placeholder: string, value: string): {
4
+ url: string;
5
+ headers: Record<string, any>;
6
+ };
2
7
  export declare class SecretBroker {
3
8
  private sekreto;
4
9
  private overrides;
@@ -2,18 +2,116 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SecretBroker = void 0;
4
4
  exports.placeholderFor = placeholderFor;
5
+ exports.encodeQueryValue = encodeQueryValue;
6
+ exports.substitute = substitute;
5
7
  const sekreto_1 = require("@voxgig/sekreto");
8
+ const plugins_1 = require("@voxgig/sekreto/plugins");
6
9
  const error_1 = require("./error");
7
10
  // The secret broker (design §5): sekreto resolves, station places. The
8
11
  // broker holds resolved values privately - they never enter options,
9
12
  // events, or captures; the SDK sees only the placeholder.
10
- // §7.2: keyed by INSTANCE. Two live instances of one api must have
11
- // distinct placeholders or the injection seam cannot tell which
12
- // credential a header wants. For an untagged instance this is the api
13
- // slug, so the single-instance case is unchanged.
14
13
  function placeholderFor(slug) {
15
14
  return '[station:' + slug + ']';
16
15
  }
16
+ const UNRESERVED = /^[A-Za-z0-9\-._~]$/;
17
+ const HEXPAIR = /^[0-9A-Fa-f]{2}$/;
18
+ // Every UTF-8 byte outside RFC 3986's unreserved set becomes upper-case %XX.
19
+ function encodeQueryValue(value) {
20
+ let out = '';
21
+ for (const byte of Buffer.from(value, 'utf8')) {
22
+ const ch = String.fromCharCode(byte);
23
+ out += byte < 0x80 && UNRESERVED.test(ch)
24
+ ? ch
25
+ : '%' + byte.toString(16).toUpperCase().padStart(2, '0');
26
+ }
27
+ return out;
28
+ }
29
+ function matchAt(text, at, end, placeholder) {
30
+ let i = at;
31
+ for (const ch of placeholder) {
32
+ if (i < end && text[i] === ch) {
33
+ i++;
34
+ continue;
35
+ }
36
+ const hex = text.substring(i + 1, i + 3);
37
+ if (i + 3 <= end && '%' === text[i] && HEXPAIR.test(hex) &&
38
+ parseInt(hex, 16) === ch.charCodeAt(0)) {
39
+ i += 3;
40
+ continue;
41
+ }
42
+ return -1;
43
+ }
44
+ return i - at;
45
+ }
46
+ // The placeholder becomes the value in header values and in the URL query,
47
+ // where an SDK percent-encodes it (any hex case) and the value is encoded in
48
+ // turn. The path and fragment are never touched; the headers are a copy.
49
+ function substitute(url, headers, placeholder, value) {
50
+ const out = { ...(headers || {}) };
51
+ if ('' === placeholder) {
52
+ return { url, headers: out };
53
+ }
54
+ for (const h of Object.keys(out)) {
55
+ const v = out[h];
56
+ if ('string' === typeof v && v.includes(placeholder)) {
57
+ out[h] = v.split(placeholder).join(value);
58
+ }
59
+ }
60
+ const q = url.indexOf('?');
61
+ const hash = url.indexOf('#');
62
+ if (-1 === q || (-1 !== hash && hash < q)) {
63
+ return { url, headers: out };
64
+ }
65
+ const end = -1 === hash ? url.length : hash;
66
+ const encoded = encodeQueryValue(value);
67
+ let query = '';
68
+ for (let i = q + 1; i < end;) {
69
+ const n = matchAt(url, i, end, placeholder);
70
+ if (0 < n) {
71
+ query += encoded;
72
+ i += n;
73
+ }
74
+ else {
75
+ query += url[i];
76
+ i++;
77
+ }
78
+ }
79
+ return { url: url.substring(0, q + 1) + query + url.substring(end), headers: out };
80
+ }
81
+ // Every form of every value is matched against the original text and the
82
+ // union of the matches redacted, so no replacement can hide another form.
83
+ function redactValues(text, values) {
84
+ const forms = new Set();
85
+ for (const value of values) {
86
+ if ('' !== value) {
87
+ forms.add(value);
88
+ forms.add(encodeQueryValue(value));
89
+ }
90
+ }
91
+ const reach = (at) => {
92
+ let end = at;
93
+ for (const form of forms) {
94
+ if (at + form.length > end && text.startsWith(form, at)) {
95
+ end = at + form.length;
96
+ }
97
+ }
98
+ return end;
99
+ };
100
+ let out = '';
101
+ for (let i = 0; i < text.length;) {
102
+ let stop = reach(i);
103
+ if (stop === i) {
104
+ out += text[i++];
105
+ continue;
106
+ }
107
+ for (let j = i + 1; j < stop; j++) {
108
+ stop = Math.max(stop, reach(j));
109
+ }
110
+ out += '[redacted]';
111
+ i = stop;
112
+ }
113
+ return out;
114
+ }
17
115
  class SecretBroker {
18
116
  constructor(providers) {
19
117
  // Values hoisted by adopt() from resident options.apikey (design §3.1).
@@ -21,27 +119,12 @@ class SecretBroker {
21
119
  this.cache = new Map();
22
120
  // Every value this broker ever held, for the exact-value scrub.
23
121
  this.held = [];
24
- this.sekreto = new sekreto_1.Sekreto({ providers });
122
+ this.sekreto = new sekreto_1.Sekreto({ plugins: plugins_1.allplugins, providers });
25
123
  }
26
124
  hoist(slug, value) {
27
125
  this.overrides.set(slug, value);
28
126
  this.held.push(value);
29
127
  }
30
- // Resolve the value for a plugin's secret name. Misses and store
31
- // errors keep sekreto's distinction (design §5.2): a miss is
32
- // station_secret_no_value, a store that could not answer is
33
- // station_secret_error with sekreto's message intact - and never a
34
- // retry against a weaker store (sekreto owns the chain).
35
- // OVERRIDES ARE KEYED BY INSTANCE; THE RESOLUTION CACHE IS KEYED BY
36
- // SECRET NAME (§5.3). A hoisted credential belongs to the one instance
37
- // it was resident in, but a resolved VALUE belongs to the name it was
38
- // resolved for - so several instances sharing one api-level `secret`
39
- // cost one lookup rather than one each, and every client an
40
- // auto-tagged `create()` produces shares the declared instance's entry
41
- // instead of re-resolving per request.
42
- //
43
- // Keying the cache by instance instead is the defect this replaces: at
44
- // 26 instances over 20 apis it turns one store round-trip into 26.
45
128
  async value(slug, name) {
46
129
  const override = this.overrides.get(slug);
47
130
  if (null != override) {
@@ -65,19 +148,10 @@ class SecretBroker {
65
148
  this.held.push(value);
66
149
  return value;
67
150
  }
68
- // Exact-value scrub, deliberately WITHOUT sekreto's four-character
69
- // readability floor (design §7 as revised): on boundaries where the
70
- // promise is absolute, every held value is scrubbed whatever its
71
- // length. sekreto's own redact() runs too, covering values resolved
72
- // by the underlying instance that station never held.
151
+ // sekreto's redact runs second; run first, it could split an encoded form.
73
152
  scrub(text) {
74
- let out = this.sekreto.redact(text);
75
- for (const value of this.held) {
76
- if ('' !== value) {
77
- out = out.split(value).join('[redacted]');
78
- }
79
- }
80
- return out;
153
+ const raw = 'string' === typeof text ? text : '';
154
+ return this.sekreto.redact(redactValues(raw, this.held));
81
155
  }
82
156
  // Drop caches so the next resolve asks the stores again (rotation
83
157
  // support rides on sekreto's refresh, design §5.3).
@@ -1 +1 @@
1
- {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/secrets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/secrets.ts"],"names":[],"mappings":"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"}
@@ -3,15 +3,6 @@
3
3
  export declare const PROFILE_DEFAULTS: {
4
4
  [k: string]: () => any;
5
5
  };
6
- /** Block-level. `feature` is a container and safe early.
7
- *
8
- * `active` IS NOT, and that is the whole timing rule: a default
9
- * synthesized into an OVERLAY block overwrites the base's real value
10
- * and silently reactivates an integration the base deliberately barred
11
- * (§3.3). So the two consumers read this same table at different
12
- * moments - validateConfig before, to every block, because a block with
13
- * no present keys is an open map; the resolver AFTER, to the merged
14
- * instance, because an absent key must stay absent through the merge. */
15
6
  export declare const BLOCK_DEFAULTS: {
16
7
  [k: string]: () => any;
17
8
  };
@@ -19,12 +10,6 @@ export declare const BLOCK_DEFAULTS: {
19
10
  * inferred, so a reader does not have to work out which of the two it
20
11
  * is, and so a port can assert it. */
21
12
  export declare const MERGE_SENSITIVE: string[];
22
- /** Materialize every documented default, DEFENSIVELY: a node that is
23
- * not the kind it expects is left alone for validate to reject with a
24
- * proper message. Pure data-in/data-out, which is what makes it
25
- * portable to 22 languages and expressible in the corpus.
26
- *
27
- * THE NORMALIZED FORM IS AN INPUT TO VALIDATION AND TO NOTHING ELSE. */
28
13
  export declare function normalizeConfig(raw: any): any;
29
14
  /** `spec/config-shape.json`, §4.3 verbatim, through the shipped mirror.
30
15
  * Every validate gets a CLONE: struct's validate consumes the spec it
@@ -32,11 +17,4 @@ export declare function normalizeConfig(raw: any): any;
32
17
  * the module constant twice would validate the second config against a
33
18
  * spec the first had already eaten. */
34
19
  export declare function configShape(): any;
35
- /** Normalize, then validate (§4.2). Raises `station_config_invalid`
36
- * with EVERY struct error at once - an eighteen-instance config that
37
- * touches three of them must not die because the eighteenth has a
38
- * typo'd package name - then the §5.2 scans.
39
- *
40
- * Takes the NORMALIZED form. Handing it a raw config is the mistake
41
- * §4.2 exists to prevent, so callers go through open()/loadConfig. */
42
20
  export declare function validateConfig(normalized: any): any;
package/dist/src/shape.js CHANGED
@@ -1,22 +1,4 @@
1
1
  "use strict";
2
- /* The config grammar, as data (design §4).
3
- *
4
- * TWO STEPS, AND THE FIRST IS WHAT MAKES THE SECOND HONEST.
5
- *
6
- * struct drops the unexpected-key check for a map whose spec node ends
7
- * up empty - "an empty spec object means the object can be open". An
8
- * optional key is `['$ONE','$NIL', spec]`, and when the data does not
9
- * carry that key the validator REMOVES it from the spec node. So a
10
- * block whose keys are all optional degenerates into an open map
11
- * exactly when the data has none of them, and `{"solar": {"bass": 1}}`
12
- * validates clean - the one property the whole exercise is for,
13
- * silently absent in the one case that matters.
14
- *
15
- * So: normalizeConfig materializes every documented default, and
16
- * validateConfig then runs a shape WITH NO OPTIONAL CONTAINERS AT ALL.
17
- * After normalization every container is present, so the shape can
18
- * require them, so unexpected-key detection is live at every level and
19
- * every error names its path. */
20
2
  Object.defineProperty(exports, "__esModule", { value: true });
21
3
  exports.MERGE_SENSITIVE = exports.BLOCK_DEFAULTS = exports.PROFILE_DEFAULTS = void 0;
22
4
  exports.normalizeConfig = normalizeConfig;
@@ -27,9 +9,6 @@ const sekreto_1 = require("@voxgig/sekreto");
27
9
  const config_shape_1 = require("./config-shape");
28
10
  const error_1 = require("./error");
29
11
  const descriptor_1 = require("./descriptor");
30
- // ---------------------------------------------------------------------
31
- // The defaults table - ONE table, two callers
32
- // ---------------------------------------------------------------------
33
12
  /** Profile-level containers. Safe to materialize early either way:
34
13
  * they are containers, and a missing one merges as empty regardless. */
35
14
  exports.PROFILE_DEFAULTS = {
@@ -38,15 +17,6 @@ exports.PROFILE_DEFAULTS = {
38
17
  sdk: () => ({}),
39
18
  feature: () => ({}),
40
19
  };
41
- /** Block-level. `feature` is a container and safe early.
42
- *
43
- * `active` IS NOT, and that is the whole timing rule: a default
44
- * synthesized into an OVERLAY block overwrites the base's real value
45
- * and silently reactivates an integration the base deliberately barred
46
- * (§3.3). So the two consumers read this same table at different
47
- * moments - validateConfig before, to every block, because a block with
48
- * no present keys is an open map; the resolver AFTER, to the merged
49
- * instance, because an absent key must stay absent through the merge. */
50
20
  exports.BLOCK_DEFAULTS = {
51
21
  active: () => true,
52
22
  feature: () => ({}),
@@ -58,12 +28,6 @@ exports.MERGE_SENSITIVE = ['active'];
58
28
  // ---------------------------------------------------------------------
59
29
  // normalizeConfig
60
30
  // ---------------------------------------------------------------------
61
- /** Materialize every documented default, DEFENSIVELY: a node that is
62
- * not the kind it expects is left alone for validate to reject with a
63
- * proper message. Pure data-in/data-out, which is what makes it
64
- * portable to 22 languages and expressible in the corpus.
65
- *
66
- * THE NORMALIZED FORM IS AN INPUT TO VALIDATION AND TO NOTHING ELSE. */
67
31
  function normalizeConfig(raw) {
68
32
  if (!ismap(raw)) {
69
33
  return raw;
@@ -91,7 +55,6 @@ function normalizeConfig(raw) {
91
55
  prof[k] = exports.PROFILE_DEFAULTS[k]();
92
56
  }
93
57
  }
94
- // A `secrets` written without `providers` still gets the chain.
95
58
  if (ismap(prof.secrets) && undefined === prof.secrets.providers) {
96
59
  prof.secrets = { ...prof.secrets, providers: [{ kind: 'env' }] };
97
60
  }
@@ -123,16 +86,6 @@ function normalizeConfig(raw) {
123
86
  out.profiles = profiles;
124
87
  return out;
125
88
  }
126
- /** Per feature entry, at every level: `active` -> true.
127
- *
128
- * A FEATURE NAMED IN THE CONFIG IS ONE YOU ARE ASKING FOR. The SDK's
129
- * own default is `active: false` for all but `log`, and
130
- * `{"retry": {"retries": 3}}` plainly means "retry, with three
131
- * attempts". It also keeps the feature map closed, for the same reason
132
- * every other block needs one present key.
133
- *
134
- * Defensive like the rest: a non-map is returned untouched for validate
135
- * to reject by path. */
136
89
  function normfeatures(f) {
137
90
  if (!ismap(f)) {
138
91
  return f;
@@ -162,30 +115,9 @@ const CREDENTIAL_KEYS = [
162
115
  'apikey', 'auth', 'authorization', 'token',
163
116
  'secret', 'password', 'credential', 'bearer',
164
117
  ];
165
- /** The suffix rule catches `access_key`, `X-Api-Token` and friends in
166
- * one rule rather than a growing list of spellings. */
167
118
  const CREDENTIAL_SUFFIX = ['_KEY', '_TOKEN', '_SECRET', '_PASSWORD'];
168
- /** §5.2's backstop, and it is stated as one rather than as a grammar.
169
- * `validname()` is a NAME grammar, not a credential filter: it rejects
170
- * uppercase, hyphens, `+`, `/` and `=`, so it excludes most real
171
- * credential formats - but a lowercase hex token passes it cleanly. A
172
- * character class cannot tell a name from a secret.
173
- *
174
- * Derived names break on every separator (`voxgig_solardemo.apikey`
175
- * runs 6/9/6) and a hand-written name for a human to read does too; a
176
- * 24-character unbroken run is not a name anybody writes. Note this is
177
- * a RUN bound, not a length bound: `acme_internal_billing_service.apikey`
178
- * is 36 characters and passes, which is the false positive a naive
179
- * length bound would produce. */
180
119
  const RUN_BOUND = 24;
181
120
  const UNBROKEN_RUN = new RegExp('[A-Za-z0-9]{' + RUN_BOUND + ',}');
182
- /** Normalize, then validate (§4.2). Raises `station_config_invalid`
183
- * with EVERY struct error at once - an eighteen-instance config that
184
- * touches three of them must not die because the eighteenth has a
185
- * typo'd package name - then the §5.2 scans.
186
- *
187
- * Takes the NORMALIZED form. Handing it a raw config is the mistake
188
- * §4.2 exists to prevent, so callers go through open()/loadConfig. */
189
121
  function validateConfig(normalized) {
190
122
  const errs = [];
191
123
  (0, struct_1.validate)(normalized, configShape(), { errs });
@@ -195,11 +127,6 @@ function validateConfig(normalized) {
195
127
  scanConfig(normalized);
196
128
  return normalized;
197
129
  }
198
- /** `plugin` is REMOVED, not aliased (§3.4) - a deprecated alias would
199
- * be a second grammar for one concept in 17 ports. The shape already
200
- * rejects it as an unexpected key; this says what to rename, because
201
- * "unexpected key: plugin" alone does not, and the migration for a
202
- * single-instance project is exactly this one rename. */
203
130
  function renamehint(cfg) {
204
131
  const profiles = ismap(cfg) && ismap(cfg.profiles) ? cfg.profiles : {};
205
132
  const hit = Object.keys(profiles)
@@ -211,8 +138,6 @@ function renamehint(cfg) {
211
138
  hit.map((p) => 'profiles.' + p).join(', ') +
212
139
  ' - the keys are unchanged, an untagged ref IS an api slug (§3.4)';
213
140
  }
214
- /** The §5.2 scans, over the parts of the grammar that hold arbitrary
215
- * data. Everything else is closed by construction and needs no scan. */
216
141
  function scanConfig(cfg) {
217
142
  const secrets = [];
218
143
  const reserved = [];
@@ -241,14 +166,8 @@ function scanConfig(cfg) {
241
166
  if (undefined !== block.secret) {
242
167
  secretvalue(block.secret, bpath + '.secret', secrets);
243
168
  }
244
- // `options` is passthrough to a generated constructor, so it is
245
- // the one place a value can hide.
246
169
  scan(block.options, bpath + '.options', secrets, reserved);
247
170
  checkfeatures(block.feature, bpath + '.feature', secrets, reserved, invalid);
248
- // §4.4's explicit checks, applied where the shape cannot reach,
249
- // raising the same code the shape would - and pinned in the
250
- // corpus so each workaround is removed deliberately when struct
251
- // is fixed rather than forgotten.
252
171
  checkpolicy(block.policy, bpath + '.policy', invalid);
253
172
  }
254
173
  }
@@ -284,19 +203,6 @@ function checkfeatures(f, path, secrets, reserved, invalid) {
284
203
  scan(f[name], fpath, secrets, reserved);
285
204
  }
286
205
  }
287
- /** The policy block's §4.4 workarounds, in one place because they are
288
- * one class of gap: struct cannot check what its own defects hide.
289
- *
290
- * - `hosts`, `allow.op` and `allow.method` are `$CHILD` string lists,
291
- * so element 0 escapes the shape (see firstelement below).
292
- * - `budget` is a map whose keys are ALL optional scalars, and struct
293
- * removes an unsatisfied optional key from the spec node - so
294
- * `budget: {rp: 1}` degenerates the spec into an open map and the
295
- * typo passes. `allow` does not have this problem (its `$CHILD` keys
296
- * stay in the spec whether or not the data carries them, keeping the
297
- * map closed), and neither does `policy` itself (`hosts` anchors it);
298
- * `budget` alone needs the explicit unexpected-key check, phrased as
299
- * struct would phrase it. */
300
206
  const BUDGET_KEYS = ['concurrency', 'rps'];
301
207
  function checkpolicy(policy, path, invalid) {
302
208
  if (!ismap(policy)) {
@@ -318,19 +224,6 @@ function checkpolicy(policy, path, invalid) {
318
224
  }
319
225
  }
320
226
  }
321
- /** §4.4: `$CHILD` in list mode DOES NOT VALIDATE ELEMENT 0. Verified:
322
- * `["a", 1]` fails at index 1, `[1]` passes. validate_CHILD installs the
323
- * template across the data's indices, sets keyI = 0 and returns element
324
- * 0 as the slot value, and the injection loop resumes past it. An
325
- * upstream struct defect; filing it is a deliverable of this plan.
326
- *
327
- * It reaches EVERY string list in the shape. §4.4 says the only one left
328
- * is `policy.hosts` because the profile-level `order` list is gone - but
329
- * §8.4's per-feature `order` carries `before`/`after` string lists, so
330
- * the reach is three lists, not one, and §4.5 pins `order: [7]`
331
- * accordingly. Applied where the shape cannot reach, raising the same
332
- * code the shape would, and pinned in the corpus so the workaround is
333
- * removed deliberately when struct is fixed rather than forgotten. */
334
227
  function firstelement(list, path, invalid) {
335
228
  if (!Array.isArray(list) || 0 === list.length) {
336
229
  return;
@@ -360,8 +253,6 @@ function scan(node, path, secrets, reserved) {
360
253
  for (const key of Object.keys(node)) {
361
254
  const kpath = path + '.' + key;
362
255
  const val = node[key];
363
- // §8.6: station owns feature composition, so an `options.feature`
364
- // in a declarative config is a second, unreconciled ordering input.
365
256
  if ('feature' === key) {
366
257
  reserved.push(kpath + ' is reserved: configure features under the ' +
367
258
  'block\'s own `feature` key, not through `options`');
@@ -387,10 +278,6 @@ function credentialkey(key) {
387
278
  const tok = (0, descriptor_1.envtoken)(key);
388
279
  return CREDENTIAL_SUFFIX.some((s) => tok.endsWith(s));
389
280
  }
390
- /** A `secret`-named key holds a NAME, and that exemption is not a
391
- * loophole - it is the whole design. Two checks, not one, and they live
392
- * in the same three lines precisely so a port cannot implement only the
393
- * first and inherit the gap the second exists to close. */
394
281
  function secretvalue(val, path, secrets) {
395
282
  if ('string' !== typeof val) {
396
283
  secrets.push(path + ' must be a secret name (a string), but found ' +