@memberjunction/server 6.2.0-edge.1 → 6.2.0-edge.3
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 +30 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/config.d.ts +2189 -71
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +123 -3
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +11 -23
- package/dist/context.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +2143 -205
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +24441 -14433
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts +15 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.js +16 -2
- package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +31 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js +215 -0
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -0
- package/dist/generic/PushStatusResolver.d.ts +38 -0
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +84 -1
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +56 -4
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +191 -74
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +4 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +33 -1
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +204 -50
- package/dist/index.js.map +1 -1
- package/dist/postgresqlCompat.d.ts +8 -0
- package/dist/postgresqlCompat.d.ts.map +1 -0
- package/dist/postgresqlCompat.js +19 -0
- package/dist/postgresqlCompat.js.map +1 -0
- package/dist/postgresqlPoolSettings.d.ts +108 -0
- package/dist/postgresqlPoolSettings.d.ts.map +1 -0
- package/dist/postgresqlPoolSettings.js +134 -0
- package/dist/postgresqlPoolSettings.js.map +1 -0
- package/dist/resolvers/AdhocQueryResolver.d.ts +23 -18
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +77 -167
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +55 -0
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -0
- package/dist/resolvers/AgentRunStatusPublisher.js +141 -0
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -0
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +90 -0
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/ConversationRunEventsResolver.js +283 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.d.ts +98 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.d.ts.map +1 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.js +227 -0
- package/dist/resolvers/DuplicateEntryCheckResolver.js.map +1 -0
- package/dist/resolvers/EntityRecordNameResolver.d.ts +7 -23
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +9 -47
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +2 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +9 -0
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.d.ts +107 -0
- package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -0
- package/dist/resolvers/HumanHandoffResolver.js +324 -0
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -0
- package/dist/resolvers/MeetingResolver.d.ts +69 -0
- package/dist/resolvers/MeetingResolver.d.ts.map +1 -0
- package/dist/resolvers/MeetingResolver.js +381 -0
- package/dist/resolvers/MeetingResolver.js.map +1 -0
- package/dist/resolvers/MergeRecordsResolver.d.ts +7 -0
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +16 -2
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +34 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +202 -7
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +45 -89
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +94 -240
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +0 -16
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +23 -153
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunDecisionResolver.d.ts +149 -0
- package/dist/resolvers/RunDecisionResolver.d.ts.map +1 -0
- package/dist/resolvers/RunDecisionResolver.js +396 -0
- package/dist/resolvers/RunDecisionResolver.js.map +1 -0
- package/dist/resolvers/VectorizeEntityResolver.d.ts +1 -1
- package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.js +14 -10
- package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
- package/dist/resolvers/adhocTimeout.d.ts +7 -0
- package/dist/resolvers/adhocTimeout.d.ts.map +1 -0
- package/dist/resolvers/adhocTimeout.js +12 -0
- package/dist/resolvers/adhocTimeout.js.map +1 -0
- package/dist/resolvers/meetings/index.d.ts +5 -0
- package/dist/resolvers/meetings/index.d.ts.map +1 -0
- package/dist/resolvers/meetings/index.js +5 -0
- package/dist/resolvers/meetings/index.js.map +1 -0
- package/dist/resolvers/meetings/meetingHelpers.d.ts +17 -0
- package/dist/resolvers/meetings/meetingHelpers.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingHelpers.js +212 -0
- package/dist/resolvers/meetings/meetingHelpers.js.map +1 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts +12 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingMutations.js +418 -0
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -0
- package/dist/resolvers/meetings/meetingQueries.d.ts +7 -0
- package/dist/resolvers/meetings/meetingQueries.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingQueries.js +113 -0
- package/dist/resolvers/meetings/meetingQueries.js.map +1 -0
- package/dist/resolvers/meetings/meetingTypes.d.ts +89 -0
- package/dist/resolvers/meetings/meetingTypes.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingTypes.js +345 -0
- package/dist/resolvers/meetings/meetingTypes.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +8 -5
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +8 -0
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -1
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +36 -0
- package/dist/services/WorkQueueHostService.d.ts.map +1 -0
- package/dist/services/WorkQueueHostService.js +97 -0
- package/dist/services/WorkQueueHostService.js.map +1 -0
- package/dist/services/workQueueConfig.d.ts +103 -0
- package/dist/services/workQueueConfig.d.ts.map +1 -0
- package/dist/services/workQueueConfig.js +48 -0
- package/dist/services/workQueueConfig.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +95 -92
- package/src/__tests__/AdhocQueryResolver.bugs.test.ts +14 -35
- package/src/__tests__/AdhocQueryResolver.pagination.test.ts +6 -2
- package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +3 -3
- package/src/__tests__/AgentRunStatusPublisher.test.ts +175 -0
- package/src/__tests__/DuplicateEntryCheckResolver.test.ts +300 -0
- package/src/__tests__/EntityRecordNameResolver.fieldSecurity.test.ts +27 -72
- package/src/__tests__/HumanHandoffResolver.test.ts +233 -0
- package/src/__tests__/MeetingResolver.test.ts +374 -0
- package/src/__tests__/RealtimeBridgeResolver.test.ts +240 -2
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +216 -2
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +7 -1
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +7 -1
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +7 -1
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +96 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +52 -0
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +21 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +291 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +182 -12
- package/src/__tests__/RunAIAgentResolver.streaming.test.ts +18 -27
- package/src/__tests__/RunDecisionResolver.test.ts +699 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +43 -0
- package/src/__tests__/VectorizeEntityResolver.test.ts +106 -0
- package/src/__tests__/WorkQueueHostService.test.ts +133 -0
- package/src/__tests__/adhocTimeoutClamp.test.ts +26 -0
- package/src/__tests__/conversationRunEvents.test.ts +399 -0
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +283 -0
- package/src/__tests__/postgresqlPoolSettings.test.ts +131 -0
- package/src/__tests__/pushStatusFanOut.test.ts +206 -0
- package/src/__tests__/translateBracketsToPG.test.ts +20 -0
- package/src/auth/__tests__/backward-compatibility.test.ts +1 -0
- package/src/config.ts +130 -3
- package/src/context.ts +11 -24
- package/src/generated/graphql-schemas/__mj.ts +24183 -17182
- package/src/generic/FireAndForgetHeartbeat.ts +16 -2
- package/src/generic/OrphanedConversationDetailReconciler.ts +267 -0
- package/src/generic/PushStatusResolver.ts +97 -1
- package/src/generic/ResolverBase.ts +220 -76
- package/src/generic/RunViewResolver.ts +33 -2
- package/src/index.ts +228 -51
- package/src/postgresqlCompat.ts +21 -0
- package/src/postgresqlPoolSettings.ts +213 -0
- package/src/resolvers/AdhocQueryResolver.ts +88 -188
- package/src/resolvers/AgentRunStatusPublisher.ts +175 -0
- package/src/resolvers/ConversationRunEventsResolver.ts +308 -0
- package/src/resolvers/DuplicateEntryCheckResolver.ts +232 -0
- package/src/resolvers/EntityRecordNameResolver.ts +9 -51
- package/src/resolvers/FetchEntityVectorsResolver.ts +2 -1
- package/src/resolvers/GetDataResolver.ts +10 -0
- package/src/resolvers/HumanHandoffResolver.ts +304 -0
- package/src/resolvers/MeetingResolver.ts +438 -0
- package/src/resolvers/MergeRecordsResolver.ts +14 -2
- package/src/resolvers/RealtimeBridgeResolver.ts +227 -13
- package/src/resolvers/RealtimeClientSessionResolver.ts +99 -287
- package/src/resolvers/RunAIAgentResolver.ts +28 -174
- package/src/resolvers/RunDecisionResolver.ts +435 -0
- package/src/resolvers/VectorizeEntityResolver.ts +16 -11
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +93 -0
- package/src/resolvers/adhocTimeout.ts +12 -0
- package/src/resolvers/meetings/index.ts +4 -0
- package/src/resolvers/meetings/meetingHelpers.ts +307 -0
- package/src/resolvers/meetings/meetingMutations.ts +535 -0
- package/src/resolvers/meetings/meetingQueries.ts +172 -0
- package/src/resolvers/meetings/meetingTypes.ts +238 -0
- package/src/rest/ViewOperationsHandler.ts +8 -5
- package/src/services/TaskGraphActionRunner.ts +29 -1
- package/src/services/WorkQueueHostService.ts +129 -0
- package/src/services/workQueueConfig.ts +52 -0
- package/src/types.ts +5 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts +0 -33
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +0 -1
- package/dist/resolvers/adhoc-query-helpers.js +0 -50
- package/dist/resolvers/adhoc-query-helpers.js.map +0 -1
- package/src/__tests__/adhoc-query-helpers.test.ts +0 -50
- package/src/resolvers/adhoc-query-helpers.ts +0 -67
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { LogError, RunView, } from '@memberjunction/core';
|
|
2
|
+
import { EscapeSQLString, UUIDsEqual } from '@memberjunction/global';
|
|
3
|
+
import { MeetingDialInService } from '@memberjunction/livekit-room-server';
|
|
4
|
+
import { NotificationEngine } from '@memberjunction/notifications';
|
|
5
|
+
export async function LoadMeetingEntity(id, user, provider) {
|
|
6
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
7
|
+
const escapedID = EscapeSQLString(id.trim());
|
|
8
|
+
const res = await rv.RunView({
|
|
9
|
+
EntityName: 'MJ: Meetings',
|
|
10
|
+
ExtraFilter: `ID = '${escapedID}'`,
|
|
11
|
+
ResultType: 'entity_object',
|
|
12
|
+
}, user);
|
|
13
|
+
if (res.Success && res.Results && res.Results.length > 0) {
|
|
14
|
+
return res.Results[0];
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
export async function LoadParticipants(meetingID, user, provider) {
|
|
19
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
20
|
+
const escapedID = EscapeSQLString(meetingID.trim());
|
|
21
|
+
const res = await rv.RunView({
|
|
22
|
+
EntityName: 'MJ: Meeting Participants',
|
|
23
|
+
ExtraFilter: `MeetingID = '${escapedID}'`,
|
|
24
|
+
ResultType: 'entity_object',
|
|
25
|
+
}, user);
|
|
26
|
+
if (!res.Success || !res.Results) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
return res.Results.map((p) => MapParticipantToType(p));
|
|
30
|
+
}
|
|
31
|
+
export async function IsUserHostOrCoHost(meeting, user, provider) {
|
|
32
|
+
if (UUIDsEqual(meeting.HostUserID, user.ID)) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
36
|
+
const escapedID = EscapeSQLString(meeting.ID);
|
|
37
|
+
const escapedUserID = EscapeSQLString(user.ID);
|
|
38
|
+
const res = await rv.RunView({
|
|
39
|
+
EntityName: 'MJ: Meeting Participants',
|
|
40
|
+
ExtraFilter: `MeetingID = '${escapedID}' AND UserID = '${escapedUserID}' AND Role IN ('Host', 'CoHost')`,
|
|
41
|
+
ResultType: 'entity_object',
|
|
42
|
+
}, user);
|
|
43
|
+
return Boolean(res.Success && res.Results && res.Results.length > 0);
|
|
44
|
+
}
|
|
45
|
+
export async function ResolveDefaultPhoneNumber(user, provider) {
|
|
46
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
47
|
+
const res = await rv.RunView({
|
|
48
|
+
EntityName: 'MJ: Phone Numbers',
|
|
49
|
+
ExtraFilter: "Status = 'Active'",
|
|
50
|
+
OrderBy: '__mj_CreatedAt ASC',
|
|
51
|
+
ResultType: 'entity_object',
|
|
52
|
+
}, user);
|
|
53
|
+
if (res.Success && res.Results && res.Results.length > 0) {
|
|
54
|
+
return res.Results[0];
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
export async function GenerateUniqueDialInCode(phoneNumberID, user, provider) {
|
|
59
|
+
return MeetingDialInService.Instance.GenerateUniqueDialInCode(phoneNumberID, user, provider);
|
|
60
|
+
}
|
|
61
|
+
export async function EnsureMeetingInteraction(meeting, user, provider) {
|
|
62
|
+
try {
|
|
63
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
64
|
+
const escapedRoom = EscapeSQLString(meeting.RoomName);
|
|
65
|
+
const existing = await rv.RunView({
|
|
66
|
+
EntityName: 'MJ: Interactions',
|
|
67
|
+
ExtraFilter: `RoomName = '${escapedRoom}'`,
|
|
68
|
+
ResultType: 'entity_object',
|
|
69
|
+
}, user);
|
|
70
|
+
if (existing.Success && existing.Results && existing.Results.length > 0) {
|
|
71
|
+
return existing.Results[0];
|
|
72
|
+
}
|
|
73
|
+
const entity = await provider.GetEntityObject('MJ: Interactions', user);
|
|
74
|
+
entity.Channel = 'Meeting';
|
|
75
|
+
entity.Direction = 'Inbound';
|
|
76
|
+
entity.Status = 'Active';
|
|
77
|
+
entity.RoomName = meeting.RoomName;
|
|
78
|
+
entity.StartedAt = new Date();
|
|
79
|
+
entity.AnsweredAt = new Date();
|
|
80
|
+
entity.RecordingEnabled = meeting.RecordingPolicy === 'Automatic' || meeting.RecordingPolicy === 'Allowed';
|
|
81
|
+
if (await entity.Save()) {
|
|
82
|
+
await RecordInteractionEvent(entity.ID, 'Created', user, provider, { MeetingID: meeting.ID, RoomName: meeting.RoomName });
|
|
83
|
+
await RecordInteractionEvent(entity.ID, 'Answered', user, provider);
|
|
84
|
+
return entity;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
LogError(`[MeetingResolver] ensureMeetingInteraction failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export async function RecordInteractionEvent(interactionID, eventType, user, provider, details) {
|
|
94
|
+
try {
|
|
95
|
+
const eventEntity = await provider.GetEntityObject('MJ: Interaction Events', user);
|
|
96
|
+
eventEntity.InteractionID = interactionID;
|
|
97
|
+
eventEntity.EventType = eventType;
|
|
98
|
+
eventEntity.ActorUserID = user.ID;
|
|
99
|
+
eventEntity.OccurredAt = new Date();
|
|
100
|
+
if (details) {
|
|
101
|
+
eventEntity.Details = JSON.stringify(details);
|
|
102
|
+
}
|
|
103
|
+
await eventEntity.Save();
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
LogError(`[MeetingResolver] recordInteractionEvent (${eventType}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export async function CloseMeetingInteraction(roomName, user, provider) {
|
|
110
|
+
try {
|
|
111
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
112
|
+
const escapedRoom = EscapeSQLString(roomName);
|
|
113
|
+
const res = await rv.RunView({
|
|
114
|
+
EntityName: 'MJ: Interactions',
|
|
115
|
+
ExtraFilter: `RoomName = '${escapedRoom}' AND Status = 'Active'`,
|
|
116
|
+
ResultType: 'entity_object',
|
|
117
|
+
}, user);
|
|
118
|
+
if (res.Success && res.Results && res.Results.length > 0) {
|
|
119
|
+
const interaction = res.Results[0];
|
|
120
|
+
interaction.Status = 'Ended';
|
|
121
|
+
interaction.EndedAt = new Date();
|
|
122
|
+
await interaction.Save();
|
|
123
|
+
await RecordInteractionEvent(interaction.ID, 'Ended', user, provider);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
LogError(`[MeetingResolver] closeMeetingInteraction failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export async function SendMeetingInviteNotification(meeting, targetUserID, contextUser, provider) {
|
|
131
|
+
try {
|
|
132
|
+
await NotificationEngine.Instance.Config(false, contextUser, provider);
|
|
133
|
+
const inviter = contextUser.Name?.trim() || contextUser.Email || 'Someone';
|
|
134
|
+
await NotificationEngine.Instance.SendNotification({
|
|
135
|
+
userId: targetUserID,
|
|
136
|
+
typeNameOrId: 'Meeting Invitation',
|
|
137
|
+
title: `Invitation: ${meeting.Title}`,
|
|
138
|
+
message: `${inviter} invited you to the meeting "${meeting.Title}".`,
|
|
139
|
+
resourceConfiguration: { type: 'meeting', meetingID: meeting.ID, roomName: meeting.RoomName },
|
|
140
|
+
}, contextUser);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
LogError(`[MeetingResolver] sendMeetingInviteNotification failed for user ${targetUserID}: ${err instanceof Error ? err.message : String(err)}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
export function NormalizeParticipantRole(roleInput, defaultRole = 'Attendee') {
|
|
147
|
+
switch (roleInput?.trim().toLowerCase()) {
|
|
148
|
+
case 'host':
|
|
149
|
+
return 'Host';
|
|
150
|
+
case 'cohost':
|
|
151
|
+
return 'CoHost';
|
|
152
|
+
case 'agent':
|
|
153
|
+
return 'Agent';
|
|
154
|
+
case 'attendee':
|
|
155
|
+
default:
|
|
156
|
+
return defaultRole;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export function NormalizeRecordingPolicy(policyInput) {
|
|
160
|
+
switch (policyInput?.trim().toLowerCase()) {
|
|
161
|
+
case 'allowed':
|
|
162
|
+
return 'Allowed';
|
|
163
|
+
case 'automatic':
|
|
164
|
+
return 'Automatic';
|
|
165
|
+
case 'off':
|
|
166
|
+
default:
|
|
167
|
+
return 'Off';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
export function MapMeetingToType(m, participants) {
|
|
171
|
+
return {
|
|
172
|
+
ID: m.ID,
|
|
173
|
+
Title: m.Title,
|
|
174
|
+
Description: m.Description ?? undefined,
|
|
175
|
+
HostUserID: m.HostUserID,
|
|
176
|
+
HostUserName: m.HostUser ?? undefined,
|
|
177
|
+
RoomName: m.RoomName,
|
|
178
|
+
Status: m.Status,
|
|
179
|
+
ScheduledStartAt: m.ScheduledStartAt ?? undefined,
|
|
180
|
+
ScheduledEndAt: m.ScheduledEndAt ?? undefined,
|
|
181
|
+
StartedAt: m.StartedAt ?? undefined,
|
|
182
|
+
EndedAt: m.EndedAt ?? undefined,
|
|
183
|
+
AllowPhoneDialIn: m.AllowPhoneDialIn,
|
|
184
|
+
DialInPhoneNumberID: m.DialInPhoneNumberID ?? undefined,
|
|
185
|
+
DialInPhoneNumber: m.DialInPhoneNumber ?? undefined,
|
|
186
|
+
DialInCode: m.DialInCode ?? undefined,
|
|
187
|
+
RecordingPolicy: m.RecordingPolicy,
|
|
188
|
+
ConversationID: m.ConversationID ?? undefined,
|
|
189
|
+
Participants: participants,
|
|
190
|
+
CreatedAt: m.__mj_CreatedAt,
|
|
191
|
+
UpdatedAt: m.__mj_UpdatedAt,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export function MapParticipantToType(p, userNameFallback, userEmailFallback) {
|
|
195
|
+
return {
|
|
196
|
+
ID: p.ID,
|
|
197
|
+
MeetingID: p.MeetingID,
|
|
198
|
+
UserID: p.UserID ?? undefined,
|
|
199
|
+
UserName: p.User ?? userNameFallback ?? undefined,
|
|
200
|
+
UserEmail: userEmailFallback ?? undefined,
|
|
201
|
+
AgentID: p.AgentID ?? undefined,
|
|
202
|
+
AgentName: p.Agent ?? undefined,
|
|
203
|
+
ExternalName: p.ExternalName ?? undefined,
|
|
204
|
+
ExternalEmail: p.ExternalEmail ?? undefined,
|
|
205
|
+
ExternalPhone: p.ExternalPhone ?? undefined,
|
|
206
|
+
Role: p.Role,
|
|
207
|
+
InviteStatus: p.InviteStatus,
|
|
208
|
+
JoinedAt: p.JoinedAt ?? undefined,
|
|
209
|
+
LeftAt: p.LeftAt ?? undefined,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=meetingHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meetingHelpers.js","sourceRoot":"","sources":["../../../src/resolvers/meetings/meetingHelpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
2
|
+
import { SessionManager } from '../../agentSessions/SessionManager.js';
|
|
3
|
+
import { MeetingResult, StartMeetingResult, CreateMeetingInput, UpdateMeetingInput, RSVPMeetingInput } from './meetingTypes.js';
|
|
4
|
+
import * as defaultHelpers from './meetingHelpers.js';
|
|
5
|
+
export type MeetingHelpers = typeof defaultHelpers;
|
|
6
|
+
export declare function ExecuteCreateMeeting(provider: IMetadataProvider, user: UserInfo, input: CreateMeetingInput, helpers?: Partial<MeetingHelpers>): Promise<MeetingResult>;
|
|
7
|
+
export declare function ExecuteUpdateMeeting(provider: IMetadataProvider, user: UserInfo, input: UpdateMeetingInput, helpers?: Partial<MeetingHelpers>): Promise<MeetingResult>;
|
|
8
|
+
export declare function ExecuteStartMeeting(provider: IMetadataProvider, user: UserInfo, meetingID: string, sessionManager: SessionManager, helpers?: Partial<MeetingHelpers>): Promise<StartMeetingResult>;
|
|
9
|
+
export declare function ExecuteEndMeeting(provider: IMetadataProvider, user: UserInfo, meetingID: string, helpers?: Partial<MeetingHelpers>): Promise<MeetingResult>;
|
|
10
|
+
export declare function ExecuteCancelMeeting(provider: IMetadataProvider, user: UserInfo, meetingID: string, helpers?: Partial<MeetingHelpers>): Promise<MeetingResult>;
|
|
11
|
+
export declare function ExecuteRSVPMeeting(provider: IMetadataProvider, user: UserInfo, input: RSVPMeetingInput, helpers?: Partial<MeetingHelpers>): Promise<MeetingResult>;
|
|
12
|
+
//# sourceMappingURL=meetingMutations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meetingMutations.d.ts","sourceRoot":"","sources":["../../../src/resolvers/meetings/meetingMutations.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EAGjB,QAAQ,EACT,MAAM,sBAAsB,CAAC;AAY9B,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAEvE,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAEjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC;AAMnD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,kBAAkB,EACzB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,CAoHxB;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,kBAAkB,EACzB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,CA6IxB;AAED,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,cAAc,EAC9B,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAmF7B;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,CAwCxB;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,CA4BxB;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,gBAAgB,EACvB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,CAiDxB"}
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { LogError, RunView, } from '@memberjunction/core';
|
|
3
|
+
import { EscapeSQLString, UUIDsEqual } from '@memberjunction/global';
|
|
4
|
+
import { LiveKitTokenService, LiveKitAgentRoomCoordinator, LiveKitEgressService, LiveKitUserIdentity, } from '@memberjunction/livekit-room-server';
|
|
5
|
+
import { CorrelateRecordingStart } from '../meetingRecordingRegistration.js';
|
|
6
|
+
import * as defaultHelpers from './meetingHelpers.js';
|
|
7
|
+
function resolveHelpers(overrides) {
|
|
8
|
+
return { ...defaultHelpers, ...overrides };
|
|
9
|
+
}
|
|
10
|
+
export async function ExecuteCreateMeeting(provider, user, input, helpers) {
|
|
11
|
+
const h = resolveHelpers(helpers);
|
|
12
|
+
try {
|
|
13
|
+
const trimmedTitle = input.Title?.trim();
|
|
14
|
+
if (!trimmedTitle) {
|
|
15
|
+
return { Success: false, ErrorMessage: 'Meeting title is required.' };
|
|
16
|
+
}
|
|
17
|
+
if (input.ScheduledStartAt && input.ScheduledEndAt && input.ScheduledEndAt <= input.ScheduledStartAt) {
|
|
18
|
+
return { Success: false, ErrorMessage: 'Scheduled end time must be after scheduled start time.' };
|
|
19
|
+
}
|
|
20
|
+
const allowDialIn = input.AllowPhoneDialIn ?? false;
|
|
21
|
+
let dialInPhoneNumberID = input.DialInPhoneNumberID?.trim();
|
|
22
|
+
let dialInCode;
|
|
23
|
+
if (allowDialIn) {
|
|
24
|
+
if (!dialInPhoneNumberID) {
|
|
25
|
+
// Select default active phone number
|
|
26
|
+
const defaultNumber = await h.ResolveDefaultPhoneNumber(user, provider);
|
|
27
|
+
if (!defaultNumber) {
|
|
28
|
+
return {
|
|
29
|
+
Success: false,
|
|
30
|
+
ErrorMessage: 'Cannot allow phone dial-in: no active phone numbers are configured in the system.',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
dialInPhoneNumberID = defaultNumber.ID;
|
|
34
|
+
}
|
|
35
|
+
// Generate a random unique dial-in code (6 digits)
|
|
36
|
+
dialInCode = await h.GenerateUniqueDialInCode(dialInPhoneNumberID, user, provider);
|
|
37
|
+
if (!dialInCode) {
|
|
38
|
+
return { Success: false, ErrorMessage: 'Failed to generate a unique dial-in code for this phone number.' };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Room name is always unguessable and generated: mj-mtg-<uuid>
|
|
42
|
+
const roomName = `mj-mtg-${randomUUID()}`;
|
|
43
|
+
const meeting = await provider.GetEntityObject('MJ: Meetings', user);
|
|
44
|
+
meeting.Title = trimmedTitle;
|
|
45
|
+
meeting.Description = input.Description?.trim() || null;
|
|
46
|
+
meeting.HostUserID = user.ID;
|
|
47
|
+
meeting.RoomName = roomName;
|
|
48
|
+
meeting.Status = 'Scheduled';
|
|
49
|
+
meeting.ScheduledStartAt = input.ScheduledStartAt ?? null;
|
|
50
|
+
meeting.ScheduledEndAt = input.ScheduledEndAt ?? null;
|
|
51
|
+
meeting.AllowPhoneDialIn = allowDialIn;
|
|
52
|
+
meeting.DialInPhoneNumberID = allowDialIn ? dialInPhoneNumberID : null;
|
|
53
|
+
meeting.DialInCode = allowDialIn ? dialInCode : null;
|
|
54
|
+
meeting.RecordingPolicy = h.NormalizeRecordingPolicy(input.RecordingPolicy);
|
|
55
|
+
if (!(await meeting.Save())) {
|
|
56
|
+
const err = meeting.LatestResult?.CompleteMessage ?? 'Failed to save meeting.';
|
|
57
|
+
LogError(`[MeetingResolver] CreateMeeting save failed: ${err}`);
|
|
58
|
+
return { Success: false, ErrorMessage: err };
|
|
59
|
+
}
|
|
60
|
+
// Add Host as accepted participant
|
|
61
|
+
const hostParticipant = await provider.GetEntityObject('MJ: Meeting Participants', user);
|
|
62
|
+
hostParticipant.MeetingID = meeting.ID;
|
|
63
|
+
hostParticipant.UserID = user.ID;
|
|
64
|
+
hostParticipant.Role = 'Host';
|
|
65
|
+
hostParticipant.InviteStatus = 'Accepted';
|
|
66
|
+
await hostParticipant.Save();
|
|
67
|
+
// Add other participants
|
|
68
|
+
const participants = [h.MapParticipantToType(hostParticipant, user.Name, user.Email)];
|
|
69
|
+
if (input.Participants && input.Participants.length > 0) {
|
|
70
|
+
for (const pInput of input.Participants) {
|
|
71
|
+
// Skip if duplicate of host
|
|
72
|
+
if (pInput.UserID && UUIDsEqual(pInput.UserID, user.ID)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const participant = await provider.GetEntityObject('MJ: Meeting Participants', user);
|
|
76
|
+
participant.MeetingID = meeting.ID;
|
|
77
|
+
if (pInput.AgentID && pInput.AgentID.trim()) {
|
|
78
|
+
participant.AgentID = pInput.AgentID.trim();
|
|
79
|
+
participant.Role = 'Agent';
|
|
80
|
+
participant.InviteStatus = 'Accepted';
|
|
81
|
+
}
|
|
82
|
+
else if (pInput.UserID && pInput.UserID.trim()) {
|
|
83
|
+
participant.UserID = pInput.UserID.trim();
|
|
84
|
+
participant.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
|
|
85
|
+
participant.InviteStatus = 'Invited';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// External guest
|
|
89
|
+
participant.ExternalName = pInput.ExternalName?.trim() || null;
|
|
90
|
+
participant.ExternalEmail = pInput.ExternalEmail?.trim() || null;
|
|
91
|
+
participant.ExternalPhone = pInput.ExternalPhone?.trim() || null;
|
|
92
|
+
participant.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
|
|
93
|
+
participant.InviteStatus = 'Invited';
|
|
94
|
+
}
|
|
95
|
+
if (await participant.Save()) {
|
|
96
|
+
participants.push(h.MapParticipantToType(participant));
|
|
97
|
+
// Send notification for internal users
|
|
98
|
+
if (participant.UserID) {
|
|
99
|
+
void h.SendMeetingInviteNotification(meeting, participant.UserID, user, provider);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
Success: true,
|
|
106
|
+
Meeting: h.MapMeetingToType(meeting, participants),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
111
|
+
LogError(`[MeetingResolver] CreateMeeting exception: ${msg}`);
|
|
112
|
+
return { Success: false, ErrorMessage: msg };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function ExecuteUpdateMeeting(provider, user, input, helpers) {
|
|
116
|
+
const h = resolveHelpers(helpers);
|
|
117
|
+
try {
|
|
118
|
+
const meeting = await h.LoadMeetingEntity(input.MeetingID, user, provider);
|
|
119
|
+
if (!meeting) {
|
|
120
|
+
return { Success: false, ErrorMessage: 'Meeting not found.' };
|
|
121
|
+
}
|
|
122
|
+
// Check authorization (host or co-host)
|
|
123
|
+
const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
|
|
124
|
+
if (!authorized) {
|
|
125
|
+
return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may modify this meeting.' };
|
|
126
|
+
}
|
|
127
|
+
if (meeting.Status === 'Ended' || meeting.Status === 'Cancelled') {
|
|
128
|
+
return { Success: false, ErrorMessage: `Cannot modify a meeting with status '${meeting.Status}'.` };
|
|
129
|
+
}
|
|
130
|
+
if (input.Title !== undefined) {
|
|
131
|
+
const trimmedTitle = input.Title.trim();
|
|
132
|
+
if (!trimmedTitle) {
|
|
133
|
+
return { Success: false, ErrorMessage: 'Meeting title cannot be empty.' };
|
|
134
|
+
}
|
|
135
|
+
meeting.Title = trimmedTitle;
|
|
136
|
+
}
|
|
137
|
+
if (input.Description !== undefined) {
|
|
138
|
+
meeting.Description = input.Description?.trim() || null;
|
|
139
|
+
}
|
|
140
|
+
if (input.ScheduledStartAt !== undefined) {
|
|
141
|
+
meeting.ScheduledStartAt = input.ScheduledStartAt;
|
|
142
|
+
}
|
|
143
|
+
if (input.ScheduledEndAt !== undefined) {
|
|
144
|
+
meeting.ScheduledEndAt = input.ScheduledEndAt;
|
|
145
|
+
}
|
|
146
|
+
if (meeting.ScheduledStartAt && meeting.ScheduledEndAt && meeting.ScheduledEndAt <= meeting.ScheduledStartAt) {
|
|
147
|
+
return { Success: false, ErrorMessage: 'Scheduled end time must be after scheduled start time.' };
|
|
148
|
+
}
|
|
149
|
+
if (input.RecordingPolicy !== undefined) {
|
|
150
|
+
meeting.RecordingPolicy = h.NormalizeRecordingPolicy(input.RecordingPolicy);
|
|
151
|
+
}
|
|
152
|
+
if (input.AllowPhoneDialIn !== undefined) {
|
|
153
|
+
meeting.AllowPhoneDialIn = input.AllowPhoneDialIn;
|
|
154
|
+
if (meeting.AllowPhoneDialIn && !meeting.DialInCode) {
|
|
155
|
+
let phoneID = input.DialInPhoneNumberID?.trim() || meeting.DialInPhoneNumberID;
|
|
156
|
+
if (!phoneID) {
|
|
157
|
+
const defPhone = await h.ResolveDefaultPhoneNumber(user, provider);
|
|
158
|
+
phoneID = defPhone?.ID;
|
|
159
|
+
}
|
|
160
|
+
if (phoneID) {
|
|
161
|
+
meeting.DialInPhoneNumberID = phoneID;
|
|
162
|
+
meeting.DialInCode = await h.GenerateUniqueDialInCode(phoneID, user, provider);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (input.DialInPhoneNumberID !== undefined && input.DialInPhoneNumberID.trim()) {
|
|
167
|
+
meeting.DialInPhoneNumberID = input.DialInPhoneNumberID.trim();
|
|
168
|
+
}
|
|
169
|
+
if (!(await meeting.Save())) {
|
|
170
|
+
const err = meeting.LatestResult?.CompleteMessage ?? 'Failed to update meeting.';
|
|
171
|
+
return { Success: false, ErrorMessage: err };
|
|
172
|
+
}
|
|
173
|
+
// If participants specified in update, sync participants (upsert by UserID/AgentID/ExternalEmail)
|
|
174
|
+
if (input.Participants !== undefined) {
|
|
175
|
+
const existing = await h.LoadParticipants(meeting.ID, user, provider);
|
|
176
|
+
for (const pInput of input.Participants) {
|
|
177
|
+
const isSelf = pInput.UserID && UUIDsEqual(pInput.UserID, user.ID);
|
|
178
|
+
const match = existing.find((e) => (pInput.UserID && e.UserID && UUIDsEqual(e.UserID, pInput.UserID)) ||
|
|
179
|
+
(pInput.AgentID && e.AgentID && UUIDsEqual(e.AgentID, pInput.AgentID)) ||
|
|
180
|
+
(pInput.ExternalEmail && e.ExternalEmail && e.ExternalEmail.toLowerCase() === pInput.ExternalEmail.toLowerCase()));
|
|
181
|
+
if (match) {
|
|
182
|
+
if (!isSelf && pInput.Role) {
|
|
183
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
184
|
+
const escapedPID = EscapeSQLString(match.ID);
|
|
185
|
+
const partRes = await rv.RunView({
|
|
186
|
+
EntityName: 'MJ: Meeting Participants',
|
|
187
|
+
ExtraFilter: `ID = '${escapedPID}'`,
|
|
188
|
+
ResultType: 'entity_object',
|
|
189
|
+
}, user);
|
|
190
|
+
if (partRes.Success && partRes.Results && partRes.Results.length > 0) {
|
|
191
|
+
const part = partRes.Results[0];
|
|
192
|
+
part.Role = h.NormalizeParticipantRole(pInput.Role, part.Role);
|
|
193
|
+
await part.Save();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// New participant
|
|
199
|
+
const newPart = await provider.GetEntityObject('MJ: Meeting Participants', user);
|
|
200
|
+
newPart.MeetingID = meeting.ID;
|
|
201
|
+
if (pInput.AgentID && pInput.AgentID.trim()) {
|
|
202
|
+
newPart.AgentID = pInput.AgentID.trim();
|
|
203
|
+
newPart.Role = 'Agent';
|
|
204
|
+
newPart.InviteStatus = 'Accepted';
|
|
205
|
+
}
|
|
206
|
+
else if (pInput.UserID && pInput.UserID.trim()) {
|
|
207
|
+
newPart.UserID = pInput.UserID.trim();
|
|
208
|
+
newPart.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
|
|
209
|
+
newPart.InviteStatus = 'Invited';
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
newPart.ExternalName = pInput.ExternalName?.trim() || null;
|
|
213
|
+
newPart.ExternalEmail = pInput.ExternalEmail?.trim() || null;
|
|
214
|
+
newPart.ExternalPhone = pInput.ExternalPhone?.trim() || null;
|
|
215
|
+
newPart.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
|
|
216
|
+
newPart.InviteStatus = 'Invited';
|
|
217
|
+
}
|
|
218
|
+
if (await newPart.Save()) {
|
|
219
|
+
if (newPart.UserID) {
|
|
220
|
+
void h.SendMeetingInviteNotification(meeting, newPart.UserID, user, provider);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const updatedParticipants = await h.LoadParticipants(meeting.ID, user, provider);
|
|
227
|
+
return {
|
|
228
|
+
Success: true,
|
|
229
|
+
Meeting: h.MapMeetingToType(meeting, updatedParticipants),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
234
|
+
LogError(`[MeetingResolver] UpdateMeeting exception: ${msg}`);
|
|
235
|
+
return { Success: false, ErrorMessage: msg };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
export async function ExecuteStartMeeting(provider, user, meetingID, sessionManager, helpers) {
|
|
239
|
+
const h = resolveHelpers(helpers);
|
|
240
|
+
try {
|
|
241
|
+
const meeting = await h.LoadMeetingEntity(meetingID, user, provider);
|
|
242
|
+
if (!meeting) {
|
|
243
|
+
return { Success: false, ErrorMessage: 'Meeting not found.' };
|
|
244
|
+
}
|
|
245
|
+
const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
|
|
246
|
+
if (!authorized) {
|
|
247
|
+
return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may start this meeting.' };
|
|
248
|
+
}
|
|
249
|
+
if (meeting.Status === 'Ended' || meeting.Status === 'Cancelled') {
|
|
250
|
+
return { Success: false, ErrorMessage: `Meeting cannot be started because its status is '${meeting.Status}'.` };
|
|
251
|
+
}
|
|
252
|
+
const now = new Date();
|
|
253
|
+
meeting.Status = 'Live';
|
|
254
|
+
meeting.StartedAt = meeting.StartedAt ?? now;
|
|
255
|
+
if (!(await meeting.Save())) {
|
|
256
|
+
return { Success: false, ErrorMessage: meeting.LatestResult?.CompleteMessage ?? 'Failed to update meeting status to Live.' };
|
|
257
|
+
}
|
|
258
|
+
// 1. Create or get Interaction row for this meeting
|
|
259
|
+
const interaction = await h.EnsureMeetingInteraction(meeting, user, provider);
|
|
260
|
+
// 2. Start all AI agent participants
|
|
261
|
+
const participants = await h.LoadParticipants(meeting.ID, user, provider);
|
|
262
|
+
const agentParticipants = participants.filter((p) => p.Role === 'Agent' && p.AgentID);
|
|
263
|
+
for (const ap of agentParticipants) {
|
|
264
|
+
try {
|
|
265
|
+
const createdSession = await sessionManager.CreateSession({ agentID: ap.AgentID, userID: user.ID }, user, provider);
|
|
266
|
+
await LiveKitAgentRoomCoordinator.Instance.StartAgentRoomSession({
|
|
267
|
+
AgentSessionID: createdSession.ID,
|
|
268
|
+
RoomName: meeting.RoomName,
|
|
269
|
+
AgentID: ap.AgentID,
|
|
270
|
+
ContextUser: user,
|
|
271
|
+
MetadataProvider: provider,
|
|
272
|
+
TurnMode: 'Active',
|
|
273
|
+
TurnAddressing: 'Auto',
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
catch (agentErr) {
|
|
277
|
+
LogError(`[MeetingResolver] Failed to start agent participant ${ap.AgentID} in room ${meeting.RoomName}: ${agentErr instanceof Error ? agentErr.message : String(agentErr)}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// 3. Initiate recording if RecordingPolicy is 'Automatic'
|
|
281
|
+
if (meeting.RecordingPolicy === 'Automatic') {
|
|
282
|
+
try {
|
|
283
|
+
const egress = await new LiveKitEgressService().StartRoomRecording({ RoomName: meeting.RoomName });
|
|
284
|
+
if (egress && egress.EgressID) {
|
|
285
|
+
void CorrelateRecordingStart(meeting.RoomName, egress.EgressID, user, provider);
|
|
286
|
+
if (interaction) {
|
|
287
|
+
await h.RecordInteractionEvent(interaction.ID, 'RecordingStarted', user, provider, { EgressID: egress.EgressID });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (recErr) {
|
|
292
|
+
LogError(`[MeetingResolver] Automatic recording initiation failed for room ${meeting.RoomName}: ${recErr instanceof Error ? recErr.message : String(recErr)}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// 4. Mint LiveKit client token for the caller
|
|
296
|
+
const tokenService = new LiveKitTokenService();
|
|
297
|
+
const identity = LiveKitUserIdentity(user.ID);
|
|
298
|
+
const mintedToken = await tokenService.MintClientToken(meeting.RoomName, identity, user.Name ?? user.Email);
|
|
299
|
+
return {
|
|
300
|
+
Success: true,
|
|
301
|
+
Meeting: h.MapMeetingToType(meeting, participants),
|
|
302
|
+
RoomName: meeting.RoomName,
|
|
303
|
+
ClientToken: mintedToken.Token,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
308
|
+
LogError(`[MeetingResolver] StartMeeting exception: ${msg}`);
|
|
309
|
+
return { Success: false, ErrorMessage: msg };
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
export async function ExecuteEndMeeting(provider, user, meetingID, helpers) {
|
|
313
|
+
const h = resolveHelpers(helpers);
|
|
314
|
+
try {
|
|
315
|
+
const meeting = await h.LoadMeetingEntity(meetingID, user, provider);
|
|
316
|
+
if (!meeting) {
|
|
317
|
+
return { Success: false, ErrorMessage: 'Meeting not found.' };
|
|
318
|
+
}
|
|
319
|
+
const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
|
|
320
|
+
if (!authorized) {
|
|
321
|
+
return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may end this meeting.' };
|
|
322
|
+
}
|
|
323
|
+
const now = new Date();
|
|
324
|
+
meeting.Status = 'Ended';
|
|
325
|
+
meeting.EndedAt = now;
|
|
326
|
+
if (!(await meeting.Save())) {
|
|
327
|
+
return { Success: false, ErrorMessage: meeting.LatestResult?.CompleteMessage ?? 'Failed to update meeting status to Ended.' };
|
|
328
|
+
}
|
|
329
|
+
// 1. Stop all AI agents in room
|
|
330
|
+
try {
|
|
331
|
+
await LiveKitAgentRoomCoordinator.Instance.StopAllAgentsInRoom(meeting.RoomName, 'Explicit', user, provider);
|
|
332
|
+
}
|
|
333
|
+
catch (err) {
|
|
334
|
+
LogError(`[MeetingResolver] Error stopping agents for room ${meeting.RoomName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
335
|
+
}
|
|
336
|
+
// 2. Close Interaction record if exists
|
|
337
|
+
await h.CloseMeetingInteraction(meeting.RoomName, user, provider);
|
|
338
|
+
const participants = await h.LoadParticipants(meeting.ID, user, provider);
|
|
339
|
+
return {
|
|
340
|
+
Success: true,
|
|
341
|
+
Meeting: h.MapMeetingToType(meeting, participants),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
346
|
+
LogError(`[MeetingResolver] EndMeeting exception: ${msg}`);
|
|
347
|
+
return { Success: false, ErrorMessage: msg };
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
export async function ExecuteCancelMeeting(provider, user, meetingID, helpers) {
|
|
351
|
+
const h = resolveHelpers(helpers);
|
|
352
|
+
try {
|
|
353
|
+
const meeting = await h.LoadMeetingEntity(meetingID, user, provider);
|
|
354
|
+
if (!meeting) {
|
|
355
|
+
return { Success: false, ErrorMessage: 'Meeting not found.' };
|
|
356
|
+
}
|
|
357
|
+
const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
|
|
358
|
+
if (!authorized) {
|
|
359
|
+
return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may cancel this meeting.' };
|
|
360
|
+
}
|
|
361
|
+
meeting.Status = 'Cancelled';
|
|
362
|
+
if (!(await meeting.Save())) {
|
|
363
|
+
return { Success: false, ErrorMessage: meeting.LatestResult?.CompleteMessage ?? 'Failed to cancel meeting.' };
|
|
364
|
+
}
|
|
365
|
+
const participants = await h.LoadParticipants(meeting.ID, user, provider);
|
|
366
|
+
return {
|
|
367
|
+
Success: true,
|
|
368
|
+
Meeting: h.MapMeetingToType(meeting, participants),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
373
|
+
LogError(`[MeetingResolver] CancelMeeting exception: ${msg}`);
|
|
374
|
+
return { Success: false, ErrorMessage: msg };
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
export async function ExecuteRSVPMeeting(provider, user, input, helpers) {
|
|
378
|
+
const h = resolveHelpers(helpers);
|
|
379
|
+
try {
|
|
380
|
+
const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
381
|
+
const validStatuses = ['Accepted', 'Declined', 'Tentative'];
|
|
382
|
+
const statusInput = input.InviteStatus.trim();
|
|
383
|
+
const matchedStatus = validStatuses.find((s) => s.toLowerCase() === statusInput.toLowerCase());
|
|
384
|
+
if (!matchedStatus) {
|
|
385
|
+
return { Success: false, ErrorMessage: `Invalid RSVP status: '${statusInput}'. Expected Accepted, Declined, or Tentative.` };
|
|
386
|
+
}
|
|
387
|
+
const escapedMeetingID = EscapeSQLString(input.MeetingID.trim());
|
|
388
|
+
const escapedUserID = EscapeSQLString(user.ID);
|
|
389
|
+
const pResult = await rv.RunView({
|
|
390
|
+
EntityName: 'MJ: Meeting Participants',
|
|
391
|
+
ExtraFilter: `MeetingID = '${escapedMeetingID}' AND UserID = '${escapedUserID}'`,
|
|
392
|
+
ResultType: 'entity_object',
|
|
393
|
+
}, user);
|
|
394
|
+
if (!pResult.Success || !pResult.Results || pResult.Results.length === 0) {
|
|
395
|
+
return { Success: false, ErrorMessage: 'Participant record not found for the caller in this meeting.' };
|
|
396
|
+
}
|
|
397
|
+
const participant = pResult.Results[0];
|
|
398
|
+
participant.InviteStatus = matchedStatus;
|
|
399
|
+
if (!(await participant.Save())) {
|
|
400
|
+
return { Success: false, ErrorMessage: participant.LatestResult?.CompleteMessage ?? 'Failed to save RSVP response.' };
|
|
401
|
+
}
|
|
402
|
+
const meeting = await h.LoadMeetingEntity(input.MeetingID, user, provider);
|
|
403
|
+
if (!meeting) {
|
|
404
|
+
return { Success: false, ErrorMessage: 'Meeting not found.' };
|
|
405
|
+
}
|
|
406
|
+
const participants = await h.LoadParticipants(meeting.ID, user, provider);
|
|
407
|
+
return {
|
|
408
|
+
Success: true,
|
|
409
|
+
Meeting: h.MapMeetingToType(meeting, participants),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
414
|
+
LogError(`[MeetingResolver] RSVPMeeting exception: ${msg}`);
|
|
415
|
+
return { Success: false, ErrorMessage: msg };
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=meetingMutations.js.map
|