@memberjunction/core-entities-server 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.
Files changed (54) hide show
  1. package/dist/custom/MJAIAgentCoAgentEntityServer.server.d.ts +78 -0
  2. package/dist/custom/MJAIAgentCoAgentEntityServer.server.d.ts.map +1 -0
  3. package/dist/custom/MJAIAgentCoAgentEntityServer.server.js +224 -0
  4. package/dist/custom/MJAIAgentCoAgentEntityServer.server.js.map +1 -0
  5. package/dist/custom/MJAIAgentEntityServer.server.d.ts +50 -0
  6. package/dist/custom/MJAIAgentEntityServer.server.d.ts.map +1 -0
  7. package/dist/custom/MJAIAgentEntityServer.server.js +126 -0
  8. package/dist/custom/MJAIAgentEntityServer.server.js.map +1 -0
  9. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts +6 -3
  10. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts.map +1 -1
  11. package/dist/custom/MJAIAgentNoteEntityServer.server.js +10 -7
  12. package/dist/custom/MJAIAgentNoteEntityServer.server.js.map +1 -1
  13. package/dist/custom/MJAIAgentSessionBridgeEntityServer.server.d.ts +50 -0
  14. package/dist/custom/MJAIAgentSessionBridgeEntityServer.server.d.ts.map +1 -0
  15. package/dist/custom/MJAIAgentSessionBridgeEntityServer.server.js +133 -0
  16. package/dist/custom/MJAIAgentSessionBridgeEntityServer.server.js.map +1 -0
  17. package/dist/custom/MJAIAgentSessionBridgeParticipantEntityServer.server.d.ts +33 -0
  18. package/dist/custom/MJAIAgentSessionBridgeParticipantEntityServer.server.d.ts.map +1 -0
  19. package/dist/custom/MJAIAgentSessionBridgeParticipantEntityServer.server.js +90 -0
  20. package/dist/custom/MJAIAgentSessionBridgeParticipantEntityServer.server.js.map +1 -0
  21. package/dist/custom/MJAIBridgeAgentIdentityEntityServer.server.d.ts +49 -0
  22. package/dist/custom/MJAIBridgeAgentIdentityEntityServer.server.d.ts.map +1 -0
  23. package/dist/custom/MJAIBridgeAgentIdentityEntityServer.server.js +152 -0
  24. package/dist/custom/MJAIBridgeAgentIdentityEntityServer.server.js.map +1 -0
  25. package/dist/custom/MJAIBridgeProviderChannelEntityServer.server.d.ts +33 -0
  26. package/dist/custom/MJAIBridgeProviderChannelEntityServer.server.d.ts.map +1 -0
  27. package/dist/custom/MJAIBridgeProviderChannelEntityServer.server.js +90 -0
  28. package/dist/custom/MJAIBridgeProviderChannelEntityServer.server.js.map +1 -0
  29. package/dist/custom/MJAIBridgeProviderEntityServer.server.d.ts +52 -0
  30. package/dist/custom/MJAIBridgeProviderEntityServer.server.d.ts.map +1 -0
  31. package/dist/custom/MJAIBridgeProviderEntityServer.server.js +154 -0
  32. package/dist/custom/MJAIBridgeProviderEntityServer.server.js.map +1 -0
  33. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.d.ts +63 -0
  34. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.d.ts.map +1 -0
  35. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.js +212 -0
  36. package/dist/custom/MJAIRemoteBrowserProviderEntityServer.server.js.map +1 -0
  37. package/dist/custom/MJDuplicateRunEntityServer.server.d.ts.map +1 -1
  38. package/dist/custom/MJDuplicateRunEntityServer.server.js +6 -2
  39. package/dist/custom/MJDuplicateRunEntityServer.server.js.map +1 -1
  40. package/dist/custom/MJRecordProcessEntityServer.server.d.ts +61 -0
  41. package/dist/custom/MJRecordProcessEntityServer.server.d.ts.map +1 -0
  42. package/dist/custom/MJRecordProcessEntityServer.server.js +152 -0
  43. package/dist/custom/MJRecordProcessEntityServer.server.js.map +1 -0
  44. package/dist/custom/json-schema-lite.d.ts +36 -0
  45. package/dist/custom/json-schema-lite.d.ts.map +1 -0
  46. package/dist/custom/json-schema-lite.js +125 -0
  47. package/dist/custom/json-schema-lite.js.map +1 -0
  48. package/dist/custom/query-extraction/sync.js +40 -19
  49. package/dist/custom/query-extraction/sync.js.map +1 -1
  50. package/dist/index.d.ts +10 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +10 -0
  53. package/dist/index.js.map +1 -1
  54. package/package.json +24 -24
