@memberjunction/integration-engine 5.37.0 → 5.39.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 (74) hide show
  1. package/dist/ActionMetadataGenerator.d.ts +8 -1
  2. package/dist/ActionMetadataGenerator.d.ts.map +1 -1
  3. package/dist/ActionMetadataGenerator.js +22 -3
  4. package/dist/ActionMetadataGenerator.js.map +1 -1
  5. package/dist/AdaptiveConcurrency.d.ts +85 -0
  6. package/dist/AdaptiveConcurrency.d.ts.map +1 -0
  7. package/dist/AdaptiveConcurrency.js +148 -0
  8. package/dist/AdaptiveConcurrency.js.map +1 -0
  9. package/dist/BaseIntegrationConnector.d.ts +127 -3
  10. package/dist/BaseIntegrationConnector.d.ts.map +1 -1
  11. package/dist/BaseIntegrationConnector.js +126 -11
  12. package/dist/BaseIntegrationConnector.js.map +1 -1
  13. package/dist/BaseRESTIntegrationConnector.d.ts +80 -15
  14. package/dist/BaseRESTIntegrationConnector.d.ts.map +1 -1
  15. package/dist/BaseRESTIntegrationConnector.js +314 -64
  16. package/dist/BaseRESTIntegrationConnector.js.map +1 -1
  17. package/dist/ConflictRecency.d.ts +24 -0
  18. package/dist/ConflictRecency.d.ts.map +1 -0
  19. package/dist/ConflictRecency.js +25 -0
  20. package/dist/ConflictRecency.js.map +1 -0
  21. package/dist/ContentHash.d.ts +28 -0
  22. package/dist/ContentHash.d.ts.map +1 -0
  23. package/dist/ContentHash.js +54 -0
  24. package/dist/ContentHash.js.map +1 -0
  25. package/dist/EnrichSchemaConstraints.d.ts +59 -0
  26. package/dist/EnrichSchemaConstraints.d.ts.map +1 -0
  27. package/dist/EnrichSchemaConstraints.js +168 -0
  28. package/dist/EnrichSchemaConstraints.js.map +1 -0
  29. package/dist/FieldMappingEngine.d.ts +22 -0
  30. package/dist/FieldMappingEngine.d.ts.map +1 -1
  31. package/dist/FieldMappingEngine.js +66 -5
  32. package/dist/FieldMappingEngine.js.map +1 -1
  33. package/dist/HashDiff.d.ts +68 -0
  34. package/dist/HashDiff.d.ts.map +1 -0
  35. package/dist/HashDiff.js +108 -0
  36. package/dist/HashDiff.js.map +1 -0
  37. package/dist/IntegrationActionGenerator.d.ts +93 -0
  38. package/dist/IntegrationActionGenerator.d.ts.map +1 -0
  39. package/dist/IntegrationActionGenerator.js +313 -0
  40. package/dist/IntegrationActionGenerator.js.map +1 -0
  41. package/dist/IntegrationConnectorCreationPipeline.d.ts +86 -0
  42. package/dist/IntegrationConnectorCreationPipeline.d.ts.map +1 -0
  43. package/dist/IntegrationConnectorCreationPipeline.js +226 -0
  44. package/dist/IntegrationConnectorCreationPipeline.js.map +1 -0
  45. package/dist/IntegrationEngine.d.ts +199 -1
  46. package/dist/IntegrationEngine.d.ts.map +1 -1
  47. package/dist/IntegrationEngine.js +1592 -109
  48. package/dist/IntegrationEngine.js.map +1 -1
  49. package/dist/IntegrationSchemaSync.d.ts +82 -0
  50. package/dist/IntegrationSchemaSync.d.ts.map +1 -1
  51. package/dist/IntegrationSchemaSync.js +289 -42
  52. package/dist/IntegrationSchemaSync.js.map +1 -1
  53. package/dist/MatchEngine.d.ts.map +1 -1
  54. package/dist/MatchEngine.js +4 -0
  55. package/dist/MatchEngine.js.map +1 -1
  56. package/dist/RateLimiter.d.ts +117 -0
  57. package/dist/RateLimiter.d.ts.map +1 -0
  58. package/dist/RateLimiter.js +159 -0
  59. package/dist/RateLimiter.js.map +1 -0
  60. package/dist/SyncLogger.d.ts +106 -0
  61. package/dist/SyncLogger.d.ts.map +1 -0
  62. package/dist/SyncLogger.js +176 -0
  63. package/dist/SyncLogger.js.map +1 -0
  64. package/dist/WatermarkService.d.ts +36 -1
  65. package/dist/WatermarkService.d.ts.map +1 -1
  66. package/dist/WatermarkService.js +113 -3
  67. package/dist/WatermarkService.js.map +1 -1
  68. package/dist/index.d.ts +23 -6
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +11 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/types.d.ts +52 -1
  73. package/dist/types.d.ts.map +1 -1
  74. package/package.json +8 -6
