@inforge/migrations-tools-cli 1.1.1 → 1.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 (3) hide show
  1. package/README.md +29 -0
  2. package/dist/index.js +98 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -103,6 +103,35 @@ Select "Logs" to see recent operations with status, timestamps, and details.
103
103
 
104
104
  All operations are logged to `.logs/operations.log` (JSON format, one per line).
105
105
 
106
+ ## Debugging
107
+
108
+ ### Debug Logs
109
+
110
+ When errors occur, detailed error information including stack traces and API request/response data is automatically logged to `.logs/debug.log`. The error message will show you the exact path to the debug log file.
111
+
112
+ **Example error message:**
113
+ ```
114
+ Failed to apply changes: The requested resource does not exist
115
+
116
+ Error details logged to: /path/to/your/project/.logs/debug.log
117
+ ```
118
+
119
+ ### Enable Verbose Debug Logging
120
+
121
+ For more detailed troubleshooting, enable debug mode to see all API calls and internal operations:
122
+
123
+ ```bash
124
+ DEBUG=true imigrate
125
+ ```
126
+
127
+ This will log detailed information about:
128
+ - API queries and their results
129
+ - Request/response payloads
130
+ - Internal state changes
131
+ - Detailed error contexts
132
+
133
+ Debug logs are written in JSON format with timestamps and structured context for easy analysis.
134
+
106
135
  ## Safety Features
107
136
 
108
137
  ### Atomic Operations
