@memberjunction/server 5.43.0 → 5.45.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/dist/agentSessions/ReturningVisitorRecap.d.ts +39 -0
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js +198 -0
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -0
- package/dist/agentSessions/SessionJanitor.d.ts +13 -0
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +65 -7
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +40 -0
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/index.d.ts.map +1 -1
- package/dist/agentSessions/index.js +3 -1
- package/dist/agentSessions/index.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +10 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +16 -0
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +1 -1
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +1 -1
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +26 -0
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/config.d.ts +1883 -144
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +160 -36
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +45 -2
- package/dist/context.js.map +1 -1
- package/dist/generated/generated.d.ts +1684 -54
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +57105 -48029
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +13 -0
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +22 -0
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +4 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -3
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +6 -0
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts +26 -0
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -0
- package/dist/realtimeWidget/WidgetRouter.js +182 -0
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -0
- package/dist/realtimeWidget/WidgetSessionService.d.ts +265 -0
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -0
- package/dist/realtimeWidget/WidgetSessionService.js +477 -0
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -0
- package/dist/realtimeWidget/host-identity.d.ts +40 -0
- package/dist/realtimeWidget/host-identity.d.ts.map +1 -0
- package/dist/realtimeWidget/host-identity.js +58 -0
- package/dist/realtimeWidget/host-identity.js.map +1 -0
- package/dist/realtimeWidget/index.d.ts +10 -0
- package/dist/realtimeWidget/index.d.ts.map +1 -0
- package/dist/realtimeWidget/index.js +9 -0
- package/dist/realtimeWidget/index.js.map +1 -0
- package/dist/realtimeWidget/visitorIdentity.d.ts +76 -0
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -0
- package/dist/realtimeWidget/visitorIdentity.js +202 -0
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -0
- package/dist/realtimeWidget/widgetCore.d.ts +106 -0
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -0
- package/dist/realtimeWidget/widgetCore.js +173 -0
- package/dist/realtimeWidget/widgetCore.js.map +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +51 -0
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.js +79 -0
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -0
- package/dist/resolvers/ComponentRegistryResolver.d.ts +7 -0
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +31 -8
- package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
- package/dist/resolvers/EntityPermissionResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityPermissionResolver.js +1 -2
- package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +74 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +211 -2
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +6 -4
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +29 -14
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +9 -6
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +15 -13
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +8 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +28 -4
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +91 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +337 -17
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +17 -2
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RingCentralTelephonyResolver.d.ts +27 -0
- package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
- package/dist/resolvers/RingCentralTelephonyResolver.js +87 -0
- package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts +12 -3
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +50 -17
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.js +2 -0
- package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
- package/dist/resolvers/TeamsMeetingsResolver.d.ts +28 -0
- package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
- package/dist/resolvers/TeamsMeetingsResolver.js +91 -0
- package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
- package/dist/resolvers/TelephonyResolver.d.ts +26 -0
- package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
- package/dist/resolvers/TelephonyResolver.js +86 -0
- package/dist/resolvers/TelephonyResolver.js.map +1 -0
- package/dist/resolvers/TestQuerySQLResolver.d.ts +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +2 -3
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/VonageTelephonyResolver.d.ts +26 -0
- package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
- package/dist/resolvers/VonageTelephonyResolver.js +86 -0
- package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
- package/dist/resolvers/meetingRecordingRegistration.d.ts +124 -0
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -0
- package/dist/resolvers/meetingRecordingRegistration.js +311 -0
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -0
- package/dist/resolvers/peaksSidecar.d.ts +30 -0
- package/dist/resolvers/peaksSidecar.d.ts.map +1 -0
- package/dist/resolvers/peaksSidecar.js +51 -0
- package/dist/resolvers/peaksSidecar.js.map +1 -0
- package/dist/rest/MediaAccessKeys.d.ts +68 -0
- package/dist/rest/MediaAccessKeys.d.ts.map +1 -0
- package/dist/rest/MediaAccessKeys.js +96 -0
- package/dist/rest/MediaAccessKeys.js.map +1 -0
- package/dist/rest/MediaStreamHandler.d.ts +26 -0
- package/dist/rest/MediaStreamHandler.d.ts.map +1 -0
- package/dist/rest/MediaStreamHandler.js +195 -0
- package/dist/rest/MediaStreamHandler.js.map +1 -0
- package/dist/rest/mediaRange.d.ts +41 -0
- package/dist/rest/mediaRange.d.ts.map +1 -0
- package/dist/rest/mediaRange.js +60 -0
- package/dist/rest/mediaRange.js.map +1 -0
- package/dist/telephony/RingCentralTelephonyService.d.ts +115 -0
- package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
- package/dist/telephony/RingCentralTelephonyService.js +262 -0
- package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
- package/dist/telephony/TeamsMeetingsRouter.d.ts +40 -0
- package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
- package/dist/telephony/TeamsMeetingsRouter.js +96 -0
- package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
- package/dist/telephony/TeamsMeetingsService.d.ts +113 -0
- package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
- package/dist/telephony/TeamsMeetingsService.js +196 -0
- package/dist/telephony/TeamsMeetingsService.js.map +1 -0
- package/dist/telephony/TwilioTelephonyRouter.d.ts +36 -0
- package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
- package/dist/telephony/TwilioTelephonyRouter.js +143 -0
- package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
- package/dist/telephony/TwilioTelephonyService.d.ts +95 -0
- package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
- package/dist/telephony/TwilioTelephonyService.js +193 -0
- package/dist/telephony/TwilioTelephonyService.js.map +1 -0
- package/dist/telephony/VonageTelephonyRouter.d.ts +41 -0
- package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
- package/dist/telephony/VonageTelephonyRouter.js +201 -0
- package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
- package/dist/telephony/VonageTelephonyService.d.ts +90 -0
- package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
- package/dist/telephony/VonageTelephonyService.js +191 -0
- package/dist/telephony/VonageTelephonyService.js.map +1 -0
- package/dist/telephony/calendar-scheduler.d.ts +67 -0
- package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
- package/dist/telephony/calendar-scheduler.js +133 -0
- package/dist/telephony/calendar-scheduler.js.map +1 -0
- package/dist/telephony/index.d.ts +29 -0
- package/dist/telephony/index.d.ts.map +1 -0
- package/dist/telephony/index.js +38 -0
- package/dist/telephony/index.js.map +1 -0
- package/dist/telephony/media-upgrade-router.d.ts +33 -0
- package/dist/telephony/media-upgrade-router.d.ts.map +1 -0
- package/dist/telephony/media-upgrade-router.js +56 -0
- package/dist/telephony/media-upgrade-router.js.map +1 -0
- package/dist/telephony/ringcentral-runtime.d.ts +14 -0
- package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
- package/dist/telephony/ringcentral-runtime.js +18 -0
- package/dist/telephony/ringcentral-runtime.js.map +1 -0
- package/dist/telephony/teams-meetings-runtime.d.ts +16 -0
- package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
- package/dist/telephony/teams-meetings-runtime.js +20 -0
- package/dist/telephony/teams-meetings-runtime.js.map +1 -0
- package/dist/telephony/teamsAcsMediaRegistry.d.ts +69 -0
- package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
- package/dist/telephony/teamsAcsMediaRegistry.js +118 -0
- package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
- package/dist/telephony/telephony-runtime.d.ts +14 -0
- package/dist/telephony/telephony-runtime.d.ts.map +1 -0
- package/dist/telephony/telephony-runtime.js +18 -0
- package/dist/telephony/telephony-runtime.js.map +1 -0
- package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
- package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
- package/dist/telephony/twilioMediaRegistry.js +106 -0
- package/dist/telephony/twilioMediaRegistry.js.map +1 -0
- package/dist/telephony/vonage-runtime.d.ts +14 -0
- package/dist/telephony/vonage-runtime.d.ts.map +1 -0
- package/dist/telephony/vonage-runtime.js +18 -0
- package/dist/telephony/vonage-runtime.js.map +1 -0
- package/dist/telephony/vonageMediaRegistry.d.ts +78 -0
- package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
- package/dist/telephony/vonageMediaRegistry.js +158 -0
- package/dist/telephony/vonageMediaRegistry.js.map +1 -0
- package/package.json +88 -82
- package/src/__tests__/FileResolverPeaks.test.ts +64 -0
- package/src/__tests__/MediaAccessKeys.test.ts +68 -0
- package/src/__tests__/MediaStreamHandler.test.ts +91 -0
- package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -1
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +69 -0
- package/src/__tests__/RealtimeCoAgentAppAwareness.integration.test.ts +191 -0
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +123 -0
- package/src/__tests__/SessionManager.test.ts +2 -0
- package/src/__tests__/meetingRecordingRegistration.test.ts +248 -0
- package/src/__tests__/search-knowledge-tags.test.ts +9 -9
- package/src/__tests__/teams-meetings-service.test.ts +65 -0
- package/src/__tests__/teamsAcsMediaRegistry.test.ts +82 -0
- package/src/__tests__/twilio-telephony-service.test.ts +23 -0
- package/src/__tests__/twilioMediaRegistry.test.ts +103 -0
- package/src/__tests__/vonageMediaRegistry.test.ts +180 -0
- package/src/__tests__/widget.test.ts +204 -0
- package/src/__tests__/widgetGuestElevation.test.ts +57 -0
- package/src/__tests__/widgetHostIdentity.test.ts +117 -0
- package/src/agentSessions/ReturningVisitorRecap.ts +242 -0
- package/src/agentSessions/SessionJanitor.ts +66 -6
- package/src/agentSessions/SessionManager.ts +41 -0
- package/src/agentSessions/index.ts +3 -1
- package/src/auth/magicLink/MagicLinkRouter.ts +17 -0
- package/src/auth/magicLink/index.ts +1 -0
- package/src/auth/magicLink/types.ts +26 -0
- package/src/config.ts +172 -38
- package/src/context.ts +50 -3
- package/src/generated/generated.ts +26726 -20464
- package/src/generic/ResolverBase.ts +28 -0
- package/src/generic/RunViewResolver.ts +4 -0
- package/src/index.ts +119 -3
- package/src/integration/CustomColumnPromoter.ts +6 -0
- package/src/realtimeWidget/WidgetRouter.ts +204 -0
- package/src/realtimeWidget/WidgetSessionService.ts +714 -0
- package/src/realtimeWidget/host-identity.ts +84 -0
- package/src/realtimeWidget/index.ts +15 -0
- package/src/realtimeWidget/visitorIdentity.ts +258 -0
- package/src/realtimeWidget/widgetCore.ts +231 -0
- package/src/realtimeWidget/widgetGuestElevation.ts +115 -0
- package/src/resolvers/ComponentRegistryResolver.ts +36 -10
- package/src/resolvers/EntityPermissionResolver.ts +1 -2
- package/src/resolvers/FileResolver.ts +199 -1
- package/src/resolvers/QueryResolver.ts +33 -19
- package/src/resolvers/QuerySystemUserResolver.ts +14 -10
- package/src/resolvers/RealtimeBridgeResolver.ts +36 -4
- package/src/resolvers/RealtimeClientSessionResolver.ts +383 -9
- package/src/resolvers/RemoteBrowserActionResolver.ts +18 -2
- package/src/resolvers/RingCentralTelephonyResolver.ts +64 -0
- package/src/resolvers/RunAIAgentResolver.ts +60 -15
- package/src/resolvers/SearchKnowledgeResolver.ts +2 -0
- package/src/resolvers/TeamsMeetingsResolver.ts +68 -0
- package/src/resolvers/TelephonyResolver.ts +63 -0
- package/src/resolvers/TestQuerySQLResolver.ts +2 -3
- package/src/resolvers/VonageTelephonyResolver.ts +63 -0
- package/src/resolvers/meetingRecordingRegistration.ts +432 -0
- package/src/resolvers/peaksSidecar.ts +52 -0
- package/src/rest/MediaAccessKeys.ts +121 -0
- package/src/rest/MediaStreamHandler.ts +223 -0
- package/src/rest/mediaRange.ts +76 -0
- package/src/telephony/RingCentralTelephonyService.ts +342 -0
- package/src/telephony/TeamsMeetingsRouter.ts +124 -0
- package/src/telephony/TeamsMeetingsService.ts +268 -0
- package/src/telephony/TwilioTelephonyRouter.ts +184 -0
- package/src/telephony/TwilioTelephonyService.ts +261 -0
- package/src/telephony/VonageTelephonyRouter.ts +239 -0
- package/src/telephony/VonageTelephonyService.ts +259 -0
- package/src/telephony/calendar-scheduler.ts +176 -0
- package/src/telephony/index.ts +43 -0
- package/src/telephony/media-upgrade-router.ts +62 -0
- package/src/telephony/ringcentral-runtime.ts +22 -0
- package/src/telephony/teams-meetings-runtime.ts +24 -0
- package/src/telephony/teamsAcsMediaRegistry.ts +152 -0
- package/src/telephony/telephony-runtime.ts +22 -0
- package/src/telephony/twilioMediaRegistry.ts +137 -0
- package/src/telephony/vonage-runtime.ts +22 -0
- package/src/telephony/vonageMediaRegistry.ts +200 -0
- package/dist/agents/skip-agent.d.ts +0 -111
- package/dist/agents/skip-agent.d.ts.map +0 -1
- package/dist/agents/skip-agent.js +0 -1487
- package/dist/agents/skip-agent.js.map +0 -1
- package/dist/agents/skip-sdk.d.ts +0 -261
- package/dist/agents/skip-sdk.d.ts.map +0 -1
- package/dist/agents/skip-sdk.js +0 -909
- package/dist/agents/skip-sdk.js.map +0 -1
- package/src/agents/skip-agent.ts +0 -1594
- package/src/agents/skip-sdk.ts +0 -1210
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GraphQL surface for OUTBOUND RingCentral telephony: `PlaceRingCentralCall` rings a real
|
|
3
|
+
* phone from an agent identity and connects the pinned agent. Thin — it authorizes the caller, then
|
|
4
|
+
* delegates to the startup-constructed {@link RingCentralTelephonyService} (which owns the bridge
|
|
5
|
+
* orchestration + the shared media registry). Inbound calls arrive via the public
|
|
6
|
+
* `POST /telephony/ringcentral/webhook` notification, not GraphQL.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/server
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
12
|
+
import { LogError, IMetadataProvider } from '@memberjunction/core';
|
|
13
|
+
import { AppContext } from '../types.js';
|
|
14
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
15
|
+
import { GetReadWriteProvider } from '../util.js';
|
|
16
|
+
import { GetRingCentralTelephonyService } from '../telephony/ringcentral-runtime.js';
|
|
17
|
+
|
|
18
|
+
/** Result of an outbound RingCentral place-call attempt. */
|
|
19
|
+
@ObjectType()
|
|
20
|
+
export class PlaceRingCentralCallResult {
|
|
21
|
+
@Field(() => Boolean)
|
|
22
|
+
Success: boolean;
|
|
23
|
+
|
|
24
|
+
@Field(() => String, { nullable: true })
|
|
25
|
+
ErrorMessage?: string;
|
|
26
|
+
|
|
27
|
+
/** The placed RingCentral telephony session id (the bridge's external connection id). */
|
|
28
|
+
@Field(() => String)
|
|
29
|
+
SessionId: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Resolver()
|
|
33
|
+
export class RingCentralTelephonyResolver extends ResolverBase {
|
|
34
|
+
/**
|
|
35
|
+
* Places an outbound call from the given agent identity (its phone number is the caller-id) to a
|
|
36
|
+
* destination number, connecting the pinned agent over the realtime bridge. Returns the telephony
|
|
37
|
+
* session id.
|
|
38
|
+
*/
|
|
39
|
+
@Mutation(() => PlaceRingCentralCallResult)
|
|
40
|
+
async PlaceRingCentralCall(
|
|
41
|
+
@Arg('agentIdentityId', () => String) agentIdentityId: string,
|
|
42
|
+
@Arg('toNumber', () => String) toNumber: string,
|
|
43
|
+
@Ctx() context: AppContext = {} as AppContext,
|
|
44
|
+
): Promise<PlaceRingCentralCallResult> {
|
|
45
|
+
const failure = (msg: string): PlaceRingCentralCallResult => ({ Success: false, ErrorMessage: msg, SessionId: '' });
|
|
46
|
+
try {
|
|
47
|
+
const user = this.GetUserFromPayload(context.userPayload);
|
|
48
|
+
if (!user) {
|
|
49
|
+
return failure('Unable to determine current user.');
|
|
50
|
+
}
|
|
51
|
+
const service = GetRingCentralTelephonyService();
|
|
52
|
+
if (!service) {
|
|
53
|
+
return failure('RingCentral telephony is not configured on this server.');
|
|
54
|
+
}
|
|
55
|
+
const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
|
|
56
|
+
const sessionId = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
|
|
57
|
+
return { Success: true, SessionId: sessionId };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
60
|
+
LogError(`PlaceRingCentralCall failed: ${msg}`);
|
|
61
|
+
return failure(msg);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -12,6 +12,7 @@ import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
|
|
|
12
12
|
import { startLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
|
|
13
13
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
14
14
|
import { GetReadWriteProvider } from '../util.js';
|
|
15
|
+
import { resolveWidgetGuestRunContext, elevateUserPayload } from '../realtimeWidget/widgetGuestElevation.js';
|
|
15
16
|
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
16
17
|
import { GetAttachmentService } from '@memberjunction/aiengine';
|
|
17
18
|
import { NotificationEngine } from '@memberjunction/notifications';
|
|
@@ -376,7 +377,12 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
376
377
|
conversationId?: string,
|
|
377
378
|
/** Optional external ref the caller can read to observe the agent run as it becomes available
|
|
378
379
|
* (used by the fire-and-forget liveness pulse to enrich heartbeats with the run id/status). */
|
|
379
|
-
runRef?: { current: MJAIAgentRunEntityExtended | null }
|
|
380
|
+
runRef?: { current: MJAIAgentRunEntityExtended | null },
|
|
381
|
+
/** Per-request Plan Mode toggle — threaded into ExecuteAgentParams.planMode (root-agent HITL gate). */
|
|
382
|
+
planMode?: boolean,
|
|
383
|
+
/** Skill IDs the user requested (via `/skill-name`) — threaded into ExecuteAgentParams.requestedSkillIDs.
|
|
384
|
+
* The framework intersects them with the agent's accepted skills AND the user's Run permission. */
|
|
385
|
+
requestedSkillIDs?: string[]
|
|
380
386
|
): Promise<AIAgentRunResult> {
|
|
381
387
|
const startTime = Date.now();
|
|
382
388
|
|
|
@@ -428,6 +434,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
428
434
|
lastRunId: lastRunId,
|
|
429
435
|
autoPopulateLastRunPayload: autoPopulateLastRunPayload,
|
|
430
436
|
configurationId: configurationId,
|
|
437
|
+
planMode: planMode,
|
|
438
|
+
requestedSkillIDs: requestedSkillIDs,
|
|
431
439
|
data: parsedData,
|
|
432
440
|
context: {
|
|
433
441
|
dataSource: dataSource
|
|
@@ -614,7 +622,12 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
614
622
|
@Arg('createNotification', { nullable: true }) createNotification?: boolean,
|
|
615
623
|
@Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
|
|
616
624
|
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string,
|
|
617
|
-
@Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean
|
|
625
|
+
@Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean,
|
|
626
|
+
/** Per-request Plan Mode toggle — symmetric with RunAIAgentFromConversationDetail. */
|
|
627
|
+
@Arg('planMode', { nullable: true }) planMode?: boolean,
|
|
628
|
+
/** Skill IDs the user requested — symmetric with RunAIAgentFromConversationDetail. Intersected
|
|
629
|
+
* server-side with the agent's accepted skills AND the user's Run permission. */
|
|
630
|
+
@Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
|
|
618
631
|
): Promise<AIAgentRunResult> {
|
|
619
632
|
// Check API key scope authorization for agent execution
|
|
620
633
|
await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
|
|
@@ -628,7 +641,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
628
641
|
p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
|
|
629
642
|
data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
|
|
630
643
|
conversationDetailId, createArtifacts || false, createNotification || false,
|
|
631
|
-
sourceArtifactId, sourceArtifactVersionId
|
|
644
|
+
sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs
|
|
632
645
|
);
|
|
633
646
|
|
|
634
647
|
LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
|
|
@@ -658,7 +671,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
658
671
|
createArtifacts || false,
|
|
659
672
|
createNotification || false,
|
|
660
673
|
sourceArtifactId,
|
|
661
|
-
sourceArtifactVersionId
|
|
674
|
+
sourceArtifactVersionId,
|
|
675
|
+
undefined, // conversationId (not pre-resolved on this path)
|
|
676
|
+
undefined, // runRef
|
|
677
|
+
planMode,
|
|
678
|
+
requestedSkillIDs
|
|
662
679
|
);
|
|
663
680
|
}
|
|
664
681
|
|
|
@@ -684,7 +701,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
684
701
|
@Arg('createArtifacts', { nullable: true }) createArtifacts?: boolean,
|
|
685
702
|
@Arg('createNotification', { nullable: true }) createNotification?: boolean,
|
|
686
703
|
@Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
|
|
687
|
-
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string
|
|
704
|
+
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string,
|
|
705
|
+
/** Per-request Plan Mode toggle — symmetric with the other run mutations. */
|
|
706
|
+
@Arg('planMode', { nullable: true }) planMode?: boolean,
|
|
707
|
+
/** User-requested skill IDs — symmetric with the other run mutations. */
|
|
708
|
+
@Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
|
|
688
709
|
): Promise<AIAgentRunResult> {
|
|
689
710
|
const p = GetReadWriteProvider(providers);
|
|
690
711
|
return this.executeAIAgent(
|
|
@@ -705,7 +726,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
705
726
|
createArtifacts || false,
|
|
706
727
|
createNotification || false,
|
|
707
728
|
sourceArtifactId,
|
|
708
|
-
sourceArtifactVersionId
|
|
729
|
+
sourceArtifactVersionId,
|
|
730
|
+
undefined, // conversationId (not pre-resolved on this path)
|
|
731
|
+
undefined, // runRef
|
|
732
|
+
planMode,
|
|
733
|
+
requestedSkillIDs
|
|
709
734
|
);
|
|
710
735
|
}
|
|
711
736
|
|
|
@@ -932,7 +957,9 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
932
957
|
@Arg('createNotification', { nullable: true }) createNotification?: boolean,
|
|
933
958
|
@Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
|
|
934
959
|
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string,
|
|
935
|
-
@Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean
|
|
960
|
+
@Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean,
|
|
961
|
+
@Arg('planMode', { nullable: true }) planMode?: boolean,
|
|
962
|
+
@Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
|
|
936
963
|
): Promise<AIAgentRunResult> {
|
|
937
964
|
// Check API key scope authorization for agent execution
|
|
938
965
|
await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
|
|
@@ -948,6 +975,17 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
948
975
|
};
|
|
949
976
|
}
|
|
950
977
|
|
|
978
|
+
// PUBLIC WEB-WIDGET PRIVILEGED DISPATCH (public-web-widget.md Phase 0): when the request is a
|
|
979
|
+
// widget guest, the agent runs under a TRUSTED SERVER PRINCIPAL and the agent id is taken
|
|
980
|
+
// AUTHORITATIVELY from the widget instance (never the client-supplied arg) — so a guest needs
|
|
981
|
+
// no grants to WRITE the AI run entities and cannot run an arbitrary agent under elevation.
|
|
982
|
+
// Conversation OWNERSHIP is still enforced under the guest principal below: the guest loads its
|
|
983
|
+
// own ConversationDetail through the Widget Guest RLS filters, so a detail id from another
|
|
984
|
+
// session resolves to "not found" before any elevated work happens.
|
|
985
|
+
const widgetElevation = await resolveWidgetGuestRunContext(userPayload, p);
|
|
986
|
+
const effectiveAgentId = widgetElevation ? widgetElevation.pinnedAgentId : agentId;
|
|
987
|
+
const effectiveUserPayload = widgetElevation ? elevateUserPayload(userPayload, widgetElevation.elevatedUser) : userPayload;
|
|
988
|
+
|
|
951
989
|
try {
|
|
952
990
|
// LATENCY OPTIMIZATION (Opt #2 + #3): Load ConversationDetail once here to extract
|
|
953
991
|
// conversationId, then pass it downstream. Previously this record was loaded multiple
|
|
@@ -978,13 +1016,13 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
978
1016
|
// Fire-and-forget mode: start execution in background, return immediately.
|
|
979
1017
|
// The client will receive the result via WebSocket PubSub completion event.
|
|
980
1018
|
this.executeAgentInBackground(
|
|
981
|
-
p, dataSource,
|
|
1019
|
+
p, dataSource, effectiveAgentId, effectiveUserPayload, messagesJson, sessionId, pubSub,
|
|
982
1020
|
data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
|
|
983
1021
|
conversationDetailId, createArtifacts || false, createNotification || false,
|
|
984
|
-
sourceArtifactId, sourceArtifactVersionId, conversationId
|
|
1022
|
+
sourceArtifactId, sourceArtifactVersionId, conversationId, planMode, requestedSkillIDs
|
|
985
1023
|
);
|
|
986
1024
|
|
|
987
|
-
LogStatus(`🔥 Fire-and-forget: Agent ${
|
|
1025
|
+
LogStatus(`🔥 Fire-and-forget: Agent ${effectiveAgentId} execution started in background for session ${sessionId}`);
|
|
988
1026
|
|
|
989
1027
|
return {
|
|
990
1028
|
success: true,
|
|
@@ -996,8 +1034,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
996
1034
|
return this.executeAIAgent(
|
|
997
1035
|
p,
|
|
998
1036
|
dataSource,
|
|
999
|
-
|
|
1000
|
-
|
|
1037
|
+
effectiveAgentId,
|
|
1038
|
+
effectiveUserPayload,
|
|
1001
1039
|
messagesJson,
|
|
1002
1040
|
sessionId,
|
|
1003
1041
|
pubSub,
|
|
@@ -1012,7 +1050,10 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1012
1050
|
createNotification || false,
|
|
1013
1051
|
sourceArtifactId,
|
|
1014
1052
|
sourceArtifactVersionId,
|
|
1015
|
-
conversationId // LATENCY OPT #2: pass pre-resolved conversationId
|
|
1053
|
+
conversationId, // LATENCY OPT #2: pass pre-resolved conversationId
|
|
1054
|
+
undefined, // runRef
|
|
1055
|
+
planMode,
|
|
1056
|
+
requestedSkillIDs
|
|
1016
1057
|
);
|
|
1017
1058
|
} catch (error) {
|
|
1018
1059
|
const errorMessage = (error as Error).message || 'Unknown error loading conversation history';
|
|
@@ -1227,7 +1268,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1227
1268
|
sourceArtifactId?: string,
|
|
1228
1269
|
sourceArtifactVersionId?: string,
|
|
1229
1270
|
/** LATENCY OPT #2: Pre-resolved conversationId avoids redundant DB load in AgentRunner */
|
|
1230
|
-
conversationId?: string
|
|
1271
|
+
conversationId?: string,
|
|
1272
|
+
/** Per-request Plan Mode toggle — threaded through to ExecuteAgentParams.planMode. */
|
|
1273
|
+
planMode?: boolean,
|
|
1274
|
+
/** Skill IDs the user requested — threaded through to ExecuteAgentParams.requestedSkillIDs. */
|
|
1275
|
+
requestedSkillIDs?: string[]
|
|
1231
1276
|
): void {
|
|
1232
1277
|
// Ref the liveness pulse reads to enrich heartbeats once the run is created.
|
|
1233
1278
|
const runRef: { current: MJAIAgentRunEntityExtended | null } = { current: null };
|
|
@@ -1245,7 +1290,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1245
1290
|
p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
|
|
1246
1291
|
data, payload, undefined, lastRunId, autoPopulateLastRunPayload,
|
|
1247
1292
|
configurationId, conversationDetailId, createArtifacts, createNotification,
|
|
1248
|
-
sourceArtifactId, sourceArtifactVersionId, conversationId, runRef
|
|
1293
|
+
sourceArtifactId, sourceArtifactVersionId, conversationId, runRef, planMode, requestedSkillIDs
|
|
1249
1294
|
).catch((error: unknown) => {
|
|
1250
1295
|
// Background execution failed unexpectedly (executeAIAgent has its own try-catch,
|
|
1251
1296
|
// so this would only fire for truly unexpected errors).
|
|
@@ -213,6 +213,7 @@ export class SearchKnowledgeResolver extends ResolverBase {
|
|
|
213
213
|
): Promise<SearchKnowledgeResult> {
|
|
214
214
|
const startTime = Date.now();
|
|
215
215
|
try {
|
|
216
|
+
await this.CheckAPIKeyScopeAuthorization('search:execute', '*', userPayload);
|
|
216
217
|
const currentUser = this.GetUserFromPayload(userPayload);
|
|
217
218
|
if (!currentUser) {
|
|
218
219
|
return this.errorResult('Unable to determine current user', startTime);
|
|
@@ -400,6 +401,7 @@ export class SearchKnowledgeResolver extends ResolverBase {
|
|
|
400
401
|
): Promise<SearchKnowledgeResult> {
|
|
401
402
|
const startTime = Date.now();
|
|
402
403
|
try {
|
|
404
|
+
await this.CheckAPIKeyScopeAuthorization('search:execute', '*', userPayload);
|
|
403
405
|
const currentUser = this.GetUserFromPayload(userPayload);
|
|
404
406
|
if (!currentUser) {
|
|
405
407
|
return this.errorResult('Unable to determine current user', startTime);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GraphQL surface for Teams meeting joins: `StartTeamsMeetingSession` has an agent identity
|
|
3
|
+
* join a Teams meeting by URL and connects the pinned agent over the realtime bridge. Thin — it authorizes
|
|
4
|
+
* the caller, then delegates to the startup-constructed {@link TeamsMeetingsService} (which owns the bridge
|
|
5
|
+
* orchestration + the shared ACS media registry). Roster/call-ended updates arrive via the public
|
|
6
|
+
* `POST /meetings/teams/notifications` Graph webhook, not GraphQL.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors `TelephonyResolver.ts` (the Twilio `PlaceTwilioCall` equivalent).
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/server
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
14
|
+
import { LogError, IMetadataProvider } from '@memberjunction/core';
|
|
15
|
+
import { AppContext } from '../types.js';
|
|
16
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
17
|
+
import { GetReadWriteProvider } from '../util.js';
|
|
18
|
+
import { GetTeamsMeetingsService } from '../telephony/teams-meetings-runtime.js';
|
|
19
|
+
|
|
20
|
+
/** Result of a Teams meeting join attempt. */
|
|
21
|
+
@ObjectType()
|
|
22
|
+
export class StartTeamsMeetingResult {
|
|
23
|
+
@Field(() => Boolean)
|
|
24
|
+
Success: boolean;
|
|
25
|
+
|
|
26
|
+
@Field(() => String, { nullable: true })
|
|
27
|
+
ErrorMessage?: string;
|
|
28
|
+
|
|
29
|
+
/** The Graph call id the bot joined (the bridge's external connection id), when successful. */
|
|
30
|
+
@Field(() => String)
|
|
31
|
+
CallId: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Resolver()
|
|
35
|
+
export class TeamsMeetingsResolver extends ResolverBase {
|
|
36
|
+
/**
|
|
37
|
+
* Has the given agent identity join a Teams meeting by URL, connecting the pinned agent over the realtime
|
|
38
|
+
* bridge. Returns the Graph call id.
|
|
39
|
+
*/
|
|
40
|
+
@Mutation(() => StartTeamsMeetingResult)
|
|
41
|
+
async StartTeamsMeetingSession(
|
|
42
|
+
@Arg('agentIdentityId', () => String) agentIdentityId: string,
|
|
43
|
+
@Arg('joinUrl', () => String) joinUrl: string,
|
|
44
|
+
@Ctx() context: AppContext = {} as AppContext,
|
|
45
|
+
): Promise<StartTeamsMeetingResult> {
|
|
46
|
+
const failure = (msg: string): StartTeamsMeetingResult => ({ Success: false, ErrorMessage: msg, CallId: '' });
|
|
47
|
+
try {
|
|
48
|
+
const user = this.GetUserFromPayload(context.userPayload);
|
|
49
|
+
if (!user) {
|
|
50
|
+
return failure('Unable to determine current user.');
|
|
51
|
+
}
|
|
52
|
+
const service = GetTeamsMeetingsService();
|
|
53
|
+
if (!service) {
|
|
54
|
+
return failure('Teams meetings are not configured on this server.');
|
|
55
|
+
}
|
|
56
|
+
const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
|
|
57
|
+
const result = await service.JoinMeetingByUrl(agentIdentityId, joinUrl, user, provider);
|
|
58
|
+
if (!result.accepted) {
|
|
59
|
+
return failure(result.reason ?? 'The meeting join was not accepted.');
|
|
60
|
+
}
|
|
61
|
+
return { Success: true, CallId: result.callId ?? '' };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
64
|
+
LogError(`StartTeamsMeetingSession failed: ${msg}`);
|
|
65
|
+
return failure(msg);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GraphQL surface for OUTBOUND telephony: `PlaceTwilioCall` rings a real phone from
|
|
3
|
+
* an agent identity and connects the pinned agent. Thin — it authorizes the caller, then delegates to
|
|
4
|
+
* the startup-constructed {@link TwilioTelephonyService} (which owns the bridge orchestration + the
|
|
5
|
+
* shared media registry). Inbound calls arrive via the public `POST /telephony/twilio/voice` webhook,
|
|
6
|
+
* not GraphQL.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/server
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
12
|
+
import { LogError, IMetadataProvider } from '@memberjunction/core';
|
|
13
|
+
import { AppContext } from '../types.js';
|
|
14
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
15
|
+
import { GetReadWriteProvider } from '../util.js';
|
|
16
|
+
import { GetTwilioTelephonyService } from '../telephony/telephony-runtime.js';
|
|
17
|
+
|
|
18
|
+
/** Result of an outbound place-call attempt. */
|
|
19
|
+
@ObjectType()
|
|
20
|
+
export class PlaceCallResult {
|
|
21
|
+
@Field(() => Boolean)
|
|
22
|
+
Success: boolean;
|
|
23
|
+
|
|
24
|
+
@Field(() => String, { nullable: true })
|
|
25
|
+
ErrorMessage?: string;
|
|
26
|
+
|
|
27
|
+
/** The placed Twilio Call SID (the bridge's external connection id). */
|
|
28
|
+
@Field(() => String)
|
|
29
|
+
CallSid: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Resolver()
|
|
33
|
+
export class TelephonyResolver extends ResolverBase {
|
|
34
|
+
/**
|
|
35
|
+
* Places an outbound call from the given agent identity (its phone number is the caller-id) to a
|
|
36
|
+
* destination number, connecting the pinned agent over the realtime bridge. Returns the Call SID.
|
|
37
|
+
*/
|
|
38
|
+
@Mutation(() => PlaceCallResult)
|
|
39
|
+
async PlaceTwilioCall(
|
|
40
|
+
@Arg('agentIdentityId', () => String) agentIdentityId: string,
|
|
41
|
+
@Arg('toNumber', () => String) toNumber: string,
|
|
42
|
+
@Ctx() context: AppContext = {} as AppContext,
|
|
43
|
+
): Promise<PlaceCallResult> {
|
|
44
|
+
const failure = (msg: string): PlaceCallResult => ({ Success: false, ErrorMessage: msg, CallSid: '' });
|
|
45
|
+
try {
|
|
46
|
+
const user = this.GetUserFromPayload(context.userPayload);
|
|
47
|
+
if (!user) {
|
|
48
|
+
return failure('Unable to determine current user.');
|
|
49
|
+
}
|
|
50
|
+
const service = GetTwilioTelephonyService();
|
|
51
|
+
if (!service) {
|
|
52
|
+
return failure('Twilio telephony is not configured on this server.');
|
|
53
|
+
}
|
|
54
|
+
const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
|
|
55
|
+
const callSid = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
|
|
56
|
+
return { Success: true, CallSid: callSid };
|
|
57
|
+
} catch (error) {
|
|
58
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
59
|
+
LogError(`PlaceTwilioCall failed: ${msg}`);
|
|
60
|
+
return failure(msg);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -2,7 +2,6 @@ import { Arg, Ctx, Field, InputType, Int, ObjectType, Query, Resolver } from 'ty
|
|
|
2
2
|
import { GraphQLJSONObject } from 'graphql-type-json';
|
|
3
3
|
import { RunQuery, IRunQueryProvider, LogError, LogStatus, QueryExecutionSpec } from '@memberjunction/core';
|
|
4
4
|
import { AppContext } from '../types.js';
|
|
5
|
-
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
6
5
|
import { GetReadOnlyProvider } from '../util.js';
|
|
7
6
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
8
7
|
|
|
@@ -85,7 +84,7 @@ export class TestQuerySQLResult {
|
|
|
85
84
|
* enabling external systems (e.g., Skip-Brain) to test query SQL before saving to the database.
|
|
86
85
|
*
|
|
87
86
|
* Security:
|
|
88
|
-
* - Requires
|
|
87
|
+
* - Requires `query:test` scope for API key users (no-op for JWT auth)
|
|
89
88
|
* - Uses read-only database connection (no mutation possible)
|
|
90
89
|
* - Enforces MaxRows limit (default 100) to prevent unbounded queries
|
|
91
90
|
*
|
|
@@ -93,7 +92,6 @@ export class TestQuerySQLResult {
|
|
|
93
92
|
*/
|
|
94
93
|
@Resolver()
|
|
95
94
|
export class TestQuerySQLResolver extends ResolverBase {
|
|
96
|
-
@RequireSystemUser()
|
|
97
95
|
@Query(() => TestQuerySQLResult, {
|
|
98
96
|
description: 'Test transient SQL with full composition + Nunjucks template processing without requiring a saved query'
|
|
99
97
|
})
|
|
@@ -102,6 +100,7 @@ export class TestQuerySQLResolver extends ResolverBase {
|
|
|
102
100
|
@Ctx() context: AppContext
|
|
103
101
|
): Promise<TestQuerySQLResult> {
|
|
104
102
|
try {
|
|
103
|
+
await this.CheckAPIKeyScopeAuthorization('query:test', '*', context.userPayload);
|
|
105
104
|
// Use read-only provider for security — no mutation possible
|
|
106
105
|
const provider = GetReadOnlyProvider(context.providers, { allowFallbackToReadWrite: false });
|
|
107
106
|
if (!provider) {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GraphQL surface for OUTBOUND Vonage telephony: `PlaceVonageCall` rings a real phone from
|
|
3
|
+
* an agent identity and connects the pinned agent. Thin — it authorizes the caller, then delegates to
|
|
4
|
+
* the startup-constructed {@link VonageTelephonyService} (which owns the bridge orchestration + the
|
|
5
|
+
* shared media registry). Inbound calls arrive via the public `POST /telephony/vonage/answer` webhook,
|
|
6
|
+
* not GraphQL.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/server
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
12
|
+
import { LogError, IMetadataProvider } from '@memberjunction/core';
|
|
13
|
+
import { AppContext } from '../types.js';
|
|
14
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
15
|
+
import { GetReadWriteProvider } from '../util.js';
|
|
16
|
+
import { GetVonageTelephonyService } from '../telephony/vonage-runtime.js';
|
|
17
|
+
|
|
18
|
+
/** Result of an outbound place-call attempt. */
|
|
19
|
+
@ObjectType()
|
|
20
|
+
export class PlaceVonageCallResult {
|
|
21
|
+
@Field(() => Boolean)
|
|
22
|
+
Success: boolean;
|
|
23
|
+
|
|
24
|
+
@Field(() => String, { nullable: true })
|
|
25
|
+
ErrorMessage?: string;
|
|
26
|
+
|
|
27
|
+
/** The placed Vonage call UUID (the bridge's external connection id). */
|
|
28
|
+
@Field(() => String)
|
|
29
|
+
CallId: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Resolver()
|
|
33
|
+
export class VonageTelephonyResolver extends ResolverBase {
|
|
34
|
+
/**
|
|
35
|
+
* Places an outbound call from the given agent identity (its phone number is the caller-id) to a
|
|
36
|
+
* destination number, connecting the pinned agent over the realtime bridge. Returns the call UUID.
|
|
37
|
+
*/
|
|
38
|
+
@Mutation(() => PlaceVonageCallResult)
|
|
39
|
+
async PlaceVonageCall(
|
|
40
|
+
@Arg('agentIdentityId', () => String) agentIdentityId: string,
|
|
41
|
+
@Arg('toNumber', () => String) toNumber: string,
|
|
42
|
+
@Ctx() context: AppContext = {} as AppContext,
|
|
43
|
+
): Promise<PlaceVonageCallResult> {
|
|
44
|
+
const failure = (msg: string): PlaceVonageCallResult => ({ Success: false, ErrorMessage: msg, CallId: '' });
|
|
45
|
+
try {
|
|
46
|
+
const user = this.GetUserFromPayload(context.userPayload);
|
|
47
|
+
if (!user) {
|
|
48
|
+
return failure('Unable to determine current user.');
|
|
49
|
+
}
|
|
50
|
+
const service = GetVonageTelephonyService();
|
|
51
|
+
if (!service) {
|
|
52
|
+
return failure('Vonage telephony is not configured on this server.');
|
|
53
|
+
}
|
|
54
|
+
const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
|
|
55
|
+
const callId = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
|
|
56
|
+
return { Success: true, CallId: callId };
|
|
57
|
+
} catch (error) {
|
|
58
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
59
|
+
LogError(`PlaceVonageCall failed: ${msg}`);
|
|
60
|
+
return failure(msg);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|