@@ -0,0 +1,226 @@
1
+ import { Metadata } from '@memberjunction/core';
2
+ import { IntegrationProgressEmitter, } from '@memberjunction/integration-progress-artifacts';
3
+ import { SoftPKClassifier, } from '@memberjunction/integration-pk-classifier';
4
+ import { IntegrationEngineBase } from '@memberjunction/integration-engine-base';
5
+ import { IntegrationSchemaSync } from './IntegrationSchemaSync.js';
6
+ /**
7
+ * The unified pipeline that drives connector creation / refresh end-to-end:
8
+ *
9
+ * 1. ConnectionTest stage — verifies credentials before any heavy work
10
+ * 2. Introspect stage — parallel describe via the connector
11
+ * 3. Persist stage — bounded-concurrency upsert with overlay precedence
12
+ * 4. PKClassify stage — soft PK classifier on objects still missing a PK
13
+ *
14
+ * Every stage emits structured events through IntegrationProgressEmitter so the
15
+ * stream is identical regardless of vendor. Stages also emit checkpoint events
16
+ * carrying enough resumableState that the orchestrator can pick up from a kill
17
+ * or container restart without re-running prior stages.
18
+ *
19
+ * The pipeline does NOT generate MJ entities itself — that gate (D7) lives in
20
+ * the CodeGen metadata layer: rows without a PK are simply not promoted to
21
+ * `__mj.Entity`. The pipeline emits `entity.skipped-no-pk` events for visibility.
22
+ */
23
+ export class IntegrationConnectorCreationPipeline {
24
+ async Run(opts) {
25
+ const runID = opts.RunID ?? IntegrationProgressEmitter.newRunID('connector');
26
+ const manifest = {
27
+ runID,
28
+ runKind: 'ConnectorCreation',
29
+ integrationID: opts.CompanyIntegration.IntegrationID,
30
+ companyIntegrationID: opts.CompanyIntegration.ID,
31
+ triggerType: opts.TriggerType ?? 'Pipeline',
32
+ startedAt: new Date().toISOString(),
33
+ expectedStages: ['ConnectionTest', 'Introspect', 'Persist', 'PKClassify'],
34
+ context: {
35
+ connectorClass: opts.Connector.constructor.name,
36
+ integrationName: opts.CompanyIntegration.Integration ?? null,
37
+ },
38
+ };
39
+ const emitter = new IntegrationProgressEmitter(manifest, {
40
+ rootDir: opts.ArtifactRootDir,
41
+ consoleMirror: opts.ConsoleMirror,
42
+ });
43
+ emitter.runStart(`Connector creation pipeline started for ${opts.CompanyIntegration.Integration ?? '(integration)'} run=${runID}`);
44
+ try {
45
+ await this.StageConnectionTest(emitter, opts);
46
+ const sourceSchema = await this.StageIntrospect(emitter, opts);
47
+ const persistResult = await this.StagePersist(emitter, opts, sourceSchema);
48
+ const { verdicts, unresolved } = await this.StagePKClassify(emitter, opts);
49
+ emitter.stageComplete('Pipeline', {
50
+ processed: persistResult.ObjectsCreated + persistResult.ObjectsUpdated,
51
+ succeeded: verdicts.filter(v => v.Confident).length,
52
+ skipped: unresolved.length,
53
+ });
54
+ await emitter.complete(`Pipeline complete. ${persistResult.ObjectsCreated} objects created, ${persistResult.ObjectsUpdated} updated, ${unresolved.length} unresolved PKs.`);
55
+ return {
56
+ RunID: runID,
57
+ Success: true,
58
+ PersistResult: persistResult,
59
+ PKVerdicts: verdicts,
60
+ UnresolvedObjects: unresolved,
61
+ Manifest: manifest,
62
+ };
63
+ }
64
+ catch (err) {
65
+ const msg = err instanceof Error ? err.message : String(err);
66
+ await emitter.fail(`Pipeline failed: ${msg}`);
67
+ return {
68
+ RunID: runID,
69
+ Success: false,
70
+ PKVerdicts: [],
71
+ UnresolvedObjects: [],
72
+ Manifest: manifest,
73
+ FailureMessage: msg,
74
+ };
75
+ }
76
+ finally {
77
+ await emitter.flush();
78
+ }
79
+ }
80
+ // ── Stage 1: connection ──────────────────────────────────────────────
81
+ async StageConnectionTest(emitter, opts) {
82
+ emitter.stageStart('ConnectionTest', 'Validating credentials before heavy work');
83
+ const startMs = Date.now();
84
+ const result = await opts.Connector.TestConnection(opts.CompanyIntegration, opts.ContextUser);
85
+ if (!result.Success) {
86
+ emitter.stageError('ConnectionTest', result.Message ?? 'Connection failed', { code: 'connection-failed' });
87
+ throw new Error(`ConnectionTest failed: ${result.Message ?? 'unknown reason'}`);
88
+ }
89
+ emitter.stageComplete('ConnectionTest', { processed: 1, succeeded: 1 });
90
+ emitter.checkpoint('ConnectionTest', { completedAt: new Date().toISOString(), durationMs: Date.now() - startMs });
91
+ }
92
+ // ── Stage 2: introspect ──────────────────────────────────────────────
93
+ async StageIntrospect(emitter, opts) {
94
+ emitter.stageStart('Introspect', 'Discovering objects and fields via connector');
95
+ const startMs = Date.now();
96
+ try {
97
+ const schema = await opts.Connector.IntrospectSchema(opts.CompanyIntegration, opts.ContextUser, opts.IntrospectOptions);
98
+ const fieldCount = schema.Objects.reduce((acc, o) => acc + o.Fields.length, 0);
99
+ emitter.stageComplete('Introspect', {
100
+ processed: schema.Objects.length,
101
+ succeeded: schema.Objects.length,
102
+ totalKnown: schema.Objects.length,
103
+ });
104
+ emitter.checkpoint('Introspect', {
105
+ objectsDiscovered: schema.Objects.length,
106
+ fieldsDiscovered: fieldCount,
107
+ durationMs: Date.now() - startMs,
108
+ });
109
+ return schema;
110
+ }
111
+ catch (err) {
112
+ const msg = err instanceof Error ? err.message : String(err);
113
+ emitter.stageError('Introspect', msg, { code: 'introspect-failed' });
114
+ throw err;
115
+ }
116
+ }
117
+ // ── Stage 3: persist ─────────────────────────────────────────────────
118
+ async StagePersist(emitter, opts, sourceSchema) {
119
+ emitter.stageStart('Persist', 'Upserting IntegrationObject/Field rows with overlay precedence');
120
+ const startMs = Date.now();
121
+ const persistResult = await IntegrationSchemaSync.PersistDiscoveredSchema({
122
+ IntegrationID: opts.CompanyIntegration.IntegrationID,
123
+ SourceSchema: sourceSchema,
124
+ ContextUser: opts.ContextUser,
125
+ Provider: opts.Provider,
126
+ UseTransactionGroup: true,
127
+ });
128
+ // Emit per-object + per-field structural-transparency events so the UI/audit
129
+ // trail captures WHO won each attribute.
130
+ for (const objLog of persistResult.ObjectMergeLog) {
131
+ emitter.objectAdded(objLog.ObjectName, objLog.EffectiveSource);
132
+ }
133
+ for (const fieldLog of persistResult.FieldMergeLog) {
134
+ emitter.fieldAdded(fieldLog.ObjectName, fieldLog.FieldName, fieldLog.EffectiveSource);
135
+ }
136
+ emitter.stageComplete('Persist', {
137
+ processed: persistResult.ObjectsCreated + persistResult.ObjectsUpdated,
138
+ succeeded: persistResult.ObjectsCreated + persistResult.ObjectsUpdated,
139
+ });
140
+ emitter.checkpoint('Persist', {
141
+ objectsCreated: persistResult.ObjectsCreated,
142
+ objectsUpdated: persistResult.ObjectsUpdated,
143
+ fieldsCreated: persistResult.FieldsCreated,
144
+ fieldsUpdated: persistResult.FieldsUpdated,
145
+ durationMs: Date.now() - startMs,
146
+ });
147
+ return persistResult;
148
+ }
149
+ // ── Stage 4: PK classification ───────────────────────────────────────
150
+ async StagePKClassify(emitter, opts) {
151
+ emitter.stageStart('PKClassify', 'Soft PK classifier for objects still missing a PK');
152
+ const md = opts.Provider ?? Metadata.Provider;
153
+ const engine = IntegrationEngineBase.Instance;
154
+ // Refresh from DB so we see what Persist just wrote
155
+ await engine.Config(true, opts.ContextUser, md);
156
+ const objects = engine.GetIntegrationObjectsByIntegrationID(opts.CompanyIntegration.IntegrationID);
157
+ const classifier = new SoftPKClassifier();
158
+ const verdicts = [];
159
+ const unresolved = [];
160
+ for (const obj of objects) {
161
+ const fields = engine.GetIntegrationObjectFields(obj.ID);
162
+ const hasPK = fields.some(f => f.IsPrimaryKey);
163
+ if (hasPK) {
164
+ emitter.entityGenerated(obj.Name, obj.Name);
165
+ continue;
166
+ }
167
+ emitter.pkClassifierInvoked(obj.Name);
168
+ const verdict = await classifier.Classify({
169
+ object: obj,
170
+ fields,
171
+ universalConvention: opts.UniversalPKConvention,
172
+ sampleRows: opts.SampleRowsByObject?.[obj.Name],
173
+ llmInference: opts.LLMInference,
174
+ });
175
+ emitter.pkClassifierResult(obj.Name, {
176
+ Confident: verdict.Confident,
177
+ Nominee: verdict.Nominee,
178
+ Confidence: verdict.Confidence,
179
+ Strategy: verdict.Strategy,
180
+ Reason: verdict.Reason,
181
+ });
182
+ verdicts.push({
183
+ ObjectName: obj.Name,
184
+ Confident: verdict.Confident,
185
+ Nominee: verdict.Nominee,
186
+ Confidence: verdict.Confidence,
187
+ Strategy: verdict.Strategy,
188
+ Reason: verdict.Reason,
189
+ });
190
+ if (verdict.Confident && verdict.Nominee) {
191
+ const winning = fields.find(f => f.Name === verdict.Nominee);
192
+ if (winning) {
193
+ winning.IsPrimaryKey = true;
194
+ const saved = await winning.Save();
195
+ if (!saved) {
196
+ emitter.stageError('PKClassify', `Failed to persist PK on ${obj.Name}.${verdict.Nominee}: ${winning.LatestResult?.CompleteMessage ?? 'unknown error'}`);
197
+ unresolved.push(obj.Name);
198
+ continue;
199
+ }
200
+ emitter.entityGenerated(obj.Name, obj.Name);
201
+ }
202
+ else {
203
+ // Classifier nominated a field that's not in our cache — refuse silently and skip.
204
+ unresolved.push(obj.Name);
205
+ emitter.entitySkippedNoPK(obj.Name);
206
+ }
207
+ }
208
+ else {
209
+ unresolved.push(obj.Name);
210
+ emitter.entitySkippedNoPK(obj.Name);
211
+ }
212
+ }
213
+ emitter.stageComplete('PKClassify', {
214
+ processed: verdicts.length,
215
+ succeeded: verdicts.filter(v => v.Confident).length,
216
+ skipped: unresolved.length,
217
+ });
218
+ emitter.checkpoint('PKClassify', {
219
+ totalObjects: objects.length,
220
+ verdicts: verdicts.length,
221
+ unresolved: unresolved.length,
222
+ });
223
+ return { verdicts, unresolved };
224
+ }
225
+ }
226
+ //# sourceMappingURL=IntegrationConnectorCreationPipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IntegrationConnectorCreationPipeline.js","sourceRoot":"","sources":["../src/IntegrationConnectorCreationPipeline.ts"],"names":[],"mappings":"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"}
@@ -82,10 +82,30 @@ export declare class IntegrationEngine extends BaseSingleton<IntegrationEngine>
82
82
  * Internal sync execution method. Contains the full orchestration logic.
