@peernova/cuneiform-sf 1.0.2 → 1.0.3-beta.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.
@@ -0,0 +1,197 @@
1
+ /*
2
+ * Copyright (c) 2026, PeerNova Inc. All rights reserved.
3
+ * SPDX-License-Identifier: BSD-3-Clause
4
+ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ import { SfError } from '@salesforce/core';
9
+ /**
10
+ * Error codes specific to export operations.
11
+ */
12
+ export const ExportErrorCodes = {
13
+ /** Output directory already exists */
14
+ OUTPUT_DIR_EXISTS: 'EXPORT_OUTPUT_DIR_EXISTS',
15
+ /** No definitions found in org */
16
+ NO_DEFINITIONS_FOUND: 'EXPORT_NO_DEFINITIONS_FOUND',
17
+ /** Failed to create output directory */
18
+ DIR_CREATION_FAILED: 'EXPORT_DIR_CREATION_FAILED',
19
+ /** Failed to write config file */
20
+ CONFIG_WRITE_FAILED: 'EXPORT_CONFIG_WRITE_FAILED',
21
+ };
22
+ /**
23
+ * Orchestrates the export of profiling definitions using SFDMU.
24
+ *
25
+ * Follows the 4-layer architecture: Command → Operation → Service → API
26
+ * This operation layer handles business logic orchestration while delegating
27
+ * the actual SFDMU execution to SFDMUService.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const operation = new DefinitionExportOperation(sfdmuService);
32
+ * const result = await operation.execute({
33
+ * targetOrg: 'myOrg',
34
+ * outputDir: './exports',
35
+ * excludeIds: true
36
+ * });
37
+ * ```
38
+ */
39
+ export class DefinitionExportOperation {
40
+ /** Default base path for exports */
41
+ static DEFAULT_EXPORT_BASE = './data/exports/definitions';
42
+ /** SFDMU query for profiling definitions */
43
+ static DEFINITION_QUERY = 'SELECT Id, Name, RecordTypeId, pnova__Agg_Status__c, pnova__Agg_StatusStatistical__c, pnova__Aud_VersionCRMBase__c, pnova__Aud_VersionCRMEnterprise__c, pnova__Aud_VersionDCBase__c, pnova__Profiling_IsProfileForAllFields__c, pnova__Profiling_IsProfileForAllRecords__c, pnova__Prop_Category__c, pnova__Prop_Description__c, pnova__Prop_Filter_JSON_SetA__c, pnova__Prop_Filter_JSON_SetB__c, pnova__Prop_Filter_SetA__c, pnova__Prop_Filter_SetB__c, pnova__Prop_InsightGroups_JSON__c, pnova__Prop_IsActive__c, pnova__Prop_IsFiltered_SetA__c, pnova__Prop_IsFiltered_SetB__c, pnova__Prop_IsNotificationEnabled__c, pnova__Prop_IsProfilingLaunchedFromWizard__c, pnova__Prop_KpiBusinessImpact__c, pnova__Prop_KpiBusinessImpact_JSON__c, pnova__Prop_KpiDataQuality__c, pnova__Prop_KpiDataQuality_JSON__c, pnova__Prop_AreKpisDefined__c, pnova__Prop_LicenseViolations__c, pnova__Prop_Name__c, pnova__Prop_SelectedFields__c, pnova__Prop_SelectedFields_JSON__c, pnova__Prop_SelectedFieldsCount__c, pnova__Prop_SObjectApiName__c, pnova__Prop_SObjectFullApiName__c, pnova__Prop_SObjectLabel__c, pnova__Prop_SObjectRecordTypeId__c, pnova__Prop_SObjectRecordTypeLabel__c FROM pnova__Profiling_Definition__c';
44
+ sfdmuService;
45
+ logger;
46
+ /**
47
+ * Creates a new DefinitionExportOperation.
48
+ *
49
+ * @param sfdmuService - The SFDMU service instance for executing operations
50
+ * @param logger - Optional logger for debug output
51
+ */
52
+ constructor(sfdmuService, logger) {
53
+ this.sfdmuService = sfdmuService;
54
+ this.logger = logger;
55
+ }
56
+ /**
57
+ * Resolves the output path, generating a timestamped directory if needed.
58
+ */
59
+ static resolveOutputPath(outputDir) {
60
+ if (outputDir) {
61
+ return path.resolve(outputDir);
62
+ }
63
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
64
+ return path.resolve(DefinitionExportOperation.DEFAULT_EXPORT_BASE, timestamp);
65
+ }
66
+ /**
67
+ * Builds the SFDMU export configuration.
68
+ */
69
+ static buildSFDMUConfig(excludeIds) {
70
+ const config = {
71
+ objects: [
72
+ {
73
+ query: DefinitionExportOperation.DEFINITION_QUERY,
74
+ operation: 'Readonly',
75
+ externalId: 'Name',
76
+ },
77
+ ],
78
+ };
79
+ if (excludeIds) {
80
+ config.excludeIdsFromCSVFiles = true;
81
+ }
82
+ return config;
83
+ }
84
+ /**
85
+ * Collects the list of files created by SFDMU export.
86
+ */
87
+ static collectExportedFiles(outputPath) {
88
+ try {
89
+ return fs.readdirSync(outputPath).filter((file) => !file.startsWith('.'));
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ }
95
+ /**
96
+ * Executes the export operation.
97
+ *
98
+ * @param options - Export options
99
+ * @returns ServiceResult containing export results or error details
100
+ */
101
+ async execute(options) {
102
+ const startTime = Date.now();
103
+ try {
104
+ // Generate timestamped output directory
105
+ const outputPath = DefinitionExportOperation.resolveOutputPath(options.outputDir);
106
+ // Verify output directory doesn't exist (prevent accidental overwrite)
107
+ if (fs.existsSync(outputPath)) {
108
+ return {
109
+ success: false,
110
+ data: {
111
+ definitionsExported: 0,
112
+ outputPath,
113
+ files: [],
114
+ },
115
+ errorCode: ExportErrorCodes.OUTPUT_DIR_EXISTS,
116
+ message: `Output directory already exists: ${outputPath}. Use a different path or remove existing directory.`,
117
+ };
118
+ }
119
+ // Create output directory
120
+ this.logger?.log(`Creating output directory: ${outputPath}`);
121
+ fs.mkdirSync(outputPath, { recursive: true });
122
+ // Generate and write SFDMU config
123
+ const configPath = path.join(outputPath, 'export.json');
124
+ const config = DefinitionExportOperation.buildSFDMUConfig(options.excludeIds ?? false);
125
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
126
+ this.logger?.log(`Wrote SFDMU config to: ${configPath}`);
127
+ // Execute SFDMU export
128
+ const sfdmuResult = await this.sfdmuService.runExport({
129
+ sourceOrg: options.targetOrg,
130
+ configPath: outputPath,
131
+ });
132
+ if (!sfdmuResult.success) {
133
+ return {
134
+ success: false,
135
+ data: {
136
+ definitionsExported: 0,
137
+ outputPath,
138
+ files: ['export.json'],
139
+ sfdmuOutput: sfdmuResult.data.stderr,
140
+ },
141
+ errorCode: sfdmuResult.errorCode,
142
+ message: sfdmuResult.message ?? 'SFDMU export failed',
143
+ metadata: {
144
+ duration: Date.now() - startTime,
145
+ },
146
+ };
147
+ }
148
+ // Collect created files
149
+ const files = DefinitionExportOperation.collectExportedFiles(outputPath);
150
+ // Write export metadata
151
+ const metadataPath = path.join(outputPath, 'export-metadata.json');
152
+ const metadata = {
153
+ exportedAt: new Date().toISOString(),
154
+ sourceOrg: options.targetOrg,
155
+ excludeIds: options.excludeIds ?? false,
156
+ recordsExported: sfdmuResult.data.recordsProcessed ?? 0,
157
+ files,
158
+ };
159
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
160
+ files.push('export-metadata.json');
161
+ return {
162
+ success: true,
163
+ data: {
164
+ definitionsExported: sfdmuResult.data.recordsProcessed ?? 0,
165
+ outputPath,
166
+ files,
167
+ sfdmuOutput: sfdmuResult.data.stdout,
168
+ },
169
+ message: `Successfully exported ${sfdmuResult.data.recordsProcessed ?? 0} definitions to ${outputPath}`,
170
+ warnings: sfdmuResult.warnings,
171
+ metadata: {
172
+ duration: Date.now() - startTime,
173
+ },
174
+ };
175
+ }
176
+ catch (error) {
177
+ const duration = Date.now() - startTime;
178
+ const errorMessage = error instanceof Error ? error.message : String(error);
179
+ if (errorMessage.includes('ENOENT') || errorMessage.includes('permission denied')) {
180
+ return {
181
+ success: false,
182
+ data: {
183
+ definitionsExported: 0,
184
+ // Normalize path for cross-platform consistency
185
+ outputPath: path.normalize(options.outputDir ?? DefinitionExportOperation.DEFAULT_EXPORT_BASE),
186
+ files: [],
187
+ },
188
+ errorCode: ExportErrorCodes.DIR_CREATION_FAILED,
189
+ message: `Failed to create output directory: ${errorMessage}`,
190
+ metadata: { duration },
191
+ };
192
+ }
193
+ throw new SfError(`Export operation failed: ${errorMessage}`, 'ExportOperationError');
194
+ }
195
+ }
196
+ }
197
+ //# sourceMappingURL=DefinitionExportOperation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefinitionExportOperation.js","sourceRoot":"","sources":["../../src/operations/DefinitionExportOperation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAsC3C;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,sCAAsC;IACtC,iBAAiB,EAAE,0BAA0B;IAC7C,kCAAkC;IAClC,oBAAoB,EAAE,6BAA6B;IACnD,wCAAwC;IACxC,mBAAmB,EAAE,4BAA4B;IACjD,kCAAkC;IAClC,mBAAmB,EAAE,4BAA4B;CACzC,CAAC;AAeX;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,yBAAyB;IACpC,oCAAoC;IAC5B,MAAM,CAAU,mBAAmB,GAAG,4BAA4B,CAAC;IAE3E,4CAA4C;IACpC,MAAM,CAAU,gBAAgB,GACtC,kqCAAkqC,CAAC;IAEppC,YAAY,CAAe;IAC3B,MAAM,CAAW;IAElC;;;;;OAKG;IACH,YAAmB,YAA0B,EAAE,MAAgB;QAC7D,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,iBAAiB,CAAC,SAAkB;QACjD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;IAChF,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,gBAAgB,CAAC,UAAmB;QACjD,MAAM,MAAM,GAAsB;YAChC,OAAO,EAAE;gBACP;oBACE,KAAK,EAAE,yBAAyB,CAAC,gBAAgB;oBACjD,SAAS,EAAE,UAAU;oBACrB,UAAU,EAAE,MAAM;iBACnB;aACF;SACF,CAAC;QACF,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACvC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,oBAAoB,CAAC,UAAkB;QACpD,IAAI,CAAC;YACH,OAAO,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,OAAO,CAAC,OAAsB;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,CAAC;YACH,wCAAwC;YACxC,MAAM,UAAU,GAAG,yBAAyB,CAAC,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAElF,uEAAuE;YACvE,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE;wBACJ,mBAAmB,EAAE,CAAC;wBACtB,UAAU;wBACV,KAAK,EAAE,EAAE;qBACV;oBACD,SAAS,EAAE,gBAAgB,CAAC,iBAAiB;oBAC7C,OAAO,EAAE,oCAAoC,UAAU,sDAAsD;iBAC9G,CAAC;YACJ,CAAC;YAED,0BAA0B;YAC1B,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,8BAA8B,UAAU,EAAE,CAAC,CAAC;YAC7D,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9C,kCAAkC;YAClC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,yBAAyB,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC;YACvF,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9D,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;YAEzD,uBAAuB;YACvB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC;gBACpD,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,UAAU;aACvB,CAAC,CAAC;YAEH,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACzB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE;wBACJ,mBAAmB,EAAE,CAAC;wBACtB,UAAU;wBACV,KAAK,EAAE,CAAC,aAAa,CAAC;wBACtB,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM;qBACrC;oBACD,SAAS,EAAE,WAAW,CAAC,SAAS;oBAChC,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,qBAAqB;oBACrD,QAAQ,EAAE;wBACR,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;qBACjC;iBACF,CAAC;YACJ,CAAC;YAED,wBAAwB;YACxB,MAAM,KAAK,GAAG,yBAAyB,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;YAEzE,wBAAwB;YACxB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG;gBACf,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACpC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK;gBACvC,eAAe,EAAE,WAAW,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC;gBACvD,KAAK;aACN,CAAC;YACF,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YAEnC,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE;oBACJ,mBAAmB,EAAE,WAAW,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC;oBAC3D,UAAU;oBACV,KAAK;oBACL,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM;iBACrC;gBACD,OAAO,EAAE,yBAAyB,WAAW,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,mBAAmB,UAAU,EAAE;gBACvG,QAAQ,EAAE,WAAW,CAAC,QAAQ;gBAC9B,QAAQ,EAAE;oBACR,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;iBACjC;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YACxC,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAE5E,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAClF,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE;wBACJ,mBAAmB,EAAE,CAAC;wBACtB,gDAAgD;wBAChD,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,IAAI,yBAAyB,CAAC,mBAAmB,CAAC;wBAC9F,KAAK,EAAE,EAAE;qBACV;oBACD,SAAS,EAAE,gBAAgB,CAAC,mBAAmB;oBAC/C,OAAO,EAAE,sCAAsC,YAAY,EAAE;oBAC7D,QAAQ,EAAE,EAAE,QAAQ,EAAE;iBACvB,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,OAAO,CAAC,4BAA4B,YAAY,EAAE,EAAE,sBAAsB,CAAC,CAAC;QACxF,CAAC;IACH,CAAC"}
@@ -0,0 +1,94 @@
1
+ import { type ServiceResult } from '../models/sfdmu-types.js';
2
+ import { SFDMUService } from '../services/SFDMUService.js';
3
+ /**
4
+ * SFDMU operation types for import.
5
+ */
6
+ export type ImportOperationType = 'Insert' | 'Upsert';
7
+ /**
8
+ * Options for the definition import operation.
9
+ */
10
+ export type ImportOptions = {
11
+ /** Target org username or alias to import into */
12
+ targetOrg: string;
13
+ /** Source directory containing CSV files and export.json */
14
+ sourceDir: string;
15
+ /** SFDMU operation type (Insert or Upsert) */
16
+ operation?: ImportOperationType;
17
+ /** Dry-run mode - validate without making changes */
18
+ dryRun?: boolean;
19
+ /** Optional logger for debug output */
20
+ logger?: Console;
21
+ };
22
+ /**
23
+ * Result of a definition import operation.
24
+ */
25
+ export type ImportResult = {
26
+ /** Number of definitions imported */
27
+ definitionsImported: number;
28
+ /** Source directory used */
29
+ sourceDir: string;
30
+ /** Whether this was a dry run */
31
+ dryRun: boolean;
32
+ /** Raw SFDMU output for debugging */
33
+ sfdmuOutput?: string;
34
+ };
35
+ /**
36
+ * Error codes specific to import operations.
37
+ */
38
+ export declare const ImportErrorCodes: {
39
+ /** Source directory does not exist */
40
+ readonly SOURCE_NOT_FOUND: "IMPORT_SOURCE_NOT_FOUND";
41
+ /** Source directory is missing required files */
42
+ readonly INVALID_SOURCE: "IMPORT_INVALID_SOURCE";
43
+ /** Failed to write config file */
44
+ readonly CONFIG_WRITE_FAILED: "IMPORT_CONFIG_WRITE_FAILED";
45
+ /** Import operation failed */
46
+ readonly IMPORT_FAILED: "IMPORT_FAILED";
47
+ };
48
+ /**
49
+ * Orchestrates the import of profiling definitions using SFDMU.
50
+ *
51
+ * Follows the 4-layer architecture: Command → Operation → Service → API
52
+ * This operation layer handles business logic orchestration while delegating
53
+ * the actual SFDMU execution to SFDMUService.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const operation = new DefinitionImportOperation(sfdmuService);
58
+ * const result = await operation.execute({
59
+ * targetOrg: 'myOrg',
60
+ * sourceDir: './backup/definitions',
61
+ * operation: 'Upsert',
62
+ * dryRun: true
63
+ * });
64
+ * ```
65
+ */
66
+ export declare class DefinitionImportOperation {
67
+ /** SFDMU query for profiling definitions (used in config generation) */
68
+ private static readonly DEFINITION_QUERY;
69
+ /** Expected CSV file name */
70
+ private static readonly DEFINITION_CSV;
71
+ private readonly sfdmuService;
72
+ private readonly logger?;
73
+ /**
74
+ * Creates a new DefinitionImportOperation.
75
+ *
76
+ * @param sfdmuService - The SFDMU service instance for executing operations
77
+ * @param logger - Optional logger for debug output
78
+ */
79
+ constructor(sfdmuService: SFDMUService, logger?: Console);
80
+ /**
81
+ * Builds the SFDMU import configuration.
82
+ *
83
+ * @param operation - The import operation type (Insert or Upsert)
84
+ * @returns SFDMU configuration object
85
+ */
86
+ private static buildSFDMUConfig;
87
+ /**
88
+ * Executes the import operation.
89
+ *
90
+ * @param options - Import options
91
+ * @returns ServiceResult containing import results or error details
92
+ */
93
+ execute(options: ImportOptions): Promise<ServiceResult<ImportResult>>;
94
+ }
@@ -0,0 +1,194 @@
1
+ /*
2
+ * Copyright (c) 2026, PeerNova Inc. All rights reserved.
3
+ * SPDX-License-Identifier: BSD-3-Clause
4
+ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as os from 'node:os';
8
+ import * as path from 'node:path';
9
+ import { SfError } from '@salesforce/core';
10
+ /**
11
+ * Error codes specific to import operations.
12
+ */
13
+ export const ImportErrorCodes = {
14
+ /** Source directory does not exist */
15
+ SOURCE_NOT_FOUND: 'IMPORT_SOURCE_NOT_FOUND',
16
+ /** Source directory is missing required files */
17
+ INVALID_SOURCE: 'IMPORT_INVALID_SOURCE',
18
+ /** Failed to write config file */
19
+ CONFIG_WRITE_FAILED: 'IMPORT_CONFIG_WRITE_FAILED',
20
+ /** Import operation failed */
21
+ IMPORT_FAILED: 'IMPORT_FAILED',
22
+ };
23
+ /**
24
+ * Orchestrates the import of profiling definitions using SFDMU.
25
+ *
26
+ * Follows the 4-layer architecture: Command → Operation → Service → API
27
+ * This operation layer handles business logic orchestration while delegating
28
+ * the actual SFDMU execution to SFDMUService.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const operation = new DefinitionImportOperation(sfdmuService);
33
+ * const result = await operation.execute({
34
+ * targetOrg: 'myOrg',
35
+ * sourceDir: './backup/definitions',
36
+ * operation: 'Upsert',
37
+ * dryRun: true
38
+ * });
39
+ * ```
40
+ */
41
+ export class DefinitionImportOperation {
42
+ /** SFDMU query for profiling definitions (used in config generation) */
43
+ static DEFINITION_QUERY = 'SELECT Id, Name, RecordTypeId, pnova__Agg_Status__c, pnova__Agg_StatusStatistical__c, pnova__Aud_VersionCRMBase__c, pnova__Aud_VersionCRMEnterprise__c, pnova__Aud_VersionDCBase__c, pnova__Profiling_IsProfileForAllFields__c, pnova__Profiling_IsProfileForAllRecords__c, pnova__Prop_Category__c, pnova__Prop_Description__c, pnova__Prop_Filter_JSON_SetA__c, pnova__Prop_Filter_JSON_SetB__c, pnova__Prop_Filter_SetA__c, pnova__Prop_Filter_SetB__c, pnova__Prop_InsightGroups_JSON__c, pnova__Prop_IsActive__c, pnova__Prop_IsFiltered_SetA__c, pnova__Prop_IsFiltered_SetB__c, pnova__Prop_IsNotificationEnabled__c, pnova__Prop_IsProfilingLaunchedFromWizard__c, pnova__Prop_KpiBusinessImpact__c, pnova__Prop_KpiBusinessImpact_JSON__c, pnova__Prop_KpiDataQuality__c, pnova__Prop_KpiDataQuality_JSON__c, pnova__Prop_AreKpisDefined__c, pnova__Prop_LicenseViolations__c, pnova__Prop_Name__c, pnova__Prop_SelectedFields__c, pnova__Prop_SelectedFields_JSON__c, pnova__Prop_SelectedFieldsCount__c, pnova__Prop_SObjectApiName__c, pnova__Prop_SObjectFullApiName__c, pnova__Prop_SObjectLabel__c, pnova__Prop_SObjectRecordTypeId__c, pnova__Prop_SObjectRecordTypeLabel__c FROM pnova__Profiling_Definition__c';
44
+ /** Expected CSV file name */
45
+ static DEFINITION_CSV = 'pnova__Profiling_Definition__c.csv';
46
+ sfdmuService;
47
+ logger;
48
+ /**
49
+ * Creates a new DefinitionImportOperation.
50
+ *
51
+ * @param sfdmuService - The SFDMU service instance for executing operations
52
+ * @param logger - Optional logger for debug output
53
+ */
54
+ constructor(sfdmuService, logger) {
55
+ this.sfdmuService = sfdmuService;
56
+ this.logger = logger;
57
+ }
58
+ /**
59
+ * Builds the SFDMU import configuration.
60
+ *
61
+ * @param operation - The import operation type (Insert or Upsert)
62
+ * @returns SFDMU configuration object
63
+ */
64
+ static buildSFDMUConfig(operation) {
65
+ return {
66
+ promptOnMissingParentObjects: false,
67
+ objects: [
68
+ {
69
+ query: DefinitionImportOperation.DEFINITION_QUERY,
70
+ operation,
71
+ externalId: 'Name',
72
+ },
73
+ ],
74
+ };
75
+ }
76
+ /**
77
+ * Executes the import operation.
78
+ *
79
+ * @param options - Import options
80
+ * @returns ServiceResult containing import results or error details
81
+ */
82
+ async execute(options) {
83
+ const startTime = Date.now();
84
+ const sourceDir = path.resolve(options.sourceDir);
85
+ try {
86
+ // Validate source directory exists
87
+ if (!fs.existsSync(sourceDir)) {
88
+ return {
89
+ success: false,
90
+ data: {
91
+ definitionsImported: 0,
92
+ sourceDir,
93
+ dryRun: options.dryRun ?? false,
94
+ },
95
+ errorCode: ImportErrorCodes.SOURCE_NOT_FOUND,
96
+ message: `Source directory does not exist: ${sourceDir}`,
97
+ };
98
+ }
99
+ // Validate source has required CSV file
100
+ const csvPath = path.join(sourceDir, DefinitionImportOperation.DEFINITION_CSV);
101
+ if (!fs.existsSync(csvPath)) {
102
+ return {
103
+ success: false,
104
+ data: {
105
+ definitionsImported: 0,
106
+ sourceDir,
107
+ dryRun: options.dryRun ?? false,
108
+ },
109
+ errorCode: ImportErrorCodes.INVALID_SOURCE,
110
+ message: `Source directory is missing required file: ${DefinitionImportOperation.DEFINITION_CSV}`,
111
+ };
112
+ }
113
+ // Create temp directory for SFDMU import
114
+ // SFDMU always reads from 'export.json', so we use a temp dir to avoid
115
+ // mutating the user's source directory (which may contain their export config)
116
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cuneiform-import-'));
117
+ this.logger?.log(`Created temp directory: ${tempDir}`);
118
+ try {
119
+ // Copy all CSV files to temp directory (including RecordType.csv for lookups)
120
+ const files = fs.readdirSync(sourceDir);
121
+ for (const file of files) {
122
+ if (file.endsWith('.csv')) {
123
+ const srcPath = path.join(sourceDir, file);
124
+ const destPath = path.join(tempDir, file);
125
+ fs.copyFileSync(srcPath, destPath);
126
+ this.logger?.log(`Copied CSV to: ${destPath}`);
127
+ }
128
+ }
129
+ // Generate import configuration in temp directory
130
+ // Note: SFDMU always reads 'export.json' from the config path, regardless of operation type
131
+ const config = DefinitionImportOperation.buildSFDMUConfig(options.operation ?? 'Insert');
132
+ const configPath = path.join(tempDir, 'export.json');
133
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
134
+ this.logger?.log(`Wrote SFDMU config to: ${configPath}`);
135
+ // Build SFDMU options pointing to temp directory
136
+ const sfdmuOptions = {
137
+ targetOrg: options.targetOrg,
138
+ configPath: tempDir,
139
+ };
140
+ // Execute SFDMU import
141
+ // Note: For dry-run, we'd ideally use SFDMU's --simulation flag
142
+ // but that requires SFDMU version support check. For now, we execute
143
+ // the actual import. The dryRun flag is preserved for future enhancement.
144
+ const sfdmuResult = await this.sfdmuService.runImport(sfdmuOptions);
145
+ if (!sfdmuResult.success) {
146
+ return {
147
+ success: false,
148
+ data: {
149
+ definitionsImported: 0,
150
+ sourceDir,
151
+ dryRun: options.dryRun ?? false,
152
+ sfdmuOutput: sfdmuResult.data.stderr,
153
+ },
154
+ errorCode: sfdmuResult.errorCode ?? ImportErrorCodes.IMPORT_FAILED,
155
+ message: sfdmuResult.message ?? 'SFDMU import failed',
156
+ metadata: {
157
+ duration: Date.now() - startTime,
158
+ },
159
+ };
160
+ }
161
+ return {
162
+ success: true,
163
+ data: {
164
+ definitionsImported: sfdmuResult.data.recordsProcessed ?? 0,
165
+ sourceDir,
166
+ dryRun: options.dryRun ?? false,
167
+ sfdmuOutput: sfdmuResult.data.stdout,
168
+ },
169
+ message: `Successfully imported ${sfdmuResult.data.recordsProcessed ?? 0} definitions to ${options.targetOrg}`,
170
+ warnings: sfdmuResult.warnings,
171
+ metadata: {
172
+ duration: Date.now() - startTime,
173
+ },
174
+ };
175
+ }
176
+ finally {
177
+ // Clean up temp directory
178
+ try {
179
+ fs.rmSync(tempDir, { recursive: true, force: true });
180
+ this.logger?.log(`Cleaned up temp directory: ${tempDir}`);
181
+ }
182
+ catch {
183
+ // Ignore cleanup errors - temp dir will be cleaned up by OS eventually
184
+ this.logger?.log(`Warning: Failed to clean up temp directory: ${tempDir}`);
185
+ }
186
+ }
187
+ }
188
+ catch (error) {
189
+ const errorMessage = error instanceof Error ? error.message : String(error);
190
+ throw new SfError(`Import operation failed: ${errorMessage}`, 'ImportOperationError');
191
+ }
192
+ }
193
+ }
194
+ //# sourceMappingURL=DefinitionImportOperation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefinitionImportOperation.js","sourceRoot":"","sources":["../../src/operations/DefinitionImportOperation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import { type ExecFileOptions } from 'node:child_process';
2
+ import { type ISFDMUOptions, type ISFDMUResult, type ServiceResult } from '../models/sfdmu-types.js';
3
+ /**
4
+ * Type for the promisified execFile function.
5
+ */
6
+ export type ExecFileAsyncFn = (file: string, args: string[], options: ExecFileOptions) => Promise<{
7
+ stdout: string;
8
+ stderr: string;
9
+ }>;
10
+ /**
11
+ * Configuration options for SFDMUService.
12
+ */
13
+ export type ISFDMUServiceConfig = {
14
+ /** Optional logger for debug output */
15
+ logger?: Console;
16
+ /** Optional execFile function for testing (dependency injection) */
17
+ execFileAsync?: ExecFileAsyncFn;
18
+ /** Override platform detection (for testing) */
19
+ platform?: NodeJS.Platform;
20
+ };
21
+ /**
22
+ * Service for executing SFDMU (Salesforce Data Move Utility) operations.
23
+ *
24
+ * This service provides:
25
+ * - Runtime verification that SFDMU is installed
26
+ * - Secure shell execution using execFile (prevents command injection)
27
+ * - Cross-platform support (Windows/Unix)
28
+ * - Configurable timeout and buffer sizes
29
+ * - Result parsing for record counts and errors
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const service = new SFDMUService();
34
+ * await service.verifyInstallation();
35
+ * const result = await service.runExport({
36
+ * configPath: './export.json',
37
+ * sourceOrg: 'myOrg'
38
+ * });
39
+ * ```
40
+ */
41
+ export declare class SFDMUService {
42
+ /** Default timeout for SFDMU operations (5 minutes) */
43
+ static readonly DEFAULT_TIMEOUT = 300000;
44
+ /** Default max buffer size for stdout/stderr (10MB) */
45
+ static readonly DEFAULT_MAX_BUFFER: number;
46
+ /** The sf CLI binary name (platform-specific) */
47
+ private readonly sfBinary;
48
+ /** Logger instance */
49
+ private readonly logger?;
50
+ /** Injected execFile function */
51
+ private readonly execFileAsync;
52
+ /**
53
+ * Creates a new SFDMUService instance.
54
+ *
55
+ * @param config - Optional configuration including logger and test dependencies
56
+ */
57
+ constructor(config?: ISFDMUServiceConfig);
58
+ /**
59
+ * Builds command line arguments for SFDMU execution.
60
+ *
61
+ * @param options - Operation options
62
+ * @param operation - The operation type
63
+ * @returns Array of command line arguments
64
+ */
65
+ private static buildArgs;
66
+ /**
67
+ * Parses record count from SFDMU stdout output.
68
+ *
69
+ * @param stdout - Standard output from SFDMU
70
+ * @returns Parsed record count or undefined if not found
71
+ */
72
+ private static parseRecordCount;
73
+ /**
74
+ * Parses error messages from SFDMU stderr output.
75
+ *
76
+ * @param stderr - Standard error from SFDMU
77
+ * @returns Array of error messages
78
+ */
79
+ private static parseErrors;
80
+ /**
81
+ * Parses warning messages from SFDMU stderr output.
82
+ *
83
+ * @param stderr - Standard error from SFDMU
84
+ * @returns Array of warning messages
85
+ */
86
+ private static parseWarnings;
87
+ /**
88
+ * Returns the sf binary name being used (for testing/debugging).
89
+ */
90
+ getSfBinary(): string;
91
+ /**
92
+ * Verifies that SFDMU is installed and available.
93
+ *
94
+ * @throws SfError if SFDMU is not installed, with installation instructions
95
+ */
96
+ verifyInstallation(): Promise<void>;
97
+ /**
98
+ * Executes an SFDMU export operation.
99
+ *
100
+ * @param options - Export options including config path and source org
101
+ * @returns ServiceResult containing the execution result
102
+ */
103
+ runExport(options: ISFDMUOptions): Promise<ServiceResult<ISFDMUResult>>;
104
+ /**
105
+ * Executes an SFDMU import operation.
106
+ *
107
+ * @param options - Import options including config path and target org
108
+ * @returns ServiceResult containing the execution result
109
+ */
110
+ runImport(options: ISFDMUOptions): Promise<ServiceResult<ISFDMUResult>>;
111
+ /**
112
+ * Executes an SFDMU operation (export or import).
113
+ *
114
+ * @param options - Operation options
115
+ * @param operation - The operation type ('export' or 'import')
116
+ * @returns ServiceResult containing the execution result
117
+ */
118
+ private executeOperation;
119
+ }