@memberjunction/metadata-sync 2.54.0 → 2.56.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 (64) hide show
  1. package/README.md +92 -51
  2. package/dist/index.d.ts +21 -1
  3. package/dist/index.js +41 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/file-backup-manager.js +2 -2
  6. package/dist/lib/file-backup-manager.js.map +1 -1
  7. package/dist/lib/sql-logger.d.ts +44 -0
  8. package/dist/lib/sql-logger.js +140 -0
  9. package/dist/lib/sql-logger.js.map +1 -0
  10. package/dist/lib/sync-engine.js +2 -2
  11. package/dist/lib/sync-engine.js.map +1 -1
  12. package/dist/lib/transaction-manager.d.ts +36 -0
  13. package/dist/lib/transaction-manager.js +117 -0
  14. package/dist/lib/transaction-manager.js.map +1 -0
  15. package/dist/services/FileResetService.d.ts +30 -0
  16. package/dist/services/FileResetService.js +182 -0
  17. package/dist/services/FileResetService.js.map +1 -0
  18. package/dist/services/InitService.d.ts +17 -0
  19. package/dist/services/InitService.js +118 -0
  20. package/dist/services/InitService.js.map +1 -0
  21. package/dist/services/PullService.d.ts +45 -0
  22. package/dist/services/PullService.js +564 -0
  23. package/dist/services/PullService.js.map +1 -0
  24. package/dist/services/PushService.d.ts +45 -0
  25. package/dist/services/PushService.js +394 -0
  26. package/dist/services/PushService.js.map +1 -0
  27. package/dist/services/StatusService.d.ts +32 -0
  28. package/dist/services/StatusService.js +138 -0
  29. package/dist/services/StatusService.js.map +1 -0
  30. package/dist/services/WatchService.d.ts +32 -0
  31. package/dist/services/WatchService.js +242 -0
  32. package/dist/services/WatchService.js.map +1 -0
  33. package/dist/services/index.d.ts +16 -0
  34. package/dist/services/index.js +28 -0
  35. package/dist/services/index.js.map +1 -0
  36. package/package.json +14 -45
  37. package/bin/debug.js +0 -7
  38. package/bin/run +0 -17
  39. package/bin/run.js +0 -6
  40. package/dist/commands/file-reset/index.d.ts +0 -15
  41. package/dist/commands/file-reset/index.js +0 -221
  42. package/dist/commands/file-reset/index.js.map +0 -1
  43. package/dist/commands/init/index.d.ts +0 -7
  44. package/dist/commands/init/index.js +0 -155
  45. package/dist/commands/init/index.js.map +0 -1
  46. package/dist/commands/pull/index.d.ts +0 -246
  47. package/dist/commands/pull/index.js +0 -1448
  48. package/dist/commands/pull/index.js.map +0 -1
  49. package/dist/commands/push/index.d.ts +0 -41
  50. package/dist/commands/push/index.js +0 -1131
  51. package/dist/commands/push/index.js.map +0 -1
  52. package/dist/commands/status/index.d.ts +0 -10
  53. package/dist/commands/status/index.js +0 -199
  54. package/dist/commands/status/index.js.map +0 -1
  55. package/dist/commands/validate/index.d.ts +0 -15
  56. package/dist/commands/validate/index.js +0 -149
  57. package/dist/commands/validate/index.js.map +0 -1
  58. package/dist/commands/watch/index.d.ts +0 -15
  59. package/dist/commands/watch/index.js +0 -300
  60. package/dist/commands/watch/index.js.map +0 -1
  61. package/dist/hooks/init.d.ts +0 -3
  62. package/dist/hooks/init.js +0 -59
  63. package/dist/hooks/init.js.map +0 -1
  64. package/oclif.manifest.json +0 -376