83
83
  */
84
84
  private executeSyncInternal;
85
+ /**
86
+ * Builds the durable progress emitter for a sync run. Best-effort: returns
87
+ * undefined (and never throws) if the artifact store can't be initialized, so
88
+ * structured logging can never block a sync.
89
+ */
90
+ private createSyncProgressEmitter;
91
+ /** Maps the engine SyncTriggerType to the manifest's triggerType vocabulary. */
92
+ private mapTriggerTypeForManifest;
93
+ /** Writes the terminal artifact result + flushes. Best-effort — never throws. */
94
+ private finalizeSyncProgress;
85
95
  /**
86
96
  * Loads all configuration needed for a sync run.
87
97
  */
88
98
  private LoadRunConfiguration;
99
+ /**
100
+ * Periodic full-reconcile cadence (plan §C5: "periodic full reconcile for hard deletes"). When the
101
+ * caller did NOT explicitly request FullSync, an integration can opt into automatic periodic full
102
+ * reconciles via CompanyIntegration.Configuration {"fullSyncEvery": N}: every Nth completed run
103
+ * (and the first) does a full fetch + orphan/delete-detection instead of a watermark-incremental
104
+ * pull, so hard-deletes upstream are reclaimed on a schedule without the caller tracking cadence.
105
+ * Zero cost when unset (no DB read); returns false on N<=1 / unset / any error (incremental — no
106
+ * behavior change).
107
+ */
108
+ private resolveScheduledFullSync;
89
109
  /**
90
110
  * Creates a new CompanyIntegrationRun record to track this sync.
91
111
  */
