@memberjunction/metadata-sync 2.128.0 → 2.129.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.
@@ -1 +1 @@
1
- {"version":3,"file":"PullService.js","sourceRoot":"","sources":["../../src/services/PullService.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs-extra';\nimport path from 'path';\nimport { RunView, EntityInfo, UserInfo, BaseEntity } from '@memberjunction/core';\nimport { SyncEngine, RecordData } from '../lib/sync-engine';\nimport { loadEntityConfig, EntityConfig } from '../config';\nimport { configManager } from '../lib/config-manager';\nimport { FileWriteBatch } from '../lib/file-write-batch';\nimport { JsonWriteHelper } from '../lib/json-write-helper';\nimport { RecordProcessor } from '../lib/RecordProcessor';\n\nexport interface PullOptions {\n entity: string;\n filter?: string;\n dryRun?: boolean;\n multiFile?: string;\n verbose?: boolean;\n noValidate?: boolean;\n targetDir?: string;\n updateExistingRecords?: boolean;\n createNewFileIfNotFound?: boolean;\n include?: string[]; // Only process these directories (whitelist, supports patterns)\n exclude?: string[]; // Skip these directories (blacklist, supports patterns)\n}\n\nexport interface PullCallbacks {\n onProgress?: (message: string) => void;\n onSuccess?: (message: string) => void;\n onError?: (message: string) => void;\n onWarn?: (message: string) => void;\n onLog?: (message: string) => void;\n}\n\nexport interface PullResult {\n processed: number;\n created: number;\n updated: number;\n skipped: number;\n targetDir: string;\n}\n\nexport class PullService {\n private syncEngine: SyncEngine;\n private contextUser: UserInfo;\n private createdBackupFiles: string[] = [];\n private createdBackupDirs: Set<string> = new Set();\n private fileWriteBatch: FileWriteBatch;\n private recordProcessor: RecordProcessor;\n \n constructor(syncEngine: SyncEngine, contextUser: UserInfo) {\n this.syncEngine = syncEngine;\n this.contextUser = contextUser;\n this.fileWriteBatch = new FileWriteBatch();\n this.recordProcessor = new RecordProcessor(syncEngine, contextUser);\n }\n \n async pull(options: PullOptions, callbacks?: PullCallbacks): Promise<PullResult> {\n // Validate that include and exclude are not used together\n if (options.include && options.exclude) {\n throw new Error('Cannot specify both --include and --exclude options. Please use one or the other.');\n }\n\n // Clear any previous batch operations\n this.fileWriteBatch.clear();\n this.createdBackupFiles = [];\n this.createdBackupDirs.clear();\n \n let targetDir: string;\n let entityConfig: EntityConfig | null;\n \n // Check if we should use a specific target directory\n if (options.targetDir) {\n if (options.verbose) {\n callbacks?.onLog?.(`Using specified target directory: ${options.targetDir}`);\n }\n process.chdir(options.targetDir);\n targetDir = process.cwd();\n \n // Load entity config from the current directory\n entityConfig = await loadEntityConfig(targetDir);\n if (!entityConfig) {\n throw new Error(`No .mj-sync.json found in ${targetDir}`);\n }\n if (entityConfig.entity !== options.entity) {\n throw new Error(`Directory ${targetDir} is configured for entity \"${entityConfig.entity}\", not \"${options.entity}\"`);\n }\n } else {\n // Original behavior - find entity directory\n const entityDirs = await this.findEntityDirectories(options.entity);\n \n if (entityDirs.length === 0) {\n throw new Error(`No directory found for entity \"${options.entity}\". Run \"mj sync init\" first.`);\n }\n \n if (entityDirs.length === 1) {\n targetDir = entityDirs[0];\n } else {\n // Multiple directories found - in service mode, we'll use the first one\n // The CLI can handle prompting for selection\n throw new Error(`Multiple directories found for entity \"${options.entity}\". Please specify target directory.`);\n }\n \n entityConfig = await loadEntityConfig(targetDir);\n if (!entityConfig) {\n throw new Error(`Invalid entity configuration in ${targetDir}`);\n }\n }\n \n // Show configuration notice only if relevant and in verbose mode\n if (options.verbose && entityConfig?.pull?.appendRecordsToExistingFile && entityConfig?.pull?.newFileName) {\n const targetFile = path.join(targetDir, entityConfig.pull.newFileName.endsWith('.json') \n ? entityConfig.pull.newFileName \n : `${entityConfig.pull.newFileName}.json`);\n \n if (await fs.pathExists(targetFile)) {\n callbacks?.onLog?.(`\\nšŸ“ Configuration: New records will be appended to existing file '${path.basename(targetFile)}'`);\n }\n }\n \n // Pull records\n callbacks?.onProgress?.(`Pulling ${options.entity} records`);\n const rv = new RunView();\n \n let filter = '';\n if (options.filter) {\n filter = options.filter;\n } else if (entityConfig?.pull?.filter) {\n filter = entityConfig.pull.filter;\n }\n \n const result = await rv.RunView({\n EntityName: options.entity,\n ExtraFilter: filter,\n ResultType: 'entity_object'\n }, this.contextUser);\n \n if (!result.Success) {\n throw new Error(`Failed to pull records: ${result.ErrorMessage}`);\n }\n \n callbacks?.onSuccess?.(`Found ${result.Results.length} records`);\n \n if (options.dryRun) {\n callbacks?.onLog?.(`\\nDry run mode - would pull ${result.Results.length} records to ${targetDir}`);\n return {\n processed: 0,\n created: 0,\n updated: 0,\n skipped: 0,\n targetDir\n };\n }\n \n // Process records with error handling and rollback\n let pullResult: Omit<PullResult, 'targetDir'>;\n \n try {\n pullResult = await this.processRecords(\n result.Results,\n options,\n targetDir,\n entityConfig,\n callbacks\n );\n \n // Write all batched file changes at once\n if (!options.dryRun) {\n const filesWritten = await this.fileWriteBatch.flush();\n if (options.verbose && filesWritten > 0) {\n callbacks?.onSuccess?.(`Wrote ${filesWritten} files with consistent property ordering`);\n }\n }\n \n // Operation succeeded - clean up backup files\n if (!options.dryRun) {\n await this.cleanupBackupFiles();\n }\n \n } catch (error) {\n callbacks?.onError?.(`Pull operation failed: ${(error as any).message || error}`);\n \n // Attempt to rollback file changes if not in dry run mode\n if (!options.dryRun) {\n try {\n await this.rollbackFileChanges(callbacks);\n callbacks?.onWarn?.('File changes have been rolled back due to operation failure');\n } catch (rollbackError) {\n callbacks?.onError?.(`Rollback failed: ${(rollbackError as any).message || rollbackError}`);\n }\n }\n \n throw error;\n }\n \n return {\n ...pullResult,\n targetDir\n };\n }\n \n private async processRecords(\n records: BaseEntity[],\n options: PullOptions,\n targetDir: string,\n entityConfig: EntityConfig,\n callbacks?: PullCallbacks\n ): Promise<Omit<PullResult, 'targetDir'>> {\n const entityInfo = this.syncEngine.getEntityInfo(options.entity);\n if (!entityInfo) {\n throw new Error(`Entity information not found for: ${options.entity}`);\n }\n \n callbacks?.onProgress?.('Processing records');\n let processed = 0;\n let updated = 0;\n let created = 0;\n let skipped = 0;\n \n // If multi-file flag is set, collect all records\n if (options.multiFile) {\n const allRecords: RecordData[] = [];\n const errors: string[] = [];\n \n // Process records in parallel for multi-file mode\n const recordPromises = records.map(async (record, index) => {\n try {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = (record as any)[pk.Name];\n }\n \n // Process record for multi-file\n const recordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n options.verbose, \n true\n );\n \n return { success: true, recordData, index };\n } catch (error) {\n const errorMessage = `Failed to process record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, recordData: null, index };\n }\n });\n \n const recordResults = await Promise.all(recordPromises);\n \n // Collect successful records\n for (const result of recordResults) {\n if (result.success && result.recordData) {\n allRecords.push(result.recordData);\n processed++;\n }\n }\n \n if (options.verbose) {\n callbacks?.onProgress?.(`Processed ${processed}/${records.length} records in parallel`);\n }\n \n // Queue all records to single file for batched write\n if (allRecords.length > 0) {\n const fileName = options.multiFile.endsWith('.json') ? options.multiFile : `${options.multiFile}.json`;\n const filePath = path.join(targetDir, fileName);\n this.fileWriteBatch.queueWrite(filePath, allRecords);\n callbacks?.onSuccess?.(`Queued ${processed} records for ${path.basename(filePath)}`);\n }\n \n // If there were errors during parallel processing, throw them\n if (errors.length > 0) {\n throw new Error(`Multi-file processing completed with ${errors.length} errors:\\n${errors.join('\\n')}`);\n }\n } else {\n // Smart update logic for single-file-per-record\n const result = await this.processIndividualRecords(\n records,\n options,\n targetDir,\n entityConfig,\n entityInfo,\n callbacks\n );\n \n processed = result.processed;\n updated = result.updated;\n created = result.created;\n skipped = result.skipped;\n \n // Final status\n const statusParts = [`Processed ${processed} records`];\n if (updated > 0) statusParts.push(`updated ${updated}`);\n if (created > 0) statusParts.push(`created ${created}`);\n if (skipped > 0) statusParts.push(`skipped ${skipped}`);\n \n callbacks?.onSuccess?.(statusParts.join(', '));\n }\n \n return { processed, created, updated, skipped };\n }\n \n /**\n * Clean up backup files created during the pull operation\n * Should be called after successful pull operations to remove persistent backup files\n */\n async cleanupBackupFiles(): Promise<void> {\n if (this.createdBackupFiles.length === 0 && this.createdBackupDirs.size === 0) {\n return;\n }\n \n const errors: string[] = [];\n \n // Remove backup files\n for (const backupPath of this.createdBackupFiles) {\n try {\n if (await fs.pathExists(backupPath)) {\n await fs.remove(backupPath);\n }\n } catch (error) {\n errors.push(`Failed to remove backup file ${backupPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n \n // Remove empty backup directories\n for (const backupDir of this.createdBackupDirs) {\n try {\n await this.removeEmptyBackupDirectory(backupDir);\n } catch (error) {\n errors.push(`Failed to remove backup directory ${backupDir}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n \n // Clear the tracking arrays\n this.createdBackupFiles = [];\n this.createdBackupDirs.clear();\n \n if (errors.length > 0) {\n throw new Error(`Backup cleanup completed with errors:\\n${errors.join('\\n')}`);\n }\n }\n\n /**\n * Remove a backup directory if it's empty\n */\n private async removeEmptyBackupDirectory(backupDir: string): Promise<void> {\n try {\n // Check if directory exists\n if (!(await fs.pathExists(backupDir))) {\n return;\n }\n \n // Only remove if it's actually a .backups directory for safety\n if (!backupDir.endsWith('.backups')) {\n return;\n }\n \n // Check if directory is empty\n const files = await fs.readdir(backupDir);\n if (files.length === 0) {\n await fs.remove(backupDir);\n }\n } catch (error) {\n // Log error but don't throw - cleanup should be non-critical\n // The error will be caught by the caller and included in the error list\n throw error;\n }\n }\n \n /**\n * Get the list of backup files created during the current pull operation\n */\n getCreatedBackupFiles(): string[] {\n return [...this.createdBackupFiles];\n }\n \n /**\n * Rollback file changes by restoring from backup files\n * Called when pull operation fails after files have been modified\n */\n private async rollbackFileChanges(callbacks?: PullCallbacks): Promise<void> {\n if (this.createdBackupFiles.length === 0) {\n callbacks?.onLog?.('No backup files found - no rollback needed');\n return;\n }\n \n callbacks?.onProgress?.(`Rolling back ${this.createdBackupFiles.length} file changes...`);\n \n const errors: string[] = [];\n let restoredCount = 0;\n \n for (const backupPath of this.createdBackupFiles) {\n try {\n // Extract original file path from backup path\n const backupDir = path.dirname(backupPath);\n const backupFileName = path.basename(backupPath);\n \n // Remove timestamp and .backup extension to get original filename\n const originalFileName = backupFileName.replace(/\\.\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.backup$/, '.json');\n const originalFilePath = path.join(path.dirname(backupDir), originalFileName);\n \n if (await fs.pathExists(backupPath)) {\n await fs.copy(backupPath, originalFilePath);\n restoredCount++;\n }\n } catch (error) {\n errors.push(`Failed to restore ${backupPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n \n if (errors.length > 0) {\n throw new Error(`Rollback completed with ${errors.length} errors (${restoredCount} files restored):\\n${errors.join('\\n')}`);\n }\n \n callbacks?.onSuccess?.(`Successfully rolled back ${restoredCount} file changes`);\n }\n \n private async processIndividualRecords(\n records: BaseEntity[],\n options: PullOptions,\n targetDir: string,\n entityConfig: EntityConfig,\n entityInfo: EntityInfo,\n callbacks?: PullCallbacks\n ): Promise<{ processed: number; updated: number; created: number; skipped: number }> {\n let processed = 0;\n let updated = 0;\n let created = 0;\n let skipped = 0;\n \n // Find existing files\n const filePattern = entityConfig.pull?.filePattern || entityConfig.filePattern || '*.json';\n const existingFiles = await this.findExistingFiles(targetDir, filePattern);\n \n if (options.verbose) {\n callbacks?.onLog?.(`Found ${existingFiles.length} existing files matching pattern '${filePattern}'`);\n existingFiles.forEach(f => callbacks?.onLog?.(` - ${path.basename(f)}`));\n }\n \n // Load existing records and build lookup map\n const existingRecordsMap = await this.loadExistingRecords(existingFiles, entityInfo);\n \n if (options.verbose) {\n callbacks?.onLog?.(`Loaded ${existingRecordsMap.size} existing records from files`);\n }\n \n // Separate records into new and existing\n const newRecords: Array<{ record: BaseEntity; primaryKey: Record<string, any> }> = [];\n const existingRecordsToUpdate: Array<{ record: BaseEntity; primaryKey: Record<string, any>; filePath: string }> = [];\n \n for (const record of records) {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = (record as any)[pk.Name];\n }\n \n // Create lookup key\n const lookupKey = this.createPrimaryKeyLookup(primaryKey);\n const existingFileInfo = existingRecordsMap.get(lookupKey);\n \n if (existingFileInfo) {\n // Record exists locally\n if (entityConfig.pull?.updateExistingRecords !== false) {\n existingRecordsToUpdate.push({ record, primaryKey, filePath: existingFileInfo.filePath });\n } else {\n skipped++;\n if (options.verbose) {\n callbacks?.onLog?.(`Skipping existing record: ${lookupKey}`);\n }\n }\n } else {\n // Record doesn't exist locally\n if (entityConfig.pull?.createNewFileIfNotFound !== false) {\n newRecords.push({ record, primaryKey });\n } else {\n skipped++;\n if (options.verbose) {\n callbacks?.onLog?.(`Skipping new record (createNewFileIfNotFound=false): ${lookupKey}`);\n }\n }\n }\n }\n \n // Track which files have been backed up to avoid duplicates\n const backedUpFiles = new Set<string>();\n const errors: string[] = [];\n \n // Process existing records updates in parallel\n if (existingRecordsToUpdate.length > 0) {\n callbacks?.onProgress?.(`Updating existing records (parallel processing)`);\n \n const updatePromises = existingRecordsToUpdate.map(async ({ record, primaryKey, filePath }, index) => {\n try {\n // Create backup if configured (only once per file)\n if (entityConfig.pull?.backupBeforeUpdate && !backedUpFiles.has(filePath)) {\n await this.createBackup(filePath, entityConfig.pull?.backupDirectory);\n backedUpFiles.add(filePath);\n }\n \n // Load existing file data\n const existingData = await fs.readJson(filePath);\n \n // Find the specific existing record that matches this primary key\n let existingRecordData: RecordData;\n if (Array.isArray(existingData)) {\n // Find the matching record in the array\n const matchingRecord = existingData.find(r => \n this.createPrimaryKeyLookup(r.primaryKey || {}) === this.createPrimaryKeyLookup(primaryKey)\n );\n existingRecordData = matchingRecord || existingData[0]; // Fallback to first if not found\n } else {\n existingRecordData = existingData;\n }\n \n // Process the new record data (isNewRecord = false for updates)\n const newRecordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n options.verbose, \n false, \n existingRecordData\n );\n \n // Apply merge strategy\n const mergedData = await this.mergeRecords(\n existingRecordData,\n newRecordData,\n entityConfig.pull?.mergeStrategy || 'merge',\n entityConfig.pull?.preserveFields || []\n );\n \n // Queue updated data for batched write\n if (Array.isArray(existingData)) {\n // Queue array update - batch will handle merging\n const primaryKeyLookup = this.createPrimaryKeyLookup(primaryKey);\n this.fileWriteBatch.queueArrayUpdate(filePath, mergedData, primaryKeyLookup);\n } else {\n // Queue single record update\n this.fileWriteBatch.queueSingleUpdate(filePath, mergedData);\n }\n \n if (options.verbose) {\n callbacks?.onLog?.(`Updated: ${filePath}`);\n }\n \n return { success: true, index };\n } catch (error) {\n const errorMessage = `Failed to update record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, index };\n }\n });\n \n const updateResults = await Promise.all(updatePromises);\n updated = updateResults.filter(r => r.success).length;\n processed += updated;\n \n if (options.verbose) {\n callbacks?.onSuccess?.(`Completed ${updated}/${existingRecordsToUpdate.length} record updates`);\n }\n }\n \n // Process new records in parallel\n if (newRecords.length > 0) {\n callbacks?.onProgress?.(`Creating new records (parallel processing)`);\n \n if (entityConfig.pull?.appendRecordsToExistingFile && entityConfig.pull?.newFileName) {\n // Append all new records to a single file using parallel processing\n const fileName = entityConfig.pull.newFileName.endsWith('.json') \n ? entityConfig.pull.newFileName \n : `${entityConfig.pull.newFileName}.json`;\n const filePath = path.join(targetDir, fileName);\n \n // Process all new records in parallel\n const newRecordPromises = newRecords.map(async ({ record, primaryKey }, index) => {\n try {\n // For new records, pass isNewRecord = true (default)\n const recordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n options.verbose, \n true\n );\n \n // Use queueArrayUpdate to append the new record without overwriting existing updates\n // For new records, we can use a special lookup key since they don't exist yet\n const newRecordLookup = this.createPrimaryKeyLookup(primaryKey);\n this.fileWriteBatch.queueArrayUpdate(filePath, recordData, newRecordLookup);\n \n return { success: true, index };\n } catch (error) {\n const errorMessage = `Failed to process new record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, index };\n }\n });\n \n const newRecordResults = await Promise.all(newRecordPromises);\n created = newRecordResults.filter(r => r.success).length;\n processed += created;\n \n if (options.verbose) {\n callbacks?.onLog?.(`Queued ${created} new records for: ${filePath}`);\n }\n } else {\n // Create individual files for each new record in parallel\n const individualRecordPromises = newRecords.map(async ({ record, primaryKey }, index) => {\n try {\n await this.processRecord(record, primaryKey, targetDir, entityConfig, options.verbose);\n return { success: true, index };\n } catch (error) {\n const errorMessage = `Failed to process new record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, index };\n }\n });\n \n const individualResults = await Promise.all(individualRecordPromises);\n created = individualResults.filter(r => r.success).length;\n processed += created;\n \n if (options.verbose) {\n callbacks?.onSuccess?.(`Created ${created}/${newRecords.length} individual record files`);\n }\n }\n }\n \n // If there were errors during parallel processing, throw them\n if (errors.length > 0) {\n throw new Error(`Parallel processing completed with ${errors.length} errors:\\n${errors.join('\\n')}`);\n }\n \n return { processed, updated, created, skipped };\n }\n \n private async processRecord(\n record: BaseEntity, \n primaryKey: Record<string, any>,\n targetDir: string, \n entityConfig: EntityConfig,\n verbose?: boolean\n ): Promise<void> {\n const recordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n verbose, \n true\n );\n \n // Determine file path\n const fileName = this.buildFileName(primaryKey, entityConfig);\n const filePath = path.join(targetDir, fileName);\n \n // Queue JSON file for batched write with controlled property order\n this.fileWriteBatch.queueWrite(filePath, recordData);\n }\n\n \n\n\n\n private async findEntityDirectories(entityName: string): Promise<string[]> {\n const dirs: string[] = [];\n \n // Search for directories with matching entity config\n const searchDirs = async (dir: string) => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(dir, entry.name);\n const config = await loadEntityConfig(fullPath);\n \n if (config && config.entity === entityName) {\n dirs.push(fullPath);\n } else {\n // Recurse\n await searchDirs(fullPath);\n }\n }\n }\n };\n \n await searchDirs(configManager.getOriginalCwd());\n return dirs;\n }\n \n private buildFileName(primaryKey: Record<string, any>, _entityConfig: EntityConfig): string {\n // Use primary key values to build filename\n const keys = Object.values(primaryKey);\n \n if (keys.length === 1 && typeof keys[0] === 'string') {\n // Single string key - use as base if it's a guid\n const key = keys[0];\n if (key.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {\n // It's a GUID, use first 8 chars, prefixed with dot, lowercase\n return `.${key.substring(0, 8).toLowerCase()}.json`;\n }\n // Use the whole key if not too long, prefixed with dot\n if (key.length <= 50) {\n return `.${key.replace(/[^a-zA-Z0-9\\-_]/g, '').toLowerCase()}.json`;\n }\n }\n \n // Multiple keys or numeric - create composite name, prefixed with dot\n return '.' + keys.map(k => String(k).replace(/[^a-zA-Z0-9\\-_]/g, '').toLowerCase()).join('-') + '.json';\n }\n \n private async findExistingFiles(dir: string, pattern: string): Promise<string[]> {\n const files: string[] = [];\n \n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isFile()) {\n const fileName = entry.name;\n \n // Simple pattern matching\n if (pattern === '*.json' && fileName.endsWith('.json')) {\n files.push(path.join(dir, fileName));\n } else if (pattern === '.*.json' && fileName.startsWith('.') && fileName.endsWith('.json')) {\n files.push(path.join(dir, fileName));\n } else if (pattern === fileName) {\n files.push(path.join(dir, fileName));\n }\n }\n }\n } catch (error) {\n // Directory might not exist yet\n if ((error as any).code !== 'ENOENT') {\n throw error;\n }\n }\n \n return files;\n }\n \n private async loadExistingRecords(\n files: string[], \n _entityInfo: EntityInfo\n ): Promise<Map<string, { filePath: string; recordData: RecordData }>> {\n const recordsMap = new Map<string, { filePath: string; recordData: RecordData }>();\n \n for (const filePath of files) {\n try {\n const fileData = await fs.readJson(filePath);\n const records = Array.isArray(fileData) ? fileData : [fileData];\n \n for (const record of records) {\n if (record.primaryKey) {\n const lookupKey = this.createPrimaryKeyLookup(record.primaryKey);\n recordsMap.set(lookupKey, { filePath, recordData: record });\n }\n }\n } catch (error) {\n // Skip files that can't be parsed\n }\n }\n \n return recordsMap;\n }\n \n private createPrimaryKeyLookup(primaryKey: Record<string, any>): string {\n const keys = Object.keys(primaryKey).sort();\n return keys.map(k => `${k}:${primaryKey[k]}`).join('|');\n }\n \n private async mergeRecords(\n existing: RecordData,\n newData: RecordData,\n strategy: 'overwrite' | 'merge' | 'skip',\n preserveFields: string[]\n ): Promise<RecordData> {\n if (strategy === 'skip') {\n return existing;\n }\n \n if (strategy === 'overwrite') {\n const result: RecordData = {\n fields: { ...newData.fields },\n primaryKey: newData.primaryKey,\n sync: newData.sync\n };\n \n // Restore preserved fields from existing\n if (preserveFields.length > 0 && existing.fields) {\n for (const field of preserveFields) {\n if (field in existing.fields) {\n result.fields[field] = existing.fields[field];\n }\n }\n }\n \n if (newData.relatedEntities) {\n result.relatedEntities = newData.relatedEntities;\n }\n \n return result;\n }\n \n // Default 'merge' strategy\n const result: RecordData = {\n fields: { ...existing.fields, ...newData.fields },\n primaryKey: newData.primaryKey || existing.primaryKey,\n sync: newData.sync\n };\n \n // Restore preserved fields\n if (preserveFields.length > 0 && existing.fields) {\n for (const field of preserveFields) {\n if (field in existing.fields) {\n result.fields[field] = existing.fields[field];\n }\n }\n }\n \n if (existing.relatedEntities || newData.relatedEntities) {\n result.relatedEntities = {\n ...existing.relatedEntities,\n ...newData.relatedEntities\n };\n }\n \n return result;\n }\n \n private async createBackup(filePath: string, backupDirName?: string): Promise<void> {\n const dir = path.dirname(filePath);\n const fileName = path.basename(filePath);\n const backupDir = path.join(dir, backupDirName || '.backups');\n \n // Ensure backup directory exists\n await fs.ensureDir(backupDir);\n // Track the backup directory for cleanup\n this.createdBackupDirs.add(backupDir);\n \n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n // Remove .json extension, add timestamp, then add .backup extension\n const backupFileName = fileName.replace(/\\.json$/, `.${timestamp}.backup`);\n const backupPath = path.join(backupDir, backupFileName);\n \n try {\n await fs.copy(filePath, backupPath);\n // Track the created backup file for cleanup\n this.createdBackupFiles.push(backupPath);\n } catch (error) {\n // Log error but don't throw\n }\n }\n}"]}
1
+ {"version":3,"file":"PullService.js","sourceRoot":"","sources":["../../src/services/PullService.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs-extra';\nimport path from 'path';\nimport { RunView, EntityInfo, UserInfo, BaseEntity } from '@memberjunction/core';\nimport { SyncEngine, RecordData } from '../lib/sync-engine';\nimport { loadEntityConfig, EntityConfig } from '../config';\nimport { configManager } from '../lib/config-manager';\nimport { FileWriteBatch } from '../lib/file-write-batch';\nimport { JsonWriteHelper } from '../lib/json-write-helper';\nimport { RecordProcessor } from '../lib/RecordProcessor';\n\nexport interface PullOptions {\n entity: string;\n filter?: string;\n dryRun?: boolean;\n multiFile?: string;\n verbose?: boolean;\n noValidate?: boolean;\n targetDir?: string;\n updateExistingRecords?: boolean;\n createNewFileIfNotFound?: boolean;\n include?: string[]; // Only process these directories (whitelist, supports patterns)\n exclude?: string[]; // Skip these directories (blacklist, supports patterns)\n}\n\nexport interface PullCallbacks {\n onProgress?: (message: string) => void;\n onSuccess?: (message: string) => void;\n onError?: (message: string) => void;\n onWarn?: (message: string) => void;\n onLog?: (message: string) => void;\n}\n\nexport interface PullResult {\n processed: number;\n created: number;\n updated: number;\n skipped: number;\n targetDir: string;\n}\n\nexport class PullService {\n private syncEngine: SyncEngine;\n private contextUser: UserInfo;\n private createdBackupFiles: string[] = [];\n private createdBackupDirs: Set<string> = new Set();\n private fileWriteBatch: FileWriteBatch;\n private recordProcessor: RecordProcessor;\n \n constructor(syncEngine: SyncEngine, contextUser: UserInfo) {\n this.syncEngine = syncEngine;\n this.contextUser = contextUser;\n this.fileWriteBatch = new FileWriteBatch();\n this.recordProcessor = new RecordProcessor(syncEngine, contextUser);\n }\n \n async pull(options: PullOptions, callbacks?: PullCallbacks): Promise<PullResult> {\n // Validate that include and exclude are not used together\n if (options.include && options.exclude) {\n throw new Error('Cannot specify both --include and --exclude options. Please use one or the other.');\n }\n\n // Clear any previous batch operations\n this.fileWriteBatch.clear();\n this.createdBackupFiles = [];\n this.createdBackupDirs.clear();\n \n let targetDir: string;\n let entityConfig: EntityConfig | null;\n \n // Check if we should use a specific target directory\n if (options.targetDir) {\n if (options.verbose) {\n callbacks?.onLog?.(`Using specified target directory: ${options.targetDir}`);\n }\n process.chdir(options.targetDir);\n targetDir = process.cwd();\n \n // Load entity config from the current directory\n entityConfig = await loadEntityConfig(targetDir);\n if (!entityConfig) {\n throw new Error(`No .mj-sync.json found in ${targetDir}`);\n }\n if (entityConfig.entity !== options.entity) {\n throw new Error(`Directory ${targetDir} is configured for entity \"${entityConfig.entity}\", not \"${options.entity}\"`);\n }\n } else {\n // Original behavior - find entity directory\n const entityDirs = await this.findEntityDirectories(options.entity);\n \n if (entityDirs.length === 0) {\n throw new Error(`No directory found for entity \"${options.entity}\". Run \"mj sync init\" first.`);\n }\n \n if (entityDirs.length === 1) {\n targetDir = entityDirs[0];\n } else {\n // Multiple directories found - in service mode, we'll use the first one\n // The CLI can handle prompting for selection\n throw new Error(`Multiple directories found for entity \"${options.entity}\". Please specify target directory.`);\n }\n \n entityConfig = await loadEntityConfig(targetDir);\n if (!entityConfig) {\n throw new Error(`Invalid entity configuration in ${targetDir}`);\n }\n }\n \n // Show configuration notice only if relevant and in verbose mode\n if (options.verbose && entityConfig?.pull?.appendRecordsToExistingFile && entityConfig?.pull?.newFileName) {\n const targetFile = path.join(targetDir, entityConfig.pull.newFileName.endsWith('.json') \n ? entityConfig.pull.newFileName \n : `${entityConfig.pull.newFileName}.json`);\n \n if (await fs.pathExists(targetFile)) {\n callbacks?.onLog?.(`\\nšŸ“ Configuration: New records will be appended to existing file '${path.basename(targetFile)}'`);\n }\n }\n \n // Pull records\n callbacks?.onProgress?.(`Pulling ${options.entity} records`);\n const rv = new RunView();\n \n let filter = '';\n if (options.filter) {\n filter = options.filter;\n } else if (entityConfig?.pull?.filter) {\n filter = entityConfig.pull.filter;\n }\n \n const result = await rv.RunView({\n EntityName: options.entity,\n ExtraFilter: filter,\n ResultType: 'entity_object'\n }, this.contextUser);\n \n if (!result.Success) {\n throw new Error(`Failed to pull records: ${result.ErrorMessage}`);\n }\n \n callbacks?.onSuccess?.(`Found ${result.Results.length} records`);\n \n if (options.dryRun) {\n callbacks?.onLog?.(`\\nDry run mode - would pull ${result.Results.length} records to ${targetDir}`);\n return {\n processed: 0,\n created: 0,\n updated: 0,\n skipped: 0,\n targetDir\n };\n }\n \n // Process records with error handling and rollback\n let pullResult: Omit<PullResult, 'targetDir'>;\n \n try {\n pullResult = await this.processRecords(\n result.Results,\n options,\n targetDir,\n entityConfig,\n callbacks\n );\n \n // Write all batched file changes at once\n if (!options.dryRun) {\n const filesWritten = await this.fileWriteBatch.flush();\n if (options.verbose && filesWritten > 0) {\n callbacks?.onSuccess?.(`Wrote ${filesWritten} files with consistent property ordering`);\n }\n }\n \n // Operation succeeded - clean up backup files\n if (!options.dryRun) {\n await this.cleanupBackupFiles();\n }\n \n } catch (error) {\n callbacks?.onError?.(`Pull operation failed: ${(error as any).message || error}`);\n \n // Attempt to rollback file changes if not in dry run mode\n if (!options.dryRun) {\n try {\n await this.rollbackFileChanges(callbacks);\n callbacks?.onWarn?.('File changes have been rolled back due to operation failure');\n } catch (rollbackError) {\n callbacks?.onError?.(`Rollback failed: ${(rollbackError as any).message || rollbackError}`);\n }\n }\n \n throw error;\n }\n \n return {\n ...pullResult,\n targetDir\n };\n }\n \n private async processRecords(\n records: BaseEntity[],\n options: PullOptions,\n targetDir: string,\n entityConfig: EntityConfig,\n callbacks?: PullCallbacks\n ): Promise<Omit<PullResult, 'targetDir'>> {\n const entityInfo = this.syncEngine.getEntityInfo(options.entity);\n if (!entityInfo) {\n throw new Error(`Entity information not found for: ${options.entity}`);\n }\n \n callbacks?.onProgress?.('Processing records');\n let processed = 0;\n let updated = 0;\n let created = 0;\n let skipped = 0;\n \n // If multi-file flag is set, collect all records\n if (options.multiFile) {\n const allRecords: RecordData[] = [];\n const errors: string[] = [];\n \n // Process records in parallel for multi-file mode\n const recordPromises = records.map(async (record, index) => {\n try {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = (record as any)[pk.Name];\n }\n \n // Process record for multi-file\n const recordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n options.verbose, \n true\n );\n \n return { success: true, recordData, index };\n } catch (error) {\n const errorMessage = `Failed to process record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, recordData: null, index };\n }\n });\n \n const recordResults = await Promise.all(recordPromises);\n \n // Collect successful records\n for (const result of recordResults) {\n if (result.success && result.recordData) {\n allRecords.push(result.recordData);\n processed++;\n }\n }\n \n if (options.verbose) {\n callbacks?.onProgress?.(`Processed ${processed}/${records.length} records in parallel`);\n }\n \n // Queue all records to single file for batched write\n if (allRecords.length > 0) {\n const fileName = options.multiFile.endsWith('.json') ? options.multiFile : `${options.multiFile}.json`;\n const filePath = path.join(targetDir, fileName);\n this.fileWriteBatch.queueWrite(filePath, allRecords);\n callbacks?.onSuccess?.(`Queued ${processed} records for ${path.basename(filePath)}`);\n }\n \n // If there were errors during parallel processing, throw them\n if (errors.length > 0) {\n throw new Error(`Multi-file processing completed with ${errors.length} errors:\\n${errors.join('\\n')}`);\n }\n } else {\n // Smart update logic for single-file-per-record\n const result = await this.processIndividualRecords(\n records,\n options,\n targetDir,\n entityConfig,\n entityInfo,\n callbacks\n );\n \n processed = result.processed;\n updated = result.updated;\n created = result.created;\n skipped = result.skipped;\n \n // Final status\n const statusParts = [`Processed ${processed} records`];\n if (updated > 0) statusParts.push(`updated ${updated}`);\n if (created > 0) statusParts.push(`created ${created}`);\n if (skipped > 0) statusParts.push(`skipped ${skipped}`);\n \n callbacks?.onSuccess?.(statusParts.join(', '));\n }\n \n return { processed, created, updated, skipped };\n }\n \n /**\n * Clean up backup files created during the pull operation\n * Should be called after successful pull operations to remove persistent backup files\n */\n async cleanupBackupFiles(): Promise<void> {\n if (this.createdBackupFiles.length === 0 && this.createdBackupDirs.size === 0) {\n return;\n }\n \n const errors: string[] = [];\n \n // Remove backup files\n for (const backupPath of this.createdBackupFiles) {\n try {\n if (await fs.pathExists(backupPath)) {\n await fs.remove(backupPath);\n }\n } catch (error) {\n errors.push(`Failed to remove backup file ${backupPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n \n // Remove empty backup directories\n for (const backupDir of this.createdBackupDirs) {\n try {\n await this.removeEmptyBackupDirectory(backupDir);\n } catch (error) {\n errors.push(`Failed to remove backup directory ${backupDir}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n \n // Clear the tracking arrays\n this.createdBackupFiles = [];\n this.createdBackupDirs.clear();\n \n if (errors.length > 0) {\n throw new Error(`Backup cleanup completed with errors:\\n${errors.join('\\n')}`);\n }\n }\n\n /**\n * Remove a backup directory if it's empty\n */\n private async removeEmptyBackupDirectory(backupDir: string): Promise<void> {\n try {\n // Check if directory exists\n if (!(await fs.pathExists(backupDir))) {\n return;\n }\n \n // Only remove if it's actually a .backups directory for safety\n if (!backupDir.endsWith('.backups')) {\n return;\n }\n \n // Check if directory is empty\n const files = await fs.readdir(backupDir);\n if (files.length === 0) {\n await fs.remove(backupDir);\n }\n } catch (error) {\n // Log error but don't throw - cleanup should be non-critical\n // The error will be caught by the caller and included in the error list\n throw error;\n }\n }\n \n /**\n * Get the list of backup files created during the current pull operation\n */\n getCreatedBackupFiles(): string[] {\n return [...this.createdBackupFiles];\n }\n \n /**\n * Rollback file changes by restoring from backup files\n * Called when pull operation fails after files have been modified\n */\n private async rollbackFileChanges(callbacks?: PullCallbacks): Promise<void> {\n if (this.createdBackupFiles.length === 0) {\n callbacks?.onLog?.('No backup files found - no rollback needed');\n return;\n }\n \n callbacks?.onProgress?.(`Rolling back ${this.createdBackupFiles.length} file changes...`);\n \n const errors: string[] = [];\n let restoredCount = 0;\n \n for (const backupPath of this.createdBackupFiles) {\n try {\n // Extract original file path from backup path\n const backupDir = path.dirname(backupPath);\n const backupFileName = path.basename(backupPath);\n \n // Remove timestamp and .backup extension to get original filename\n const originalFileName = backupFileName.replace(/\\.\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.backup$/, '.json');\n const originalFilePath = path.join(path.dirname(backupDir), originalFileName);\n \n if (await fs.pathExists(backupPath)) {\n await fs.copy(backupPath, originalFilePath);\n restoredCount++;\n }\n } catch (error) {\n errors.push(`Failed to restore ${backupPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n \n if (errors.length > 0) {\n throw new Error(`Rollback completed with ${errors.length} errors (${restoredCount} files restored):\\n${errors.join('\\n')}`);\n }\n \n callbacks?.onSuccess?.(`Successfully rolled back ${restoredCount} file changes`);\n }\n \n private async processIndividualRecords(\n records: BaseEntity[],\n options: PullOptions,\n targetDir: string,\n entityConfig: EntityConfig,\n entityInfo: EntityInfo,\n callbacks?: PullCallbacks\n ): Promise<{ processed: number; updated: number; created: number; skipped: number }> {\n let processed = 0;\n let updated = 0;\n let created = 0;\n let skipped = 0;\n \n // Find existing files\n const filePattern = entityConfig.pull?.filePattern || entityConfig.filePattern || '*.json';\n const existingFiles = await this.findExistingFiles(targetDir, filePattern);\n \n if (options.verbose) {\n callbacks?.onLog?.(`Found ${existingFiles.length} existing files matching pattern '${filePattern}'`);\n existingFiles.forEach(f => callbacks?.onLog?.(` - ${path.basename(f)}`));\n }\n \n // Load existing records and build lookup map\n const existingRecordsMap = await this.loadExistingRecords(existingFiles, entityInfo);\n \n if (options.verbose) {\n callbacks?.onLog?.(`Loaded ${existingRecordsMap.size} existing records from files`);\n }\n \n // Separate records into new and existing\n const newRecords: Array<{ record: BaseEntity; primaryKey: Record<string, any> }> = [];\n const existingRecordsToUpdate: Array<{ record: BaseEntity; primaryKey: Record<string, any>; filePath: string }> = [];\n \n for (const record of records) {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = (record as any)[pk.Name];\n }\n \n // Create lookup key\n const lookupKey = this.createPrimaryKeyLookup(primaryKey);\n const existingFileInfo = existingRecordsMap.get(lookupKey);\n \n if (existingFileInfo) {\n // Record exists locally\n if (entityConfig.pull?.updateExistingRecords !== false) {\n existingRecordsToUpdate.push({ record, primaryKey, filePath: existingFileInfo.filePath });\n } else {\n skipped++;\n if (options.verbose) {\n callbacks?.onLog?.(`Skipping existing record: ${lookupKey}`);\n }\n }\n } else {\n // Record doesn't exist locally\n if (entityConfig.pull?.createNewFileIfNotFound !== false) {\n newRecords.push({ record, primaryKey });\n } else {\n skipped++;\n if (options.verbose) {\n callbacks?.onLog?.(`Skipping new record (createNewFileIfNotFound=false): ${lookupKey}`);\n }\n }\n }\n }\n \n // Track which files have been backed up to avoid duplicates\n const backedUpFiles = new Set<string>();\n const errors: string[] = [];\n \n // Process existing records updates in parallel\n if (existingRecordsToUpdate.length > 0) {\n callbacks?.onProgress?.(`Updating existing records (parallel processing)`);\n \n const updatePromises = existingRecordsToUpdate.map(async ({ record, primaryKey, filePath }, index) => {\n try {\n // Create backup if configured (only once per file)\n if (entityConfig.pull?.backupBeforeUpdate && !backedUpFiles.has(filePath)) {\n await this.createBackup(filePath, entityConfig.pull?.backupDirectory);\n backedUpFiles.add(filePath);\n }\n \n // Load existing file data\n const existingData = await fs.readJson(filePath);\n \n // Find the specific existing record that matches this primary key\n let existingRecordData: RecordData;\n if (Array.isArray(existingData)) {\n // Find the matching record in the array\n const matchingRecord = existingData.find(r => \n this.createPrimaryKeyLookup(r.primaryKey || {}) === this.createPrimaryKeyLookup(primaryKey)\n );\n existingRecordData = matchingRecord || existingData[0]; // Fallback to first if not found\n } else {\n existingRecordData = existingData;\n }\n \n // Process the new record data (isNewRecord = false for updates)\n const newRecordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n options.verbose, \n false, \n existingRecordData\n );\n \n // Apply merge strategy\n const mergedData = await this.mergeRecords(\n existingRecordData,\n newRecordData,\n entityConfig.pull?.mergeStrategy || 'merge',\n entityConfig.pull?.preserveFields || []\n );\n \n // Queue updated data for batched write\n if (Array.isArray(existingData)) {\n // Queue array update - batch will handle merging\n const primaryKeyLookup = this.createPrimaryKeyLookup(primaryKey);\n this.fileWriteBatch.queueArrayUpdate(filePath, mergedData, primaryKeyLookup);\n } else {\n // Queue single record update\n this.fileWriteBatch.queueSingleUpdate(filePath, mergedData);\n }\n \n if (options.verbose) {\n callbacks?.onLog?.(`Updated: ${filePath}`);\n }\n \n return { success: true, index };\n } catch (error) {\n const errorMessage = `Failed to update record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, index };\n }\n });\n \n const updateResults = await Promise.all(updatePromises);\n updated = updateResults.filter(r => r.success).length;\n processed += updated;\n \n if (options.verbose) {\n callbacks?.onSuccess?.(`Completed ${updated}/${existingRecordsToUpdate.length} record updates`);\n }\n }\n \n // Process new records in parallel\n if (newRecords.length > 0) {\n callbacks?.onProgress?.(`Creating new records (parallel processing)`);\n \n if (entityConfig.pull?.appendRecordsToExistingFile && entityConfig.pull?.newFileName) {\n // Append all new records to a single file using parallel processing\n const fileName = entityConfig.pull.newFileName.endsWith('.json') \n ? entityConfig.pull.newFileName \n : `${entityConfig.pull.newFileName}.json`;\n const filePath = path.join(targetDir, fileName);\n \n // Process all new records in parallel\n const newRecordPromises = newRecords.map(async ({ record, primaryKey }, index) => {\n try {\n // For new records, pass isNewRecord = true (default)\n const recordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n options.verbose, \n true\n );\n \n // Use queueArrayUpdate to append the new record without overwriting existing updates\n // For new records, we can use a special lookup key since they don't exist yet\n const newRecordLookup = this.createPrimaryKeyLookup(primaryKey);\n this.fileWriteBatch.queueArrayUpdate(filePath, recordData, newRecordLookup);\n \n return { success: true, index };\n } catch (error) {\n const errorMessage = `Failed to process new record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, index };\n }\n });\n \n const newRecordResults = await Promise.all(newRecordPromises);\n created = newRecordResults.filter(r => r.success).length;\n processed += created;\n \n if (options.verbose) {\n callbacks?.onLog?.(`Queued ${created} new records for: ${filePath}`);\n }\n } else {\n // Create individual files for each new record in parallel\n const individualRecordPromises = newRecords.map(async ({ record, primaryKey }, index) => {\n try {\n await this.processRecord(record, primaryKey, targetDir, entityConfig, options.verbose);\n return { success: true, index };\n } catch (error) {\n const errorMessage = `Failed to process new record ${index + 1}: ${(error as any).message || error}`;\n errors.push(errorMessage);\n callbacks?.onWarn?.(errorMessage);\n return { success: false, index };\n }\n });\n \n const individualResults = await Promise.all(individualRecordPromises);\n created = individualResults.filter(r => r.success).length;\n processed += created;\n \n if (options.verbose) {\n callbacks?.onSuccess?.(`Created ${created}/${newRecords.length} individual record files`);\n }\n }\n }\n \n // If there were errors during parallel processing, throw them\n if (errors.length > 0) {\n throw new Error(`Parallel processing completed with ${errors.length} errors:\\n${errors.join('\\n')}`);\n }\n \n return { processed, updated, created, skipped };\n }\n \n private async processRecord(\n record: BaseEntity, \n primaryKey: Record<string, any>,\n targetDir: string, \n entityConfig: EntityConfig,\n verbose?: boolean\n ): Promise<void> {\n const recordData = await this.recordProcessor.processRecord(\n record, \n primaryKey, \n targetDir, \n entityConfig, \n verbose, \n true\n );\n \n // Determine file path\n const fileName = this.buildFileName(primaryKey, entityConfig);\n const filePath = path.join(targetDir, fileName);\n \n // Queue JSON file for batched write with controlled property order\n this.fileWriteBatch.queueWrite(filePath, recordData);\n }\n\n \n\n\n\n private async findEntityDirectories(entityName: string): Promise<string[]> {\n const dirs: string[] = [];\n \n // Search for directories with matching entity config\n const searchDirs = async (dir: string) => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(dir, entry.name);\n const config = await loadEntityConfig(fullPath);\n \n if (config && config.entity === entityName) {\n dirs.push(fullPath);\n } else {\n // Recurse\n await searchDirs(fullPath);\n }\n }\n }\n };\n \n await searchDirs(configManager.getOriginalCwd());\n return dirs;\n }\n \n private buildFileName(primaryKey: Record<string, any>, _entityConfig: EntityConfig): string {\n // Use primary key values to build filename\n const keys = Object.values(primaryKey);\n \n if (keys.length === 1 && typeof keys[0] === 'string') {\n // Single string key - use as base if it's a guid\n const key = keys[0];\n if (key.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {\n // It's a GUID, use first 8 chars, prefixed with dot, lowercase\n return `.${key.substring(0, 8).toLowerCase()}.json`;\n }\n // Use the whole key if not too long, prefixed with dot\n if (key.length <= 50) {\n return `.${key.replace(/[^a-zA-Z0-9\\-_]/g, '').toLowerCase()}.json`;\n }\n }\n \n // Multiple keys or numeric - create composite name, prefixed with dot\n return '.' + keys.map(k => String(k).replace(/[^a-zA-Z0-9\\-_]/g, '').toLowerCase()).join('-') + '.json';\n }\n \n private async findExistingFiles(dir: string, pattern: string): Promise<string[]> {\n const files: string[] = [];\n\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isFile()) {\n const fileName = entry.name;\n\n // Normalize pattern by removing leading **/ (glob recursion prefix)\n const normalizedPattern = pattern.startsWith('**/') ? pattern.substring(3) : pattern;\n\n // Simple pattern matching\n if (normalizedPattern === '*.json' && fileName.endsWith('.json')) {\n files.push(path.join(dir, fileName));\n } else if (normalizedPattern === '.*.json' && fileName.startsWith('.') && fileName.endsWith('.json')) {\n files.push(path.join(dir, fileName));\n } else if (normalizedPattern === fileName) {\n files.push(path.join(dir, fileName));\n }\n }\n }\n } catch (error) {\n // Directory might not exist yet\n if ((error as any).code !== 'ENOENT') {\n throw error;\n }\n }\n\n return files;\n }\n \n private async loadExistingRecords(\n files: string[], \n _entityInfo: EntityInfo\n ): Promise<Map<string, { filePath: string; recordData: RecordData }>> {\n const recordsMap = new Map<string, { filePath: string; recordData: RecordData }>();\n \n for (const filePath of files) {\n try {\n const fileData = await fs.readJson(filePath);\n const records = Array.isArray(fileData) ? fileData : [fileData];\n \n for (const record of records) {\n if (record.primaryKey) {\n const lookupKey = this.createPrimaryKeyLookup(record.primaryKey);\n recordsMap.set(lookupKey, { filePath, recordData: record });\n }\n }\n } catch (error) {\n // Skip files that can't be parsed\n }\n }\n \n return recordsMap;\n }\n \n private createPrimaryKeyLookup(primaryKey: Record<string, any>): string {\n const keys = Object.keys(primaryKey).sort();\n return keys.map(k => `${k}:${primaryKey[k]}`).join('|');\n }\n \n private async mergeRecords(\n existing: RecordData,\n newData: RecordData,\n strategy: 'overwrite' | 'merge' | 'skip',\n preserveFields: string[]\n ): Promise<RecordData> {\n if (strategy === 'skip') {\n return existing;\n }\n\n if (strategy === 'overwrite') {\n // Create result with correct property order: fields, relatedEntities, primaryKey, sync\n const result: RecordData = {\n fields: { ...newData.fields }\n } as RecordData;\n\n // Restore preserved fields from existing\n if (preserveFields.length > 0 && existing.fields) {\n for (const field of preserveFields) {\n if (field in existing.fields) {\n result.fields[field] = existing.fields[field];\n }\n }\n }\n\n // Add relatedEntities before primaryKey and sync\n if (newData.relatedEntities) {\n result.relatedEntities = newData.relatedEntities;\n }\n\n result.primaryKey = newData.primaryKey;\n result.sync = newData.sync;\n\n return result;\n }\n\n // Default 'merge' strategy - create with correct property order\n const result: RecordData = {\n fields: { ...existing.fields, ...newData.fields }\n } as RecordData;\n\n // Restore preserved fields\n if (preserveFields.length > 0 && existing.fields) {\n for (const field of preserveFields) {\n if (field in existing.fields) {\n result.fields[field] = existing.fields[field];\n }\n }\n }\n\n // Add relatedEntities before primaryKey and sync\n if (existing.relatedEntities || newData.relatedEntities) {\n result.relatedEntities = {\n ...existing.relatedEntities,\n ...newData.relatedEntities\n };\n }\n\n result.primaryKey = newData.primaryKey || existing.primaryKey;\n result.sync = newData.sync;\n\n return result;\n }\n \n private async createBackup(filePath: string, backupDirName?: string): Promise<void> {\n const dir = path.dirname(filePath);\n const fileName = path.basename(filePath);\n const backupDir = path.join(dir, backupDirName || '.backups');\n \n // Ensure backup directory exists\n await fs.ensureDir(backupDir);\n // Track the backup directory for cleanup\n this.createdBackupDirs.add(backupDir);\n \n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n // Remove .json extension, add timestamp, then add .backup extension\n const backupFileName = fileName.replace(/\\.json$/, `.${timestamp}.backup`);\n const backupPath = path.join(backupDir, backupFileName);\n \n try {\n await fs.copy(filePath, backupPath);\n // Track the created backup file for cleanup\n this.createdBackupFiles.push(backupPath);\n } catch (error) {\n // Log error but don't throw\n }\n }\n}"]}
@@ -544,14 +544,44 @@ class PushService {
544
544
  if (!entity) {
545
545
  throw new Error(`Failed to create entity object for ${entityName}`);
546
546
  }
547
+ // Get parent entity from context if available (needed for @parent refs in primaryKey)
548
+ let parentEntity = null;
549
+ if (parentContext) {
550
+ const parentRecordId = flattenedRecord.dependencies.values().next().value;
551
+ if (parentRecordId) {
552
+ parentEntity = batchContext.get(parentRecordId) || null;
553
+ }
554
+ if (!parentEntity) {
555
+ throw new Error(`Parent entity not found in batch context for ${entityName}. Parent dependencies: ${Array.from(flattenedRecord.dependencies).join(', ')}`);
556
+ }
557
+ }
547
558
  // Check if record exists
548
- const primaryKey = record.primaryKey;
559
+ // Process primaryKey values through processFieldValue to resolve @lookup, @parent, etc.
560
+ // Create a resolution collector to track @lookup and @parent resolutions
561
+ const resolutionCollector = { notes: [], fieldPrefix: 'primaryKey' };
562
+ let resolvedPrimaryKey;
563
+ if (record.primaryKey && Object.keys(record.primaryKey).length > 0) {
564
+ resolvedPrimaryKey = {};
565
+ for (const [pkField, pkValue] of Object.entries(record.primaryKey)) {
566
+ try {
567
+ resolvedPrimaryKey[pkField] = await this.syncEngine.processFieldValue(pkValue, entityDir, parentEntity, null, // rootRecord
568
+ 0, batchContext, resolutionCollector, pkField);
569
+ }
570
+ catch (pkError) {
571
+ // Check if this is a deferrable lookup error
572
+ if (pkError instanceof sync_engine_1.DeferrableLookupError) {
573
+ throw new Error(`Cannot defer lookup in primaryKey field '${pkField}': ${pkError.message}. Primary key lookups must resolve immediately.`);
574
+ }
575
+ throw pkError;
576
+ }
577
+ }
578
+ }
549
579
  let exists = false;
550
580
  let isNew = false;
551
- if (primaryKey && Object.keys(primaryKey).length > 0) {
581
+ if (resolvedPrimaryKey && Object.keys(resolvedPrimaryKey).length > 0) {
552
582
  // First check if the record exists using the sync engine's loadEntity method
553
583
  // This avoids the "Error in BaseEntity.Load" message for missing records
554
- const existingEntity = await this.syncEngine.loadEntity(entityName, primaryKey);
584
+ const existingEntity = await this.syncEngine.loadEntity(entityName, resolvedPrimaryKey);
555
585
  if (existingEntity) {
556
586
  // Record exists, use the loaded entity
557
587
  entity = existingEntity;
@@ -560,7 +590,7 @@ class PushService {
560
590
  else {
561
591
  // Record doesn't exist in database
562
592
  const autoCreate = this.syncConfig?.push?.autoCreateMissingRecords ?? false;
563
- const pkDisplay = Object.entries(primaryKey)
593
+ const pkDisplay = Object.entries(resolvedPrimaryKey)
564
594
  .map(([key, value]) => `${key}=${value}`)
565
595
  .join(', ');
566
596
  if (!autoCreate) {
@@ -580,9 +610,9 @@ class PushService {
580
610
  if (!exists) {
581
611
  entity.NewRecord();
582
612
  isNew = true;
583
- // Set primary key values for new records if provided
584
- if (primaryKey) {
585
- for (const [pkField, pkValue] of Object.entries(primaryKey)) {
613
+ // Set primary key values for new records if provided (use resolved values)
614
+ if (resolvedPrimaryKey) {
615
+ for (const [pkField, pkValue] of Object.entries(resolvedPrimaryKey)) {
586
616
  entity.Set(pkField, pkValue);
587
617
  }
588
618
  }
@@ -599,29 +629,18 @@ class PushService {
599
629
  }
600
630
  // Store original field values to preserve @ references
601
631
  const originalFields = { ...record.fields };
602
- // Get parent entity from context if available
603
- let parentEntity = null;
604
- if (parentContext) {
605
- // Find the parent's flattened record ID
606
- // The parent record was flattened before this child, so it should have a lower ID number
607
- const parentRecordId = flattenedRecord.dependencies.values().next().value;
608
- if (parentRecordId) {
609
- parentEntity = batchContext.get(parentRecordId) || null;
610
- }
611
- if (!parentEntity) {
612
- // Parent should have been processed before child due to dependency ordering
613
- throw new Error(`Parent entity not found in batch context for ${entityName}. Parent dependencies: ${Array.from(flattenedRecord.dependencies).join(', ')}`);
614
- }
615
- }
616
632
  // Process field values with parent context and batch context
633
+ // Note: parentEntity was already resolved above for primaryKey processing
617
634
  // Process each field with better error reporting
618
635
  // Track if we hit any deferrable lookup errors
619
636
  let hasDeferrableLookupError = false;
637
+ // Switch the collector to track field resolutions
638
+ resolutionCollector.fieldPrefix = 'fields';
620
639
  for (const [fieldName, fieldValue] of Object.entries(record.fields)) {
621
640
  try {
622
641
  const processedValue = await this.syncEngine.processFieldValue(fieldValue, entityDir, parentEntity, null, // rootRecord
623
- 0, batchContext // Pass batch context for lookups
624
- );
642
+ 0, batchContext, // Pass batch context for lookups
643
+ resolutionCollector, fieldName);
625
644
  entity.Set(fieldName, processedValue);
626
645
  }
627
646
  catch (fieldError) {
@@ -804,15 +823,9 @@ class PushService {
804
823
  logError(` File Path: ${flattenedRecord.path}`);
805
824
  // Log the LatestResult for debugging
806
825
  if (entity.LatestResult) {
807
- if (entity.LatestResult.Message) {
808
- logError(` Database Message: ${entity.LatestResult.Message}`);
809
- }
810
- if (entity.LatestResult.Errors && entity.LatestResult.Errors.length > 0) {
811
- logError(` Errors:`);
812
- entity.LatestResult.Errors.forEach((err, idx) => {
813
- const errorMsg = typeof err === 'string' ? err : (err?.message || JSON.stringify(err));
814
- logError(` ${idx + 1}. ${errorMsg}`);
815
- });
826
+ const completeMessage = entity.LatestResult.CompleteMessage;
827
+ if (completeMessage) {
828
+ logError(` Database Error: ${completeMessage}`);
816
829
  }
817
830
  if (entity.LatestResult.SQL) {
818
831
  // Don't log the full SQL as it might be huge, just indicate it's available
@@ -848,7 +861,7 @@ class PushService {
848
861
  fieldInfo.push(`${fieldName}=${this.formatFieldValue(processedValue)}`);
849
862
  }
850
863
  // Get the actual error details from the entity
851
- const errorMessage = entity.LatestResult?.Message || 'Unknown error';
864
+ const errorMessage = entity.LatestResult?.CompleteMessage || 'Unknown error';
852
865
  const errorDetails = entity.LatestResult?.Errors?.map(err => typeof err === 'string' ? err : (err?.message || JSON.stringify(err)))?.join(', ') || '';
853
866
  // Log detailed error information
854
867
  callbacks?.onError?.(`\nāŒ FATAL ERROR: Failed to save ${entityName} record`);
@@ -920,6 +933,21 @@ class PushService {
920
933
  }
921
934
  // Restore original field values to preserve @ references
922
935
  record.fields = originalFields;
936
+ // Only update __mj_sync_notes if the record was actually dirty (changed)
937
+ // For unchanged records, preserve existing notes to maintain stability
938
+ if (isNew || isDirty) {
939
+ // Update __mj_sync_notes with resolution information
940
+ // This helps users understand how @lookup and @parent references were resolved
941
+ // Use type assertion through unknown to handle the dynamic property
942
+ const recordWithNotes = record;
943
+ if (resolutionCollector.notes.length > 0) {
944
+ recordWithNotes.__mj_sync_notes = resolutionCollector.notes;
945
+ }
946
+ else {
947
+ // Remove existing notes if no resolutions were tracked
948
+ delete recordWithNotes.__mj_sync_notes;
949
+ }
950
+ }
923
951
  // Return appropriate status
924
952
  // If we had deferred lookups, return 'deferred' to indicate partial save
925
953
  // The record is saved but will be re-processed in Phase 2.5
@@ -1015,7 +1043,7 @@ class PushService {
1015
1043
  const deleteResult = await existingEntity.Delete();
1016
1044
  if (!deleteResult) {
1017
1045
  // Check the LatestResult for error details
1018
- const errorMessage = existingEntity.LatestResult?.Message || 'Unknown error';
1046
+ const errorMessage = existingEntity.LatestResult?.CompleteMessage || 'Unknown error';
1019
1047
  const errorDetails = existingEntity.LatestResult?.Errors?.map(err => typeof err === 'string' ? err : (err?.message || JSON.stringify(err)))?.join(', ') || '';
1020
1048
  callbacks?.onError?.(`\nāŒ Failed to delete ${entityName} record`);
1021
1049
  callbacks?.onError?.(` Primary Key: {${primaryKeyDisplay.join(', ')}}`);