@memberjunction/metadata-sync 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,26 @@
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.configManager = exports.ConfigManager = void 0;
12
12
  const cosmiconfig_1 = require("cosmiconfig");
13
+ const config_1 = require("@memberjunction/config");
14
+ /**
15
+ * Default configuration for MetadataSync
16
+ *
17
+ * Provides database connection settings from environment variables,
18
+ * matching the pattern used by MJServer's DEFAULT_SERVER_CONFIG.
19
+ * This ensures consistent behavior with the MJ ecosystem.
20
+ */
21
+ const DEFAULT_SYNC_CONFIG = {
22
+ // Database connection settings (environment-driven with defaults)
23
+ dbHost: process.env.DB_HOST ?? 'localhost',
24
+ dbPort: process.env.DB_PORT ? parseInt(process.env.DB_PORT, 10) : 1433,
25
+ dbDatabase: process.env.DB_DATABASE,
26
+ dbUsername: process.env.DB_USERNAME,
27
+ dbPassword: process.env.DB_PASSWORD,
28
+ dbTrustServerCertificate: ['true', '1', 'Y', 'y'].includes(process.env.DB_TRUST_SERVER_CERTIFICATE ?? '') ? 'Y' : 'N',
29
+ dbEncrypt: process.env.DB_ENCRYPT ?? undefined,
30
+ dbInstanceName: process.env.DB_INSTANCE_NAME,
31
+ mjCoreSchema: process.env.MJ_CORE_SCHEMA ?? '__mj',
32
+ };
13
33
  /**
14
34
  * Configuration manager singleton for handling MJ configuration
15
35
  *
@@ -72,10 +92,11 @@ class ConfigManager {
72
92
  // Always search from the original working directory
73
93
  const searchPath = this.getOriginalCwd();
74
94
  const result = explorer.search(searchPath);
75
- if (!result || !result.config) {
76
- throw new Error('No mj.config.cjs found');
77
- }
78
- this.mjConfig = result.config;
95
+ // Merge user config with DEFAULT_SYNC_CONFIG (user config takes precedence)
96
+ // This ensures environment variables are used for database settings
97
+ // when not explicitly set in the config file
98
+ const userConfig = result?.config ?? {};
99
+ this.mjConfig = (0, config_1.mergeConfigs)(DEFAULT_SYNC_CONFIG, userConfig);
79
100
  this.configLoaded = true;
80
101
  return this.mjConfig;
81
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/lib/config-manager.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,6CAA8C;AAG9C;;;;;;GAMG;AACH,MAAa,aAAa;IAChB,MAAM,CAAC,QAAQ,CAAgB;IAC/B,WAAW,GAAkB,IAAI,CAAC;IAClC,QAAQ,GAAoB,IAAI,CAAC;IACjC,YAAY,GAAG,KAAK,CAAC;IAE7B;QACE,2CAA2C;IAC7C,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC5B,aAAa,CAAC,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAC/C,CAAC;QACD,OAAO,aAAa,CAAC,QAAQ,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,0BAA0B;YAC1B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,GAAW;QACxB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;IACzB,CAAC;IAED;;;;;;;;OAQG;IACH,YAAY,CAAC,WAAW,GAAG,KAAK;QAC9B,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,WAAW,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,QAAQ,CAAC;QACvB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAA,6BAAe,EAAC,IAAI,CAAC,CAAC;YACvC,oDAAoD;YACpD,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAE3C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAC5C,CAAC;YAED,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;YAC9B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,OAAO,IAAI,CAAC,QAAQ,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;QAC7B,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF;AAxFD,sCAwFC;AAED,4CAA4C;AAC/B,QAAA,aAAa,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC","sourcesContent":["/**\n * @fileoverview Shared configuration manager for MetadataSync commands\n * @module lib/config-manager\n * \n * This module provides a centralized configuration management system that handles\n * loading MJ config from the original working directory, regardless of any\n * directory changes made during command execution.\n */\n\nimport { cosmiconfigSync } from 'cosmiconfig';\nimport { MJConfig } from '../config';\n\n/**\n * Configuration manager singleton for handling MJ configuration\n * \n * Stores the original working directory and MJ configuration to ensure\n * consistent access across all commands, even when the current working\n * directory changes during execution.\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private originalCwd: string | null = null;\n private mjConfig: MJConfig | null = null;\n private configLoaded = false;\n\n private constructor() {\n // Original cwd will be set on first access\n }\n\n /**\n * Get the singleton instance of ConfigManager\n */\n static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * Get the original working directory from when the process started\n * \n * @returns The original working directory path\n */\n getOriginalCwd(): string {\n if (!this.originalCwd) {\n // Capture on first access\n this.originalCwd = process.cwd();\n }\n return this.originalCwd;\n }\n \n /**\n * Set the original working directory (for testing or special cases)\n * \n * @param cwd - The working directory to use as original\n */\n setOriginalCwd(cwd: string): void {\n this.originalCwd = cwd;\n }\n\n /**\n * Load MemberJunction configuration\n * \n * Searches for mj.config.cjs starting from the original working directory\n * and walking up the directory tree. Caches the result for subsequent calls.\n * \n * @param forceReload - Force reload the configuration even if cached\n * @returns MJConfig object if found, null if not found or invalid\n */\n loadMJConfig(forceReload = false): MJConfig | null {\n if (this.configLoaded && !forceReload) {\n return this.mjConfig;\n }\n\n try {\n const explorer = cosmiconfigSync('mj');\n // Always search from the original working directory\n const searchPath = this.getOriginalCwd();\n const result = explorer.search(searchPath);\n \n if (!result || !result.config) {\n throw new Error('No mj.config.cjs found');\n }\n \n this.mjConfig = result.config;\n this.configLoaded = true;\n return this.mjConfig;\n } catch (error) {\n console.error('Error loading MJ config:', error);\n this.mjConfig = null;\n this.configLoaded = true;\n return null;\n }\n }\n\n /**\n * Get the cached MJ configuration\n * \n * @returns The cached MJConfig or null if not loaded\n */\n getMJConfig(): MJConfig | null {\n if (!this.configLoaded) {\n return this.loadMJConfig();\n }\n return this.mjConfig;\n }\n}\n\n// Export singleton instance for convenience\nexport const configManager = ConfigManager.getInstance();"]}
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/lib/config-manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Shared configuration manager for MetadataSync commands\n * @module lib/config-manager\n *\n * This module provides a centralized configuration management system that handles\n * loading MJ config from the original working directory, regardless of any\n * directory changes made during command execution.\n */\n\nimport { cosmiconfigSync } from 'cosmiconfig';\nimport { mergeConfigs } from '@memberjunction/config';\nimport { MJConfig } from '../config';\n\n/**\n * Default configuration for MetadataSync\n *\n * Provides database connection settings from environment variables,\n * matching the pattern used by MJServer's DEFAULT_SERVER_CONFIG.\n * This ensures consistent behavior with the MJ ecosystem.\n */\nconst DEFAULT_SYNC_CONFIG: Partial<MJConfig> = {\n // Database connection settings (environment-driven with defaults)\n dbHost: process.env.DB_HOST ?? 'localhost',\n dbPort: process.env.DB_PORT ? parseInt(process.env.DB_PORT, 10) : 1433,\n dbDatabase: process.env.DB_DATABASE,\n dbUsername: process.env.DB_USERNAME,\n dbPassword: process.env.DB_PASSWORD,\n dbTrustServerCertificate: ['true', '1', 'Y', 'y'].includes(process.env.DB_TRUST_SERVER_CERTIFICATE ?? '') ? 'Y' : 'N',\n dbEncrypt: process.env.DB_ENCRYPT ?? undefined,\n dbInstanceName: process.env.DB_INSTANCE_NAME,\n mjCoreSchema: process.env.MJ_CORE_SCHEMA ?? '__mj',\n};\n\n/**\n * Configuration manager singleton for handling MJ configuration\n * \n * Stores the original working directory and MJ configuration to ensure\n * consistent access across all commands, even when the current working\n * directory changes during execution.\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private originalCwd: string | null = null;\n private mjConfig: MJConfig | null = null;\n private configLoaded = false;\n\n private constructor() {\n // Original cwd will be set on first access\n }\n\n /**\n * Get the singleton instance of ConfigManager\n */\n static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * Get the original working directory from when the process started\n * \n * @returns The original working directory path\n */\n getOriginalCwd(): string {\n if (!this.originalCwd) {\n // Capture on first access\n this.originalCwd = process.cwd();\n }\n return this.originalCwd;\n }\n \n /**\n * Set the original working directory (for testing or special cases)\n * \n * @param cwd - The working directory to use as original\n */\n setOriginalCwd(cwd: string): void {\n this.originalCwd = cwd;\n }\n\n /**\n * Load MemberJunction configuration\n * \n * Searches for mj.config.cjs starting from the original working directory\n * and walking up the directory tree. Caches the result for subsequent calls.\n * \n * @param forceReload - Force reload the configuration even if cached\n * @returns MJConfig object if found, null if not found or invalid\n */\n loadMJConfig(forceReload = false): MJConfig | null {\n if (this.configLoaded && !forceReload) {\n return this.mjConfig;\n }\n\n try {\n const explorer = cosmiconfigSync('mj');\n // Always search from the original working directory\n const searchPath = this.getOriginalCwd();\n const result = explorer.search(searchPath);\n\n // Merge user config with DEFAULT_SYNC_CONFIG (user config takes precedence)\n // This ensures environment variables are used for database settings\n // when not explicitly set in the config file\n const userConfig = result?.config ?? {};\n this.mjConfig = mergeConfigs(DEFAULT_SYNC_CONFIG, userConfig) as MJConfig;\n this.configLoaded = true;\n return this.mjConfig;\n } catch (error) {\n console.error('Error loading MJ config:', error);\n this.mjConfig = null;\n this.configLoaded = true;\n return null;\n }\n }\n\n /**\n * Get the cached MJ configuration\n * \n * @returns The cached MJConfig or null if not loaded\n */\n getMJConfig(): MJConfig | null {\n if (!this.configLoaded) {\n return this.loadMJConfig();\n }\n return this.mjConfig;\n }\n}\n\n// Export singleton instance for convenience\nexport const configManager = ConfigManager.getInstance();"]}
@@ -81,7 +81,7 @@ async function initializeProvider(config) {
81
81
  password: config.dbPassword,
82
82
  options: {
83
83
  encrypt: config.dbEncrypt === 'Y' || config.dbEncrypt === 'true' ||
84
- config.dbHost.includes('.database.windows.net'), // Auto-detect Azure SQL
84
+ config.dbHost?.includes('.database.windows.net'), // Auto-detect Azure SQL
85
85
  trustServerCertificate: config.dbTrustServerCertificate === 'Y',
86
86
  instanceName: config.dbInstanceName,
87
87
  enableArithAbort: true
@@ -1 +1 @@
1
- {"version":3,"file":"provider-utils.js","sourceRoot":"","sources":["../../src/lib/provider-utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Database provider utilities for MetadataSync\n * @module provider-utils\n * \n * This module provides utilities for initializing and managing the database\n * connection, accessing system users, and finding entity directories. It handles\n * the mssql ConnectionPool lifecycle and MemberJunction provider initialization.\n */\n\nimport * as sql from 'mssql';\nimport { SQLServerDataProvider, SQLServerProviderConfigData, UserCache, setupSQLServerClient } from '@memberjunction/sqlserver-dataprovider';\nimport type { MJConfig } from '../config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { DatabaseProviderBase, UserInfo } from '@memberjunction/core';\nimport { minimatch } from 'minimatch';\n\n/** Global ConnectionPool instance for connection lifecycle management */\nlet globalPool: sql.ConnectionPool | null = null;\n\n/** Global provider instance to ensure single initialization */\nlet globalProvider: SQLServerDataProvider | null = null;\n\n/** Promise to track ongoing initialization */\nlet initializationPromise: Promise<SQLServerDataProvider> | null = null;\n\n/**\n * Initialize a SQLServerDataProvider with the given configuration\n * \n * Creates and initializes a mssql ConnectionPool for SQL Server, then sets up\n * the MemberJunction SQLServerDataProvider. The connection is stored globally\n * for proper cleanup. Auto-detects Azure SQL databases for encryption settings.\n * \n * @param config - MemberJunction configuration with database connection details\n * @returns Promise resolving to initialized SQLServerDataProvider instance\n * @throws Error if database connection fails\n * \n * @example\n * ```typescript\n * const config = loadMJConfig();\n * const provider = await initializeProvider(config);\n * // Provider is ready for use\n * ```\n */\nexport async function initializeProvider(config: MJConfig): Promise<SQLServerDataProvider> {\n // Return existing provider if already initialized\n if (globalProvider) {\n return globalProvider;\n }\n \n // Return ongoing initialization if in progress\n if (initializationPromise) {\n return initializationPromise;\n }\n \n // Start new initialization\n initializationPromise = (async () => {\n // Create mssql config\n const poolConfig: sql.config = {\n server: config.dbHost,\n port: config.dbPort ? Number(config.dbPort) : 1433,\n database: config.dbDatabase,\n user: config.dbUsername,\n password: config.dbPassword,\n options: {\n encrypt: config.dbEncrypt === 'Y' || config.dbEncrypt === 'true' || \n config.dbHost.includes('.database.windows.net'), // Auto-detect Azure SQL\n trustServerCertificate: config.dbTrustServerCertificate === 'Y',\n instanceName: config.dbInstanceName,\n enableArithAbort: true\n }\n };\n \n // Create and connect pool\n const pool = new sql.ConnectionPool(poolConfig);\n await pool.connect();\n \n // Store for cleanup\n globalPool = pool;\n \n // Create provider config\n const providerConfig = new SQLServerProviderConfigData(\n pool,\n config.mjCoreSchema || '__mj' \n );\n \n // Use setupSQLServerClient to properly initialize\n globalProvider = await setupSQLServerClient(providerConfig);\n return globalProvider;\n })();\n \n return initializationPromise;\n}\n\n/**\n * Clean up the global database connection\n * \n * Closes the mssql ConnectionPool if it exists and is connected.\n * Should be called when the CLI command completes to ensure proper cleanup.\n * \n * @returns Promise that resolves when cleanup is complete\n * \n * @example\n * ```typescript\n * try {\n * // Do work with database\n * } finally {\n * await cleanupProvider();\n * }\n * ```\n */\nexport async function cleanupProvider(): Promise<void> {\n if (globalPool && globalPool.connected) {\n await globalPool.close();\n globalPool = null;\n }\n globalProvider = null;\n initializationPromise = null;\n}\n\n/**\n * Get the system user from the UserCache\n * \n * Retrieves the \"System\" user from MemberJunction's UserCache. This user is\n * typically used for CLI operations where no specific user context exists.\n * The System user must have the Developer role to perform metadata sync operations.\n * \n * @returns The System UserInfo object\n * @throws Error if System user is not found in the cache or doesn't have Developer role\n * \n * @example\n * ```typescript\n * const systemUser = getSystemUser();\n * const syncEngine = new SyncEngine(systemUser);\n * ```\n */\nexport function getSystemUser(): UserInfo {\n const sysUser = UserCache.Instance.UserByName(\"System\", false);\n if (!sysUser) {\n throw new Error(\"System user not found in cache. Ensure the system user exists in the database.\"); \n }\n \n // Check if the System user has the Developer role\n const hasDeveloperRole = sysUser.UserRoles && sysUser.UserRoles.some(\n userRole => userRole.Role.trim().toLowerCase() === 'developer'\n );\n \n if (!hasDeveloperRole) {\n throw new Error(\n \"System user does not have the 'Developer' role. \" +\n \"The Developer role is required for metadata sync operations. \" +\n \"Please ensure the System user is assigned the Developer role in the database:\\n\" +\n \"* Add a record to the __mj.UserRole table linking the System user to the Developer role\"\n );\n }\n \n return sysUser;\n}\n\n/**\n * Get the current data provider instance\n * \n * Returns the global SQLServerDataProvider instance that was initialized by\n * initializeProvider. This allows access to data provider features like SQL logging.\n * \n * @returns The global SQLServerDataProvider instance or null if not initialized\n * \n * @example\n * ```typescript\n * const provider = getDataProvider();\n * if (provider?.CreateSqlLogger) {\n * const logger = await provider.CreateSqlLogger('/path/to/log.sql');\n * }\n * ```\n */\nexport function getDataProvider(): DatabaseProviderBase | null {\n return globalProvider;\n}\n\n/**\n * Find entity directories at the immediate level only\n *\n * Searches for directories containing .mj-sync.json files, which indicate\n * entity data directories. Only searches immediate subdirectories, not recursive.\n * If a specific directory is provided, only checks that directory.\n *\n * @param dir - Base directory to search from\n * @param specificDir - Optional specific subdirectory name to check\n * @param directoryOrder - Optional array specifying the order directories should be processed\n * @param ignoreDirectories - Optional array of directory patterns to ignore\n * @param includeFilter - Optional array of directory patterns to include (whitelist)\n * @param excludeFilter - Optional array of directory patterns to exclude (blacklist)\n * @returns Array of absolute directory paths containing .mj-sync.json files, ordered according to directoryOrder\n *\n * @example\n * ```typescript\n * // Find all entity directories\n * const dirs = findEntityDirectories(process.cwd());\n *\n * // Check specific directory\n * const dirs = findEntityDirectories(process.cwd(), 'ai-prompts');\n *\n * // Find directories with custom ordering\n * const dirs = findEntityDirectories(process.cwd(), undefined, ['prompts', 'agent-types']);\n *\n * // Filter with include patterns\n * const dirs = findEntityDirectories(process.cwd(), undefined, undefined, undefined, ['prompts', 'agent-*']);\n *\n * // Filter with exclude patterns\n * const dirs = findEntityDirectories(process.cwd(), undefined, undefined, undefined, undefined, ['*-test', 'temp']);\n * ```\n */\nexport function findEntityDirectories(\n dir: string,\n specificDir?: string,\n directoryOrder?: string[],\n ignoreDirectories?: string[],\n includeFilter?: string[],\n excludeFilter?: string[]\n): string[] {\n const results: string[] = [];\n \n // If specific directory is provided, check if it's an entity directory or root config directory\n if (specificDir) {\n const targetDir = path.isAbsolute(specificDir) ? specificDir : path.join(dir, specificDir);\n if (fs.existsSync(targetDir)) {\n const syncConfigPath = path.join(targetDir, '.mj-sync.json');\n const hasSyncConfig = fs.existsSync(syncConfigPath);\n \n if (hasSyncConfig) {\n try {\n const config = JSON.parse(fs.readFileSync(syncConfigPath, 'utf8'));\n \n // If this config has an entity field, it's an entity directory\n if (config.entity) {\n results.push(targetDir);\n return results;\n }\n \n // If this config has directoryOrder but no entity, treat it as a root config\n // and look for entity directories in its subdirectories\n if (config.directoryOrder) {\n // Merge ignore directories from parent with current config\n const mergedIgnoreDirectories = [\n ...(ignoreDirectories || []),\n ...(config.ignoreDirectories || [])\n ];\n return findEntityDirectories(\n targetDir,\n undefined,\n config.directoryOrder,\n mergedIgnoreDirectories,\n includeFilter,\n excludeFilter\n );\n }\n } catch (error) {\n // If we can't parse the config, treat it as a regular directory\n }\n }\n \n // Fallback: look for entity subdirectories in the target directory\n return findEntityDirectories(targetDir, undefined, directoryOrder, ignoreDirectories, includeFilter, excludeFilter);\n }\n return results;\n }\n \n // Otherwise, find all immediate subdirectories with .mj-sync.json\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n const foundDirectories: string[] = [];\n \n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n // Check if this directory should be ignored\n if (ignoreDirectories && ignoreDirectories.some(pattern => {\n // Simple pattern matching: exact name or ends with pattern\n return entry.name === pattern || entry.name.endsWith(pattern);\n })) {\n continue;\n }\n \n const subDir = path.join(dir, entry.name);\n const hasSyncConfig = fs.existsSync(path.join(subDir, '.mj-sync.json'));\n \n if (hasSyncConfig) {\n foundDirectories.push(subDir);\n }\n }\n }\n \n // If directoryOrder is specified, sort directories according to it\n if (directoryOrder && directoryOrder.length > 0) {\n const orderedDirs: string[] = [];\n const unorderedDirs: string[] = [];\n \n // First, add directories in the specified order\n for (const dirName of directoryOrder) {\n const matchingDir = foundDirectories.find(fullPath => \n path.basename(fullPath) === dirName\n );\n if (matchingDir) {\n orderedDirs.push(matchingDir);\n }\n }\n \n // Then, add any remaining directories in alphabetical order\n for (const foundDir of foundDirectories) {\n const dirName = path.basename(foundDir);\n if (!directoryOrder.includes(dirName)) {\n unorderedDirs.push(foundDir);\n }\n }\n \n // Sort unordered directories alphabetically\n unorderedDirs.sort((a, b) => path.basename(a).localeCompare(path.basename(b)));\n\n const allDirs = [...orderedDirs, ...unorderedDirs];\n return applyDirectoryFilters(allDirs, includeFilter, excludeFilter);\n }\n\n // No ordering specified, return in alphabetical order (existing behavior)\n const sortedDirs = foundDirectories.sort((a, b) => path.basename(a).localeCompare(path.basename(b)));\n return applyDirectoryFilters(sortedDirs, includeFilter, excludeFilter);\n}\n\n/**\n * Apply include/exclude filters to a list of directories\n *\n * @param directories - Array of directory paths to filter\n * @param includeFilter - Optional array of patterns to include (whitelist)\n * @param excludeFilter - Optional array of patterns to exclude (blacklist)\n * @returns Filtered array of directory paths\n */\nfunction applyDirectoryFilters(\n directories: string[],\n includeFilter?: string[],\n excludeFilter?: string[]\n): string[] {\n let filteredDirs = directories;\n\n // Apply include filter (whitelist)\n if (includeFilter && includeFilter.length > 0) {\n filteredDirs = directories.filter(dir => {\n const dirName = path.basename(dir);\n return includeFilter.some(pattern =>\n minimatch(dirName, pattern, { nocase: true })\n );\n });\n }\n\n // Apply exclude filter (blacklist)\n if (excludeFilter && excludeFilter.length > 0) {\n filteredDirs = filteredDirs.filter(dir => {\n const dirName = path.basename(dir);\n return !excludeFilter.some(pattern =>\n minimatch(dirName, pattern, { nocase: true })\n );\n });\n }\n\n return filteredDirs;\n}"]}
1
+ {"version":3,"file":"provider-utils.js","sourceRoot":"","sources":["../../src/lib/provider-utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Database provider utilities for MetadataSync\n * @module provider-utils\n * \n * This module provides utilities for initializing and managing the database\n * connection, accessing system users, and finding entity directories. It handles\n * the mssql ConnectionPool lifecycle and MemberJunction provider initialization.\n */\n\nimport * as sql from 'mssql';\nimport { SQLServerDataProvider, SQLServerProviderConfigData, UserCache, setupSQLServerClient } from '@memberjunction/sqlserver-dataprovider';\nimport type { MJConfig } from '../config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { DatabaseProviderBase, UserInfo } from '@memberjunction/core';\nimport { minimatch } from 'minimatch';\n\n/** Global ConnectionPool instance for connection lifecycle management */\nlet globalPool: sql.ConnectionPool | null = null;\n\n/** Global provider instance to ensure single initialization */\nlet globalProvider: SQLServerDataProvider | null = null;\n\n/** Promise to track ongoing initialization */\nlet initializationPromise: Promise<SQLServerDataProvider> | null = null;\n\n/**\n * Initialize a SQLServerDataProvider with the given configuration\n * \n * Creates and initializes a mssql ConnectionPool for SQL Server, then sets up\n * the MemberJunction SQLServerDataProvider. The connection is stored globally\n * for proper cleanup. Auto-detects Azure SQL databases for encryption settings.\n * \n * @param config - MemberJunction configuration with database connection details\n * @returns Promise resolving to initialized SQLServerDataProvider instance\n * @throws Error if database connection fails\n * \n * @example\n * ```typescript\n * const config = loadMJConfig();\n * const provider = await initializeProvider(config);\n * // Provider is ready for use\n * ```\n */\nexport async function initializeProvider(config: MJConfig): Promise<SQLServerDataProvider> {\n // Return existing provider if already initialized\n if (globalProvider) {\n return globalProvider;\n }\n \n // Return ongoing initialization if in progress\n if (initializationPromise) {\n return initializationPromise;\n }\n \n // Start new initialization\n initializationPromise = (async () => {\n // Create mssql config\n const poolConfig: sql.config = {\n server: config.dbHost,\n port: config.dbPort ? Number(config.dbPort) : 1433,\n database: config.dbDatabase,\n user: config.dbUsername,\n password: config.dbPassword,\n options: {\n encrypt: config.dbEncrypt === 'Y' || config.dbEncrypt === 'true' ||\n config.dbHost?.includes('.database.windows.net'), // Auto-detect Azure SQL\n trustServerCertificate: config.dbTrustServerCertificate === 'Y',\n instanceName: config.dbInstanceName,\n enableArithAbort: true\n }\n };\n \n // Create and connect pool\n const pool = new sql.ConnectionPool(poolConfig);\n await pool.connect();\n \n // Store for cleanup\n globalPool = pool;\n \n // Create provider config\n const providerConfig = new SQLServerProviderConfigData(\n pool,\n config.mjCoreSchema || '__mj' \n );\n \n // Use setupSQLServerClient to properly initialize\n globalProvider = await setupSQLServerClient(providerConfig);\n return globalProvider;\n })();\n \n return initializationPromise;\n}\n\n/**\n * Clean up the global database connection\n * \n * Closes the mssql ConnectionPool if it exists and is connected.\n * Should be called when the CLI command completes to ensure proper cleanup.\n * \n * @returns Promise that resolves when cleanup is complete\n * \n * @example\n * ```typescript\n * try {\n * // Do work with database\n * } finally {\n * await cleanupProvider();\n * }\n * ```\n */\nexport async function cleanupProvider(): Promise<void> {\n if (globalPool && globalPool.connected) {\n await globalPool.close();\n globalPool = null;\n }\n globalProvider = null;\n initializationPromise = null;\n}\n\n/**\n * Get the system user from the UserCache\n * \n * Retrieves the \"System\" user from MemberJunction's UserCache. This user is\n * typically used for CLI operations where no specific user context exists.\n * The System user must have the Developer role to perform metadata sync operations.\n * \n * @returns The System UserInfo object\n * @throws Error if System user is not found in the cache or doesn't have Developer role\n * \n * @example\n * ```typescript\n * const systemUser = getSystemUser();\n * const syncEngine = new SyncEngine(systemUser);\n * ```\n */\nexport function getSystemUser(): UserInfo {\n const sysUser = UserCache.Instance.UserByName(\"System\", false);\n if (!sysUser) {\n throw new Error(\"System user not found in cache. Ensure the system user exists in the database.\"); \n }\n \n // Check if the System user has the Developer role\n const hasDeveloperRole = sysUser.UserRoles && sysUser.UserRoles.some(\n userRole => userRole.Role.trim().toLowerCase() === 'developer'\n );\n \n if (!hasDeveloperRole) {\n throw new Error(\n \"System user does not have the 'Developer' role. \" +\n \"The Developer role is required for metadata sync operations. \" +\n \"Please ensure the System user is assigned the Developer role in the database:\\n\" +\n \"* Add a record to the __mj.UserRole table linking the System user to the Developer role\"\n );\n }\n \n return sysUser;\n}\n\n/**\n * Get the current data provider instance\n * \n * Returns the global SQLServerDataProvider instance that was initialized by\n * initializeProvider. This allows access to data provider features like SQL logging.\n * \n * @returns The global SQLServerDataProvider instance or null if not initialized\n * \n * @example\n * ```typescript\n * const provider = getDataProvider();\n * if (provider?.CreateSqlLogger) {\n * const logger = await provider.CreateSqlLogger('/path/to/log.sql');\n * }\n * ```\n */\nexport function getDataProvider(): DatabaseProviderBase | null {\n return globalProvider;\n}\n\n/**\n * Find entity directories at the immediate level only\n *\n * Searches for directories containing .mj-sync.json files, which indicate\n * entity data directories. Only searches immediate subdirectories, not recursive.\n * If a specific directory is provided, only checks that directory.\n *\n * @param dir - Base directory to search from\n * @param specificDir - Optional specific subdirectory name to check\n * @param directoryOrder - Optional array specifying the order directories should be processed\n * @param ignoreDirectories - Optional array of directory patterns to ignore\n * @param includeFilter - Optional array of directory patterns to include (whitelist)\n * @param excludeFilter - Optional array of directory patterns to exclude (blacklist)\n * @returns Array of absolute directory paths containing .mj-sync.json files, ordered according to directoryOrder\n *\n * @example\n * ```typescript\n * // Find all entity directories\n * const dirs = findEntityDirectories(process.cwd());\n *\n * // Check specific directory\n * const dirs = findEntityDirectories(process.cwd(), 'ai-prompts');\n *\n * // Find directories with custom ordering\n * const dirs = findEntityDirectories(process.cwd(), undefined, ['prompts', 'agent-types']);\n *\n * // Filter with include patterns\n * const dirs = findEntityDirectories(process.cwd(), undefined, undefined, undefined, ['prompts', 'agent-*']);\n *\n * // Filter with exclude patterns\n * const dirs = findEntityDirectories(process.cwd(), undefined, undefined, undefined, undefined, ['*-test', 'temp']);\n * ```\n */\nexport function findEntityDirectories(\n dir: string,\n specificDir?: string,\n directoryOrder?: string[],\n ignoreDirectories?: string[],\n includeFilter?: string[],\n excludeFilter?: string[]\n): string[] {\n const results: string[] = [];\n \n // If specific directory is provided, check if it's an entity directory or root config directory\n if (specificDir) {\n const targetDir = path.isAbsolute(specificDir) ? specificDir : path.join(dir, specificDir);\n if (fs.existsSync(targetDir)) {\n const syncConfigPath = path.join(targetDir, '.mj-sync.json');\n const hasSyncConfig = fs.existsSync(syncConfigPath);\n \n if (hasSyncConfig) {\n try {\n const config = JSON.parse(fs.readFileSync(syncConfigPath, 'utf8'));\n \n // If this config has an entity field, it's an entity directory\n if (config.entity) {\n results.push(targetDir);\n return results;\n }\n \n // If this config has directoryOrder but no entity, treat it as a root config\n // and look for entity directories in its subdirectories\n if (config.directoryOrder) {\n // Merge ignore directories from parent with current config\n const mergedIgnoreDirectories = [\n ...(ignoreDirectories || []),\n ...(config.ignoreDirectories || [])\n ];\n return findEntityDirectories(\n targetDir,\n undefined,\n config.directoryOrder,\n mergedIgnoreDirectories,\n includeFilter,\n excludeFilter\n );\n }\n } catch (error) {\n // If we can't parse the config, treat it as a regular directory\n }\n }\n \n // Fallback: look for entity subdirectories in the target directory\n return findEntityDirectories(targetDir, undefined, directoryOrder, ignoreDirectories, includeFilter, excludeFilter);\n }\n return results;\n }\n \n // Otherwise, find all immediate subdirectories with .mj-sync.json\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n const foundDirectories: string[] = [];\n \n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n // Check if this directory should be ignored\n if (ignoreDirectories && ignoreDirectories.some(pattern => {\n // Simple pattern matching: exact name or ends with pattern\n return entry.name === pattern || entry.name.endsWith(pattern);\n })) {\n continue;\n }\n \n const subDir = path.join(dir, entry.name);\n const hasSyncConfig = fs.existsSync(path.join(subDir, '.mj-sync.json'));\n \n if (hasSyncConfig) {\n foundDirectories.push(subDir);\n }\n }\n }\n \n // If directoryOrder is specified, sort directories according to it\n if (directoryOrder && directoryOrder.length > 0) {\n const orderedDirs: string[] = [];\n const unorderedDirs: string[] = [];\n \n // First, add directories in the specified order\n for (const dirName of directoryOrder) {\n const matchingDir = foundDirectories.find(fullPath => \n path.basename(fullPath) === dirName\n );\n if (matchingDir) {\n orderedDirs.push(matchingDir);\n }\n }\n \n // Then, add any remaining directories in alphabetical order\n for (const foundDir of foundDirectories) {\n const dirName = path.basename(foundDir);\n if (!directoryOrder.includes(dirName)) {\n unorderedDirs.push(foundDir);\n }\n }\n \n // Sort unordered directories alphabetically\n unorderedDirs.sort((a, b) => path.basename(a).localeCompare(path.basename(b)));\n\n const allDirs = [...orderedDirs, ...unorderedDirs];\n return applyDirectoryFilters(allDirs, includeFilter, excludeFilter);\n }\n\n // No ordering specified, return in alphabetical order (existing behavior)\n const sortedDirs = foundDirectories.sort((a, b) => path.basename(a).localeCompare(path.basename(b)));\n return applyDirectoryFilters(sortedDirs, includeFilter, excludeFilter);\n}\n\n/**\n * Apply include/exclude filters to a list of directories\n *\n * @param directories - Array of directory paths to filter\n * @param includeFilter - Optional array of patterns to include (whitelist)\n * @param excludeFilter - Optional array of patterns to exclude (blacklist)\n * @returns Filtered array of directory paths\n */\nfunction applyDirectoryFilters(\n directories: string[],\n includeFilter?: string[],\n excludeFilter?: string[]\n): string[] {\n let filteredDirs = directories;\n\n // Apply include filter (whitelist)\n if (includeFilter && includeFilter.length > 0) {\n filteredDirs = directories.filter(dir => {\n const dirName = path.basename(dir);\n return includeFilter.some(pattern =>\n minimatch(dirName, pattern, { nocase: true })\n );\n });\n }\n\n // Apply exclude filter (blacklist)\n if (excludeFilter && excludeFilter.length > 0) {\n filteredDirs = filteredDirs.filter(dir => {\n const dirName = path.basename(dir);\n return !excludeFilter.some(pattern =>\n minimatch(dirName, pattern, { nocase: true })\n );\n });\n }\n\n return filteredDirs;\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/metadata-sync",
3
- "version": "3.0.0",
3
+ "version": "3.1.1",
4
4
  "description": "MemberJunction metadata synchronization CLI tool",
5
5
  "keywords": [
6
6
  "metadata",
@@ -26,17 +26,17 @@
26
26
  "build": "tsc -b"
27
27
  },
28
28
  "dependencies": {
29
- "@memberjunction/core": "3.0.0",
30
- "@memberjunction/core-entities": "3.0.0",
31
- "@memberjunction/core-entities-server": "3.0.0",
32
- "@memberjunction/global": "3.0.0",
33
- "@memberjunction/graphql-dataprovider": "3.0.0",
34
- "@memberjunction/sqlserver-dataprovider": "3.0.0",
29
+ "@memberjunction/config": "3.1.1",
30
+ "@memberjunction/core": "3.1.1",
31
+ "@memberjunction/core-entities": "3.1.1",
32
+ "@memberjunction/core-entities-server": "3.1.1",
33
+ "@memberjunction/global": "3.1.1",
34
+ "@memberjunction/graphql-dataprovider": "3.1.1",
35
+ "@memberjunction/sqlserver-dataprovider": "3.1.1",
35
36
  "axios": "^1.6.8",
36
37
  "chalk": "^4.1.2",
37
38
  "chokidar": "^3.6.0",
38
39
  "cosmiconfig": "9.0.0",
39
- "crypto": "^1.0.1",
40
40
  "dotenv": "16.4.5",
41
41
  "fast-glob": "^3.3.2",
42
42
  "fs-extra": "^11.2.0",