@memberjunction/server 2.23.2 → 2.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/generated.d.ts +1304 -1301
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2620 -1304
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +3 -3
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +14 -11
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +16 -2
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -1
- package/package.json +22 -22
- package/src/generated/generated.ts +2615 -1304
- package/src/generic/ResolverBase.ts +18 -11
- package/src/index.ts +2 -2
- package/src/resolvers/AskSkipResolver.ts +19 -2
- package/src/types.ts +28 -0
|
@@ -27,9 +27,9 @@ import { FieldMapper } from '@memberjunction/graphql-dataprovider';
|
|
|
27
27
|
import { Subscription } from 'rxjs';
|
|
28
28
|
|
|
29
29
|
export class ResolverBase {
|
|
30
|
-
private _emit = process.env.CLOUDEVENTS_HTTP_TRANSPORT ? emitterFor(httpTransport(process.env.CLOUDEVENTS_HTTP_TRANSPORT)) : null;
|
|
31
|
-
private _cloudeventsHeaders = process.env.CLOUDEVENTS_HTTP_HEADERS ? JSON.parse(process.env.CLOUDEVENTS_HTTP_HEADERS) : {};
|
|
32
|
-
private
|
|
30
|
+
private static _emit = process.env.CLOUDEVENTS_HTTP_TRANSPORT ? emitterFor(httpTransport(process.env.CLOUDEVENTS_HTTP_TRANSPORT)) : null;
|
|
31
|
+
private static _cloudeventsHeaders = process.env.CLOUDEVENTS_HTTP_HEADERS ? JSON.parse(process.env.CLOUDEVENTS_HTTP_HEADERS) : {};
|
|
32
|
+
private static _eventSubscriptions = new Map<string, Subscription>;
|
|
33
33
|
|
|
34
34
|
protected MapFieldNamesToCodeNames(entityName: string, dataObject: any) {
|
|
35
35
|
// for the given entity name provided, check to see if there are any fields
|
|
@@ -245,7 +245,7 @@ export class ResolverBase {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
protected async EmitCloudEvent({ component, event, eventCode, args }: MJEvent) {
|
|
248
|
-
if (
|
|
248
|
+
if (ResolverBase._emit && event === MJEventType.ComponentEvent && eventCode === BaseEntity.BaseEventCode) {
|
|
249
249
|
const extendedType = args instanceof BaseEntityEvent ? `.${args.type}` : '';
|
|
250
250
|
const type = `MemberJunction.${event}${extendedType}`;
|
|
251
251
|
const source = `${process.env.CLOUDEVENTS_SOURCE ?? 'MemberJunction'}`;
|
|
@@ -255,7 +255,7 @@ export class ResolverBase {
|
|
|
255
255
|
const cloudEvent = new CloudEvent({ type, source, subject, data });
|
|
256
256
|
|
|
257
257
|
try {
|
|
258
|
-
const cloudeventTransportResponse = await
|
|
258
|
+
const cloudeventTransportResponse = await ResolverBase._emit(cloudEvent, { headers: ResolverBase._cloudeventsHeaders });
|
|
259
259
|
const cloudeventResponse = JSON.stringify(cloudeventTransportResponse);
|
|
260
260
|
if (/error/i.test(cloudeventResponse)) {
|
|
261
261
|
console.error('CloudEvent ERROR', cloudeventResponse);
|
|
@@ -548,27 +548,34 @@ export class ResolverBase {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
protected ListenForEntityMessages(entityObject: BaseEntity, pubSub: PubSubEngine, userPayload: UserPayload) {
|
|
551
|
-
|
|
551
|
+
// The unique key is set up for each entity object via it's primary key to ensure that we only have one listener at most for each unique
|
|
552
|
+
// entity in the system. This is important because we don't want to have multiple listeners for the same entity as it could
|
|
553
|
+
// cause issues with multiple messages for the same event.
|
|
554
|
+
const uniqueKey = entityObject.EntityInfo.Name;
|
|
555
|
+
|
|
556
|
+
if (!ResolverBase._eventSubscriptions.has(uniqueKey)) {
|
|
552
557
|
// listen for events from the entityObject in case it is a long running task and we can push messages back to the client via pubSub
|
|
553
|
-
|
|
558
|
+
const theSub = MJGlobal.Instance.GetEventListener(false).subscribe(async (event: MJEvent) => {
|
|
554
559
|
if (event) {
|
|
555
560
|
await this.EmitCloudEvent(event);
|
|
556
561
|
|
|
557
|
-
if (event.
|
|
562
|
+
if (event.args && event.args instanceof BaseEntityEvent) {
|
|
563
|
+
const baseEntityEvent = event.args as BaseEntityEvent;
|
|
558
564
|
// message from our entity object, relay it to the client
|
|
559
565
|
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
560
566
|
message: JSON.stringify({
|
|
561
567
|
status: 'OK',
|
|
562
568
|
type: 'EntityObjectStatusMessage',
|
|
563
|
-
entityName:
|
|
564
|
-
primaryKey:
|
|
565
|
-
message: event.args.
|
|
569
|
+
entityName: baseEntityEvent.baseEntity.EntityInfo.Name,
|
|
570
|
+
primaryKey: baseEntityEvent.baseEntity.PrimaryKey,
|
|
571
|
+
message: event.args.payload,
|
|
566
572
|
}),
|
|
567
573
|
sessionId: userPayload.sessionId,
|
|
568
574
|
});
|
|
569
575
|
}
|
|
570
576
|
}
|
|
571
577
|
});
|
|
578
|
+
ResolverBase._eventSubscriptions.set(uniqueKey, theSub);
|
|
572
579
|
}
|
|
573
580
|
}
|
|
574
581
|
|
package/src/index.ts
CHANGED
|
@@ -69,7 +69,7 @@ export { GetReadOnlyDataSource, GetReadWriteDataSource } from './util.js';
|
|
|
69
69
|
export * from './generated/generated.js';
|
|
70
70
|
|
|
71
71
|
import { resolve } from 'node:path';
|
|
72
|
-
import { DataSourceInfo } from './types.js';
|
|
72
|
+
import { DataSourceInfo, raiseEvent } from './types.js';
|
|
73
73
|
|
|
74
74
|
export type MJServerOptions = {
|
|
75
75
|
onBeforeServe?: () => void | Promise<void>;
|
|
@@ -125,8 +125,8 @@ export const serve = async (resolverPaths: Array<string>, app = createApp(), opt
|
|
|
125
125
|
console.log('Read-only Data Source has been initialized.');
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
|
|
129
128
|
setupComplete$.next(true);
|
|
129
|
+
raiseEvent('setupComplete', dataSources, null, this);
|
|
130
130
|
|
|
131
131
|
/******TEST HARNESS FOR CHANGE DETECTION */
|
|
132
132
|
/******TEST HARNESS FOR CHANGE DETECTION */
|
|
@@ -603,8 +603,14 @@ export class AskSkipResolver {
|
|
|
603
603
|
// get the list of entities
|
|
604
604
|
const entities = md.Entities.filter((e) => {
|
|
605
605
|
if (e.SchemaName !== mj_core_schema || skipSpecialIncludeEntities.includes(e.Name.trim().toLowerCase())) {
|
|
606
|
-
const
|
|
607
|
-
|
|
606
|
+
const sd = e.ScopeDefault?.trim();
|
|
607
|
+
if (sd && sd.length > 0) {
|
|
608
|
+
const scopes = sd.split(',').map((s) => s.trim().toLowerCase()) ?? ['all'];
|
|
609
|
+
return !scopes || scopes.length === 0 || scopes.includes('all') || scopes.includes('ai') || skipSpecialIncludeEntities.includes(e.Name.trim().toLowerCase());
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
return true; // no scope, so include it
|
|
613
|
+
}
|
|
608
614
|
}
|
|
609
615
|
return false;
|
|
610
616
|
});
|
|
@@ -1456,6 +1462,17 @@ export class AskSkipResolver {
|
|
|
1456
1462
|
LogError(`Error saving user notification entity for AI message: ${sResult}`, undefined, userNotification.LatestResult);
|
|
1457
1463
|
}
|
|
1458
1464
|
|
|
1465
|
+
// check to see if Skip retrieved additional data on his own outside of the DATA_REQUEST phase/process. It is possible for Skip to call back
|
|
1466
|
+
// to the MJAPI in the instance using the GetData() query in the MJAPI. If Skip did this, we need to save the data context items here.
|
|
1467
|
+
if (apiResponse.newDataItems) {
|
|
1468
|
+
apiResponse.newDataItems.forEach((skipItem) => {
|
|
1469
|
+
const newItem = dataContext.AddDataContextItem();
|
|
1470
|
+
newItem.Type = 'sql';
|
|
1471
|
+
newItem.SQL = skipItem.text;
|
|
1472
|
+
newItem.AdditionalDescription = skipItem.description;
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1459
1476
|
// Save the data context items...
|
|
1460
1477
|
// FOR NOW, we don't want to store the data in the database, we will just load it from the data context when we need it
|
|
1461
1478
|
// we need a better strategy to persist because the cost of storage and retrieval/parsing is higher than just running the query again in many/most cases
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { UserInfo } from '@memberjunction/core';
|
|
1
2
|
import { UserViewEntity } from '@memberjunction/core-entities';
|
|
2
3
|
import { GraphQLSchema } from 'graphql';
|
|
3
4
|
import { PubSubEngine } from 'type-graphql';
|
|
4
5
|
import { DataSource, QueryRunner } from 'typeorm';
|
|
6
|
+
import { getSystemUser } from './auth/index.js';
|
|
7
|
+
import { MJEvent, MJEventType, MJGlobal } from '@memberjunction/global';
|
|
5
8
|
|
|
6
9
|
export type UserPayload = {
|
|
7
10
|
email: string;
|
|
@@ -69,3 +72,28 @@ export type RunViewGenericParams = {
|
|
|
69
72
|
userPayload?: UserPayload;
|
|
70
73
|
pubSub: PubSubEngine;
|
|
71
74
|
};
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
export class MJServerEvent {
|
|
78
|
+
type: 'setupComplete' | 'requestReceived' | 'requestCompleted' | 'requestFailed';
|
|
79
|
+
dataSources: DataSourceInfo[];
|
|
80
|
+
userPayload: UserPayload;
|
|
81
|
+
systemUser: UserInfo;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const MJ_SERVER_EVENT_CODE = 'MJ_SERVER_EVENT';
|
|
85
|
+
|
|
86
|
+
export async function raiseEvent(type: MJServerEvent['type'], dataSources: DataSourceInfo[], userPayload: UserPayload, component?: any) {
|
|
87
|
+
const event = new MJServerEvent();
|
|
88
|
+
event.type = type;
|
|
89
|
+
event.dataSources = dataSources;
|
|
90
|
+
event.userPayload = userPayload;
|
|
91
|
+
event.systemUser = await getSystemUser();
|
|
92
|
+
|
|
93
|
+
const mje = new MJEvent();
|
|
94
|
+
mje.args = event;
|
|
95
|
+
mje.component = component;
|
|
96
|
+
mje.event = MJEventType.ComponentEvent;
|
|
97
|
+
mje.eventCode = MJ_SERVER_EVENT_CODE;
|
|
98
|
+
MJGlobal.Instance.RaiseEvent(mje);
|
|
99
|
+
}
|