@salesforce/core 4.0.0 → 4.0.1

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 (153) hide show
  1. package/LICENSE.txt +1 -1
  2. package/README.md +93 -44
  3. package/lib/config/aliasesConfig.d.ts +12 -0
  4. package/lib/config/aliasesConfig.js +28 -0
  5. package/lib/config/authInfoConfig.d.ts +19 -0
  6. package/lib/config/authInfoConfig.js +35 -0
  7. package/lib/config/config.d.ts +87 -22
  8. package/lib/config/config.js +117 -65
  9. package/lib/config/configAggregator.d.ts +41 -35
  10. package/lib/config/configAggregator.js +102 -73
  11. package/lib/config/configFile.d.ts +2 -2
  12. package/lib/config/configFile.js +38 -29
  13. package/lib/config/configGroup.d.ts +141 -0
  14. package/lib/config/configGroup.js +225 -0
  15. package/lib/config/configStore.d.ts +9 -9
  16. package/lib/config/configStore.js +17 -15
  17. package/lib/config/envVars.d.ts +15 -9
  18. package/lib/config/envVars.js +71 -47
  19. package/lib/config/orgUsersConfig.js +2 -0
  20. package/lib/config/sandboxOrgConfig.js +2 -0
  21. package/lib/config/sandboxProcessCache.d.ts +16 -0
  22. package/lib/config/sandboxProcessCache.js +38 -0
  23. package/lib/config/tokensConfig.d.ts +10 -0
  24. package/lib/config/tokensConfig.js +29 -0
  25. package/lib/config/ttlConfig.d.ts +34 -0
  26. package/lib/config/ttlConfig.js +50 -0
  27. package/lib/crypto/crypto.js +15 -22
  28. package/lib/crypto/keyChain.js +2 -3
  29. package/lib/crypto/keyChainImpl.d.ts +5 -3
  30. package/lib/crypto/keyChainImpl.js +58 -61
  31. package/lib/crypto/secureBuffer.d.ts +1 -1
  32. package/lib/deviceOauthService.d.ts +3 -3
  33. package/lib/deviceOauthService.js +27 -25
  34. package/lib/exported.d.ts +15 -12
  35. package/lib/exported.js +28 -16
  36. package/lib/global.d.ts +11 -3
  37. package/lib/global.js +39 -12
  38. package/lib/lifecycleEvents.d.ts +1 -1
  39. package/lib/lifecycleEvents.js +3 -0
  40. package/lib/logger.d.ts +19 -9
  41. package/lib/logger.js +112 -86
  42. package/lib/messages.d.ts +53 -36
  43. package/lib/messages.js +81 -91
  44. package/lib/org/authInfo.d.ts +56 -20
  45. package/lib/org/authInfo.js +232 -131
  46. package/lib/org/authRemover.d.ts +8 -7
  47. package/lib/org/authRemover.js +32 -28
  48. package/lib/org/connection.d.ts +13 -37
  49. package/lib/org/connection.js +78 -124
  50. package/lib/org/index.js +5 -1
  51. package/lib/org/org.d.ts +151 -48
  52. package/lib/org/org.js +466 -220
  53. package/lib/org/orgConfigProperties.d.ts +64 -3
  54. package/lib/org/orgConfigProperties.js +96 -4
  55. package/lib/org/permissionSetAssignment.js +4 -13
  56. package/lib/org/scratchOrgCache.d.ts +20 -0
  57. package/lib/org/scratchOrgCache.js +33 -0
  58. package/lib/org/scratchOrgCreate.d.ts +28 -17
  59. package/lib/org/scratchOrgCreate.js +125 -53
  60. package/lib/org/scratchOrgErrorCodes.d.ts +9 -3
  61. package/lib/org/scratchOrgErrorCodes.js +34 -17
  62. package/lib/org/scratchOrgFeatureDeprecation.js +1 -6
  63. package/lib/org/scratchOrgInfoApi.d.ts +21 -47
  64. package/lib/org/scratchOrgInfoApi.js +129 -63
  65. package/lib/org/scratchOrgInfoGenerator.d.ts +6 -5
  66. package/lib/org/scratchOrgInfoGenerator.js +76 -62
  67. package/lib/org/scratchOrgLifecycleEvents.d.ts +10 -0
  68. package/lib/org/scratchOrgLifecycleEvents.js +41 -0
  69. package/lib/org/scratchOrgSettingsGenerator.d.ts +44 -21
  70. package/lib/org/scratchOrgSettingsGenerator.js +165 -98
  71. package/lib/org/scratchOrgTypes.d.ts +43 -0
  72. package/lib/org/scratchOrgTypes.js +9 -0
  73. package/lib/org/user.d.ts +1 -1
  74. package/lib/org/user.js +25 -34
  75. package/lib/schema/printer.d.ts +6 -0
  76. package/lib/schema/printer.js +34 -31
  77. package/lib/schema/validator.d.ts +12 -10
  78. package/lib/schema/validator.js +56 -76
  79. package/lib/{sfdxError.d.ts → sfError.d.ts} +12 -20
  80. package/lib/{sfdxError.js → sfError.js} +40 -30
  81. package/lib/{sfdxProject.d.ts → sfProject.d.ts} +75 -35
  82. package/lib/sfProject.js +651 -0
  83. package/lib/{globalInfo → stateAggregator}/accessors/aliasAccessor.d.ts +27 -12
  84. package/lib/{globalInfo → stateAggregator}/accessors/aliasAccessor.js +47 -31
  85. package/lib/stateAggregator/accessors/orgAccessor.d.ts +101 -0
  86. package/lib/stateAggregator/accessors/orgAccessor.js +240 -0
  87. package/lib/stateAggregator/accessors/sandboxAccessor.d.ts +8 -0
  88. package/lib/stateAggregator/accessors/sandboxAccessor.js +28 -0
  89. package/lib/stateAggregator/accessors/tokenAccessor.d.ts +63 -0
  90. package/lib/stateAggregator/accessors/tokenAccessor.js +80 -0
  91. package/lib/stateAggregator/index.d.ts +4 -0
  92. package/lib/stateAggregator/index.js +27 -0
  93. package/lib/stateAggregator/stateAggregator.d.ts +25 -0
  94. package/lib/stateAggregator/stateAggregator.js +46 -0
  95. package/lib/status/myDomainResolver.d.ts +1 -1
  96. package/lib/status/myDomainResolver.js +4 -4
  97. package/lib/status/pollingClient.js +4 -4
  98. package/lib/status/streamingClient.d.ts +2 -2
  99. package/lib/status/streamingClient.js +58 -63
  100. package/lib/status/types.d.ts +2 -2
  101. package/lib/testSetup.d.ts +206 -75
  102. package/lib/testSetup.js +463 -165
  103. package/lib/util/cache.d.ts +2 -2
  104. package/lib/util/cache.js +6 -6
  105. package/lib/util/checkLightningDomain.js +3 -4
  106. package/lib/util/directoryWriter.d.ts +12 -0
  107. package/lib/util/directoryWriter.js +54 -0
  108. package/lib/util/getJwtAudienceUrl.js +1 -1
  109. package/lib/util/internal.d.ts +28 -2
  110. package/lib/util/internal.js +65 -8
  111. package/lib/util/jsonXmlTools.js +2 -4
  112. package/lib/util/mapKeys.d.ts +9 -9
  113. package/lib/util/mapKeys.js +13 -9
  114. package/lib/util/sfdc.d.ts +51 -51
  115. package/lib/util/sfdc.js +74 -79
  116. package/lib/util/sfdcUrl.d.ts +5 -19
  117. package/lib/util/sfdcUrl.js +40 -49
  118. package/lib/util/structuredWriter.d.ts +9 -0
  119. package/lib/util/structuredWriter.js +3 -0
  120. package/lib/util/zipWriter.d.ts +8 -6
  121. package/lib/util/zipWriter.js +13 -13
  122. package/lib/webOAuthServer.d.ts +20 -6
  123. package/lib/webOAuthServer.js +102 -56
  124. package/messageTransformer/messageTransformer.ts +93 -0
  125. package/messages/auth.md +9 -1
  126. package/messages/config.md +42 -6
  127. package/messages/connection.md +8 -0
  128. package/messages/core.md +10 -0
  129. package/messages/envVars.md +37 -3
  130. package/messages/org.md +21 -1
  131. package/messages/scratchOrgCreate.md +2 -6
  132. package/messages/scratchOrgErrorCodes.md +17 -1
  133. package/messages/scratchOrgInfoApi.md +9 -0
  134. package/messages/scratchOrgInfoGenerator.md +9 -1
  135. package/package.json +121 -46
  136. package/CHANGELOG.md +0 -1244
  137. package/lib/config/keychainConfig.d.ts +0 -19
  138. package/lib/config/keychainConfig.js +0 -43
  139. package/lib/globalInfo/accessors/orgAccessor.d.ts +0 -13
  140. package/lib/globalInfo/accessors/orgAccessor.js +0 -45
  141. package/lib/globalInfo/accessors/tokenAccessor.d.ts +0 -13
  142. package/lib/globalInfo/accessors/tokenAccessor.js +0 -35
  143. package/lib/globalInfo/globalInfoConfig.d.ts +0 -36
  144. package/lib/globalInfo/globalInfoConfig.js +0 -105
  145. package/lib/globalInfo/index.d.ts +0 -6
  146. package/lib/globalInfo/index.js +0 -29
  147. package/lib/globalInfo/sfdxDataHandler.d.ts +0 -43
  148. package/lib/globalInfo/sfdxDataHandler.js +0 -217
  149. package/lib/globalInfo/types.d.ts +0 -39
  150. package/lib/globalInfo/types.js +0 -10
  151. package/lib/sfdxProject.js +0 -557
  152. package/lib/util/fs.d.ts +0 -201
  153. package/lib/util/fs.js +0 -378
