@memberjunction/metadata-sync 2.55.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 -1129
  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
@@ -0,0 +1,32 @@
1
+ import { SyncEngine } from '../lib/sync-engine';
2
+ export interface StatusOptions {
3
+ dir?: string;
4
+ }
5
+ export interface StatusCallbacks {
6
+ onProgress?: (message: string) => void;
7
+ onLog?: (message: string) => void;
8
+ onWarn?: (message: string) => void;
9
+ }
10
+ export interface StatusResult {
11
+ new: number;
12
+ modified: number;
13
+ deleted: number;
14
+ unchanged: number;
15
+ }
16
+ export interface EntityStatusResult {
17
+ entityName: string;
18
+ directory: string;
19
+ new: number;
20
+ modified: number;
21
+ deleted: number;
22
+ unchanged: number;
23
+ }
24
+ export declare class StatusService {
25
+ private syncEngine;
26
+ constructor(syncEngine: SyncEngine);
27
+ checkStatus(options: StatusOptions, callbacks?: StatusCallbacks): Promise<{
28
+ summary: StatusResult;
29
+ details: EntityStatusResult[];
30
+ }>;
31
+ private checkEntityDirectory;
32
+ }
@@ -0,0 +1,138 @@
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
+ exports.StatusService = void 0;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fast_glob_1 = __importDefault(require("fast-glob"));
10
+ const config_1 = require("../config");
11
+ const provider_utils_1 = require("../lib/provider-utils");
12
+ class StatusService {
13
+ syncEngine;
14
+ constructor(syncEngine) {
15
+ this.syncEngine = syncEngine;
16
+ }
17
+ async checkStatus(options, callbacks) {
18
+ const entityDirs = (0, provider_utils_1.findEntityDirectories)(process.cwd(), options.dir);
19
+ if (entityDirs.length === 0) {
20
+ throw new Error('No entity directories found');
21
+ }
22
+ callbacks?.onLog?.(`Found ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} to check`);
23
+ const details = [];
24
+ let totalNew = 0;
25
+ let totalModified = 0;
26
+ let totalDeleted = 0;
27
+ let totalUnchanged = 0;
28
+ for (const entityDir of entityDirs) {
29
+ const entityConfig = await (0, config_1.loadEntityConfig)(entityDir);
30
+ if (!entityConfig) {
31
+ callbacks?.onWarn?.(`Skipping ${entityDir} - no valid entity configuration`);
32
+ continue;
33
+ }
34
+ callbacks?.onLog?.(`Checking ${entityConfig.entity} in ${entityDir}`);
35
+ const result = await this.checkEntityDirectory(entityDir, entityConfig, callbacks);
36
+ details.push({
37
+ entityName: entityConfig.entity,
38
+ directory: entityDir,
39
+ ...result
40
+ });
41
+ totalNew += result.new;
42
+ totalModified += result.modified;
43
+ totalDeleted += result.deleted;
44
+ totalUnchanged += result.unchanged;
45
+ // Report directory summary
46
+ if (result.new > 0 || result.modified > 0 || result.deleted > 0) {
47
+ callbacks?.onLog?.(` New: ${result.new}, Modified: ${result.modified}, Deleted: ${result.deleted}, Unchanged: ${result.unchanged}`);
48
+ }
49
+ else {
50
+ callbacks?.onLog?.(` All ${result.unchanged} records are up to date`);
51
+ }
52
+ }
53
+ return {
54
+ summary: {
55
+ new: totalNew,
56
+ modified: totalModified,
57
+ deleted: totalDeleted,
58
+ unchanged: totalUnchanged
59
+ },
60
+ details
61
+ };
62
+ }
63
+ async checkEntityDirectory(entityDir, entityConfig, callbacks) {
64
+ const result = { new: 0, modified: 0, deleted: 0, unchanged: 0 };
65
+ // Find files matching the configured pattern
66
+ const pattern = entityConfig.filePattern || '*.json';
67
+ const jsonFiles = await (0, fast_glob_1.default)(pattern, {
68
+ cwd: entityDir,
69
+ ignore: ['.mj-sync.json', '.mj-folder.json', '**/*.backup'],
70
+ dot: true // Include dotfiles (files starting with .)
71
+ });
72
+ for (const file of jsonFiles) {
73
+ try {
74
+ const filePath = path_1.default.join(entityDir, file);
75
+ const recordData = await fs_extra_1.default.readJson(filePath);
76
+ if (recordData.primaryKey) {
77
+ // Check if record exists in database
78
+ const entity = await this.syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);
79
+ if (!entity) {
80
+ result.deleted++;
81
+ }
82
+ else {
83
+ // Check if modified
84
+ const currentChecksum = this.syncEngine.calculateChecksum(recordData.fields);
85
+ if (recordData.sync?.checksum !== currentChecksum) {
86
+ result.modified++;
87
+ }
88
+ else {
89
+ result.unchanged++;
90
+ }
91
+ }
92
+ }
93
+ else {
94
+ // New record
95
+ result.new++;
96
+ }
97
+ }
98
+ catch (error) {
99
+ callbacks?.onWarn?.(`Failed to check ${file}: ${error}`);
100
+ }
101
+ }
102
+ // Recursively process subdirectories
103
+ const entries = await fs_extra_1.default.readdir(entityDir, { withFileTypes: true });
104
+ for (const entry of entries) {
105
+ if (entry.isDirectory() && !entry.name.startsWith('.')) {
106
+ const subDir = path_1.default.join(entityDir, entry.name);
107
+ // Load subdirectory config and merge with parent config
108
+ let subEntityConfig = { ...entityConfig };
109
+ const subDirConfig = await (0, config_1.loadEntityConfig)(subDir);
110
+ if (subDirConfig) {
111
+ // Check if this is a new entity type (has different entity name)
112
+ if (subDirConfig.entity && subDirConfig.entity !== entityConfig.entity) {
113
+ // This is a different entity type, skip it (will be processed separately)
114
+ continue;
115
+ }
116
+ // Merge defaults: parent defaults + subdirectory overrides
117
+ subEntityConfig = {
118
+ ...entityConfig,
119
+ ...subDirConfig,
120
+ defaults: {
121
+ ...entityConfig.defaults,
122
+ ...(subDirConfig.defaults || {})
123
+ }
124
+ };
125
+ }
126
+ // Process subdirectory with merged config
127
+ const subResult = await this.checkEntityDirectory(subDir, subEntityConfig, callbacks);
128
+ result.new += subResult.new;
129
+ result.modified += subResult.modified;
130
+ result.deleted += subResult.deleted;
131
+ result.unchanged += subResult.unchanged;
132
+ }
133
+ }
134
+ return result;
135
+ }
136
+ }
137
+ exports.StatusService = StatusService;
138
+ //# sourceMappingURL=StatusService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusService.js","sourceRoot":"","sources":["../../src/services/StatusService.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs-extra';\nimport path from 'path';\nimport fastGlob from 'fast-glob';\nimport { SyncEngine, RecordData } from '../lib/sync-engine';\nimport { loadEntityConfig } from '../config';\nimport { findEntityDirectories } from '../lib/provider-utils';\n\nexport interface StatusOptions {\n dir?: string;\n}\n\nexport interface StatusCallbacks {\n onProgress?: (message: string) => void;\n onLog?: (message: string) => void;\n onWarn?: (message: string) => void;\n}\n\nexport interface StatusResult {\n new: number;\n modified: number;\n deleted: number;\n unchanged: number;\n}\n\nexport interface EntityStatusResult {\n entityName: string;\n directory: string;\n new: number;\n modified: number;\n deleted: number;\n unchanged: number;\n}\n\nexport class StatusService {\n private syncEngine: SyncEngine;\n \n constructor(syncEngine: SyncEngine) {\n this.syncEngine = syncEngine;\n }\n \n async checkStatus(options: StatusOptions, callbacks?: StatusCallbacks): Promise<{\n summary: StatusResult;\n details: EntityStatusResult[];\n }> {\n const entityDirs = findEntityDirectories(process.cwd(), options.dir);\n \n if (entityDirs.length === 0) {\n throw new Error('No entity directories found');\n }\n \n callbacks?.onLog?.(`Found ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} to check`);\n \n const details: EntityStatusResult[] = [];\n let totalNew = 0;\n let totalModified = 0;\n let totalDeleted = 0;\n let totalUnchanged = 0;\n \n for (const entityDir of entityDirs) {\n const entityConfig = await loadEntityConfig(entityDir);\n if (!entityConfig) {\n callbacks?.onWarn?.(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n callbacks?.onLog?.(`Checking ${entityConfig.entity} in ${entityDir}`);\n \n const result = await this.checkEntityDirectory(\n entityDir,\n entityConfig,\n callbacks\n );\n \n details.push({\n entityName: entityConfig.entity,\n directory: entityDir,\n ...result\n });\n \n totalNew += result.new;\n totalModified += result.modified;\n totalDeleted += result.deleted;\n totalUnchanged += result.unchanged;\n \n // Report directory summary\n if (result.new > 0 || result.modified > 0 || result.deleted > 0) {\n callbacks?.onLog?.(` New: ${result.new}, Modified: ${result.modified}, Deleted: ${result.deleted}, Unchanged: ${result.unchanged}`);\n } else {\n callbacks?.onLog?.(` All ${result.unchanged} records are up to date`);\n }\n }\n \n return {\n summary: {\n new: totalNew,\n modified: totalModified,\n deleted: totalDeleted,\n unchanged: totalUnchanged\n },\n details\n };\n }\n \n private async checkEntityDirectory(\n entityDir: string,\n entityConfig: any,\n callbacks?: StatusCallbacks\n ): Promise<StatusResult> {\n const result: StatusResult = { new: 0, modified: 0, deleted: 0, unchanged: 0 };\n \n // Find files matching the configured pattern\n const pattern = entityConfig.filePattern || '*.json';\n const jsonFiles = await fastGlob(pattern, {\n cwd: entityDir,\n ignore: ['.mj-sync.json', '.mj-folder.json', '**/*.backup'],\n dot: true // Include dotfiles (files starting with .)\n });\n \n for (const file of jsonFiles) {\n try {\n const filePath = path.join(entityDir, file);\n const recordData: RecordData = await fs.readJson(filePath);\n \n if (recordData.primaryKey) {\n // Check if record exists in database\n const entity = await this.syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);\n \n if (!entity) {\n result.deleted++;\n } else {\n // Check if modified\n const currentChecksum = this.syncEngine.calculateChecksum(recordData.fields);\n if (recordData.sync?.checksum !== currentChecksum) {\n result.modified++;\n } else {\n result.unchanged++;\n }\n }\n } else {\n // New record\n result.new++;\n }\n \n } catch (error) {\n callbacks?.onWarn?.(`Failed to check ${file}: ${error}`);\n }\n }\n \n // Recursively process subdirectories\n const entries = await fs.readdir(entityDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n const subDir = path.join(entityDir, entry.name);\n \n // Load subdirectory config and merge with parent config\n let subEntityConfig = { ...entityConfig };\n const subDirConfig = await loadEntityConfig(subDir);\n \n if (subDirConfig) {\n // Check if this is a new entity type (has different entity name)\n if (subDirConfig.entity && subDirConfig.entity !== entityConfig.entity) {\n // This is a different entity type, skip it (will be processed separately)\n continue;\n }\n \n // Merge defaults: parent defaults + subdirectory overrides\n subEntityConfig = {\n ...entityConfig,\n ...subDirConfig,\n defaults: {\n ...entityConfig.defaults,\n ...(subDirConfig.defaults || {})\n }\n };\n }\n \n // Process subdirectory with merged config\n const subResult = await this.checkEntityDirectory(\n subDir,\n subEntityConfig,\n callbacks\n );\n \n result.new += subResult.new;\n result.modified += subResult.modified;\n result.deleted += subResult.deleted;\n result.unchanged += subResult.unchanged;\n }\n }\n \n return result;\n }\n}"]}
@@ -0,0 +1,32 @@
1
+ import chokidar from 'chokidar';
2
+ import { BaseEntity } from '@memberjunction/core';
3
+ import { SyncEngine } from '../lib/sync-engine';
4
+ export interface WatchOptions {
5
+ dir?: string;
6
+ debounceMs?: number;
7
+ ignorePatterns?: string[];
8
+ }
9
+ export interface WatchCallbacks {
10
+ onFileAdd?: (filePath: string, entityDir: string, entityConfig: any) => void;
11
+ onFileChange?: (filePath: string, entityDir: string, entityConfig: any) => void;
12
+ onFileDelete?: (filePath: string, entityDir: string, entityConfig: any) => void;
13
+ onLog?: (message: string) => void;
14
+ onWarn?: (message: string) => void;
15
+ onError?: (error: Error) => void;
16
+ onRecordCreated?: (entity: BaseEntity, entityConfig: any) => void;
17
+ onRecordUpdated?: (entity: BaseEntity, changes: any, entityConfig: any) => void;
18
+ onRecordSaved?: (entity: BaseEntity, isNew: boolean, entityConfig: any) => void;
19
+ }
20
+ export interface WatchResult {
21
+ watchers: chokidar.FSWatcher[];
22
+ stop: () => Promise<void>;
23
+ }
24
+ export declare class WatchService {
25
+ private syncEngine;
26
+ private debounceTimers;
27
+ constructor(syncEngine: SyncEngine);
28
+ watch(options?: WatchOptions, callbacks?: WatchCallbacks): Promise<WatchResult>;
29
+ private handleFileChange;
30
+ private syncJsonFile;
31
+ private syncExternalFile;
32
+ }
@@ -0,0 +1,242 @@
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
+ exports.WatchService = void 0;
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 config_1 = require("../config");
11
+ const provider_utils_1 = require("../lib/provider-utils");
12
+ class WatchService {
13
+ syncEngine;
14
+ debounceTimers = new Map();
15
+ constructor(syncEngine) {
16
+ this.syncEngine = syncEngine;
17
+ }
18
+ async watch(options = {}, callbacks) {
19
+ const entityDirs = (0, provider_utils_1.findEntityDirectories)(process.cwd(), options.dir);
20
+ if (entityDirs.length === 0) {
21
+ throw new Error('No entity directories found');
22
+ }
23
+ callbacks?.onLog?.(`Watching ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} for changes`);
24
+ // Set up watchers
25
+ const watchers = [];
26
+ for (const entityDir of entityDirs) {
27
+ const entityConfig = await (0, config_1.loadEntityConfig)(entityDir);
28
+ if (!entityConfig) {
29
+ callbacks?.onWarn?.(`Skipping ${entityDir} - no valid entity configuration`);
30
+ continue;
31
+ }
32
+ callbacks?.onLog?.(`Watching ${entityConfig.entity} in ${entityDir}`);
33
+ // Watch for JSON files and external files
34
+ const patterns = [
35
+ path_1.default.join(entityDir, entityConfig.filePattern || '**/*.json'),
36
+ path_1.default.join(entityDir, '**/*.md'),
37
+ path_1.default.join(entityDir, '**/*.txt'),
38
+ path_1.default.join(entityDir, '**/*.html'),
39
+ path_1.default.join(entityDir, '**/*.liquid'),
40
+ path_1.default.join(entityDir, '**/*.sql')
41
+ ];
42
+ const ignored = [
43
+ '**/node_modules/**',
44
+ '**/.git/**',
45
+ '**/.mj-sync.json',
46
+ '**/.mj-folder.json',
47
+ '**/*.backup',
48
+ ...(options.ignorePatterns || [])
49
+ ];
50
+ const watcher = chokidar_1.default.watch(patterns, {
51
+ ignored,
52
+ persistent: true,
53
+ ignoreInitial: true
54
+ });
55
+ watcher
56
+ .on('add', (filePath) => {
57
+ callbacks?.onFileAdd?.(filePath, entityDir, entityConfig);
58
+ this.handleFileChange(filePath, 'added', entityDir, entityConfig, options, callbacks);
59
+ })
60
+ .on('change', (filePath) => {
61
+ callbacks?.onFileChange?.(filePath, entityDir, entityConfig);
62
+ this.handleFileChange(filePath, 'changed', entityDir, entityConfig, options, callbacks);
63
+ })
64
+ .on('unlink', (filePath) => {
65
+ callbacks?.onFileDelete?.(filePath, entityDir, entityConfig);
66
+ this.handleFileChange(filePath, 'deleted', entityDir, entityConfig, options, callbacks);
67
+ });
68
+ watchers.push(watcher);
69
+ }
70
+ return {
71
+ watchers,
72
+ stop: async () => {
73
+ // Clear all debounce timers
74
+ for (const timer of this.debounceTimers.values()) {
75
+ clearTimeout(timer);
76
+ }
77
+ this.debounceTimers.clear();
78
+ // Close all watchers
79
+ await Promise.all(watchers.map(w => w.close()));
80
+ }
81
+ };
82
+ }
83
+ handleFileChange(filePath, event, entityDir, entityConfig, options, callbacks) {
84
+ // Clear existing debounce timer
85
+ const existingTimer = this.debounceTimers.get(filePath);
86
+ if (existingTimer) {
87
+ clearTimeout(existingTimer);
88
+ }
89
+ // Set new debounce timer
90
+ const debounceMs = options.debounceMs || 1000;
91
+ const timer = setTimeout(async () => {
92
+ this.debounceTimers.delete(filePath);
93
+ try {
94
+ const relativePath = path_1.default.relative(entityDir, filePath);
95
+ callbacks?.onLog?.(`File ${event}: ${relativePath}`);
96
+ if (event === 'deleted') {
97
+ // Handle deletion
98
+ callbacks?.onLog?.('File deletion detected - manual database cleanup may be required');
99
+ }
100
+ else if (filePath.endsWith('.json')) {
101
+ // Handle JSON file change
102
+ await this.syncJsonFile(filePath, entityDir, entityConfig, callbacks);
103
+ }
104
+ else {
105
+ // Handle external file change
106
+ await this.syncExternalFile(filePath, entityDir, entityConfig, callbacks);
107
+ }
108
+ }
109
+ catch (error) {
110
+ const errorMessage = `Failed to sync ${filePath}: ${error.message || error}`;
111
+ callbacks?.onWarn?.(errorMessage);
112
+ if (error instanceof Error) {
113
+ callbacks?.onError?.(error);
114
+ }
115
+ }
116
+ }, debounceMs);
117
+ this.debounceTimers.set(filePath, timer);
118
+ }
119
+ async syncJsonFile(filePath, entityDir, entityConfig, callbacks) {
120
+ const recordData = await fs_extra_1.default.readJson(filePath);
121
+ // Build defaults
122
+ const defaults = await this.syncEngine.buildDefaults(filePath, entityConfig);
123
+ // Load or create entity
124
+ let entity = null;
125
+ let isNew = false;
126
+ if (recordData.primaryKey) {
127
+ entity = await this.syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);
128
+ }
129
+ if (!entity) {
130
+ // New record
131
+ entity = await this.syncEngine.createEntityObject(entityConfig.entity);
132
+ entity.NewRecord();
133
+ isNew = true;
134
+ }
135
+ // Apply defaults first
136
+ for (const [field, value] of Object.entries(defaults)) {
137
+ if (field in entity) {
138
+ entity[field] = value;
139
+ }
140
+ }
141
+ // Apply record fields
142
+ for (const [field, value] of Object.entries(recordData.fields)) {
143
+ if (field in entity) {
144
+ const processedValue = await this.syncEngine.processFieldValue(value, path_1.default.dirname(filePath));
145
+ entity[field] = processedValue;
146
+ }
147
+ }
148
+ // Check if the record is dirty before saving
149
+ let wasActuallyUpdated = false;
150
+ let changes = null;
151
+ if (!isNew && entity.Dirty) {
152
+ // Record is dirty, get the changes
153
+ changes = entity.GetChangesSinceLastSave();
154
+ const changeKeys = Object.keys(changes);
155
+ if (changeKeys.length > 0) {
156
+ wasActuallyUpdated = true;
157
+ // Get primary key info for display
158
+ const entityInfo = this.syncEngine.getEntityInfo(entityConfig.entity);
159
+ const primaryKeyDisplay = [];
160
+ if (entityInfo) {
161
+ for (const pk of entityInfo.PrimaryKeys) {
162
+ primaryKeyDisplay.push(`${pk.Name}: ${entity.Get(pk.Name)}`);
163
+ }
164
+ }
165
+ callbacks?.onLog?.(`📝 Updating ${entityConfig.entity} record:`);
166
+ if (primaryKeyDisplay.length > 0) {
167
+ callbacks?.onLog?.(` Primary Key: ${primaryKeyDisplay.join(', ')}`);
168
+ }
169
+ callbacks?.onLog?.(` Changes:`);
170
+ for (const fieldName of changeKeys) {
171
+ const field = entity.GetFieldByName(fieldName);
172
+ const oldValue = field ? field.OldValue : undefined;
173
+ const newValue = changes[fieldName];
174
+ callbacks?.onLog?.(` ${fieldName}: ${oldValue} → ${newValue}`);
175
+ }
176
+ callbacks?.onRecordUpdated?.(entity, changes, entityConfig);
177
+ }
178
+ }
179
+ else if (isNew) {
180
+ wasActuallyUpdated = true;
181
+ callbacks?.onRecordCreated?.(entity, entityConfig);
182
+ }
183
+ // Save the record
184
+ const saved = await entity.Save();
185
+ if (!saved) {
186
+ const message = entity.LatestResult?.Message;
187
+ if (message) {
188
+ throw new Error(`Failed to save record: ${message}`);
189
+ }
190
+ const errors = entity.LatestResult?.Errors?.map(err => typeof err === 'string' ? err : (err?.message || JSON.stringify(err)))?.join(', ') || 'Unknown error';
191
+ throw new Error(`Failed to save record: ${errors}`);
192
+ }
193
+ if (wasActuallyUpdated) {
194
+ callbacks?.onLog?.(`Successfully ${isNew ? 'created' : 'updated'} ${entityConfig.entity} record`);
195
+ callbacks?.onRecordSaved?.(entity, isNew, entityConfig);
196
+ }
197
+ else {
198
+ callbacks?.onLog?.(`No changes detected for ${entityConfig.entity} record - skipped update`);
199
+ }
200
+ // Update the local file with new primary key if created
201
+ if (isNew) {
202
+ const entityInfo = this.syncEngine.getEntityInfo(entityConfig.entity);
203
+ if (entityInfo) {
204
+ const newPrimaryKey = {};
205
+ for (const pk of entityInfo.PrimaryKeys) {
206
+ newPrimaryKey[pk.Name] = entity.Get(pk.Name);
207
+ }
208
+ recordData.primaryKey = newPrimaryKey;
209
+ // Update sync metadata
210
+ recordData.sync = {
211
+ lastModified: new Date().toISOString(),
212
+ checksum: this.syncEngine.calculateChecksum(recordData.fields)
213
+ };
214
+ // Write back to file
215
+ await fs_extra_1.default.writeJson(filePath, recordData, { spaces: 2 });
216
+ }
217
+ }
218
+ }
219
+ async syncExternalFile(filePath, entityDir, entityConfig, callbacks) {
220
+ // Find the corresponding JSON file
221
+ const fileName = path_1.default.basename(filePath);
222
+ const parts = fileName.split('.');
223
+ if (parts.length >= 3) {
224
+ // Format: uuid.fieldname.ext
225
+ const jsonFileName = `${parts[0]}.json`;
226
+ const fieldName = parts[1];
227
+ const jsonFilePath = path_1.default.join(path_1.default.dirname(filePath), jsonFileName);
228
+ if (await fs_extra_1.default.pathExists(jsonFilePath)) {
229
+ // Update the JSON file's sync metadata to trigger a sync
230
+ const recordData = await fs_extra_1.default.readJson(jsonFilePath);
231
+ recordData.sync = {
232
+ lastModified: new Date().toISOString(),
233
+ checksum: recordData.sync?.checksum || ''
234
+ };
235
+ await fs_extra_1.default.writeJson(jsonFilePath, recordData, { spaces: 2 });
236
+ callbacks?.onLog?.(`Updated sync metadata for ${jsonFileName} due to external file change`);
237
+ }
238
+ }
239
+ }
240
+ }
241
+ exports.WatchService = WatchService;
242
+ //# sourceMappingURL=WatchService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WatchService.js","sourceRoot":"","sources":["../../src/services/WatchService.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs-extra';\nimport path from 'path';\nimport chokidar from 'chokidar';\nimport { BaseEntity } from '@memberjunction/core';\nimport { SyncEngine, RecordData } from '../lib/sync-engine';\nimport { loadEntityConfig } from '../config';\nimport { findEntityDirectories } from '../lib/provider-utils';\n\nexport interface WatchOptions {\n dir?: string;\n debounceMs?: number;\n ignorePatterns?: string[];\n}\n\nexport interface WatchCallbacks {\n onFileAdd?: (filePath: string, entityDir: string, entityConfig: any) => void;\n onFileChange?: (filePath: string, entityDir: string, entityConfig: any) => void;\n onFileDelete?: (filePath: string, entityDir: string, entityConfig: any) => void;\n onLog?: (message: string) => void;\n onWarn?: (message: string) => void;\n onError?: (error: Error) => void;\n onRecordCreated?: (entity: BaseEntity, entityConfig: any) => void;\n onRecordUpdated?: (entity: BaseEntity, changes: any, entityConfig: any) => void;\n onRecordSaved?: (entity: BaseEntity, isNew: boolean, entityConfig: any) => void;\n}\n\nexport interface WatchResult {\n watchers: chokidar.FSWatcher[];\n stop: () => Promise<void>;\n}\n\nexport class WatchService {\n private syncEngine: SyncEngine;\n private debounceTimers: Map<string, NodeJS.Timeout> = new Map();\n \n constructor(syncEngine: SyncEngine) {\n this.syncEngine = syncEngine;\n }\n \n async watch(options: WatchOptions = {}, callbacks?: WatchCallbacks): Promise<WatchResult> {\n const entityDirs = findEntityDirectories(process.cwd(), options.dir);\n \n if (entityDirs.length === 0) {\n throw new Error('No entity directories found');\n }\n \n callbacks?.onLog?.(`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 callbacks?.onWarn?.(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n callbacks?.onLog?.(`Watching ${entityConfig.entity} in ${entityDir}`);\n \n // Watch for JSON files and external files\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 ...(options.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) => {\n callbacks?.onFileAdd?.(filePath, entityDir, entityConfig);\n this.handleFileChange(filePath, 'added', entityDir, entityConfig, options, callbacks);\n })\n .on('change', (filePath) => {\n callbacks?.onFileChange?.(filePath, entityDir, entityConfig);\n this.handleFileChange(filePath, 'changed', entityDir, entityConfig, options, callbacks);\n })\n .on('unlink', (filePath) => {\n callbacks?.onFileDelete?.(filePath, entityDir, entityConfig);\n this.handleFileChange(filePath, 'deleted', entityDir, entityConfig, options, callbacks);\n });\n \n watchers.push(watcher);\n }\n \n return {\n watchers,\n stop: async () => {\n // Clear all debounce timers\n for (const timer of this.debounceTimers.values()) {\n clearTimeout(timer);\n }\n this.debounceTimers.clear();\n \n // Close all watchers\n await Promise.all(watchers.map(w => w.close()));\n }\n };\n }\n \n private handleFileChange(\n filePath: string,\n event: string,\n entityDir: string,\n entityConfig: any,\n options: WatchOptions,\n callbacks?: WatchCallbacks\n ): 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 = options.debounceMs || 1000;\n const timer = setTimeout(async () => {\n this.debounceTimers.delete(filePath);\n \n try {\n const relativePath = path.relative(entityDir, filePath);\n callbacks?.onLog?.(`File ${event}: ${relativePath}`);\n \n if (event === 'deleted') {\n // Handle deletion\n callbacks?.onLog?.('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, callbacks);\n } else {\n // Handle external file change\n await this.syncExternalFile(filePath, entityDir, entityConfig, callbacks);\n }\n } catch (error) {\n const errorMessage = `Failed to sync ${filePath}: ${(error as any).message || error}`;\n callbacks?.onWarn?.(errorMessage);\n if (error instanceof Error) {\n callbacks?.onError?.(error);\n }\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 callbacks?: WatchCallbacks\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 let changes: any = null;\n \n if (!isNew && entity.Dirty) {\n // Record is dirty, get the changes\n changes = (entity as any).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 callbacks?.onLog?.(`📝 Updating ${entityConfig.entity} record:`);\n if (primaryKeyDisplay.length > 0) {\n callbacks?.onLog?.(` Primary Key: ${primaryKeyDisplay.join(', ')}`);\n }\n callbacks?.onLog?.(` 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 callbacks?.onLog?.(` ${fieldName}: ${oldValue} → ${newValue}`);\n }\n \n callbacks?.onRecordUpdated?.(entity, changes, entityConfig);\n }\n } else if (isNew) {\n wasActuallyUpdated = true;\n callbacks?.onRecordCreated?.(entity, entityConfig);\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 callbacks?.onLog?.(`Successfully ${isNew ? 'created' : 'updated'} ${entityConfig.entity} record`);\n callbacks?.onRecordSaved?.(entity, isNew, entityConfig);\n } else {\n callbacks?.onLog?.(`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 callbacks?: WatchCallbacks\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 callbacks?.onLog?.(`Updated sync metadata for ${jsonFileName} due to external file change`);\n }\n }\n }\n}"]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @fileoverview Service exports for MetadataSync library usage
3
+ * @module services
4
+ *
5
+ * This module exports all the service classes that can be used programmatically
6
+ * without the CLI interface. These services provide the core functionality
7
+ * for metadata synchronization operations.
8
+ */
9
+ export { InitService, InitOptions, InitCallbacks } from './InitService';
10
+ export { PullService, PullOptions, PullCallbacks, PullResult } from './PullService';
11
+ export { PushService, PushOptions, PushCallbacks, PushResult, EntityPushResult } from './PushService';
12
+ export { ValidationService } from './ValidationService';
13
+ export { FormattingService } from './FormattingService';
14
+ export { StatusService, StatusOptions, StatusCallbacks, StatusResult, EntityStatusResult } from './StatusService';
15
+ export { FileResetService, FileResetOptions, FileResetCallbacks, FileResetResult } from './FileResetService';
16
+ export { WatchService, WatchOptions, WatchCallbacks, WatchResult } from './WatchService';
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Service exports for MetadataSync library usage
4
+ * @module services
5
+ *
6
+ * This module exports all the service classes that can be used programmatically
7
+ * without the CLI interface. These services provide the core functionality
8
+ * for metadata synchronization operations.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.WatchService = exports.FileResetService = exports.StatusService = exports.FormattingService = exports.ValidationService = exports.PushService = exports.PullService = exports.InitService = void 0;
12
+ var InitService_1 = require("./InitService");
13
+ Object.defineProperty(exports, "InitService", { enumerable: true, get: function () { return InitService_1.InitService; } });
14
+ var PullService_1 = require("./PullService");
15
+ Object.defineProperty(exports, "PullService", { enumerable: true, get: function () { return PullService_1.PullService; } });
16
+ var PushService_1 = require("./PushService");
17
+ Object.defineProperty(exports, "PushService", { enumerable: true, get: function () { return PushService_1.PushService; } });
18
+ var ValidationService_1 = require("./ValidationService");
19
+ Object.defineProperty(exports, "ValidationService", { enumerable: true, get: function () { return ValidationService_1.ValidationService; } });
20
+ var FormattingService_1 = require("./FormattingService");
21
+ Object.defineProperty(exports, "FormattingService", { enumerable: true, get: function () { return FormattingService_1.FormattingService; } });
22
+ var StatusService_1 = require("./StatusService");
23
+ Object.defineProperty(exports, "StatusService", { enumerable: true, get: function () { return StatusService_1.StatusService; } });
24
+ var FileResetService_1 = require("./FileResetService");
25
+ Object.defineProperty(exports, "FileResetService", { enumerable: true, get: function () { return FileResetService_1.FileResetService; } });
26
+ var WatchService_1 = require("./WatchService");
27
+ Object.defineProperty(exports, "WatchService", { enumerable: true, get: function () { return WatchService_1.WatchService; } });
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,6CAAwE;AAA/D,0GAAA,WAAW,OAAA;AACpB,6CAAoF;AAA3E,0GAAA,WAAW,OAAA;AACpB,6CAAsG;AAA7F,0GAAA,WAAW,OAAA;AACpB,yDAAwD;AAA/C,sHAAA,iBAAiB,OAAA;AAC1B,yDAAwD;AAA/C,sHAAA,iBAAiB,OAAA;AAC1B,iDAAkH;AAAzG,8GAAA,aAAa,OAAA;AACtB,uDAA6G;AAApG,oHAAA,gBAAgB,OAAA;AACzB,+CAAyF;AAAhF,4GAAA,YAAY,OAAA","sourcesContent":["/**\n * @fileoverview Service exports for MetadataSync library usage\n * @module services\n * \n * This module exports all the service classes that can be used programmatically\n * without the CLI interface. These services provide the core functionality\n * for metadata synchronization operations.\n */\n\nexport { InitService, InitOptions, InitCallbacks } from './InitService';\nexport { PullService, PullOptions, PullCallbacks, PullResult } from './PullService';\nexport { PushService, PushOptions, PushCallbacks, PushResult, EntityPushResult } from './PushService';\nexport { ValidationService } from './ValidationService';\nexport { FormattingService } from './FormattingService';\nexport { StatusService, StatusOptions, StatusCallbacks, StatusResult, EntityStatusResult } from './StatusService';\nexport { FileResetService, FileResetOptions, FileResetCallbacks, FileResetResult } from './FileResetService';\nexport { WatchService, WatchOptions, WatchCallbacks, WatchResult } from './WatchService';"]}