@conduitplatform/module-tools 0.17.0-alpha.6 → 0.17.0-alpha.7

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/dist/index.cjs CHANGED
@@ -48,6 +48,8 @@ __export(index_exports, {
48
48
  RouteBuilder: () => RouteBuilder,
49
49
  RoutingManager: () => RoutingManager,
50
50
  addServiceToServer: () => addServiceToServer,
51
+ containsRedactedMarker: () => containsRedactedMarker,
52
+ convictConfigParser: () => convictConfigParser,
51
53
  createParsedRouterRequest: () => createParsedRouterRequest,
52
54
  createServer: () => createServer,
53
55
  exportModel: () => exportModel,
@@ -57,7 +59,12 @@ __export(index_exports, {
57
59
  linearBackoffTimeoutAsync: () => linearBackoffTimeoutAsync,
58
60
  merge: () => merge,
59
61
  readConduitPeersManifest: () => readConduitPeersManifest,
62
+ reconcileStoredModuleConfig: () => reconcileStoredModuleConfig,
63
+ redactSensitiveConfig: () => redactSensitiveConfig,
64
+ restoreRedactedSecrets: () => restoreRedactedSecrets,
60
65
  sanitizeDocumentsForExport: () => sanitizeDocumentsForExport,
66
+ stableConfigJson: () => stableConfigJson,
67
+ storedConfigsEquivalent: () => storedConfigsEquivalent,
61
68
  stripInternalFields: () => stripInternalFields,
62
69
  wrapFunctionsAsync: () => wrapFunctionsAsync,
63
70
  wrapGrpcFunctions: () => wrapGrpcFunctions,
@@ -284,11 +291,19 @@ function wrapGrpcFunctions(functions, postponeRestart, noAuth = false) {
284
291
  try {
285
292
  invoked = functions[name](call, callback);
286
293
  } catch (error) {
287
- return throwError(callback, error.message);
294
+ return throwError(
295
+ callback,
296
+ error.message,
297
+ error instanceof import_grpc_sdk3.GrpcError ? error.code : import_grpc_js2.status.INTERNAL
298
+ );
288
299
  }
289
300
  if (typeof invoked?.then === "function") {
290
301
  invoked.then().catch((error) => {
291
- return throwError(callback, error.message);
302
+ return throwError(
303
+ callback,
304
+ error.message,
305
+ error instanceof import_grpc_sdk3.GrpcError ? error.code : import_grpc_js2.status.INTERNAL
306
+ );
292
307
  });
293
308
  }
294
309
  };
@@ -1775,6 +1790,110 @@ var convictConfigParser = (config) => {
1775
1790
  return config;
1776
1791
  };
1777
1792
 
1793
+ // src/utilities/redactSensitiveConfig.ts
1794
+ var WELL_KNOWN_SECRET_KEYS = /^(apiKey|api_key|password|secret|privateKey|private_key)$/i;
1795
+ function isRecord(value) {
1796
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1797
+ }
1798
+ function isSchemaLeaf(value) {
1799
+ return isRecord(value) && ("default" in value || "format" in value || "type" in value) && !isRecord(value._cvtProperties);
1800
+ }
1801
+ function isSensitiveLeaf(value) {
1802
+ return isSchemaLeaf(value) && value.sensitive === true;
1803
+ }
1804
+ function unwrapSchema(schema) {
1805
+ if (isRecord(schema) && isRecord(schema._cvtProperties)) {
1806
+ return schema._cvtProperties;
1807
+ }
1808
+ return schema;
1809
+ }
1810
+ var REDACTED_MARKER = "[REDACTED]";
1811
+ function containsRedactedMarker(value) {
1812
+ if (value === REDACTED_MARKER) return true;
1813
+ if (Array.isArray(value)) {
1814
+ return value.some(containsRedactedMarker);
1815
+ }
1816
+ if (!isRecord(value)) return false;
1817
+ return Object.values(value).some(containsRedactedMarker);
1818
+ }
1819
+ function redactSensitiveConfig(config, schema) {
1820
+ if (!isRecord(config)) return config;
1821
+ const redacted = Array.isArray(config) ? [...config] : { ...config };
1822
+ const node = unwrapSchema(schema);
1823
+ for (const [key, value] of Object.entries(redacted)) {
1824
+ const childSchema = isRecord(node) ? node[key] : void 0;
1825
+ if (isSensitiveLeaf(childSchema) || WELL_KNOWN_SECRET_KEYS.test(key)) {
1826
+ if (typeof value === "string" && value.length > 0) {
1827
+ redacted[key] = REDACTED_MARKER;
1828
+ }
1829
+ continue;
1830
+ }
1831
+ if (isRecord(value) || Array.isArray(value)) {
1832
+ redacted[key] = redactSensitiveConfig(
1833
+ value,
1834
+ childSchema
1835
+ );
1836
+ }
1837
+ }
1838
+ return redacted;
1839
+ }
1840
+ function restoreRedactedSecrets(incoming, current, schema) {
1841
+ if (Array.isArray(incoming) && Array.isArray(current)) {
1842
+ return incoming.map(
1843
+ (item, index) => restoreRedactedSecrets(item, current[index], schema)
1844
+ );
1845
+ }
1846
+ if (!isRecord(incoming) || !isRecord(current)) return incoming;
1847
+ const restored = { ...incoming };
1848
+ const node = unwrapSchema(schema);
1849
+ for (const [key, value] of Object.entries(restored)) {
1850
+ const childSchema = isRecord(node) ? node[key] : void 0;
1851
+ const currentValue = current[key];
1852
+ if (isSensitiveLeaf(childSchema) || WELL_KNOWN_SECRET_KEYS.test(key)) {
1853
+ if (value === REDACTED_MARKER && typeof currentValue === "string" && currentValue.length > 0 && currentValue !== REDACTED_MARKER) {
1854
+ restored[key] = currentValue;
1855
+ }
1856
+ continue;
1857
+ }
1858
+ if ((isRecord(value) || Array.isArray(value)) && (isRecord(currentValue) || Array.isArray(currentValue))) {
1859
+ restored[key] = restoreRedactedSecrets(value, currentValue, childSchema);
1860
+ }
1861
+ }
1862
+ return restored;
1863
+ }
1864
+
1865
+ // src/utilities/reconcileModuleConfig.ts
1866
+ function isRecord2(value) {
1867
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1868
+ }
1869
+ function sortJson(value) {
1870
+ if (Array.isArray(value)) {
1871
+ return value.map(sortJson);
1872
+ }
1873
+ if (!isRecord2(value)) {
1874
+ return value;
1875
+ }
1876
+ return Object.fromEntries(
1877
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortJson(nested)])
1878
+ );
1879
+ }
1880
+ function stableConfigJson(value) {
1881
+ return JSON.stringify(sortJson(value));
1882
+ }
1883
+ function storedConfigsEquivalent(left, right) {
1884
+ return stableConfigJson(left) === stableConfigJson(right);
1885
+ }
1886
+ async function reconcileStoredModuleConfig(args) {
1887
+ if (storedConfigsEquivalent(args.stored, args.migrated)) {
1888
+ return { config: args.migrated, persisted: false };
1889
+ }
1890
+ if (containsRedactedMarker(args.migrated)) {
1891
+ return { config: args.migrated, persisted: false };
1892
+ }
1893
+ const persisted = await args.configureOverride(args.migrated);
1894
+ return { config: persisted, persisted: true };
1895
+ }
1896
+
1778
1897
  // src/routing/RoutingController.ts
1779
1898
  var import_grpc_js5 = require("@grpc/grpc-js");
1780
1899
  var RoutingController = class {
@@ -1827,6 +1946,9 @@ var ManagedModule = class extends ConduitServiceModule {
1827
1946
  throw new Error("Failed to initialize grpcSdk");
1828
1947
  }
1829
1948
  }
1949
+ get configInitialized() {
1950
+ return this._configInitialized;
1951
+ }
1830
1952
  get name() {
1831
1953
  return this._moduleName;
1832
1954
  }
@@ -2018,9 +2140,10 @@ var ManagedModule = class extends ConduitServiceModule {
2018
2140
  });
2019
2141
  }
