@memberjunction/external-change-detection 2.32.2 → 2.34.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 +243 -0
- package/package.json +5 -5
package/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# MemberJunction External Change Detection
|
|
2
|
+
|
|
3
|
+
A powerful library for detecting and reconciling changes made to entities by external systems or integrations in MemberJunction applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The `@memberjunction/external-change-detection` package provides functionality to detect when records in your MemberJunction entities have been modified by external systems, third-party integrations, or direct database changes that bypass the MemberJunction application logic. This helps maintain data integrity and ensures that your application can react appropriately to external modifications.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- Detect external changes to entity records
|
|
12
|
+
- Compare current state with previous snapshots
|
|
13
|
+
- Generate detailed change reports
|
|
14
|
+
- Support for field-level change detection
|
|
15
|
+
- Configurable change detection criteria
|
|
16
|
+
- Ability to replay/apply detected changes
|
|
17
|
+
- Built-in optimization for large datasets
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @memberjunction/external-change-detection
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Dependencies
|
|
26
|
+
|
|
27
|
+
This package relies on the following MemberJunction packages:
|
|
28
|
+
- `@memberjunction/core`
|
|
29
|
+
- `@memberjunction/core-entities`
|
|
30
|
+
- `@memberjunction/global`
|
|
31
|
+
- `@memberjunction/sqlserver-dataprovider`
|
|
32
|
+
|
|
33
|
+
## Basic Usage
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { ExternalChangeDetector } from '@memberjunction/external-change-detection';
|
|
37
|
+
import { User } from '@memberjunction/core-entities';
|
|
38
|
+
|
|
39
|
+
async function detectChanges() {
|
|
40
|
+
// Create change detector instance
|
|
41
|
+
const detector = new ExternalChangeDetector();
|
|
42
|
+
|
|
43
|
+
// Run detection for the User entity
|
|
44
|
+
const changes = await detector.detectChanges({
|
|
45
|
+
entityName: 'User',
|
|
46
|
+
captureTimeLimit: 30, // minutes
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Process detected changes
|
|
50
|
+
console.log(`Detected ${changes.length} changes in User entity`);
|
|
51
|
+
|
|
52
|
+
// Replay changes if needed
|
|
53
|
+
if (changes.length > 0) {
|
|
54
|
+
await detector.replayChanges(changes);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
detectChanges();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Eligible Entities
|
|
62
|
+
|
|
63
|
+
Not all entities support external change detection. For an entity to be eligible for change detection:
|
|
64
|
+
|
|
65
|
+
1. The entity must have a TrackChanges property set to true in the metadata
|
|
66
|
+
2. The entity must have a LastUpdated or LastModifiedDate field
|
|
67
|
+
3. The entity must have the required fields for tracking history
|
|
68
|
+
|
|
69
|
+
You can check if an entity is eligible using:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { ExternalChangeDetector } from '@memberjunction/external-change-detection';
|
|
73
|
+
|
|
74
|
+
const detector = new ExternalChangeDetector();
|
|
75
|
+
const isEligible = await detector.isEntityEligibleForChangeDetection('User');
|
|
76
|
+
|
|
77
|
+
console.log(`User entity is eligible for change detection: ${isEligible}`);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Detecting Changes
|
|
81
|
+
|
|
82
|
+
### Simple Detection
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { ExternalChangeDetector } from '@memberjunction/external-change-detection';
|
|
86
|
+
|
|
87
|
+
const detector = new ExternalChangeDetector();
|
|
88
|
+
const changes = await detector.detectChanges({
|
|
89
|
+
entityName: 'Customer',
|
|
90
|
+
captureTimeLimit: 60 // Look back 60 minutes
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Filtering by Record IDs
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { ExternalChangeDetector } from '@memberjunction/external-change-detection';
|
|
98
|
+
|
|
99
|
+
const detector = new ExternalChangeDetector();
|
|
100
|
+
const changes = await detector.detectChanges({
|
|
101
|
+
entityName: 'Product',
|
|
102
|
+
recordIDs: [1001, 1002, 1003], // Only check these specific records
|
|
103
|
+
captureTimeLimit: 24 * 60 // Look back 24 hours
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Setting Change Criteria
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { ExternalChangeDetector, ExternalChangeDetectorCriteria } from '@memberjunction/external-change-detection';
|
|
111
|
+
|
|
112
|
+
const criteria: ExternalChangeDetectorCriteria = {
|
|
113
|
+
entityName: 'Order',
|
|
114
|
+
captureTimeLimit: 120, // 2 hours
|
|
115
|
+
includeFieldNames: ['Status', 'TotalAmount', 'CustomerID'], // Only check these fields
|
|
116
|
+
excludeFieldNames: ['UpdatedBy', 'InternalNotes'] // Ignore changes to these fields
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const detector = new ExternalChangeDetector();
|
|
120
|
+
const changes = await detector.detectChanges(criteria);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Replaying Changes
|
|
124
|
+
|
|
125
|
+
Once changes are detected, you can replay or apply them through the MemberJunction application to ensure that all business logic is properly executed:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { ExternalChangeDetector } from '@memberjunction/external-change-detection';
|
|
129
|
+
|
|
130
|
+
async function syncChanges() {
|
|
131
|
+
const detector = new ExternalChangeDetector();
|
|
132
|
+
|
|
133
|
+
// Detect changes
|
|
134
|
+
const changes = await detector.detectChanges({
|
|
135
|
+
entityName: 'Invoice',
|
|
136
|
+
captureTimeLimit: 720 // 12 hours
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (changes.length > 0) {
|
|
140
|
+
// Apply the detected changes through MemberJunction
|
|
141
|
+
const results = await detector.replayChanges(changes);
|
|
142
|
+
|
|
143
|
+
// Log results
|
|
144
|
+
console.log(`Applied ${results.successCount} changes successfully`);
|
|
145
|
+
console.log(`Failed to apply ${results.failureCount} changes`);
|
|
146
|
+
|
|
147
|
+
if (results.failureCount > 0) {
|
|
148
|
+
console.error('Failures:', results.failures);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Return Types
|
|
155
|
+
|
|
156
|
+
### ExternalChangeResult
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
interface ExternalChangeResult {
|
|
160
|
+
entityName: string;
|
|
161
|
+
recordID: number;
|
|
162
|
+
fieldChanges: ExternalFieldChange[];
|
|
163
|
+
errorMessage?: string;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### ExternalFieldChange
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
interface ExternalFieldChange {
|
|
171
|
+
fieldName: string;
|
|
172
|
+
oldValue: any;
|
|
173
|
+
newValue: any;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### ReplayChangesResult
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
interface ReplayChangesResult {
|
|
181
|
+
successCount: number;
|
|
182
|
+
failureCount: number;
|
|
183
|
+
successes: ReplayChangeSuccess[];
|
|
184
|
+
failures: ReplayChangeFailure[];
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Server-Side Usage
|
|
189
|
+
|
|
190
|
+
This library is primarily intended for server-side applications, often running as scheduled jobs or services that periodically check for external changes and reconcile them.
|
|
191
|
+
|
|
192
|
+
Example of setting up a scheduled check:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import { ExternalChangeDetector } from '@memberjunction/external-change-detection';
|
|
196
|
+
import { EntityInfo } from '@memberjunction/core';
|
|
197
|
+
|
|
198
|
+
async function scheduleChangeDetection() {
|
|
199
|
+
const detector = new ExternalChangeDetector();
|
|
200
|
+
|
|
201
|
+
// Get all entities that support change detection
|
|
202
|
+
const metadata = new EntityInfo();
|
|
203
|
+
const entities = await metadata.getEntitiesWithTrackChanges();
|
|
204
|
+
|
|
205
|
+
// Check each eligible entity
|
|
206
|
+
for (const entity of entities) {
|
|
207
|
+
try {
|
|
208
|
+
const isEligible = await detector.isEntityEligibleForChangeDetection(entity.Name);
|
|
209
|
+
|
|
210
|
+
if (isEligible) {
|
|
211
|
+
console.log(`Checking ${entity.Name} for external changes...`);
|
|
212
|
+
|
|
213
|
+
const changes = await detector.detectChanges({
|
|
214
|
+
entityName: entity.Name,
|
|
215
|
+
captureTimeLimit: 24 * 60 // Daily check
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (changes.length > 0) {
|
|
219
|
+
await detector.replayChanges(changes);
|
|
220
|
+
console.log(`Applied ${changes.length} changes to ${entity.Name}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch (error) {
|
|
224
|
+
console.error(`Error processing ${entity.Name}:`, error);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Performance Considerations
|
|
231
|
+
|
|
232
|
+
For large entities with many records, change detection can be resource-intensive. Consider using these optimization strategies:
|
|
233
|
+
|
|
234
|
+
1. Use smaller `captureTimeLimit` values
|
|
235
|
+
2. Filter by specific `recordIDs` when possible
|
|
236
|
+
3. Use `includeFieldNames` to limit which fields are checked
|
|
237
|
+
4. Schedule detection jobs during off-peak hours
|
|
238
|
+
5. Process entities in batches
|
|
239
|
+
6. Implement error handling and retry logic
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/external-change-detection",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.34.0",
|
|
4
4
|
"description": "Library used by server side applications to determine if changes have been made to entities by external systems/integrations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"typescript": "^5.4.5"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@memberjunction/core": "2.
|
|
23
|
-
"@memberjunction/core-entities": "2.
|
|
24
|
-
"@memberjunction/global": "2.
|
|
25
|
-
"@memberjunction/sqlserver-dataprovider": "2.
|
|
22
|
+
"@memberjunction/core": "2.34.0",
|
|
23
|
+
"@memberjunction/core-entities": "2.34.0",
|
|
24
|
+
"@memberjunction/global": "2.34.0",
|
|
25
|
+
"@memberjunction/sqlserver-dataprovider": "2.34.0"
|
|
26
26
|
}
|
|
27
27
|
}
|