@conduitplatform/module-tools 0.17.0-alpha.3 → 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
  };
@@ -302,7 +317,7 @@ function throwError(callback, message, code = import_grpc_js2.status.INTERNAL) {
302
317
  }
303
318
 
304
319
  // src/helpers/GrpcToParsedRouterRequest.ts
305
- function createParsedRouterRequest(params, urlParams, queryParams, bodyParams, path4, headers, context, cookies) {
320
+ function createParsedRouterRequest(params, urlParams, queryParams, bodyParams, path4, headers, context, cookies, rawHeaders, rawBody) {
306
321
  return {
307
322
  request: {
308
323
  params,
@@ -311,6 +326,8 @@ function createParsedRouterRequest(params, urlParams, queryParams, bodyParams, p
311
326
  bodyParams: bodyParams ?? {},
312
327
  path: path4 ?? "",
313
328
  headers,
329
+ rawHeaders: rawHeaders ?? [],
330
+ rawBody: rawBody ?? Buffer.alloc(0),
314
331
  context: context ?? {},
315
332
  cookies: cookies ?? {}
316
333
  }
@@ -515,6 +532,14 @@ var RouteBuilder = class {
515
532
  this._options.rateLimit = { maxRequests, resetInterval };
516
533
  return this;
517
534
  }
535
+ captureRawBody(capture) {
536
+ this._options.captureRawBody = capture;
537
+ return this;
538
+ }
539
+ captureRawHeaders(capture) {
540
+ this._options.captureRawHeaders = capture;
541
+ return this;
542
+ }
518
543
  return(name, fields) {
519
544
  this._returns = new import_grpc_sdk5.ConduitRouteReturnDefinition(name, fields);
520
545
  return this;
@@ -664,6 +689,12 @@ function wrapRouterGrpcFunction(fun, routerType) {
664
689
  routerRequest = !call.request.hasOwnProperty("event");
665
690
  if (routerRequest) {
666
691
  call.request.headers = parseRequestData(call.request.headers);
692
+ call.request.rawHeaders = call.request.rawHeaders ? JSON.parse(call.request.rawHeaders) : [];
693
+ if (call.request.rawBody && !Buffer.isBuffer(call.request.rawBody)) {
694
+ call.request.rawBody = Buffer.from(call.request.rawBody);
695
+ } else if (!call.request.rawBody) {
696
+ call.request.rawBody = Buffer.alloc(0);
697
+ }
667
698
  }
668
699
  } catch (e) {
669
700
  import_grpc_sdk6.ConduitGrpcSdk.Metrics?.increment(`${routerType}_grpc_errors_total`);
@@ -1759,6 +1790,110 @@ var convictConfigParser = (config) => {
1759
1790
  return config;
1760
1791
  };
1761
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
+
1762
1897
  // src/routing/RoutingController.ts
1763
1898
  var import_grpc_js5 = require("@grpc/grpc-js");
1764
1899
  var RoutingController = class {
@@ -1811,6 +1946,9 @@ var ManagedModule = class extends ConduitServiceModule {
1811
1946
  throw new Error("Failed to initialize grpcSdk");
1812
1947
  }
1813
1948
  }
1949
+ get configInitialized() {
1950
+ return this._configInitialized;
1951
+ }
1814
1952
  get name() {
1815
1953
  return this._moduleName;
1816
1954
  }
@@ -2002,9 +2140,10 @@ var ManagedModule = class extends ConduitServiceModule {
2002
2140
  });
2003
2141
  }
2004
2142
  let config = JSON.parse(call.request.newConfig);
2005
- config = merge(this.config.getProperties(), config);
2006
- config = await this.preConfig(config);
2007
2143
  const previousConfig = this.config.getProperties();
2144
+ config = merge(previousConfig, config);
2145
+ config = restoreRedactedSecrets(config, previousConfig, this.configSchema);
2146
+ config = await this.preConfig(config);
2008
2147
  try {
2009
2148
  this.config.load(config).validate({
2010
2149
  allowed: "warn"
@@ -2080,7 +2219,21 @@ var ManagedModule = class extends ConduitServiceModule {
2080
2219
  this.configOverride
2081
2220
  );
2082
2221
  ConfigController.getInstance();
2083
- 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
+ }
2084
2237
  if (!config || config.active || !config.hasOwnProperty("active"))
2085
2238
  await this.onConfig();
2086
2239
  }
@@ -2125,6 +2278,8 @@ var ModuleError = class extends import_grpc_sdk15.GrpcError {
2125
2278
  RouteBuilder,
2126
2279
  RoutingManager,
2127
2280
  addServiceToServer,
2281
+ containsRedactedMarker,
2282
+ convictConfigParser,
2128
2283
  createParsedRouterRequest,
2129
2284
  createServer,
2130
2285
  exportModel,
@@ -2134,7 +2289,12 @@ var ModuleError = class extends import_grpc_sdk15.GrpcError {
2134
2289
  linearBackoffTimeoutAsync,
2135
2290
  merge,
2136
2291
  readConduitPeersManifest,
2292
+ reconcileStoredModuleConfig,
2293
+ redactSensitiveConfig,
2294
+ restoreRedactedSecrets,
2137
2295
  sanitizeDocumentsForExport,
2296
+ stableConfigJson,
2297
+ storedConfigsEquivalent,
2138
2298
  stripInternalFields,
2139
2299
  wrapFunctionsAsync,
2140
2300
  wrapGrpcFunctions,