@@ -0,0 +1,90 @@
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 { BaseEntity, RunView, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/core';
8
+ import { RegisterClass } from '@memberjunction/global';
9
+ import { MJAIBridgeProviderChannelEntity } from '@memberjunction/core-entities';
10
+ /**
11
+ * Server-side `MJ: AI Bridge Provider Channels` entity — the junction declaring which registered
12
+ * `AIAgentChannel`s a provider contributes (Zoom → Meeting Controls + Native Whiteboard, etc.).
13
+ *
14
+ * The only invariant worth enforcing is uniqueness of `(ProviderID, ChannelID)` — a provider
15
+ * shouldn't list the same channel twice. **The database already enforces this with a UNIQUE
16
+ * constraint (`UQ_AIBridgeProviderChannel (ProviderID, ChannelID)`)**, so this check is
17
+ * **defense-in-depth / friendly-message only**: it turns the raw SQL unique-violation error into a
18
+ * clear, field-attributed message at validation time (before the INSERT/UPDATE is attempted) and
19
+ * is consistent with how the sibling co-agent / identity servers surface their cross-record rules.
20
+ * No format/shape invariants exist for this purely-relational row, so there is nothing else to add.
21
+ */
22
+ let MJAIBridgeProviderChannelEntityServer = class MJAIBridgeProviderChannelEntityServer extends MJAIBridgeProviderChannelEntity {
23
+ /** Enable async validation so the friendly-message uniqueness check runs. */
24
+ get DefaultSkipAsyncValidation() {
25
+ return false;
26
+ }
27
+ async ValidateAsync() {
28
+ const result = await super.ValidateAsync();
29
+ if (!result.Success)
30
+ return result;
31
+ const providerDirty = this.GetFieldByName('ProviderID')?.Dirty ?? false;
32
+ const channelDirty = this.GetFieldByName('ChannelID')?.Dirty ?? false;
33
+ if (!this.IsSaved || providerDirty || channelDirty) {
34
+ const conflict = await this.countOtherProviderChannelRows();
35
+ const dupError = BuildDuplicateProviderChannelError(this.ProviderID, this.ChannelID, conflict);
36
+ if (dupError) {
37
+ result.Errors.push(dupError);
38
+ result.Success = false;
39
+ }
40
+ }
41
+ return result;
42
+ }
43
+ /**
44
+ * Counts OTHER rows pairing this provider with this channel (excluding this row when updating).
45
+ * A failed query counts as 0 (fail-open; the DB UNIQUE constraint is the hard backstop anyway).
46
+ */
47
+ async countOtherProviderChannelRows() {
48
+ if (!this.ProviderID || !this.ChannelID) {
49
+ return 0; // required-field violations are sync Validate()'s job
50
+ }
51
+ try {
52
+ const md = this.ProviderToUse;
53
+ const selfExclusion = this.IsSaved ? ` AND ID <> '${this.safeLiteral(this.ID)}'` : '';
54
+ const filter = `ProviderID='${this.safeLiteral(this.ProviderID)}' AND ` +
55
+ `ChannelID='${this.safeLiteral(this.ChannelID)}'${selfExclusion}`;
56
+ const rv = RunView.FromMetadataProvider(md);
57
+ const queryResult = await rv.RunView({
58
+ EntityName: 'MJ: AI Bridge Provider Channels',
59
+ ExtraFilter: filter,
60
+ Fields: ['ID'],
61
+ ResultType: 'simple',
62
+ }, this.ContextCurrentUser);
63
+ return queryResult.Success ? (queryResult.Results?.length ?? 0) : 0;
64
+ }
65
+ catch {
66
+ return 0;
67
+ }
68
+ }
69
+ /** Escapes a UUID/string for safe inclusion in an ExtraFilter literal. */
70
+ safeLiteral(value) {
71
+ return value.replace(/'/g, "''");
72
+ }
73
+ };
74
+ MJAIBridgeProviderChannelEntityServer = __decorate([
75
+ RegisterClass(BaseEntity, 'MJ: AI Bridge Provider Channels')
76
+ ], MJAIBridgeProviderChannelEntityServer);
77
+ export { MJAIBridgeProviderChannelEntityServer };
78
+ /**
79
+ * PURE invariant: a provider may list a given channel only once. Returns the friendly error when
80
+ * `existingCount` other rows already pair this `(ProviderID, ChannelID)`, else `null`.
81
+ * (Defense-in-depth over the DB `UQ_AIBridgeProviderChannel` UNIQUE constraint.)
82
+ */
83
+ export function BuildDuplicateProviderChannelError(providerID, channelID, existingCount) {
84
+ if (existingCount <= 0) {
85
+ return null;
86
+ }
87
+ return new ValidationErrorInfo('ChannelID', `This provider already contributes the selected channel (${existingCount} existing row(s)). ` +
88
+ 'A provider can list each channel only once — edit the existing row instead.', channelID, ValidationErrorType.Failure);
89
+ }
90
+ //# sourceMappingURL=MJAIBridgeProviderChannelEntityServer.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MJAIBridgeProviderChannelEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIBridgeProviderChannelEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAqB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAoB,MAAM,sBAAsB,CAAC;AAC1I,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAEhF;;;;;;;;;;;GAWG;AAEI,IAAM,qCAAqC,GAA3C,MAAM,qCAAsC,SAAQ,+BAA+B;IACtF,6EAA6E;IAC7E,IAAoB,0BAA0B;QAC1C,OAAO,KAAK,CAAC;IACjB,CAAC;IAEe,KAAK,CAAC,aAAa;QAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC;QAEnC,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC;QACxE,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC;QACtE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,aAAa,IAAI,YAAY,EAAE,CAAC;YACjD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,6BAA6B,EAAE,CAAC;YAC5D,MAAM,QAAQ,GAAG,kCAAkC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC/F,IAAI,QAAQ,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC7B,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,6BAA6B;QACvC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,OAAO,CAAC,CAAC,CAAC,sDAAsD;QACpE,CAAC;QACD,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,CAAC,aAA6C,CAAC;YAC9D,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,MAAM,MAAM,GACR,eAAe,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ;gBACxD,cAAc,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,aAAa,EAAE,CAAC;YACtE,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAC5C,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,OAAO,CAChC;gBACI,UAAU,EAAE,iCAAiC;gBAC7C,WAAW,EAAE,MAAM;gBACnB,MAAM,EAAE,CAAC,IAAI,CAAC;gBACd,UAAU,EAAE,QAAQ;aACvB,EACD,IAAI,CAAC,kBAAkB,CAC1B,CAAC;YACF,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,CAAC,CAAC;QACb,CAAC;IACL,CAAC;IAED,0EAA0E;IAClE,WAAW,CAAC,KAAa;QAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;CACJ,CAAA;AA1DY,qCAAqC;IADjD,aAAa,CAAC,UAAU,EAAE,iCAAiC,CAAC;GAChD,qCAAqC,CA0DjD;;AAED;;;;GAIG;AACH,MAAM,UAAU,kCAAkC,CAC9C,UAAyB,EACzB,SAAwB,EACxB,aAAqB;IAErB,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,mBAAmB,CAC1B,WAAW,EACX,2DAA2D,aAAa,qBAAqB;QACzF,6EAA6E,EACjF,SAAS,EACT,mBAAmB,CAAC,OAAO,CAC9B,CAAC;AACN,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { ValidationErrorInfo, ValidationResult } from '@memberjunction/core';
2
+ import { MJAIBridgeProviderEntity } from '@memberjunction/core-entities';
3
+ /**
4
+ * The complete set of known `IBridgeProviderFeatures` keys (see the generated
5
+ * `MJAIBridgeProviderEntity_IBridgeProviderFeatures` interface and
6
+ * `metadata/entities/JSONType-interfaces/IBridgeProviderFeatures.ts`). `SupportedFeatures` is a
7
+ * flat object of optional booleans, so the validation is: every present key must be in this set
8
+ * and every value must be a boolean. Keeping the list here (rather than reflecting off a runtime
9
+ * value) makes the validator a PURE, dependency-free, easily-unit-tested function and gives a
10
+ * friendly "unknown feature flag" message that a free-form `additionalProperties:false` schema
11
+ * would not.
12
+ */
13
+ export declare const KNOWN_BRIDGE_PROVIDER_FEATURE_KEYS: ReadonlySet<string>;
14
+ /**
15
+ * Server-side `MJ: AI Bridge Providers` entity enforcing the invariants the architecture documents
16
+ * (see `/plans/realtime/realtime-bridges-architecture.md` §3): the engine GATES every optional
17
+ * driver call on the `SupportedFeatures` JSON, so a malformed / mistyped flags blob is a latent
18
+ * runtime bug. We catch it at write time.
19
+ *
20
+ * Invariants:
21
+ * 1. **`SupportedFeatures` (when dirty/non-null) is well-formed `IBridgeProviderFeatures`** — it
22
+ * parses as a JSON object whose every key is a known feature flag and every value is a boolean.
23
+ * Unknown keys (typos like `OutbondDial`) and non-boolean values (`"true"`, `1`) are rejected
24
+ * with a precise message. PURE helper `ValidateSupportedFeaturesJson`.
25
+ * 2. **`DriverClass` is non-empty** — it is the `ClassFactory` key the engine resolves the bridge
26
+ * driver from; a blank value silently fails resolution. (The DB column is NOT NULL but allows
27
+ * empty/whitespace strings, so this adds the meaningful check.) PURE helper
28
+ * `ValidateDriverClass`.
29
+ *
30
+ * No cross-record `RunView` is needed here — both invariants are purely intra-row, so this is the
31
+ * cheapest possible `ValidateAsync` (no DB round trips).
32
+ */
33
+ export declare class MJAIBridgeProviderEntityServer extends MJAIBridgeProviderEntity {
34
+ /** Enable async validation so these checks run on the server save path. */
35
+ get DefaultSkipAsyncValidation(): boolean;
36
+ ValidateAsync(): Promise<ValidationResult>;
37
+ }
38
+ /**
39
+ * PURE invariant: `DriverClass` must be a non-empty, non-whitespace string. Returns the error, or
40
+ * `null` when valid. (A `null`/`undefined` value is left to the sync required-field validator.)
41
+ */
42
+ export declare function ValidateDriverClass(driverClass: string | null | undefined): ValidationErrorInfo | null;
43
+ /**
44
+ * PURE invariant core for `SupportedFeatures` (exported for unit tests): the raw column value must
45
+ * either be null/empty (unsupported — valid) or a JSON OBJECT whose keys are all known
46
+ * `IBridgeProviderFeatures` flags and whose values are all booleans.
47
+ *
48
+ * @param raw The raw `SupportedFeatures` column value.
49
+ * @returns The violations (empty array = valid).
50
+ */
51
+ export declare function ValidateSupportedFeaturesJson(raw: string | null | undefined): ValidationErrorInfo[];
52
+ //# sourceMappingURL=MJAIBridgeProviderEntityServer.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MJAIBridgeProviderEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJAIBridgeProviderEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,mBAAmB,EAAuB,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE;;;;;;;;;GASG;AACH,eAAO,MAAM,kCAAkC,EAAE,WAAW,CAAC,MAAM,CAoBjE,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,8BAA+B,SAAQ,wBAAwB;IACxE,2EAA2E;IAC3E,IAAoB,0BAA0B,IAAI,OAAO,CAExD;IAEqB,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC;CA0BnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,mBAAmB,GAAG,IAAI,CAatG;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,mBAAmB,EAAE,CA8BnG"}
@@ -0,0 +1,154 @@
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 { BaseEntity, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/core';
8
+ import { RegisterClass } from '@memberjunction/global';
9
+ import { MJAIBridgeProviderEntity } from '@memberjunction/core-entities';
10
+ /**
11
+ * The complete set of known `IBridgeProviderFeatures` keys (see the generated
12
+ * `MJAIBridgeProviderEntity_IBridgeProviderFeatures` interface and
13
+ * `metadata/entities/JSONType-interfaces/IBridgeProviderFeatures.ts`). `SupportedFeatures` is a
14
+ * flat object of optional booleans, so the validation is: every present key must be in this set
15
+ * and every value must be a boolean. Keeping the list here (rather than reflecting off a runtime
16
+ * value) makes the validator a PURE, dependency-free, easily-unit-tested function and gives a
17
+ * friendly "unknown feature flag" message that a free-form `additionalProperties:false` schema
18
+ * would not.
19
+ */
20
+ export const KNOWN_BRIDGE_PROVIDER_FEATURE_KEYS = new Set([
21
+ // Join methods
22
+ 'OnDemandJoin',
23
+ 'ScheduledJoin',
24
+ 'InviteJoin',
25
+ 'NativeInvite',
26
+ 'InboundRouting',
27
+ 'OutboundDial',
28
+ // Media tracks (directional)
29
+ 'AudioIn',
30
+ 'AudioOut',
31
+ 'VideoIn',
32
+ 'VideoOut',
33
+ 'ScreenIn',
34
+ 'ScreenOut',
35
+ // Signals & telephony
36
+ 'SpeakerDiarization',
37
+ 'DTMF',
38
+ 'CallTransfer',
39
+ 'Recording',
40
+ ]);
41
+ /**
42
+ * Server-side `MJ: AI Bridge Providers` entity enforcing the invariants the architecture documents
43
+ * (see `/plans/realtime/realtime-bridges-architecture.md` §3): the engine GATES every optional
44
+ * driver call on the `SupportedFeatures` JSON, so a malformed / mistyped flags blob is a latent
45
+ * runtime bug. We catch it at write time.
46
+ *
47
+ * Invariants:
48
+ * 1. **`SupportedFeatures` (when dirty/non-null) is well-formed `IBridgeProviderFeatures`** — it
49
+ * parses as a JSON object whose every key is a known feature flag and every value is a boolean.
50
+ * Unknown keys (typos like `OutbondDial`) and non-boolean values (`"true"`, `1`) are rejected
51
+ * with a precise message. PURE helper `ValidateSupportedFeaturesJson`.
52
+ * 2. **`DriverClass` is non-empty** — it is the `ClassFactory` key the engine resolves the bridge
53
+ * driver from; a blank value silently fails resolution. (The DB column is NOT NULL but allows
54
+ * empty/whitespace strings, so this adds the meaningful check.) PURE helper
55
+ * `ValidateDriverClass`.
56
+ *
57
+ * No cross-record `RunView` is needed here — both invariants are purely intra-row, so this is the
58
+ * cheapest possible `ValidateAsync` (no DB round trips).
59
+ */
60
+ let MJAIBridgeProviderEntityServer = class MJAIBridgeProviderEntityServer extends MJAIBridgeProviderEntity {
61
+ /** Enable async validation so these checks run on the server save path. */
62
+ get DefaultSkipAsyncValidation() {
63
+ return false;
64
+ }
65
+ async ValidateAsync() {
66
+ const result = await super.ValidateAsync();
67
+ if (!result.Success)
68
+ return result;
69
+ // (2) DriverClass non-empty — cheap, only when new or DriverClass changed.
70
+ const driverDirty = this.GetFieldByName('DriverClass')?.Dirty ?? false;
71
+ if (!this.IsSaved || driverDirty) {
72
+ const driverError = ValidateDriverClass(this.DriverClass);
73
+ if (driverError) {
74
+ result.Errors.push(driverError);
75
+ result.Success = false;
76
+ }
77
+ }
78
+ // (1) SupportedFeatures JSON shape — only when new or the column changed.
79
+ const featuresDirty = this.GetFieldByName('SupportedFeatures')?.Dirty ?? false;
80
+ if (!this.IsSaved || featuresDirty) {
81
+ const featureErrors = ValidateSupportedFeaturesJson(this.SupportedFeatures);
82
+ if (featureErrors.length > 0) {
83
+ result.Errors.push(...featureErrors);
84
+ result.Success = false;
85
+ }
86
+ }
87
+ return result;
88
+ }
89
+ };
90
+ MJAIBridgeProviderEntityServer = __decorate([
91
+ RegisterClass(BaseEntity, 'MJ: AI Bridge Providers')
92
+ ], MJAIBridgeProviderEntityServer);
93
+ export { MJAIBridgeProviderEntityServer };
94
+ /**
95
+ * PURE invariant: `DriverClass` must be a non-empty, non-whitespace string. Returns the error, or
96
+ * `null` when valid. (A `null`/`undefined` value is left to the sync required-field validator.)
97
+ */
98
+ export function ValidateDriverClass(driverClass) {
99
+ if (driverClass == null) {
100
+ return null; // required-field violation is sync Validate()'s job
101
+ }
102
+ if (driverClass.trim().length === 0) {
103
+ return new ValidationErrorInfo('DriverClass', 'DriverClass cannot be blank — it is the ClassFactory key the bridge engine uses to resolve the driver.', driverClass, ValidationErrorType.Failure);
104
+ }
105
+ return null;
106
+ }
107
+ /**
108
+ * PURE invariant core for `SupportedFeatures` (exported for unit tests): the raw column value must
109
+ * either be null/empty (unsupported — valid) or a JSON OBJECT whose keys are all known
110
+ * `IBridgeProviderFeatures` flags and whose values are all booleans.
111
+ *
112
+ * @param raw The raw `SupportedFeatures` column value.
113
+ * @returns The violations (empty array = valid).
114
+ */
115
+ export function ValidateSupportedFeaturesJson(raw) {
116
+ if (raw == null || raw.trim().length === 0) {
117
+ return []; // omitted = "no features supported" — a valid state
118
+ }
119
+ let parsed;
120
+ try {
121
+ parsed = JSON.parse(raw);
122
+ }
123
+ catch {
124
+ return [buildFeaturesError('SupportedFeatures is not valid JSON.', raw)];
125
+ }
126
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
127
+ return [buildFeaturesError('SupportedFeatures must be a JSON object of feature flags (got ' + describeJsonType(parsed) + ').', raw)];
128
+ }
129
+ const errors = [];
130
+ const obj = parsed;
131
+ for (const key of Object.keys(obj)) {
132
+ if (!KNOWN_BRIDGE_PROVIDER_FEATURE_KEYS.has(key)) {
133
+ errors.push(buildFeaturesError(`SupportedFeatures contains unknown feature flag '${key}'.`, raw));
134
+ continue;
135
+ }
136
+ if (typeof obj[key] !== 'boolean') {
137
+ errors.push(buildFeaturesError(`SupportedFeatures flag '${key}' must be a boolean (got ${describeJsonType(obj[key])}).`, raw));
138
+ }
139
+ }
140
+ return errors;
141
+ }
142
+ /** Builds a `SupportedFeatures` failure with the standard source/type. */
143
+ function buildFeaturesError(message, value) {
144
+ return new ValidationErrorInfo('SupportedFeatures', message, value, ValidationErrorType.Failure);
145
+ }
146
+ /** Human-readable JSON type label used in error messages. */
147
+ function describeJsonType(value) {
148
+ if (value === null)
149
+ return 'null';
150
+ if (Array.isArray(value))
151
+ return 'array';
152
+ return typeof value;
153
+ }
154
+ //# sourceMappingURL=MJAIBridgeProviderEntityServer.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MJAIBridgeProviderEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIBridgeProviderEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,mBAAmB,EAAoB,MAAM,sBAAsB,CAAC;AAC9G,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAwB,IAAI,GAAG,CAAS;IACnF,eAAe;IACf,cAAc;IACd,eAAe;IACf,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,6BAA6B;IAC7B,SAAS;IACT,UAAU;IACV,SAAS;IACT,UAAU;IACV,UAAU;IACV,WAAW;IACX,sBAAsB;IACtB,oBAAoB;IACpB,MAAM;IACN,cAAc;IACd,WAAW;CACd,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AAEI,IAAM,8BAA8B,GAApC,MAAM,8BAA+B,SAAQ,wBAAwB;IACxE,2EAA2E;IAC3E,IAAoB,0BAA0B;QAC1C,OAAO,KAAK,CAAC;IACjB,CAAC;IAEe,KAAK,CAAC,aAAa;QAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC;QAEnC,2EAA2E;QAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1D,IAAI,WAAW,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAChC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,CAAC;QACL,CAAC;QAED,0EAA0E;QAC1E,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC;QAC/E,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,aAAa,GAAG,6BAA6B,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC5E,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;gBACrC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ,CAAA;AAhCY,8BAA8B;IAD1C,aAAa,CAAC,UAAU,EAAE,yBAAyB,CAAC;GACxC,8BAA8B,CAgC1C;;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAsC;IACtE,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,CAAC,oDAAoD;IACrE,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,mBAAmB,CAC1B,aAAa,EACb,wGAAwG,EACxG,WAAW,EACX,mBAAmB,CAAC,OAAO,CAC9B,CAAC;IACN,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAA8B;IACxE,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,CAAC,CAAC,oDAAoD;IACnE,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,CAAC,kBAAkB,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACzE,OAAO,CAAC,kBAAkB,CAAC,gEAAgE,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IACzI,CAAC;IAED,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,kCAAkC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,oDAAoD,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;YAClG,SAAS;QACb,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CACP,kBAAkB,CAAC,2BAA2B,GAAG,4BAA4B,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CACpH,CAAC;QACN,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,0EAA0E;AAC1E,SAAS,kBAAkB,CAAC,OAAe,EAAE,KAAa;IACtD,OAAO,IAAI,mBAAmB,CAAC,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;AACrG,CAAC;AAED,6DAA6D;AAC7D,SAAS,gBAAgB,CAAC,KAAc;IACpC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,OAAO,OAAO,KAAK,CAAC;AACxB,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { ValidationErrorInfo, ValidationResult } from '@memberjunction/core';
2
+ import { MJAIRemoteBrowserProviderEntity } from '@memberjunction/core-entities';
3
+ /**
4
+ * The complete set of known `IRemoteBrowserProviderFeatures` keys (see the generated
5
+ * `MJAIRemoteBrowserProviderEntity_IRemoteBrowserProviderFeatures` interface and
6
+ * `metadata/entities/JSONType-interfaces/IRemoteBrowserProviderFeatures.ts`). `SupportedFeatures`
7
+ * is a flat object of optional booleans, so the validation is: every present key must be in this
8
+ * set and every value must be a boolean. Keeping the list here (rather than reflecting off a
9
+ * runtime value) makes the validator a PURE, dependency-free, easily-unit-tested function and
10
+ * gives a friendly "unknown feature flag" message that a free-form `additionalProperties:false`
11
+ * schema would not. Mirrors `KNOWN_BRIDGE_PROVIDER_FEATURE_KEYS`.
12
+ */
13
+ export declare const KNOWN_REMOTE_BROWSER_PROVIDER_FEATURE_KEYS: ReadonlySet<string>;
14
+ /** The valid `DefaultControlMode` values (mirrors the `RemoteBrowserControlMode` union + the DB CHECK). */
15
+ export declare const REMOTE_BROWSER_CONTROL_MODES: ReadonlySet<string>;
16
+ /**
17
+ * Server-side `MJ: AI Remote Browser Providers` entity enforcing the invariants the Remote Browser
18
+ * channel relies on (see `/plans/realtime/realtime-bridges-architecture.md` §4d-i). The engine GATES
19
+ * every optional session method on the `SupportedFeatures` JSON and resolves the driver from
20
+ * `DriverClass`, so a malformed flags blob, a blank driver, or a control mode the backend cannot
21
+ * satisfy are all latent runtime bugs. We catch them at write time.
22
+ *
23
+ * Invariants (all purely intra-row — the cheapest possible `ValidateAsync`, no DB round trips):
24
+ * 1. **`SupportedFeatures` (when dirty/non-null) is well-formed `IRemoteBrowserProviderFeatures`** —
25
+ * it parses as a JSON object whose every key is a known feature flag and every value is a
26
+ * boolean. Unknown keys and non-boolean values are rejected. PURE `ValidateRemoteBrowserSupportedFeaturesJson`.
27
+ * 2. **`DriverClass` is non-empty** — the `ClassFactory` key the engine resolves the backend from.
28
+ * PURE `ValidateRemoteBrowserDriverClass`.
29
+ * 3. **`DefaultControlMode` is satisfiable by the declared features** — `Collaborative` requires
30
+ * `HumanTakeover`; `ViewOnly` and `Collaborative` require `LiveView`. A backend advertising a
31
+ * mode it cannot honor is a configuration error. PURE `ValidateControlModeAgainstFeatures`.
32
+ */
33
+ export declare class MJAIRemoteBrowserProviderEntityServer extends MJAIRemoteBrowserProviderEntity {
34
+ /** Enable async validation so these checks run on the server save path. */
35
+ get DefaultSkipAsyncValidation(): boolean;
36
+ ValidateAsync(): Promise<ValidationResult>;
37
+ }
38
+ /**
39
+ * PURE invariant: `DriverClass` must be a non-empty, non-whitespace string. Returns the error, or
40
+ * `null` when valid. (A `null`/`undefined` value is left to the sync required-field validator.)
41
+ */
42
+ export declare function ValidateRemoteBrowserDriverClass(driverClass: string | null | undefined): ValidationErrorInfo | null;
43
+ /**
44
+ * PURE invariant core for `SupportedFeatures` (exported for unit tests): the raw column value must
45
+ * either be null/empty (no features — valid) or a JSON OBJECT whose keys are all known
46
+ * `IRemoteBrowserProviderFeatures` flags and whose values are all booleans.
47
+ *
48
+ * @param raw The raw `SupportedFeatures` column value.
49
+ * @returns The violations (empty array = valid).
50
+ */
51
+ export declare function ValidateRemoteBrowserSupportedFeaturesJson(raw: string | null | undefined): ValidationErrorInfo[];
52
+ /**
53
+ * PURE invariant: the `DefaultControlMode` must be satisfiable by the backend's declared
54
+ * `SupportedFeatures`. `Collaborative` needs `HumanTakeover`; `ViewOnly` and `Collaborative` need
55
+ * `LiveView`. `AgentOnly` (and an unrecognized mode, which the sync CHECK/value-list validator owns)
56
+ * impose no feature prerequisite here. Returns the error, or `null` when valid.
57
+ *
58
+ * @param mode The `DefaultControlMode` value.
59
+ * @param rawFeatures The raw `SupportedFeatures` column value.
60
+ * @returns The violation, or `null` when valid.
61
+ */
62
+ export declare function ValidateControlModeAgainstFeatures(mode: string | null | undefined, rawFeatures: string | null | undefined): ValidationErrorInfo | null;
63
+ //# sourceMappingURL=MJAIRemoteBrowserProviderEntityServer.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MJAIRemoteBrowserProviderEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJAIRemoteBrowserProviderEntityServer.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,mBAAmB,EAAuB,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAEhF;;;;;;;;;GASG;AACH,eAAO,MAAM,0CAA0C,EAAE,WAAW,CAAC,MAAM,CAgBzE,CAAC;AAEH,2GAA2G;AAC3G,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,MAAM,CAA+D,CAAC;AAE7H;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,qCAAsC,SAAQ,+BAA+B;IACtF,2EAA2E;IAC3E,IAAoB,0BAA0B,IAAI,OAAO,CAExD;IAEqB,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAqCnE;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,mBAAmB,GAAG,IAAI,CAanH;AAED;;;;;;;GAOG;AACH,wBAAgB,0CAA0C,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,mBAAmB,EAAE,CA8BhH;AAED;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAC9C,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,mBAAmB,GAAG,IAAI,CA2B5B"}
@@ -0,0 +1,212 @@
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 { BaseEntity, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/core';
8
+ import { RegisterClass } from '@memberjunction/global';
9
+ import { MJAIRemoteBrowserProviderEntity } from '@memberjunction/core-entities';
10
+ /**
11
+ * The complete set of known `IRemoteBrowserProviderFeatures` keys (see the generated
12
+ * `MJAIRemoteBrowserProviderEntity_IRemoteBrowserProviderFeatures` interface and
13
+ * `metadata/entities/JSONType-interfaces/IRemoteBrowserProviderFeatures.ts`). `SupportedFeatures`
14
+ * is a flat object of optional booleans, so the validation is: every present key must be in this
15
+ * set and every value must be a boolean. Keeping the list here (rather than reflecting off a
16
+ * runtime value) makes the validator a PURE, dependency-free, easily-unit-tested function and
17
+ * gives a friendly "unknown feature flag" message that a free-form `additionalProperties:false`
18
+ * schema would not. Mirrors `KNOWN_BRIDGE_PROVIDER_FEATURE_KEYS`.
19
+ */
20
+ export const KNOWN_REMOTE_BROWSER_PROVIDER_FEATURE_KEYS = new Set([
21
+ // Control substrate & strategies
22
+ 'RawCdpControl',
23
+ 'NativeAIControl',
24
+ // Viewing & collaboration
25
+ 'LiveView',
26
+ 'HumanTakeover',
27
+ 'ScreenStreaming',
28
+ // Operational
29
+ 'Stealth',
30
+ 'ProxyEgress',
31
+ 'SessionRecording',
32
+ 'PersistentContext',
33
+ 'MultiTab',
34
+ 'FileDownloads',
35
+ 'CaptchaSolving',
36
+ ]);
37
+ /** The valid `DefaultControlMode` values (mirrors the `RemoteBrowserControlMode` union + the DB CHECK). */
38
+ export const REMOTE_BROWSER_CONTROL_MODES = new Set(['AgentOnly', 'ViewOnly', 'Collaborative']);
39
+ /**
40
+ * Server-side `MJ: AI Remote Browser Providers` entity enforcing the invariants the Remote Browser
41
+ * channel relies on (see `/plans/realtime/realtime-bridges-architecture.md` §4d-i). The engine GATES
42
+ * every optional session method on the `SupportedFeatures` JSON and resolves the driver from
43
+ * `DriverClass`, so a malformed flags blob, a blank driver, or a control mode the backend cannot
44
+ * satisfy are all latent runtime bugs. We catch them at write time.
45
+ *
46
+ * Invariants (all purely intra-row — the cheapest possible `ValidateAsync`, no DB round trips):
47
+ * 1. **`SupportedFeatures` (when dirty/non-null) is well-formed `IRemoteBrowserProviderFeatures`** —
48
+ * it parses as a JSON object whose every key is a known feature flag and every value is a
49
+ * boolean. Unknown keys and non-boolean values are rejected. PURE `ValidateRemoteBrowserSupportedFeaturesJson`.
50
+ * 2. **`DriverClass` is non-empty** — the `ClassFactory` key the engine resolves the backend from.
51
+ * PURE `ValidateRemoteBrowserDriverClass`.
52
+ * 3. **`DefaultControlMode` is satisfiable by the declared features** — `Collaborative` requires
53
+ * `HumanTakeover`; `ViewOnly` and `Collaborative` require `LiveView`. A backend advertising a
54
+ * mode it cannot honor is a configuration error. PURE `ValidateControlModeAgainstFeatures`.
55
+ */
56
+ let MJAIRemoteBrowserProviderEntityServer = class MJAIRemoteBrowserProviderEntityServer extends MJAIRemoteBrowserProviderEntity {
57
+ /** Enable async validation so these checks run on the server save path. */
58
+ get DefaultSkipAsyncValidation() {
59
+ return false;
60
+ }
61
+ async ValidateAsync() {
62
+ const result = await super.ValidateAsync();
63
+ if (!result.Success)
64
+ return result;
65
+ // (2) DriverClass non-empty — cheap, only when new or DriverClass changed.
66
+ const driverDirty = this.GetFieldByName('DriverClass')?.Dirty ?? false;
67
+ if (!this.IsSaved || driverDirty) {
68
+ const driverError = ValidateRemoteBrowserDriverClass(this.DriverClass);
69
+ if (driverError) {
70
+ result.Errors.push(driverError);
71
+ result.Success = false;
72
+ }
73
+ }
74
+ // (1) SupportedFeatures JSON shape — only when new or the column changed.
75
+ const featuresDirty = this.GetFieldByName('SupportedFeatures')?.Dirty ?? false;
76
+ if (!this.IsSaved || featuresDirty) {
77
+ const featureErrors = ValidateRemoteBrowserSupportedFeaturesJson(this.SupportedFeatures);
78
+ if (featureErrors.length > 0) {
79
+ result.Errors.push(...featureErrors);
80
+ result.Success = false;
81
+ }
82
+ }
83
+ // (3) DefaultControlMode must be satisfiable by the declared features — re-validate whenever
84
+ // either the mode or the features changed (a feature change can invalidate an existing mode).
85
+ const modeDirty = this.GetFieldByName('DefaultControlMode')?.Dirty ?? false;
86
+ if (!this.IsSaved || modeDirty || featuresDirty) {
87
+ const modeError = ValidateControlModeAgainstFeatures(this.DefaultControlMode, this.SupportedFeatures);
88
+ if (modeError) {
89
+ result.Errors.push(modeError);
90
+ result.Success = false;
91
+ }
92
+ }
93
+ return result;
94
+ }
95
+ };
96
+ MJAIRemoteBrowserProviderEntityServer = __decorate([
97
+ RegisterClass(BaseEntity, 'MJ: AI Remote Browser Providers')
98
+ ], MJAIRemoteBrowserProviderEntityServer);
99
+ export { MJAIRemoteBrowserProviderEntityServer };
100
+ /**
101
+ * PURE invariant: `DriverClass` must be a non-empty, non-whitespace string. Returns the error, or
102
+ * `null` when valid. (A `null`/`undefined` value is left to the sync required-field validator.)
103
+ */
104
+ export function ValidateRemoteBrowserDriverClass(driverClass) {
105
+ if (driverClass == null) {
106
+ return null; // required-field violation is sync Validate()'s job
107
+ }
108
+ if (driverClass.trim().length === 0) {
109
+ return new ValidationErrorInfo('DriverClass', 'DriverClass cannot be blank — it is the ClassFactory key the Remote Browser engine uses to resolve the backend driver.', driverClass, ValidationErrorType.Failure);
110
+ }
111
+ return null;
112
+ }
113
+ /**
114
+ * PURE invariant core for `SupportedFeatures` (exported for unit tests): the raw column value must
115
+ * either be null/empty (no features — valid) or a JSON OBJECT whose keys are all known
116
+ * `IRemoteBrowserProviderFeatures` flags and whose values are all booleans.
117
+ *
118
+ * @param raw The raw `SupportedFeatures` column value.
119
+ * @returns The violations (empty array = valid).
120
+ */
121
+ export function ValidateRemoteBrowserSupportedFeaturesJson(raw) {
122
+ if (raw == null || raw.trim().length === 0) {
123
+ return []; // omitted = "no features supported" — a valid state
124
+ }
125
+ let parsed;
126
+ try {
127
+ parsed = JSON.parse(raw);
128
+ }
129
+ catch {
130
+ return [buildFeaturesError('SupportedFeatures is not valid JSON.', raw)];
131
+ }
132
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
133
+ return [buildFeaturesError('SupportedFeatures must be a JSON object of feature flags (got ' + describeJsonType(parsed) + ').', raw)];
134
+ }
135
+ const errors = [];
136
+ const obj = parsed;
137
+ for (const key of Object.keys(obj)) {
138
+ if (!KNOWN_REMOTE_BROWSER_PROVIDER_FEATURE_KEYS.has(key)) {
139
+ errors.push(buildFeaturesError(`SupportedFeatures contains unknown feature flag '${key}'.`, raw));
140
+ continue;
141
+ }
142
+ if (typeof obj[key] !== 'boolean') {
143
+ errors.push(buildFeaturesError(`SupportedFeatures flag '${key}' must be a boolean (got ${describeJsonType(obj[key])}).`, raw));
144
+ }
145
+ }
146
+ return errors;
147
+ }
148
+ /**
149
+ * PURE invariant: the `DefaultControlMode` must be satisfiable by the backend's declared
150
+ * `SupportedFeatures`. `Collaborative` needs `HumanTakeover`; `ViewOnly` and `Collaborative` need
151
+ * `LiveView`. `AgentOnly` (and an unrecognized mode, which the sync CHECK/value-list validator owns)
152
+ * impose no feature prerequisite here. Returns the error, or `null` when valid.
153
+ *
154
+ * @param mode The `DefaultControlMode` value.
155
+ * @param rawFeatures The raw `SupportedFeatures` column value.
156
+ * @returns The violation, or `null` when valid.
157
+ */
158
+ export function ValidateControlModeAgainstFeatures(mode, rawFeatures) {
159
+ if (mode == null || !REMOTE_BROWSER_CONTROL_MODES.has(mode)) {
160
+ return null; // null / unrecognized mode is the sync value-list validator's job
161
+ }
162
+ if (mode === 'AgentOnly') {
163
+ return null; // no feature prerequisite
164
+ }
165
+ const features = parseFeatureFlags(rawFeatures);
166
+ const missing = [];
167
+ // ViewOnly + Collaborative both need a way for humans to watch.
168
+ if (features['LiveView'] !== true) {
169
+ missing.push('LiveView');
170
+ }
171
+ // Collaborative additionally needs humans to be able to take the wheel.
172
+ if (mode === 'Collaborative' && features['HumanTakeover'] !== true) {
173
+ missing.push('HumanTakeover');
174
+ }
175
+ if (missing.length === 0) {
176
+ return null;
177
+ }
178
+ return new ValidationErrorInfo('DefaultControlMode', `DefaultControlMode '${mode}' requires SupportedFeatures ${missing.map(m => `'${m}'`).join(' and ')} to be enabled.`, mode, ValidationErrorType.Failure);
179
+ }
180
+ /**
181
+ * Parses the raw `SupportedFeatures` JSON into a flag map for the control-mode check, tolerating
182
+ * malformed input (returns `{}` — invariant #1 reports the JSON shape error separately, so this
183
+ * check does not double-report).
184
+ */
185
+ function parseFeatureFlags(raw) {
186
+ if (raw == null || raw.trim().length === 0) {
187
+ return {};
188
+ }
189
+ try {
190
+ const parsed = JSON.parse(raw);
191
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
192
+ return parsed;
193
+ }
194
+ }
195
+ catch {
196
+ // shape error is reported by ValidateRemoteBrowserSupportedFeaturesJson; treat as no flags here
197
+ }
198
+ return {};
199
+ }
200
+ /** Builds a `SupportedFeatures` failure with the standard source/type. */
201
+ function buildFeaturesError(message, value) {
202
+ return new ValidationErrorInfo('SupportedFeatures', message, value, ValidationErrorType.Failure);
203
+ }
204
+ /** Human-readable JSON type label used in error messages. */
205
+ function describeJsonType(value) {
206
+ if (value === null)
207
+ return 'null';
208
+ if (Array.isArray(value))
209
+ return 'array';
210
+ return typeof value;
211
+ }
212
+ //# sourceMappingURL=MJAIRemoteBrowserProviderEntityServer.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MJAIRemoteBrowserProviderEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJAIRemoteBrowserProviderEntityServer.server.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MJDuplicateRunEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJDuplicateRunEntityServer.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAA0B,MAAM,+BAA+B,CAAC;AA4C7F,qBACa,0BAA2B,SAAQ,oBAAoB;IACnD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAuBrC;;;OAGG;YACW,iBAAiB;IAmE/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;;OAIG;IACH;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,2BAA2B;CA8BtC"}
1
+ {"version":3,"file":"MJDuplicateRunEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJDuplicateRunEntityServer.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAA0B,MAAM,+BAA+B,CAAC;AA4C7F,qBACa,0BAA2B,SAAQ,oBAAoB;IACnD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAuBrC;;;OAGG;YACW,iBAAiB;IAuE/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;;OAIG;IACH;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,2BAA2B;CA8BtC"}
@@ -73,12 +73,16 @@ let MJDuplicateRunEntityServer = class MJDuplicateRunEntityServer extends MJDupl
73
73
  async runDetectionAsync() {
74
74
  const startTime = Date.now();
75
75
  try {
76
- const detector = new DuplicateRecordDetector();
76
+ // Thread this entity's provider (request-scoped — each MJAPI call binds its own
77
+ // connection) down the detection stack instead of letting it fall back to the
78
+ // process-global default provider.
79
+ const provider = this.ProviderToUse;
80
+ const detector = new DuplicateRecordDetector(provider);
77
81
  const request = new PotentialDuplicateRequest();
78
82
  request.EntityID = this.EntityID;
79
83
  request.ListID = this.SourceListID || undefined; // Optional — if not set, scans all entity records
80
84
  // Find the first active entity document for this entity to get template/thresholds
81
- const rv = new RunView();
85
+ const rv = new RunView(this.RunViewProviderToUse);
82
86
  const edResult = await rv.RunView({
83
87
  EntityName: 'MJ: Entity Documents',
84
88
  ExtraFilter: `EntityID='${this.EntityID}' AND Status='Active'`,