@memberjunction/integration-engine 5.40.2 → 5.42.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 +34 -0
- package/dist/BaseIntegrationConnector.d.ts +109 -0
- package/dist/BaseIntegrationConnector.d.ts.map +1 -1
- package/dist/BaseIntegrationConnector.js +308 -93
- package/dist/BaseIntegrationConnector.js.map +1 -1
- package/dist/BaseRESTIntegrationConnector.d.ts +32 -0
- package/dist/BaseRESTIntegrationConnector.d.ts.map +1 -1
- package/dist/BaseRESTIntegrationConnector.js +182 -28
- package/dist/BaseRESTIntegrationConnector.js.map +1 -1
- package/dist/ContentHash.d.ts +22 -0
- package/dist/ContentHash.d.ts.map +1 -1
- package/dist/ContentHash.js +35 -0
- package/dist/ContentHash.js.map +1 -1
- package/dist/CustomColumnPromotion.d.ts +108 -0
- package/dist/CustomColumnPromotion.d.ts.map +1 -0
- package/dist/CustomColumnPromotion.js +202 -0
- package/dist/CustomColumnPromotion.js.map +1 -0
- package/dist/CustomOverflow.d.ts +64 -0
- package/dist/CustomOverflow.d.ts.map +1 -0
- package/dist/CustomOverflow.js +74 -0
- package/dist/CustomOverflow.js.map +1 -0
- package/dist/FieldMappingEngine.d.ts.map +1 -1
- package/dist/FieldMappingEngine.js +22 -3
- package/dist/FieldMappingEngine.js.map +1 -1
- package/dist/IntegrationConnectorCreationPipeline.d.ts +33 -0
- package/dist/IntegrationConnectorCreationPipeline.d.ts.map +1 -1
- package/dist/IntegrationConnectorCreationPipeline.js +157 -0
- package/dist/IntegrationConnectorCreationPipeline.js.map +1 -1
- package/dist/IntegrationEngine.d.ts +106 -6
- package/dist/IntegrationEngine.d.ts.map +1 -1
- package/dist/IntegrationEngine.js +874 -170
- package/dist/IntegrationEngine.js.map +1 -1
- package/dist/IntegrationSchemaSync.d.ts +84 -13
- package/dist/IntegrationSchemaSync.d.ts.map +1 -1
- package/dist/IntegrationSchemaSync.js +198 -36
- package/dist/IntegrationSchemaSync.js.map +1 -1
- package/dist/KeySerialization.d.ts +21 -0
- package/dist/KeySerialization.d.ts.map +1 -0
- package/dist/KeySerialization.js +29 -0
- package/dist/KeySerialization.js.map +1 -0
- package/dist/MatchEngine.d.ts.map +1 -1
- package/dist/MatchEngine.js +12 -4
- package/dist/MatchEngine.js.map +1 -1
- package/dist/RecordFlatten.d.ts +49 -0
- package/dist/RecordFlatten.d.ts.map +1 -0
- package/dist/RecordFlatten.js +50 -0
- package/dist/RecordFlatten.js.map +1 -0
- package/dist/StreamingDiscovery.d.ts +145 -0
- package/dist/StreamingDiscovery.d.ts.map +1 -0
- package/dist/StreamingDiscovery.js +306 -0
- package/dist/StreamingDiscovery.js.map +1 -0
- package/dist/SyncLogger.d.ts +1 -1
- package/dist/SyncLogger.d.ts.map +1 -1
- package/dist/SyncLogger.js +19 -1
- package/dist/SyncLogger.js.map +1 -1
- package/dist/auth-helpers/BasicAuthHeaderBuilder.d.ts +36 -0
- package/dist/auth-helpers/BasicAuthHeaderBuilder.d.ts.map +1 -0
- package/dist/auth-helpers/BasicAuthHeaderBuilder.js +38 -0
- package/dist/auth-helpers/BasicAuthHeaderBuilder.js.map +1 -0
- package/dist/auth-helpers/OAuth1aSigner.d.ts +56 -0
- package/dist/auth-helpers/OAuth1aSigner.d.ts.map +1 -0
- package/dist/auth-helpers/OAuth1aSigner.js +91 -0
- package/dist/auth-helpers/OAuth1aSigner.js.map +1 -0
- package/dist/auth-helpers/OAuth2TokenManager.d.ts +103 -0
- package/dist/auth-helpers/OAuth2TokenManager.d.ts.map +1 -0
- package/dist/auth-helpers/OAuth2TokenManager.js +143 -0
- package/dist/auth-helpers/OAuth2TokenManager.js.map +1 -0
- package/dist/auth-helpers/index.d.ts +11 -0
- package/dist/auth-helpers/index.d.ts.map +1 -0
- package/dist/auth-helpers/index.js +8 -0
- package/dist/auth-helpers/index.js.map +1 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomColumnPromotion.d.ts","sourceRoot":"","sources":["../src/CustomColumnPromotion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,0FAA0F;AAC1F,MAAM,WAAW,kBAAkB;IAC/B,4FAA4F;IAC5F,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IAC9D,yFAAyF;IACzF,aAAa,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,2GAA2G;AAC3G,MAAM,WAAW,gBAAgB;IAC7B,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,YAAY,EAAE,OAAO,EAAE,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;IAC/B,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,QAAQ,EAAE,kBAAkB,CAAC;CAChC;AAED,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC7C;AAmBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,gBAAgB,EAAE,EACzB,IAAI,GAAE,oBAAyB,GAChC,kBAAkB,EAAE,CAsBtB;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,kBAAkB,CA4BjF;AAwCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAC9B,mBAAmB,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EACrD,SAAS,GAAE,MAA2B,GACvC,gBAAgB,EAAE,CA0BpB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKtD"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion planner — the brain of the post-sync custom-column step (gaps.md §2, M2).
|
|
3
|
+
*
|
|
4
|
+
* After a sync, the values a source returned with no field map are parked as JSON in the
|
|
5
|
+
* {@link CUSTOM_OVERFLOW_COLUMN} system column (M1 capture). This module decides, from a
|
|
6
|
+
* coverage scan of that column, WHICH of those keys earn a real column and WHAT bounded
|
|
7
|
+
* type each should get. It is PURE — no DB, no RSU, no I/O — so the genuinely new logic is
|
|
8
|
+
* fully unit-testable. The server-side orchestrator (M2b) feeds the resulting plan into the
|
|
9
|
+
* EXISTING refresh pipeline (SchemaEvolution ADD COLUMN → RSU → IntegrationSchemaSync IOF →
|
|
10
|
+
* field map); this module never touches schema itself.
|
|
11
|
+
*
|
|
12
|
+
* Design rules (from gaps.md §2 + the connector-code conventions):
|
|
13
|
+
* - Provable-only / never fabricate: a key earns a column only on PERVASIVENESS evidence
|
|
14
|
+
* (coverage ≥ threshold), never on a single malformed row. PK/FK are NEVER inferred here —
|
|
15
|
+
* customs are always emitted nullable, non-PK, non-FK (classification is deferred to D4).
|
|
16
|
+
* - Generous bounded typing (the NVARCHAR(MAX) problem): size columns comfortably from the
|
|
17
|
+
* observed samples and err LARGER — a roomy bounded column beats a truncating tight one,
|
|
18
|
+
* and both beat MAX. Only fall back to MAX/TEXT when the observed length genuinely can't be
|
|
19
|
+
* bounded. Narrow to number/boolean/datetime ONLY when every non-null sample unambiguously
|
|
20
|
+
* supports it; otherwise default to a (generously bounded) string — that is the safe choice
|
|
21
|
+
* that can hold anything the source later returns.
|
|
22
|
+
* - Terminate / never re-promote: a key whose column already exists is skipped, so the
|
|
23
|
+
* capture→promote loop converges instead of re-promoting forever.
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULT_COVERAGE_THRESHOLD = 0; // §23 — presence-based: a key seen in even one row earns a column.
|
|
26
|
+
/** SQL Server's largest bounded NVARCHAR before MAX; above this we must use MAX/TEXT. */
|
|
27
|
+
const MAX_BOUNDED_STRING = 4000;
|
|
28
|
+
/** Floor for a generous string bound — never size a custom string column tighter than this. */
|
|
29
|
+
const MIN_STRING_BOUND = 255;
|
|
30
|
+
/**
|
|
31
|
+
* Minimum all-integer sample before we trust the field is INTEGRAL and narrow to BIGINT (#A9). Below this
|
|
32
|
+
* a handful of integer samples does NOT prove the unscanned tail is integer-only — a later decimal would be
|
|
33
|
+
* silently rejected by BIGINT (dead-lettered). Under the threshold we use wide fixed-point (which holds
|
|
34
|
+
* integers too), so a later decimal never fails; the column can still re-promote to BIGINT once enough
|
|
35
|
+
* integer evidence accrues.
|
|
36
|
+
*/
|
|
37
|
+
const MIN_SAMPLE_FOR_INTEGER_NARROW = 12;
|
|
38
|
+
/** Matches an ISO-8601-ish date / datetime so we don't mistake "5" or "2020" for a date. */
|
|
39
|
+
const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
40
|
+
/**
|
|
41
|
+
* Plans which overflow keys to promote to real columns. Pure; deterministic (sorted by key).
|
|
42
|
+
*
|
|
43
|
+
* @param stats - per-key coverage statistics from the overflow scan
|
|
44
|
+
* @param opts - coverage threshold + the set of already-existing column names
|
|
45
|
+
* @returns the promotion candidates, sorted by key for stable, replayable output
|
|
46
|
+
*/
|
|
47
|
+
export function planPromotions(stats, opts = {}) {
|
|
48
|
+
const threshold = opts.CoverageThreshold ?? DEFAULT_COVERAGE_THRESHOLD;
|
|
49
|
+
const existing = lowercaseSet(opts.ExistingColumnNames);
|
|
50
|
+
const candidates = [];
|
|
51
|
+
for (const stat of stats) {
|
|
52
|
+
// Terminate / never re-promote: the column already exists.
|
|
53
|
+
if (existing.has(stat.Key.toLowerCase()))
|
|
54
|
+
continue;
|
|
55
|
+
// Guard div-by-zero only; §23 — presence is enough (default threshold 0), so a key seen in
|
|
56
|
+
// even one row earns a column. A higher bar is opt-in via CoverageThreshold.
|
|
57
|
+
if (stat.TotalRows <= 0)
|
|
58
|
+
continue;
|
|
59
|
+
const coverage = stat.Occurrences / stat.TotalRows;
|
|
60
|
+
if (coverage < threshold)
|
|
61
|
+
continue;
|
|
62
|
+
candidates.push({
|
|
63
|
+
Key: stat.Key,
|
|
64
|
+
Coverage: coverage,
|
|
65
|
+
Inferred: inferColumnTypeFromSamples(stat.SampleValues),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return candidates.sort((a, b) => a.Key.localeCompare(b.Key));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Infers a generously-bounded column type from observed sample values. Narrows to
|
|
72
|
+
* boolean/number/datetime ONLY when EVERY non-null sample unambiguously supports it;
|
|
73
|
+
* otherwise defaults to a comfortably-bounded string. Never returns MAX/TEXT unless the
|
|
74
|
+
* observed string length genuinely can't be bounded.
|
|
75
|
+
*/
|
|
76
|
+
export function inferColumnTypeFromSamples(samples) {
|
|
77
|
+
const nonNull = samples.filter(v => v !== null && v !== undefined);
|
|
78
|
+
// No evidence → a safe, generous default string.
|
|
79
|
+
if (nonNull.length === 0)
|
|
80
|
+
return stringType(MIN_STRING_BOUND);
|
|
81
|
+
if (nonNull.every(isBoolean)) {
|
|
82
|
+
return { SchemaFieldType: 'boolean', SqlServerType: 'BIT', PostgresType: 'BOOLEAN', MaxLength: null };
|
|
83
|
+
}
|
|
84
|
+
if (nonNull.every(isFiniteNumber)) {
|
|
85
|
+
// Narrow to BIGINT only with an ADEQUATE all-integer sample (#A9). A small all-integer sample
|
|
86
|
+
// doesn't prove the field is always integral — a decimal in the unscanned tail would be silently
|
|
87
|
+
// rejected by BIGINT. Below the threshold, use wide fixed-point (which holds integers too).
|
|
88
|
+
const confidentInteger = nonNull.length >= MIN_SAMPLE_FOR_INTEGER_NARROW && nonNull.every(v => Number.isInteger(v));
|
|
89
|
+
return confidentInteger
|
|
90
|
+
? { SchemaFieldType: 'number', SqlServerType: 'BIGINT', PostgresType: 'BIGINT', MaxLength: null }
|
|
91
|
+
// Generous fixed-point — wide precision so we don't truncate or reject decimals.
|
|
92
|
+
: { SchemaFieldType: 'number', SqlServerType: 'DECIMAL(38,10)', PostgresType: 'DECIMAL(38,10)', MaxLength: null };
|
|
93
|
+
}
|
|
94
|
+
if (nonNull.every(isIsoDateString)) {
|
|
95
|
+
return { SchemaFieldType: 'datetime', SqlServerType: 'DATETIMEOFFSET', PostgresType: 'TIMESTAMPTZ', MaxLength: null };
|
|
96
|
+
}
|
|
97
|
+
// Default: a generously-bounded string sized to comfortably hold the longest observed value.
|
|
98
|
+
const longest = Math.max(...nonNull.map(v => String(v).length));
|
|
99
|
+
return stringType(generousStringBound(longest));
|
|
100
|
+
}
|
|
101
|
+
/** Builds a string {@link InferredColumnType}; bound===null ⇒ unbounded (MAX/TEXT). */
|
|
102
|
+
function stringType(bound) {
|
|
103
|
+
if (bound === null) {
|
|
104
|
+
return { SchemaFieldType: 'string', SqlServerType: 'NVARCHAR(MAX)', PostgresType: 'TEXT', MaxLength: null };
|
|
105
|
+
}
|
|
106
|
+
return { SchemaFieldType: 'string', SqlServerType: `NVARCHAR(${bound})`, PostgresType: `VARCHAR(${bound})`, MaxLength: bound };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Generous bound for a string column: double the longest observed length (room to grow),
|
|
110
|
+
* floored at {@link MIN_STRING_BOUND}; if that would exceed the bounded limit, fall back to
|
|
111
|
+
* unbounded (null → MAX/TEXT) since it genuinely can't be bounded safely.
|
|
112
|
+
*/
|
|
113
|
+
function generousStringBound(longestObserved) {
|
|
114
|
+
const doubled = Math.max(longestObserved * 2, MIN_STRING_BOUND);
|
|
115
|
+
return doubled > MAX_BOUNDED_STRING ? null : doubled;
|
|
116
|
+
}
|
|
117
|
+
function isBoolean(v) {
|
|
118
|
+
return typeof v === 'boolean';
|
|
119
|
+
}
|
|
120
|
+
function isFiniteNumber(v) {
|
|
121
|
+
return typeof v === 'number' && Number.isFinite(v);
|
|
122
|
+
}
|
|
123
|
+
function isIsoDateString(v) {
|
|
124
|
+
return typeof v === 'string' && ISO_DATE_RE.test(v) && !Number.isNaN(Date.parse(v));
|
|
125
|
+
}
|
|
126
|
+
function lowercaseSet(set) {
|
|
127
|
+
if (!set || set.size === 0)
|
|
128
|
+
return new Set();
|
|
129
|
+
return new Set([...set].map(s => s.toLowerCase()));
|
|
130
|
+
}
|
|
131
|
+
/** Max distinct sample values retained per key for type inference (bounded memory). */
|
|
132
|
+
const DEFAULT_SAMPLE_CAP = 20;
|
|
133
|
+
/**
|
|
134
|
+
* Builds per-key coverage statistics from a SAMPLE of rows that carried overflow JSON.
|
|
135
|
+
* Each row's overflow column is a JSON object string (what M1 parked); this tallies, per key,
|
|
136
|
+
* how many sampled rows had it non-null and collects a bounded sample of its values for type
|
|
137
|
+
* inference. Robust to malformed/empty JSON (such rows contribute to TotalRows but no keys).
|
|
138
|
+
*
|
|
139
|
+
* Coverage is therefore computed over the SAMPLE (bounded memory at any table size) — a
|
|
140
|
+
* statistically sound basis for the pervasiveness decision; the exactness the threshold needs
|
|
141
|
+
* (a key on ~half the rows vs. a junk key on one) survives sampling.
|
|
142
|
+
*
|
|
143
|
+
* @param overflowJsonStrings - the raw overflow-column value from each sampled row
|
|
144
|
+
* @param sampleCap - max values retained per key (default {@link DEFAULT_SAMPLE_CAP})
|
|
145
|
+
*/
|
|
146
|
+
export function buildOverflowStats(overflowJsonStrings, sampleCap = DEFAULT_SAMPLE_CAP) {
|
|
147
|
+
const byKey = new Map();
|
|
148
|
+
let totalRows = 0;
|
|
149
|
+
for (const raw of overflowJsonStrings) {
|
|
150
|
+
totalRows++;
|
|
151
|
+
const parsed = safeParseObject(raw);
|
|
152
|
+
if (!parsed)
|
|
153
|
+
continue;
|
|
154
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
155
|
+
if (value === null || value === undefined)
|
|
156
|
+
continue;
|
|
157
|
+
let entry = byKey.get(key);
|
|
158
|
+
if (!entry) {
|
|
159
|
+
entry = { occurrences: 0, samples: [] };
|
|
160
|
+
byKey.set(key, entry);
|
|
161
|
+
}
|
|
162
|
+
entry.occurrences++;
|
|
163
|
+
if (entry.samples.length < sampleCap)
|
|
164
|
+
entry.samples.push(value);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return [...byKey.entries()].map(([key, e]) => ({
|
|
168
|
+
Key: key,
|
|
169
|
+
Occurrences: e.occurrences,
|
|
170
|
+
TotalRows: totalRows,
|
|
171
|
+
SampleValues: e.samples,
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Sanitizes a source key into a safe SQL/MJ column identifier (letters, digits, underscore;
|
|
176
|
+
* never leading-digit; bounded length). The original key is kept as the field map's
|
|
177
|
+
* SourceFieldName; the sanitized form becomes the column + DestinationFieldName. Returns the
|
|
178
|
+
* BASE name only — collision resolution (suffixing) is the orchestrator's job since it needs
|
|
179
|
+
* the existing-column context.
|
|
180
|
+
*/
|
|
181
|
+
export function sanitizeColumnName(key) {
|
|
182
|
+
let name = key.replace(/[^A-Za-z0-9_]/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '');
|
|
183
|
+
if (name.length === 0)
|
|
184
|
+
name = 'Custom';
|
|
185
|
+
if (/^[0-9]/.test(name))
|
|
186
|
+
name = `c_${name}`;
|
|
187
|
+
return name.length > 120 ? name.slice(0, 120) : name;
|
|
188
|
+
}
|
|
189
|
+
function safeParseObject(raw) {
|
|
190
|
+
if (!raw || typeof raw !== 'string')
|
|
191
|
+
return null;
|
|
192
|
+
try {
|
|
193
|
+
const parsed = JSON.parse(raw);
|
|
194
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
195
|
+
? parsed
|
|
196
|
+
: null;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=CustomColumnPromotion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomColumnPromotion.js","sourceRoot":"","sources":["../src/CustomColumnPromotion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name of the per-record custom-overflow column. Written on every integration table
|
|
3
|
+
* alongside the other `__mj_integration_*` columns when present. Holds a JSON object of
|
|
4
|
+
* the source fields a record returned that have NO field map — the "extra" keys the
|
|
5
|
+
* target table doesn't (yet) have a column for.
|
|
6
|
+
*
|
|
7
|
+
* This is the capture half of framework-level custom-column support (gaps.md §2). A
|
|
8
|
+
* source with no schema/describe endpoint (the PropFuel class) can only learn its full
|
|
9
|
+
* field set by reading data; a static catalog then silently drops any extra key at
|
|
10
|
+
* {@link MapSingleRecord} (only mapped fields get persisted). Rather than lose them, the
|
|
11
|
+
* unmapped keys are parked here, on the row, in the SAME write as the mapped fields — so
|
|
12
|
+
* capture costs no extra round-trip. A post-sync Runtime-Schema-Updation (RSU) pass later
|
|
13
|
+
* reads this column back out and promotes pervasive keys to real columns (ADD COLUMN +
|
|
14
|
+
* CodeGen + a field map). It does NOT backfill historical values: once the field map exists
|
|
15
|
+
* the key is no longer "unmapped", so the NEXT sync maps it natively and populates the new
|
|
16
|
+
* column with the LIVE source value (a full sync repopulates every row; an incremental fills
|
|
17
|
+
* rows as they next change) — and stops re-capturing it here. The loop converges go-forward.
|
|
18
|
+
*
|
|
19
|
+
* Shape mirrors {@link CONTENT_HASH_COLUMN}: a JSON-serialized string sidecar, identical
|
|
20
|
+
* in kind to `__mj_integration_LastSyncedSnapshot`. SS `NVARCHAR(MAX)` / PG `TEXT`; the
|
|
21
|
+
* post-sync coverage scan + spread cast `::jsonb` on Postgres when they query it.
|
|
22
|
+
*
|
|
23
|
+
* This is BACKEND PLUMBING, not user-facing metadata. It is a SYSTEM field — in the same
|
|
24
|
+
* hidden/internal class as `__mj_integration_ContentHash` & the other `__mj_integration_*`
|
|
25
|
+
* columns: metadata-registered only so the engine's `entity.Set(...)`/`entity.Fields` write
|
|
26
|
+
* path is permitted to touch it (so it is NOT an out-of-band "phantom" column the engine
|
|
27
|
+
* writes blind), but NOT surfaced or managed through the metadata-driven framework — not in
|
|
28
|
+
* forms, not user-mappable, not "a field" anyone works with. It is machinery.
|
|
29
|
+
*
|
|
30
|
+
* The things that genuinely ENTER the metadata-driven framework are the columns this gets
|
|
31
|
+
* PROMOTED into: a pervasive key here is turned into a real user-facing, mappable EntityField
|
|
32
|
+
* (IntegrationSchemaSync IOF → RSU ADD COLUMN → CodeGen → md.Refresh) BEFORE the engine maps
|
|
33
|
+
* to it. So: backend staging until promotion, first-class metadata-driven schema after. Only
|
|
34
|
+
* the JSON *values* parked here are ever transient.
|
|
35
|
+
*
|
|
36
|
+
* Gated everywhere by EntityInfo field presence, so it is a no-op on tables that predate
|
|
37
|
+
* the column. CRUCIAL invariant: when a record has NO unmapped keys, NOTHING is written
|
|
38
|
+
* here — empty across all rows is the signal that no RSU pass is needed, which is what
|
|
39
|
+
* keeps a customs-free sync byte-identical to today (single-stage, zero overhead).
|
|
40
|
+
*/
|
|
41
|
+
export declare const CUSTOM_OVERFLOW_COLUMN = "__mj_integration_CustomOverflow";
|
|
42
|
+
/**
|
|
43
|
+
* Computes the unmapped subset of a record's external fields: every key the source
|
|
44
|
+
* returned that is NOT the SourceFieldName of any active field map.
|
|
45
|
+
*
|
|
46
|
+
* Pure + O(columns) — no per-row allocation beyond the result object, which is empty
|
|
47
|
+
* (and discarded by the caller) for the common no-customs case.
|
|
48
|
+
*
|
|
49
|
+
* Honest limit (documented in gaps.md §2): a field consumed only indirectly — e.g. as a
|
|
50
|
+
* `combine`/`custom` transform input rather than as a map's own SourceFieldName — will
|
|
51
|
+
* also appear here. That is harmless (the value is still in `Fields`); the post-sync
|
|
52
|
+
* promotion stage applies a coverage + novelty filter before it ever creates a column.
|
|
53
|
+
*
|
|
54
|
+
* @param externalFields - the full source record (`ExternalRecord.Fields`)
|
|
55
|
+
* @param mappedSourceFieldNames - SourceFieldName of every active field map
|
|
56
|
+
* @returns the extra keys + values, or an empty object when everything was mapped
|
|
57
|
+
*/
|
|
58
|
+
export declare function computeUnmappedFields(externalFields: Record<string, unknown>, mappedSourceFieldNames: ReadonlySet<string>): Record<string, unknown>;
|
|
59
|
+
/**
|
|
60
|
+
* Whether a computed unmapped-field object carries anything worth persisting. Used by
|
|
61
|
+
* both the per-record write gate and (later) the post-sync RSU trigger gate.
|
|
62
|
+
*/
|
|
63
|
+
export declare function hasUnmappedFields(unmapped: Record<string, unknown> | undefined | null): boolean;
|
|
64
|
+
//# sourceMappingURL=CustomOverflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomOverflow.d.ts","sourceRoot":"","sources":["../src/CustomOverflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,sBAAsB,oCAAoC,CAAC;AAExE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACjC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAAC,GAC5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAE/F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name of the per-record custom-overflow column. Written on every integration table
|
|
3
|
+
* alongside the other `__mj_integration_*` columns when present. Holds a JSON object of
|
|
4
|
+
* the source fields a record returned that have NO field map — the "extra" keys the
|
|
5
|
+
* target table doesn't (yet) have a column for.
|
|
6
|
+
*
|
|
7
|
+
* This is the capture half of framework-level custom-column support (gaps.md §2). A
|
|
8
|
+
* source with no schema/describe endpoint (the PropFuel class) can only learn its full
|
|
9
|
+
* field set by reading data; a static catalog then silently drops any extra key at
|
|
10
|
+
* {@link MapSingleRecord} (only mapped fields get persisted). Rather than lose them, the
|
|
11
|
+
* unmapped keys are parked here, on the row, in the SAME write as the mapped fields — so
|
|
12
|
+
* capture costs no extra round-trip. A post-sync Runtime-Schema-Updation (RSU) pass later
|
|
13
|
+
* reads this column back out and promotes pervasive keys to real columns (ADD COLUMN +
|
|
14
|
+
* CodeGen + a field map). It does NOT backfill historical values: once the field map exists
|
|
15
|
+
* the key is no longer "unmapped", so the NEXT sync maps it natively and populates the new
|
|
16
|
+
* column with the LIVE source value (a full sync repopulates every row; an incremental fills
|
|
17
|
+
* rows as they next change) — and stops re-capturing it here. The loop converges go-forward.
|
|
18
|
+
*
|
|
19
|
+
* Shape mirrors {@link CONTENT_HASH_COLUMN}: a JSON-serialized string sidecar, identical
|
|
20
|
+
* in kind to `__mj_integration_LastSyncedSnapshot`. SS `NVARCHAR(MAX)` / PG `TEXT`; the
|
|
21
|
+
* post-sync coverage scan + spread cast `::jsonb` on Postgres when they query it.
|
|
22
|
+
*
|
|
23
|
+
* This is BACKEND PLUMBING, not user-facing metadata. It is a SYSTEM field — in the same
|
|
24
|
+
* hidden/internal class as `__mj_integration_ContentHash` & the other `__mj_integration_*`
|
|
25
|
+
* columns: metadata-registered only so the engine's `entity.Set(...)`/`entity.Fields` write
|
|
26
|
+
* path is permitted to touch it (so it is NOT an out-of-band "phantom" column the engine
|
|
27
|
+
* writes blind), but NOT surfaced or managed through the metadata-driven framework — not in
|
|
28
|
+
* forms, not user-mappable, not "a field" anyone works with. It is machinery.
|
|
29
|
+
*
|
|
30
|
+
* The things that genuinely ENTER the metadata-driven framework are the columns this gets
|
|
31
|
+
* PROMOTED into: a pervasive key here is turned into a real user-facing, mappable EntityField
|
|
32
|
+
* (IntegrationSchemaSync IOF → RSU ADD COLUMN → CodeGen → md.Refresh) BEFORE the engine maps
|
|
33
|
+
* to it. So: backend staging until promotion, first-class metadata-driven schema after. Only
|
|
34
|
+
* the JSON *values* parked here are ever transient.
|
|
35
|
+
*
|
|
36
|
+
* Gated everywhere by EntityInfo field presence, so it is a no-op on tables that predate
|
|
37
|
+
* the column. CRUCIAL invariant: when a record has NO unmapped keys, NOTHING is written
|
|
38
|
+
* here — empty across all rows is the signal that no RSU pass is needed, which is what
|
|
39
|
+
* keeps a customs-free sync byte-identical to today (single-stage, zero overhead).
|
|
40
|
+
*/
|
|
41
|
+
export const CUSTOM_OVERFLOW_COLUMN = '__mj_integration_CustomOverflow';
|
|
42
|
+
/**
|
|
43
|
+
* Computes the unmapped subset of a record's external fields: every key the source
|
|
44
|
+
* returned that is NOT the SourceFieldName of any active field map.
|
|
45
|
+
*
|
|
46
|
+
* Pure + O(columns) — no per-row allocation beyond the result object, which is empty
|
|
47
|
+
* (and discarded by the caller) for the common no-customs case.
|
|
48
|
+
*
|
|
49
|
+
* Honest limit (documented in gaps.md §2): a field consumed only indirectly — e.g. as a
|
|
50
|
+
* `combine`/`custom` transform input rather than as a map's own SourceFieldName — will
|
|
51
|
+
* also appear here. That is harmless (the value is still in `Fields`); the post-sync
|
|
52
|
+
* promotion stage applies a coverage + novelty filter before it ever creates a column.
|
|
53
|
+
*
|
|
54
|
+
* @param externalFields - the full source record (`ExternalRecord.Fields`)
|
|
55
|
+
* @param mappedSourceFieldNames - SourceFieldName of every active field map
|
|
56
|
+
* @returns the extra keys + values, or an empty object when everything was mapped
|
|
57
|
+
*/
|
|
58
|
+
export function computeUnmappedFields(externalFields, mappedSourceFieldNames) {
|
|
59
|
+
const unmapped = {};
|
|
60
|
+
for (const key of Object.keys(externalFields)) {
|
|
61
|
+
if (!mappedSourceFieldNames.has(key)) {
|
|
62
|
+
unmapped[key] = externalFields[key];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return unmapped;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether a computed unmapped-field object carries anything worth persisting. Used by
|
|
69
|
+
* both the per-record write gate and (later) the post-sync RSU trigger gate.
|
|
70
|
+
*/
|
|
71
|
+
export function hasUnmappedFields(unmapped) {
|
|
72
|
+
return unmapped != null && Object.keys(unmapped).length > 0;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=CustomOverflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomOverflow.js","sourceRoot":"","sources":["../src/CustomOverflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,iCAAiC,CAAC;AAExE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB,CACjC,cAAuC,EACvC,sBAA2C;IAE3C,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,QAAQ,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAoD;IAClF,OAAO,QAAQ,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldMappingEngine.d.ts","sourceRoot":"","sources":["../src/FieldMappingEngine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FieldMappingEngine.d.ts","sourceRoot":"","sources":["../src/FieldMappingEngine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAe/D;;;GAGG;AACH,qBAAa,kBAAkB;IAC3B;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAwD;IAE5F;;;;;;;;OAQG;IACI,KAAK,CACR,OAAO,EAAE,cAAc,EAAE,EACzB,SAAS,EAAE,2BAA2B,EAAE,EACxC,UAAU,EAAE,MAAM,GACnB,YAAY,EAAE;IAKjB;;OAEG;IACH,OAAO,CAAC,eAAe;IAyCvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAMlB;;OAEG;IACH,OAAO,CAAC,UAAU;IAMlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAkBnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAcnB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAY7B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAQ5B"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { MJLruCache } from '@memberjunction/global';
|
|
2
|
+
import { computeUnmappedFields } from './CustomOverflow.js';
|
|
3
|
+
import { flattenRecord, hasNestedObject } from './RecordFlatten.js';
|
|
2
4
|
/**
|
|
3
5
|
* Engine responsible for applying field-level mappings and transformations
|
|
4
6
|
* from external records to MJ entity fields.
|
|
@@ -34,18 +36,35 @@ export class FieldMappingEngine {
|
|
|
34
36
|
* Maps a single external record through all active field mappings.
|
|
35
37
|
*/
|
|
36
38
|
MapSingleRecord(record, fieldMaps, entityName) {
|
|
39
|
+
// Flatten nested source objects to scalar columns (e.g. checkin_question.id →
|
|
40
|
+
// checkin_question_id) BEFORE mapping. The match keys on the mapped PK VALUE
|
|
41
|
+
// (MatchEngine.FindByKeyFields), so an object-valued source field would produce a
|
|
42
|
+
// per-occurrence / per-version key → duplicate rows. Discovery flattens identically, so
|
|
43
|
+
// the field maps reference the flattened scalar names. A record with no nested objects
|
|
44
|
+
// passes through unchanged — every flat-record connector is a no-op here.
|
|
45
|
+
const ext = hasNestedObject(record.Fields)
|
|
46
|
+
? { ...record, Fields: flattenRecord(record.Fields) }
|
|
47
|
+
: record;
|
|
37
48
|
const mappedFields = {};
|
|
49
|
+
const mappedSourceNames = new Set();
|
|
38
50
|
for (const fieldMap of fieldMaps) {
|
|
39
|
-
|
|
51
|
+
mappedSourceNames.add(fieldMap.SourceFieldName);
|
|
52
|
+
const value = this.ApplyFieldMapping(ext, fieldMap);
|
|
40
53
|
if (value !== undefined) {
|
|
41
54
|
mappedFields[fieldMap.DestinationFieldName] = value;
|
|
42
55
|
}
|
|
43
56
|
}
|
|
57
|
+
// Capture the source keys with no field map (gaps.md §2). Cheap O(columns) diff;
|
|
58
|
+
// the result is empty (and discarded by the writer) in the common all-mapped case,
|
|
59
|
+
// so this adds no measurable cost to a customs-free sync. The engine parks any extras
|
|
60
|
+
// in the __mj_integration_CustomOverflow system column — see {@link CustomOverflow}.
|
|
61
|
+
const unmappedFields = computeUnmappedFields(ext.Fields, mappedSourceNames);
|
|
44
62
|
return {
|
|
45
|
-
ExternalRecord:
|
|
63
|
+
ExternalRecord: ext,
|
|
46
64
|
MJEntityName: entityName,
|
|
47
65
|
MappedFields: mappedFields,
|
|
48
|
-
ChangeType:
|
|
66
|
+
ChangeType: ext.IsDeleted ? 'Delete' : 'Create',
|
|
67
|
+
UnmappedFields: unmappedFields,
|
|
49
68
|
};
|
|
50
69
|
}
|
|
51
70
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldMappingEngine.js","sourceRoot":"","sources":["../src/FieldMappingEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"FieldMappingEngine.js","sourceRoot":"","sources":["../src/FieldMappingEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,6 +38,13 @@ export interface ConnectorCreationPipelineOptions {
|
|
|
38
38
|
RunID?: string;
|
|
39
39
|
/** Trigger reason recorded in the manifest. */
|
|
40
40
|
TriggerType?: 'Manual' | 'Scheduled' | 'Webhook' | 'Pipeline' | 'Restart';
|
|
41
|
+
/**
|
|
42
|
+
* §7 — when true, this is a COMPREHENSIVE re-discovery: declared/discovered objects (and their
|
|
43
|
+
* fields) ABSENT from this run are deactivated (Status='Disabled', never deleted; reversible on a
|
|
44
|
+
* later rediscovery). Only set on a full-surface refresh — a scoped/partial discovery must leave it
|
|
45
|
+
* false so it never disables what it didn't look at. Threaded to PersistDiscoveredSchema.
|
|
46
|
+
*/
|
|
47
|
+
DeactivateAbsent?: boolean;
|
|
41
48
|
}
|
|
42
49
|
/** Outcome of a single pipeline invocation. */
|
|
43
50
|
export interface ConnectorCreationPipelineResult {
|
|
@@ -77,7 +84,33 @@ export interface ConnectorCreationPipelineResult {
|
|
|
77
84
|
* `__mj.Entity`. The pipeline emits `entity.skipped-no-pk` events for visibility.
|
|
78
85
|
*/
|
|
79
86
|
export declare class IntegrationConnectorCreationPipeline {
|
|
87
|
+
/** In-flight runs by CompanyIntegrationID — coalesces a concurrent duplicate onto the same promise. */
|
|
88
|
+
private static readonly inFlightRuns;
|
|
89
|
+
/** Just-completed runs by CompanyIntegrationID — coalesces a *sequential* duplicate within the window. */
|
|
90
|
+
private static readonly recentRuns;
|
|
91
|
+
/** Default coalesce window (ms) when the env override is unset/invalid. */
|
|
92
|
+
private static readonly DEFAULT_COALESCE_WINDOW_MS;
|
|
93
|
+
/**
|
|
94
|
+
* How long a just-completed run is reused for a duplicate invocation of the SAME CompanyIntegration.
|
|
95
|
+
* Sized only to absorb the create-time double-fire (the `IsActive` Save-hook runs the pipeline, then
|
|
96
|
+
* `IntegrationCreateConnection` calls it again milliseconds later) — short enough that a genuine,
|
|
97
|
+
* later operator-initiated re-refresh always runs fresh. Override via the
|
|
98
|
+
* `MJ_CONNECTOR_PIPELINE_COALESCE_WINDOW_MS` env var (a positive integer of milliseconds; set 0/unset
|
|
99
|
+
* to use the default). Env-based, matching the RSU env-var convention (RSU_WORK_DIR, etc.).
|
|
100
|
+
*/
|
|
101
|
+
private static get COALESCE_WINDOW_MS();
|
|
102
|
+
/**
|
|
103
|
+
* Public entry. De-dups the known create-time double-invocation: the connection's `IsActive`
|
|
104
|
+
* false→true Save fires the entity-server hook (which runs this pipeline WITH LLM PK inference),
|
|
105
|
+
* and the create resolver then calls it again. Both converge here, so we run the pipeline ONCE
|
|
106
|
+
* per CompanyIntegration and hand both callers the same result — no double introspect/persist/
|
|
107
|
+
* classify, no double live API calls, and the resolver still gets a real summary. A legitimate
|
|
108
|
+
* re-refresh later (outside the window) runs fresh.
|
|
109
|
+
*/
|
|
80
110
|
Run(opts: ConnectorCreationPipelineOptions): Promise<ConnectorCreationPipelineResult>;
|
|
111
|
+
/** Drops recent-run entries older than the coalesce window so the map stays bounded. */
|
|
112
|
+
private static pruneRecentRuns;
|
|
113
|
+
private runInternal;
|
|
81
114
|
private StageConnectionTest;
|
|
82
115
|
private StageIntrospect;
|
|
83
116
|
private StagePersist;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IntegrationConnectorCreationPipeline.d.ts","sourceRoot":"","sources":["../src/IntegrationConnectorCreationPipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,KAAK,EACR,0BAA0B,EAG7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEH,KAAK,sBAAsB,EAC9B,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAEH,KAAK,kBAAkB,EAC1B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"IntegrationConnectorCreationPipeline.d.ts","sourceRoot":"","sources":["../src/IntegrationConnectorCreationPipeline.ts"],"names":[],"mappings":"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"}
|