@@ -1,149 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- const core_1 = require("@oclif/core");
30
- const path = __importStar(require("path"));
31
- const fs = __importStar(require("fs"));
32
- const chalk_1 = __importDefault(require("chalk"));
33
- const ValidationService_1 = require("../../services/ValidationService");
34
- const FormattingService_1 = require("../../services/FormattingService");
35
- const config_1 = require("../../config");
36
- const provider_utils_1 = require("../../lib/provider-utils");
37
- const ora_classic_1 = __importDefault(require("ora-classic"));
38
- class Validate extends core_1.Command {
39
- static description = 'Validate metadata files for correctness and dependencies';
40
- static examples = [
41
- `<%= config.bin %> <%= command.id %>`,
42
- `<%= config.bin %> <%= command.id %> --verbose`,
43
- `<%= config.bin %> <%= command.id %> --format=json`,
44
- `<%= config.bin %> <%= command.id %> --dir=./metadata`,
45
- `<%= config.bin %> <%= command.id %> --no-report`,
46
- `<%= config.bin %> <%= command.id %> -o validation-results.md`,
47
- ];
48
- static flags = {
49
- dir: core_1.Flags.string({
50
- description: 'Directory to validate (defaults to current directory)',
51
- default: process.cwd()
52
- }),
53
- verbose: core_1.Flags.boolean({
54
- char: 'v',
55
- description: 'Show detailed validation output'
56
- }),
57
- format: core_1.Flags.string({
58
- description: 'Output format',
59
- options: ['human', 'json'],
60
- default: 'human'
61
- }),
62
- 'max-depth': core_1.Flags.integer({
63
- description: 'Maximum nesting depth before warning',
64
- default: 10
65
- }),
66
- 'no-best-practices': core_1.Flags.boolean({
67
- description: 'Skip best practice checks'
68
- }),
69
- 'no-report': core_1.Flags.boolean({
70
- description: 'Skip saving validation report to markdown file'
71
- }),
72
- 'output-file': core_1.Flags.string({
73
- char: 'o',
74
- description: 'Custom output filename for report'
75
- })
76
- };
77
- async run() {
78
- const { flags } = await this.parse(Validate);
79
- const spinner = (0, ora_classic_1.default)();
80
- const options = {
81
- verbose: flags.verbose,
82
- outputFormat: flags.format,
83
- maxNestingDepth: flags['max-depth'],
84
- checkBestPractices: !flags['no-best-practices']
85
- };
86
- try {
87
- // Load MJ config and initialize provider
88
- spinner.start('Loading configuration');
89
- const mjConfig = (0, config_1.loadMJConfig)();
90
- if (!mjConfig) {
91
- spinner.fail('No mj.config.cjs found');
92
- this.error('No mj.config.cjs found in current directory or parent directories');
93
- }
94
- spinner.stop();
95
- await (0, provider_utils_1.initializeProvider)(mjConfig);
96
- const validator = new ValidationService_1.ValidationService(options);
97
- const formatter = new FormattingService_1.FormattingService();
98
- const resolvedPath = path.resolve(flags.dir);
99
- if (options.outputFormat === 'human') {
100
- this.log(chalk_1.default.blue(`Validating metadata in: ${resolvedPath}`));
101
- this.log('');
102
- }
103
- const result = await validator.validateDirectory(resolvedPath);
104
- // Save report by default (unless --no-report is specified)
105
- if (!flags['no-report']) {
106
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
107
- const defaultFilename = `validation-report-${timestamp}.md`;
108
- const outputFile = flags['output-file'] || defaultFilename;
109
- // Save to the validation directory by default
110
- const outputPath = path.resolve(resolvedPath, outputFile);
111
- const markdownReport = formatter.formatValidationResultAsMarkdown(result);
112
- fs.writeFileSync(outputPath, markdownReport, 'utf8');
113
- if (options.outputFormat === 'human') {
114
- this.log(chalk_1.default.gray(`\nReport saved to: ${outputPath}`));
115
- }
116
- }
117
- if (options.outputFormat === 'json') {
118
- this.log(formatter.formatValidationResultAsJson(result));
119
- }
120
- else {
121
- const output = formatter.formatValidationResult(result, options.verbose);
122
- this.log(output);
123
- }
124
- // Exit with error code if validation failed
125
- if (!result.isValid) {
126
- this.exit(1);
127
- }
128
- }
129
- catch (error) {
130
- if (options.outputFormat === 'json') {
131
- this.log(JSON.stringify({
132
- error: error instanceof Error ? error.message : String(error),
133
- isValid: false
134
- }, null, 2));
135
- }
136
- else {
137
- this.error(chalk_1.default.red(`Validation failed: ${error instanceof Error ? error.message : String(error)}`));
138
- }
139
- this.exit(1);
140
- }
141
- finally {
142
- // Exit process to prevent background MJ tasks from throwing errors
143
- // We don't explicitly close the connection - let the process termination handle it
144
- process.exit(0);
145
- }
146
- }
147
- }
148
- exports.default = Validate;
149
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/validate/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport chalk from 'chalk';\nimport { ValidationService } from '../../services/ValidationService';\nimport { FormattingService } from '../../services/FormattingService';\nimport { ValidationOptions } from '../../types/validation';\nimport { loadMJConfig } from '../../config';\nimport { initializeProvider } from '../../lib/provider-utils';\nimport ora from 'ora-classic';\n\nexport default class Validate extends Command {\n static description = 'Validate metadata files for correctness and dependencies';\n\n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --verbose`,\n `<%= config.bin %> <%= command.id %> --format=json`,\n `<%= config.bin %> <%= command.id %> --dir=./metadata`,\n `<%= config.bin %> <%= command.id %> --no-report`,\n `<%= config.bin %> <%= command.id %> -o validation-results.md`,\n ];\n\n static flags = {\n dir: Flags.string({ \n description: 'Directory to validate (defaults to current directory)',\n default: process.cwd()\n }),\n verbose: Flags.boolean({ \n char: 'v', \n description: 'Show detailed validation output' \n }),\n format: Flags.string({\n description: 'Output format',\n options: ['human', 'json'],\n default: 'human'\n }),\n 'max-depth': Flags.integer({\n description: 'Maximum nesting depth before warning',\n default: 10\n }),\n 'no-best-practices': Flags.boolean({\n description: 'Skip best practice checks'\n }),\n 'no-report': Flags.boolean({\n description: 'Skip saving validation report to markdown file'\n }),\n 'output-file': Flags.string({\n char: 'o',\n description: 'Custom output filename for report'\n })\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Validate);\n const spinner = ora();\n \n const options: ValidationOptions = {\n verbose: flags.verbose,\n outputFormat: flags.format as 'human' | 'json',\n maxNestingDepth: flags['max-depth'],\n checkBestPractices: !flags['no-best-practices']\n };\n \n try {\n // Load MJ config and initialize provider\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n spinner.fail('No mj.config.cjs found');\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n spinner.stop();\n await initializeProvider(mjConfig);\n \n const validator = new ValidationService(options);\n const formatter = new FormattingService();\n \n const resolvedPath = path.resolve(flags.dir);\n \n if (options.outputFormat === 'human') {\n this.log(chalk.blue(`Validating metadata in: ${resolvedPath}`));\n this.log('');\n }\n \n const result = await validator.validateDirectory(resolvedPath);\n \n // Save report by default (unless --no-report is specified)\n if (!flags['no-report']) {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);\n const defaultFilename = `validation-report-${timestamp}.md`;\n const outputFile = flags['output-file'] || defaultFilename;\n // Save to the validation directory by default\n const outputPath = path.resolve(resolvedPath, outputFile);\n \n const markdownReport = formatter.formatValidationResultAsMarkdown(result);\n fs.writeFileSync(outputPath, markdownReport, 'utf8');\n \n if (options.outputFormat === 'human') {\n this.log(chalk.gray(`\\nReport saved to: ${outputPath}`));\n }\n }\n \n if (options.outputFormat === 'json') {\n this.log(formatter.formatValidationResultAsJson(result));\n } else {\n const output = formatter.formatValidationResult(result, options.verbose);\n this.log(output);\n }\n \n // Exit with error code if validation failed\n if (!result.isValid) {\n this.exit(1);\n }\n } catch (error) {\n if (options.outputFormat === 'json') {\n this.log(JSON.stringify({ \n error: error instanceof Error ? error.message : String(error),\n isValid: false\n }, null, 2));\n } else {\n this.error(chalk.red(`Validation failed: ${error instanceof Error ? error.message : String(error)}`));\n }\n this.exit(1);\n } finally {\n // Exit process to prevent background MJ tasks from throwing errors\n // We don't explicitly close the connection - let the process termination handle it\n process.exit(0);\n }\n }\n}"]}
@@ -1,15 +0,0 @@
1
- import { Command } from '@oclif/core';
2
- export default class Watch extends Command {
3
- static description: string;
4
- static examples: string[];
5
- static flags: {
6
- dir: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
- };
8
- private syncEngine;
9
- private syncConfig;
10
- private debounceTimers;
11
- run(): Promise<void>;
12
- private handleFileChange;
13
- private syncJsonFile;
14
- private syncExternalFile;
15
- }
@@ -1,300 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const core_1 = require("@oclif/core");
7
- const fs_extra_1 = __importDefault(require("fs-extra"));
8
- const path_1 = __importDefault(require("path"));
9
- const chokidar_1 = __importDefault(require("chokidar"));
10
- const ora_classic_1 = __importDefault(require("ora-classic"));
11
- const config_1 = require("../../config");
12
- const provider_utils_1 = require("../../lib/provider-utils");
13
- const singleton_manager_1 = require("../../lib/singleton-manager");
14
- const provider_utils_2 = require("../../lib/provider-utils");
15
- class Watch extends core_1.Command {
16
- static description = 'Watch for file changes and automatically push to database';
17
- static examples = [
18
- `<%= config.bin %> <%= command.id %>`,
19
- `<%= config.bin %> <%= command.id %> --dir="ai-prompts"`,
20
- ];
21
- static flags = {
22
- dir: core_1.Flags.string({ description: 'Specific entity directory to watch' }),
23
- };
24
- syncEngine;
25
- syncConfig;
26
- debounceTimers = new Map();
27
- async run() {
28
- const { flags } = await this.parse(Watch);
29
- const spinner = (0, ora_classic_1.default)();
30
- try {
31
- // Load configurations
32
- spinner.start('Loading configuration');
33
- const mjConfig = (0, config_1.loadMJConfig)();
34
- if (!mjConfig) {
35
- this.error('No mj.config.cjs found in current directory or parent directories');
36
- }
37
- this.syncConfig = await (0, config_1.loadSyncConfig)(process.cwd());
38
- // Stop spinner before provider initialization (which logs to console)
39
- spinner.stop();
40
- // Initialize data provider
41
- const provider = await (0, provider_utils_1.initializeProvider)(mjConfig);
42
- // Initialize sync engine using singleton pattern
43
- this.syncEngine = await (0, singleton_manager_1.getSyncEngine)((0, provider_utils_1.getSystemUser)());
44
- // Show success after all initialization is complete
45
- spinner.succeed('Configuration and metadata loaded');
46
- // Find entity directories to watch
47
- const entityDirs = (0, provider_utils_1.findEntityDirectories)(process.cwd(), flags.dir);
48
- if (entityDirs.length === 0) {
49
- this.error('No entity directories found');
50
- }
51
- this.log(`Watching ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} for changes`);
52
- // Set up watchers
53
- const watchers = [];
54
- for (const entityDir of entityDirs) {
55
- const entityConfig = await (0, config_1.loadEntityConfig)(entityDir);
56
- if (!entityConfig) {
57
- this.warn(`Skipping ${entityDir} - no valid entity configuration`);
58
- continue;
59
- }
60
- this.log(`Watching ${entityConfig.entity} in ${entityDir}`);
61
- // Watch for JSON files and external files
62
- // All JSON files will be watched, but only dot-prefixed ones will be processed
63
- const patterns = [
64
- path_1.default.join(entityDir, entityConfig.filePattern || '**/*.json'),
65
- path_1.default.join(entityDir, '**/*.md'),
66
- path_1.default.join(entityDir, '**/*.txt'),
67
- path_1.default.join(entityDir, '**/*.html'),
68
- path_1.default.join(entityDir, '**/*.liquid'),
69
- path_1.default.join(entityDir, '**/*.sql')
70
- ];
71
- const ignored = [
72
- '**/node_modules/**',
73
- '**/.git/**',
74
- '**/.mj-sync.json',
75
- '**/.mj-folder.json',
76
- '**/*.backup',
77
- ...(this.syncConfig?.watch?.ignorePatterns || [])
78
- ];
79
- const watcher = chokidar_1.default.watch(patterns, {
80
- ignored,
81
- persistent: true,
82
- ignoreInitial: true
83
- });
84
- watcher
85
- .on('add', (filePath) => this.handleFileChange(filePath, 'added', entityDir, entityConfig))
86
- .on('change', (filePath) => this.handleFileChange(filePath, 'changed', entityDir, entityConfig))
87
- .on('unlink', (filePath) => this.handleFileChange(filePath, 'deleted', entityDir, entityConfig));
88
- watchers.push(watcher);
89
- }
90
- this.log('\nPress Ctrl+C to stop watching');
91
- // Keep process alive
92
- process.stdin.resume();
93
- // Cleanup on exit
94
- process.on('SIGINT', async () => {
95
- this.log('\nStopping watchers...');
96
- watchers.forEach(w => w.close());
97
- // Reset sync engine singleton
98
- (0, singleton_manager_1.resetSyncEngine)();
99
- // Clean up database connection
100
- await (0, provider_utils_2.cleanupProvider)();
101
- process.exit(0);
102
- });
103
- }
104
- catch (error) {
105
- spinner.fail('Watch failed');
106
- // Enhanced error logging for debugging
107
- this.log('\n=== Watch Error Details ===');
108
- this.log(`Error type: ${error?.constructor?.name || 'Unknown'}`);
109
- this.log(`Error message: ${error instanceof Error ? error.message : String(error)}`);
110
- if (error instanceof Error && error.stack) {
111
- this.log(`\nStack trace:`);
112
- this.log(error.stack);
113
- }
114
- // Log context information
115
- this.log(`\nContext:`);
116
- this.log(`- Working directory: ${process.cwd()}`);
117
- this.log(`- Specific directory: ${flags.dir || 'none (watching all directories)'}`);
118
- this.log(`- Flags: ${JSON.stringify(flags, null, 2)}`);
119
- // Check if error is related to common issues
120
- const errorMessage = error instanceof Error ? error.message : String(error);
121
- if (errorMessage.includes('No entity directories found')) {
122
- this.log(`\nHint: This appears to be an entity directory configuration issue.`);
123
- this.log(`Make sure directories have .mj-sync.json files or run "mj-sync init".`);
124
- }
125
- else if (errorMessage.includes('database') || errorMessage.includes('connection')) {
126
- this.log(`\nHint: This appears to be a database connectivity issue.`);
127
- this.log(`Check your mj.config.cjs configuration and database connectivity.`);
128
- }
129
- else if (errorMessage.includes('config') || errorMessage.includes('mj.config.cjs')) {
130
- this.log(`\nHint: This appears to be a configuration file issue.`);
131
- this.log(`Make sure mj.config.cjs exists and is properly configured.`);
132
- }
133
- else if (errorMessage.includes('ENOENT') || errorMessage.includes('no such file')) {
134
- this.log(`\nHint: File or directory access issue.`);
135
- this.log(`Check that the directories exist and are accessible.`);
136
- }
137
- else if (errorMessage.includes('chokidar') || errorMessage.includes('watch')) {
138
- this.log(`\nHint: File watching system issue.`);
139
- this.log(`Check file system permissions and available file descriptors.`);
140
- }
141
- // Reset sync engine singleton
142
- (0, singleton_manager_1.resetSyncEngine)();
143
- // Clean up database connection
144
- await (0, provider_utils_2.cleanupProvider)();
145
- this.error(error);
146
- }
147
- }
148
- async handleFileChange(filePath, event, entityDir, entityConfig) {
149
- // Clear existing debounce timer
150
- const existingTimer = this.debounceTimers.get(filePath);
151
- if (existingTimer) {
152
- clearTimeout(existingTimer);
153
- }
154
- // Set new debounce timer
155
- const debounceMs = this.syncConfig?.watch?.debounceMs || 1000;
156
- const timer = setTimeout(async () => {
157
- this.debounceTimers.delete(filePath);
158
- try {
159
- const relativePath = path_1.default.relative(entityDir, filePath);
160
- this.log(`\nFile ${event}: ${relativePath}`);
161
- if (event === 'deleted') {
162
- // Handle deletion
163
- this.log('File deletion detected - manual database cleanup may be required');
164
- }
165
- else if (filePath.endsWith('.json')) {
166
- // Handle JSON file change
167
- await this.syncJsonFile(filePath, entityDir, entityConfig);
168
- }
169
- else {
170
- // Handle external file change
171
- await this.syncExternalFile(filePath, entityDir, entityConfig);
172
- }
173
- }
174
- catch (error) {
175
- this.warn(`Failed to sync ${filePath}: ${error.message || error}`);
176
- }
177
- }, debounceMs);
178
- this.debounceTimers.set(filePath, timer);
179
- }
180
- async syncJsonFile(filePath, entityDir, entityConfig) {
181
- const recordData = await fs_extra_1.default.readJson(filePath);
182
- // Build defaults
183
- const defaults = await this.syncEngine.buildDefaults(filePath, entityConfig);
184
- // Load or create entity
185
- let entity = null;
186
- let isNew = false;
187
- if (recordData.primaryKey) {
188
- entity = await this.syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);
189
- }
190
- if (!entity) {
191
- // New record
192
- entity = await this.syncEngine.createEntityObject(entityConfig.entity);
193
- entity.NewRecord();
194
- isNew = true;
195
- }
196
- // Apply defaults first
197
- for (const [field, value] of Object.entries(defaults)) {
198
- if (field in entity) {
199
- entity[field] = value;
200
- }
201
- }
202
- // Apply record fields
203
- for (const [field, value] of Object.entries(recordData.fields)) {
204
- if (field in entity) {
205
- const processedValue = await this.syncEngine.processFieldValue(value, path_1.default.dirname(filePath));
206
- entity[field] = processedValue;
207
- }
208
- }
209
- // Check if the record is dirty before saving
210
- let wasActuallyUpdated = false;
211
- if (!isNew && entity.Dirty) {
212
- // Record is dirty, get the changes
213
- const changes = entity.GetChangesSinceLastSave();
214
- const changeKeys = Object.keys(changes);
215
- if (changeKeys.length > 0) {
216
- wasActuallyUpdated = true;
217
- // Get primary key info for display
218
- const entityInfo = this.syncEngine.getEntityInfo(entityConfig.entity);
219
- const primaryKeyDisplay = [];
220
- if (entityInfo) {
221
- for (const pk of entityInfo.PrimaryKeys) {
222
- primaryKeyDisplay.push(`${pk.Name}: ${entity.Get(pk.Name)}`);
223
- }
224
- }
225
- this.log(''); // Add newline before update output
226
- this.log(`📝 Updating ${entityConfig.entity} record:`);
227
- if (primaryKeyDisplay.length > 0) {
228
- this.log(` Primary Key: ${primaryKeyDisplay.join(', ')}`);
229
- }
230
- this.log(` Changes:`);
231
- for (const fieldName of changeKeys) {
232
- const field = entity.GetFieldByName(fieldName);
233
- const oldValue = field ? field.OldValue : undefined;
234
- const newValue = changes[fieldName];
235
- this.log(` ${fieldName}: ${oldValue} → ${newValue}`);
236
- }
237
- }
238
- }
239
- else if (isNew) {
240
- wasActuallyUpdated = true;
241
- }
242
- // Save the record
243
- const saved = await entity.Save();
244
- if (!saved) {
245
- const message = entity.LatestResult?.Message;
246
- if (message) {
247
- throw new Error(`Failed to save record: ${message}`);
248
- }
249
- const errors = entity.LatestResult?.Errors?.map(err => typeof err === 'string' ? err : (err?.message || JSON.stringify(err)))?.join(', ') || 'Unknown error';
250
- throw new Error(`Failed to save record: ${errors}`);
251
- }
252
- if (wasActuallyUpdated) {
253
- this.log(`Successfully ${isNew ? 'created' : 'updated'} ${entityConfig.entity} record`);
254
- }
255
- else {
256
- this.log(`No changes detected for ${entityConfig.entity} record - skipped update`);
257
- }
258
- // Update the local file with new primary key if created
259
- if (isNew) {
260
- const entityInfo = this.syncEngine.getEntityInfo(entityConfig.entity);
261
- if (entityInfo) {
262
- const newPrimaryKey = {};
263
- for (const pk of entityInfo.PrimaryKeys) {
264
- newPrimaryKey[pk.Name] = entity.Get(pk.Name);
265
- }
266
- recordData.primaryKey = newPrimaryKey;
267
- // Update sync metadata
268
- recordData.sync = {
269
- lastModified: new Date().toISOString(),
270
- checksum: this.syncEngine.calculateChecksum(recordData.fields)
271
- };
272
- // Write back to file
273
- await fs_extra_1.default.writeJson(filePath, recordData, { spaces: 2 });
274
- }
275
- }
276
- }
277
- async syncExternalFile(filePath, entityDir, entityConfig) {
278
- // Find the corresponding JSON file
279
- const fileName = path_1.default.basename(filePath);
280
- const parts = fileName.split('.');
281
- if (parts.length >= 3) {
282
- // Format: uuid.fieldname.ext
283
- const jsonFileName = `${parts[0]}.json`;
284
- const fieldName = parts[1];
285
- const jsonFilePath = path_1.default.join(path_1.default.dirname(filePath), jsonFileName);
286
- if (await fs_extra_1.default.pathExists(jsonFilePath)) {
287
- // Update the JSON file's sync metadata to trigger a sync
288
- const recordData = await fs_extra_1.default.readJson(jsonFilePath);
289
- recordData.sync = {
290
- lastModified: new Date().toISOString(),
291
- checksum: recordData.sync?.checksum || ''
292
- };
293
- await fs_extra_1.default.writeJson(jsonFilePath, recordData, { spaces: 2 });
294
- this.log(`Updated sync metadata for ${jsonFileName} due to external file change`);
295
- }
296
- }
297
- }
298
- }
299
- exports.default = Watch;
300
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/watch/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport chokidar from 'chokidar';\nimport ora from 'ora-classic';\nimport { loadMJConfig, loadSyncConfig, loadEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { initializeProvider, findEntityDirectories, getSystemUser } from '../../lib/provider-utils';\nimport { BaseEntity } from '@memberjunction/core';\nimport { getSyncEngine, resetSyncEngine } from '../../lib/singleton-manager';\nimport { cleanupProvider } from '../../lib/provider-utils';\n\nexport default class Watch extends Command {\n static description = 'Watch for file changes and automatically push to database';\n \n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"`,\n ];\n \n static flags = {\n dir: Flags.string({ description: 'Specific entity directory to watch' }),\n };\n \n private syncEngine!: SyncEngine;\n private syncConfig: any;\n private debounceTimers: Map<string, NodeJS.Timeout> = new Map();\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Watch);\n const spinner = ora();\n \n try {\n // Load configurations\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n this.syncConfig = await loadSyncConfig(process.cwd());\n \n // Stop spinner before provider initialization (which logs to console)\n spinner.stop();\n \n // Initialize data provider\n const provider = await initializeProvider(mjConfig);\n \n // Initialize sync engine using singleton pattern\n this.syncEngine = await getSyncEngine(getSystemUser());\n \n // Show success after all initialization is complete\n spinner.succeed('Configuration and metadata loaded');\n \n // Find entity directories to watch\n const entityDirs = findEntityDirectories(process.cwd(), flags.dir);\n \n if (entityDirs.length === 0) {\n this.error('No entity directories found');\n }\n \n this.log(`Watching ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} for changes`);\n \n // Set up watchers\n const watchers: chokidar.FSWatcher[] = [];\n \n for (const entityDir of entityDirs) {\n const entityConfig = await loadEntityConfig(entityDir);\n if (!entityConfig) {\n this.warn(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n this.log(`Watching ${entityConfig.entity} in ${entityDir}`);\n \n // Watch for JSON files and external files\n // All JSON files will be watched, but only dot-prefixed ones will be processed\n const patterns = [\n path.join(entityDir, entityConfig.filePattern || '**/*.json'),\n path.join(entityDir, '**/*.md'),\n path.join(entityDir, '**/*.txt'),\n path.join(entityDir, '**/*.html'),\n path.join(entityDir, '**/*.liquid'),\n path.join(entityDir, '**/*.sql')\n ];\n \n const ignored = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.mj-sync.json',\n '**/.mj-folder.json',\n '**/*.backup',\n ...(this.syncConfig?.watch?.ignorePatterns || [])\n ];\n \n const watcher = chokidar.watch(patterns, {\n ignored,\n persistent: true,\n ignoreInitial: true\n });\n \n watcher\n .on('add', (filePath) => this.handleFileChange(filePath, 'added', entityDir, entityConfig))\n .on('change', (filePath) => this.handleFileChange(filePath, 'changed', entityDir, entityConfig))\n .on('unlink', (filePath) => this.handleFileChange(filePath, 'deleted', entityDir, entityConfig));\n \n watchers.push(watcher);\n }\n \n this.log('\\nPress Ctrl+C to stop watching');\n \n // Keep process alive\n process.stdin.resume();\n \n // Cleanup on exit\n process.on('SIGINT', async () => {\n this.log('\\nStopping watchers...');\n watchers.forEach(w => w.close());\n // Reset sync engine singleton\n resetSyncEngine();\n // Clean up database connection\n await cleanupProvider();\n process.exit(0);\n });\n \n } catch (error) {\n spinner.fail('Watch failed');\n \n // Enhanced error logging for debugging\n this.log('\\n=== Watch Error Details ===');\n this.log(`Error type: ${error?.constructor?.name || 'Unknown'}`);\n this.log(`Error message: ${error instanceof Error ? error.message : String(error)}`);\n \n if (error instanceof Error && error.stack) {\n this.log(`\\nStack trace:`);\n this.log(error.stack);\n }\n \n // Log context information\n this.log(`\\nContext:`);\n this.log(`- Working directory: ${process.cwd()}`);\n this.log(`- Specific directory: ${flags.dir || 'none (watching all directories)'}`);\n this.log(`- Flags: ${JSON.stringify(flags, null, 2)}`);\n \n // Check if error is related to common issues\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (errorMessage.includes('No entity directories found')) {\n this.log(`\\nHint: This appears to be an entity directory configuration issue.`);\n this.log(`Make sure directories have .mj-sync.json files or run \"mj-sync init\".`);\n } else if (errorMessage.includes('database') || errorMessage.includes('connection')) {\n this.log(`\\nHint: This appears to be a database connectivity issue.`);\n this.log(`Check your mj.config.cjs configuration and database connectivity.`);\n } else if (errorMessage.includes('config') || errorMessage.includes('mj.config.cjs')) {\n this.log(`\\nHint: This appears to be a configuration file issue.`);\n this.log(`Make sure mj.config.cjs exists and is properly configured.`);\n } else if (errorMessage.includes('ENOENT') || errorMessage.includes('no such file')) {\n this.log(`\\nHint: File or directory access issue.`);\n this.log(`Check that the directories exist and are accessible.`);\n } else if (errorMessage.includes('chokidar') || errorMessage.includes('watch')) {\n this.log(`\\nHint: File watching system issue.`);\n this.log(`Check file system permissions and available file descriptors.`);\n }\n \n // Reset sync engine singleton\n resetSyncEngine();\n // Clean up database connection\n await cleanupProvider();\n this.error(error as Error);\n }\n }\n \n private async handleFileChange(\n filePath: string,\n event: string,\n entityDir: string,\n entityConfig: any\n ): Promise<void> {\n // Clear existing debounce timer\n const existingTimer = this.debounceTimers.get(filePath);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n \n // Set new debounce timer\n const debounceMs = this.syncConfig?.watch?.debounceMs || 1000;\n const timer = setTimeout(async () => {\n this.debounceTimers.delete(filePath);\n \n try {\n const relativePath = path.relative(entityDir, filePath);\n this.log(`\\nFile ${event}: ${relativePath}`);\n \n if (event === 'deleted') {\n // Handle deletion\n this.log('File deletion detected - manual database cleanup may be required');\n } else if (filePath.endsWith('.json')) {\n // Handle JSON file change\n await this.syncJsonFile(filePath, entityDir, entityConfig);\n } else {\n // Handle external file change\n await this.syncExternalFile(filePath, entityDir, entityConfig);\n }\n } catch (error) {\n this.warn(`Failed to sync ${filePath}: ${(error as any).message || error}`);\n }\n }, debounceMs);\n \n this.debounceTimers.set(filePath, timer);\n }\n \n private async syncJsonFile(\n filePath: string,\n entityDir: string,\n entityConfig: any\n ): Promise<void> {\n const recordData: RecordData = await fs.readJson(filePath);\n \n // Build defaults\n const defaults = await this.syncEngine.buildDefaults(filePath, entityConfig);\n \n // Load or create entity\n let entity: BaseEntity | null = null;\n let isNew = false;\n \n if (recordData.primaryKey) {\n entity = await this.syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);\n }\n \n if (!entity) {\n // New record\n entity = await this.syncEngine.createEntityObject(entityConfig.entity);\n entity.NewRecord();\n isNew = true;\n }\n \n // Apply defaults first\n for (const [field, value] of Object.entries(defaults)) {\n if (field in entity) {\n (entity as any)[field] = value;\n }\n }\n \n // Apply record fields\n for (const [field, value] of Object.entries(recordData.fields)) {\n if (field in entity) {\n const processedValue = await this.syncEngine.processFieldValue(value, path.dirname(filePath));\n (entity as any)[field] = processedValue;\n }\n }\n \n // Check if the record is dirty before saving\n let wasActuallyUpdated = false;\n if (!isNew && entity.Dirty) {\n // Record is dirty, get the changes\n const changes = entity.GetChangesSinceLastSave();\n const changeKeys = Object.keys(changes);\n if (changeKeys.length > 0) {\n wasActuallyUpdated = true;\n \n // Get primary key info for display\n const entityInfo = this.syncEngine.getEntityInfo(entityConfig.entity);\n const primaryKeyDisplay: string[] = [];\n if (entityInfo) {\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKeyDisplay.push(`${pk.Name}: ${entity.Get(pk.Name)}`);\n }\n }\n \n this.log(''); // Add newline before update output\n this.log(`📝 Updating ${entityConfig.entity} record:`);\n if (primaryKeyDisplay.length > 0) {\n this.log(` Primary Key: ${primaryKeyDisplay.join(', ')}`);\n }\n this.log(` Changes:`);\n for (const fieldName of changeKeys) {\n const field = entity.GetFieldByName(fieldName);\n const oldValue = field ? field.OldValue : undefined;\n const newValue = (changes as any)[fieldName];\n this.log(` ${fieldName}: ${oldValue} → ${newValue}`);\n }\n }\n } else if (isNew) {\n wasActuallyUpdated = true;\n }\n \n // Save the record\n const saved = await entity.Save();\n if (!saved) {\n const message = entity.LatestResult?.Message;\n if (message) {\n throw new Error(`Failed to save record: ${message}`);\n }\n \n const errors = entity.LatestResult?.Errors?.map(err => \n typeof err === 'string' ? err : (err?.message || JSON.stringify(err))\n )?.join(', ') || 'Unknown error';\n throw new Error(`Failed to save record: ${errors}`);\n }\n \n if (wasActuallyUpdated) {\n this.log(`Successfully ${isNew ? 'created' : 'updated'} ${entityConfig.entity} record`);\n } else {\n this.log(`No changes detected for ${entityConfig.entity} record - skipped update`);\n }\n \n // Update the local file with new primary key if created\n if (isNew) {\n const entityInfo = this.syncEngine.getEntityInfo(entityConfig.entity);\n if (entityInfo) {\n const newPrimaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n newPrimaryKey[pk.Name] = entity.Get(pk.Name);\n }\n recordData.primaryKey = newPrimaryKey;\n \n // Update sync metadata\n recordData.sync = {\n lastModified: new Date().toISOString(),\n checksum: this.syncEngine.calculateChecksum(recordData.fields)\n };\n \n // Write back to file\n await fs.writeJson(filePath, recordData, { spaces: 2 });\n }\n }\n }\n \n private async syncExternalFile(\n filePath: string,\n entityDir: string,\n entityConfig: any\n ): Promise<void> {\n // Find the corresponding JSON file\n const fileName = path.basename(filePath);\n const parts = fileName.split('.');\n \n if (parts.length >= 3) {\n // Format: uuid.fieldname.ext\n const jsonFileName = `${parts[0]}.json`;\n const fieldName = parts[1];\n const jsonFilePath = path.join(path.dirname(filePath), jsonFileName);\n \n if (await fs.pathExists(jsonFilePath)) {\n // Update the JSON file's sync metadata to trigger a sync\n const recordData: RecordData = await fs.readJson(jsonFilePath);\n recordData.sync = {\n lastModified: new Date().toISOString(),\n checksum: recordData.sync?.checksum || ''\n };\n await fs.writeJson(jsonFilePath, recordData, { spaces: 2 });\n \n this.log(`Updated sync metadata for ${jsonFileName} due to external file change`);\n }\n }\n }\n}"]}
@@ -1,3 +0,0 @@
1
- import { Hook } from '@oclif/core';
2
- declare const hook: Hook<'init'>;
3
- export default hook;
@@ -1,59 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- const core_entities_server_1 = require("@memberjunction/core-entities-server");
27
- const dotenv = __importStar(require("dotenv"));
28
- const path = __importStar(require("path"));
29
- const provider_utils_1 = require("../lib/provider-utils");
30
- const config_manager_1 = require("../lib/config-manager");
31
- const hook = async function () {
32
- // Capture the original working directory FIRST before any changes
33
- config_manager_1.configManager.getOriginalCwd();
34
- // Load .env from the repository root first
35
- dotenv.config({ path: path.join(__dirname, '../../../../.env') });
36
- // Then load local .env from package directory to override
37
- dotenv.config({
38
- path: path.join(__dirname, '../../.env'),
39
- override: true // This ensures local values override already loaded ones
40
- });
41
- // Load core entities server subclasses
42
- (0, core_entities_server_1.LoadCoreEntitiesServerSubClasses)();
43
- // Register cleanup handlers
44
- process.on('exit', () => {
45
- (0, provider_utils_1.cleanupProvider)().catch(() => {
46
- // Ignore errors during cleanup
47
- });
48
- });
49
- process.on('SIGINT', async () => {
50
- await (0, provider_utils_1.cleanupProvider)();
51
- process.exit(0);
52
- });
53
- process.on('SIGTERM', async () => {
54
- await (0, provider_utils_1.cleanupProvider)();
55
- process.exit(0);
56
- });
57
- };
58
- exports.default = hook;
59
- //# sourceMappingURL=init.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/hooks/init.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AACA,+EAAwF;AACxF,+CAAiC;AACjC,2CAA6B;AAC7B,0DAAwD;AACxD,0DAAsD;AAEtD,MAAM,IAAI,GAAiB,KAAK;IAC9B,kEAAkE;IAClE,8BAAa,CAAC,cAAc,EAAE,CAAC;IAE/B,2CAA2C;IAC3C,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,EAAE,CAAC,CAAC;IAElE,0DAA0D;IAC1D,MAAM,CAAC,MAAM,CAAC;QACZ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;QACxC,QAAQ,EAAE,IAAI,CAAE,yDAAyD;KAC1E,CAAC,CAAC;IAEH,uCAAuC;IACvC,IAAA,uDAAgC,GAAE,CAAC;IAEnC,4BAA4B;IAC5B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACtB,IAAA,gCAAe,GAAE,CAAC,KAAK,CAAC,GAAG,EAAE;YAC3B,+BAA+B;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,IAAA,gCAAe,GAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,IAAA,gCAAe,GAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,kBAAe,IAAI,CAAC","sourcesContent":["import { Hook } from '@oclif/core';\nimport { LoadCoreEntitiesServerSubClasses } from '@memberjunction/core-entities-server';\nimport * as dotenv from 'dotenv';\nimport * as path from 'path';\nimport { cleanupProvider } from '../lib/provider-utils';\nimport { configManager } from '../lib/config-manager';\n\nconst hook: Hook<'init'> = async function () {\n // Capture the original working directory FIRST before any changes\n configManager.getOriginalCwd();\n \n // Load .env from the repository root first\n dotenv.config({ path: path.join(__dirname, '../../../../.env') });\n \n // Then load local .env from package directory to override\n dotenv.config({ \n path: path.join(__dirname, '../../.env'),\n override: true // This ensures local values override already loaded ones\n });\n \n // Load core entities server subclasses\n LoadCoreEntitiesServerSubClasses();\n \n // Register cleanup handlers\n process.on('exit', () => {\n cleanupProvider().catch(() => {\n // Ignore errors during cleanup\n });\n });\n \n process.on('SIGINT', async () => {\n await cleanupProvider();\n process.exit(0);\n });\n \n process.on('SIGTERM', async () => {\n await cleanupProvider();\n process.exit(0);\n });\n};\n\nexport default hook;"]}