@memberjunction/metadata-sync 6.2.0-edge.1 → 6.2.0-edge.3
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 +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/RecordProcessor.d.ts.map +1 -1
- package/dist/lib/RecordProcessor.js +2 -6
- package/dist/lib/RecordProcessor.js.map +1 -1
- package/dist/lib/collection-resolver.d.ts +4 -22
- package/dist/lib/collection-resolver.d.ts.map +1 -1
- package/dist/lib/collection-resolver.js +4 -117
- package/dist/lib/collection-resolver.js.map +1 -1
- package/dist/lib/sync-engine.d.ts +10 -0
- package/dist/lib/sync-engine.d.ts.map +1 -1
- package/dist/lib/sync-engine.js +25 -0
- package/dist/lib/sync-engine.js.map +1 -1
- package/dist/services/PushService.d.ts +17 -2
- package/dist/services/PushService.d.ts.map +1 -1
- package/dist/services/PushService.js +73 -35
- package/dist/services/PushService.js.map +1 -1
- package/dist/services/ValidationService.js +1 -1
- package/dist/services/ValidationService.js.map +1 -1
- package/package.json +15 -14
|
@@ -134,7 +134,7 @@ export declare class PushService {
|
|
|
134
134
|
private syncEngine;
|
|
135
135
|
private contextUser;
|
|
136
136
|
private warnings;
|
|
137
|
-
|
|
137
|
+
protected changeDetails: RecordChangeDetail[];
|
|
138
138
|
private syncConfig;
|
|
139
139
|
private deferredFileWrites;
|
|
140
140
|
private deferredRecords;
|
|
@@ -224,6 +224,20 @@ export declare class PushService {
|
|
|
224
224
|
private addWarning;
|
|
225
225
|
/** The process-wide provider that owns the push transaction. */
|
|
226
226
|
private hostProvider;
|
|
227
|
+
/**
|
|
228
|
+
* When a directory wrote a metadata-dataset entity, reload inside the push transaction so the
|
|
229
|
+
* next directory sees those rows (MJ#4836). Dry runs never reload.
|
|
230
|
+
*
|
|
231
|
+
* `since` is an index into `changeDetails`. Pass the index from before one directory to reload
|
|
232
|
+
* only for that directory. Pass the index from the start of Phase 2 before Phase 2.5 so a
|
|
233
|
+
* deletion recorded after the per-directory reloads still reloads, without repeating them.
|
|
234
|
+
*/
|
|
235
|
+
private reloadMetadataIfTouched;
|
|
236
|
+
/**
|
|
237
|
+
* After a rollback, drop any metadata the within-transaction reloads copied in. A pool read
|
|
238
|
+
* sees only committed rows. A failure here must not hide the rollback error.
|
|
239
|
+
*/
|
|
240
|
+
private refreshHostMetadataAfterRollback;
|
|
227
241
|
/**
|
|
228
242
|
* Run every phase inside the push transaction, commit it, then do the post-commit work.
|
|
229
243
|
* Never returns or throws with the transaction still open.
|
|
@@ -336,7 +350,8 @@ export declare class PushService {
|
|
|
336
350
|
private recordsMatch;
|
|
337
351
|
private _buildBatchContextKey;
|
|
338
352
|
/**
|
|
339
|
-
* Builds the payload used for calculating record checksums, including composition axes (§5, §6)
|
|
353
|
+
* Builds the payload used for calculating record checksums, including composition axes (§5, §6).
|
|
354
|
+
* Shares its shape with pull via {@link SyncEngine.BuildRecordChecksumPayload}.
|
|
340
355
|
*/
|
|
341
356
|
private buildRecordChecksumPayload;
|
|
342
357
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PushService.d.ts","sourceRoot":"","sources":["../../src/services/PushService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAY,QAAQ,EAAyF,iBAAiB,
|
|
1
|
+
{"version":3,"file":"PushService.d.ts","sourceRoot":"","sources":["../../src/services/PushService.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import { Metadata, EntitySaveOptions, IsVerboseLoggingEnabled } from '@memberjunction/core';
|
|
6
6
|
import { UUIDsEqual } from '@memberjunction/global';
|
|
7
7
|
import { IsStringSQLType } from '@memberjunction/sql-dialect';
|
|
8
|
-
import { DeferrableLookupError } from '../lib/sync-engine.js';
|
|
8
|
+
import { SyncEngine, DeferrableLookupError } from '../lib/sync-engine.js';
|
|
9
9
|
import { SyncMetadataEngine } from '../lib/sync-metadata-engine.js';
|
|
10
10
|
import { BatchContextIndex } from '../lib/batch-context-index.js';
|
|
11
11
|
import { loadEntityConfig, loadSyncConfig } from '../config.js';
|
|
@@ -23,7 +23,7 @@ import { findEntityDirectories } from '../lib/provider-utils.js';
|
|
|
23
23
|
import { DeletionAuditor } from '../lib/deletion-auditor.js';
|
|
24
24
|
import { describeMissingEntitySubclass } from '../lib/entity-subclass-guard.js';
|
|
25
25
|
import { DeletionReportGenerator } from '../lib/deletion-report-generator.js';
|
|
26
|
-
import { resolveCollectionRelationship } from '
|
|
26
|
+
import { resolveCollectionRelationship } from '@memberjunction/record-graph';
|
|
27
27
|
function emptyPushTotals() {
|
|
28
28
|
return { created: 0, updated: 0, unchanged: 0, deleted: 0, skipped: 0, deferred: 0, errors: 0 };
|
|
29
29
|
}
|
|
@@ -482,6 +482,37 @@ export class PushService {
|
|
|
482
482
|
hostProvider() {
|
|
483
483
|
return Metadata.Provider; // global-provider-ok: mj sync is single-process; this provider owns the push transaction
|
|
484
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* When a directory wrote a metadata-dataset entity, reload inside the push transaction so the
|
|
487
|
+
* next directory sees those rows (MJ#4836). Dry runs never reload.
|
|
488
|
+
*
|
|
489
|
+
* `since` is an index into `changeDetails`. Pass the index from before one directory to reload
|
|
490
|
+
* only for that directory. Pass the index from the start of Phase 2 before Phase 2.5 so a
|
|
491
|
+
* deletion recorded after the per-directory reloads still reloads, without repeating them.
|
|
492
|
+
*/
|
|
493
|
+
async reloadMetadataIfTouched(since, dryRun) {
|
|
494
|
+
if (dryRun) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const host = this.hostProvider();
|
|
498
|
+
const touched = this.changeDetails.slice(since).some((change) => host.IsMetadataDatasetMember(change.entityName));
|
|
499
|
+
if (touched) {
|
|
500
|
+
await host.RefreshWithinTransaction();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* After a rollback, drop any metadata the within-transaction reloads copied in. A pool read
|
|
505
|
+
* sees only committed rows. A failure here must not hide the rollback error.
|
|
506
|
+
*/
|
|
507
|
+
async refreshHostMetadataAfterRollback(callbacks) {
|
|
508
|
+
try {
|
|
509
|
+
await this.hostProvider().Refresh();
|
|
510
|
+
}
|
|
511
|
+
catch (refreshError) {
|
|
512
|
+
const message = refreshError instanceof Error ? refreshError.message : String(refreshError);
|
|
513
|
+
callbacks?.onWarn?.(`⚠️ Metadata could not be reloaded after the push rolled back: ${message}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
485
516
|
/**
|
|
486
517
|
* Run every phase inside the push transaction, commit it, then do the post-commit work.
|
|
487
518
|
* Never returns or throws with the transaction still open.
|
|
@@ -517,14 +548,21 @@ export class PushService {
|
|
|
517
548
|
}
|
|
518
549
|
// PHASE 1: creates and updates
|
|
519
550
|
const totals = await this.processAllEntityDirectories(run);
|
|
520
|
-
//
|
|
551
|
+
// Taken before any Phase 2 write. Each directory already reloaded after its own writes,
|
|
552
|
+
// so Phase 2 does not reload again. Phase 2.5 uses this index: a deletion lands in
|
|
553
|
+
// changeDetails after it, and that is the only reason to reload again (MJ#4836).
|
|
554
|
+
const changesBeforePhase2 = this.changeDetails.length;
|
|
555
|
+
// PHASE 2: deletions in reverse dependency order.
|
|
521
556
|
if (run.deletionAudit && totals.errors === 0) {
|
|
522
557
|
const deletionResult = await this.processDeletionsFromAudit(run.deletionAudit, options, callbacks);
|
|
523
558
|
totals.deleted += deletionResult.deleted;
|
|
524
559
|
totals.errors += deletionResult.errors;
|
|
525
560
|
}
|
|
526
|
-
// PHASE 2.5: deferred records (circular dependencies)
|
|
561
|
+
// PHASE 2.5: deferred records (circular dependencies).
|
|
562
|
+
// Reload when a deletion since the start of Phase 2 touched a metadata dataset, so a
|
|
563
|
+
// deferred save sees that row gone. Directories already reloaded their own writes (MJ#4836).
|
|
527
564
|
if (this.deferredRecords.length > 0 && totals.errors === 0) {
|
|
565
|
+
await this.reloadMetadataIfTouched(changesBeforePhase2, options.dryRun);
|
|
528
566
|
const deferredResult = await this.processDeferredRecords(options, callbacks);
|
|
529
567
|
totals.created += deferredResult.created;
|
|
530
568
|
totals.updated += deferredResult.updated;
|
|
@@ -550,6 +588,11 @@ export class PushService {
|
|
|
550
588
|
if (!options.dryRun) {
|
|
551
589
|
callbacks?.onWarn?.('\n⚠️ Rolling back database transaction due to error...');
|
|
552
590
|
rolledBack = await transactionManager.rollbackTransaction();
|
|
591
|
+
if (rolledBack) {
|
|
592
|
+
// The within-transaction reloads copied uncommitted rows into memory. A pool read
|
|
593
|
+
// puts back only what survived the rollback (MJ#4836).
|
|
594
|
+
await this.refreshHostMetadataAfterRollback(callbacks);
|
|
595
|
+
}
|
|
553
596
|
await this.writeFilesWithCommittedRecords(run);
|
|
554
597
|
for (const line of DescribeRollbackOutcome(rolledBack, this.committedWrites, configManager.getOriginalCwd())) {
|
|
555
598
|
callbacks?.onWarn?.(line);
|
|
@@ -642,7 +685,11 @@ export class PushService {
|
|
|
642
685
|
const dirName = path.relative(process.cwd(), entityDir) || '.';
|
|
643
686
|
this.useDirectoryMode(entityDir, options);
|
|
644
687
|
this.announceDirectory(dirName, progressPrefix, entityConfig.entity, entityDir, options, callbacks);
|
|
688
|
+
const firstChange = this.changeDetails.length;
|
|
645
689
|
const result = await this.processEntityDirectory(entityDir, entityConfig, options, run.fileBackupManager, callbacks, run.configDir);
|
|
690
|
+
// Nested relatedEntities land in changeDetails under their own entity name, so the
|
|
691
|
+
// directory's configured entity is not what decides the reload (MJ#4836).
|
|
692
|
+
await this.reloadMetadataIfTouched(firstChange, options.dryRun);
|
|
646
693
|
this.reportDirectoryResult(progressPrefix, dirName, result, options, callbacks);
|
|
647
694
|
addPushTotals(totals, result);
|
|
648
695
|
addPushTotals(this.runningTotals, result);
|
|
@@ -1317,20 +1364,6 @@ export class PushService {
|
|
|
1317
1364
|
}
|
|
1318
1365
|
}
|
|
1319
1366
|
}
|
|
1320
|
-
if (options.dryRun) {
|
|
1321
|
-
// Still add to batch context so child records at later dependency levels
|
|
1322
|
-
// can resolve @parent references. Without this, dry-run fails on any
|
|
1323
|
-
// metadata with parent-child nesting (e.g. Actions → Action Params).
|
|
1324
|
-
const batchContextEntry = { key: lookupKey, entity };
|
|
1325
|
-
if (exists) {
|
|
1326
|
-
callbacks?.onLog?.(`[DRY RUN] Would update ${entityName} record`);
|
|
1327
|
-
return { status: 'updated', batchContextEntry };
|
|
1328
|
-
}
|
|
1329
|
-
else {
|
|
1330
|
-
callbacks?.onLog?.(`[DRY RUN] Would create ${entityName} record`);
|
|
1331
|
-
return { status: 'created', batchContextEntry };
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
1367
|
// If updating an existing record that's dirty, capture what changed for the
|
|
1335
1368
|
// end-of-run recap. The inline diff is verbose-only now: the recap is the default
|
|
1336
1369
|
// surface, and emitting the diff mid-spinner previously garbled the spinner line.
|
|
@@ -1382,6 +1415,22 @@ export class PushService {
|
|
|
1382
1415
|
status: 'unchanged',
|
|
1383
1416
|
};
|
|
1384
1417
|
}
|
|
1418
|
+
// A dry run stops here, after the same change detection a real push uses, so an
|
|
1419
|
+
// in-sync record reports unchanged above rather than "would update" (#4529).
|
|
1420
|
+
if (options.dryRun) {
|
|
1421
|
+
// Still add to batch context so child records at later dependency levels
|
|
1422
|
+
// can resolve @parent references. Without this, dry-run fails on any
|
|
1423
|
+
// metadata with parent-child nesting (e.g. Actions → Action Params).
|
|
1424
|
+
const batchContextEntry = { key: lookupKey, entity };
|
|
1425
|
+
if (exists) {
|
|
1426
|
+
callbacks?.onLog?.(`[DRY RUN] Would update ${entityName} record`);
|
|
1427
|
+
return { status: 'updated', batchContextEntry };
|
|
1428
|
+
}
|
|
1429
|
+
else {
|
|
1430
|
+
callbacks?.onLog?.(`[DRY RUN] Would create ${entityName} record`);
|
|
1431
|
+
return { status: 'created', batchContextEntry };
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1385
1434
|
// Save the record with detailed error logging
|
|
1386
1435
|
const recordName = entity.Get('Name');
|
|
1387
1436
|
const entityRecordId = entity.Get('ID');
|
|
@@ -2291,21 +2340,11 @@ export class PushService {
|
|
|
2291
2340
|
return keyParts.join('|');
|
|
2292
2341
|
}
|
|
2293
2342
|
/**
|
|
2294
|
-
* Builds the payload used for calculating record checksums, including composition axes (§5, §6)
|
|
2343
|
+
* Builds the payload used for calculating record checksums, including composition axes (§5, §6).
|
|
2344
|
+
* Shares its shape with pull via {@link SyncEngine.BuildRecordChecksumPayload}.
|
|
2295
2345
|
*/
|
|
2296
2346
|
buildRecordChecksumPayload(record, fieldsOverride) {
|
|
2297
|
-
|
|
2298
|
-
if (!record.collections && !record.embeds && !record.extension) {
|
|
2299
|
-
return fields;
|
|
2300
|
-
}
|
|
2301
|
-
const payload = { fields };
|
|
2302
|
-
if (record.collections)
|
|
2303
|
-
payload.collections = record.collections;
|
|
2304
|
-
if (record.embeds)
|
|
2305
|
-
payload.embeds = record.embeds;
|
|
2306
|
-
if (record.extension)
|
|
2307
|
-
payload.extension = record.extension;
|
|
2308
|
-
return payload;
|
|
2347
|
+
return SyncEngine.BuildRecordChecksumPayload(fieldsOverride ?? record.fields, record.collections, record.embeds, record.extension);
|
|
2309
2348
|
}
|
|
2310
2349
|
/**
|
|
2311
2350
|
* Applies first-class composition axes onto the entity before Save (§5):
|
|
@@ -2391,8 +2430,8 @@ export class PushService {
|
|
|
2391
2430
|
collectionCompanion = propVal;
|
|
2392
2431
|
}
|
|
2393
2432
|
}
|
|
2394
|
-
// Dynamically register collection companion if entity supports
|
|
2395
|
-
if (!collectionCompanion && typeof entity.
|
|
2433
|
+
// Dynamically register collection companion if entity supports DeclareRelatedRecordsDynamic
|
|
2434
|
+
if (!collectionCompanion && typeof entity.DeclareRelatedRecordsDynamic === 'function') {
|
|
2396
2435
|
const entityInfo = entity.EntityInfo ?? new Metadata().EntityByName(entityName);
|
|
2397
2436
|
const resolved = resolveCollectionRelationship(entityInfo, colName);
|
|
2398
2437
|
if (resolved) {
|
|
@@ -2404,8 +2443,7 @@ export class PushService {
|
|
|
2404
2443
|
OnRemove: resolved.onRemove,
|
|
2405
2444
|
...(resolved.orderBy ? { OrderBy: resolved.orderBy } : {}),
|
|
2406
2445
|
};
|
|
2407
|
-
|
|
2408
|
-
collectionCompanion = declareFn(colOpts);
|
|
2446
|
+
collectionCompanion = entity.DeclareRelatedRecordsDynamic(colOpts);
|
|
2409
2447
|
}
|
|
2410
2448
|
}
|
|
2411
2449
|
if (!collectionCompanion) {
|