@memberjunction/core-entities-server 6.2.0-edge.3 → 6.2.0-edge.5
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/MJAIAgentSessionEntityServer.server.d.ts +47 -0
- package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJAIAgentSessionEntityServer.server.js +101 -0
- package/dist/custom/MJAIAgentSessionEntityServer.server.js.map +1 -0
- package/dist/custom/MJAIPromptRunEntityServer.server.d.ts +32 -1
- package/dist/custom/MJAIPromptRunEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIPromptRunEntityServer.server.js +96 -31
- package/dist/custom/MJAIPromptRunEntityServer.server.js.map +1 -1
- package/dist/custom/MJApplicationEntityServer.server.js +5 -3
- package/dist/custom/MJApplicationEntityServer.server.js.map +1 -1
- package/dist/custom/MJArtifactVersionEntityServer.server.js +2 -2
- package/dist/custom/MJArtifactVersionEntityServer.server.js.map +1 -1
- package/dist/custom/MJConversationDetailEntityServer.server.d.ts +16 -3
- package/dist/custom/MJConversationDetailEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJConversationDetailEntityServer.server.js +62 -5
- package/dist/custom/MJConversationDetailEntityServer.server.js.map +1 -1
- package/dist/custom/MJDataContextItemEntityServer.server.d.ts +33 -0
- package/dist/custom/MJDataContextItemEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJDataContextItemEntityServer.server.js +84 -0
- package/dist/custom/MJDataContextItemEntityServer.server.js.map +1 -0
- package/dist/custom/MJFileEntityServer.server.d.ts +45 -0
- package/dist/custom/MJFileEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJFileEntityServer.server.js +101 -0
- package/dist/custom/MJFileEntityServer.server.js.map +1 -0
- package/dist/custom/MJQueryEntityServer.server.d.ts +5 -1
- package/dist/custom/MJQueryEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJQueryEntityServer.server.js +11 -6
- package/dist/custom/MJQueryEntityServer.server.js.map +1 -1
- package/dist/custom/MJQuerySQLEntityServer.server.js +3 -3
- package/dist/custom/MJQuerySQLEntityServer.server.js.map +1 -1
- package/dist/custom/MJRowLevelSecurityFilterEntityServer.server.d.ts +26 -14
- package/dist/custom/MJRowLevelSecurityFilterEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJRowLevelSecurityFilterEntityServer.server.js +57 -32
- package/dist/custom/MJRowLevelSecurityFilterEntityServer.server.js.map +1 -1
- package/dist/custom/MJUserRoutineEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJUserRoutineEntityServer.server.js +12 -3
- package/dist/custom/MJUserRoutineEntityServer.server.js.map +1 -1
- package/dist/custom/MJUserViewEntityServer.server.d.ts +26 -0
- package/dist/custom/MJUserViewEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJUserViewEntityServer.server.js +74 -4
- package/dist/custom/MJUserViewEntityServer.server.js.map +1 -1
- package/dist/custom/MJVectorIndexEntityServer.server.d.ts +96 -7
- package/dist/custom/MJVectorIndexEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJVectorIndexEntityServer.server.js +276 -37
- package/dist/custom/MJVectorIndexEntityServer.server.js.map +1 -1
- package/dist/custom/query-extraction/pipeline.d.ts.map +1 -1
- package/dist/custom/query-extraction/pipeline.js +56 -5
- package/dist/custom/query-extraction/pipeline.js.map +1 -1
- package/dist/custom/query-extraction/types.d.ts +3 -0
- package/dist/custom/query-extraction/types.d.ts.map +1 -1
- package/dist/custom/rowFilterValidation.d.ts +47 -2
- package/dist/custom/rowFilterValidation.d.ts.map +1 -1
- package/dist/custom/rowFilterValidation.js +122 -11
- package/dist/custom/rowFilterValidation.js.map +1 -1
- package/dist/custom/rubrics/versionPublish.d.ts.map +1 -1
- package/dist/custom/rubrics/versionPublish.js +7 -5
- package/dist/custom/rubrics/versionPublish.js.map +1 -1
- package/dist/custom/sessionConfigGuard.d.ts +70 -0
- package/dist/custom/sessionConfigGuard.d.ts.map +1 -0
- package/dist/custom/sessionConfigGuard.js +125 -0
- package/dist/custom/sessionConfigGuard.js.map +1 -0
- package/dist/custom/template-extraction/pipeline.d.ts +6 -1
- package/dist/custom/template-extraction/pipeline.d.ts.map +1 -1
- package/dist/custom/template-extraction/pipeline.js +15 -6
- package/dist/custom/template-extraction/pipeline.js.map +1 -1
- package/dist/custom/template-extraction/types.d.ts +1 -1
- package/dist/custom/template-extraction/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +30 -30
|
@@ -4,10 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { BaseEntity } from '@memberjunction/core';
|
|
7
|
+
import { BaseEntity, DatabaseProviderBase } from '@memberjunction/core';
|
|
8
8
|
import { RegisterClass } from '@memberjunction/global';
|
|
9
9
|
import { MJRowLevelSecurityFilterEntity } from '@memberjunction/core-entities';
|
|
10
|
-
import { BuildSameEntityErrors, CollectRowFilterReferrers, ToValidationErrors, ValidateRowFilterTextAgainstEntity } from './rowFilterValidation.js';
|
|
10
|
+
import { BuildSameEntityErrors, CollectRowFilterReferrers, IsRoleOnlyReferrerSet, ToValidationErrors, ValidateRoleRowFilterText, ValidateRowFilterTextAgainstEntity } from './rowFilterValidation.js';
|
|
11
11
|
/**
|
|
12
12
|
* Server-side `MJ: Row Level Security Filters` entity — the SECOND enforcement
|
|
13
13
|
* point of the row-filter validation (plan §5.3). The scope-rule subclasses
|
|
@@ -15,21 +15,26 @@ import { BuildSameEntityErrors, CollectRowFilterReferrers, ToValidationErrors, V
|
|
|
15
15
|
* against the rule's entity when the RULE is saved; without an equivalent
|
|
16
16
|
* check when the FILTER is saved, both are trivially bypassable: attach a
|
|
17
17
|
* valid filter, then edit its text (or acquire a new, different-entity
|
|
18
|
-
* referrer) to reference anything. On a `FilterText` change
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* (fail closed). Check 6 has no single rule to anchor on here (a filter
|
|
24
|
-
* record itself carries no entity binding — see plan §5.1), so it anchors on
|
|
25
|
-
* the first referrer that DOES resolve to an entity and requires every other
|
|
26
|
-
* referrer to agree with it; zero or one resolvable referrer trivially
|
|
27
|
-
* satisfies the invariant.
|
|
18
|
+
* referrer) to reference anything. On a `FilterText` change this subclass
|
|
19
|
+
* re-validates the new text against EVERY current referrer (EntityPermission
|
|
20
|
+
* rows via their four `*RLSFilterID` columns, plus both API scope tables via
|
|
21
|
+
* `RowFilterID`) and rejects if any check fails — including referrers whose
|
|
22
|
+
* entity cannot be resolved (fail closed).
|
|
28
23
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
24
|
+
* Which checks apply depends on who references the filter:
|
|
25
|
+
* - **Any API-key or API-application scope rule** → the strict API-key rules
|
|
26
|
+
* (checks 4 and 6): plain columns of the referrer's entity only, and every
|
|
27
|
+
* referrer must agree on ONE entity. Check 6 has no single rule to anchor on
|
|
28
|
+
* here (a filter record carries no entity binding — see plan §5.1), so it
|
|
29
|
+
* anchors on the first referrer that resolves to an entity.
|
|
30
|
+
* - **Only role permission rows** → a role filter. Role filters legitimately use
|
|
31
|
+
* subqueries (a user's tenant memberships) and are shared across every
|
|
32
|
+
* tenant-scoped entity, so the new text is instead screened for dangerous SQL
|
|
33
|
+
* and compiled against each referencing entity's base view.
|
|
34
|
+
*
|
|
35
|
+
* Either way an invalid filter is rejected at save, where it is diagnosable,
|
|
36
|
+
* rather than failing every read of the entities it scopes with an unexplained
|
|
37
|
+
* SQL error.
|
|
33
38
|
*/
|
|
34
39
|
let MJRowLevelSecurityFilterEntityServer = class MJRowLevelSecurityFilterEntityServer extends MJRowLevelSecurityFilterEntity {
|
|
35
40
|
/** Enable async validation so the referrer re-validation (which queries three tables) runs on Save. */
|
|
@@ -39,7 +44,7 @@ let MJRowLevelSecurityFilterEntityServer = class MJRowLevelSecurityFilterEntityS
|
|
|
39
44
|
async ValidateAsync() {
|
|
40
45
|
const result = await super.ValidateAsync();
|
|
41
46
|
// Only re-validate when the text changes (or on create — a new filter has
|
|
42
|
-
// no referrers yet, so
|
|
47
|
+
// no referrers yet, so there is nothing to validate against).
|
|
43
48
|
const filterTextDirty = this.GetFieldByName('FilterText')?.Dirty ?? false;
|
|
44
49
|
if (this.IsSaved && !filterTextDirty) {
|
|
45
50
|
return result;
|
|
@@ -49,22 +54,11 @@ let MJRowLevelSecurityFilterEntityServer = class MJRowLevelSecurityFilterEntityS
|
|
|
49
54
|
const filterText = this.FilterText ?? '';
|
|
50
55
|
try {
|
|
51
56
|
const referrers = await CollectRowFilterReferrers(this.ID, md, this.ContextCurrentUser);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!referrer.Entity) {
|
|
55
|
-
errors.push(`${referrer.Description} references this filter but does not resolve to an entity — the new ` +
|
|
56
|
-
`FilterText cannot be validated against it; rejecting (fail closed).`);
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const validation = ValidateRowFilterTextAgainstEntity(filterText, referrer.Entity);
|
|
60
|
-
errors.push(...validation.errors.map(e => `${referrer.Description}: ${e}`));
|
|
57
|
+
if (IsRoleOnlyReferrerSet(referrers)) {
|
|
58
|
+
errors.push(...await this.validateAsRoleFilter(filterText, referrers));
|
|
61
59
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// referrer that resolves to an entity and require every other referrer to match it.
|
|
65
|
-
const anchor = referrers.find(r => r.Entity)?.Entity;
|
|
66
|
-
if (anchor) {
|
|
67
|
-
errors.push(...BuildSameEntityErrors(referrers, anchor));
|
|
60
|
+
else {
|
|
61
|
+
errors.push(...this.validateAsApiKeyFilter(filterText, referrers));
|
|
68
62
|
}
|
|
69
63
|
}
|
|
70
64
|
catch (e) {
|
|
@@ -76,6 +70,37 @@ let MJRowLevelSecurityFilterEntityServer = class MJRowLevelSecurityFilterEntityS
|
|
|
76
70
|
}
|
|
77
71
|
return result;
|
|
78
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* The strict API-key rules: check 4 (FilterText's columns must resolve against every
|
|
75
|
+
* referrer's entity) and check 6 (every referrer must agree on the same entity).
|
|
76
|
+
*/
|
|
77
|
+
validateAsApiKeyFilter(filterText, referrers) {
|
|
78
|
+
const errors = [];
|
|
79
|
+
for (const referrer of referrers) {
|
|
80
|
+
if (!referrer.Entity) {
|
|
81
|
+
errors.push(`${referrer.Description} references this filter but does not resolve to an entity — the new ` +
|
|
82
|
+
`FilterText cannot be validated against it; rejecting (fail closed).`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const validation = ValidateRowFilterTextAgainstEntity(filterText, referrer.Entity);
|
|
86
|
+
errors.push(...validation.errors.map(e => `${referrer.Description}: ${e}`));
|
|
87
|
+
}
|
|
88
|
+
// No single referrer is "the rule" here (unlike the scope-rule save path), so anchor on
|
|
89
|
+
// the first referrer that resolves to an entity and require every other referrer to match it.
|
|
90
|
+
const anchor = referrers.find(r => r.Entity)?.Entity;
|
|
91
|
+
if (anchor) {
|
|
92
|
+
errors.push(...BuildSameEntityErrors(referrers, anchor));
|
|
93
|
+
}
|
|
94
|
+
return errors;
|
|
95
|
+
}
|
|
96
|
+
/** A role filter: screened, then compiled against every referencing entity's base view. */
|
|
97
|
+
async validateAsRoleFilter(filterText, referrers) {
|
|
98
|
+
const provider = this.ProviderToUse;
|
|
99
|
+
if (!(provider instanceof DatabaseProviderBase)) {
|
|
100
|
+
return ['A role row-level-security filter can only be validated against a database provider; rejecting (fail closed).'];
|
|
101
|
+
}
|
|
102
|
+
return ValidateRoleRowFilterText(filterText, referrers, provider, this.ContextCurrentUser);
|
|
103
|
+
}
|
|
79
104
|
};
|
|
80
105
|
MJRowLevelSecurityFilterEntityServer = __decorate([
|
|
81
106
|
RegisterClass(BaseEntity, 'MJ: Row Level Security Filters')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJRowLevelSecurityFilterEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJRowLevelSecurityFilterEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAuC,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"MJRowLevelSecurityFilterEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJRowLevelSecurityFilterEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAuC,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EAErB,kBAAkB,EAClB,yBAAyB,EACzB,kCAAkC,EACrC,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEI,IAAM,oCAAoC,GAA1C,MAAM,oCAAqC,SAAQ,8BAA8B;IACpF,uGAAuG;IACvG,IAAoB,0BAA0B;QAC1C,OAAO,KAAK,CAAC;IACjB,CAAC;IAEe,KAAK,CAAC,aAAa;QAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC;QAE3C,0EAA0E;QAC1E,8DAA8D;QAC9D,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC;QAC1E,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;YACnC,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,aAA6C,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QAEzC,IAAI,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,yBAAyB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;YACxF,IAAI,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;YAC3E,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;YACvE,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;YAChE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QAC3B,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;OAGG;IACK,sBAAsB,CAAC,UAAkB,EAAE,SAA8B;QAC7E,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC/B,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,CACP,GAAG,QAAQ,CAAC,WAAW,sEAAsE;oBAC7F,qEAAqE,CACxE,CAAC;gBACF,SAAS;YACb,CAAC;YACD,MAAM,UAAU,GAAG,kCAAkC,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnF,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAChF,CAAC;QAED,wFAAwF;QACxF,8FAA8F;QAC9F,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACrD,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,2FAA2F;IACnF,KAAK,CAAC,oBAAoB,CAAC,UAAkB,EAAE,SAA8B;QACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC;QACpC,IAAI,CAAC,CAAC,QAAQ,YAAY,oBAAoB,CAAC,EAAE,CAAC;YAC9C,OAAO,CAAC,8GAA8G,CAAC,CAAC;QAC5H,CAAC;QACD,OAAO,yBAAyB,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/F,CAAC;CACJ,CAAA;AAzEY,oCAAoC;IADhD,aAAa,CAAC,UAAU,EAAE,gCAAgC,CAAC;GAC/C,oCAAoC,CAyEhD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJUserRoutineEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJUserRoutineEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,mBAAmB,EAAE,iBAAiB,EAAqD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE/J,OAAO,EAAE,mBAAmB,EAAwD,MAAM,+BAA+B,CAAC;AAG1H;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,yBAA0B,SAAQ,mBAAmB;IACxC,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzD,QAAQ,IAAI,gBAAgB;IAS5C;;;;;;OAMG;IACmB,MAAM,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ7E,uIAAuI;YACzH,gBAAgB;IAqB9B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;
|
|
1
|
+
{"version":3,"file":"MJUserRoutineEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJUserRoutineEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,mBAAmB,EAAE,iBAAiB,EAAqD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE/J,OAAO,EAAE,mBAAmB,EAAwD,MAAM,+BAA+B,CAAC;AAG1H;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,yBAA0B,SAAQ,mBAAmB;IACxC,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzD,QAAQ,IAAI,gBAAgB;IAS5C;;;;;;OAMG;IACmB,MAAM,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ7E,uIAAuI;YACzH,gBAAgB;IAqB9B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IA8B9B,4GAA4G;IAC5G,OAAO,CAAC,gBAAgB;IAmCxB,oFAAoF;IACpF,OAAO,CAAC,cAAc;IAWtB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAe5B"}
|
|
@@ -95,13 +95,13 @@ let MJUserRoutineEntityServer = class MJUserRoutineEntityServer extends MJUserRo
|
|
|
95
95
|
if (explicitlySet) {
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
|
-
const scheduleChanged = ['CronExpression', 'Timezone', 'StartAt']
|
|
98
|
+
const scheduleChanged = ['CronExpression', 'Timezone', 'StartAt', 'ScheduleMode']
|
|
99
99
|
.some(fieldName => this.GetFieldByName(fieldName)?.Dirty === true);
|
|
100
100
|
if (this.NextRunAt != null && !scheduleChanged) {
|
|
101
101
|
return;
|
|
102
102
|
}
|
|
103
103
|
try {
|
|
104
|
-
this.NextRunAt = ComputeRoutineNextRunAt(this.CronExpression, this.Timezone, new Date(), this.StartAt);
|
|
104
|
+
this.NextRunAt = ComputeRoutineNextRunAt(this.CronExpression, this.Timezone, new Date(), this.StartAt, this.ScheduleMode ?? 'Recurring');
|
|
105
105
|
}
|
|
106
106
|
catch {
|
|
107
107
|
// Invalid cron/timezone — leave NextRunAt untouched; Validate() reports the
|
|
@@ -110,13 +110,22 @@ let MJUserRoutineEntityServer = class MJUserRoutineEntityServer extends MJUserRo
|
|
|
110
110
|
}
|
|
111
111
|
/** Reject invalid cron expressions and cron/timezone combinations that cannot compute a next occurrence. */
|
|
112
112
|
validateSchedule(result) {
|
|
113
|
+
const mode = this.ScheduleMode ?? 'Recurring';
|
|
114
|
+
const hasCron = this.CronExpression != null && this.CronExpression.trim().length > 0;
|
|
115
|
+
if (!hasCron) {
|
|
116
|
+
if (mode === 'OneShot' || (mode === 'Adaptive' && this.RoutineType === 'AgentWake')) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
result.Errors.push(new ValidationErrorInfo('CronExpression', `CronExpression is required when ScheduleMode is '${mode}'.`, this.CronExpression, ValidationErrorType.Failure));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
113
122
|
const cronResult = CronExpressionHelper.ValidateExpression(this.CronExpression);
|
|
114
123
|
if (!cronResult.Success) {
|
|
115
124
|
result.Errors.push(...cronResult.Errors);
|
|
116
125
|
return;
|
|
117
126
|
}
|
|
118
127
|
try {
|
|
119
|
-
ComputeRoutineNextRunAt(this.CronExpression, this.Timezone, new Date(), this.StartAt);
|
|
128
|
+
ComputeRoutineNextRunAt(this.CronExpression, this.Timezone, new Date(), this.StartAt, mode);
|
|
120
129
|
}
|
|
121
130
|
catch (error) {
|
|
122
131
|
result.Errors.push(new ValidationErrorInfo('CronExpression', `Cannot compute a next run time from CronExpression '${this.CronExpression}' with Timezone '${this.Timezone}': ` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJUserRoutineEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJUserRoutineEntityServer.server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"MJUserRoutineEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJUserRoutineEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,32 @@ export declare class MJUserViewEntityServer extends MJUserViewEntityExtended {
|
|
|
19
19
|
*/
|
|
20
20
|
protected get SmartFilterImplemented(): boolean;
|
|
21
21
|
Validate(): ValidationResult;
|
|
22
|
+
/**
|
|
23
|
+
* SECURITY: screens the SQL this view stores with the clause screen the RunView API applies to
|
|
24
|
+
* client filters — its WhereClause (set directly, compiled from FilterState, or made by a Smart
|
|
25
|
+
* Filter) and the ORDER BY built from SortState / GridState. Any user who can save a view can
|
|
26
|
+
* write these, and the provider splices them into view SQL. A CustomWhereClause is left to the
|
|
27
|
+
* Owner gate above. Only a new view or a changed clause is screened here; the provider screens
|
|
28
|
+
* every stored clause again when the view runs. Both use the provider's own screen, so a clause
|
|
29
|
+
* is judged the same way at save and at run.
|
|
30
|
+
*/
|
|
31
|
+
private validateStoredClauses;
|
|
32
|
+
/**
|
|
33
|
+
* The ORDER BY built from SortState / GridState, or null when SortState is not valid JSON. Such
|
|
34
|
+
* a view cannot build an ORDER BY when it runs either, so there is nothing to screen.
|
|
35
|
+
*/
|
|
36
|
+
private storedOrderBy;
|
|
37
|
+
/**
|
|
38
|
+
* Adds a validation failure on `field` when the provider's client-clause screen refuses `clause`,
|
|
39
|
+
* or when the provider cannot screen (fails closed).
|
|
40
|
+
*/
|
|
41
|
+
private screenStoredClause;
|
|
42
|
+
/**
|
|
43
|
+
* A `{%UserView "id"%}` template becomes a subquery only when the view runs, and the provider
|
|
44
|
+
* screens that rendered clause. Here each template stands in as `SELECT NULL` so the rest of
|
|
45
|
+
* the clause can be parsed.
|
|
46
|
+
*/
|
|
47
|
+
private static neutralizeViewTemplates;
|
|
22
48
|
/**
|
|
23
49
|
* SECURITY gate: `CustomWhereClause = 1` tells the platform to fold the stored
|
|
24
50
|
* `WhereClause` into view SQL verbatim — it bypasses both the auto-generation in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJUserViewEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJUserViewEntityServer.server.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,UAAU,EAAY,iBAAiB,EAAsD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACjK,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"MJUserViewEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJUserViewEntityServer.server.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,UAAU,EAAY,iBAAiB,EAAsD,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACjK,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAexE;;GAEG;AACH,UAAU,uBAAwB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC7B;AAED,qBACa,sBAAuB,SAAQ,wBAAwB;IAChE;;OAEG;IACH,cAAuB,sBAAsB,IAAI,OAAO,CAEvD;IAEe,QAAQ,IAAI,gBAAgB;IAQ5C;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAQrB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAItC;;;;;;;;OAQG;IACH,OAAO,CAAC,sCAAsC;IAyB9C;;;;OAIG;IACU,8BAA8B,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAC,CAAC;IAkF5I;;;OAGG;IACH,SAAS,CAAC,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,uBAAuB;IAwC5E;;OAEG;IACH,SAAS,CAAC,4BAA4B,CAAC,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM;CAoC1H"}
|
|
@@ -4,13 +4,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
+
var MJUserViewEntityServer_1;
|
|
7
8
|
import { RegisterClass, CleanAndParseJSON } from "@memberjunction/global";
|
|
8
9
|
import { BaseEntity, LogError, ValidationErrorInfo, ValidationErrorType } from "@memberjunction/core";
|
|
9
10
|
import { MJUserViewEntityExtended } from '@memberjunction/core-entities';
|
|
10
11
|
import { AIPromptParams } from "@memberjunction/ai-core-plus";
|
|
11
12
|
import { AIEngine } from "@memberjunction/aiengine";
|
|
12
13
|
import { AIPromptRunner } from "@memberjunction/ai-prompts";
|
|
13
|
-
|
|
14
|
+
import { IsClientClauseScreeningProvider } from "@memberjunction/generic-database-provider";
|
|
15
|
+
let MJUserViewEntityServer = MJUserViewEntityServer_1 = class MJUserViewEntityServer extends MJUserViewEntityExtended {
|
|
14
16
|
/**
|
|
15
17
|
* This property is hard-coded to true in this class because we DO support smart filters in this class. If you want to disable smart filters for a specific view you can override this property in your subclass and set it to false.
|
|
16
18
|
*/
|
|
@@ -20,9 +22,76 @@ let MJUserViewEntityServer = class MJUserViewEntityServer extends MJUserViewEnti
|
|
|
20
22
|
Validate() {
|
|
21
23
|
const result = super.Validate();
|
|
22
24
|
this.validateCustomWhereClauseAuthorization(result);
|
|
25
|
+
this.validateStoredClauses(result);
|
|
23
26
|
result.Success = result.Success && result.Errors.length === 0;
|
|
24
27
|
return result;
|
|
25
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* SECURITY: screens the SQL this view stores with the clause screen the RunView API applies to
|
|
31
|
+
* client filters — its WhereClause (set directly, compiled from FilterState, or made by a Smart
|
|
32
|
+
* Filter) and the ORDER BY built from SortState / GridState. Any user who can save a view can
|
|
33
|
+
* write these, and the provider splices them into view SQL. A CustomWhereClause is left to the
|
|
34
|
+
* Owner gate above. Only a new view or a changed clause is screened here; the provider screens
|
|
35
|
+
* every stored clause again when the view runs. Both use the provider's own screen, so a clause
|
|
36
|
+
* is judged the same way at save and at run.
|
|
37
|
+
*/
|
|
38
|
+
validateStoredClauses(result) {
|
|
39
|
+
const changed = (...fields) => !this.IsSaved || fields.some(f => this.GetFieldByName(f)?.Dirty === true);
|
|
40
|
+
if (!this.CustomWhereClause && changed('WhereClause', 'CustomWhereClause')) {
|
|
41
|
+
const where = MJUserViewEntityServer_1.neutralizeViewTemplates(this.WhereClause ?? '');
|
|
42
|
+
this.screenStoredClause(result, 'WhereClause', where, 'view WhereClause');
|
|
43
|
+
}
|
|
44
|
+
const orderBy = changed('SortState', 'GridState') ? this.storedOrderBy() : null;
|
|
45
|
+
if (orderBy) {
|
|
46
|
+
// The provider transforms a stored sort for its platform before running it; screen that form.
|
|
47
|
+
this.screenStoredClause(result, 'SortState', orderBy, 'OrderBy', this.ViewEntityInfo);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The ORDER BY built from SortState / GridState, or null when SortState is not valid JSON. Such
|
|
52
|
+
* a view cannot build an ORDER BY when it runs either, so there is nothing to screen.
|
|
53
|
+
*/
|
|
54
|
+
storedOrderBy() {
|
|
55
|
+
try {
|
|
56
|
+
return this.OrderByClause;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Adds a validation failure on `field` when the provider's client-clause screen refuses `clause`,
|
|
64
|
+
* or when the provider cannot screen (fails closed).
|
|
65
|
+
*/
|
|
66
|
+
screenStoredClause(result, field, clause, label, entityInfo) {
|
|
67
|
+
if (!clause.trim())
|
|
68
|
+
return;
|
|
69
|
+
const provider = this.ProviderToUse;
|
|
70
|
+
// When MJUserViewEntityServer is resolved in a mixed-tier process (e.g. CLI test runner)
|
|
71
|
+
// against a Network provider (GraphQLDataProvider), defer SQL AST screening to MJServer's
|
|
72
|
+
// Database provider when the GraphQL mutation executes on the server.
|
|
73
|
+
if (provider && provider.ProviderType === 'Network') {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
if (!IsClientClauseScreeningProvider(provider)) {
|
|
78
|
+
throw new Error(`Invalid ${label}: the data provider cannot screen client SQL`);
|
|
79
|
+
}
|
|
80
|
+
provider.ScreenClientClause(clause, label, this.ActiveUser, entityInfo);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
84
|
+
result.Errors.push(new ValidationErrorInfo(field, message, clause, ValidationErrorType.Failure));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A `{%UserView "id"%}` template becomes a subquery only when the view runs, and the provider
|
|
89
|
+
* screens that rendered clause. Here each template stands in as `SELECT NULL` so the rest of
|
|
90
|
+
* the clause can be parsed.
|
|
91
|
+
*/
|
|
92
|
+
static neutralizeViewTemplates(whereClause) {
|
|
93
|
+
return whereClause.replace(/{%[^%]+%}/g, 'SELECT NULL');
|
|
94
|
+
}
|
|
26
95
|
/**
|
|
27
96
|
* SECURITY gate: `CustomWhereClause = 1` tells the platform to fold the stored
|
|
28
97
|
* `WhereClause` into view SQL verbatim — it bypasses both the auto-generation in
|
|
@@ -39,8 +108,9 @@ let MJUserViewEntityServer = class MJUserViewEntityServer extends MJUserViewEnti
|
|
|
39
108
|
}
|
|
40
109
|
const customDirty = this.GetFieldByName('CustomWhereClause')?.Dirty === true;
|
|
41
110
|
const whereDirty = this.GetFieldByName('WhereClause')?.Dirty === true;
|
|
42
|
-
|
|
43
|
-
|
|
111
|
+
// A new record is always authorized: a field first written without NewRecord() seeding it
|
|
112
|
+
// does not read as dirty. On an existing record, only a change needs authorizing.
|
|
113
|
+
if (this.IsSaved && !customDirty && !whereDirty) {
|
|
44
114
|
return;
|
|
45
115
|
}
|
|
46
116
|
const user = this.ContextCurrentUser
|
|
@@ -199,7 +269,7 @@ let MJUserViewEntityServer = class MJUserViewEntityServer extends MJUserViewEnti
|
|
|
199
269
|
return [fkeyViewsDesc, relatedEntitiesDesc].filter(s => s.length > 0).join('\n');
|
|
200
270
|
}
|
|
201
271
|
};
|
|
202
|
-
MJUserViewEntityServer = __decorate([
|
|
272
|
+
MJUserViewEntityServer = MJUserViewEntityServer_1 = __decorate([
|
|
203
273
|
RegisterClass(BaseEntity, 'MJ: User Views')
|
|
204
274
|
], MJUserViewEntityServer);
|
|
205
275
|
export { MJUserViewEntityServer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJUserViewEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJUserViewEntityServer.server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MJUserViewEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJUserViewEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,10 +4,32 @@ import { MJVectorIndexEntity } from "@memberjunction/core-entities";
|
|
|
4
4
|
* Server-side VectorIndex entity that syncs with the vector database provider.
|
|
5
5
|
* On create: calls vectorDB.CreateIndex() to provision the index in the provider (e.g., Pinecone).
|
|
6
6
|
* On delete: calls vectorDB.DeleteIndex() to remove the index from the provider.
|
|
7
|
+
*
|
|
8
|
+
* Provisioning is DETACHED from the save that triggers it: the save returns once the metadata row is
|
|
9
|
+
* written, and the provider call runs afterwards (see {@link Save}). That call is bounded by
|
|
10
|
+
* {@link CREATE_INDEX_TIMEOUT_MS}: past it the hook stops waiting and records `timed-out`. The provider
|
|
11
|
+
* call itself is abandoned, not cancelled (there is no cancellation handle), so the bound limits how
|
|
12
|
+
* long this record's provisioning stays open, not the provider's work.
|
|
13
|
+
* Pinecone's createIndex returns as soon as the request is accepted (we never pass waitUntilReady),
|
|
14
|
+
* so the bound only ever trips on a hung connection, not on a slow index build.
|
|
15
|
+
*
|
|
16
|
+
* Whatever the outcome, it is written onto the row's `ProviderConfig` as a {@link VectorIndexProvisionState}.
|
|
7
17
|
*/
|
|
8
18
|
export declare class MJVectorIndexEntityServer extends MJVectorIndexEntity {
|
|
19
|
+
/** Upper bound on one provider CreateIndex call. */
|
|
20
|
+
static readonly CREATE_INDEX_TIMEOUT_MS = 60000;
|
|
21
|
+
/** Upper bound on the one embedding call that learns a model's width (see resolveDimensions). */
|
|
22
|
+
static readonly DIMENSION_PROBE_TIMEOUT_MS = 30000;
|
|
23
|
+
/** Width used only when the record has none and the probe cannot answer (OpenAI text-embedding-3-small). */
|
|
24
|
+
static readonly DEFAULT_DIMENSIONS = 1536;
|
|
25
|
+
/** The one string embedded to learn a model's width; its content is irrelevant, only the vector's length is read. */
|
|
26
|
+
private static readonly DIMENSION_PROBE_TEXT;
|
|
9
27
|
/**
|
|
10
28
|
* After saving, if this is a new record, create the index in the provider.
|
|
29
|
+
* The provider call is deliberately NOT awaited: the client only needs the metadata row, and the
|
|
30
|
+
* request that triggered the save (an "Auto" index from the UI, or the Config page) must not wait
|
|
31
|
+
* on the provider. Save() never throws over provisioning; the outcome is recorded on the row's
|
|
32
|
+
* `ProviderConfig` instead (see {@link createIndexInProvider}).
|
|
11
33
|
*/
|
|
12
34
|
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
13
35
|
/**
|
|
@@ -21,9 +43,23 @@ export declare class MJVectorIndexEntityServer extends MJVectorIndexEntity {
|
|
|
21
43
|
*/
|
|
22
44
|
private sanitizeIndexName;
|
|
23
45
|
/**
|
|
24
|
-
*
|
|
46
|
+
* The detached half of {@link Save}: provision, then write the outcome onto the row.
|
|
47
|
+
*
|
|
48
|
+
* Before this, a provider that refused (`success: false`), threw, or never answered reached only
|
|
49
|
+
* the server log, and the committed row looked exactly like one with an index behind it. The
|
|
50
|
+
* row's `ProviderConfig` now says which of the {@link VectorIndexProvisionState}s it is in.
|
|
51
|
+
*
|
|
52
|
+
* Keep this name: the integration suite's content-vectorization fixture stubs it by name to keep
|
|
53
|
+
* the provider out of the run.
|
|
25
54
|
*/
|
|
26
55
|
private createIndexInProvider;
|
|
56
|
+
/**
|
|
57
|
+
* Create the index in the vector database provider and report what happened.
|
|
58
|
+
*
|
|
59
|
+
* Returns rather than logs, so {@link createIndexInProvider} records every outcome the same way.
|
|
60
|
+
* Throws only when the driver throws or the call times out; the caller classifies both.
|
|
61
|
+
*/
|
|
62
|
+
private provisionIndexInProvider;
|
|
27
63
|
/**
|
|
28
64
|
* Delete the index from the vector database provider.
|
|
29
65
|
*/
|
|
@@ -37,18 +73,71 @@ export declare class MJVectorIndexEntityServer extends MJVectorIndexEntity {
|
|
|
37
73
|
* Resolve the embedding dimensions to create the provider index at.
|
|
38
74
|
*
|
|
39
75
|
* Prefers this index's own `Dimensions` column, which is where the operator states it and what the
|
|
40
|
-
* embedding call already honors.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
76
|
+
* embedding call already honors. When the record carries none (every index created from the UI:
|
|
77
|
+
* the Config page's Create Index and the "Vector Index: Auto" path both leave it null, and
|
|
78
|
+
* `MJ: AI Models` has no width column to copy from), the width is learned by embedding one short
|
|
79
|
+
* string with the index's own model and reading the vector's length. Every provider fixes the width
|
|
80
|
+
* at create time, so guessing it wrong gives an index the sync can never write to: a 384-dimension
|
|
81
|
+
* model's vectors are rejected by a `VECTOR(1536)` column or a 1536-wide Pinecone index outright.
|
|
44
82
|
*
|
|
45
|
-
* 1536 (OpenAI text-embedding-3-small) remains the fallback
|
|
83
|
+
* 1536 (OpenAI text-embedding-3-small) remains the fallback only when the probe cannot run or
|
|
84
|
+
* fails, and the failure is logged so the width can be set by hand. A wrong fallback does not go
|
|
85
|
+
* unnoticed: the vectorize pipeline compares every returned vector against the index's width and
|
|
86
|
+
* refuses the batch before upserting it.
|
|
46
87
|
*/
|
|
47
88
|
private resolveDimensions;
|
|
89
|
+
/**
|
|
90
|
+
* Embed one short string with this index's embedding model and return the vector's length, or null
|
|
91
|
+
* when there is no model, no user context, or the call fails. `ModelID` is pinned so the answer
|
|
92
|
+
* comes from the model the index is for; the run row is skipped since this is not a real workload.
|
|
93
|
+
*/
|
|
94
|
+
private probeModelDimensions;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the distance metric to request the provider index be created with.
|
|
97
|
+
*
|
|
98
|
+
* `Metric` on this row is what the operator asked for; `cosine` is the fallback. This used to be
|
|
99
|
+
* hardcoded to `cosine` at the call site, which made the `Metric` write-back a tautology: the
|
|
100
|
+
* column simply echoed a constant this file had chosen, so it could never disagree with the
|
|
101
|
+
* provider and could never tell you the provider had done something else.
|
|
102
|
+
*/
|
|
103
|
+
private resolveMetric;
|
|
104
|
+
/**
|
|
105
|
+
* Resolve `work` or reject after `timeoutMs`, whichever comes first. The timer is cleared when the
|
|
106
|
+
* work settles, so a fast provider leaves nothing behind. On timeout the provider may still finish
|
|
107
|
+
* on its side; the record simply does not get its metadata written back, and the log says so.
|
|
108
|
+
*/
|
|
109
|
+
private static withTimeout;
|
|
48
110
|
/**
|
|
49
111
|
* After provider creates the index, save the returned metadata back to our record.
|
|
50
|
-
* Stores ExternalID, Dimensions, Metric, and
|
|
112
|
+
* Stores ExternalID, Dimensions, Metric, the provisioning state, and provider config as JSON.
|
|
113
|
+
*
|
|
114
|
+
* **Provider truth beats our request.** `Dimensions` and `Metric` are read off the provider's
|
|
115
|
+
* own response when it reports them, and only fall back to what we asked for. A provider is
|
|
116
|
+
* free to round, clamp or ignore a requested dimension, and the whole point of these two
|
|
117
|
+
* columns is to be checkable against the embeddings we later generate; a column that can
|
|
118
|
+
* only ever repeat our own request is not a check.
|
|
119
|
+
*
|
|
120
|
+
* A failed write-back is logged rather than recorded: the index exists, and the only way to
|
|
121
|
+
* record anything on the row is the same save that just failed.
|
|
51
122
|
*/
|
|
52
123
|
private saveProviderMetadata;
|
|
124
|
+
private writeBackFailureMessage;
|
|
125
|
+
/** The provider's own dimension, when it reported a usable one. */
|
|
126
|
+
private readProviderDimension;
|
|
127
|
+
/** The provider's own metric, when it reported a recognized one. */
|
|
128
|
+
private readProviderMetric;
|
|
129
|
+
/**
|
|
130
|
+
* Write the provisioning outcome onto the row, so a row that has no index behind it says so
|
|
131
|
+
* instead of looking identical to one that does.
|
|
132
|
+
*
|
|
133
|
+
* Best-effort by construction: this runs after the caller's save has already returned, and a
|
|
134
|
+
* second failure here must not replace the original diagnosis with a save error.
|
|
135
|
+
*/
|
|
136
|
+
private recordProvisionState;
|
|
137
|
+
/**
|
|
138
|
+
* Merge the provisioning outcome into the existing `ProviderConfig` JSON bag, preserving any
|
|
139
|
+
* driver-specific keys already there (e.g. Pinecone's `namespaceField`).
|
|
140
|
+
*/
|
|
141
|
+
private buildProviderConfig;
|
|
53
142
|
}
|
|
54
143
|
//# sourceMappingURL=MJVectorIndexEntityServer.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJVectorIndexEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJVectorIndexEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,
|
|
1
|
+
{"version":3,"file":"MJVectorIndexEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJVectorIndexEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAmD,MAAM,sBAAsB,CAAC;AAEtH,OAAO,EAAE,mBAAmB,EAA0B,MAAM,+BAA+B,CAAC;AAoC5F;;;;;;;;;;;;;;GAcG;AACH,qBACa,yBAA0B,SAAQ,mBAAmB;IAC9D,oDAAoD;IACpD,gBAAuB,uBAAuB,SAAU;IACxD,iGAAiG;IACjG,gBAAuB,0BAA0B,SAAU;IAC3D,4GAA4G;IAC5G,gBAAuB,kBAAkB,QAAQ;IACjD,qHAAqH;IACrH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAqB;IAEjE;;;;;;OAMG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAazE;;OAEG;IACmB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;;;;;;;;OASG;YACW,qBAAqB;IAkCnC;;;;;OAKG;YACW,wBAAwB;IAkDtC;;OAEG;YACW,uBAAuB;IAyBrC;;;OAGG;YACW,mBAAmB;IAgDjC;;;;;;;;;;;;;;;OAeG;YACW,iBAAiB;IAY/B;;;;OAIG;YACW,oBAAoB;IAqClC;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IASrB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAe1B;;;;;;;;;;;;OAYG;YACW,oBAAoB;IAiClC,OAAO,CAAC,uBAAuB;IAM/B,mEAAmE;IACnE,OAAO,CAAC,qBAAqB;IAM7B,oEAAoE;IACpE,OAAO,CAAC,kBAAkB;IAS1B;;;;;;OAMG;YACW,oBAAoB;IAelC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAuB9B"}
|