package/lib/logger.js CHANGED
@@ -11,14 +11,15 @@ const events_1 = require("events");
11
11
  const os = require("os");
12
12
  const path = require("path");
13
13
  const stream_1 = require("stream");
14
+ const fs = require("fs");
15
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
14
16
  // @ts-ignore
15
17
  const Bunyan = require("@salesforce/bunyan");
16
18
  const kit_1 = require("@salesforce/kit");
17
19
  const ts_types_1 = require("@salesforce/ts-types");
18
20
  const Debug = require("debug");
19
21
  const global_1 = require("./global");
20
- const sfdxError_1 = require("./sfdxError");
21
- const fs_1 = require("./util/fs");
22
+ const sfError_1 = require("./sfError");
22
23
  /**
23
24
  * Standard `Logger` levels.
24
25
  *
@@ -34,7 +35,7 @@ var LoggerLevel;
34
35
  LoggerLevel[LoggerLevel["FATAL"] = 60] = "FATAL";
35
36
  })(LoggerLevel = exports.LoggerLevel || (exports.LoggerLevel = {}));
36
37
  /**
37
- * `Logger` format types.
38
+ * `Logger` format types.
38
39
  */
39
40
  var LoggerFormat;
40
41
  (function (LoggerFormat) {
@@ -68,10 +69,21 @@ class Logger {
68
69
  *
69
70
  * @param optionsOrName A set of `LoggerOptions` or name to use with the default options.
70
71
  *
71
- * **Throws** *{@link SfdxError}{ name: 'RedundantRootLoggerError' }* More than one attempt is made to construct the root
72
+ * **Throws** *{@link SfError}{ name: 'RedundantRootLoggerError' }* More than one attempt is made to construct the root
72
73
  * `Logger`.
73
74
  */
74
75
  constructor(optionsOrName) {
76
+ /**
77
+ * The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
78
+ * See 'period' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
79
+ */
80
+ this.logRotationPeriod = new kit_1.Env().getString('SF_LOG_ROTATION_PERIOD') ?? '1d';
81
+ /**
82
+ * The number of backup rotated log files to keep.
83
+ * Example: '3' will have the base sf.log file, and the past 3 (period) log files.
84
+ * See 'count' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
85
+ */
86
+ this.logRotationCount = new kit_1.Env().getNumber('SF_LOG_ROTATION_COUNT') ?? 2;
75
87
  /**
76
88
  * Whether debug is enabled for this Logger.
77
89
  */
@@ -102,11 +114,11 @@ class Logger {
102
114
  options = optionsOrName;
103
115
  }
104
116
  if (Logger.rootLogger && options.name === Logger.ROOT_NAME) {
105
- throw new sfdxError_1.SfdxError('Can not create another root logger.', 'RedundantRootLoggerError');
117
+ throw new sfError_1.SfError('Can not create another root logger.', 'RedundantRootLoggerError');
106
118
  }
107
119
  // Inspect format to know what logging format to use then delete from options to
108
120
  // ensure it doesn't conflict with Bunyan.
109
- this.format = options.format || LoggerFormat.JSON;
121
+ this.format = options.format ?? LoggerFormat.JSON;
110
122
  delete options.format;
111
123
  // If the log format is LOGFMT, we need to convert any stream(s) into a LOGFMT type stream.
112
124
  if (this.format === LoggerFormat.LOGFMT && options.stream) {
@@ -127,7 +139,7 @@ class Logger {
127
139
  this.bunyan.streams = [];
128
140
  }
129
141
  // all SFDX loggers must filter sensitive data
130
- this.addFilter((...args) => _filter(...args));
142
+ this.addFilter((...args) => filterSecrets(...args));
131
143
  if (global_1.Global.getEnvironmentMode() !== global_1.Mode.TEST) {
132
144
  Logger.lifecycle.on('uncaughtException', this.uncaughtExceptionHandler);
133
145
  Logger.lifecycle.on('exit', this.exitHandler);
@@ -143,7 +155,8 @@ class Logger {
143
155
  }
144
156
  const rootLogger = (this.rootLogger = new Logger(Logger.ROOT_NAME).setLevel());
145
157
  // disable log file writing, if applicable
146
- if (process.env.SFDX_DISABLE_LOG_FILE !== 'true' && global_1.Global.getEnvironmentMode() !== global_1.Mode.TEST) {
158
+ const disableLogFile = new kit_1.Env().getString('SF_DISABLE_LOG_FILE');
159
+ if (disableLogFile !== 'true' && global_1.Global.getEnvironmentMode() !== global_1.Mode.TEST) {
147
160
  await rootLogger.addLogFileStream(global_1.Global.LOG_FILE_PATH);
148
161
  }
149
162
  rootLogger.enableDEBUG();
@@ -198,13 +211,13 @@ class Logger {
198
211
  *
199
212
  * @param {string} levelName The level name to convert to a `LoggerLevel` enum value.
200
213
  *
201
- * **Throws** *{@link SfdxError}{ name: 'UnrecognizedLoggerLevelNameError' }* The level name was not case-insensitively recognized as a valid `LoggerLevel` value.
214
+ * **Throws** *{@link SfError}{ name: 'UnrecognizedLoggerLevelNameError' }* The level name was not case-insensitively recognized as a valid `LoggerLevel` value.
202
215
  * @see {@Link LoggerLevel}
203
216
  */
204
217
  static getLevelByName(levelName) {
205
218
  levelName = levelName.toUpperCase();
206
219
  if (!(0, ts_types_1.isKeyOf)(LoggerLevel, levelName)) {
207
- throw new sfdxError_1.SfdxError(`Invalid log level "${levelName}".`, 'UnrecognizedLoggerLevelNameError');
220
+ throw new sfError_1.SfError(`Invalid log level "${levelName}".`, 'UnrecognizedLoggerLevelNameError');
208
221
  }
209
222
  return LoggerLevel[levelName];
210
223
  }
@@ -228,34 +241,37 @@ class Logger {
228
241
  async addLogFileStream(logFile) {
229
242
  try {
230
243
  // Check if we have write access to the log file (i.e., we created it already)
231
- await fs_1.fs.access(logFile, fs_1.fs.constants.W_OK);
244
+ await fs.promises.access(logFile, fs.constants.W_OK);
232
245
  }
233
246
  catch (err1) {
234
247
  try {
235
- await fs_1.fs.mkdirp(path.dirname(logFile), {
236
- mode: fs_1.fs.DEFAULT_USER_DIR_MODE,
237
- });
248
+ if (process.platform === 'win32') {
249
+ await fs.promises.mkdir(path.dirname(logFile), { recursive: true });
250
+ }
251
+ else {
252
+ await fs.promises.mkdir(path.dirname(logFile), { recursive: true, mode: 0o700 });
253
+ }
238
254
  }
239
255
  catch (err2) {
240
- // noop; directory exists already
256
+ throw sfError_1.SfError.wrap(err2);
241
257
  }
242
258
  try {
243
- await fs_1.fs.writeFile(logFile, '', { mode: fs_1.fs.DEFAULT_USER_FILE_MODE });
259
+ await fs.promises.writeFile(logFile, '', { mode: '600' });
244
260
  }
245
261
  catch (err3) {
246
- throw sfdxError_1.SfdxError.wrap(err3);
262
+ throw sfError_1.SfError.wrap(err3);
247
263
  }
248
264
  }
249
265
  // avoid multiple streams to same log file
250
266
  if (!this.bunyan.streams.find(
251
267
  // No bunyan typings
252
268
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
253
- (stream) => stream.type === 'file' && stream.path === logFile)) {
254
- // TODO: rotating-file
255
- // https://github.com/trentm/node-bunyan#stream-type-rotating-file
269
+ (stream) => stream.type === 'rotating-file' && stream.path === logFile)) {
256
270
  this.addStream({
257
- type: 'file',
271
+ type: 'rotating-file',
258
272
  path: logFile,
273
+ period: this.logRotationPeriod,
274
+ count: this.logRotationCount,
259
275
  level: this.bunyan.level(),
260
276
  });
261
277
  }
@@ -268,34 +284,37 @@ class Logger {
268
284
  addLogFileStreamSync(logFile) {
269
285
  try {
270
286
  // Check if we have write access to the log file (i.e., we created it already)
271
- fs_1.fs.accessSync(logFile, fs_1.fs.constants.W_OK);
287
+ fs.accessSync(logFile, fs.constants.W_OK);
272
288
  }
273
289
  catch (err1) {
274
290
  try {
275
- fs_1.fs.mkdirpSync(path.dirname(logFile), {
276
- mode: fs_1.fs.DEFAULT_USER_DIR_MODE,
277
- });
291
+ if (process.platform === 'win32') {
292
+ fs.mkdirSync(path.dirname(logFile), { recursive: true });
293
+ }
294
+ else {
295
+ fs.mkdirSync(path.dirname(logFile), { recursive: true, mode: 0o700 });
296
+ }
278
297
  }
279
298
  catch (err2) {
280
- // noop; directory exists already
299
+ throw sfError_1.SfError.wrap(err2);
281
300
  }
282
301
  try {
283
- fs_1.fs.writeFileSync(logFile, '', { mode: fs_1.fs.DEFAULT_USER_FILE_MODE });
302
+ fs.writeFileSync(logFile, '', { mode: '600' });
284
303
  }
285
304
  catch (err3) {
286
- throw sfdxError_1.SfdxError.wrap(err3);
305
+ throw sfError_1.SfError.wrap(err3);
287
306
  }
288
307
  }
289
308
  // avoid multiple streams to same log file
290
309
  if (!this.bunyan.streams.find(
291
310
  // No bunyan typings
292
311
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
293
- (stream) => stream.type === 'file' && stream.path === logFile)) {
294
- // TODO: rotating-file
295
- // https://github.com/trentm/node-bunyan#stream-type-rotating-file
312
+ (stream) => stream.type === 'rotating-file' && stream.path === logFile)) {
296
313
  this.addStream({
297
- type: 'file',
314
+ type: 'rotating-file',
298
315
  path: logFile,
316
+ period: this.logRotationPeriod,
317
+ count: this.logRotationCount,
299
318
  level: this.bunyan.level(),
300
319
  });
301
320
  }
@@ -319,7 +338,7 @@ class Logger {
319
338
  *
320
339
  * @param {LoggerLevelValue} [level] The logger level.
321
340
  *
322
- * **Throws** *{@link SfdxError}{ name: 'UnrecognizedLoggerLevelNameError' }* A value of `level` read from `SFDX_LOG_LEVEL`
341
+ * **Throws** *{@link SfError}{ name: 'UnrecognizedLoggerLevelNameError' }* A value of `level` read from `SFDX_LOG_LEVEL`
323
342
  * was invalid.
324
343
  *
325
344
  * ```
@@ -335,7 +354,8 @@ class Logger {
335
354
  */
336
355
  setLevel(level) {
337
356
  if (level == null) {
338
- level = process.env.SFDX_LOG_LEVEL ? Logger.getLevelByName(process.env.SFDX_LOG_LEVEL) : Logger.DEFAULT_LEVEL;
357
+ const logLevelFromEnvVar = new kit_1.Env().getString('SF_LOG_LEVEL');
358
+ level = logLevelFromEnvVar ? Logger.getLevelByName(logLevelFromEnvVar) : Logger.DEFAULT_LEVEL;
339
359
  }
340
360
  this.bunyan.level(level);
341
361
  return this;
@@ -343,7 +363,9 @@ class Logger {
343
363
  /**
344
364
  * Gets the underlying Bunyan logger.
345
365
  */
346
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
366
+ // leave this typed as any to keep if from trying to export the type from the untyped bunyan module
367
+ // this prevents consumers from getting node_modules/@salesforce/core/lib/logger.d.ts:281:24 - error TS2304: Cannot find name 'Bunyan'.
368
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
347
369
  getBunyanLogger() {
348
370
  return this.bunyan;
349
371
  }
@@ -400,7 +422,8 @@ class Logger {
400
422
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
401
423
  this.bunyan.streams.forEach(async (stream) => {
402
424
  if (stream.type === 'file') {
403
- content += await fs_1.fs.readFile(stream.path, 'utf8');
425
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
426
+ content += await fs.promises.readFile(stream.path, 'utf8');
404
427
  }
405
428
  });
406
429
  return content;
@@ -412,7 +435,6 @@ class Logger {
412
435
  * @param filter A function with signature `(...args: any[]) => any[]` that transforms log message arguments.
413
436
  */
414
437
  addFilter(filter) {
415
- // eslint disable-line @typescript-eslint/no-explicit-any
416
438
  if (!this.bunyan.filters) {
417
439
  this.bunyan.filters = [];
418
440
  }
@@ -421,8 +443,7 @@ class Logger {
421
443
  /**
422
444
  * Close the logger, including any streams, and remove all listeners.
423
445
  *
424
- * @param fn A function with signature `(stream: LoggerStream) => void` to call for each stream with
425
- * the stream as an arg.
446
+ * @param fn A function with signature `(stream: LoggerStream) => void` to call for each stream with the stream as an arg.
426
447
  */
427
448
  close(fn) {
428
449
  if (this.bunyan.streams) {
@@ -452,7 +473,7 @@ class Logger {
452
473
  */
453
474
  child(name, fields = {}) {
454
475
  if (!name) {
455
- throw new sfdxError_1.SfdxError('LoggerNameRequired');
476
+ throw new sfError_1.SfError('LoggerNameRequired');
456
477
  }
457
478
  fields.log = name;
458
479
  const child = new Logger(name);
@@ -480,6 +501,7 @@ class Logger {
480
501
  */
481
502
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
482
503
  trace(...args) {
504
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
483
505
  this.bunyan.trace(this.applyFilters(LoggerLevel.TRACE, ...args));
484
506
  return this;
485
507
  }
@@ -542,8 +564,10 @@ class Logger {
542
564
  */
543
565
  fatal(...args) {
544
566
  // always show fatal to stderr
545
- // eslint-disable-next-line no-console
546
- console.error(...args);
567
+ // IMPORTANT:
568
+ // Do not use console.error() here, if fatal() is called from the uncaughtException handler, it
569
+ // will be re-thrown and caught again by the uncaughtException handler, causing an infinite loop.
570
+ console.log(...args); // eslint-disable-line no-console
547
571
  this.bunyan.fatal(this.applyFilters(LoggerLevel.FATAL, ...args));
548
572
  return this;
549
573
  }
@@ -561,6 +585,7 @@ class Logger {
561
585
  stream: new stream_1.Writable({
562
586
  write: (chunk, encoding, next) => {
563
587
  try {
588
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
564
589
  const json = (0, kit_1.parseJsonMap)(chunk.toString());
565
590
  const logLevel = (0, ts_types_1.ensureNumber)(json.level);
566
591
  if (this.getLevel() <= logLevel) {
@@ -595,11 +620,14 @@ class Logger {
595
620
  }
596
621
  return args && args.length === 1 ? args[0] : args;
597
622
  }
623
+ // eslint-disable-next-line class-methods-use-this
598
624
  createLogFmtFormatterStream(loggerStream) {
599
625
  const logFmtWriteableStream = new stream_1.Writable({
600
626
  write: (chunk, enc, cb) => {
601
627
  try {
628
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
602
629
  const parsedJSON = JSON.parse(chunk.toString());
630
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
603
631
  const keys = Object.keys(parsedJSON);
604
632
  let logEntry = '';
605
633
  keys.forEach((key) => {
@@ -662,50 +690,48 @@ const FILTERED_KEYS = [
662
690
  { name: 'sfdxauthurl', regex: 'sfdx[^\'"]*auth[^\'"]*url' },
663
691
  ];
664
692
  // SFDX code and plugins should never show tokens or connect app information in the logs
665
- const _filter = (...args) => {
666
- return args.map((arg) => {
667
- if ((0, ts_types_1.isArray)(arg)) {
668
- return _filter(...arg);
669
- }
670
- if (arg) {
671
- let _arg;
672
- // Normalize all objects into a string. This include errors.
673
- if (arg instanceof Buffer) {
674
- _arg = '<Buffer>';
675
- }
676
- else if ((0, ts_types_1.isObject)(arg)) {
677
- _arg = JSON.stringify(arg);
678
- }
679
- else if ((0, ts_types_1.isString)(arg)) {
680
- _arg = arg;
681
- }
682
- else {
683
- _arg = '';
684
- }
685
- const HIDDEN = 'HIDDEN';
686
- FILTERED_KEYS.forEach((key) => {
687
- let expElement = key;
688
- let expName = key;
689
- // Filtered keys can be strings or objects containing regular expression components.
690
- if ((0, ts_types_1.isPlainObject)(key)) {
691
- expElement = key.regex;
692
- expName = key.name;
693
- }
694
- const hiddenAttrMessage = `"<${expName} - ${HIDDEN}>"`;
695
- // Match all json attribute values case insensitive: ex. {" Access*^&(*()^* Token " : " 45143075913458901348905 \n\t" ...}
696
- const regexTokens = new RegExp(`(['"][^'"]*${expElement}[^'"]*['"]\\s*:\\s*)['"][^'"]*['"]`, 'gi');
697
- _arg = _arg.replace(regexTokens, `$1${hiddenAttrMessage}`);
698
- // Match all key value attribute case insensitive: ex. {" key\t" : ' access_token ' , " value " : " dsafgasr431 " ....}
699
- const keyRegex = new RegExp(`(['"]\\s*key\\s*['"]\\s*:)\\s*['"]\\s*${expElement}\\s*['"]\\s*.\\s*['"]\\s*value\\s*['"]\\s*:\\s*['"]\\s*[^'"]*['"]`, 'gi');
700
- _arg = _arg.replace(keyRegex, `$1${hiddenAttrMessage}`);
701
- });
702
- _arg = _arg.replace(/(00D\w{12,15})![.\w]*/, `<${HIDDEN}>`);
703
- // return an object if an object was logged; otherwise return the filtered string.
704
- return (0, ts_types_1.isObject)(arg) ? (0, kit_1.parseJson)(_arg) : _arg;
693
+ const filterSecrets = (...args) => args.map((arg) => {
694
+ if ((0, ts_types_1.isArray)(arg)) {
695
+ return filterSecrets(...arg);
696
+ }
697
+ if (arg) {
698
+ let mutableArg;
699
+ // Normalize all objects into a string. This includes errors.
700
+ if (arg instanceof Buffer) {
701
+ mutableArg = '<Buffer>';
705
702
  }
706
- else {
707
- return arg;
703
+ else if ((0, ts_types_1.isObject)(arg)) {
704
+ mutableArg = JSON.stringify(arg);
708
705
  }
709
- });
710
- };
706
+ else if ((0, ts_types_1.isString)(arg)) {
707
+ mutableArg = arg;
708
+ }
709
+ else {
710
+ mutableArg = '';
711
+ }
712
+ const HIDDEN = 'HIDDEN';
713
+ FILTERED_KEYS.forEach((key) => {
714
+ let expElement = key;
715
+ let expName = key;
716
+ // Filtered keys can be strings or objects containing regular expression components.
717
+ if ((0, ts_types_1.isPlainObject)(key)) {
718
+ expElement = key.regex;
719
+ expName = key.name;
720
+ }
721
+ const hiddenAttrMessage = `"<${expName} - ${HIDDEN}>"`;
722
+ // Match all json attribute values case insensitive: ex. {" Access*^&(*()^* Token " : " 45143075913458901348905 \n\t" ...}
723
+ const regexTokens = new RegExp(`(['"][^'"]*${expElement}[^'"]*['"]\\s*:\\s*)['"][^'"]*['"]`, 'gi');
724
+ mutableArg = mutableArg.replace(regexTokens, `$1${hiddenAttrMessage}`);
725
+ // Match all key value attribute case insensitive: ex. {" key\t" : ' access_token ' , " value " : " dsafgasr431 " ....}
726
+ const keyRegex = new RegExp(`(['"]\\s*key\\s*['"]\\s*:)\\s*['"]\\s*${expElement}\\s*['"]\\s*.\\s*['"]\\s*value\\s*['"]\\s*:\\s*['"]\\s*[^'"]*['"]`, 'gi');
727
+ mutableArg = mutableArg.replace(keyRegex, `$1${hiddenAttrMessage}`);
728
+ });
729
+ mutableArg = mutableArg.replace(/(00D\w{12,15})![.\w]*/, `<${HIDDEN}>`);
730
+ // return an object if an object was logged; otherwise return the filtered string.
731
+ return (0, ts_types_1.isObject)(arg) ? (0, kit_1.parseJson)(mutableArg) : mutableArg;
732
+ }
733
+ else {
734
+ return arg;
735
+ }
736
+ });
711
737
  //# sourceMappingURL=logger.js.map
package/lib/messages.d.ts CHANGED
@@ -1,16 +1,21 @@
1
1
  import { AnyJson } from '@salesforce/ts-types';
2
- import { SfdxError } from './sfdxError';
3
- export declare type Tokens = Array<string | boolean | number | null | undefined>;
2
+ import { SfError } from './sfError';
3
+ export type Tokens = Array<string | boolean | number | null | undefined>;
4
+ export type StructuredMessage = {
5
+ message: string;
6
+ name: string;
7
+ actions?: string[];
8
+ };
4
9
  /**
5
10
  * A loader function to return messages.
6
11
  *
7
12
  * @param locale The local set by the framework.
8
13
  */
9
- export declare type LoaderFunction<T extends string> = (locale: string) => Messages<T>;
10
- export declare type StoredMessage = string | string[] | {
14
+ export type LoaderFunction<T extends string> = (locale: string) => Messages<T>;
15
+ export type StoredMessage = string | string[] | {
11
16
  [s: string]: StoredMessage;
12
17
  };
13
- export declare type StoredMessageMap = Map<string, StoredMessage>;
18
+ export type StoredMessageMap = Map<string, StoredMessage>;
14
19
  /**
15
20
  * The core message framework manages messages and allows them to be accessible by
16
21
  * all plugins and consumers of sfdx-core. It is set up to handle localization down
@@ -75,14 +80,14 @@ export declare type StoredMessageMap = Map<string, StoredMessage>;
75
80
  *
76
81
  * // Now you can use the messages from anywhere in your code or file.
77
82
  * // If using importMessageDirectory, the bundle name is the file name.
78
- * const messages: Messages = Messages.load(packageName, bundleName);
83
+ * const messages: Messages = Messages.loadMessages(packageName, bundleName);
79
84
  *
80
85
  * // Messages now contains all the message in the bundleName file.
81
86
  * messages.getMessage('authInfoCreationError');
82
87
  * ```
83
88
  */
84
89
  export declare class Messages<T extends string> {
85
- private messages;
90
+ readonly messages: StoredMessageMap;
86
91
  private static loaders;
87
92
  private static bundles;
88
93
  /**
@@ -96,7 +101,7 @@ export declare class Messages<T extends string> {
96
101
  /**
97
102
  * Create a new messages bundle.
98
103
  *
99
- * **Note:** Use {Messages.load} unless you are writing your own loader function.
104
+ * **Note:** Use {Messages.loadMessages} unless you are writing your own loader function.
100
105
  *
101
106
  * @param bundleName The bundle name.
102
107
  * @param locale The locale.
@@ -117,7 +122,7 @@ export declare class Messages<T extends string> {
117
122
  */
118
123
  static getLocale(): string;
119
124
  /**
120
- * Set a custom loader function for a package and bundle that will be called on {@link Messages.load}.
125
+ * Set a custom loader function for a package and bundle that will be called on {@link Messages.loadMessages}.
121
126
  *
122
127
  * @param packageName The npm package name.
123
128
  * @param bundle The name of the bundle.
@@ -143,7 +148,7 @@ export declare class Messages<T extends string> {
143
148
  static importMessageFile(packageName: string, filePath: string): void;
144
149
  /**
145
150
  * Import all json and js files in a messages directory. Use the file name as the bundle key when
146
- * {@link Messages.load} is called. By default, we're assuming the moduleDirectoryPart is a
151
+ * {@link Messages.loadMessages} is called. By default, we're assuming the moduleDirectoryPart is a
147
152
  * typescript project and will truncate to root path (where the package.json file is). If your messages
148
153
  * directory is in another spot or you are not using typescript, pass in false for truncateToProjectPath.
149
154
  *
@@ -162,38 +167,15 @@ export declare class Messages<T extends string> {
162
167
  * Load messages for a given package and bundle. If the bundle is not already cached, use the loader function
163
168
  * created from {@link Messages.setLoaderFunction} or {@link Messages.importMessagesDirectory}.
164
169
  *
165
- * **NOTE: Use {@link Messages.load} instead for safe message validation and usage.**
166
- *
167
170
  * ```typescript
168
171
  * Messages.importMessagesDirectory(__dirname);
169
- * const messages = Messages.load('packageName', 'bundleName');
172
+ * const messages = Messages.loadMessages('packageName', 'bundleName');
170
173
  * ```
171
174
  *
172
175
  * @param packageName The name of the npm package.
173
176
  * @param bundleName The name of the bundle to load.
174
177
  */
175
178
  static loadMessages(packageName: string, bundleName: string): Messages<string>;
176
- /**
177
- * Load messages for a given package and bundle. If the bundle is not already cached, use the loader function
178
- * created from {@link Messages.setLoaderFunction} or {@link Messages.importMessagesDirectory}.
179
- *
180
- * The message keys that will be used must be passed in for validation. This prevents runtime errors if messages are used but not defined.
181
- *
182
- * **NOTE: This should be defined at the top of the file so validation is done at load time rather than runtime.**
183
- *
184
- * ```typescript
185
- * Messages.importMessagesDirectory(__dirname);
186
- * const messages = Messages.load('packageName', 'bundleName', [
187
- * 'messageKey1',
188
- * 'messageKey2',
189
- * ]);
190
- * ```
191
- *
192
- * @param packageName The name of the npm package.
193
- * @param bundleName The name of the bundle to load.
194
- * @param keys The message keys that will be used.
195
- */
196
- static load<T extends string>(packageName: string, bundleName: string, keys: [T, ...T[]]): Messages<T>;
197
179
  /**
198
180
  * Check if a bundle already been loaded.
199
181
  *
@@ -244,9 +226,44 @@ export declare class Messages<T extends string> {
244
226
  * @param key The key of the error message.
245
227
  * @param tokens The error message tokens.
246
228
  * @param actionTokens The action messages tokens.
247
- * @param exitCodeOrCause The exit code which will be used by SfdxCommand or he underlying error that caused this error to be raised.
229
+ * @param exitCodeOrCause The exit code which will be used by SfdxCommand or the underlying error that caused this error to be raised.
248
230
  * @param cause The underlying error that caused this error to be raised.
249
231
  */
250
- createError(key: T, tokens?: Tokens, actionTokens?: Tokens, exitCodeOrCause?: number | Error, cause?: Error): SfdxError;
232
+ createError(key: T, tokens?: Tokens, actionTokens?: Tokens, exitCodeOrCause?: number | Error, cause?: Error): SfError;
233
+ /**
234
+ * Convenience method to create warning using message labels.
235
+ *
236
+ * `warning.name` will be the upper-cased key, remove prefixed `warning.` and will always end in Warning.
237
+ * `warning.actions` will be loaded using `${key}.actions` if available.
238
+ *
239
+ * @param key The key of the warning message.
240
+ * @param tokens The warning message tokens.
241
+ * @param actionTokens The action messages tokens.
242
+ */
243
+ createWarning(key: T, tokens?: Tokens, actionTokens?: Tokens): StructuredMessage;
244
+ /**
245
+ * Convenience method to create info using message labels.
246
+ *
247
+ * `info.name` will be the upper-cased key, remove prefixed `info.` and will always end in Info.
248
+ * `info.actions` will be loaded using `${key}.actions` if available.
249
+ *
250
+ * @param key The key of the warning message.
251
+ * @param tokens The warning message tokens.
252
+ * @param actionTokens The action messages tokens.
253
+ */
254
+ createInfo(key: T, tokens?: Tokens, actionTokens?: Tokens): StructuredMessage;
255
+ /**
256
+ * Formats message contents given a message type, key, tokens and actions tokens
257
+ *
258
+ * `<type>.name` will be the upper-cased key, remove prefixed `<type>.` and will always end in 'Error | Warning | Info.
259
+ * `<type>.actions` will be loaded using `${key}.actions` if available.
260
+ *
261
+ * @param type The type of the message set must 'error' | 'warning' | 'info'.
262
+ * @param key The key of the warning message.
263
+ * @param tokens The warning message tokens.
264
+ * @param actionTokens The action messages tokens.
265
+ * @param preserveName Do not require that the name end in the type ('error' | 'warning' | 'info').
266
+ */
267
+ private formatMessageContents;
251
268
  private getMessageWithMap;
252
269
  }