@@ -94,6 +114,71 @@ export declare class IntegrationEngine extends BaseSingleton<IntegrationEngine>
94
114
  * Processes all entity maps, aggregating results with progress tracking.
95
115
  */
96
116
  private ExecuteEntityMaps;
117
+ /**
118
+ * Groups the run's entity maps into dependency layers (parents before children) using the
119
+ * IntegrationObject FK graph (RelatedIntegrationObjectID). Layer 0 = roots (no FK dependency on
120
+ * another selected object); layer N depends only on layers &lt; N. Maps within a layer are
121
+ * mutually independent and safe to run concurrently. Falls back to a single layer (all maps,
122
+ * original order) if the graph can't be resolved — preserving current behavior. Stable: the
123
+ * original config order is preserved within each layer.
124
+ */
125
+ private buildEntityMapDependencyLayers;
126
+ /**
127
+ * Builds the selected-object FK dependency graph for a run: each selected IntegrationObject →
128
+ * the set of its SELECTED parent IntegrationObject IDs (via IntegrationObjectField.RelatedIntegrationObjectID).
129
+ * Shared by {@link buildEntityMapDependencyLayers} (parent-before-child ordering) and the
130
+ * second-layer silent-empty tripwire ({@link checkSecondLayerEmpty}). Returns null when the
131
+ * graph can't be resolved (no IOs, or none of the maps resolve to an IO) — callers then fall
132
+ * back to flat/original ordering.
133
+ */
134
+ private computeSelectedDependencyGraph;
135
+ /**
136
+ * Surfaces the second-layer silent-empty case as a structured warning. An object that HAS FK
137
+ * parents (an association/dependent — a "second-layer" object) but fetched ZERO records is the
138
+ * classic silent fail: a successful run that quietly produced nothing because its parents
139
+ * weren't synced/mapped or the DAG ordered it too early. Rather than let that look identical to
140
+ * "genuinely no data", we emit a SyncWarning (with the parent record counts) so it is visible
141
+ * over GraphQL. Must be called AFTER the map completes; relies on parents (earlier layers)
142
+ * having already recorded their counts in `processedByIoId`.
143
+ */
144
+ private checkSecondLayerEmpty;
145
+ /** Opt-in sync concurrency from CompanyIntegration.Configuration; default 1 (sequential), clamped [1,16]. */
146
+ private getSyncConcurrency;
147
+ /** Runs `fn` over items with at most `cap` concurrent executions. cap&lt;=1 → strictly sequential. */
148
+ private runBounded;
149
+ /** Per-integration request-spacing chain for the rate limiter (keyed by IntegrationID → last scheduled time). */
150
+ private readonly _rateLimiters;
151
+ /** Minimum ms between outbound requests for this integration (Integration.BatchRequestWaitTime; 0 = disabled). */
152
+ private getRequestSpacingMs;
153
+ /**
154
+ * Rate-limits outbound connector requests per integration, honoring
155
+ * Integration.BatchRequestWaitTime. No-op when the limit is unset/-1 (the default → zero
156
+ * behavior change). Requests are chained per integration so concurrent callers (opt-in
157
+ * parallel sync) are spaced apart too — the safety net that keeps parallelism within the
158
+ * vendor's rate limit.
159
+ */
160
+ private rateLimit;
161
+ /**
162
+ * Adaptive token-bucket limiter for this company integration (plan.md §7 peak-aware rate
163
+ * limiting), lazily created and configured from the connector's RateLimitPolicy — or, when the
164
+ * connector declares none, from Integration.BatchRequestWaitTime (spacing → tokens/sec). Keyed by
165
+ * CompanyIntegrationID (NOT IntegrationID): source limits are per-credential, so two companies on
166
+ * the same vendor have independent budgets and must not share one bucket. {@link reportRateOutcome}
167
+ * feeds 429s/successes back so the rate auto-tunes (AIMD).
168
+ */
169
+ private getRateLimiter;
170
+ /**
171
+ * Feed a fetch/write outcome back to the company integration's adaptive limiter. No
172
+ * `throttledErr` = a clean response → ramp the rate up; a rate-limit error → back off (honoring
173
+ * the connector's parsed Retry-After). Other errors are ignored (don't ramp, don't back off).
174
+ */
175
+ private reportRateOutcome;
176
+ /**
177
+ * Feed a push/CRUD result to the limiter so the WRITE path tunes the rate too (the fetch path
178
+ * already does): a 2xx ramps the rate up, a 429 backs it off (honoring Retry-After). Otherwise
179
+ * leave the rate untouched.
180
+ */
181
+ private reportRateForCrud;
97
182
  /**
98
183
  * Processes a single entity map based on SyncDirection:
99
184
  * - Pull: fetch from external → map → match → apply to MJ
@@ -123,6 +208,36 @@ export declare class IntegrationEngine extends BaseSingleton<IntegrationEngine>
123
208
  private LoadAllMJRecords;
124
209
  /** Pushes a single changed MJ record to the external system. */
