@memberjunction/core-entities-server 2.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # MemberJunction Core Entities Server
2
+
3
+ Server-side entity subclasses for MemberJunction that provide extended functionality and business logic for core entities when running in a Node.js environment.
4
+
5
+ ## Overview
6
+
7
+ This package contains server-side implementations of MemberJunction entity subclasses that require server-specific functionality such as:
8
+ - Direct database access
9
+ - File system operations
10
+ - Server-side API integrations
11
+ - Complex business logic that should only run on the server
12
+ - Automatic creation/management of related entities
13
+
14
+ ## Purpose
15
+
16
+ While the base `@memberjunction/core-entities` package provides entity classes that work in any JavaScript environment (browser or server), some entity operations require server-specific capabilities. This package provides those extended implementations.
17
+
18
+ ### Key Differences from Core Entities
19
+
20
+ - **Core Entities**: Work everywhere, basic CRUD operations, suitable for client-side usage
21
+ - **Core Entities Server**: Server-only, extended functionality, can directly interact with system resources
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @memberjunction/core-entities-server
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Basic Setup
32
+
33
+ ```typescript
34
+ import { LoadCoreEntitiesServerSubClasses } from '@memberjunction/core-entities-server';
35
+
36
+ // Load all server-side entity subclasses at application startup
37
+ LoadCoreEntitiesServerSubClasses();
38
+ ```
39
+
40
+ **Important**: Call `LoadCoreEntitiesServerSubClasses()` early in your application initialization to ensure the server-side subclasses are registered with the MemberJunction metadata system before any entities are instantiated.
41
+
42
+ ### Example: AI Prompt Entity
43
+
44
+ The package includes an extended AI Prompt entity that automatically manages Template and Template Contents records:
45
+
46
+ ```typescript
47
+ import { Metadata } from '@memberjunction/core';
48
+
49
+ // The metadata system will automatically use the server-side subclass
50
+ const md = new Metadata();
51
+ const aiPrompt = await md.GetEntityObject<AIPromptEntity>('AI Prompts');
52
+
53
+ // Setting TemplateText will automatically create/update Template records
54
+ aiPrompt.TemplateText = `You are a helpful assistant...`;
55
+
56
+ // Save will handle all the Template management automatically
57
+ await aiPrompt.Save();
58
+ ```
59
+
60
+ ## Available Server-Side Entities
61
+
62
+ ### AIPromptEntityExtendedServer
63
+
64
+ Extends the base AI Prompt entity with automatic Template management:
65
+
66
+ - **Virtual Property**: `TemplateText` - A convenient way to get/set the prompt template content
67
+ - **Automatic Template Creation**: Creates Template and Template Contents records when saving
68
+ - **Automatic Template Updates**: Updates existing templates when content changes
69
+ - **Proper Relationship Management**: Maintains proper foreign key relationships
70
+
71
+ ## Architecture
72
+
73
+ ### Entity Registration
74
+
75
+ The package uses MemberJunction's entity subclassing system:
76
+
77
+ 1. At startup, `LoadCoreEntitiesServerSubClasses()` is called
78
+ 2. This registers all server-side entity subclasses with the metadata system
79
+ 3. When code requests an entity (e.g., "AI Prompts"), the metadata system returns the server-side subclass
80
+ 4. The server-side subclass extends the base entity with additional functionality
81
+
82
+ ### Virtual Properties
83
+
84
+ Server-side entities can expose virtual properties that don't exist in the database but provide convenient access to complex data:
85
+
86
+ ```typescript
87
+ export class AIPromptEntityExtendedServer extends AIPromptEntity {
88
+ private _TemplateText?: string;
89
+
90
+ get TemplateText(): string | undefined {
91
+ return this._TemplateText;
92
+ }
93
+
94
+ set TemplateText(value: string | undefined) {
95
+ this._TemplateText = value;
96
+ }
97
+ }
98
+ ```
99
+
100
+ ## Development Guidelines
101
+
102
+ ### Creating New Server-Side Entities
103
+
104
+ 1. Create a new file in `src/custom/`
105
+ 2. Import and extend the base entity class
106
+ 3. Add server-specific functionality
107
+ 4. Register the subclass in the loader
108
+
109
+ Example:
110
+
111
+ ```typescript
112
+ import { BaseEntity, RegisterClass } from '@memberjunction/core';
113
+ import { UserEntity } from '@memberjunction/core-entities';
114
+
115
+ @RegisterClass(BaseEntity, 'Users')
116
+ export class UserEntityExtendedServer extends UserEntity {
117
+ async BeforeSave(): Promise<boolean> {
118
+ // Server-side validation or processing
119
+ if (this.Email) {
120
+ // Verify email domain against company whitelist
121
+ const validDomain = await this.checkEmailDomain(this.Email);
122
+ if (!validDomain) {
123
+ throw new Error('Invalid email domain');
124
+ }
125
+ }
126
+ return super.BeforeSave();
127
+ }
128
+
129
+ private async checkEmailDomain(email: string): Promise<boolean> {
130
+ // Server-side logic to validate email domain
131
+ return true;
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### Best Practices
137
+
138
+ 1. **Keep It Server-Side**: Only include code that must run on the server
139
+ 2. **Extend, Don't Replace**: Always extend the base entity class, don't replace core functionality
140
+ 3. **Handle Errors Gracefully**: Server-side operations can fail - handle errors appropriately
141
+ 4. **Document Virtual Properties**: Clearly document any virtual properties and their behavior
142
+ 5. **Test Thoroughly**: Server-side logic can be complex - ensure comprehensive testing
143
+
144
+ ## Integration with Other MJ Packages
145
+
146
+ This package works seamlessly with:
147
+
148
+ - `@memberjunction/core`: Provides the base entity system
149
+ - `@memberjunction/core-entities`: Provides the base entity classes
150
+ - `@memberjunction/server`: Can be used in MJ server applications
151
+ - `@memberjunction/cli`: Used by CLI tools like MetadataSync
152
+
153
+ ## Common Use Cases
154
+
155
+ ### 1. Automatic Related Entity Management
156
+ ```typescript
157
+ // AI Prompts automatically manage their Template records
158
+ const prompt = await md.GetEntityObject<AIPromptEntity>('AI Prompts');
159
+ prompt.TemplateText = "New prompt content";
160
+ await prompt.Save(); // Template and Template Contents created/updated automatically
161
+ ```
162
+
163
+ ### 2. Server-Side Validation
164
+ ```typescript
165
+ @RegisterClass(BaseEntity, 'Documents')
166
+ export class DocumentEntityServer extends DocumentEntity {
167
+ async BeforeSave(): Promise<boolean> {
168
+ // Scan document for viruses using server-side scanner
169
+ if (this.Content) {
170
+ const isSafe = await virusScanner.scan(this.Content);
171
+ if (!isSafe) {
172
+ throw new Error('Document failed security scan');
173
+ }
174
+ }
175
+ return super.BeforeSave();
176
+ }
177
+ }
178
+ ```
179
+
180
+ ### 3. Complex Business Logic
181
+ ```typescript
182
+ @RegisterClass(BaseEntity, 'Orders')
183
+ export class OrderEntityServer extends OrderEntity {
184
+ async AfterSave(): Promise<boolean> {
185
+ // Send order to fulfillment system
186
+ await fulfillmentAPI.submitOrder(this);
187
+
188
+ // Update inventory
189
+ await inventorySystem.decrementStock(this.OrderItems);
190
+
191
+ return super.AfterSave();
192
+ }
193
+ }
194
+ ```
195
+
196
+ ## Troubleshooting
197
+
198
+ ### Entity subclass not being used
199
+ Ensure `LoadCoreEntitiesServerSubClasses()` is called before any entity instantiation.
200
+
201
+ ### Module loading errors
202
+ This package uses CommonJS. Ensure your Node.js application is configured to handle CommonJS modules.
203
+
204
+ ### Virtual properties not persisting
205
+ Virtual properties are not saved to the database. Use them as convenient accessors that manage real database fields behind the scenes.
206
+
207
+ ## Future Enhancements
208
+
209
+ - Additional server-side entity implementations
210
+ - Integration with file storage providers
211
+ - Advanced caching mechanisms
212
+ - Batch processing utilities
213
+ - Background job integration
214
+
215
+ ## Contributing
216
+
217
+ When contributing new server-side entities:
218
+
219
+ 1. Follow the existing patterns
220
+ 2. Document all virtual properties
221
+ 3. Include comprehensive tests
222
+ 4. Ensure no client-side dependencies
223
+ 5. Update this README with new entities
224
+
225
+ ## License
226
+
227
+ This package is part of the MemberJunction open-source project.
@@ -0,0 +1,93 @@
1
+ import { EntitySaveOptions, IMetadataProvider, TransactionGroupBase } from "@memberjunction/core";
2
+ import { TemplateEntity, AIPromptEntityExtended } from "@memberjunction/core-entities";
3
+ /**
4
+ * Server specific sub-class that handles the automatic creation and updating of
5
+ * Templates and Template Contents entity records linked to the AI Prompt.
6
+ * This class extends the AIPromptEntityExtended class and overrides the Save() method and
7
+ * also provides additional utility functionality that is used within Save() and can be overridden
8
+ * by subclasses to provide custom logic for creating or updating the linked Template and Template Contents, etc.
9
+ */
10
+ export declare class AIPromptEntityExtendedServer extends AIPromptEntityExtended {
11
+ /**
12
+ * private property to hold the template text.
13
+ */
14
+ private _templateText;
15
+ /**
16
+ * Virtual property to hold the template text.
17
+ * This property is used to create or update the Template and Template Contents entity records automatically
18
+ * whenever the AIPrompt is saved.
19
+ */
20
+ get TemplateText(): string;
21
+ set TemplateText(value: string);
22
+ private static _templateContentTypeID;
23
+ /**
24
+ * The Template Content Type ID that will be used for creating new Template Contents
25
+ * linked to this AI Prompt. This is automatically set the first time the AI Prompt is saved
26
+ * and can be manually set ahead of that if desired to a different Template Content Types ID
27
+ */
28
+ static get TemplateContentTypeID(): string | null;
29
+ static set TemplateContentTypeID(value: string | null);
30
+ private static _rootTemplateCategoryID;
31
+ /**
32
+ * The root category ID in the Template Categories entity that will be used for creating new
33
+ * templates linked to this AI Prompt. The way it works is we automatically create new sub-categories
34
+ * of the root category for each AI Prompt Category. Those sub-categories are below the
35
+ * root category. If RootTemplateCategoryID is null when the first such operation occurs upon
36
+ * Save() of a given AIPrompt in a given process space, we will load a category with the name
37
+ * of "AI Prompts" and use that as the root category ID. If such a category does not exist, we will
38
+ * create it automatically.
39
+ * @returns {string | null} The root template category ID or null if not set.
40
+ * @static
41
+ */
42
+ static get RootTemplateCategoryID(): string | null;
43
+ static set RootTemplateCategoryID(value: string | null);
44
+ /**
45
+ * This internal method can be overriden by subclasses
46
+ * to provide a custom way of getting or creating the root template category ID.
47
+ * The default implementation checks if the RootTemplateCategoryID is set, and
48
+ * if not, it attempts to find a category with the name "AI Prompts" (or you can override
49
+ * this with a Setting in the AI Prompts entity called "Root Template Category Name").
50
+ * If such a category does not exist, it creates one and sets the RootTemplateCategoryID.
51
+ * @returns {string} The root template category ID.
52
+ * @protected
53
+ */
54
+ protected getOrCreateRootTemplateCategoryID(): Promise<string>;
55
+ /**
56
+ * This method creates a new root template category with the given name.
57
+ * It will create a new Template Category entity record and return its ID.
58
+ * @param name The name of the root template category to create.
59
+ * @returns {string} The ID of the newly created root template category.
60
+ * @protected
61
+ */
62
+ protected createRootTemplateCategory(name: string): Promise<string>;
63
+ /**
64
+ * The reason for this override is to automatically create and update Templates and Template Contents
65
+ * entity records that are linked to this AI Prompt. The logic works like this:
66
+ * 1. If the TemplateID is null (initial state), and the TemplateText virtual property is not empty, a new Templates entity record and a new Template Contents entity record will be created and linked to this record's TemplateID property.
67
+ * 2. If the TemplateID is not null, the TemplateText changing will result in the linked Template Contents (via the TemplateID) being updated.
68
+ * @param options
69
+ */
70
+ Save(options?: EntitySaveOptions): Promise<boolean>;
71
+ /**
72
+ * This internal method is used to update the linked Template Contents entity record and can
73
+ * be overridden by subclasses to provide custom logic for updating the Template Contents.
74
+ * @param md
75
+ * @param tg
76
+ * @returns
77
+ */
78
+ protected UpdateLinkedTemplateContents(md: IMetadataProvider, tg?: TransactionGroupBase): Promise<void>;
79
+ /**
80
+ * This method is used to create a linked Template record and Template Contents record for this AI Prompt.
81
+ * It is called automatically when the AI Prompt is saved and the TemplateID is null.
82
+ * It can be overridden by subclasses to provide custom logic for creating the linked Template.
83
+ * @returns {Promise<TemplateEntity | null>} The created Template entity record or null if not created.
84
+ */
85
+ protected CreateLinkedTemplateAndTemplateContents(md: IMetadataProvider): Promise<TemplateEntity | null>;
86
+ /**
87
+ * This method retrieves the Template Content Type ID that will be used for creating new Template Contents
88
+ * @returns
89
+ */
90
+ protected getTemplateContentTypeID(): Promise<string>;
91
+ }
92
+ export declare function LoadAIPromptEntityExtendedServerSubClass(): void;
93
+ //# sourceMappingURL=AIPromptEntityExtended.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AIPromptEntityExtended.server.d.ts","sourceRoot":"","sources":["../../src/custom/AIPromptEntityExtended.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,iBAAiB,EAAE,iBAAiB,EAA6B,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEzI,OAAO,EAA4E,cAAc,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEjK;;;;;;GAMG;AACH,qBACa,4BAA6B,SAAQ,sBAAsB;IACpE;;OAEG;IACH,OAAO,CAAC,aAAa,CAAc;IACnC;;;;OAIG;IACH,IAAW,YAAY,IAAI,MAAM,CAEhC;IACD,IAAW,YAAY,CAAC,KAAK,EAAE,MAAM,EAEpC;IAED,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAuB;IAC5D;;;;OAIG;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;;;;;;;;;;OAUG;IACH,WAAkB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAExD;IACD,WAAkB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAE5D;IAED;;;;;;;;;OASG;cACa,iCAAiC,IAAI,OAAO,CAAC,MAAM,CAAC;IA0BpE;;;;;;OAMG;cACa,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBzE;;;;;;OAMG;IACY,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBlE;;;;;;OAMG;cACa,4BAA4B,CAAC,EAAE,EAAE,iBAAiB,EAAE,EAAE,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C7G;;;;;OAKG;cACa,uCAAuC,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA8B9G;;;OAGG;cACa,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC;CAoB9D;AAGD,wBAAgB,wCAAwC,SAAK"}
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var AIPromptEntityExtendedServer_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.LoadAIPromptEntityExtendedServerSubClass = exports.AIPromptEntityExtendedServer = void 0;
11
+ const core_1 = require("@memberjunction/core");
12
+ const global_1 = require("@memberjunction/global");
13
+ const core_entities_1 = require("@memberjunction/core-entities");
14
+ /**
15
+ * Server specific sub-class that handles the automatic creation and updating of
16
+ * Templates and Template Contents entity records linked to the AI Prompt.
17
+ * This class extends the AIPromptEntityExtended class and overrides the Save() method and
18
+ * also provides additional utility functionality that is used within Save() and can be overridden
19
+ * by subclasses to provide custom logic for creating or updating the linked Template and Template Contents, etc.
20
+ */
21
+ let AIPromptEntityExtendedServer = AIPromptEntityExtendedServer_1 = class AIPromptEntityExtendedServer extends core_entities_1.AIPromptEntityExtended {
22
+ constructor() {
23
+ super(...arguments);
24
+ /**
25
+ * private property to hold the template text.
26
+ */
27
+ this._templateText = "";
28
+ }
29
+ /**
30
+ * Virtual property to hold the template text.
31
+ * This property is used to create or update the Template and Template Contents entity records automatically
32
+ * whenever the AIPrompt is saved.
33
+ */
34
+ get TemplateText() {
35
+ return this._templateText;
36
+ }
37
+ set TemplateText(value) {
38
+ this._templateText = value;
39
+ }
40
+ /**
41
+ * The Template Content Type ID that will be used for creating new Template Contents
42
+ * linked to this AI Prompt. This is automatically set the first time the AI Prompt is saved
43
+ * and can be manually set ahead of that if desired to a different Template Content Types ID
44
+ */
45
+ static get TemplateContentTypeID() {
46
+ return this._templateContentTypeID;
47
+ }
48
+ static set TemplateContentTypeID(value) {
49
+ this._templateContentTypeID = value;
50
+ }
51
+ /**
52
+ * The root category ID in the Template Categories entity that will be used for creating new
53
+ * templates linked to this AI Prompt. The way it works is we automatically create new sub-categories
54
+ * of the root category for each AI Prompt Category. Those sub-categories are below the
55
+ * root category. If RootTemplateCategoryID is null when the first such operation occurs upon
56
+ * Save() of a given AIPrompt in a given process space, we will load a category with the name
57
+ * of "AI Prompts" and use that as the root category ID. If such a category does not exist, we will
58
+ * create it automatically.
59
+ * @returns {string | null} The root template category ID or null if not set.
60
+ * @static
61
+ */
62
+ static get RootTemplateCategoryID() {
63
+ return this._rootTemplateCategoryID;
64
+ }
65
+ static set RootTemplateCategoryID(value) {
66
+ this._rootTemplateCategoryID = value;
67
+ }
68
+ /**
69
+ * This internal method can be overriden by subclasses
70
+ * to provide a custom way of getting or creating the root template category ID.
71
+ * The default implementation checks if the RootTemplateCategoryID is set, and
72
+ * if not, it attempts to find a category with the name "AI Prompts" (or you can override
73
+ * this with a Setting in the AI Prompts entity called "Root Template Category Name").
74
+ * If such a category does not exist, it creates one and sets the RootTemplateCategoryID.
75
+ * @returns {string} The root template category ID.
76
+ * @protected
77
+ */
78
+ async getOrCreateRootTemplateCategoryID() {
79
+ if (AIPromptEntityExtendedServer_1.RootTemplateCategoryID) {
80
+ return AIPromptEntityExtendedServer_1.RootTemplateCategoryID;
81
+ }
82
+ // look for an existing root level category with the name "AI Prompts"
83
+ const e = this.EntityInfo;
84
+ const catName = e.Settings.find(s => s.Name.trim().toLowerCase() ===
85
+ "Root Template Category Name")?.Value || "AI Prompts";
86
+ const rv = new core_1.RunView(this.ProviderToUse);
87
+ const result = await rv.RunView({
88
+ EntityName: "Template Categories",
89
+ ExtraFilter: `Name='${catName}' AND ParentID IS NULL`,
90
+ OrderBy: "__mj_CreatedAt ASC" // first one
91
+ }, this.ContextCurrentUser);
92
+ if (result && result.Success && result.Results.length > 0) {
93
+ // we found an existing root category, cache it and return it
94
+ AIPromptEntityExtendedServer_1.RootTemplateCategoryID = result.Results[0].ID;
95
+ return AIPromptEntityExtendedServer_1.RootTemplateCategoryID;
96
+ }
97
+ else {
98
+ // we did not find an existing root category, so create one
99
+ return await this.createRootTemplateCategory(catName);
100
+ }
101
+ }
102
+ /**
103
+ * This method creates a new root template category with the given name.
104
+ * It will create a new Template Category entity record and return its ID.
105
+ * @param name The name of the root template category to create.
106
+ * @returns {string} The ID of the newly created root template category.
107
+ * @protected
108
+ */
109
+ async createRootTemplateCategory(name) {
110
+ const md = this.ProviderToUse;
111
+ const rootCategory = await md.GetEntityObject("Template Categories", this.ContextCurrentUser);
112
+ rootCategory.NewRecord();
113
+ rootCategory.Name = name;
114
+ rootCategory.Description = "Root category for AI Prompts (Auto-Created by AI Prompts Entity)";
115
+ rootCategory.UserID = this.ContextCurrentUser.ID;
116
+ // save the category
117
+ if (rootCategory.Save()) {
118
+ AIPromptEntityExtendedServer_1.RootTemplateCategoryID = rootCategory.ID;
119
+ return AIPromptEntityExtendedServer_1.RootTemplateCategoryID;
120
+ }
121
+ else {
122
+ // this is an error state, we failed to create the root category
123
+ throw new Error(`Failed to create root template category with name '${name}'. Please check the logs for more details.`);
124
+ }
125
+ }
126
+ /**
127
+ * The reason for this override is to automatically create and update Templates and Template Contents
128
+ * entity records that are linked to this AI Prompt. The logic works like this:
129
+ * 1. If the TemplateID is null (initial state), and the TemplateText virtual property is not empty, a new Templates entity record and a new Template Contents entity record will be created and linked to this record's TemplateID property.
130
+ * 2. If the TemplateID is not null, the TemplateText changing will result in the linked Template Contents (via the TemplateID) being updated.
131
+ * @param options
132
+ */
133
+ async Save(options) {
134
+ const md = this.ProviderToUse;
135
+ // now do the work of creating or updating the Template and Template Contents
136
+ if (this.TemplateID === null && this.TemplateText?.trim().length > 0) {
137
+ const template = await this.CreateLinkedTemplateAndTemplateContents(md);
138
+ if (template) {
139
+ this.TemplateID = template.ID; // link the Template to this AI Prompt
140
+ }
141
+ }
142
+ else if (this.TemplateID && this.TemplateText?.trim().length > 0) {
143
+ // we have a linked Template, so update the Template Contents associated with it
144
+ await this.UpdateLinkedTemplateContents(md);
145
+ }
146
+ // now save the AI Prompt itself
147
+ return await super.Save(options);
148
+ }
149
+ /**
150
+ * This internal method is used to update the linked Template Contents entity record and can
151
+ * be overridden by subclasses to provide custom logic for updating the Template Contents.
152
+ * @param md
153
+ * @param tg
154
+ * @returns
155
+ */
156
+ async UpdateLinkedTemplateContents(md, tg) {
157
+ // we have a linked Template, so update the Template Contents associated with it
158
+ if (!this.TemplateID) {
159
+ throw new Error("Cannot update linked Template Contents because TemplateID is null.");
160
+ }
161
+ const rv = new core_1.RunView(this.ProviderToUse);
162
+ const result = await rv.RunView({
163
+ EntityName: "Template Contents",
164
+ ExtraFilter: `TemplateID='${this.TemplateID}'`,
165
+ OrderBy: "__mj_CreatedAt ASC", // first one
166
+ ResultType: 'entity_object',
167
+ MaxRows: 1 // should only be one row
168
+ }, this.ContextCurrentUser);
169
+ let tc = undefined;
170
+ if (result && result.Success && result.Results.length > 0) {
171
+ // we found an existing Template Content, so update it
172
+ tc = result.Results[0];
173
+ }
174
+ else {
175
+ tc = await md.GetEntityObject("Template Contents", this.ContextCurrentUser);
176
+ tc.NewRecord();
177
+ tc.TemplateID = this.TemplateID; // link to the existing Template
178
+ tc.TypeID = await this.getTemplateContentTypeID(); // use the Template Content Type ID for AI Prompts
179
+ tc.Priority = 1; // default priority
180
+ tc.IsActive = true; // set it to active by default
181
+ }
182
+ // for both new and existing Template Contents, we set the Template Text
183
+ tc.TemplateText = this.TemplateText; // set the Template Text
184
+ if (tg) {
185
+ tc.TransactionGroup = tg; // link to the transaction group if provided
186
+ }
187
+ // now save the Template Contents
188
+ if (await tc.Save()) {
189
+ // if we saved successfully, we can return
190
+ return;
191
+ }
192
+ else {
193
+ // if we failed to save, throw an error
194
+ throw new Error("Failed to update linked Template Contents for the AI Prompt.");
195
+ }
196
+ }
197
+ /**
198
+ * This method is used to create a linked Template record and Template Contents record for this AI Prompt.
199
+ * It is called automatically when the AI Prompt is saved and the TemplateID is null.
200
+ * It can be overridden by subclasses to provide custom logic for creating the linked Template.
201
+ * @returns {Promise<TemplateEntity | null>} The created Template entity record or null if not created.
202
+ */
203
+ async CreateLinkedTemplateAndTemplateContents(md) {
204
+ // we have no linked template, but we have template text, so create a new template and template contents
205
+ const t = await md.GetEntityObject("Templates", this.ContextCurrentUser);
206
+ t.NewRecord();
207
+ t.Name = this.Name; // propagate the name
208
+ t.Description = "Template for AI Prompt: " + this.Name;
209
+ t.UserID = this.ContextCurrentUser.ID;
210
+ t.CategoryID = await this.getOrCreateRootTemplateCategoryID();
211
+ t.IsActive = true;
212
+ if (await t.Save()) {
213
+ // now create the template contents
214
+ const tc = await md.GetEntityObject("Template Contents", this.ContextCurrentUser);
215
+ tc.NewRecord();
216
+ tc.TemplateID = t.ID;
217
+ tc.TypeID = await this.getTemplateContentTypeID();
218
+ tc.TemplateText = this.TemplateText;
219
+ tc.Priority = 1; // default priority
220
+ tc.IsActive = true;
221
+ if (await tc.Save()) {
222
+ return t;
223
+ }
224
+ else {
225
+ throw new Error("Failed to save Template Contents for the new Template.");
226
+ }
227
+ }
228
+ else {
229
+ throw new Error("Failed to save new Template for the AI Prompt.");
230
+ }
231
+ }
232
+ /**
233
+ * This method retrieves the Template Content Type ID that will be used for creating new Template Contents
234
+ * @returns
235
+ */
236
+ async getTemplateContentTypeID() {
237
+ if (AIPromptEntityExtendedServer_1.TemplateContentTypeID) {
238
+ return AIPromptEntityExtendedServer_1.TemplateContentTypeID;
239
+ }
240
+ // we will use the TemplateEntityType for AI Prompts
241
+ const rv = this.ProviderToUse;
242
+ const result = await rv.RunView({
243
+ EntityName: "Template Content Types",
244
+ ExtraFilter: "Name='Text'",
245
+ OrderBy: "__mj_CreatedAt ASC" // first one
246
+ }, this.ContextCurrentUser);
247
+ if (result && result.Success && result.Results.length > 0) {
248
+ // we found a Template Content Type, return its ID but cache it first
249
+ AIPromptEntityExtendedServer_1.TemplateContentTypeID = result.Results[0].ID;
250
+ return result.Results[0].ID;
251
+ }
252
+ else {
253
+ throw new Error("Failed to find Template Content Type ID (Text) for AI Prompts.");
254
+ }
255
+ }
256
+ };
257
+ exports.AIPromptEntityExtendedServer = AIPromptEntityExtendedServer;
258
+ AIPromptEntityExtendedServer._templateContentTypeID = null;
259
+ AIPromptEntityExtendedServer._rootTemplateCategoryID = null;
260
+ exports.AIPromptEntityExtendedServer = AIPromptEntityExtendedServer = AIPromptEntityExtendedServer_1 = __decorate([
261
+ (0, global_1.RegisterClass)(core_1.BaseEntity, "AI Prompts")
262
+ ], AIPromptEntityExtendedServer);
263
+ function LoadAIPromptEntityExtendedServerSubClass() { }
264
+ exports.LoadAIPromptEntityExtendedServerSubClass = LoadAIPromptEntityExtendedServerSubClass;
265
+ //# sourceMappingURL=AIPromptEntityExtended.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AIPromptEntityExtended.server.js","sourceRoot":"","sources":["../../src/custom/AIPromptEntityExtended.server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { DuplicateRunEntity } from "@memberjunction/core-entities";
2
+ export declare class DuplicateRunEntity_Server extends DuplicateRunEntity {
3
+ Save(): Promise<boolean>;
4
+ }
5
+ export declare function LoadDuplicateRunEntityServerSubClass(): void;
6
+ //# sourceMappingURL=DuplicateRunEntity.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DuplicateRunEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/DuplicateRunEntity.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,qBACa,yBAA0B,SAAQ,kBAAkB;IAChD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAiBxC;AAED,wBAAgB,oCAAoC,SAAK"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LoadDuplicateRunEntityServerSubClass = exports.DuplicateRunEntity_Server = void 0;
10
+ const core_1 = require("@memberjunction/core");
11
+ const global_1 = require("@memberjunction/global");
12
+ const core_entities_1 = require("@memberjunction/core-entities");
13
+ const ai_vector_dupe_1 = require("@memberjunction/ai-vector-dupe");
14
+ let DuplicateRunEntity_Server = class DuplicateRunEntity_Server extends core_entities_1.DuplicateRunEntity {
15
+ async Save() {
16
+ const saveResult = await super.Save();
17
+ if (saveResult && this.EndedAt === null) {
18
+ // do something
19
+ const duplicateRecordDetector = new ai_vector_dupe_1.DuplicateRecordDetector();
20
+ let request = new core_1.PotentialDuplicateRequest();
21
+ request.EntityID = this.EntityID;
22
+ request.ListID = this.SourceListID;
23
+ request.Options = {
24
+ DuplicateRunID: this.ID,
25
+ };
26
+ const response = await duplicateRecordDetector.getDuplicateRecords(request, this.ContextCurrentUser);
27
+ }
28
+ return saveResult;
29
+ }
30
+ };
31
+ exports.DuplicateRunEntity_Server = DuplicateRunEntity_Server;
32
+ exports.DuplicateRunEntity_Server = DuplicateRunEntity_Server = __decorate([
33
+ (0, global_1.RegisterClass)(core_1.BaseEntity, 'Duplicate Runs')
34
+ ], DuplicateRunEntity_Server);
35
+ function LoadDuplicateRunEntityServerSubClass() { }
36
+ exports.LoadDuplicateRunEntityServerSubClass = LoadDuplicateRunEntityServerSubClass;
37
+ //# sourceMappingURL=DuplicateRunEntity.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DuplicateRunEntity.server.js","sourceRoot":"","sources":["../../src/custom/DuplicateRunEntity.server.ts"],"names":[],"mappings":";;;;;;;;;AAAA,+CAA6E;AAC7E,mDAAuD;AACvD,iEAAmE;AACnE,mEAAyE;AAGlE,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,kCAAkB;IACtD,KAAK,CAAC,IAAI;QACb,MAAM,UAAU,GAAY,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,UAAU,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YACtC,eAAe;YACf,MAAM,uBAAuB,GAA4B,IAAI,wCAAuB,EAAE,CAAC;YACvF,IAAI,OAAO,GAA8B,IAAI,gCAAyB,EAAE,CAAC;YACzE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC;YACnC,OAAO,CAAC,OAAO,GAAG;gBACd,cAAc,EAAE,IAAI,CAAC,EAAE;aAC1B,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACzG,CAAC;QAED,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ,CAAA;AAlBY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,sBAAa,EAAC,iBAAU,EAAE,gBAAgB,CAAC;GAC/B,yBAAyB,CAkBrC;AAED,SAAgB,oCAAoC,KAAI,CAAC;AAAzD,oFAAyD"}
@@ -0,0 +1,11 @@
1
+ import { ReportEntity } from "@memberjunction/core-entities";
2
+ export declare class ReportEntity_Server extends ReportEntity {
3
+ /**
4
+ * The server side Report Entity sub-class has a simple logic that will create a snapshot of the report when it is first created and each time it is modified, but only
5
+ * if it is either newly created or if the Configuration field has changed.
6
+ * @returns
7
+ */
8
+ Save(): Promise<boolean>;
9
+ }
10
+ export declare function LoadReportEntityServerSubClass(): void;
11
+ //# sourceMappingURL=reportEntity.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reportEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/reportEntity.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAA6C,MAAM,+BAA+B,CAAC;AAGxG,qBACa,mBAAoB,SAAQ,YAAY;IACjD;;;;OAIG;IACU,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAmHxC;AAED,wBAAgB,8BAA8B,SAAK"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LoadReportEntityServerSubClass = exports.ReportEntity_Server = void 0;
10
+ const core_1 = require("@memberjunction/core");
11
+ const global_1 = require("@memberjunction/global");
12
+ const core_entities_1 = require("@memberjunction/core-entities");
13
+ let ReportEntity_Server = class ReportEntity_Server extends core_entities_1.ReportEntity {
14
+ /**
15
+ * The server side Report Entity sub-class has a simple logic that will create a snapshot of the report when it is first created and each time it is modified, but only
16
+ * if it is either newly created or if the Configuration field has changed.
17
+ * @returns
18
+ */
19
+ async Save() {
20
+ try {
21
+ // first let's get the actual parsed object for the Configuration field
22
+ const config = this.Configuration && this.Configuration.length > 0 ? (0, global_1.SafeJSONParse)(this.Configuration) : null;
23
+ const oldTextConfig = this.GetFieldByName('Configuration')?.OldValue;
24
+ const oldConfig = oldTextConfig && oldTextConfig.length > 0 ? (0, global_1.SafeJSONParse)(oldTextConfig) : null;
25
+ if ((config && oldConfig) || (config && !this.IsSaved)) {
26
+ let createSnapshot = false;
27
+ let createReportVersion = false;
28
+ if (this.IsSaved) {
29
+ // existing record
30
+ // we nave a configuration and an old configuration, so we can compare them, cast them to their strong types first
31
+ const castedConfig = config;
32
+ const castedOldConfig = oldConfig;
33
+ // Next, we need to see if the data context has changed at all. We do this by comparing the # of items in the data context. a Data context's items are immutable and we only add new Data Context Items
34
+ // so we can simply check to see if we have new data context items or not
35
+ const dataContextChanged = Object.keys(castedConfig.dataContext || {})?.length !== Object.keys(castedOldConfig.dataContext || {})?.length;
36
+ // next up, we check to see if anything in the execution results changed. The simple way to do that is convert the execution results back to a string and compare those strings
37
+ const executionResultsChanged = JSON.stringify(castedConfig.executionResults) !== JSON.stringify(castedOldConfig.executionResults);
38
+ // next up we check to see if the analysis changed, which would also represent a "data" change
39
+ const analysisChanged = castedConfig.analysis !== castedOldConfig.analysis;
40
+ // finally, we check to see if the configuration itself has OUTSIDE of the data elements we just checked. We do that by deleting those properties from those objects, converting to strings
41
+ // and comparing them
42
+ delete castedConfig.dataContext;
43
+ delete castedConfig.analysis;
44
+ delete castedConfig.executionResults;
45
+ delete castedOldConfig.dataContext;
46
+ delete castedOldConfig.executionResults;
47
+ delete castedOldConfig.analysis;
48
+ // we can now compare the two objects
49
+ const configChanged = JSON.stringify(castedConfig) !== JSON.stringify(castedOldConfig);
50
+ // now our logic is this - if the DATA changed, but the configuration did NOT change, that means we want to create a new SNAPSHOT of the report - which is the data changing side
51
+ // if the configuration changed at all we wnat to create a new Report Version. Sometimes both changd and we do both
52
+ createSnapshot = dataContextChanged || executionResultsChanged || analysisChanged;
53
+ createReportVersion = configChanged;
54
+ }
55
+ else {
56
+ // we have a new record set createSnapshot to true and createReportVersion to true
57
+ createSnapshot = true;
58
+ createReportVersion = true;
59
+ }
60
+ const wasNewRecord = !this.IsSaved;
61
+ const saveResult = await super.Save();
62
+ if (saveResult && (createSnapshot || createReportVersion)) {
63
+ // here we either have a new record or the configuration has changed, so we need to create a snapshot of the report
64
+ let success = true;
65
+ const md = new core_1.Metadata();
66
+ if (createReportVersion) {
67
+ const reportVersion = await md.GetEntityObject('MJ: Report Versions', this.ContextCurrentUser);
68
+ reportVersion.ReportID = this.ID;
69
+ // const get highest new version number already in DB
70
+ let newVersionNumber = 1;
71
+ if (!wasNewRecord) {
72
+ const rv = new core_1.RunView();
73
+ const rvResult = await rv.RunView({
74
+ Fields: ['VersionNumber'],
75
+ EntityName: 'MJ: Report Versions',
76
+ ExtraFilter: `ReportID = '${this.ID}'`,
77
+ MaxRows: 1,
78
+ OrderBy: 'VersionNumber DESC',
79
+ }, this.ContextCurrentUser);
80
+ if (rvResult.Success && rvResult.Results.length > 0) {
81
+ newVersionNumber = parseInt(rvResult.Results[0].VersionNumber) + 1;
82
+ }
83
+ else {
84
+ newVersionNumber = 1; // this is an error state as we previously had a saved report, BUT there were no saved versions for the report, so we are going to use 1 here, but let's log a warning
85
+ console.warn('ReportEntity_Server.Save(): No report versions found for report ID:', this.ID);
86
+ console.warn('ReportEntity_Server.Save(): Using version number 1 for new report version');
87
+ }
88
+ }
89
+ reportVersion.Name = this.Name; // copy current name to the new version
90
+ reportVersion.Description = this.Description; // copy current description to the new version
91
+ reportVersion.VersionNumber = newVersionNumber;
92
+ reportVersion.Configuration = JSON.stringify(this.Configuration);
93
+ success = success && await reportVersion.Save();
94
+ if (!success) {
95
+ console.error('ReportEntity_Server.Save(): Error saving report version\n' + reportVersion.LatestResult.Message);
96
+ }
97
+ }
98
+ if (createSnapshot) {
99
+ const snapshot = await md.GetEntityObject('Report Snapshots', this.ContextCurrentUser);
100
+ snapshot.ReportID = this.ID;
101
+ snapshot.UserID = this.ContextCurrentUser.ID;
102
+ // in the snapshot entity the ResultSet column is the Configuration column from the Report entity
103
+ snapshot.ResultSet = JSON.stringify(this.Configuration);
104
+ success = success && await snapshot.Save();
105
+ }
106
+ return success;
107
+ }
108
+ else {
109
+ return saveResult;
110
+ }
111
+ }
112
+ else {
113
+ // no configuration or no parseable configuration, so we just call super.Save();
114
+ return super.Save();
115
+ }
116
+ }
117
+ catch (e) {
118
+ console.error('Error in ReportEntity_Server.Save():', e);
119
+ return false;
120
+ }
121
+ }
122
+ };
123
+ exports.ReportEntity_Server = ReportEntity_Server;
124
+ exports.ReportEntity_Server = ReportEntity_Server = __decorate([
125
+ (0, global_1.RegisterClass)(core_1.BaseEntity, 'Reports')
126
+ ], ReportEntity_Server);
127
+ function LoadReportEntityServerSubClass() { }
128
+ exports.LoadReportEntityServerSubClass = LoadReportEntityServerSubClass;
129
+ //# sourceMappingURL=reportEntity.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reportEntity.server.js","sourceRoot":"","sources":["../../src/custom/reportEntity.server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { EntityInfo } from "@memberjunction/core";
2
+ import { AIModelEntityExtended, UserViewEntityExtended } from '@memberjunction/core-entities';
3
+ export declare class UserViewEntity_Server extends UserViewEntityExtended {
4
+ /**
5
+ * 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.
6
+ */
7
+ protected get SmartFilterImplemented(): boolean;
8
+ /**
9
+ * Default implementation simply returns 'OpenAI' - override this in your subclass if you are using a different AI vendor.
10
+ * @returns
11
+ */
12
+ protected get AIVendorName(): string;
13
+ /**
14
+ * Default implementation simply grabs the first AI model that matches GetAIModelName().
15
+ * @returns
16
+ */
17
+ protected GetAIModel(): Promise<AIModelEntityExtended>;
18
+ /**
19
+ * This method will use AI to return a valid WHERE clause based on the provided prompt. This is automatically called at the right time if the view has SmartFilterEnabled turned on and the SmartFilterPrompt is set. If you want
20
+ * to call this directly to get back a WHERE clause for other purposes you can call this method directly and provide both a prompt and the entity that the view is based on.
21
+ * @param prompt
22
+ */
23
+ GenerateSmartFilterWhereClause(prompt: string, entityInfo: EntityInfo): Promise<{
24
+ whereClause: string;
25
+ userExplanation: string;
26
+ }>;
27
+ GenerateSysPrompt(entityInfo: EntityInfo): string;
28
+ }
29
+ export declare function LoadUserViewEntityServerSubClass(): void;
30
+ //# sourceMappingURL=userViewEntity.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userViewEntity.server.d.ts","sourceRoot":"","sources":["../../src/custom/userViewEntity.server.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,UAAU,EAAsB,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAiB,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAM5G,qBACa,qBAAsB,SAAQ,sBAAsB;IAC7D;;OAEG;IACH,cAAuB,sBAAsB,IAAI,OAAO,CAEvD;IAED;;;OAGG;IACH,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED;;;OAGG;cACa,UAAU,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAS5D;;;;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;IAuErI,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;CAoH3D;AAGD,wBAAgB,gCAAgC,SAE/C"}
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LoadUserViewEntityServerSubClass = exports.UserViewEntity_Server = void 0;
10
+ const global_1 = require("@memberjunction/global");
11
+ const core_1 = require("@memberjunction/core");
12
+ const core_entities_1 = require("@memberjunction/core-entities");
13
+ const ai_1 = require("@memberjunction/ai");
14
+ const aiengine_1 = require("@memberjunction/aiengine");
15
+ const ai_openai_1 = require("@memberjunction/ai-openai");
16
+ (0, ai_openai_1.LoadOpenAILLM)(); // this is to prevent tree shaking since the openai package is not directly used and rather instantiated dynamically in the LoadOpenAILLM function. Since no static code path exists tree shaking can result in this class being optimized out
17
+ let UserViewEntity_Server = class UserViewEntity_Server extends core_entities_1.UserViewEntityExtended {
18
+ /**
19
+ * 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.
20
+ */
21
+ get SmartFilterImplemented() {
22
+ return true;
23
+ }
24
+ /**
25
+ * Default implementation simply returns 'OpenAI' - override this in your subclass if you are using a different AI vendor.
26
+ * @returns
27
+ */
28
+ get AIVendorName() {
29
+ return 'OpenAI';
30
+ }
31
+ /**
32
+ * Default implementation simply grabs the first AI model that matches GetAIModelName().
33
+ * @returns
34
+ */
35
+ async GetAIModel() {
36
+ await aiengine_1.AIEngine.Instance.Config(false, this.ContextCurrentUser); // most of the time this is already loaded, but just in case it isn't we will load it here
37
+ const models = aiengine_1.AIEngine.Instance.Models.filter(m => m.AIModelType.trim().toLowerCase() === 'llm' &&
38
+ m.Vendor.trim().toLowerCase() === this.AIVendorName.trim().toLowerCase());
39
+ // next, sort the models by the PowerRank field so that the highest power rank model is the first array element
40
+ models.sort((a, b) => b.PowerRank - a.PowerRank); // highest power rank first
41
+ return models[0];
42
+ }
43
+ /**
44
+ * This method will use AI to return a valid WHERE clause based on the provided prompt. This is automatically called at the right time if the view has SmartFilterEnabled turned on and the SmartFilterPrompt is set. If you want
45
+ * to call this directly to get back a WHERE clause for other purposes you can call this method directly and provide both a prompt and the entity that the view is based on.
46
+ * @param prompt
47
+ */
48
+ async GenerateSmartFilterWhereClause(prompt, entityInfo) {
49
+ try {
50
+ const model = await this.GetAIModel();
51
+ const llm = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(ai_1.BaseLLM, model.DriverClass, (0, ai_1.GetAIAPIKey)(model.DriverClass));
52
+ const chatParams = {
53
+ model: model.APINameOrName,
54
+ messages: [
55
+ {
56
+ role: 'system',
57
+ content: this.GenerateSysPrompt(entityInfo)
58
+ },
59
+ {
60
+ role: 'user',
61
+ content: `${prompt}`,
62
+ },
63
+ ],
64
+ };
65
+ const result = await llm.ChatCompletion(chatParams);
66
+ if (result && result.data) {
67
+ const llmResponse = result.data.choices[0].message.content;
68
+ if (llmResponse) {
69
+ // try to parse it as JSON
70
+ try {
71
+ const cleansed = (0, global_1.CleanJSON)(llmResponse);
72
+ if (!cleansed)
73
+ throw new Error('Invalid JSON response from AI: ' + llmResponse);
74
+ const parsed = JSON.parse(cleansed);
75
+ if (parsed.whereClause && parsed.whereClause.length > 0) {
76
+ // we have the where clause. Sometimes the LLM prefixes it with WHERE and somtimes not, we need to strip WHERE if it is there
77
+ const trimmed = parsed.whereClause.trim();
78
+ let ret = '';
79
+ if (trimmed.toLowerCase().startsWith('where '))
80
+ ret = trimmed.substring(6);
81
+ else
82
+ ret = parsed.whereClause;
83
+ return {
84
+ whereClause: ret,
85
+ userExplanation: parsed.userExplanationMessage
86
+ };
87
+ }
88
+ else if (parsed.whereClause !== undefined && parsed.whereClause !== null) {
89
+ return {
90
+ whereClause: '', // empty string is valid, it means no where clause
91
+ userExplanation: parsed.userExplanationMessage
92
+ };
93
+ }
94
+ else {
95
+ // if we get here, no whereClause property was provided by the LLM, that is an error
96
+ throw new Error('Invalid response from AI, no whereClause property found in response: ' + llmResponse);
97
+ }
98
+ }
99
+ catch (e) {
100
+ (0, core_1.LogError)(e);
101
+ throw new Error('Error parsing JSON response from AI: ' + llmResponse);
102
+ }
103
+ }
104
+ else
105
+ throw new Error('Null response from AI');
106
+ }
107
+ else
108
+ throw new Error('No result returned from AI');
109
+ }
110
+ catch (e) {
111
+ (0, core_1.LogError)(e);
112
+ throw e;
113
+ }
114
+ }
115
+ GenerateSysPrompt(entityInfo) {
116
+ const processedViews = [entityInfo.BaseView];
117
+ const md = new core_1.Metadata();
118
+ const listsEntity = md.EntityByName("Lists");
119
+ const listDetailsEntity = md.EntityByName("List Details");
120
+ const gptSysPrompt = `You are an expert in SQL and Microsoft SQL Server.
121
+ You will be provided a user prompt representing how they want to filter the data.
122
+ You may *NOT* use JOINS, only sub-queries for related tables.
123
+
124
+ I am a bot and can only understand JSON. Your response must be parsable into this type:
125
+ const returnType = {
126
+ whereClause: string,
127
+ orderByClause: string
128
+ userExplanationMessage: string
129
+ };
130
+
131
+ In MemberJunction, we have a concept called "Entities" and these are metadata constructs that wrap SQL tables and views. The entity that we are currently
132
+ building a filter for is called "${entityInfo.Name}" and has an ID of "${entityInfo.ID}"
133
+
134
+ You won't be using this Entity name or ID in your SQL, unless you need to use it for List filtering (more on that below).
135
+
136
+ The view that the user is querying is called ${entityInfo.BaseView} and has these fields:
137
+ ${entityInfo.Fields.map(f => {
138
+ let ret = `${f.Name} (${f.Type})`;
139
+ if (f.RelatedEntity) {
140
+ ret += ` (fkey to ${f.RelatedEntityBaseView})`;
141
+ }
142
+ return ret;
143
+ }).join(',')}`;
144
+ const fkeyFields = entityInfo.Fields.filter(f => f.RelatedEntity && f.RelatedEntity.length > 0);
145
+ const fkeyBaseViewsDistinct = fkeyFields.map(f => f.RelatedEntityBaseView).filter((v, i, a) => a.indexOf(v) === i);
146
+ const relationships = `
147
+ In addition, ${entityInfo.BaseView} has links to other views, as shown here, you can use these views in sub-queries to achieve the request from the user.
148
+ If there are multiple filters related to a single related view, attempt to combine them into a single sub-query for efficiency.
149
+ ${
150
+ // this part returns a list of all the related views and the fields that are related to the current view via fkeys in the current view
151
+ fkeyBaseViewsDistinct.map(v => {
152
+ if (processedViews.indexOf(v) === -1) {
153
+ const e = md.Entities.find(e => e.BaseView === v);
154
+ if (e) {
155
+ processedViews.push(v); // already processed this view now, so we won't repeat it
156
+ return `* ${e.SchemaName}.${e.BaseView}: ${e.Fields.map(ef => {
157
+ return ef.Name + ' (' + ef.Type + ')';
158
+ }).join(',')}`;
159
+ }
160
+ else
161
+ return '';
162
+ }
163
+ else
164
+ return ''; // already did this at some point
165
+ }).join('\n')}
166
+ ${
167
+ // this part returns a list of all the related views and the fields that are related to the current view fkeys in THOSE views
168
+ entityInfo.RelatedEntities.map(r => {
169
+ const e = md.Entities.find(e => e.Name === r.RelatedEntity);
170
+ if (e) {
171
+ if (processedViews.indexOf(e.BaseView) === -1) {
172
+ processedViews.push(e.BaseView); // note that we are processing this view now, so we won't repeat it
173
+ return `* ${e.SchemaName}.${e.BaseView}: ${e.Fields.map(ef => {
174
+ let ret = `${ef.Name} (${ef.Type})`;
175
+ if (ef.RelatedEntity) {
176
+ ret += ` (fkey to ${ef.RelatedEntityBaseView})`;
177
+ }
178
+ return ret;
179
+ }).join(',')}`;
180
+ }
181
+ else
182
+ return ''; // already did this at some point
183
+ }
184
+ else
185
+ return '';
186
+ }).join('\n')}
187
+
188
+ <IMPORTANT - LISTS FEATURE>
189
+ In addition to the above related views, a user may talk about "Lists" in their request. A List is a static set of records modeled in our database with the ${listsEntity.SchemaName}.vwLists view and
190
+ the ${listsEntity.SchemaName}.vwListDetails view. ${listsEntity.SchemaName}.vwLists contains the list "header" information with these columns:
191
+ ${listsEntity.Fields.map(f => {
192
+ return f.Name + ' (' + f.SQLFullType + ')';
193
+ }).join(', ')}
194
+ The vwListDetails view contains the list "detail" information with these columns which is basically the records that are part of the list. ${listsEntity.SchemaName}.vwListDetails contains these columns:
195
+ ${listDetailsEntity.Fields.map(f => {
196
+ return f.Name + ' (' + f.SQLFullType + ')';
197
+ }).join(', ')}.
198
+
199
+ If a user is asking to use a list in creating a view, you need to use a sub-query along these lines:
200
+
201
+ ID IN (SELECT RecordID FROM ${listsEntity.SchemaName}.vwListDetails WHERE ListID='My List ID')
202
+
203
+ In this example we're assuming the user has asked us to filter to include only records that are part of the list with the ID of 'My List ID'. In reality the prompt you will have will have a UUID/GUID type ID not a text string like this.
204
+ You can use any fields at the detail level filter the records and of course combine this type of list-oriented sub-query with other filters as appropriate to satisfy the user's request.
205
+
206
+ It is also possible that a user will provide ONLY the name of the list they want to filter on. If they provide the List ID, use it with a query like the above. However, if ONLY a List name is provided, you can do as follows: use this style of query with a join to the vwLists view (the list "header") to filter on the name
207
+ of the view or other header information if they want to filter on other list header attributes you can do this. Here is an example:
208
+
209
+ ID IN (SELECT ld.RecordID FROM ${listsEntity.SchemaName}.vwListDetails ld INNER JOIN ${listsEntity.SchemaName}.vwLists l ON ld.ListID=l.ID WHERE l.Name='My List Name')
210
+
211
+ No need to use table aliasing if you're just using the vwListDetails view, in that simple subquery it is automatic and unnecessary. If you need to join to the vwLists view, you can use the aliases "l" and "ld", as shown in the example above.
212
+
213
+ </IMPORTANT - LISTS FEATURE>
214
+ <IMPORTANT - OTHER VIEWS>
215
+ The user might reference other "views" in their request. In the user's terminology a view is what we call a "User View" in MemberJunction system-speak. The idea is a user might ask for a filter that includes or excludes
216
+ records from another view. Unlike Lists, which are STATIC sets of records, User Views are dynamic and can change based on the underlying data. So, what we need to do is use a sub-query that pulls in the SQL for the other view
217
+ The user will be referring to the other view by name, so what you need to do when generating SQL for this scenario is to simply embed a sub-query along the lines of this example, updated of course in the context of the user's request and the rest of any filters you are building:
218
+ ID IN ({%UserView "ViewID"%}) -- this is for filtering the primary key using other User Views for this entity: "${entityInfo.Name}"
219
+ AccountID IN ({%UserView "ViewID"%}) -- this is an example where the foreign key relationship for the AccountID field in this entity (${entityInfo.Name}) links to another entity hypothetically called "Accounts" and we want to use an Accounts view for filtering in some way
220
+ By including this sub-query in your generated WHERE clause, it will give me what I need to dynamically replace the {%UserView "View Name"%} with the actual SQL for the view that the user is referring to. Since that actual SQL
221
+ can change over time, I don't want to embed it directly here but rather have it templatized and each time it is run, I will pre-process the SQL to replace the template with the actual SQL for the view.
222
+ </IMPORTANT - OTHER VIEWS>
223
+ `;
224
+ return gptSysPrompt + (processedViews.length > 1 /*we always have 1 from the entity base view*/ ? relationships : '') + `
225
+ **** REMEMBER **** I am a BOT, do not return anything other than JSON to me or I will choke on your response!`;
226
+ }
227
+ };
228
+ exports.UserViewEntity_Server = UserViewEntity_Server;
229
+ exports.UserViewEntity_Server = UserViewEntity_Server = __decorate([
230
+ (0, global_1.RegisterClass)(core_1.BaseEntity, 'User Views')
231
+ ], UserViewEntity_Server);
232
+ function LoadUserViewEntityServerSubClass() {
233
+ }
234
+ exports.LoadUserViewEntityServerSubClass = LoadUserViewEntityServerSubClass;
235
+ //# sourceMappingURL=userViewEntity.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userViewEntity.server.js","sourceRoot":"","sources":["../../src/custom/userViewEntity.server.ts"],"names":[],"mappings":";;;;;;;;;AAAA,mDAA4E;AAC5E,+CAAkF;AAClF,iEAA4G;AAC5G,2CAAsE;AACtE,uDAAoD;AACpD,yDAA0D;AAC1D,IAAA,yBAAa,GAAE,CAAC,CAAC,8OAA8O;AAGxP,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,sCAAsB;IAC7D;;OAEG;IACH,IAAuB,sBAAsB;QACzC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,IAAc,YAAY;QACtB,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED;;;OAGG;IACO,KAAK,CAAC,UAAU;QACtB,MAAM,mBAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,0FAA0F;QAC1J,MAAM,MAAM,GAAG,mBAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK;YACrD,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAA;QACpH,+GAA+G;QAC/G,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,2BAA2B;QAC7E,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,8BAA8B,CAAC,MAAc,EAAE,UAAsB;QAC9E,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,iBAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAU,YAAO,EAAE,KAAK,CAAC,WAAW,EAAE,IAAA,gBAAW,EAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;YAE/H,MAAM,UAAU,GAAe;gBAC3B,KAAK,EAAE,KAAK,CAAC,aAAa;gBAC1B,QAAQ,EAAE;oBACN;wBACI,IAAI,EAAE,QAAQ;wBACd,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC;qBAC9C;oBACD;wBACI,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,GAAG,MAAM,EAAE;qBACvB;iBACJ;aACJ,CAAA;YACD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;YACpD,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBACxB,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC3D,IAAI,WAAW,EAAE,CAAC;oBACd,0BAA0B;oBAC1B,IAAI,CAAC;wBACD,MAAM,QAAQ,GAAG,IAAA,kBAAS,EAAC,WAAW,CAAC,CAAC;wBACxC,IAAI,CAAC,QAAQ;4BACT,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,WAAW,CAAC,CAAC;wBAErE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBACpC,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACtD,6HAA6H;4BAC7H,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;4BAC1C,IAAI,GAAG,GAAW,EAAE,CAAC;4BACrB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gCAC1C,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;;gCAE3B,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;4BAE7B,OAAQ;gCACI,WAAW,EAAE,GAAG;gCAChB,eAAe,EAAE,MAAM,CAAC,sBAAsB;6BACjD,CAAC;wBACd,CAAC;6BACI,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;4BACvE,OAAQ;gCACJ,WAAW,EAAE,EAAE,EAAG,kDAAkD;gCACpE,eAAe,EAAE,MAAM,CAAC,sBAAsB;6BACjD,CAAC;wBACN,CAAC;6BACI,CAAC;4BACF,oFAAoF;4BACpF,MAAM,IAAI,KAAK,CAAC,uEAAuE,GAAG,WAAW,CAAC,CAAC;wBAC3G,CAAC;oBACL,CAAC;oBACD,OAAO,CAAC,EAAE,CAAC;wBACP,IAAA,eAAQ,EAAC,CAAC,CAAC,CAAC;wBACZ,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,WAAW,CAAC,CAAC;oBAC3E,CAAC;gBACL,CAAC;;oBAEG,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACjD,CAAC;;gBAEG,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,CAAC,EAAE,CAAC;YACP,IAAA,eAAQ,EAAC,CAAC,CAAC,CAAC;YACZ,MAAM,CAAC,CAAC;QACZ,CAAC;IACL,CAAC;IAEM,iBAAiB,CAAC,UAAsB;QAC3C,MAAM,cAAc,GAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvD,MAAM,EAAE,GAAG,IAAI,eAAQ,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,iBAAiB,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;QAC1D,MAAM,YAAY,GAAW;;;;;;;;;;;;mCAYF,UAAU,CAAC,IAAI,uBAAuB,UAAU,CAAC,EAAE;;;;+CAIvC,UAAU,CAAC,QAAQ;EAChE,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YACxB,IAAI,GAAG,GAAW,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC;YAC1C,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;gBAClB,GAAG,IAAI,aAAa,CAAC,CAAC,qBAAqB,GAAG,CAAC;YACnD,CAAC;YACD,OAAO,GAAG,CAAC;QACf,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;QAEN,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAChG,MAAM,qBAAqB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACnH,MAAM,aAAa,GAAW;eACvB,UAAU,CAAC,QAAQ;;EAEhC;QACE,sIAAsI;QACtI,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YAC1B,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,EAAE,CAAC;oBACJ,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,yDAAyD;oBACjF,OAAO,KAAK,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;wBACzD,OAAO,EAAE,CAAC,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC;oBAC1C,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAE,EAAE,CAAA;gBACnB,CAAC;;oBAEG,OAAO,EAAE,CAAC;YAClB,CAAC;;gBAEG,OAAO,EAAE,CAAC,CAAC,iCAAiC;QACpD,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAChB;EACE;QACE,6HAA6H;QAC7H,UAAU,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YAC/B,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC;YAC5D,IAAI,CAAC,EAAE,CAAC;gBACJ,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC5C,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,mEAAmE;oBACpG,OAAO,KAAK,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;wBACzD,IAAI,GAAG,GAAW,GAAG,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,GAAG,CAAC;wBAC5C,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC;4BACnB,GAAG,IAAI,aAAa,EAAE,CAAC,qBAAqB,GAAG,CAAC;wBACpD,CAAC;wBACD,OAAO,GAAG,CAAC;oBACf,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAE,EAAE,CAAA;gBACnB,CAAC;;oBAEG,OAAO,EAAE,CAAC,CAAC,iCAAiC;YACpD,CAAC;;gBAEG,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAChB;;;6JAG6J,WAAW,CAAC,UAAU;MAC7K,WAAW,CAAC,UAAU,wBAAwB,WAAW,CAAC,UAAU;EACxE,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YACzB,OAAO,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC;QAC/C,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;6IACgI,WAAW,CAAC,UAAU;EACjK,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YAC/B,OAAO,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC;QAC/C,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;8BAIiB,WAAW,CAAC,UAAU;;;;;;;;iCAQnB,WAAW,CAAC,UAAU,gCAAgC,WAAW,CAAC,UAAU;;;;;;;;;sHASS,UAAU,CAAC,IAAI;4IACO,UAAU,CAAC,IAAI;;;;CAI1J,CAAA;QAEO,OAAO,YAAY,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,8CAA8C,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG;sHACV,CAAC;IACnH,CAAC;CACJ,CAAA;AA7NY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,sBAAa,EAAC,iBAAU,EAAE,YAAY,CAAC;GAC3B,qBAAqB,CA6NjC;AAGD,SAAgB,gCAAgC;AAEhD,CAAC;AAFD,4EAEC"}
@@ -0,0 +1,6 @@
1
+ export * from './custom/AIPromptEntityExtended.server';
2
+ export * from './custom/DuplicateRunEntity.server';
3
+ export * from './custom/reportEntity.server';
4
+ export * from './custom/userViewEntity.server';
5
+ export declare function LoadCoreEntitiesServerSubClasses(): void;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAG/C,wBAAgB,gCAAgC,IAAI,IAAI,CAKvD"}
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.LoadCoreEntitiesServerSubClasses = void 0;
18
+ const AIPromptEntityExtended_server_1 = require("./custom/AIPromptEntityExtended.server");
19
+ const DuplicateRunEntity_server_1 = require("./custom/DuplicateRunEntity.server");
20
+ const reportEntity_server_1 = require("./custom/reportEntity.server");
21
+ const userViewEntity_server_1 = require("./custom/userViewEntity.server");
22
+ __exportStar(require("./custom/AIPromptEntityExtended.server"), exports);
23
+ __exportStar(require("./custom/DuplicateRunEntity.server"), exports);
24
+ __exportStar(require("./custom/reportEntity.server"), exports);
25
+ __exportStar(require("./custom/userViewEntity.server"), exports);
26
+ // Call the stub functions to ensure that the custom subclasses are not tree shaken out.
27
+ function LoadCoreEntitiesServerSubClasses() {
28
+ (0, AIPromptEntityExtended_server_1.LoadAIPromptEntityExtendedServerSubClass)();
29
+ (0, DuplicateRunEntity_server_1.LoadDuplicateRunEntityServerSubClass)();
30
+ (0, reportEntity_server_1.LoadReportEntityServerSubClass)();
31
+ (0, userViewEntity_server_1.LoadUserViewEntityServerSubClass)();
32
+ }
33
+ exports.LoadCoreEntitiesServerSubClasses = LoadCoreEntitiesServerSubClasses;
34
+ LoadCoreEntitiesServerSubClasses();
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,0FAAkG;AAClG,kFAA0F;AAC1F,sEAA8E;AAC9E,0EAAkF;AAElF,yEAAuD;AACvD,qEAAmD;AACnD,+DAA6C;AAC7C,iEAA+C;AAE/C,wFAAwF;AACxF,SAAgB,gCAAgC;IAC5C,IAAA,wEAAwC,GAAE,CAAC;IAC3C,IAAA,gEAAoC,GAAE,CAAC;IACvC,IAAA,oDAA8B,GAAE,CAAC;IACjC,IAAA,wDAAgC,GAAE,CAAC;AACvC,CAAC;AALD,4EAKC;AACD,gCAAgC,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@memberjunction/core-entities-server",
3
+ "version": "2.46.0",
4
+ "description": "Entity subclasses for the metadata layer of MemberJunction that are only used on server side applications like MJAPI, distributed as part of each release of MemberJunction",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "/dist"
9
+ ],
10
+ "scripts": {
11
+ "start": "ts-node-dev src/index.ts",
12
+ "build": "tsc",
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "author": "MemberJunction.com",
16
+ "license": "ISC",
17
+ "devDependencies": {
18
+ "ts-node-dev": "^2.0.0",
19
+ "typescript": "^5.4.5"
20
+ },
21
+ "dependencies": {
22
+ "@memberjunction/core": "2.46.0",
23
+ "@memberjunction/global": "2.46.0",
24
+ "@memberjunction/core-entities": "2.46.0",
25
+ "@memberjunction/ai-vector-dupe": "2.46.0",
26
+ "@memberjunction/skip-types": "2.46.0",
27
+ "@memberjunction/aiengine": "2.46.0",
28
+ "zod": "^3.23.8"
29
+ }
30
+ }