@memberjunction/metadata-sync 2.117.0 → 2.118.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 (37) hide show
  1. package/README.md +24 -0
  2. package/dist/index.d.ts +9 -0
  3. package/dist/index.js +12 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/database-reference-scanner.d.ts +56 -0
  6. package/dist/lib/database-reference-scanner.js +175 -0
  7. package/dist/lib/database-reference-scanner.js.map +1 -0
  8. package/dist/lib/deletion-auditor.d.ts +76 -0
  9. package/dist/lib/deletion-auditor.js +219 -0
  10. package/dist/lib/deletion-auditor.js.map +1 -0
  11. package/dist/lib/deletion-report-generator.d.ts +58 -0
  12. package/dist/lib/deletion-report-generator.js +287 -0
  13. package/dist/lib/deletion-report-generator.js.map +1 -0
  14. package/dist/lib/entity-foreign-key-helper.d.ts +51 -0
  15. package/dist/lib/entity-foreign-key-helper.js +83 -0
  16. package/dist/lib/entity-foreign-key-helper.js.map +1 -0
  17. package/dist/lib/provider-utils.d.ts +9 -1
  18. package/dist/lib/provider-utils.js +42 -5
  19. package/dist/lib/provider-utils.js.map +1 -1
  20. package/dist/lib/record-dependency-analyzer.d.ts +44 -0
  21. package/dist/lib/record-dependency-analyzer.js +133 -0
  22. package/dist/lib/record-dependency-analyzer.js.map +1 -1
  23. package/dist/services/PullService.d.ts +2 -0
  24. package/dist/services/PullService.js +4 -0
  25. package/dist/services/PullService.js.map +1 -1
  26. package/dist/services/PushService.d.ts +42 -2
  27. package/dist/services/PushService.js +451 -109
  28. package/dist/services/PushService.js.map +1 -1
  29. package/dist/services/StatusService.d.ts +2 -0
  30. package/dist/services/StatusService.js +5 -1
  31. package/dist/services/StatusService.js.map +1 -1
  32. package/dist/services/ValidationService.d.ts +4 -0
  33. package/dist/services/ValidationService.js +32 -2
  34. package/dist/services/ValidationService.js.map +1 -1
  35. package/dist/types/validation.d.ts +2 -0
  36. package/dist/types/validation.js.map +1 -1
  37. package/package.json +9 -8