125
210
  private PushSingleRecord;
211
+ /**
212
+ * Surface a SKIPPED push (forbidden write / unsupported op) as a structured SyncWarning so a
213
+ * change that was NOT written to the external system is visible over GraphQL — not just a
214
+ * console.warn + a silent RecordsSkipped bump. Mirrors the read-side silent-fail surfacing
215
+ * (plan.md §8 "things go right, and when they don't it's loud" — applied to the write path).
216
+ */
217
+ private warnPushSkip;
218
+ /**
219
+ * Pull-first 3-way combine for bidirectional push. Snapshot (last-synced external state) is
220
+ * the common ancestor; MJ-current is "ours"; the re-fetched external record is "theirs".
221
+ * - field only WE changed → push our value
222
+ * - field only THEY changed → leave it (don't push; next pull brings it into MJ)
223
+ * - both changed, same value → converged, skip
224
+ * - both changed, different → true conflict → ConflictResolution policy
225
+ * Returns the attribute subset MJ should actually push. Safe fallbacks: no snapshot / no
226
+ * GetRecord support / fetch failure → push the full attribute set (prior behavior). Never throws.
227
+ */
228
+ private computePushCombine;
229
+ /** Loose value equality for conflict comparison across JSON/string/number/bool/null shapes. */
230
+ private valuesEqual;
231
+ /**
232
+ * MostRecent conflict resolution: compares the MJ row's last-update time
233
+ * (`__mj_UpdatedAt`) against the external record's `ModifiedAt`. Record-level recency
234
+ * (most sources don't expose per-field timestamps), so the caller computes it once
235
+ * and applies it to every conflicting field. Returns null when a timestamp is
236
+ * missing/unparseable → caller falls back to DestWins (a conflict is never dropped).
237
+ */
238
+ private resolveMostRecentWinner;
239
+ /** Marks an MJ mirror record in-conflict (Manual resolution) via its standard sync columns. Best-effort. */
240
+ private markConflictOnMJRecord;
126
241
  /**
127
242
  * Full-sync orphan detection: finds MJ records that have a record map entry
128
243
  * but were NOT returned by the external system during this full pull.
@@ -145,24 +260,100 @@ export declare class IntegrationEngine extends BaseSingleton<IntegrationEngine>
145
260
  * Loads active field maps for a given entity map.
146
261
  */
