@memberjunction/metadata-sync 2.47.0 → 2.48.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.
- package/README.md +217 -15
- package/dist/commands/pull/index.d.ts +90 -5
- package/dist/commands/pull/index.js +930 -118
- package/dist/commands/pull/index.js.map +1 -1
- package/dist/commands/push/index.js +18 -10
- package/dist/commands/push/index.js.map +1 -1
- package/dist/commands/status/index.js +18 -7
- package/dist/commands/status/index.js.map +1 -1
- package/dist/commands/watch/index.js +19 -6
- package/dist/commands/watch/index.js.map +1 -1
- package/dist/config.d.ts +69 -0
- package/dist/config.js +2 -13
- package/dist/config.js.map +1 -1
- package/dist/hooks/init.js +3 -0
- package/dist/hooks/init.js.map +1 -1
- package/dist/lib/config-manager.d.ts +56 -0
- package/dist/lib/config-manager.js +104 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/provider-utils.js +45 -26
- package/dist/lib/provider-utils.js.map +1 -1
- package/dist/lib/singleton-manager.d.ts +34 -0
- package/dist/lib/singleton-manager.js +62 -0
- package/dist/lib/singleton-manager.js.map +1 -0
- package/oclif.manifest.json +50 -43
- package/package.json +6 -6
|
@@ -38,6 +38,10 @@ const fs = __importStar(require("fs"));
|
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
/** Global DataSource instance for connection lifecycle management */
|
|
40
40
|
let globalDataSource = null;
|
|
41
|
+
/** Global provider instance to ensure single initialization */
|
|
42
|
+
let globalProvider = null;
|
|
43
|
+
/** Promise to track ongoing initialization */
|
|
44
|
+
let initializationPromise = null;
|
|
41
45
|
/**
|
|
42
46
|
* Initialize a SQLServerDataProvider with the given configuration
|
|
43
47
|
*
|
|
@@ -57,32 +61,45 @@ let globalDataSource = null;
|
|
|
57
61
|
* ```
|
|
58
62
|
*/
|
|
59
63
|
async function initializeProvider(config) {
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
64
|
+
// Return existing provider if already initialized
|
|
65
|
+
if (globalProvider) {
|
|
66
|
+
return globalProvider;
|
|
67
|
+
}
|
|
68
|
+
// Return ongoing initialization if in progress
|
|
69
|
+
if (initializationPromise) {
|
|
70
|
+
return initializationPromise;
|
|
71
|
+
}
|
|
72
|
+
// Start new initialization
|
|
73
|
+
initializationPromise = (async () => {
|
|
74
|
+
// Create TypeORM DataSource
|
|
75
|
+
const dataSource = new typeorm_1.DataSource({
|
|
76
|
+
type: 'mssql',
|
|
77
|
+
host: config.dbHost,
|
|
78
|
+
port: config.dbPort ? Number(config.dbPort) : 1433,
|
|
79
|
+
database: config.dbDatabase,
|
|
80
|
+
username: config.dbUsername,
|
|
81
|
+
password: config.dbPassword,
|
|
82
|
+
synchronize: false,
|
|
83
|
+
logging: false,
|
|
84
|
+
options: {
|
|
85
|
+
encrypt: config.dbEncrypt === 'Y' || config.dbEncrypt === 'true' ||
|
|
86
|
+
config.dbHost.includes('.database.windows.net'), // Auto-detect Azure SQL
|
|
87
|
+
trustServerCertificate: config.dbTrustServerCertificate === 'Y',
|
|
88
|
+
instanceName: config.dbInstanceName
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
// Initialize the data source
|
|
92
|
+
await dataSource.initialize();
|
|
93
|
+
// Store for cleanup
|
|
94
|
+
globalDataSource = dataSource;
|
|
95
|
+
// Create provider config
|
|
96
|
+
const providerConfig = new sqlserver_dataprovider_1.SQLServerProviderConfigData(dataSource, 'system@sync.cli', // Default user for CLI
|
|
97
|
+
config.mjCoreSchema || '__mj', 0);
|
|
98
|
+
// Use setupSQLServerClient to properly initialize
|
|
99
|
+
globalProvider = await (0, sqlserver_dataprovider_1.setupSQLServerClient)(providerConfig);
|
|
100
|
+
return globalProvider;
|
|
101
|
+
})();
|
|
102
|
+
return initializationPromise;
|
|
86
103
|
}
|
|
87
104
|
exports.initializeProvider = initializeProvider;
|
|
88
105
|
/**
|
|
@@ -107,6 +124,8 @@ async function cleanupProvider() {
|
|
|
107
124
|
await globalDataSource.destroy();
|
|
108
125
|
globalDataSource = null;
|
|
109
126
|
}
|
|
127
|
+
globalProvider = null;
|
|
128
|
+
initializationPromise = null;
|
|
110
129
|
}
|
|
111
130
|
exports.cleanupProvider = cleanupProvider;
|
|
112
131
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-utils.js","sourceRoot":"","sources":["../../src/lib/provider-utils.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,qCAAqC;AACrC,mFAA6I;AAE7I,uCAAyB;AACzB,2CAA6B;
|
|
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 TypeORM DataSource lifecycle and MemberJunction provider initialization.\n */\n\nimport { DataSource } from 'typeorm';\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 { UserInfo } from '@memberjunction/core';\nimport { configManager } from './config-manager';\n\n/** Global DataSource instance for connection lifecycle management */\nlet globalDataSource: DataSource | 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 TypeORM DataSource 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 TypeORM DataSource\n const dataSource = new DataSource({\n type: 'mssql',\n host: config.dbHost,\n port: config.dbPort ? Number(config.dbPort) : 1433,\n database: config.dbDatabase,\n username: config.dbUsername,\n password: config.dbPassword,\n synchronize: false,\n logging: false,\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 }\n });\n \n // Initialize the data source\n await dataSource.initialize();\n \n // Store for cleanup\n globalDataSource = dataSource;\n \n // Create provider config\n const providerConfig = new SQLServerProviderConfigData(\n dataSource,\n 'system@sync.cli', // Default user for CLI\n config.mjCoreSchema || '__mj',\n 0\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 * Destroys the TypeORM DataSource if it exists and is initialized.\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 (globalDataSource && globalDataSource.isInitialized) {\n await globalDataSource.destroy();\n globalDataSource = 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 * \n * @returns The System UserInfo object\n * @throws Error if System user is not found in the cache\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 return sysUser;\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 * @returns Array of absolute directory paths containing .mj-sync.json files\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 */\nexport function findEntityDirectories(dir: string, specificDir?: string): string[] {\n const results: string[] = [];\n \n // If specific directory is provided, check if it's an entity directory\n if (specificDir) {\n const targetDir = path.isAbsolute(specificDir) ? specificDir : path.join(dir, specificDir);\n if (fs.existsSync(targetDir)) {\n const hasSyncConfig = fs.existsSync(path.join(targetDir, '.mj-sync.json'));\n if (hasSyncConfig) {\n results.push(targetDir);\n }\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 \n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n const subDir = path.join(dir, entry.name);\n const hasSyncConfig = fs.existsSync(path.join(subDir, '.mj-sync.json'));\n \n if (hasSyncConfig) {\n results.push(subDir);\n }\n }\n }\n \n return results;\n}"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Singleton manager for shared instances across MetadataSync
|
|
3
|
+
* @module singleton-manager
|
|
4
|
+
*
|
|
5
|
+
* This module ensures that expensive resources like SyncEngine are only
|
|
6
|
+
* initialized once per process, preventing duplicate metadata refreshes
|
|
7
|
+
* and improving performance.
|
|
8
|
+
*/
|
|
9
|
+
import { SyncEngine } from './sync-engine';
|
|
10
|
+
import { UserInfo } from '@memberjunction/core';
|
|
11
|
+
/**
|
|
12
|
+
* Get or create a singleton SyncEngine instance
|
|
13
|
+
*
|
|
14
|
+
* Ensures that only one SyncEngine is created and initialized per process,
|
|
15
|
+
* preventing duplicate metadata refreshes that cause the double GetAllMetadata()
|
|
16
|
+
* console output.
|
|
17
|
+
*
|
|
18
|
+
* @param contextUser - The user context for database operations
|
|
19
|
+
* @returns Promise resolving to initialized SyncEngine instance
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const syncEngine = await getSyncEngine(getSystemUser());
|
|
24
|
+
* // Use syncEngine for operations
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function getSyncEngine(contextUser: UserInfo): Promise<SyncEngine>;
|
|
28
|
+
/**
|
|
29
|
+
* Reset the singleton SyncEngine instance
|
|
30
|
+
*
|
|
31
|
+
* Should be called when cleaning up resources to ensure a fresh
|
|
32
|
+
* instance is created on the next request.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resetSyncEngine(): void;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Singleton manager for shared instances across MetadataSync
|
|
4
|
+
* @module singleton-manager
|
|
5
|
+
*
|
|
6
|
+
* This module ensures that expensive resources like SyncEngine are only
|
|
7
|
+
* initialized once per process, preventing duplicate metadata refreshes
|
|
8
|
+
* and improving performance.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.resetSyncEngine = exports.getSyncEngine = void 0;
|
|
12
|
+
const sync_engine_1 = require("./sync-engine");
|
|
13
|
+
/** Global SyncEngine instance */
|
|
14
|
+
let globalSyncEngine = null;
|
|
15
|
+
/** Promise to track ongoing SyncEngine initialization */
|
|
16
|
+
let syncEngineInitPromise = null;
|
|
17
|
+
/**
|
|
18
|
+
* Get or create a singleton SyncEngine instance
|
|
19
|
+
*
|
|
20
|
+
* Ensures that only one SyncEngine is created and initialized per process,
|
|
21
|
+
* preventing duplicate metadata refreshes that cause the double GetAllMetadata()
|
|
22
|
+
* console output.
|
|
23
|
+
*
|
|
24
|
+
* @param contextUser - The user context for database operations
|
|
25
|
+
* @returns Promise resolving to initialized SyncEngine instance
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const syncEngine = await getSyncEngine(getSystemUser());
|
|
30
|
+
* // Use syncEngine for operations
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
async function getSyncEngine(contextUser) {
|
|
34
|
+
// Return existing engine if already initialized
|
|
35
|
+
if (globalSyncEngine) {
|
|
36
|
+
return globalSyncEngine;
|
|
37
|
+
}
|
|
38
|
+
// Return ongoing initialization if in progress
|
|
39
|
+
if (syncEngineInitPromise) {
|
|
40
|
+
return syncEngineInitPromise;
|
|
41
|
+
}
|
|
42
|
+
// Start new initialization
|
|
43
|
+
syncEngineInitPromise = (async () => {
|
|
44
|
+
globalSyncEngine = new sync_engine_1.SyncEngine(contextUser);
|
|
45
|
+
await globalSyncEngine.initialize();
|
|
46
|
+
return globalSyncEngine;
|
|
47
|
+
})();
|
|
48
|
+
return syncEngineInitPromise;
|
|
49
|
+
}
|
|
50
|
+
exports.getSyncEngine = getSyncEngine;
|
|
51
|
+
/**
|
|
52
|
+
* Reset the singleton SyncEngine instance
|
|
53
|
+
*
|
|
54
|
+
* Should be called when cleaning up resources to ensure a fresh
|
|
55
|
+
* instance is created on the next request.
|
|
56
|
+
*/
|
|
57
|
+
function resetSyncEngine() {
|
|
58
|
+
globalSyncEngine = null;
|
|
59
|
+
syncEngineInitPromise = null;
|
|
60
|
+
}
|
|
61
|
+
exports.resetSyncEngine = resetSyncEngine;
|
|
62
|
+
//# sourceMappingURL=singleton-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"singleton-manager.js","sourceRoot":"","sources":["../../src/lib/singleton-manager.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,+CAA2C;AAG3C,iCAAiC;AACjC,IAAI,gBAAgB,GAAsB,IAAI,CAAC;AAE/C,yDAAyD;AACzD,IAAI,qBAAqB,GAA+B,IAAI,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACI,KAAK,UAAU,aAAa,CAAC,WAAqB;IACvD,gDAAgD;IAChD,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,+CAA+C;IAC/C,IAAI,qBAAqB,EAAE,CAAC;QAC1B,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,2BAA2B;IAC3B,qBAAqB,GAAG,CAAC,KAAK,IAAI,EAAE;QAClC,gBAAgB,GAAG,IAAI,wBAAU,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,gBAAgB,CAAC,UAAU,EAAE,CAAC;QACpC,OAAO,gBAAgB,CAAC;IAC1B,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAnBD,sCAmBC;AAED;;;;;GAKG;AACH,SAAgB,eAAe;IAC7B,gBAAgB,GAAG,IAAI,CAAC;IACxB,qBAAqB,GAAG,IAAI,CAAC;AAC/B,CAAC;AAHD,0CAGC","sourcesContent":["/**\n * @fileoverview Singleton manager for shared instances across MetadataSync\n * @module singleton-manager\n * \n * This module ensures that expensive resources like SyncEngine are only\n * initialized once per process, preventing duplicate metadata refreshes\n * and improving performance.\n */\n\nimport { SyncEngine } from './sync-engine';\nimport { UserInfo } from '@memberjunction/core';\n\n/** Global SyncEngine instance */\nlet globalSyncEngine: SyncEngine | null = null;\n\n/** Promise to track ongoing SyncEngine initialization */\nlet syncEngineInitPromise: Promise<SyncEngine> | null = null;\n\n/**\n * Get or create a singleton SyncEngine instance\n * \n * Ensures that only one SyncEngine is created and initialized per process,\n * preventing duplicate metadata refreshes that cause the double GetAllMetadata()\n * console output.\n * \n * @param contextUser - The user context for database operations\n * @returns Promise resolving to initialized SyncEngine instance\n * \n * @example\n * ```typescript\n * const syncEngine = await getSyncEngine(getSystemUser());\n * // Use syncEngine for operations\n * ```\n */\nexport async function getSyncEngine(contextUser: UserInfo): Promise<SyncEngine> {\n // Return existing engine if already initialized\n if (globalSyncEngine) {\n return globalSyncEngine;\n }\n \n // Return ongoing initialization if in progress\n if (syncEngineInitPromise) {\n return syncEngineInitPromise;\n }\n \n // Start new initialization\n syncEngineInitPromise = (async () => {\n globalSyncEngine = new SyncEngine(contextUser);\n await globalSyncEngine.initialize();\n return globalSyncEngine;\n })();\n \n return syncEngineInitPromise;\n}\n\n/**\n * Reset the singleton SyncEngine instance\n * \n * Should be called when cleaning up resources to ensure a fresh\n * instance is created on the next request.\n */\nexport function resetSyncEngine(): void {\n globalSyncEngine = null;\n syncEngineInitPromise = null;\n}"]}
|
package/oclif.manifest.json
CHANGED
|
@@ -24,47 +24,47 @@
|
|
|
24
24
|
"index.js"
|
|
25
25
|
]
|
|
26
26
|
},
|
|
27
|
-
"
|
|
27
|
+
"push": {
|
|
28
28
|
"aliases": [],
|
|
29
29
|
"args": {},
|
|
30
|
-
"description": "
|
|
30
|
+
"description": "Push local file changes to the database",
|
|
31
31
|
"examples": [
|
|
32
|
-
"<%= config.bin %> <%= command.id %>
|
|
33
|
-
"<%= config.bin %> <%= command.id %> --
|
|
32
|
+
"<%= config.bin %> <%= command.id %>",
|
|
33
|
+
"<%= config.bin %> <%= command.id %> --dry-run",
|
|
34
|
+
"<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"",
|
|
35
|
+
"<%= config.bin %> <%= command.id %> --ci"
|
|
34
36
|
],
|
|
35
37
|
"flags": {
|
|
36
|
-
"
|
|
37
|
-
"description": "
|
|
38
|
-
"name": "
|
|
39
|
-
"required": true,
|
|
40
|
-
"hasDynamicHelp": false,
|
|
41
|
-
"multiple": false,
|
|
42
|
-
"type": "option"
|
|
43
|
-
},
|
|
44
|
-
"filter": {
|
|
45
|
-
"description": "Additional filter for pulling specific records",
|
|
46
|
-
"name": "filter",
|
|
38
|
+
"dir": {
|
|
39
|
+
"description": "Specific entity directory to push",
|
|
40
|
+
"name": "dir",
|
|
47
41
|
"hasDynamicHelp": false,
|
|
48
42
|
"multiple": false,
|
|
49
43
|
"type": "option"
|
|
50
44
|
},
|
|
51
45
|
"dry-run": {
|
|
52
|
-
"description": "Show what would be
|
|
46
|
+
"description": "Show what would be pushed without actually pushing",
|
|
53
47
|
"name": "dry-run",
|
|
54
48
|
"allowNo": false,
|
|
55
49
|
"type": "boolean"
|
|
56
50
|
},
|
|
57
|
-
"
|
|
58
|
-
"description": "
|
|
59
|
-
"name": "
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
51
|
+
"ci": {
|
|
52
|
+
"description": "CI mode - no prompts, fail on issues",
|
|
53
|
+
"name": "ci",
|
|
54
|
+
"allowNo": false,
|
|
55
|
+
"type": "boolean"
|
|
56
|
+
},
|
|
57
|
+
"verbose": {
|
|
58
|
+
"char": "v",
|
|
59
|
+
"description": "Show detailed field-level output",
|
|
60
|
+
"name": "verbose",
|
|
61
|
+
"allowNo": false,
|
|
62
|
+
"type": "boolean"
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"hasDynamicHelp": false,
|
|
66
66
|
"hiddenAliases": [],
|
|
67
|
-
"id": "
|
|
67
|
+
"id": "push",
|
|
68
68
|
"pluginAlias": "@memberjunction/metadata-sync",
|
|
69
69
|
"pluginName": "@memberjunction/metadata-sync",
|
|
70
70
|
"pluginType": "core",
|
|
@@ -74,43 +74,50 @@
|
|
|
74
74
|
"relativePath": [
|
|
75
75
|
"dist",
|
|
76
76
|
"commands",
|
|
77
|
-
"
|
|
77
|
+
"push",
|
|
78
78
|
"index.js"
|
|
79
79
|
]
|
|
80
80
|
},
|
|
81
|
-
"
|
|
81
|
+
"pull": {
|
|
82
82
|
"aliases": [],
|
|
83
83
|
"args": {},
|
|
84
|
-
"description": "
|
|
84
|
+
"description": "Pull metadata from database to local files",
|
|
85
85
|
"examples": [
|
|
86
|
-
"<%= config.bin %> <%= command.id %>",
|
|
87
|
-
"<%= config.bin %> <%= command.id %> --
|
|
88
|
-
"<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"",
|
|
89
|
-
"<%= config.bin %> <%= command.id %> --ci"
|
|
86
|
+
"<%= config.bin %> <%= command.id %> --entity=\"AI Prompts\"",
|
|
87
|
+
"<%= config.bin %> <%= command.id %> --entity=\"AI Prompts\" --filter=\"CategoryID='customer-service-id'\""
|
|
90
88
|
],
|
|
91
89
|
"flags": {
|
|
92
|
-
"
|
|
93
|
-
"description": "
|
|
94
|
-
"name": "
|
|
90
|
+
"entity": {
|
|
91
|
+
"description": "Entity name to pull",
|
|
92
|
+
"name": "entity",
|
|
93
|
+
"required": true,
|
|
94
|
+
"hasDynamicHelp": false,
|
|
95
|
+
"multiple": false,
|
|
96
|
+
"type": "option"
|
|
97
|
+
},
|
|
98
|
+
"filter": {
|
|
99
|
+
"description": "Additional filter for pulling specific records",
|
|
100
|
+
"name": "filter",
|
|
95
101
|
"hasDynamicHelp": false,
|
|
96
102
|
"multiple": false,
|
|
97
103
|
"type": "option"
|
|
98
104
|
},
|
|
99
105
|
"dry-run": {
|
|
100
|
-
"description": "Show what would be
|
|
106
|
+
"description": "Show what would be pulled without actually pulling",
|
|
101
107
|
"name": "dry-run",
|
|
102
108
|
"allowNo": false,
|
|
103
109
|
"type": "boolean"
|
|
104
110
|
},
|
|
105
|
-
"
|
|
106
|
-
"description": "
|
|
107
|
-
"name": "
|
|
108
|
-
"
|
|
109
|
-
"
|
|
111
|
+
"multi-file": {
|
|
112
|
+
"description": "Create a single file with multiple records (provide filename)",
|
|
113
|
+
"name": "multi-file",
|
|
114
|
+
"hasDynamicHelp": false,
|
|
115
|
+
"multiple": false,
|
|
116
|
+
"type": "option"
|
|
110
117
|
},
|
|
111
118
|
"verbose": {
|
|
112
119
|
"char": "v",
|
|
113
|
-
"description": "Show detailed
|
|
120
|
+
"description": "Show detailed output",
|
|
114
121
|
"name": "verbose",
|
|
115
122
|
"allowNo": false,
|
|
116
123
|
"type": "boolean"
|
|
@@ -118,7 +125,7 @@
|
|
|
118
125
|
},
|
|
119
126
|
"hasDynamicHelp": false,
|
|
120
127
|
"hiddenAliases": [],
|
|
121
|
-
"id": "
|
|
128
|
+
"id": "pull",
|
|
122
129
|
"pluginAlias": "@memberjunction/metadata-sync",
|
|
123
130
|
"pluginName": "@memberjunction/metadata-sync",
|
|
124
131
|
"pluginType": "core",
|
|
@@ -128,7 +135,7 @@
|
|
|
128
135
|
"relativePath": [
|
|
129
136
|
"dist",
|
|
130
137
|
"commands",
|
|
131
|
-
"
|
|
138
|
+
"pull",
|
|
132
139
|
"index.js"
|
|
133
140
|
]
|
|
134
141
|
},
|
|
@@ -199,5 +206,5 @@
|
|
|
199
206
|
]
|
|
200
207
|
}
|
|
201
208
|
},
|
|
202
|
-
"version": "2.
|
|
209
|
+
"version": "2.48.0"
|
|
203
210
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/metadata-sync",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.48.0",
|
|
4
4
|
"description": "MemberJunction metadata synchronization CLI tool",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oclif",
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@inquirer/prompts": "^5.0.1",
|
|
54
|
-
"@memberjunction/core": "2.
|
|
55
|
-
"@memberjunction/core-entities": "2.
|
|
56
|
-
"@memberjunction/core-entities-server": "2.
|
|
57
|
-
"@memberjunction/sqlserver-dataprovider": "2.
|
|
58
|
-
"@memberjunction/graphql-dataprovider": "2.
|
|
54
|
+
"@memberjunction/core": "2.48.0",
|
|
55
|
+
"@memberjunction/core-entities": "2.48.0",
|
|
56
|
+
"@memberjunction/core-entities-server": "2.48.0",
|
|
57
|
+
"@memberjunction/sqlserver-dataprovider": "2.48.0",
|
|
58
|
+
"@memberjunction/graphql-dataprovider": "2.48.0",
|
|
59
59
|
"@oclif/core": "^3",
|
|
60
60
|
"@oclif/plugin-help": "^6",
|
|
61
61
|
"@oclif/plugin-version": "^2.0.17",
|