@memberjunction/core-entities-server 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.
- package/dist/custom/IntegrationLLMPKCallback.d.ts +30 -0
- package/dist/custom/IntegrationLLMPKCallback.d.ts.map +1 -0
- package/dist/custom/IntegrationLLMPKCallback.js +123 -0
- package/dist/custom/IntegrationLLMPKCallback.js.map +1 -0
- package/dist/custom/MJAIPromptRunEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIPromptRunEntityServer.server.js +14 -4
- package/dist/custom/MJAIPromptRunEntityServer.server.js.map +1 -1
- package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts +94 -0
- package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJCompanyIntegrationEntityServer.server.js +207 -0
- package/dist/custom/MJCompanyIntegrationEntityServer.server.js.map +1 -0
- package/dist/custom/MJEntityDocumentEntityServer.server.d.ts +69 -0
- package/dist/custom/MJEntityDocumentEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJEntityDocumentEntityServer.server.js +245 -0
- package/dist/custom/MJEntityDocumentEntityServer.server.js.map +1 -0
- package/dist/custom/MJQueryEntityServer.server.d.ts +8 -24
- package/dist/custom/MJQueryEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJQueryEntityServer.server.js +22 -109
- package/dist/custom/MJQueryEntityServer.server.js.map +1 -1
- package/dist/custom/query-extraction/parse.js +1 -1
- package/dist/custom/query-extraction/parse.js.map +1 -1
- package/dist/custom/query-extraction/pipeline.d.ts.map +1 -1
- package/dist/custom/query-extraction/pipeline.js +2 -1
- package/dist/custom/query-extraction/pipeline.js.map +1 -1
- package/dist/custom/query-extraction/resolve.d.ts +7 -6
- package/dist/custom/query-extraction/resolve.d.ts.map +1 -1
- package/dist/custom/query-extraction/resolve.js +18 -16
- package/dist/custom/query-extraction/resolve.js.map +1 -1
- package/dist/custom/query-extraction/sync.d.ts.map +1 -1
- package/dist/custom/query-extraction/sync.js +24 -14
- package/dist/custom/query-extraction/sync.js.map +1 -1
- package/dist/custom/query-extraction/types.d.ts +3 -2
- package/dist/custom/query-extraction/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +24 -22
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM PK inference callback used by SoftPKClassifier's LLM tier.
|
|
3
|
+
*
|
|
4
|
+
* The classifier cascade is:
|
|
5
|
+
* universal-convention → naming-heuristic → statistical → LLM → none
|
|
6
|
+
*
|
|
7
|
+
* When the deterministic tiers all yield no confident nominee, this callback
|
|
8
|
+
* gets called with the object name + field list (plus sample rows when
|
|
9
|
+
* available) and returns the LLM's best guess of a primary-key field. If
|
|
10
|
+
* the LLM also can't identify one, the verdict comes back `none` and the
|
|
11
|
+
* pipeline drops the IO (only for `MetadataSource='Discovered'`).
|
|
12
|
+
*
|
|
13
|
+
* Model selection: highest-priority active LanguageModel from AIEngine.
|
|
14
|
+
* API key: resolved via the central AIAPIKeys registry (no AI vendor key
|
|
15
|
+
* reading happens in this file — `GetAIAPIKeyGlobal` is the central
|
|
16
|
+
* server-side gate).
|
|
17
|
+
*
|
|
18
|
+
* If AIEngine has no active language model, or the model's driver can't be
|
|
19
|
+
* resolved, the callback returns a `nominee: null, confidence: 0`
|
|
20
|
+
* (skip-the-LLM-tier) result — never a fabricated PK.
|
|
21
|
+
*/
|
|
22
|
+
import { type UserInfo } from '@memberjunction/core';
|
|
23
|
+
import type { LLMOneShotCallback } from '@memberjunction/integration-pk-classifier';
|
|
24
|
+
/**
|
|
25
|
+
* Builds an `LLMOneShotCallback` that calls a server-side LLM to infer a PK.
|
|
26
|
+
* Returns `null` if AIEngine isn't loadable or no language model is active —
|
|
27
|
+
* pipeline silently skips the LLM tier in that case (verdict cascades to `none`).
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildIntegrationLLMPKCallback(contextUser: UserInfo): Promise<LLMOneShotCallback | null>;
|
|
30
|
+
//# sourceMappingURL=IntegrationLLMPKCallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntegrationLLMPKCallback.d.ts","sourceRoot":"","sources":["../../src/custom/IntegrationLLMPKCallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAK1E,OAAO,KAAK,EACR,kBAAkB,EAGrB,MAAM,2CAA2C,CAAC;AAEnD;;;;GAIG;AACH,wBAAsB,6BAA6B,CAC/C,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA0GpC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM PK inference callback used by SoftPKClassifier's LLM tier.
|
|
3
|
+
*
|
|
4
|
+
* The classifier cascade is:
|
|
5
|
+
* universal-convention → naming-heuristic → statistical → LLM → none
|
|
6
|
+
*
|
|
7
|
+
* When the deterministic tiers all yield no confident nominee, this callback
|
|
8
|
+
* gets called with the object name + field list (plus sample rows when
|
|
9
|
+
* available) and returns the LLM's best guess of a primary-key field. If
|
|
10
|
+
* the LLM also can't identify one, the verdict comes back `none` and the
|
|
11
|
+
* pipeline drops the IO (only for `MetadataSource='Discovered'`).
|
|
12
|
+
*
|
|
13
|
+
* Model selection: highest-priority active LanguageModel from AIEngine.
|
|
14
|
+
* API key: resolved via the central AIAPIKeys registry (no AI vendor key
|
|
15
|
+
* reading happens in this file — `GetAIAPIKeyGlobal` is the central
|
|
16
|
+
* server-side gate).
|
|
17
|
+
*
|
|
18
|
+
* If AIEngine has no active language model, or the model's driver can't be
|
|
19
|
+
* resolved, the callback returns a `nominee: null, confidence: 0`
|
|
20
|
+
* (skip-the-LLM-tier) result — never a fabricated PK.
|
|
21
|
+
*/
|
|
22
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
23
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
24
|
+
import { BaseLLM } from '@memberjunction/ai';
|
|
25
|
+
import { GetAIAPIKeyGlobal } from '@memberjunction/ai';
|
|
26
|
+
import { AIEngine } from '@memberjunction/aiengine';
|
|
27
|
+
/**
|
|
28
|
+
* Builds an `LLMOneShotCallback` that calls a server-side LLM to infer a PK.
|
|
29
|
+
* Returns `null` if AIEngine isn't loadable or no language model is active —
|
|
30
|
+
* pipeline silently skips the LLM tier in that case (verdict cascades to `none`).
|
|
31
|
+
*/
|
|
32
|
+
export async function buildIntegrationLLMPKCallback(contextUser) {
|
|
33
|
+
try {
|
|
34
|
+
await AIEngine.Instance.Config(false, contextUser);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
LogError(`[IntegrationLLMPKCallback] AIEngine.Config failed; LLM PK tier disabled: ${err instanceof Error ? err.message : err}`);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const models = AIEngine.Instance.LanguageModels.filter(m => m.IsActive === true);
|
|
41
|
+
if (models.length === 0) {
|
|
42
|
+
LogStatus(`[IntegrationLLMPKCallback] No active language model registered; LLM PK tier disabled.`);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
// Highest PowerRank wins (or first if rank not set). The classifier doesn't
|
|
46
|
+
// need a frontier model — a cheap, fast chat model is perfectly capable of
|
|
47
|
+
// "given these field names + types, which is the PK?" Sort descending so
|
|
48
|
+
// priority-marked models surface first.
|
|
49
|
+
const sorted = [...models].sort((a, b) => (b.PowerRank ?? 0) - (a.PowerRank ?? 0));
|
|
50
|
+
const model = sorted[0];
|
|
51
|
+
const driverClass = model.DriverClass;
|
|
52
|
+
const apiName = model.APINameOrName;
|
|
53
|
+
if (!driverClass) {
|
|
54
|
+
LogStatus(`[IntegrationLLMPKCallback] Selected model "${model.Name}" has no DriverClass; LLM PK tier disabled.`);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const apiKey = GetAIAPIKeyGlobal(driverClass);
|
|
58
|
+
if (!apiKey) {
|
|
59
|
+
LogStatus(`[IntegrationLLMPKCallback] No API key registered for driver "${driverClass}"; LLM PK tier disabled.`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const llm = MJGlobal.Instance.ClassFactory.CreateInstance(BaseLLM, driverClass, apiKey);
|
|
63
|
+
if (!llm) {
|
|
64
|
+
LogStatus(`[IntegrationLLMPKCallback] ClassFactory could not instantiate BaseLLM driver "${driverClass}"; LLM PK tier disabled.`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
LogStatus(`[IntegrationLLMPKCallback] LLM PK tier active using ${driverClass} / ${apiName}.`);
|
|
68
|
+
return async function llmPKInference(prompt) {
|
|
69
|
+
const systemMsg = `You are a database schema expert. Given a table's field list (and optional sample rows), ` +
|
|
70
|
+
`identify the single field most likely to be the primary key. ` +
|
|
71
|
+
`A primary key is unique, non-null, and immutable. ` +
|
|
72
|
+
`Common patterns: an "Id"/"<TableName>Id"/"UUID"/"GUID" field, ` +
|
|
73
|
+
`a system-generated identifier, or an int/long that's required + read-only + unique. ` +
|
|
74
|
+
`If no field plausibly qualifies (e.g. all fields are descriptive text, the table looks like a view or value list), ` +
|
|
75
|
+
`return nominee=null. NEVER guess a non-existent field name.`;
|
|
76
|
+
const userMsg = `Table: ${prompt.objectName}\n` +
|
|
77
|
+
`Fields (${prompt.fields.length}):\n` +
|
|
78
|
+
prompt.fields
|
|
79
|
+
.map(f => ` - ${f.name}` +
|
|
80
|
+
`${f.type ? ` (${f.type})` : ''}` +
|
|
81
|
+
`${f.length != null ? ` length=${f.length}` : ''}` +
|
|
82
|
+
`${f.isUnique ? ' UNIQUE' : ''}`)
|
|
83
|
+
.join('\n') +
|
|
84
|
+
(prompt.sampleSnippet
|
|
85
|
+
? `\n\nSample rows (JSON, may be truncated):\n${prompt.sampleSnippet}`
|
|
86
|
+
: '') +
|
|
87
|
+
`\n\nReturn STRICT JSON ONLY with this exact shape:\n` +
|
|
88
|
+
`{"nominee": "<field-name-or-null>", "confidence": <0..1>, "reason": "<one-line>"}`;
|
|
89
|
+
const params = {
|
|
90
|
+
model: apiName,
|
|
91
|
+
messages: [
|
|
92
|
+
{ role: 'system', content: systemMsg },
|
|
93
|
+
{ role: 'user', content: userMsg },
|
|
94
|
+
],
|
|
95
|
+
temperature: 0.1,
|
|
96
|
+
responseFormat: 'JSON',
|
|
97
|
+
};
|
|
98
|
+
try {
|
|
99
|
+
const result = await llm.ChatCompletion(params);
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
LogStatus(`[IntegrationLLMPKCallback] LLM call for "${prompt.objectName}" failed: ${result.errorMessage}`);
|
|
102
|
+
return { nominee: null, confidence: 0, reason: `LLM call failed: ${result.errorMessage ?? 'unknown'}` };
|
|
103
|
+
}
|
|
104
|
+
const content = result.data.choices?.[0]?.message?.content;
|
|
105
|
+
if (!content) {
|
|
106
|
+
return { nominee: null, confidence: 0, reason: 'LLM returned no content.' };
|
|
107
|
+
}
|
|
108
|
+
const parsed = JSON.parse(content);
|
|
109
|
+
const nominee = parsed.nominee && prompt.fields.some(f => f.name === parsed.nominee)
|
|
110
|
+
? parsed.nominee
|
|
111
|
+
: null;
|
|
112
|
+
const confidence = typeof parsed.confidence === 'number' ? Math.max(0, Math.min(1, parsed.confidence)) : 0;
|
|
113
|
+
const reason = typeof parsed.reason === 'string' ? parsed.reason : 'LLM verdict.';
|
|
114
|
+
return { nominee, confidence, reason };
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
118
|
+
LogStatus(`[IntegrationLLMPKCallback] LLM call threw for "${prompt.objectName}": ${msg}`);
|
|
119
|
+
return { nominee: null, confidence: 0, reason: `Exception during LLM inference: ${msg}` };
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=IntegrationLLMPKCallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntegrationLLMPKCallback.js","sourceRoot":"","sources":["../../src/custom/IntegrationLLMPKCallback.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJAIPromptRunEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAkD,MAAM,sBAAsB,CAAC;AAErH,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAG3E;;;;;;GAMG;AACH,qBACa,yBAA0B,SAAQ,2BAA2B;IAEtE;;OAEG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA6BlE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,OAAO;
|
|
1
|
+
{"version":3,"file":"MJAIPromptRunEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAkD,MAAM,sBAAsB,CAAC;AAErH,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAG3E;;;;;;GAMG;AACH,qBACa,yBAA0B,SAAQ,2BAA2B;IAEtE;;OAEG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA6BlE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,IAAI,OAAO;IAuCxC;;OAEG;cACa,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAqEpD;;OAEG;cACa,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBxD;;;;OAIG;IACU,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BlD;;;;OAIG;IACH,IAAW,cAAc,CAAC,KAAK,EAAE,MAAM,EAGtC;IAED,IAAW,cAAc,IAAI,MAAM,CAElC;IAED;;;;OAIG;IACH,IAAW,IAAI,CAAC,KAAK,EAAE,MAAM,EAG5B;IAED,IAAW,IAAI,IAAI,MAAM,CAExB;IACD;;;;;OAKG;IACH,SAAS,CAAC,eAAe,IAAI,IAAI;CAKpC"}
|
|
@@ -62,9 +62,13 @@ let MJAIPromptRunEntityServer = class MJAIPromptRunEntityServer extends MJAIProm
|
|
|
62
62
|
if (this.Cost != null && this.Cost > 0) {
|
|
63
63
|
return false;
|
|
64
64
|
}
|
|
65
|
-
// Must have token usage to calculate (at least one token
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
// Must have token usage to calculate (at least one input or output token > 0). Input is the
|
|
66
|
+
// TOTAL input the provider processed: net-new (TokensPrompt) + cache reads + cache writes.
|
|
67
|
+
// A heavily-cached call can have TokensPrompt === 0 yet still incur input cost via cache
|
|
68
|
+
// tokens, so we gate on the total rather than net-new alone.
|
|
69
|
+
const totalInputTokens = (this.TokensPrompt ?? 0) + (this.TokensCacheRead ?? 0) + (this.TokensCacheWrite ?? 0);
|
|
70
|
+
const totalCompletionTokens = this.TokensCompletion ?? 0;
|
|
71
|
+
if (totalInputTokens <= 0 && totalCompletionTokens <= 0) {
|
|
68
72
|
return false;
|
|
69
73
|
}
|
|
70
74
|
// Must have model and vendor information
|
|
@@ -99,7 +103,13 @@ let MJAIPromptRunEntityServer = class MJAIPromptRunEntityServer extends MJAIProm
|
|
|
99
103
|
LogError(`Failed to create price calculator for driver class: ${priceUnitType.DriverClass}`);
|
|
100
104
|
return;
|
|
101
105
|
}
|
|
102
|
-
|
|
106
|
+
// Price each input bucket at its own rate: uncached/net-new (TokensPrompt) at the
|
|
107
|
+
// standard input rate, cache reads/writes at CacheReadPricePerUnit/CacheWritePricePerUnit
|
|
108
|
+
// when the cost row records them. When those cache rates are NULL the calculator falls
|
|
109
|
+
// back to the input rate, so the result is identical to the prior single-bucket behavior
|
|
110
|
+
// for models without cache pricing — while models that DO have cache rates get the
|
|
111
|
+
// (usually much cheaper) cached-token cost instead of being billed as full input.
|
|
112
|
+
const normalizedCost = priceCalculator.CalculateNormalizedCostWithCache(activeCost, this.TokensPrompt ?? 0, this.TokensCacheRead ?? 0, this.TokensCacheWrite ?? 0, this.TokensCompletion ?? 0);
|
|
103
113
|
// Set the cost fields
|
|
104
114
|
this.Cost = normalizedCost;
|
|
105
115
|
this.CostCurrency = activeCost.Currency;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJAIPromptRunEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAqB,QAAQ,EAAwC,MAAM,sBAAsB,CAAC;AACrH,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEjF;;;;;;GAMG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,2BAA2B;IAEtE;;OAEG;IACM,KAAK,CAAC,IAAI,CAAC,OAA2B;QAC3C,IAAI,CAAC;YACD,sCAAsC;YACtC,MAAM,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAEvD,IAAI,mBAAmB,EAAE,CAAC;gBACtB,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACrC,CAAC;YAED,sEAAsE;YACtE,IAAI,CAAC,eAAe,EAAE,CAAC;YAEvB,gDAAgD;YAChD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEzC,0FAA0F;YAC1F,8CAA8C;YAC9C,IAAI,MAAM,IAAI,mBAAmB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;gBACtE,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;YACzC,CAAC;YAED,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,OAAO,GAAG,EAAE,CAAC;YACT,QAAQ,CAAC,4CAA4C,GAAG,EAAE,CAAC,CAAC;YAC5D,MAAM,GAAG,CAAC;QACd,CAAC;IACL,CAAC;IAED;;;OAGG;IACO,mBAAmB;QACzB,oDAAoD;QACpD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,wEAAwE;QACxE,yDAAyD;QACzD,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;QAC1D,MAAM,kBAAkB,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC;QAEpD,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,2CAA2C;QAC3C,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"MJAIPromptRunEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIPromptRunEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { EntitySaveOptions } from '@memberjunction/core';
|
|
2
|
+
import { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
|
|
3
|
+
/**
|
|
4
|
+
* Server-side extension of MJCompanyIntegrationEntity that:
|
|
5
|
+
*
|
|
6
|
+
* Awaits `IntegrationConnectorCreationPipeline.Run()` whenever `IsActive`
|
|
7
|
+
* transitions `false → true` on a successful save. This is the wizard-Finish
|
|
8
|
+
* trigger point — when an operator activates a connection (via the wizard,
|
|
9
|
+
* the Update mutation, direct entity edit, or any other code path that saves
|
|
10
|
+
* IsActive=true on a previously-inactive row), the pipeline runs:
|
|
11
|
+
*
|
|
12
|
+
* 1. TestConnection — verify credentials still pass
|
|
13
|
+
* 2. IntrospectSchema — live describe across all objects
|
|
14
|
+
* 3. PersistDiscoveredSchema — overlay-aware upsert (Declared/Discovered/Custom)
|
|
15
|
+
* 4. SoftPKClassifier — 4-tier cascade for IOs lacking explicit PK
|
|
16
|
+
* 5. Metadata.Refresh — engine cache picks up the new rows
|
|
17
|
+
*
|
|
18
|
+
* The pipeline emits structured JSON events to the MJAPI log via
|
|
19
|
+
* `IntegrationProgressEmitter` so operators can watch progress in real time:
|
|
20
|
+
* `tail -f /tmp/mjapi.log | grep '"event":"\(introspect\|persist\|pk\|entity\|stage\|run\)\.'`
|
|
21
|
+
*
|
|
22
|
+
* PER-RUN JSONL ARTIFACTS land at:
|
|
23
|
+
* `<cwd>/logs/integration-runs/<runID>/{manifest,progress,result}.json`
|
|
24
|
+
*
|
|
25
|
+
* SYNCHRONOUS EXECUTION. The pipeline now AWAITS so the wizard's Finish
|
|
26
|
+
* button (which does `ci.IsActive=true; ci.Save()`) stays in its "Saving..."
|
|
27
|
+
* state until the schema refresh completes. HubSpot ~130 objects × 8-way
|
|
28
|
+
* parallel describe lands ~10-30s; that becomes the wizard's perceived load
|
|
29
|
+
* time — which is the correct UX (the wizard is, in fact, updating).
|
|
30
|
+
*
|
|
31
|
+
* IDEMPOTENT BY DESIGN. The pipeline overlays existing rows; the transition
|
|
32
|
+
* guard (was-false → now-true) keeps repeat saves (renames, config tweaks)
|
|
33
|
+
* from re-firing.
|
|
34
|
+
*
|
|
35
|
+
* FAILURE ISOLATION. Pipeline failure does NOT undo the Save. Operator can
|
|
36
|
+
* re-run via the standalone `IntegrationRefreshConnectorSchema` GraphQL
|
|
37
|
+
* mutation if needed. The save still returns true even on pipeline failure.
|
|
38
|
+
*
|
|
39
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
40
|
+
* ALGORITHM GAPS — DEFERRED FOR FOLLOWUP PR (not Phase 0 PR1)
|
|
41
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
42
|
+
*
|
|
43
|
+
* Phase 0 ships the OVERLAY-ADD half of the algorithm: discovered fields
|
|
44
|
+
* the IO doesn't already know about get added with `MetadataSource='Discovered'`.
|
|
45
|
+
* The full canonical algorithm has more steps; (a) and (d) remain genuine
|
|
46
|
+
* follow-up deferrals because they require additional schema + UI wiring,
|
|
47
|
+
* while (b) is now IMPLEMENTED and (c) is largely mooted (see below):
|
|
48
|
+
*
|
|
49
|
+
* (a) DECLARED-BUT-MISSING-IN-INSTANCE → DEPRECATED. When the Declared
|
|
50
|
+
* catalog has a field for table X, but THIS customer's live introspect
|
|
51
|
+
* doesn't return that field, mark it deprecated FOR THIS COMPANY
|
|
52
|
+
* INTEGRATION only (other tenants still see Active). This is per-
|
|
53
|
+
* instance state — needs either a new junction (CompanyIntegration ×
|
|
54
|
+
* IntegrationObjectField with Status) or a Configuration JSON listing
|
|
55
|
+
* on CompanyIntegration. Currently NOT implemented: existing IOFs
|
|
56
|
+
* stay Active even when missing from the live instance.
|
|
57
|
+
*
|
|
58
|
+
* (b) AI PK INFERENCE for custom tables. IMPLEMENTED. When a Discovered
|
|
59
|
+
* table has no explicit PK marker, the SoftPKClassifier runs
|
|
60
|
+
* universal-convention → naming → statistical → LLM. The LLM tier's
|
|
61
|
+
* callback IS wired here: `buildIntegrationLLMPKCallback(user)` is built
|
|
62
|
+
* below and passed into the pipeline as `LLMInference`, so when explicit
|
|
63
|
+
* + naming + statistical all fail, an LLM proposes a (potentially
|
|
64
|
+
* composite) PK from the field schema + sample rows. (The callback can
|
|
65
|
+
* still return undefined if no AI model resolves, in which case the LLM
|
|
66
|
+
* tier degrades to a no-op — but the wiring itself is no longer a gap.)
|
|
67
|
+
*
|
|
68
|
+
* (c) DROP IF NO PK DETERMINABLE. Largely MOOTED. The original concern was
|
|
69
|
+
* that an IO ending with `Confident=false` would persist as a PK-less row
|
|
70
|
+
* polluting the catalog, so canonical behavior would DELETE it. With
|
|
71
|
+
* SoftPKClassifier's now-default synthetic-PK fallback, almost nothing
|
|
72
|
+
* reaches `Confident=false` — a synthetic identifier is emitted as the
|
|
73
|
+
* last resort — so the drop-if-no-PK path is rarely if ever exercised.
|
|
74
|
+
* Not implemented as an explicit delete, but no longer a practical gap.
|
|
75
|
+
*
|
|
76
|
+
* (d) DETAILED PROGRESS UI in the wizard. Today the wizard shows a
|
|
77
|
+
* generic "Saving..." spinner while the pipeline runs. Operators
|
|
78
|
+
* want plain-English step indicators ("Discovering tables...",
|
|
79
|
+
* "Analyzing 47 fields for Contacts...", "Inferring primary key
|
|
80
|
+
* for custom_quote_item..."). Needs an Angular wizard update +
|
|
81
|
+
* either SSE/WebSocket progress streaming or polling. Pre-existing
|
|
82
|
+
* Angular dashboards build issues on this branch block that work
|
|
83
|
+
* (out of Phase 0 PR scope).
|
|
84
|
+
*/
|
|
85
|
+
export declare class MJCompanyIntegrationEntityServer extends MJCompanyIntegrationEntity {
|
|
86
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* Resolves the registered connector for this CompanyIntegration, runs the
|
|
89
|
+
* Phase 0 v5.39.x pipeline, and refreshes the in-memory caches so the next
|
|
90
|
+
* read sees the newly-persisted IO/IOF rows.
|
|
91
|
+
*/
|
|
92
|
+
private fireSchemaRefreshPipeline;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=MJCompanyIntegrationEntityServer.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJCompanyIntegrationEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJCompanyIntegrationEntityServer.server.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,iBAAiB,EAOpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,0BAA0B,EAAuB,MAAM,+BAA+B,CAAC;AAQhG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AACH,qBACa,gCAAiC,SAAQ,0BAA0B;IACtD,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAiCzE;;;;OAIG;YACW,yBAAyB;CA0E1C"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
8
|
+
import { BaseEntity, LogError, LogStatus, Metadata, RunView, } from '@memberjunction/core';
|
|
9
|
+
import { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
|
|
10
|
+
import { IntegrationConnectorCreationPipeline, IntegrationEngine, ConnectorFactory, } from '@memberjunction/integration-engine';
|
|
11
|
+
import { buildIntegrationLLMPKCallback } from './IntegrationLLMPKCallback.js';
|
|
12
|
+
/**
|
|
13
|
+
* Server-side extension of MJCompanyIntegrationEntity that:
|
|
14
|
+
*
|
|
15
|
+
* Awaits `IntegrationConnectorCreationPipeline.Run()` whenever `IsActive`
|
|
16
|
+
* transitions `false → true` on a successful save. This is the wizard-Finish
|
|
17
|
+
* trigger point — when an operator activates a connection (via the wizard,
|
|
18
|
+
* the Update mutation, direct entity edit, or any other code path that saves
|
|
19
|
+
* IsActive=true on a previously-inactive row), the pipeline runs:
|
|
20
|
+
*
|
|
21
|
+
* 1. TestConnection — verify credentials still pass
|
|
22
|
+
* 2. IntrospectSchema — live describe across all objects
|
|
23
|
+
* 3. PersistDiscoveredSchema — overlay-aware upsert (Declared/Discovered/Custom)
|
|
24
|
+
* 4. SoftPKClassifier — 4-tier cascade for IOs lacking explicit PK
|
|
25
|
+
* 5. Metadata.Refresh — engine cache picks up the new rows
|
|
26
|
+
*
|
|
27
|
+
* The pipeline emits structured JSON events to the MJAPI log via
|
|
28
|
+
* `IntegrationProgressEmitter` so operators can watch progress in real time:
|
|
29
|
+
* `tail -f /tmp/mjapi.log | grep '"event":"\(introspect\|persist\|pk\|entity\|stage\|run\)\.'`
|
|
30
|
+
*
|
|
31
|
+
* PER-RUN JSONL ARTIFACTS land at:
|
|
32
|
+
* `<cwd>/logs/integration-runs/<runID>/{manifest,progress,result}.json`
|
|
33
|
+
*
|
|
34
|
+
* SYNCHRONOUS EXECUTION. The pipeline now AWAITS so the wizard's Finish
|
|
35
|
+
* button (which does `ci.IsActive=true; ci.Save()`) stays in its "Saving..."
|
|
36
|
+
* state until the schema refresh completes. HubSpot ~130 objects × 8-way
|
|
37
|
+
* parallel describe lands ~10-30s; that becomes the wizard's perceived load
|
|
38
|
+
* time — which is the correct UX (the wizard is, in fact, updating).
|
|
39
|
+
*
|
|
40
|
+
* IDEMPOTENT BY DESIGN. The pipeline overlays existing rows; the transition
|
|
41
|
+
* guard (was-false → now-true) keeps repeat saves (renames, config tweaks)
|
|
42
|
+
* from re-firing.
|
|
43
|
+
*
|
|
44
|
+
* FAILURE ISOLATION. Pipeline failure does NOT undo the Save. Operator can
|
|
45
|
+
* re-run via the standalone `IntegrationRefreshConnectorSchema` GraphQL
|
|
46
|
+
* mutation if needed. The save still returns true even on pipeline failure.
|
|
47
|
+
*
|
|
48
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
49
|
+
* ALGORITHM GAPS — DEFERRED FOR FOLLOWUP PR (not Phase 0 PR1)
|
|
50
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
51
|
+
*
|
|
52
|
+
* Phase 0 ships the OVERLAY-ADD half of the algorithm: discovered fields
|
|
53
|
+
* the IO doesn't already know about get added with `MetadataSource='Discovered'`.
|
|
54
|
+
* The full canonical algorithm has more steps; (a) and (d) remain genuine
|
|
55
|
+
* follow-up deferrals because they require additional schema + UI wiring,
|
|
56
|
+
* while (b) is now IMPLEMENTED and (c) is largely mooted (see below):
|
|
57
|
+
*
|
|
58
|
+
* (a) DECLARED-BUT-MISSING-IN-INSTANCE → DEPRECATED. When the Declared
|
|
59
|
+
* catalog has a field for table X, but THIS customer's live introspect
|
|
60
|
+
* doesn't return that field, mark it deprecated FOR THIS COMPANY
|
|
61
|
+
* INTEGRATION only (other tenants still see Active). This is per-
|
|
62
|
+
* instance state — needs either a new junction (CompanyIntegration ×
|
|
63
|
+
* IntegrationObjectField with Status) or a Configuration JSON listing
|
|
64
|
+
* on CompanyIntegration. Currently NOT implemented: existing IOFs
|
|
65
|
+
* stay Active even when missing from the live instance.
|
|
66
|
+
*
|
|
67
|
+
* (b) AI PK INFERENCE for custom tables. IMPLEMENTED. When a Discovered
|
|
68
|
+
* table has no explicit PK marker, the SoftPKClassifier runs
|
|
69
|
+
* universal-convention → naming → statistical → LLM. The LLM tier's
|
|
70
|
+
* callback IS wired here: `buildIntegrationLLMPKCallback(user)` is built
|
|
71
|
+
* below and passed into the pipeline as `LLMInference`, so when explicit
|
|
72
|
+
* + naming + statistical all fail, an LLM proposes a (potentially
|
|
73
|
+
* composite) PK from the field schema + sample rows. (The callback can
|
|
74
|
+
* still return undefined if no AI model resolves, in which case the LLM
|
|
75
|
+
* tier degrades to a no-op — but the wiring itself is no longer a gap.)
|
|
76
|
+
*
|
|
77
|
+
* (c) DROP IF NO PK DETERMINABLE. Largely MOOTED. The original concern was
|
|
78
|
+
* that an IO ending with `Confident=false` would persist as a PK-less row
|
|
79
|
+
* polluting the catalog, so canonical behavior would DELETE it. With
|
|
80
|
+
* SoftPKClassifier's now-default synthetic-PK fallback, almost nothing
|
|
81
|
+
* reaches `Confident=false` — a synthetic identifier is emitted as the
|
|
82
|
+
* last resort — so the drop-if-no-PK path is rarely if ever exercised.
|
|
83
|
+
* Not implemented as an explicit delete, but no longer a practical gap.
|
|
84
|
+
*
|
|
85
|
+
* (d) DETAILED PROGRESS UI in the wizard. Today the wizard shows a
|
|
86
|
+
* generic "Saving..." spinner while the pipeline runs. Operators
|
|
87
|
+
* want plain-English step indicators ("Discovering tables...",
|
|
88
|
+
* "Analyzing 47 fields for Contacts...", "Inferring primary key
|
|
89
|
+
* for custom_quote_item..."). Needs an Angular wizard update +
|
|
90
|
+
* either SSE/WebSocket progress streaming or polling. Pre-existing
|
|
91
|
+
* Angular dashboards build issues on this branch block that work
|
|
92
|
+
* (out of Phase 0 PR scope).
|
|
93
|
+
*/
|
|
94
|
+
let MJCompanyIntegrationEntityServer = class MJCompanyIntegrationEntityServer extends MJCompanyIntegrationEntity {
|
|
95
|
+
async Save(options) {
|
|
96
|
+
// Snapshot the pre-save IsActive value so we can detect the transition
|
|
97
|
+
// AFTER `super.Save()` returns successfully. When the row is new
|
|
98
|
+
// (`!this.IsSaved`), prior is `false` by default — the framework's
|
|
99
|
+
// IsActive defaults to false for new rows and the wizard explicitly
|
|
100
|
+
// flips it to true on Finish.
|
|
101
|
+
const priorIsActive = this.IsSaved
|
|
102
|
+
? !!this.GetFieldByName('IsActive').OldValue
|
|
103
|
+
: false;
|
|
104
|
+
const nowIsActive = !!this.IsActive;
|
|
105
|
+
const transitionedToActive = !priorIsActive && nowIsActive;
|
|
106
|
+
const saved = await super.Save(options);
|
|
107
|
+
if (!saved)
|
|
108
|
+
return false;
|
|
109
|
+
if (transitionedToActive) {
|
|
110
|
+
// AWAIT the pipeline — the wizard's Finish button stays in its
|
|
111
|
+
// "Saving…" state until the schema refresh completes, so the
|
|
112
|
+
// operator sees real visual feedback during the actual work
|
|
113
|
+
// instead of an instant fake-done. Pipeline failure is logged
|
|
114
|
+
// and surfaced via LatestResult but does NOT undo the activation
|
|
115
|
+
// — the connection is still saved; only the schema discovery
|
|
116
|
+
// failed and can be retried via IntegrationRefreshConnectorSchema.
|
|
117
|
+
try {
|
|
118
|
+
await this.fireSchemaRefreshPipeline();
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
LogError(`[MJCompanyIntegrationEntityServer] Schema refresh pipeline error (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Resolves the registered connector for this CompanyIntegration, runs the
|
|
128
|
+
* Phase 0 v5.39.x pipeline, and refreshes the in-memory caches so the next
|
|
129
|
+
* read sees the newly-persisted IO/IOF rows.
|
|
130
|
+
*/
|
|
131
|
+
async fireSchemaRefreshPipeline() {
|
|
132
|
+
const user = this.ContextCurrentUser;
|
|
133
|
+
if (!user) {
|
|
134
|
+
LogStatus(`[MJCompanyIntegrationEntityServer] Schema refresh skipped for ${this.ID}: no ContextCurrentUser on entity`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// `ProviderToUse` is typed `IEntityDataProvider`; the pipeline/engine APIs
|
|
138
|
+
// want the broader `IMetadataProvider`. The concrete server provider
|
|
139
|
+
// implements both, but the two interfaces don't structurally overlap, so a
|
|
140
|
+
// single `as` won't compile — narrow to `as IMetadataProvider` via unknown.
|
|
141
|
+
const provider = this.ProviderToUse;
|
|
142
|
+
LogStatus(`[MJCompanyIntegrationEntityServer] IsActive false→true detected on ${this.Integration ?? this.ID} (${this.ID}); firing schema refresh pipeline.`);
|
|
143
|
+
// Make sure the IntegrationEngine cache is hot so ConnectorFactory.Resolve
|
|
144
|
+
// can look up the registered class for this Integration.
|
|
145
|
+
await IntegrationEngine.Instance.Config(false, user, provider);
|
|
146
|
+
// Load the parent Integration row to feed ConnectorFactory.Resolve.
|
|
147
|
+
const rv = new RunView();
|
|
148
|
+
const integResult = await rv.RunView({
|
|
149
|
+
EntityName: 'MJ: Integrations',
|
|
150
|
+
ExtraFilter: `ID='${this.IntegrationID}'`,
|
|
151
|
+
ResultType: 'entity_object',
|
|
152
|
+
MaxRows: 1,
|
|
153
|
+
}, user);
|
|
154
|
+
const integration = integResult.Success ? integResult.Results[0] : undefined;
|
|
155
|
+
if (!integration) {
|
|
156
|
+
LogError(`[MJCompanyIntegrationEntityServer] Integration row not found for IntegrationID=${this.IntegrationID}; pipeline skipped.`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
let connector;
|
|
160
|
+
try {
|
|
161
|
+
connector = ConnectorFactory.Resolve(integration);
|
|
162
|
+
}
|
|
163
|
+
catch (resolveErr) {
|
|
164
|
+
LogError(`[MJCompanyIntegrationEntityServer] No connector registered for ClassName=${integration.ClassName}: ${resolveErr instanceof Error ? resolveErr.message : String(resolveErr)}`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Build the LLM PK callback so SoftPKClassifier's LLM tier can run
|
|
168
|
+
// (the 4th tier in the cascade — universal → naming → statistical → LLM
|
|
169
|
+
// → synthetic). Without this callback the LLM tier is silently skipped
|
|
170
|
+
// and any custom table without an obvious convention/heuristic match
|
|
171
|
+
// falls through to the synthetic-PK fallback (see StagePKClassify in
|
|
172
|
+
// IntegrationConnectorCreationPipeline.ts); wiring it gives such tables
|
|
173
|
+
// a chance at a more meaningful AI-proposed key first.
|
|
174
|
+
const llmInference = await buildIntegrationLLMPKCallback(user);
|
|
175
|
+
// The pipeline takes a fully-typed CompanyIntegration; this class extends
|
|
176
|
+
// MJCompanyIntegrationEntity, so `this` satisfies the contract directly.
|
|
177
|
+
const pipeline = new IntegrationConnectorCreationPipeline();
|
|
178
|
+
const result = await pipeline.Run({
|
|
179
|
+
Connector: connector,
|
|
180
|
+
CompanyIntegration: this,
|
|
181
|
+
ContextUser: user,
|
|
182
|
+
Provider: provider,
|
|
183
|
+
ConsoleMirror: true,
|
|
184
|
+
TriggerType: 'Manual',
|
|
185
|
+
LLMInference: llmInference ?? undefined,
|
|
186
|
+
});
|
|
187
|
+
// Pipeline persists IO/IOF rows — refresh metadata caches so subsequent
|
|
188
|
+
// reads see them without an MJAPI restart.
|
|
189
|
+
try {
|
|
190
|
+
await (provider ?? new Metadata()).Refresh();
|
|
191
|
+
}
|
|
192
|
+
catch { /* best-effort */ }
|
|
193
|
+
try {
|
|
194
|
+
await IntegrationEngine.Instance.Config(true, user, provider);
|
|
195
|
+
}
|
|
196
|
+
catch { /* best-effort */ }
|
|
197
|
+
LogStatus(`[MJCompanyIntegrationEntityServer] Schema refresh complete for ${this.Integration ?? this.ID}: ` +
|
|
198
|
+
`${result.PersistResult?.ObjectsCreated ?? 0} created, ${result.PersistResult?.ObjectsUpdated ?? 0} updated, ` +
|
|
199
|
+
`${result.PersistResult?.FieldsCreated ?? 0} fields created, ${result.PersistResult?.FieldsUpdated ?? 0} fields updated, ` +
|
|
200
|
+
`${result.UnresolvedObjects.length} IOs PK-unresolved (deferred for additionalSchemaInfo authoring).`);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
MJCompanyIntegrationEntityServer = __decorate([
|
|
204
|
+
RegisterClass(BaseEntity, 'MJ: Company Integrations')
|
|
205
|
+
], MJCompanyIntegrationEntityServer);
|
|
206
|
+
export { MJCompanyIntegrationEntityServer };
|
|
207
|
+
//# sourceMappingURL=MJCompanyIntegrationEntityServer.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJCompanyIntegrationEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJCompanyIntegrationEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { EntitySaveOptions, IMetadataProvider, TransactionGroupBase } from "@memberjunction/core";
|
|
2
|
+
import { MJEntityDocumentEntityExtended } from "@memberjunction/ai-core-plus";
|
|
3
|
+
import { MJTemplateEntity } from "@memberjunction/core-entities";
|
|
4
|
+
/**
|
|
5
|
+
* Server-side subclass for `MJ: Entity Documents` that mirrors the
|
|
6
|
+
* `MJAIPromptEntityServer` template-write pattern: when `TemplateText` (the
|
|
7
|
+
* virtual property on {@link MJEntityDocumentEntityExtended}) is set and the
|
|
8
|
+
* entity is saved, this class creates or updates the linked Template + primary
|
|
9
|
+
* TemplateContent records, then stamps the new `TemplateID` onto the
|
|
10
|
+
* EntityDocument before delegating to `super.Save()`.
|
|
11
|
+
*
|
|
12
|
+
* **Why this exists.** Per `mj-sync`, the `Template` virtual field on the
|
|
13
|
+
* `EntityDocument` view is read-only (a denormalized name from the FK), so a
|
|
14
|
+
* sync push can't write template body via the view. Surfacing a writable
|
|
15
|
+
* `TemplateText` virtual property plus this Save() hook is the same trick the
|
|
16
|
+
* AI Prompt entity uses, and it lets entity-document metadata files reference
|
|
17
|
+
* `@file:templates/foo.njk` exactly like prompts do.
|
|
18
|
+
*/
|
|
19
|
+
export declare class MJEntityDocumentEntityServer extends MJEntityDocumentEntityExtended {
|
|
20
|
+
private static _templateContentTypeID;
|
|
21
|
+
/**
|
|
22
|
+
* The TemplateContent.TypeID used for newly-created TemplateContents linked
|
|
23
|
+
* to an EntityDocument. Resolved once per process from the "Text" content
|
|
24
|
+
* type and cached. Settable up front if a host wants to force a different
|
|
25
|
+
* content type.
|
|
26
|
+
*/
|
|
27
|
+
static get TemplateContentTypeID(): string | null;
|
|
28
|
+
static set TemplateContentTypeID(value: string | null);
|
|
29
|
+
private static _rootTemplateCategoryID;
|
|
30
|
+
/**
|
|
31
|
+
* Root template-category ID used to host auto-created Templates for
|
|
32
|
+
* EntityDocuments. Resolved once per process by name lookup
|
|
33
|
+
* ("MJ: Entity Documents") and created on demand if missing.
|
|
34
|
+
*/
|
|
35
|
+
static get RootTemplateCategoryID(): string | null;
|
|
36
|
+
static set RootTemplateCategoryID(value: string | null);
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the root category for auto-created EntityDocument templates.
|
|
39
|
+
* Checks the in-memory cache first; falls back to a Name lookup; finally
|
|
40
|
+
* creates the category if it doesn't exist yet. Mirrors the AI Prompt
|
|
41
|
+
* pattern so existing operators recognize it.
|
|
42
|
+
*/
|
|
43
|
+
protected getOrCreateRootTemplateCategoryID(): Promise<string>;
|
|
44
|
+
/** Create the root template category when one doesn't exist yet. */
|
|
45
|
+
protected createRootTemplateCategory(name: string): Promise<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Save() override — same shape as `MJAIPromptEntityServer.Save()`:
|
|
48
|
+
*
|
|
49
|
+
* 1. If `TemplateID` is null and `TemplateText` is non-empty, create
|
|
50
|
+
* a new Template + TemplateContent and stamp the EntityDocument's
|
|
51
|
+
* `TemplateID`.
|
|
52
|
+
* 2. If `TemplateID` is set and `TemplateText` has changed, update the
|
|
53
|
+
* linked TemplateContent in place.
|
|
54
|
+
* 3. Then call `super.Save()` and, on success, sync
|
|
55
|
+
* `_originalTemplateText` so subsequent dirty-checks are accurate.
|
|
56
|
+
*
|
|
57
|
+
* Any failure in the template-write path short-circuits the save with a
|
|
58
|
+
* recorded `BaseEntityResult` so callers see the same failure shape they
|
|
59
|
+
* get from a base-entity validation error.
|
|
60
|
+
*/
|
|
61
|
+
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
62
|
+
/** Update the linked Template's primary TemplateContent in place. */
|
|
63
|
+
protected UpdateLinkedTemplateContents(md: IMetadataProvider, tg?: TransactionGroupBase): Promise<boolean>;
|
|
64
|
+
/** Create a new Template + primary TemplateContent linked to this EntityDocument. */
|
|
65
|
+
protected CreateLinkedTemplateAndTemplateContents(md: IMetadataProvider): Promise<MJTemplateEntity | null>;
|
|
66
|
+
/** Resolve the "Text" TemplateContentType ID once per process and cache it. */
|
|
67
|
+
protected getTemplateContentTypeID(): Promise<string>;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=MJEntityDocumentEntityServer.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJEntityDocumentEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJEntityDocumentEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,iBAAiB,EAAE,iBAAiB,EAAgC,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9J,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAkF,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjJ;;;;;;;;;;;;;;GAcG;AACH,qBACa,4BAA6B,SAAQ,8BAA8B;IAC5E,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAuB;IAC5D;;;;;OAKG;IACH,WAAkB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAEvD;IACD,WAAkB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAE3D;IAED,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAuB;IAC7D;;;;OAIG;IACH,WAAkB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAExD;IACD,WAAkB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAE5D;IAED;;;;;OAKG;cACa,iCAAiC,IAAI,OAAO,CAAC,MAAM,CAAC;IAuBpE,oEAAoE;cACpD,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBzE;;;;;;;;;;;;;;OAcG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAoClE,qEAAqE;cACrD,4BAA4B,CAAC,EAAE,EAAE,iBAAiB,EAAE,EAAE,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IAwChH,qFAAqF;cACrE,uCAAuC,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAoChH,+EAA+E;cAC/D,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC;CAgB9D"}
|