147
262
  private LoadFieldMaps;
263
+ /** Parses the entity map's Configuration JSON (best-effort) for engine-side feature toggles. */
264
+ private parseEntityMapConfig;
265
+ /** Opt-in partition (Merkle) reconcile flag from the entity map Configuration (GQL-managed). */
266
+ private isPartitionReconcileEnabled;
267
+ /** Partition count for the reconcile (default 256), from the entity map Configuration if set. */
268
+ private partitionReconcileCount;
269
+ /**
270
+ * Partition (Merkle) hash-diff reconcile (§7). Given ALL mapped records of a watermark-less object,
271
+ * bucket them by stable identity, fold each bucket's content hashes into one order-independent rollup,
272
+ * compare against last sync's rollups, and deep-apply (match + upsert) ONLY the partitions whose rollup
273
+ * moved (changed/added). Partitions whose rollup matches are proven identical and skipped entirely
274
+ * (counted as skipped — no match lookup, no write). The new snapshot is persisted ONLY after a clean
275
+ * apply, so a failure re-reconciles from the prior snapshot next time. Deletes are handled by the
276
+ * caller's orphan sweep over the full fetched-id set.
277
+ *
278
+ * MEMORY: this mode buffers the ENTIRE fetched set (`accumulatedMapped`) in RAM until this post-loop
279
+ * apply, rather than streaming batch-by-batch — that's the cost of one complete cross-batch snapshot.
280
+ * It is intended for watermark-less small/medium objects (the kind that re-fetch everything anyway,
281
+ * e.g. a membership roster of tens of thousands). Don't enable it on a multi-million-row object; for
282
+ * those, leave it off and rely on per-record content-hash (which streams).
283
+ */
284
+ private applyViaPartitionReconcile;
148
285
  /**
149
286
  * Applies resolved records to MJ, handling each individually for error isolation.
150
287
  */