@@ -1 +1 @@
1
- {"version":3,"file":"record-dependency-analyzer.js","sourceRoot":"","sources":["../../src/lib/record-dependency-analyzer.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata, EntityInfo } from '@memberjunction/core';\nimport { RecordData } from './sync-engine';\nimport { METADATA_KEYWORDS, isNonKeywordAtSymbol } from '../constants/metadata-keywords';\n\n/**\n * Represents a flattened record with its context and dependencies\n */\nexport interface FlattenedRecord {\n record: RecordData;\n entityName: string;\n parentContext?: {\n entityName: string;\n record: RecordData;\n recordIndex: number;\n };\n depth: number;\n path: string; // Path to this record for debugging\n dependencies: Set<string>; // Set of record IDs this record depends on\n id: string; // Unique identifier for this record in the flattened list\n originalIndex: number; // Original index in the source array\n}\n\n/**\n * Result of dependency analysis\n */\nexport interface DependencyAnalysisResult {\n sortedRecords: FlattenedRecord[];\n circularDependencies: string[][];\n dependencyGraph: Map<string, Set<string>>;\n dependencyLevels?: FlattenedRecord[][]; // Records grouped by dependency level for parallel processing\n}\n\n/**\n * Analyzes and sorts records based on their dependencies\n */\nexport class RecordDependencyAnalyzer {\n private metadata: Metadata;\n private flattenedRecords: FlattenedRecord[] = [];\n private recordIdMap: Map<string, FlattenedRecord> = new Map();\n private entityInfoCache: Map<string, EntityInfo> = new Map();\n private recordCounter: number = 0;\n\n constructor() {\n this.metadata = new Metadata();\n }\n\n /**\n * Main entry point: analyzes all records in a file and returns them in dependency order\n */\n public async analyzeFileRecords(\n records: RecordData[],\n entityName: string\n ): Promise<DependencyAnalysisResult> {\n // Reset state\n this.flattenedRecords = [];\n this.recordIdMap.clear();\n this.recordCounter = 0;\n\n // Step 1: Flatten all records (including nested relatedEntities)\n this.flattenRecords(records, entityName);\n\n // Step 2: Analyze dependencies between all flattened records\n this.analyzeDependencies();\n\n // Step 3: Detect circular dependencies\n const circularDeps = this.detectCircularDependencies();\n\n // Step 4: Perform topological sort\n const sortedRecords = this.topologicalSort();\n\n // Step 5: Build dependency graph for debugging\n const dependencyGraph = new Map<string, Set<string>>();\n for (const record of this.flattenedRecords) {\n dependencyGraph.set(record.id, record.dependencies);\n }\n\n // Step 6: Group records into dependency levels for parallel processing\n const dependencyLevels = this.groupByDependencyLevels(sortedRecords, dependencyGraph);\n\n return {\n sortedRecords,\n circularDependencies: circularDeps,\n dependencyGraph,\n dependencyLevels\n };\n }\n\n /**\n * Flattens all records including nested relatedEntities\n */\n private flattenRecords(\n records: RecordData[],\n entityName: string,\n parentContext?: FlattenedRecord['parentContext'],\n depth: number = 0,\n pathPrefix: string = '',\n parentRecordId?: string\n ): void {\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const recordId = `${entityName}_${this.recordCounter++}`;\n const path = pathPrefix ? `${pathPrefix}/${entityName}[${i}]` : `${entityName}[${i}]`;\n\n const flattenedRecord: FlattenedRecord = {\n record,\n entityName,\n parentContext,\n depth,\n path,\n dependencies: new Set(),\n id: recordId,\n originalIndex: i\n };\n\n // If this has a parent, add dependency on the parent\n if (parentRecordId) {\n flattenedRecord.dependencies.add(parentRecordId);\n }\n\n this.flattenedRecords.push(flattenedRecord);\n this.recordIdMap.set(recordId, flattenedRecord);\n\n // Recursively flatten related entities\n if (record.relatedEntities) {\n for (const [relatedEntityName, relatedRecords] of Object.entries(record.relatedEntities)) {\n this.flattenRecords(\n relatedRecords,\n relatedEntityName,\n {\n entityName,\n record,\n recordIndex: i\n },\n depth + 1,\n path,\n recordId // Pass current record ID as parent for children\n );\n }\n }\n }\n }\n\n /**\n * Analyzes dependencies between all flattened records\n */\n private analyzeDependencies(): void {\n for (const record of this.flattenedRecords) {\n // Get entity info for foreign key relationships\n const entityInfo = this.getEntityInfo(record.entityName);\n if (!entityInfo) continue;\n\n // Analyze field dependencies\n if (record.record.fields) {\n for (const [fieldName, fieldValue] of Object.entries(record.record.fields)) {\n if (typeof fieldValue === 'string') {\n // Handle @lookup references\n if (fieldValue.startsWith(METADATA_KEYWORDS.LOOKUP)) {\n const dependency = this.findLookupDependency(fieldValue, record);\n if (dependency) {\n record.dependencies.add(dependency);\n }\n }\n // Handle @root references - these create dependencies on the root record\n else if (fieldValue.startsWith(METADATA_KEYWORDS.ROOT)) {\n const rootDependency = this.findRootDependency(record);\n if (rootDependency) {\n record.dependencies.add(rootDependency);\n }\n }\n // @parent references don't create explicit dependencies in our flattened structure\n // because parent is guaranteed to be processed before children due to the way\n // we flatten records (parent always comes before its children)\n }\n }\n }\n\n // Check foreign key dependencies\n this.analyzeForeignKeyDependencies(record, entityInfo);\n }\n }\n\n /**\n * Analyzes foreign key dependencies based on EntityInfo\n */\n private analyzeForeignKeyDependencies(record: FlattenedRecord, entityInfo: EntityInfo): void {\n // Check all foreign key fields\n for (const field of entityInfo.ForeignKeys) {\n const fieldValue = record.record.fields?.[field.Name];\n if (fieldValue && typeof fieldValue === 'string' && !fieldValue.startsWith('@')) {\n // This is a direct foreign key value, find the referenced record\n const relatedEntityInfo = this.getEntityInfo(field.RelatedEntity);\n if (relatedEntityInfo) {\n const dependency = this.findRecordByPrimaryKey(\n field.RelatedEntity,\n fieldValue,\n relatedEntityInfo\n );\n if (dependency) {\n record.dependencies.add(dependency);\n }\n }\n }\n }\n }\n\n /**\n * Finds a record that matches a @lookup reference\n */\n private findLookupDependency(lookupValue: string, currentRecord: FlattenedRecord): string | null {\n // Parse lookup format: @lookup:EntityName.Field=Value or @lookup:Field=Value\n const lookupStr = lookupValue.substring(8); // Remove '@lookup:'\n \n // Handle the ?create syntax by removing it\n const cleanLookup = lookupStr.split('?')[0];\n \n // Parse entity name if present\n let targetEntity: string;\n let criteria: string;\n \n if (cleanLookup.includes('.')) {\n const parts = cleanLookup.split('.');\n targetEntity = parts[0];\n criteria = parts.slice(1).join('.');\n } else {\n // Same entity if not specified\n targetEntity = currentRecord.entityName;\n criteria = cleanLookup;\n }\n\n // Parse criteria (can be multiple with &)\n const criteriaMap = new Map<string, string>();\n for (const pair of criteria.split('&')) {\n const [field, value] = pair.split('=');\n if (field && value) {\n let resolvedValue = value.trim();\n \n // Special handling for nested @lookup references in lookup criteria\n // This creates a dependency on the looked-up record\n if (resolvedValue.startsWith(METADATA_KEYWORDS.LOOKUP)) {\n const nestedDependency = this.findLookupDependency(resolvedValue, currentRecord);\n if (nestedDependency) {\n // Add this as a dependency of the current record\n currentRecord.dependencies.add(nestedDependency);\n // Continue processing - we can't resolve the actual value here\n // but we've recorded the dependency\n }\n }\n // Special handling for @root references in lookup criteria\n else if (resolvedValue.startsWith(METADATA_KEYWORDS.ROOT)) {\n // Add dependency on root record\n const rootDep = this.findRootDependency(currentRecord);\n if (rootDep) {\n currentRecord.dependencies.add(rootDep);\n }\n // Note: We can't resolve the actual value here, but we've recorded the dependency\n }\n // Special handling for @parent references in lookup criteria\n // If the value is @parent:field, we need to resolve it from the parent context\n else if (resolvedValue.startsWith(METADATA_KEYWORDS.PARENT) && currentRecord.parentContext) {\n const parentField = resolvedValue.substring(METADATA_KEYWORDS.PARENT.length);\n \n // Try to resolve from parent context\n const parentValue = currentRecord.parentContext.record.fields?.[parentField] ||\n currentRecord.parentContext.record.primaryKey?.[parentField];\n \n if (parentValue && typeof parentValue === 'string') {\n // Check if parent value is also a @parent reference (nested parent refs)\n if (parentValue.startsWith(METADATA_KEYWORDS.PARENT)) {\n // Find the parent record to get its parent context\n const parentRecord = this.flattenedRecords.find(r =>\n r.record === currentRecord.parentContext!.record &&\n r.entityName === currentRecord.parentContext!.entityName\n );\n\n if (parentRecord && parentRecord.parentContext) {\n const grandParentField = parentValue.substring(METADATA_KEYWORDS.PARENT.length);\n const grandParentValue = parentRecord.parentContext.record.fields?.[grandParentField] ||\n parentRecord.parentContext.record.primaryKey?.[grandParentField];\n if (grandParentValue && typeof grandParentValue === 'string' && !grandParentValue.startsWith('@')) {\n resolvedValue = grandParentValue;\n }\n }\n } else if (!parentValue.startsWith('@')) {\n resolvedValue = parentValue;\n }\n }\n }\n \n criteriaMap.set(field.trim(), resolvedValue);\n }\n }\n\n // Find matching record in our flattened list\n for (const candidate of this.flattenedRecords) {\n if (candidate.entityName !== targetEntity) continue;\n if (candidate.id === currentRecord.id) continue; // Skip self\n\n // Check if all criteria match\n let allMatch = true;\n for (const [field, value] of criteriaMap) {\n let candidateValue = candidate.record.fields?.[field] || \n candidate.record.primaryKey?.[field];\n let lookupValue = value;\n \n // Resolve candidate value if it's a @parent reference\n if (typeof candidateValue === 'string' && candidateValue.startsWith(METADATA_KEYWORDS.PARENT) && candidate.parentContext) {\n const parentField = candidateValue.substring(METADATA_KEYWORDS.PARENT.length);\n const parentRecord = candidate.parentContext.record;\n candidateValue = parentRecord.fields?.[parentField] || parentRecord.primaryKey?.[parentField];\n\n // If the parent field is also a @parent reference, resolve it recursively\n if (typeof candidateValue === 'string' && candidateValue.startsWith(METADATA_KEYWORDS.PARENT)) {\n // Find the candidate's parent in our flattened list\n const candidateParent = this.flattenedRecords.find(r => \n r.record === candidate.parentContext!.record && \n r.entityName === candidate.parentContext!.entityName\n );\n if (candidateParent?.parentContext) {\n const grandParentField = candidateValue.substring(8);\n candidateValue = candidateParent.parentContext.record.fields?.[grandParentField] || \n candidateParent.parentContext.record.primaryKey?.[grandParentField];\n }\n }\n }\n \n // Resolve lookup value if it contains @parent reference\n if (typeof lookupValue === 'string' && lookupValue.includes(METADATA_KEYWORDS.PARENT)) {\n // Handle cases like \"@parent:AgentID\" or embedded references\n if (lookupValue.startsWith(METADATA_KEYWORDS.PARENT) && currentRecord.parentContext) {\n const parentField = lookupValue.substring(METADATA_KEYWORDS.PARENT.length);\n lookupValue = currentRecord.parentContext.record.fields?.[parentField] ||\n currentRecord.parentContext.record.primaryKey?.[parentField];\n\n // If still a reference, try to resolve from the parent's parent\n if (typeof lookupValue === 'string' && lookupValue.startsWith(METADATA_KEYWORDS.PARENT)) {\n const currentParent = this.flattenedRecords.find(r =>\n r.record === currentRecord.parentContext!.record &&\n r.entityName === currentRecord.parentContext!.entityName\n );\n if (currentParent?.parentContext) {\n const grandParentField = lookupValue.substring(METADATA_KEYWORDS.PARENT.length);\n lookupValue = currentParent.parentContext.record.fields?.[grandParentField] ||\n currentParent.parentContext.record.primaryKey?.[grandParentField];\n }\n }\n }\n }\n\n // Special case: if both values are @parent references pointing to the same parent field,\n // and they have the same parent context, they match\n if (value.startsWith(METADATA_KEYWORDS.PARENT) && candidateValue === value && \n currentRecord.parentContext && candidate.parentContext) {\n // Check if they share the same parent\n if (currentRecord.parentContext.record === candidate.parentContext.record) {\n // Same parent, same reference - they will resolve to the same value\n continue; // This criterion matches\n }\n }\n \n if (candidateValue !== lookupValue) {\n allMatch = false;\n break;\n }\n }\n\n if (allMatch) {\n return candidate.id;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the root record for a given record\n */\n private findRootDependency(record: FlattenedRecord): string | null {\n // If this record has no parent, it IS the root, no dependency\n if (!record.parentContext) {\n return null;\n }\n \n // Walk up the parent chain to find the root\n let current = record;\n while (current.parentContext) {\n // Try to find the parent record in our flattened list\n const parentRecord = this.flattenedRecords.find(r => \n r.record === current.parentContext!.record && \n r.entityName === current.parentContext!.entityName\n );\n \n if (!parentRecord) {\n // Parent not found, something is wrong\n return null;\n }\n \n // If this parent has no parent, it's the root\n if (!parentRecord.parentContext) {\n return parentRecord.id;\n }\n \n current = parentRecord;\n }\n \n return null;\n }\n\n /**\n * Finds a record by its primary key value\n */\n private findRecordByPrimaryKey(\n entityName: string,\n primaryKeyValue: string,\n entityInfo: EntityInfo\n ): string | null {\n // Get primary key field name\n const primaryKeyField = entityInfo.PrimaryKeys[0]?.Name;\n if (!primaryKeyField) return null;\n\n for (const candidate of this.flattenedRecords) {\n if (candidate.entityName !== entityName) continue;\n\n const candidateValue = candidate.record.primaryKey?.[primaryKeyField] ||\n candidate.record.fields?.[primaryKeyField];\n if (candidateValue === primaryKeyValue) {\n return candidate.id;\n }\n }\n\n return null;\n }\n\n /**\n * Gets EntityInfo from cache or metadata\n */\n private getEntityInfo(entityName: string): EntityInfo | null {\n if (!this.entityInfoCache.has(entityName)) {\n const info = this.metadata.EntityByName(entityName);\n if (info) {\n this.entityInfoCache.set(entityName, info);\n }\n }\n return this.entityInfoCache.get(entityName) || null;\n }\n\n /**\n * Detects circular dependencies in the dependency graph\n */\n private detectCircularDependencies(): string[][] {\n const cycles: string[][] = [];\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n const detectCycle = (recordId: string, path: string[]): boolean => {\n visited.add(recordId);\n recursionStack.add(recordId);\n path.push(recordId);\n\n const record = this.recordIdMap.get(recordId);\n if (record) {\n for (const depId of record.dependencies) {\n if (!visited.has(depId)) {\n if (detectCycle(depId, [...path])) {\n return true;\n }\n } else if (recursionStack.has(depId)) {\n // Found a cycle\n const cycleStart = path.indexOf(depId);\n const cycle = path.slice(cycleStart);\n cycle.push(depId); // Complete the cycle\n cycles.push(cycle);\n return true;\n }\n }\n }\n\n recursionStack.delete(recordId);\n return false;\n };\n\n // Check all records for cycles\n for (const record of this.flattenedRecords) {\n if (!visited.has(record.id)) {\n detectCycle(record.id, []);\n }\n }\n\n return cycles;\n }\n\n /**\n * Performs topological sort on the dependency graph\n */\n private topologicalSort(): FlattenedRecord[] {\n const result: FlattenedRecord[] = [];\n const visited = new Set<string>();\n const tempStack = new Set<string>();\n\n const visit = (recordId: string): boolean => {\n if (tempStack.has(recordId)) {\n // Circular dependency - we've already detected these\n return false;\n }\n\n if (visited.has(recordId)) {\n return true;\n }\n\n tempStack.add(recordId);\n\n const record = this.recordIdMap.get(recordId);\n if (record) {\n // Visit dependencies first\n for (const depId of record.dependencies) {\n visit(depId);\n }\n }\n\n tempStack.delete(recordId);\n visited.add(recordId);\n \n if (record) {\n result.push(record);\n }\n\n return true;\n };\n\n // Process all records, starting with those that have no dependencies\n // First, process records with no dependencies\n for (const record of this.flattenedRecords) {\n if (record.dependencies.size === 0 && !visited.has(record.id)) {\n visit(record.id);\n }\n }\n\n // Then process any remaining records (handles disconnected components)\n for (const record of this.flattenedRecords) {\n if (!visited.has(record.id)) {\n visit(record.id);\n }\n }\n\n return result;\n }\n\n /**\n * Groups sorted records into dependency levels for parallel processing\n * Records in the same level have no dependencies on each other and can be processed in parallel\n */\n private groupByDependencyLevels(\n sortedRecords: FlattenedRecord[],\n dependencyGraph: Map<string, Set<string>>\n ): FlattenedRecord[][] {\n const levels: FlattenedRecord[][] = [];\n const recordLevels = new Map<string, number>();\n \n // Calculate the level for each record\n for (const record of sortedRecords) {\n let maxDependencyLevel = -1;\n \n // Find the maximum level of all dependencies\n for (const depId of record.dependencies) {\n const depLevel = recordLevels.get(depId);\n if (depLevel !== undefined && depLevel > maxDependencyLevel) {\n maxDependencyLevel = depLevel;\n }\n }\n \n // This record's level is one more than its highest dependency\n const recordLevel = maxDependencyLevel + 1;\n recordLevels.set(record.id, recordLevel);\n \n // Add to the appropriate level array\n if (!levels[recordLevel]) {\n levels[recordLevel] = [];\n }\n levels[recordLevel].push(record);\n }\n \n return levels;\n }\n}"]}
1
+ {"version":3,"file":"record-dependency-analyzer.js","sourceRoot":"","sources":["../../src/lib/record-dependency-analyzer.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata, EntityInfo } from '@memberjunction/core';\nimport { RecordData } from './sync-engine';\nimport { METADATA_KEYWORDS, isNonKeywordAtSymbol } from '../constants/metadata-keywords';\n\n/**\n * Represents a flattened record with its context and dependencies\n */\nexport interface FlattenedRecord {\n record: RecordData;\n entityName: string;\n parentContext?: {\n entityName: string;\n record: RecordData;\n recordIndex: number;\n };\n depth: number;\n path: string; // Path to this record for debugging\n dependencies: Set<string>; // Set of record IDs this record depends on\n id: string; // Unique identifier for this record in the flattened list\n originalIndex: number; // Original index in the source array\n}\n\n/**\n * Represents a reverse dependency relationship\n * (which records depend on a given record)\n */\nexport interface ReverseDependency {\n recordId: string; // The record being referenced\n dependentId: string; // The record that depends on it\n entityName: string; // Entity of the dependent\n fieldName: string | null; // Foreign key field name (if known)\n filePath: string; // Location of dependent record\n}\n\n/**\n * Result of dependency analysis\n */\nexport interface DependencyAnalysisResult {\n sortedRecords: FlattenedRecord[];\n circularDependencies: string[][];\n dependencyGraph: Map<string, Set<string>>;\n dependencyLevels?: FlattenedRecord[][]; // Records grouped by dependency level for parallel processing\n}\n\n/**\n * Analyzes and sorts records based on their dependencies\n */\nexport class RecordDependencyAnalyzer {\n private metadata: Metadata;\n private flattenedRecords: FlattenedRecord[] = [];\n private recordIdMap: Map<string, FlattenedRecord> = new Map();\n private entityInfoCache: Map<string, EntityInfo> = new Map();\n private recordCounter: number = 0;\n\n constructor() {\n this.metadata = new Metadata();\n }\n\n /**\n * Main entry point: analyzes all records in a file and returns them in dependency order\n */\n public async analyzeFileRecords(\n records: RecordData[],\n entityName: string\n ): Promise<DependencyAnalysisResult> {\n // Reset state\n this.flattenedRecords = [];\n this.recordIdMap.clear();\n this.recordCounter = 0;\n\n // Step 1: Flatten all records (including nested relatedEntities)\n this.flattenRecords(records, entityName);\n\n // Step 2: Analyze dependencies between all flattened records\n this.analyzeDependencies();\n\n // Step 3: Detect circular dependencies\n const circularDeps = this.detectCircularDependencies();\n\n // Step 4: Perform topological sort\n const sortedRecords = this.topologicalSort();\n\n // Step 5: Build dependency graph for debugging\n const dependencyGraph = new Map<string, Set<string>>();\n for (const record of this.flattenedRecords) {\n dependencyGraph.set(record.id, record.dependencies);\n }\n\n // Step 6: Group records into dependency levels for parallel processing\n const dependencyLevels = this.groupByDependencyLevels(sortedRecords, dependencyGraph);\n\n return {\n sortedRecords,\n circularDependencies: circularDeps,\n dependencyGraph,\n dependencyLevels\n };\n }\n\n /**\n * Flattens all records including nested relatedEntities\n */\n private flattenRecords(\n records: RecordData[],\n entityName: string,\n parentContext?: FlattenedRecord['parentContext'],\n depth: number = 0,\n pathPrefix: string = '',\n parentRecordId?: string\n ): void {\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const recordId = `${entityName}_${this.recordCounter++}`;\n const path = pathPrefix ? `${pathPrefix}/${entityName}[${i}]` : `${entityName}[${i}]`;\n\n const flattenedRecord: FlattenedRecord = {\n record,\n entityName,\n parentContext,\n depth,\n path,\n dependencies: new Set(),\n id: recordId,\n originalIndex: i\n };\n\n // If this has a parent, add dependency on the parent\n if (parentRecordId) {\n flattenedRecord.dependencies.add(parentRecordId);\n }\n\n this.flattenedRecords.push(flattenedRecord);\n this.recordIdMap.set(recordId, flattenedRecord);\n\n // Recursively flatten related entities\n if (record.relatedEntities) {\n for (const [relatedEntityName, relatedRecords] of Object.entries(record.relatedEntities)) {\n this.flattenRecords(\n relatedRecords,\n relatedEntityName,\n {\n entityName,\n record,\n recordIndex: i\n },\n depth + 1,\n path,\n recordId // Pass current record ID as parent for children\n );\n }\n }\n }\n }\n\n /**\n * Analyzes dependencies between all flattened records\n */\n private analyzeDependencies(): void {\n for (const record of this.flattenedRecords) {\n // Get entity info for foreign key relationships\n const entityInfo = this.getEntityInfo(record.entityName);\n if (!entityInfo) continue;\n\n // Analyze field dependencies\n if (record.record.fields) {\n for (const [fieldName, fieldValue] of Object.entries(record.record.fields)) {\n if (typeof fieldValue === 'string') {\n // Handle @lookup references\n if (fieldValue.startsWith(METADATA_KEYWORDS.LOOKUP)) {\n const dependency = this.findLookupDependency(fieldValue, record);\n if (dependency) {\n record.dependencies.add(dependency);\n }\n }\n // Handle @root references - these create dependencies on the root record\n else if (fieldValue.startsWith(METADATA_KEYWORDS.ROOT)) {\n const rootDependency = this.findRootDependency(record);\n if (rootDependency) {\n record.dependencies.add(rootDependency);\n }\n }\n // @parent references don't create explicit dependencies in our flattened structure\n // because parent is guaranteed to be processed before children due to the way\n // we flatten records (parent always comes before its children)\n }\n }\n }\n\n // Check foreign key dependencies\n this.analyzeForeignKeyDependencies(record, entityInfo);\n }\n }\n\n /**\n * Analyzes foreign key dependencies based on EntityInfo\n */\n private analyzeForeignKeyDependencies(record: FlattenedRecord, entityInfo: EntityInfo): void {\n // Check all foreign key fields\n for (const field of entityInfo.ForeignKeys) {\n const fieldValue = record.record.fields?.[field.Name];\n if (fieldValue && typeof fieldValue === 'string' && !fieldValue.startsWith('@')) {\n // This is a direct foreign key value, find the referenced record\n const relatedEntityInfo = this.getEntityInfo(field.RelatedEntity);\n if (relatedEntityInfo) {\n const dependency = this.findRecordByPrimaryKey(\n field.RelatedEntity,\n fieldValue,\n relatedEntityInfo\n );\n if (dependency) {\n record.dependencies.add(dependency);\n }\n }\n }\n }\n }\n\n /**\n * Finds a record that matches a @lookup reference\n */\n private findLookupDependency(lookupValue: string, currentRecord: FlattenedRecord): string | null {\n // Parse lookup format: @lookup:EntityName.Field=Value or @lookup:Field=Value\n const lookupStr = lookupValue.substring(8); // Remove '@lookup:'\n \n // Handle the ?create syntax by removing it\n const cleanLookup = lookupStr.split('?')[0];\n \n // Parse entity name if present\n let targetEntity: string;\n let criteria: string;\n \n if (cleanLookup.includes('.')) {\n const parts = cleanLookup.split('.');\n targetEntity = parts[0];\n criteria = parts.slice(1).join('.');\n } else {\n // Same entity if not specified\n targetEntity = currentRecord.entityName;\n criteria = cleanLookup;\n }\n\n // Parse criteria (can be multiple with &)\n const criteriaMap = new Map<string, string>();\n for (const pair of criteria.split('&')) {\n const [field, value] = pair.split('=');\n if (field && value) {\n let resolvedValue = value.trim();\n \n // Special handling for nested @lookup references in lookup criteria\n // This creates a dependency on the looked-up record\n if (resolvedValue.startsWith(METADATA_KEYWORDS.LOOKUP)) {\n const nestedDependency = this.findLookupDependency(resolvedValue, currentRecord);\n if (nestedDependency) {\n // Add this as a dependency of the current record\n currentRecord.dependencies.add(nestedDependency);\n // Continue processing - we can't resolve the actual value here\n // but we've recorded the dependency\n }\n }\n // Special handling for @root references in lookup criteria\n else if (resolvedValue.startsWith(METADATA_KEYWORDS.ROOT)) {\n // Add dependency on root record\n const rootDep = this.findRootDependency(currentRecord);\n if (rootDep) {\n currentRecord.dependencies.add(rootDep);\n }\n // Note: We can't resolve the actual value here, but we've recorded the dependency\n }\n // Special handling for @parent references in lookup criteria\n // If the value is @parent:field, we need to resolve it from the parent context\n else if (resolvedValue.startsWith(METADATA_KEYWORDS.PARENT) && currentRecord.parentContext) {\n const parentField = resolvedValue.substring(METADATA_KEYWORDS.PARENT.length);\n \n // Try to resolve from parent context\n const parentValue = currentRecord.parentContext.record.fields?.[parentField] ||\n currentRecord.parentContext.record.primaryKey?.[parentField];\n \n if (parentValue && typeof parentValue === 'string') {\n // Check if parent value is also a @parent reference (nested parent refs)\n if (parentValue.startsWith(METADATA_KEYWORDS.PARENT)) {\n // Find the parent record to get its parent context\n const parentRecord = this.flattenedRecords.find(r =>\n r.record === currentRecord.parentContext!.record &&\n r.entityName === currentRecord.parentContext!.entityName\n );\n\n if (parentRecord && parentRecord.parentContext) {\n const grandParentField = parentValue.substring(METADATA_KEYWORDS.PARENT.length);\n const grandParentValue = parentRecord.parentContext.record.fields?.[grandParentField] ||\n parentRecord.parentContext.record.primaryKey?.[grandParentField];\n if (grandParentValue && typeof grandParentValue === 'string' && !grandParentValue.startsWith('@')) {\n resolvedValue = grandParentValue;\n }\n }\n } else if (!parentValue.startsWith('@')) {\n resolvedValue = parentValue;\n }\n }\n }\n \n criteriaMap.set(field.trim(), resolvedValue);\n }\n }\n\n // Find matching record in our flattened list\n for (const candidate of this.flattenedRecords) {\n if (candidate.entityName !== targetEntity) continue;\n if (candidate.id === currentRecord.id) continue; // Skip self\n\n // Check if all criteria match\n let allMatch = true;\n for (const [field, value] of criteriaMap) {\n let candidateValue = candidate.record.fields?.[field] || \n candidate.record.primaryKey?.[field];\n let lookupValue = value;\n \n // Resolve candidate value if it's a @parent reference\n if (typeof candidateValue === 'string' && candidateValue.startsWith(METADATA_KEYWORDS.PARENT) && candidate.parentContext) {\n const parentField = candidateValue.substring(METADATA_KEYWORDS.PARENT.length);\n const parentRecord = candidate.parentContext.record;\n candidateValue = parentRecord.fields?.[parentField] || parentRecord.primaryKey?.[parentField];\n\n // If the parent field is also a @parent reference, resolve it recursively\n if (typeof candidateValue === 'string' && candidateValue.startsWith(METADATA_KEYWORDS.PARENT)) {\n // Find the candidate's parent in our flattened list\n const candidateParent = this.flattenedRecords.find(r => \n r.record === candidate.parentContext!.record && \n r.entityName === candidate.parentContext!.entityName\n );\n if (candidateParent?.parentContext) {\n const grandParentField = candidateValue.substring(8);\n candidateValue = candidateParent.parentContext.record.fields?.[grandParentField] || \n candidateParent.parentContext.record.primaryKey?.[grandParentField];\n }\n }\n }\n \n // Resolve lookup value if it contains @parent reference\n if (typeof lookupValue === 'string' && lookupValue.includes(METADATA_KEYWORDS.PARENT)) {\n // Handle cases like \"@parent:AgentID\" or embedded references\n if (lookupValue.startsWith(METADATA_KEYWORDS.PARENT) && currentRecord.parentContext) {\n const parentField = lookupValue.substring(METADATA_KEYWORDS.PARENT.length);\n lookupValue = currentRecord.parentContext.record.fields?.[parentField] ||\n currentRecord.parentContext.record.primaryKey?.[parentField];\n\n // If still a reference, try to resolve from the parent's parent\n if (typeof lookupValue === 'string' && lookupValue.startsWith(METADATA_KEYWORDS.PARENT)) {\n const currentParent = this.flattenedRecords.find(r =>\n r.record === currentRecord.parentContext!.record &&\n r.entityName === currentRecord.parentContext!.entityName\n );\n if (currentParent?.parentContext) {\n const grandParentField = lookupValue.substring(METADATA_KEYWORDS.PARENT.length);\n lookupValue = currentParent.parentContext.record.fields?.[grandParentField] ||\n currentParent.parentContext.record.primaryKey?.[grandParentField];\n }\n }\n }\n }\n\n // Special case: if both values are @parent references pointing to the same parent field,\n // and they have the same parent context, they match\n if (value.startsWith(METADATA_KEYWORDS.PARENT) && candidateValue === value && \n currentRecord.parentContext && candidate.parentContext) {\n // Check if they share the same parent\n if (currentRecord.parentContext.record === candidate.parentContext.record) {\n // Same parent, same reference - they will resolve to the same value\n continue; // This criterion matches\n }\n }\n \n if (candidateValue !== lookupValue) {\n allMatch = false;\n break;\n }\n }\n\n if (allMatch) {\n return candidate.id;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the root record for a given record\n */\n private findRootDependency(record: FlattenedRecord): string | null {\n // If this record has no parent, it IS the root, no dependency\n if (!record.parentContext) {\n return null;\n }\n \n // Walk up the parent chain to find the root\n let current = record;\n while (current.parentContext) {\n // Try to find the parent record in our flattened list\n const parentRecord = this.flattenedRecords.find(r => \n r.record === current.parentContext!.record && \n r.entityName === current.parentContext!.entityName\n );\n \n if (!parentRecord) {\n // Parent not found, something is wrong\n return null;\n }\n \n // If this parent has no parent, it's the root\n if (!parentRecord.parentContext) {\n return parentRecord.id;\n }\n \n current = parentRecord;\n }\n \n return null;\n }\n\n /**\n * Finds a record by its primary key value\n */\n private findRecordByPrimaryKey(\n entityName: string,\n primaryKeyValue: string,\n entityInfo: EntityInfo\n ): string | null {\n // Get primary key field name\n const primaryKeyField = entityInfo.PrimaryKeys[0]?.Name;\n if (!primaryKeyField) return null;\n\n for (const candidate of this.flattenedRecords) {\n if (candidate.entityName !== entityName) continue;\n\n const candidateValue = candidate.record.primaryKey?.[primaryKeyField] ||\n candidate.record.fields?.[primaryKeyField];\n if (candidateValue === primaryKeyValue) {\n return candidate.id;\n }\n }\n\n return null;\n }\n\n /**\n * Gets EntityInfo from cache or metadata\n */\n private getEntityInfo(entityName: string): EntityInfo | null {\n if (!this.entityInfoCache.has(entityName)) {\n const info = this.metadata.EntityByName(entityName);\n if (info) {\n this.entityInfoCache.set(entityName, info);\n }\n }\n return this.entityInfoCache.get(entityName) || null;\n }\n\n /**\n * Detects circular dependencies in the dependency graph\n */\n private detectCircularDependencies(): string[][] {\n const cycles: string[][] = [];\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n const detectCycle = (recordId: string, path: string[]): boolean => {\n visited.add(recordId);\n recursionStack.add(recordId);\n path.push(recordId);\n\n const record = this.recordIdMap.get(recordId);\n if (record) {\n for (const depId of record.dependencies) {\n if (!visited.has(depId)) {\n if (detectCycle(depId, [...path])) {\n return true;\n }\n } else if (recursionStack.has(depId)) {\n // Found a cycle\n const cycleStart = path.indexOf(depId);\n const cycle = path.slice(cycleStart);\n cycle.push(depId); // Complete the cycle\n cycles.push(cycle);\n return true;\n }\n }\n }\n\n recursionStack.delete(recordId);\n return false;\n };\n\n // Check all records for cycles\n for (const record of this.flattenedRecords) {\n if (!visited.has(record.id)) {\n detectCycle(record.id, []);\n }\n }\n\n return cycles;\n }\n\n /**\n * Performs topological sort on the dependency graph\n */\n private topologicalSort(): FlattenedRecord[] {\n const result: FlattenedRecord[] = [];\n const visited = new Set<string>();\n const tempStack = new Set<string>();\n\n const visit = (recordId: string): boolean => {\n if (tempStack.has(recordId)) {\n // Circular dependency - we've already detected these\n return false;\n }\n\n if (visited.has(recordId)) {\n return true;\n }\n\n tempStack.add(recordId);\n\n const record = this.recordIdMap.get(recordId);\n if (record) {\n // Visit dependencies first\n for (const depId of record.dependencies) {\n visit(depId);\n }\n }\n\n tempStack.delete(recordId);\n visited.add(recordId);\n \n if (record) {\n result.push(record);\n }\n\n return true;\n };\n\n // Process all records, starting with those that have no dependencies\n // First, process records with no dependencies\n for (const record of this.flattenedRecords) {\n if (record.dependencies.size === 0 && !visited.has(record.id)) {\n visit(record.id);\n }\n }\n\n // Then process any remaining records (handles disconnected components)\n for (const record of this.flattenedRecords) {\n if (!visited.has(record.id)) {\n visit(record.id);\n }\n }\n\n return result;\n }\n\n /**\n * Groups sorted records into dependency levels for parallel processing\n * Records in the same level have no dependencies on each other and can be processed in parallel\n */\n private groupByDependencyLevels(\n sortedRecords: FlattenedRecord[],\n dependencyGraph: Map<string, Set<string>>\n ): FlattenedRecord[][] {\n const levels: FlattenedRecord[][] = [];\n const recordLevels = new Map<string, number>();\n \n // Calculate the level for each record\n for (const record of sortedRecords) {\n let maxDependencyLevel = -1;\n \n // Find the maximum level of all dependencies\n for (const depId of record.dependencies) {\n const depLevel = recordLevels.get(depId);\n if (depLevel !== undefined && depLevel > maxDependencyLevel) {\n maxDependencyLevel = depLevel;\n }\n }\n \n // This record's level is one more than its highest dependency\n const recordLevel = maxDependencyLevel + 1;\n recordLevels.set(record.id, recordLevel);\n \n // Add to the appropriate level array\n if (!levels[recordLevel]) {\n levels[recordLevel] = [];\n }\n levels[recordLevel].push(record);\n }\n \n return levels;\n }\n\n /**\n * Build reverse dependency map from forward dependencies\n * Maps: record ID -> list of records that depend on it\n *\n * This is essential for deletion ordering - we need to know what depends on a record\n * before we can safely delete it.\n */\n public buildReverseDependencyMap(\n records: FlattenedRecord[]\n ): Map<string, ReverseDependency[]> {\n const reverseMap = new Map<string, ReverseDependency[]>();\n\n for (const record of records) {\n // For each dependency this record has...\n for (const depId of record.dependencies) {\n // Add this record as a dependent of that dependency\n if (!reverseMap.has(depId)) {\n reverseMap.set(depId, []);\n }\n\n reverseMap.get(depId)!.push({\n recordId: depId,\n dependentId: record.id,\n entityName: record.entityName,\n fieldName: this.findForeignKeyFieldForDependency(record, depId),\n filePath: record.path\n });\n }\n }\n\n return reverseMap;\n }\n\n /**\n * Find the foreign key field that creates a dependency\n * Used for better error reporting\n */\n private findForeignKeyFieldForDependency(\n record: FlattenedRecord,\n dependencyId: string\n ): string | null {\n const entityInfo = this.getEntityInfo(record.entityName);\n if (!entityInfo) return null;\n\n const dependentRecord = this.recordIdMap.get(dependencyId);\n if (!dependentRecord) return null;\n\n // Check all foreign key fields\n for (const field of entityInfo.ForeignKeys) {\n const fieldValue = record.record.fields?.[field.Name];\n\n // Check if this field references the dependent record\n if (fieldValue && typeof fieldValue === 'string') {\n // Handle @lookup references\n if (fieldValue.startsWith(METADATA_KEYWORDS.LOOKUP)) {\n const resolvedDep = this.findLookupDependency(fieldValue, record);\n if (resolvedDep === dependencyId) {\n return field.Name;\n }\n }\n // Handle direct foreign key values\n else if (!fieldValue.startsWith('@')) {\n const relatedEntityInfo = this.getEntityInfo(field.RelatedEntity);\n if (relatedEntityInfo) {\n const dep = this.findRecordByPrimaryKey(\n field.RelatedEntity,\n fieldValue,\n relatedEntityInfo\n );\n if (dep === dependencyId) {\n return field.Name;\n }\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * Perform reverse topological sort for deletion order\n * Returns records grouped by dependency level, with leaf nodes (highest dependency level) first\n *\n * For deletions, we want to delete in reverse order of creation:\n * - Records at highest forward dependency levels (leaf nodes) delete FIRST\n * - Records at level 0 (root nodes with no dependencies) delete LAST\n *\n * This is simply the reverse of the forward topological sort used for creates.\n */\n public reverseTopologicalSort(\n records: FlattenedRecord[],\n reverseDependencies: Map<string, ReverseDependency[]>\n ): FlattenedRecord[][] {\n // Calculate forward dependency levels (same as creation order)\n const recordLevels = new Map<string, number>();\n\n // Calculate the level for each record based on its FORWARD dependencies\n for (const record of records) {\n let maxDependencyLevel = -1;\n\n // Find the maximum level of all dependencies (things this record depends ON)\n for (const depId of record.dependencies) {\n const depLevel = recordLevels.get(depId);\n if (depLevel !== undefined && depLevel > maxDependencyLevel) {\n maxDependencyLevel = depLevel;\n }\n }\n\n // This record's level is one more than its highest dependency\n const recordLevel = maxDependencyLevel + 1;\n recordLevels.set(record.id, recordLevel);\n }\n\n // Group records by level\n const forwardLevels: FlattenedRecord[][] = [];\n for (const record of records) {\n const level = recordLevels.get(record.id) || 0;\n\n if (!forwardLevels[level]) {\n forwardLevels[level] = [];\n }\n forwardLevels[level].push(record);\n }\n\n // Reverse the array for deletion order\n // Forward level 0 (roots) becomes last to delete\n // Forward level N (leaves) becomes first to delete\n return forwardLevels.reverse();\n }\n\n /**\n * Find all transitive dependents of a set of records\n * This is useful for finding all records that must be deleted when deleting a parent\n *\n * @param recordIds Set of record IDs to find dependents for\n * @param reverseDependencies Reverse dependency map\n * @returns Set of all record IDs that depend on the input records (transitively)\n */\n public findTransitiveDependents(\n recordIds: Set<string>,\n reverseDependencies: Map<string, ReverseDependency[]>\n ): Set<string> {\n const dependents = new Set<string>();\n const visited = new Set<string>();\n\n // BFS to find all transitive dependents\n const queue = Array.from(recordIds);\n\n while (queue.length > 0) {\n const recordId = queue.shift()!;\n if (visited.has(recordId)) continue;\n visited.add(recordId);\n\n const deps = reverseDependencies.get(recordId) || [];\n\n for (const dep of deps) {\n // Add dependent to result set\n dependents.add(dep.dependentId);\n\n // Queue for processing its dependents\n queue.push(dep.dependentId);\n }\n }\n\n return dependents;\n }\n}"]}
@@ -10,6 +10,8 @@ export interface PullOptions {
10
10
  targetDir?: string;
11
11
  updateExistingRecords?: boolean;
12
12
  createNewFileIfNotFound?: boolean;
13
+ include?: string[];
14
+ exclude?: string[];
13
15
  }