2020
2142
  let config = JSON.parse(call.request.newConfig);
2021
- config = merge(this.config.getProperties(), config);
2022
- config = await this.preConfig(config);
2023
2143
  const previousConfig = this.config.getProperties();
2144
+ config = merge(previousConfig, config);
2145
+ config = restoreRedactedSecrets(config, previousConfig, this.configSchema);
2146
+ config = await this.preConfig(config);
2024
2147
  try {
2025
2148
  this.config.load(config).validate({
2026
2149
  allowed: "warn"
@@ -2096,7 +2219,21 @@ var ManagedModule = class extends ConduitServiceModule {
2096
2219
  this.configOverride
2097
2220
  );
2098
2221
  ConfigController.getInstance();
2099
- if (config) ConfigController.getInstance().config = config;
2222
+ if (config) {
2223
+ const migrated = await this.preConfig(config);
2224
+ this.config.load(migrated).validate({
2225
+ allowed: "warn"
2226
+ });
2227
+ const persistable = this.config.getProperties();
2228
+ const reconciled = await reconcileStoredModuleConfig({
2229
+ stored: config,
2230
+ migrated: persistable,
2231
+ configureOverride: (next) => this.grpcSdk.config.configure(next, convictConfigParser(configSchema), true)
2232
+ });
2233
+ config = reconciled.config;
2234
+ this.config.load(config);
2235
+ ConfigController.getInstance().config = this.config.getProperties();
2236
+ }
2100
2237
  if (!config || config.active || !config.hasOwnProperty("active"))
2101
2238
  await this.onConfig();
2102
2239
  }
@@ -2141,6 +2278,8 @@ var ModuleError = class extends import_grpc_sdk15.GrpcError {
2141
2278
  RouteBuilder,
2142
2279
  RoutingManager,
2143
2280
  addServiceToServer,
2281
+ containsRedactedMarker,
2282
+ convictConfigParser,
2144
2283
  createParsedRouterRequest,
2145
2284
  createServer,
2146
2285
  exportModel,
@@ -2150,7 +2289,12 @@ var ModuleError = class extends import_grpc_sdk15.GrpcError {
2150
2289
  linearBackoffTimeoutAsync,
2151
2290
  merge,
2152
2291
  readConduitPeersManifest,
2292
+ reconcileStoredModuleConfig,
2293
+ redactSensitiveConfig,
2294
+ restoreRedactedSecrets,
2153
2295
  sanitizeDocumentsForExport,
2296
+ stableConfigJson,
2297
+ storedConfigsEquivalent,
2154
2298
  stripInternalFields,
2155
2299
  wrapFunctionsAsync,
2156
2300
  wrapGrpcFunctions,