151
288
  private ApplyRecords;
289
+ /**
290
+ * Refreshes __mj_integration_LastReconciledAt = now for a set of records that the content-hash
291
+ * fast path skipped (present + confirmed-unchanged on the source). Issues ONE set-based UPDATE
292
+ * for the whole skip set so the optimization isn't defeated by per-row writes. No-op (and never
293
+ * throws) when the entity lacks the column, has a composite PK, or the UPDATE fails — best-effort,
294
+ * mirroring PrefetchContentHashes. Keeps the column's "last confirmed present" semantics honest so
295
+ * future unseen-since-last-reconcile logic can't misclassify a still-present unchanged record.
296
+ */
297
+ private TouchLastReconciledAt;
298
+ /**
299
+ * Per-record fallback for a batch whose single transaction failed. Re-applies each
300
+ * record in its OWN transaction so a failure isolates to that record only — good
301
+ * siblings commit, the poison record(s) error out with their REAL per-record cause.
302
+ *
303
+ * Counters and the run-invariant are preserved: every record bumps RecordsProcessed
304
+ * exactly once (so the chunk's processed total still equals chunk.length), good
305
+ * records increment Created/Updated/Skipped via ApplySingleRecord, and each failure
306
+ * increments RecordsErrored and pushes a SyncRecordError classified with the SAME
307
+ * ClassifyError used by the connector path. A `sync.record.error` event is emitted
308
+ * once PER failed record (phase:'save'), carrying that record's real ExternalID /
309
+ * ChangeType — not a single batch-wide error.
310
+ *
311
+ * Begin/Commit/Rollback are always matched per record (no leaked open transaction).
312
+ */
313
+ private applyRecordsIndividually;
152
314
  /**
153
315
  * Applies a single record change (Create, Update, Delete, or Skip).
154
316
  */