package/dist/index.js CHANGED
@@ -248,12 +248,15 @@ var BackupManager = class {
248
248
  // src/core/logger.ts
249
249
  import * as fs2 from "fs/promises";
250
250
  import * as path2 from "path";
251
- var Logger = class {
251
+ var Logger = class _Logger {
252
252
  logDir;
253
253
  logFile;
254
+ debugLogFile;
255
+ static debugEnabled = process.env.DEBUG === "true";
254
256
  constructor(logDir = ".logs") {
255
257
  this.logDir = logDir;
256
258
  this.logFile = path2.join(logDir, "operations.log");
259
+ this.debugLogFile = path2.join(logDir, "debug.log");
257
260
  }
258
261
  async log(operation) {
259
262
  await this.ensureLogDir();
@@ -277,6 +280,38 @@ var Logger = class {
277
280
  const random = Math.random().toString(36).substring(2, 9);
278
281
  return `op_${timestamp}${random}`;
279
282
  }
283
+ async debug(message, context) {
284
+ await this.writeDebugLog("DEBUG", message, context);
285
+ }
286
+ async info(message, context) {
287
+ await this.writeDebugLog("INFO", message, context);
288
+ }
289
+ async error(message, error, context) {
290
+ const errorDetails = error ? {
291
+ message: error.message || String(error),
292
+ stack: error.stack,
293
+ details: error.response?.data || error.details || error
294
+ } : void 0;
295
+ await this.writeDebugLog("ERROR", message, context, errorDetails);
296
+ }
297
+ getDebugLogPath() {
298
+ return path2.resolve(this.debugLogFile);
299
+ }
300
+ async writeDebugLog(level, message, context, error) {
301
+ if (!_Logger.debugEnabled && level === "DEBUG") {
302
+ return;
303
+ }
304
+ await this.ensureLogDir();
305
+ const entry = {
306
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
307
+ level,
308
+ message,
309
+ ...context && { context },
310
+ ...error && { error }
311
+ };
312
+ const logLine = JSON.stringify(entry, null, 2) + "\n---\n";
313
+ await fs2.appendFile(this.debugLogFile, logLine, "utf-8");
314
+ }
280
315
  async ensureLogDir() {
281
316
  try {
282
317
  await fs2.mkdir(this.logDir, { recursive: true });
@@ -427,6 +462,10 @@ var FlowsHandler = class {
427
462
 
428
463
  // src/core/metadata/triggers.ts
429
464
  var TriggersHandler = class {
465
+ logger;
466
+ constructor() {
467
+ this.logger = new Logger();
468
+ }
430
469
  async fetch(connection, objectName) {
431
470
  const query = `
432
471
  SELECT Id, Name, TableEnumOrId, Status, NamespacePrefix
@@ -465,25 +504,58 @@ var TriggersHandler = class {
465
504
  await this.updateStatus(connection, triggerNames, "Active");
466
505
  }
467
506
  async updateStatus(connection, triggerNames, status) {
507
+ await this.logger.debug("TriggersHandler.updateStatus called", {
508
+ triggerNames,
509
+ status
510
+ });
468
511
  const query = `
469
512
  SELECT Id, Name
470
513
  FROM ApexTrigger
471
514
  WHERE Name IN (${triggerNames.map((n) => `'${n}'`).join(", ")})
472
515
  `;
473
- const result = await connection.tooling.query(query);
474
- if (result.records.length === 0) {
475
- throw new Error("No triggers found with the specified names");
476
- }
477
- const updates = result.records.map((trigger) => ({
478
- Id: trigger.Id,
479
- Status: status
480
- }));
481
- const results = await connection.tooling.update("ApexTrigger", updates);
482
- if (Array.isArray(results)) {
483
- const failures = results.filter((r) => !r.success);
484
- if (failures.length > 0) {
485
- throw new Error(`Failed to update ${failures.length} trigger(s)`);
516
+ await this.logger.debug("Executing Tooling API query", { query });
517
+ try {
518
+ const result = await connection.tooling.query(query);
519
+ await this.logger.debug("Query result", {
520
+ recordCount: result.records.length,
521
+ records: result.records
522
+ });
523
+ if (result.records.length === 0) {
524
+ await this.logger.error("No triggers found with specified names", null, {
525
+ triggerNames,
526
+ query
527
+ });
528
+ throw new Error("No triggers found with the specified names");
486
529
  }
530
+ const updates = result.records.map((trigger) => ({
531
+ Id: trigger.Id,
532
+ Status: status
533
+ }));
534
+ await this.logger.debug("Preparing Tooling API update", { updates });
535
+ const results = await connection.tooling.update("ApexTrigger", updates);
536
+ await this.logger.debug("Tooling API update results", {
537
+ results: Array.isArray(results) ? results : [results]
538
+ });
539
+ if (Array.isArray(results)) {
540
+ const failures = results.filter((r) => !r.success);
541
+ if (failures.length > 0) {
542
+ await this.logger.error("Some triggers failed to update", null, {
543
+ failures,
544
+ totalAttempted: results.length
545
+ });
546
+ throw new Error(`Failed to update ${failures.length} trigger(s): ${JSON.stringify(failures)}`);
547
+ }
548
+ }
549
+ await this.logger.info("Successfully updated trigger status", {
550
+ triggerCount: triggerNames.length,
551
+ status
552
+ });
553
+ } catch (error) {
554
+ await this.logger.error("Error in updateStatus", error, {
555
+ triggerNames,
556
+ status
557
+ });
558
+ throw error;
487
559
  }
488
560
  }
489
561
  };
@@ -1199,6 +1271,14 @@ Select items to toggle (Space to select, Enter to continue):`,
1199
1271
  );
1200
1272
  } catch (error) {
1201
1273
  applySpinner.stop("Changes failed");
1274
+ await this.logger.error("Failed to apply changes in IndividualCommand", error, {
1275
+ org: org.alias,
1276
+ object: selectedObject,
1277
+ automationType,
1278
+ selectedFullNames,
1279
+ toActivate,
1280
+ toDeactivate
1281
+ });
1202
1282
  await this.logger.log({
1203
1283
  id: operationId,
1204
1284
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1212,7 +1292,10 @@ Select items to toggle (Space to select, Enter to continue):`,
1212
1292
  backupPath,
1213
1293
  error: error.message
1214
1294
  });
1215
- this.prompts.error(`Failed to apply changes: ${error.message}`);
1295
+ const debugLogPath = this.logger.getDebugLogPath();
1296
+ this.prompts.error(`Failed to apply changes: ${error.message}
1297
+
1298
+ Error details logged to: ${debugLogPath}`);
1216
1299
  throw error;
1217
1300
  }
1218
1301
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inforge/migrations-tools-cli",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Inforge's interactive CLI for side-effect-free Salesforce data operations by managing automation",
5
5
  "main": "index.js",
6
6
  "type": "module",