14
16
  export interface PullCallbacks {
15
17
  onProgress?: (message: string) => void;
@@ -25,6 +25,10 @@ class PullService {
25
25
  this.recordProcessor = new RecordProcessor_1.RecordProcessor(syncEngine, contextUser);
26
26
  }
27
27
  async pull(options, callbacks) {
28
+ // Validate that include and exclude are not used together
29
+ if (options.include && options.exclude) {
30
+ throw new Error('Cannot specify both --include and --exclude options. Please use one or the other.');
31
+ }
28
32
  // Clear any previous batch operations
29
33
  this.fileWriteBatch.clear();
30
34
  this.createdBackupFiles = [];
@@ -1 +1 @@
1
- {"version":3,"file":"PullService.js","sourceRoot":"","sources":["../../src/services/PullService.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA0B;AAC1B,gDAAwB;AACxB,+CAAiF;AAEjF,sCAA2D;AAC3D,0DAAsD;AACtD,8DAAyD;AAEzD,4DAAyD;AA8BzD,MAAa,WAAW;IACd,UAAU,CAAa;IACvB,WAAW,CAAW;IACtB,kBAAkB,GAAa,EAAE,CAAC;IAClC,iBAAiB,GAAgB,IAAI,GAAG,EAAE,CAAC;IAC3C,cAAc,CAAiB;IAC/B,eAAe,CAAkB;IAEzC,YAAY,UAAsB,EAAE,WAAqB;QACvD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,IAAI,iCAAc,EAAE,CAAC;QAC3C,IAAI,CAAC,eAAe,GAAG,IAAI,iCAAe,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAoB,EAAE,SAAyB;QACxD,sCAAsC;QACtC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAE/B,IAAI,SAAiB,CAAC;QACtB,IAAI,YAAiC,CAAC;QAEtC,qDAAqD;QACrD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,SAAS,EAAE,KAAK,EAAE,CAAC,qCAAqC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACjC,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAE1B,gDAAgD;YAChD,YAAY,GAAG,MAAM,IAAA,yBAAgB,EAAC,SAAS,CAAC,CAAC;YACjD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,6BAA6B,SAAS,EAAE,CAAC,CAAC;YAC5D,CAAC;YACD,IAAI,YAAY,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC3C,MAAM,IAAI,KAAK,CAAC,aAAa,SAAS,8BAA8B,YAAY,CAAC,MAAM,WAAW,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACvH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAEpE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CAAC,kCAAkC,OAAO,CAAC,MAAM,8BAA8B,CAAC,CAAC;YAClG,CAAC;YAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,wEAAwE;gBACxE,6CAA6C;gBAC7C,MAAM,IAAI,KAAK,CAAC,0CAA0C,OAAO,CAAC,MAAM,qCAAqC,CAAC,CAAC;YACjH,CAAC;YAED,YAAY,GAAG,MAAM,IAAA,yBAAgB,EAAC,SAAS,CAAC,CAAC;YACjD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,iEAAiE;QACjE,IAAI,OAAO,CAAC,OAAO,IAAI,YAAY,EAAE,IAAI,EAAE,2BAA2B,IAAI,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;YAC1G,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACrF,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW;gBAC/B,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,CAAC;YAE7C,IAAI,MAAM,kBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,SAAS,EAAE,KAAK,EAAE,CAAC,sEAAsE,cAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACzH,CAAC;QACH,CAAC;QAED,eAAe;QACf,SAAS,EAAE,UAAU,EAAE,CAAC,WAAW,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;QAC7D,MAAM,EAAE,GAAG,IAAI,cAAO,EAAE,CAAC;QAEzB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC1B,CAAC;aAAM,IAAI,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACtC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YAC9B,UAAU,EAAE,OAAO,CAAC,MAAM;YAC1B,WAAW,EAAE,MAAM;YACnB,UAAU,EAAE,eAAe;SAC5B,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAErB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,SAAS,EAAE,SAAS,EAAE,CAAC,SAAS,MAAM,CAAC,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;QAEjE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,SAAS,EAAE,KAAK,EAAE,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,MAAM,eAAe,SAAS,EAAE,CAAC,CAAC;YACnG,OAAO;gBACL,SAAS,EAAE,CAAC;gBACZ,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,SAAS;aACV,CAAC;QACJ,CAAC;QAED,mDAAmD;QACnD,IAAI,UAAyC,CAAC;QAE9C,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,IAAI,CAAC,cAAc,CACpC,MAAM,CAAC,OAAO,EACd,OAAO,EACP,SAAS,EACT,YAAY,EACZ,SAAS,CACV,CAAC;YAEF,yCAAyC;YACzC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;gBACvD,IAAI,OAAO,CAAC,OAAO,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;oBACxC,SAAS,EAAE,SAAS,EAAE,CAAC,SAAS,YAAY,0CAA0C,CAAC,CAAC;gBAC1F,CAAC;YACH,CAAC;YAED,8CAA8C;YAC9C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAClC,CAAC;QAEH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,EAAE,OAAO,EAAE,CAAC,0BAA2B,KAAa,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;YAElF,0DAA0D;YAC1D,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;oBAC1C,SAAS,EAAE,MAAM,EAAE,CAAC,6DAA6D,CAAC,CAAC;gBACrF,CAAC;gBAAC,OAAO,aAAa,EAAE,CAAC;oBACvB,SAAS,EAAE,OAAO,EAAE,CAAC,oBAAqB,aAAqB,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC;gBAC9F,CAAC;YACH,CAAC;YAED,MAAM,KAAK,CAAC;QACd,CAAC;QAED,OAAO;YACL,GAAG,UAAU;YACb,SAAS;SACV,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,cAAc,CAC1B,OAAqB,EACrB,OAAoB,EACpB,SAAiB,EACjB,YAA0B,EAC1B,SAAyB;QAEzB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACjE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,qCAAqC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,SAAS,EAAE,UAAU,EAAE,CAAC,oBAAoB,CAAC,CAAC;QAC9C,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,iDAAiD;QACjD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,UAAU,GAAiB,EAAE,CAAC;YACpC,MAAM,MAAM,GAAa,EAAE,CAAC;YAE5B,kDAAkD;YAClD,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;gBACzD,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,UAAU,GAAwB,EAAE,CAAC;oBAC3C,KAAK,MAAM,EAAE,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;wBACxC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,GAAI,MAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;oBACjD,CAAC;oBAED,gCAAgC;oBAChC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CACzD,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,OAAO,CAAC,OAAO,EACf,IAAI,CACL,CAAC;oBAEF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;gBAC9C,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,YAAY,GAAG,4BAA4B,KAAK,GAAG,CAAC,KAAM,KAAa,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;oBACjG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oBAC1B,SAAS,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;oBAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAExD,6BAA6B;YAC7B,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;gBACnC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;oBACxC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;oBACnC,SAAS,EAAE,CAAC;gBACd,CAAC;YACH,CAAC;YAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,SAAS,EAAE,UAAU,EAAE,CAAC,aAAa,SAAS,IAAI,OAAO,CAAC,MAAM,sBAAsB,CAAC,CAAC;YAC1F,CAAC;YAED,qDAAqD;YACrD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,OAAO,CAAC;gBACvG,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBAChD,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBACrD,SAAS,EAAE,SAAS,EAAE,CAAC,UAAU,SAAS,gBAAgB,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACvF,CAAC;YAED,8DAA8D;YAC9D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,MAAM,CAAC,MAAM,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACzG,CAAC;QACH,CAAC;aAAM,CAAC;YACN,gDAAgD;YAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAChD,OAAO,EACP,OAAO,EACP,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,CACV,CAAC;YAEF,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;YAC7B,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YACzB,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YACzB,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YAEzB,eAAe;YACf,MAAM,WAAW,GAAG,CAAC,aAAa,SAAS,UAAU,CAAC,CAAC;YACvD,IAAI,OAAO,GAAG,CAAC;gBAAE,WAAW,CAAC,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;YACxD,IAAI,OAAO,GAAG,CAAC;gBAAE,WAAW,CAAC,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;YACxD,IAAI,OAAO,GAAG,CAAC;gBAAE,WAAW,CAAC,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;YAExD,SAAS,EAAE,SAAS,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,kBAAkB;QACtB,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,sBAAsB;QACtB,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACjD,IAAI,CAAC;gBACH,IAAI,MAAM,kBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBACpC,MAAM,kBAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,gCAAgC,UAAU,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACvH,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC/C,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,0BAA0B,CAAC,SAAS,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,qCAAqC,SAAS,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC3H,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAE/B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,0BAA0B,CAAC,SAAiB;QACxD,IAAI,CAAC;YACH,4BAA4B;YAC5B,IAAI,CAAC,CAAC,MAAM,kBAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;gBACtC,OAAO;YACT,CAAC;YAED,+DAA+D;YAC/D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,OAAO;YACT,CAAC;YAED,8BAA8B;YAC9B,MAAM,KAAK,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,kBAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,6DAA6D;YAC7D,wEAAwE;YACxE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,qBAAqB;QACnB,OAAO,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,mBAAmB,CAAC,SAAyB;QACzD,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,SAAS,EAAE,KAAK,EAAE,CAAC,4CAA4C,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,SAAS,EAAE,UAAU,EAAE,CAAC,gBAAgB,IAAI,CAAC,kBAAkB,CAAC,MAAM,kBAAkB,CAAC,CAAC;QAE1F,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACjD,IAAI,CAAC;gBACH,8CAA8C;gBAC9C,MAAM,SAAS,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBAC3C,MAAM,cAAc,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;gBAEjD,kEAAkE;gBAClE,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,uDAAuD,EAAE,OAAO,CAAC,CAAC;gBAClH,MAAM,gBAAgB,GAAG,cAAI,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAAC;gBAE9E,IAAI,MAAM,kBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBACpC,MAAM,kBAAE,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;oBAC5C,aAAa,EAAE,CAAC;gBAClB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,qBAAqB,UAAU,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC5G,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,MAAM,YAAY,aAAa,sBAAsB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9H,CAAC;QAED,SAAS,EAAE,SAAS,EAAE,CAAC,4BAA4B,aAAa,eAAe,CAAC,CAAC;IACnF,CAAC;IAEO,KAAK,CAAC,wBAAwB,CACpC,OAAqB,EACrB,OAAoB,EACpB,SAAiB,EACjB,YAA0B,EAC1B,UAAsB,EACtB,SAAyB;QAEzB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,sBAAsB;QACtB,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,WAAW,IAAI,YAAY,CAAC,WAAW,IAAI,QAAQ,CAAC;QAC3F,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAE3E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,SAAS,EAAE,KAAK,EAAE,CAAC,SAAS,aAAa,CAAC,MAAM,qCAAqC,WAAW,GAAG,CAAC,CAAC;YACrG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,OAAO,cAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QAED,6CAA6C;QAC7C,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QAErF,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,SAAS,EAAE,KAAK,EAAE,CAAC,UAAU,kBAAkB,CAAC,IAAI,8BAA8B,CAAC,CAAC;QACtF,CAAC;QAED,yCAAyC;QACzC,MAAM,UAAU,GAAmE,EAAE,CAAC;QACtF,MAAM,uBAAuB,GAAqF,EAAE,CAAC;QAErH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,oBAAoB;YACpB,MAAM,UAAU,GAAwB,EAAE,CAAC;YAC3C,KAAK,MAAM,EAAE,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;gBACxC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,GAAI,MAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YACjD,CAAC;YAED,oBAAoB;YACpB,MAAM,SAAS,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC;YAC1D,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAE3D,IAAI,gBAAgB,EAAE,CAAC;gBACrB,wBAAwB;gBACxB,IAAI,YAAY,CAAC,IAAI,EAAE,qBAAqB,KAAK,KAAK,EAAE,CAAC;oBACvD,uBAAuB,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC5F,CAAC;qBAAM,CAAC;oBACN,OAAO,EAAE,CAAC;oBACV,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;wBACpB,SAAS,EAAE,KAAK,EAAE,CAAC,6BAA6B,SAAS,EAAE,CAAC,CAAC;oBAC/D,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,+BAA+B;gBAC/B,IAAI,YAAY,CAAC,IAAI,EAAE,uBAAuB,KAAK,KAAK,EAAE,CAAC;oBACzD,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;gBAC1C,CAAC;qBAAM,CAAC;oBACN,OAAO,EAAE,CAAC;oBACV,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;wBACpB,SAAS,EAAE,KAAK,EAAE,CAAC,wDAAwD,SAAS,EAAE,CAAC,CAAC;oBAC1F,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,4DAA4D;QAC5D,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;QACxC,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,+CAA+C;QAC/C,IAAI,uBAAuB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvC,SAAS,EAAE,UAAU,EAAE,CAAC,iDAAiD,CAAC,CAAC;YAE3E,MAAM,cAAc,GAAG,uBAAuB,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE;gBACnG,IAAI,CAAC;oBACH,mDAAmD;oBACnD,IAAI,YAAY,CAAC,IAAI,EAAE,kBAAkB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAC1E,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;wBACtE,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC9B,CAAC;oBAED,0BAA0B;oBAC1B,MAAM,YAAY,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBAEjD,kEAAkE;oBAClE,IAAI,kBAA8B,CAAC;oBACnC,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;wBAChC,wCAAwC;wBACxC,MAAM,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAC3C,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAC5F,CAAC;wBACF,kBAAkB,GAAG,cAAc,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,iCAAiC;oBAC3F,CAAC;yBAAM,CAAC;wBACN,kBAAkB,GAAG,YAAY,CAAC;oBACpC,CAAC;oBAED,gEAAgE;oBAChE,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAC5D,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,OAAO,CAAC,OAAO,EACf,KAAK,EACL,kBAAkB,CACnB,CAAC;oBAEF,uBAAuB;oBACvB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,YAAY,CACxC,kBAAkB,EAClB,aAAa,EACb,YAAY,CAAC,IAAI,EAAE,aAAa,IAAI,OAAO,EAC3C,YAAY,CAAC,IAAI,EAAE,cAAc,IAAI,EAAE,CACxC,CAAC;oBAEF,uCAAuC;oBACvC,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;wBAChC,iDAAiD;wBACjD,MAAM,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC;wBACjE,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;oBAC/E,CAAC;yBAAM,CAAC;wBACN,6BAA6B;wBAC7B,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;oBAC9D,CAAC;oBAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;wBACpB,SAAS,EAAE,KAAK,EAAE,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;oBAC7C,CAAC;oBAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;gBAClC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,YAAY,GAAG,2BAA2B,KAAK,GAAG,CAAC,KAAM,KAAa,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;oBAChG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oBAC1B,SAAS,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;oBAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;gBACnC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YACxD,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;YACtD,SAAS,IAAI,OAAO,CAAC;YAErB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,SAAS,EAAE,SAAS,EAAE,CAAC,aAAa,OAAO,IAAI,uBAAuB,CAAC,MAAM,iBAAiB,CAAC,CAAC;YAClG,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,SAAS,EAAE,UAAU,EAAE,CAAC,4CAA4C,CAAC,CAAC;YAEtE,IAAI,YAAY,CAAC,IAAI,EAAE,2BAA2B,IAAI,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;gBACrF,oEAAoE;gBACpE,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAC9D,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW;oBAC/B,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC;gBAC5C,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBAEhD,sCAAsC;gBACtC,MAAM,iBAAiB,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE;oBAC/E,IAAI,CAAC;wBACH,qDAAqD;wBACrD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CACzD,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,OAAO,CAAC,OAAO,EACf,IAAI,CACL,CAAC;wBAEF,qFAAqF;wBACrF,8EAA8E;wBAC9E,MAAM,eAAe,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC;wBAChE,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;wBAE5E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;oBAClC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,YAAY,GAAG,gCAAgC,KAAK,GAAG,CAAC,KAAM,KAAa,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;wBACrG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;wBAC1B,SAAS,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;wBAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;oBACnC,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC9D,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;gBACzD,SAAS,IAAI,OAAO,CAAC;gBAErB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,SAAS,EAAE,KAAK,EAAE,CAAC,UAAU,OAAO,qBAAqB,QAAQ,EAAE,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,0DAA0D;gBAC1D,MAAM,wBAAwB,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE;oBACtF,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;wBACvF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;oBAClC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,YAAY,GAAG,gCAAgC,KAAK,GAAG,CAAC,KAAM,KAAa,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;wBACrG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;wBAC1B,SAAS,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;wBAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;oBACnC,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;gBACtE,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;gBAC1D,SAAS,IAAI,OAAO,CAAC;gBAErB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,SAAS,EAAE,SAAS,EAAE,CAAC,WAAW,OAAO,IAAI,UAAU,CAAC,MAAM,0BAA0B,CAAC,CAAC;gBAC5F,CAAC;YACH,CAAC;QACH,CAAC;QAED,8DAA8D;QAC9D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,sCAAsC,MAAM,CAAC,MAAM,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvG,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,MAAkB,EAClB,UAA+B,EAC/B,SAAiB,EACjB,YAA0B,EAC1B,OAAiB;QAEjB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CACzD,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,OAAO,EACP,IAAI,CACL,CAAC;QAEF,sBAAsB;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEhD,mEAAmE;QACnE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACvD,CAAC;IAMO,KAAK,CAAC,qBAAqB,CAAC,UAAkB;QACpD,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,qDAAqD;QACrD,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAE,EAAE;YACvC,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAE/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC5C,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAgB,EAAC,QAAQ,CAAC,CAAC;oBAEhD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;wBAC3C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACtB,CAAC;yBAAM,CAAC;wBACN,UAAU;wBACV,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,UAAU,CAAC,8BAAa,CAAC,cAAc,EAAE,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,aAAa,CAAC,UAA+B,EAAE,aAA2B;QAChF,2CAA2C;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEvC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YACrD,iDAAiD;YACjD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,GAAG,CAAC,KAAK,CAAC,iEAAiE,CAAC,EAAE,CAAC;gBACjF,+DAA+D;gBAC/D,OAAO,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC;YACtD,CAAC;YACD,uDAAuD;YACvD,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;gBACrB,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC;YACtE,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;IAC1G,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,GAAW,EAAE,OAAe;QAC1D,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAE/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;oBACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;oBAE5B,0BAA0B;oBAC1B,IAAI,OAAO,KAAK,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;wBACvD,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;oBACvC,CAAC;yBAAM,IAAI,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;wBAC3F,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;oBACvC,CAAC;yBAAM,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;wBAChC,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;oBACvC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gCAAgC;YAChC,IAAK,KAAa,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAC/B,KAAe,EACf,WAAuB;QAEvB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwD,CAAC;QAEnF,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;gBAEhE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;wBACtB,MAAM,SAAS,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;wBACjE,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;oBAC9D,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,kCAAkC;YACpC,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,sBAAsB,CAAC,UAA+B;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;IAEO,KAAK,CAAC,YAAY,CACxB,QAAoB,EACpB,OAAmB,EACnB,QAAwC,EACxC,cAAwB;QAExB,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAe;gBACzB,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE;gBAC7B,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,IAAI,EAAE,OAAO,CAAC,IAAI;aACnB,CAAC;YAEF,yCAAyC;YACzC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACjD,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;oBACnC,IAAI,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;wBAC7B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBAChD,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;gBAC5B,MAAM,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;YACnD,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,2BAA2B;QAC3B,MAAM,MAAM,GAAe;YACzB,MAAM,EAAE,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE;YACjD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU;YACrD,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC;QAEF,2BAA2B;QAC3B,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACjD,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;gBACnC,IAAI,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;oBAC7B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,eAAe,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YACxD,MAAM,CAAC,eAAe,GAAG;gBACvB,GAAG,QAAQ,CAAC,eAAe;gBAC3B,GAAG,OAAO,CAAC,eAAe;aAC3B,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,aAAsB;QACjE,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,IAAI,UAAU,CAAC,CAAC;QAE9D,iCAAiC;QACjC,MAAM,kBAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC9B,yCAAyC;QACzC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEtC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjE,oEAAoE;QACpE,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,SAAS,SAAS,CAAC,CAAC;QAC3E,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,kBAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACpC,4CAA4C;YAC5C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,4BAA4B;QAC9B,CAAC;IACH,CAAC;CACF;AAjzBD,kCAizBC","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}\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 // 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 // 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}"]}
@@ -6,6 +6,8 @@ export interface PushOptions {
6
6
  verbose?: boolean;
7
7
  noValidate?: boolean;
8
8
  parallelBatchSize?: number;
9
+ include?: string[];
10
+ exclude?: string[];
9
11
  }
10
12
  export interface PushCallbacks {
11
13
  onProgress?: (message: string) => void;
@@ -38,13 +40,51 @@ export declare class PushService {
38
40
  private contextUser;
39
41
  private warnings;
40
42
  private syncConfig;
43
+ private deferredFileWrites;
41
44
  constructor(syncEngine: SyncEngine, contextUser: UserInfo);
42
45
  push(options: PushOptions, callbacks?: PushCallbacks): Promise<PushResult>;
43
46
  private processEntityDirectory;
44
47
  private processFlattenedRecord;
45
48
  private formatFieldValue;
46
49
  private processDeleteRecord;
50
+ /**
51
+ * Prompt user for confirmation before proceeding with push operation
52
+ * This happens after deletion audit but before any database operations
53
+ */
54
+ private promptForConfirmation;
55
+ /**
56
+ * Audit all deletions across all metadata files
57
+ * This pre-processes all records to identify deletion dependencies and order
58
+ */
59
+ private auditAllDeletions;
60
+ /**
61
+ * Process deletions in reverse dependency order
62
+ */
63
+ private processDeletionsFromAudit;
64
+ /**
65
+ * Recursively check if any records in an array (including nested relatedEntities) have deletions
66
+ */
67
+ private hasAnyDeletions;
68
+ /**
69
+ * Write all deferred files with updated deletion timestamps
70
+ * Called in Phase 3 after all deletions complete successfully
71
+ */
72
+ private writeDeferredFiles;
73
+ /**
74
+ * Update a record in deferred file writes after successful deletion
75
+ * Finds the matching RecordData by primary key and updates its deleteRecord section
76
+ * Searches recursively through nested relatedEntities
77
+ */
78
+ private updateDeferredFileRecord;
79
+ /**
80
+ * Recursively search a RecordData and its relatedEntities for a matching record
81
+ * Updates the matching record's deleteRecord timestamp
82
+ */
83
+ private findAndUpdateRecord;
84
+ /**
85
+ * Check if two RecordData objects represent the same record
86
+ * Compares primary keys and entity context
87
+ */
88
+ private recordsMatch;
47
89
  private _buildBatchContextKey;
48
- private findEntityDirectories;
49
- private findEntityDirectoriesRecursive;
50
90
  }