155
317
  private ApplySingleRecord;
156
318
  /**
157
- * Creates a new MJ record with pre-write validation and saves a record map entry.
319
+ * Upserts an MJ record BY PRIMARY KEY (and saves a record-map entry).
320
+ *
321
+ * This is the "unmatched" write path — reached when a record matched neither the RecordMap nor a
322
+ * key-field lookup, so the caller assumed it was new. Historically it blindly `NewRecord()`+INSERTed,
323
+ * which COLLIDED with a duplicate-key violation when the dest row already existed but no RecordMap
324
+ * pointed at it. That happens for real: after the entity maps (and their record maps) are deleted while
325
+ * the dest rows persist (a maps delete+re-add, or a partial cleanup), a content-changed record matches
326
+ * neither the (gone) map nor a key field and lands here — over a live PK.
327
+ *
328
+ * Fix: load by the record's mapped PK first; only `NewRecord()` when the row does not already exist,
329
+ * otherwise UPDATE it in place. This makes the create path idempotent on the PK (§7 "idempotent upserts
330
+ * keyed on PK") and re-establishes the missing record map either way.
331
+ *
332
+ * @returns true if an existing row was updated, false if a new row was inserted (so the caller counts correctly).
158
333
  */
159
334
  private CreateRecord;
335
+ /**
336
+ * Builds the pipe-joined PK string for a record from its MAPPED fields (case-insensitively), or null
337
+ * when any PK field is absent/blank — i.e. the PK is not carried by the mapped data (server-assigned),
338
+ * so the record is genuinely new and must be inserted. Used by CreateRecord for PK-safe upsert.
339
+ */
340
+ private extractMappedPrimaryKey;
160
341
  /**
161
342
  * Updates an existing MJ record with pre-write validation.
162
343
  * If the record cannot be loaded (e.g. it was deleted or never fully created),
163
344
  * falls back to CreateRecord (upsert behavior).
164
345
  */
165
346
  private UpdateRecord;
347
+ /**
348
+ * Batch-loads the stored `__mj_integration_ContentHash` for the Update records in a
349
+ * batch, keyed by matched MJ record ID. Returns undefined (→ no fast-path skip; the
350
+ * dirty-flag path runs) when the optimization doesn't apply or can't be performed:
351
+ * - the target entity has no ContentHash column (predates the feature), or
352
+ * - the entity has a composite PK (we keep the '|'-split out of the fast path), or
353
+ * - nothing in the batch is an Update with a matched ID, or
354
+ * - the read fails (best-effort — a logging/optimization read must never break a sync).
355
+ */
356
+ private PrefetchContentHashes;
166
357
  /**
167
358
  * Runs Validate() on an entity if the method exists.
168
359
  * Throws a validation error with details if validation fails.
@@ -183,6 +374,13 @@ export declare class IntegrationEngine extends BaseSingleton<IntegrationEngine>
183
374
  * Sets fields on a BaseEntity instance from a field value map.
184
375
  */
185
376
  private SetEntityFields;
377
+ /**
378
+ * §5/§10 type-driven enforcement: clamp an over-length string to the target column's MaxLength
379
+ * (a character count — SQLMaxLength already converts nvarchar bytes→chars) so a source value
380
+ * wider than the resolved column is truncated instead of failing the whole row on "value too
381
+ * long". Non-strings / values that fit / unlimited columns (MaxLength 0) pass through unchanged.
382
+ */
383
+ private enforceMaxLength;
186
384
  /**
187
385
  * Coerce external values to something MJ's SQL provider can bind safely.
188
386
  * The external system has already done its best — this is only a safety
@@ -1 +1 @@
1
- {"version":3,"file":"IntegrationEngine.d.ts","sourceRoot":"","sources":["../src/IntegrationEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"IntegrationEngine.d.ts","sourceRoot":"","sources":["../src/IntegrationEngine.ts"],"names":[],"mappings":"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"}