@memberjunction/server 6.1.0-edge.6 → 6.1.0-edge.7
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 +24 -9
- package/dist/.tsbuildinfo +1 -1
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -0
- package/dist/config.js.map +1 -1
- package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.d.ts +30 -0
- package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.d.ts.map +1 -1
- package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.js +58 -5
- package/dist/entitySubclasses/MJEntityPermissionEntityServer.server.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +2842 -2144
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +5334 -2143
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +119 -4
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +264 -11
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +26 -2
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/generic/refusalExtensions.d.ts +52 -0
- package/dist/generic/refusalExtensions.d.ts.map +1 -0
- package/dist/generic/refusalExtensions.js +16 -0
- package/dist/generic/refusalExtensions.js.map +1 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -91
- package/dist/index.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +34 -5
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +64 -7
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +10 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +80 -4
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts +23 -0
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -0
- package/dist/rest/RealtimeSdpBrokerHandler.js +78 -0
- package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -0
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +2 -3
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/package.json +92 -92
- package/src/__tests__/EntityRecordNameResolver.fieldSecurity.test.ts +118 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +20 -0
- package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +191 -0
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +63 -0
- package/src/__tests__/ResolverBase.readableFieldsTransport.test.ts +106 -0
- package/src/__tests__/generatedGraphQLSchema.structural.test.ts +46 -0
- package/src/__tests__/resolverBase.fls.test.ts +483 -0
- package/src/__tests__/resolverBase.recordChangesFls.test.ts +358 -0
- package/src/__tests__/resolverBase.refusalExtensions.test.ts +101 -0
- package/src/__tests__/serverExtensionReservedRoots.test.ts +79 -11
- package/src/config.ts +12 -0
- package/src/entitySubclasses/MJEntityPermissionEntityServer.server.ts +65 -6
- package/src/generated/graphql-schemas/__mj.ts +6590 -4287
- package/src/generic/ResolverBase.ts +313 -10
- package/src/generic/RunViewResolver.ts +28 -2
- package/src/generic/refusalExtensions.ts +59 -0
- package/src/index.ts +137 -100
- package/src/resolvers/EntityRecordNameResolver.ts +74 -8
- package/src/resolvers/RealtimeClientSessionResolver.ts +128 -2
- package/src/rest/RealtimeSdpBrokerHandler.ts +101 -0
- package/src/serverExtensionReservedRoots.ts +2 -3
- package/dist/resolvers/RingCentralTelephonyResolver.d.ts +0 -27
- package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +0 -1
- package/dist/resolvers/RingCentralTelephonyResolver.js +0 -87
- package/dist/resolvers/RingCentralTelephonyResolver.js.map +0 -1
- package/dist/resolvers/TeamsMeetingsResolver.d.ts +0 -28
- package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +0 -1
- package/dist/resolvers/TeamsMeetingsResolver.js +0 -91
- package/dist/resolvers/TeamsMeetingsResolver.js.map +0 -1
- package/dist/resolvers/TelephonyResolver.d.ts +0 -26
- package/dist/resolvers/TelephonyResolver.d.ts.map +0 -1
- package/dist/resolvers/TelephonyResolver.js +0 -86
- package/dist/resolvers/TelephonyResolver.js.map +0 -1
- package/dist/resolvers/VonageTelephonyResolver.d.ts +0 -26
- package/dist/resolvers/VonageTelephonyResolver.d.ts.map +0 -1
- package/dist/resolvers/VonageTelephonyResolver.js +0 -86
- package/dist/resolvers/VonageTelephonyResolver.js.map +0 -1
- package/dist/telephony/RingCentralTelephonyService.d.ts +0 -115
- package/dist/telephony/RingCentralTelephonyService.d.ts.map +0 -1
- package/dist/telephony/RingCentralTelephonyService.js +0 -262
- package/dist/telephony/RingCentralTelephonyService.js.map +0 -1
- package/dist/telephony/TeamsMeetingsRouter.d.ts +0 -40
- package/dist/telephony/TeamsMeetingsRouter.d.ts.map +0 -1
- package/dist/telephony/TeamsMeetingsRouter.js +0 -112
- package/dist/telephony/TeamsMeetingsRouter.js.map +0 -1
- package/dist/telephony/TeamsMeetingsService.d.ts +0 -113
- package/dist/telephony/TeamsMeetingsService.d.ts.map +0 -1
- package/dist/telephony/TeamsMeetingsService.js +0 -196
- package/dist/telephony/TeamsMeetingsService.js.map +0 -1
- package/dist/telephony/TwilioTelephonyRouter.d.ts +0 -36
- package/dist/telephony/TwilioTelephonyRouter.d.ts.map +0 -1
- package/dist/telephony/TwilioTelephonyRouter.js +0 -143
- package/dist/telephony/TwilioTelephonyRouter.js.map +0 -1
- package/dist/telephony/TwilioTelephonyService.d.ts +0 -95
- package/dist/telephony/TwilioTelephonyService.d.ts.map +0 -1
- package/dist/telephony/TwilioTelephonyService.js +0 -193
- package/dist/telephony/TwilioTelephonyService.js.map +0 -1
- package/dist/telephony/VonageTelephonyRouter.d.ts +0 -41
- package/dist/telephony/VonageTelephonyRouter.d.ts.map +0 -1
- package/dist/telephony/VonageTelephonyRouter.js +0 -201
- package/dist/telephony/VonageTelephonyRouter.js.map +0 -1
- package/dist/telephony/VonageTelephonyService.d.ts +0 -90
- package/dist/telephony/VonageTelephonyService.d.ts.map +0 -1
- package/dist/telephony/VonageTelephonyService.js +0 -191
- package/dist/telephony/VonageTelephonyService.js.map +0 -1
- package/dist/telephony/calendar-scheduler.d.ts +0 -67
- package/dist/telephony/calendar-scheduler.d.ts.map +0 -1
- package/dist/telephony/calendar-scheduler.js +0 -133
- package/dist/telephony/calendar-scheduler.js.map +0 -1
- package/dist/telephony/index.d.ts +0 -29
- package/dist/telephony/index.d.ts.map +0 -1
- package/dist/telephony/index.js +0 -38
- package/dist/telephony/index.js.map +0 -1
- package/dist/telephony/media-upgrade-router.d.ts +0 -47
- package/dist/telephony/media-upgrade-router.d.ts.map +0 -1
- package/dist/telephony/media-upgrade-router.js +0 -72
- package/dist/telephony/media-upgrade-router.js.map +0 -1
- package/dist/telephony/ringcentral-runtime.d.ts +0 -14
- package/dist/telephony/ringcentral-runtime.d.ts.map +0 -1
- package/dist/telephony/ringcentral-runtime.js +0 -18
- package/dist/telephony/ringcentral-runtime.js.map +0 -1
- package/dist/telephony/teams-meetings-runtime.d.ts +0 -16
- package/dist/telephony/teams-meetings-runtime.d.ts.map +0 -1
- package/dist/telephony/teams-meetings-runtime.js +0 -20
- package/dist/telephony/teams-meetings-runtime.js.map +0 -1
- package/dist/telephony/teamsAcsMediaRegistry.d.ts +0 -69
- package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +0 -1
- package/dist/telephony/teamsAcsMediaRegistry.js +0 -118
- package/dist/telephony/teamsAcsMediaRegistry.js.map +0 -1
- package/dist/telephony/telephony-runtime.d.ts +0 -14
- package/dist/telephony/telephony-runtime.d.ts.map +0 -1
- package/dist/telephony/telephony-runtime.js +0 -18
- package/dist/telephony/telephony-runtime.js.map +0 -1
- package/dist/telephony/twilioMediaRegistry.d.ts +0 -60
- package/dist/telephony/twilioMediaRegistry.d.ts.map +0 -1
- package/dist/telephony/twilioMediaRegistry.js +0 -106
- package/dist/telephony/twilioMediaRegistry.js.map +0 -1
- package/dist/telephony/vonage-runtime.d.ts +0 -14
- package/dist/telephony/vonage-runtime.d.ts.map +0 -1
- package/dist/telephony/vonage-runtime.js +0 -18
- package/dist/telephony/vonage-runtime.js.map +0 -1
- package/dist/telephony/vonageMediaRegistry.d.ts +0 -78
- package/dist/telephony/vonageMediaRegistry.d.ts.map +0 -1
- package/dist/telephony/vonageMediaRegistry.js +0 -158
- package/dist/telephony/vonageMediaRegistry.js.map +0 -1
- package/src/__tests__/media-upgrade-router.test.ts +0 -43
- package/src/__tests__/teams-meetings-service.test.ts +0 -65
- package/src/__tests__/teamsAcsMediaRegistry.test.ts +0 -82
- package/src/__tests__/twilio-telephony-service.test.ts +0 -23
- package/src/__tests__/twilioMediaRegistry.test.ts +0 -103
- package/src/__tests__/vonageMediaRegistry.test.ts +0 -180
- package/src/resolvers/RingCentralTelephonyResolver.ts +0 -64
- package/src/resolvers/TeamsMeetingsResolver.ts +0 -68
- package/src/resolvers/TelephonyResolver.ts +0 -63
- package/src/resolvers/VonageTelephonyResolver.ts +0 -63
- package/src/telephony/RingCentralTelephonyService.ts +0 -342
- package/src/telephony/TeamsMeetingsRouter.ts +0 -143
- package/src/telephony/TeamsMeetingsService.ts +0 -268
- package/src/telephony/TwilioTelephonyRouter.ts +0 -184
- package/src/telephony/TwilioTelephonyService.ts +0 -261
- package/src/telephony/VonageTelephonyRouter.ts +0 -239
- package/src/telephony/VonageTelephonyService.ts +0 -259
- package/src/telephony/calendar-scheduler.ts +0 -176
- package/src/telephony/index.ts +0 -43
- package/src/telephony/media-upgrade-router.ts +0 -79
- package/src/telephony/ringcentral-runtime.ts +0 -22
- package/src/telephony/teams-meetings-runtime.ts +0 -24
- package/src/telephony/teamsAcsMediaRegistry.ts +0 -152
- package/src/telephony/telephony-runtime.ts +0 -22
- package/src/telephony/twilioMediaRegistry.ts +0 -137
- package/src/telephony/vonage-runtime.ts +0 -22
- package/src/telephony/vonageMediaRegistry.ts +0 -200
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
ParseRealtimeTypeConfiguration,
|
|
50
50
|
ResolveEffectiveRealtimeConfig,
|
|
51
51
|
RealtimeAllowedAgent,
|
|
52
|
+
RealtimeDirectActionsConfig,
|
|
52
53
|
REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION,
|
|
53
54
|
resolveRecordingStorageAccountID,
|
|
54
55
|
storeRealtimeRecording,
|
|
@@ -181,6 +182,11 @@ interface RealtimeSessionConfig {
|
|
|
181
182
|
* model-named colleague against it without re-resolving the cascade. Absent ⇒ single-target behavior.
|
|
182
183
|
*/
|
|
183
184
|
allowedAgents?: RealtimeAllowedAgent[];
|
|
185
|
+
/**
|
|
186
|
+
* The session's effective direct actions configuration (derived from the full config cascade at start).
|
|
187
|
+
* Persisted so each relayed direct action call enforces against the exact same config used for projection.
|
|
188
|
+
*/
|
|
189
|
+
directActions?: RealtimeDirectActionsConfig;
|
|
184
190
|
/**
|
|
185
191
|
* Per-session override for the agent's media kit — a `MJ: Collections` id that takes precedence
|
|
186
192
|
* over the agent's `DefaultMediaCollectionID` when the server-side `MediaChannelServer` resolves
|
|
@@ -525,6 +531,10 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
525
531
|
'under the system user (scoped-anonymous caller).',
|
|
526
532
|
);
|
|
527
533
|
}
|
|
534
|
+
LogStatus(
|
|
535
|
+
`ExecuteRealtimeSessionTool: dispatching relayed tool '${toolName}' (callId: ${callId}) for session ${agentSessionId}...`,
|
|
536
|
+
);
|
|
537
|
+
const startTime = Date.now();
|
|
528
538
|
const { ResultJson, PausedRunID, Artifacts } = await this.clientSessionService.ExecuteRelayedTool(
|
|
529
539
|
{
|
|
530
540
|
AgentSessionID: agentSessionId,
|
|
@@ -532,6 +542,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
532
542
|
// Multi-target (Move 4): the session's persisted allowed-agent union — a model-named
|
|
533
543
|
// colleague in the call is validated against this; absent ⇒ single-target behavior.
|
|
534
544
|
AllowedAgents: await this.filterAllowedAgentsByCanRun(config.allowedAgents, contextUser),
|
|
545
|
+
DirectActions: config.directActions,
|
|
535
546
|
// Attribution follows the VISITOR even when `runUser` is elevated: the delegated run
|
|
536
547
|
// row and its context-memory scope must stay the person's, not the system user's.
|
|
537
548
|
AttributionUserID: contextUser.ID,
|
|
@@ -545,6 +556,23 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
545
556
|
runUser,
|
|
546
557
|
provider,
|
|
547
558
|
);
|
|
559
|
+
const durationMs = Date.now() - startTime;
|
|
560
|
+
LogStatus(
|
|
561
|
+
`ExecuteRealtimeSessionTool: completed relayed tool '${toolName}' (callId: ${callId}) in ${durationMs}ms`,
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
if (toolName !== 'invoke-target-agent') {
|
|
565
|
+
await this.persistDirectActionTurn(
|
|
566
|
+
session,
|
|
567
|
+
callId,
|
|
568
|
+
toolName,
|
|
569
|
+
argsJson,
|
|
570
|
+
ResultJson,
|
|
571
|
+
durationMs,
|
|
572
|
+
contextUser,
|
|
573
|
+
provider,
|
|
574
|
+
);
|
|
575
|
+
}
|
|
548
576
|
|
|
549
577
|
// Roll the paused-run id forward in the session config: clear the one we just consumed, and
|
|
550
578
|
// store a new one only if the (resumed or fresh) run paused again awaiting feedback.
|
|
@@ -832,8 +860,9 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
832
860
|
|
|
833
861
|
/**
|
|
834
862
|
* Relays a co-agent CHANNEL tool-call (browser_ / Whiteboard_ etc.) onto the session's co-agent
|
|
835
|
-
* AIPromptRun.Messages
|
|
836
|
-
*
|
|
863
|
+
* AIPromptRun.Messages and records the tool execution facts as a hidden ConversationDetail turn.
|
|
864
|
+
* HiddenToUser=true ensures chat components stay speech-only while allowing session review to
|
|
865
|
+
* reconstruct action cards dynamically on load (Option 1).
|
|
837
866
|
* Ownership-gated; best-effort (a missing prompt run / save failure simply returns false).
|
|
838
867
|
*
|
|
839
868
|
* @returns `true` when the tool turn was recorded on the run.
|
|
@@ -848,6 +877,20 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
848
877
|
): Promise<boolean> {
|
|
849
878
|
const { contextUser, provider } = this.requireUserAndProvider(userPayload, providers);
|
|
850
879
|
const session = await this.loadOwnedActiveSession(agentSessionId, contextUser, provider);
|
|
880
|
+
|
|
881
|
+
// Persist the tool turn facts into a hidden ConversationDetail turn so session review
|
|
882
|
+
// can reconstruct the tool card dynamically on load (Option 1). Best-effort.
|
|
883
|
+
await this.persistDirectActionTurn(
|
|
884
|
+
session,
|
|
885
|
+
undefined,
|
|
886
|
+
toolName,
|
|
887
|
+
argsJson,
|
|
888
|
+
resultJson,
|
|
889
|
+
undefined,
|
|
890
|
+
contextUser,
|
|
891
|
+
provider,
|
|
892
|
+
);
|
|
893
|
+
|
|
851
894
|
const promptRunID = this.readPromptRunID(session);
|
|
852
895
|
if (!promptRunID) {
|
|
853
896
|
return false;
|
|
@@ -1701,6 +1744,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
1701
1744
|
await this.persistObservabilityRunIDs(
|
|
1702
1745
|
session, targetAgentId, prep.CoAgentRunID, prep.PromptRunID, prep.CoAgentRunStepID,
|
|
1703
1746
|
applicationId, prep.EffectiveConfig?.realtime?.allowedAgents,
|
|
1747
|
+
prep.EffectiveConfig?.realtime?.directActions,
|
|
1704
1748
|
);
|
|
1705
1749
|
|
|
1706
1750
|
const cfg = prep.ClientConfig;
|
|
@@ -1734,6 +1778,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
1734
1778
|
coAgentRunStepID?: string,
|
|
1735
1779
|
applicationID?: string,
|
|
1736
1780
|
allowedAgents?: RealtimeAllowedAgent[],
|
|
1781
|
+
directActions?: RealtimeDirectActionsConfig,
|
|
1737
1782
|
): Promise<void> {
|
|
1738
1783
|
// Preserve any server-authoritative voice deadline stamped at session start (this rebuilds the
|
|
1739
1784
|
// full config, so read the existing value forward rather than dropping it).
|
|
@@ -1746,6 +1791,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
1746
1791
|
maxSessionDeadlineIso: existing?.maxSessionDeadlineIso,
|
|
1747
1792
|
applicationID,
|
|
1748
1793
|
allowedAgents: allowedAgents && allowedAgents.length > 0 ? allowedAgents : undefined,
|
|
1794
|
+
directActions,
|
|
1749
1795
|
};
|
|
1750
1796
|
session.Config_ = JSON.stringify(config);
|
|
1751
1797
|
const saved = await session.Save();
|
|
@@ -2476,6 +2522,10 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
2476
2522
|
typeof parsed.maxSessionDeadlineIso === 'string' ? parsed.maxSessionDeadlineIso : undefined,
|
|
2477
2523
|
applicationID: typeof parsed.applicationID === 'string' ? parsed.applicationID : undefined,
|
|
2478
2524
|
allowedAgents: Array.isArray(parsed.allowedAgents) ? parsed.allowedAgents : undefined,
|
|
2525
|
+
directActions:
|
|
2526
|
+
parsed.directActions && typeof parsed.directActions === 'object' && typeof parsed.directActions.enabled === 'boolean'
|
|
2527
|
+
? (parsed.directActions as RealtimeDirectActionsConfig)
|
|
2528
|
+
: undefined,
|
|
2479
2529
|
};
|
|
2480
2530
|
}
|
|
2481
2531
|
} catch {
|
|
@@ -2686,4 +2736,80 @@ export class RealtimeClientSessionResolver extends ResolverBase {
|
|
|
2686
2736
|
private mapTranscriptRole(role: string): 'AI' | 'Error' | 'User' {
|
|
2687
2737
|
return role.trim().toLowerCase() === 'user' ? 'User' : 'AI';
|
|
2688
2738
|
}
|
|
2739
|
+
|
|
2740
|
+
/**
|
|
2741
|
+
* Persists a direct action or channel tool execution as a hidden ConversationDetail turn.
|
|
2742
|
+
* Stored as stable facts (Role: 'AI', HiddenToUser: true, ExternalID: callId, CompletionTime: durationMs,
|
|
2743
|
+
* Message: JSON-serialized tool facts) so that session review can reconstruct the action card dynamically
|
|
2744
|
+
* on load (Option 1) without polluting user-facing speech chat bubbles.
|
|
2745
|
+
*/
|
|
2746
|
+
private async persistDirectActionTurn(
|
|
2747
|
+
session: MJAIAgentSessionEntity,
|
|
2748
|
+
callId: string | undefined,
|
|
2749
|
+
toolName: string,
|
|
2750
|
+
argsJson: string | undefined | null,
|
|
2751
|
+
resultJson: string | undefined | null,
|
|
2752
|
+
durationMs: number | undefined,
|
|
2753
|
+
contextUser: UserInfo,
|
|
2754
|
+
provider: IMetadataProvider,
|
|
2755
|
+
): Promise<boolean> {
|
|
2756
|
+
if (!session.ConversationID) {
|
|
2757
|
+
return false;
|
|
2758
|
+
}
|
|
2759
|
+
try {
|
|
2760
|
+
const writeUser = ResolveScopedAnonymousRunUser(contextUser);
|
|
2761
|
+
const detail = await provider.GetEntityObject<MJConversationDetailEntity>(
|
|
2762
|
+
CONVERSATION_DETAIL_ENTITY,
|
|
2763
|
+
writeUser,
|
|
2764
|
+
);
|
|
2765
|
+
detail.NewRecord();
|
|
2766
|
+
detail.ConversationID = session.ConversationID;
|
|
2767
|
+
detail.Role = 'AI';
|
|
2768
|
+
detail.HiddenToUser = true;
|
|
2769
|
+
detail.AgentSessionID = session.ID;
|
|
2770
|
+
detail.UserID = contextUser.ID;
|
|
2771
|
+
if (callId) {
|
|
2772
|
+
detail.ExternalID = callId;
|
|
2773
|
+
}
|
|
2774
|
+
if (typeof durationMs === 'number' && durationMs >= 0) {
|
|
2775
|
+
detail.CompletionTime = durationMs;
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
let success = true;
|
|
2779
|
+
if (resultJson) {
|
|
2780
|
+
try {
|
|
2781
|
+
const parsed = JSON.parse(resultJson) as { success?: boolean; error?: string };
|
|
2782
|
+
if (parsed.success === false) {
|
|
2783
|
+
success = false;
|
|
2784
|
+
}
|
|
2785
|
+
} catch {
|
|
2786
|
+
// Plain-text output treated as success
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
detail.Status = success ? 'Complete' : 'Error';
|
|
2790
|
+
|
|
2791
|
+
const factPayload = {
|
|
2792
|
+
type: 'realtime_tool_execution',
|
|
2793
|
+
callId: callId ?? null,
|
|
2794
|
+
toolName,
|
|
2795
|
+
argsJson: argsJson ?? null,
|
|
2796
|
+
resultJson: resultJson ?? null,
|
|
2797
|
+
success,
|
|
2798
|
+
durationMs: durationMs ?? 0,
|
|
2799
|
+
};
|
|
2800
|
+
detail.Message = JSON.stringify(factPayload);
|
|
2801
|
+
|
|
2802
|
+
const saved = await detail.Save();
|
|
2803
|
+
if (!saved) {
|
|
2804
|
+
LogError(
|
|
2805
|
+
`RealtimeClientSessionResolver.persistDirectActionTurn save failed: ${detail.LatestResult?.CompleteMessage ?? 'unknown error'}`,
|
|
2806
|
+
);
|
|
2807
|
+
}
|
|
2808
|
+
return saved;
|
|
2809
|
+
} catch (error) {
|
|
2810
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2811
|
+
LogError(`RealtimeClientSessionResolver.persistDirectActionTurn unexpected error: ${message}`);
|
|
2812
|
+
return false;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2689
2815
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import express, { type Router, type Request, type Response, type NextFunction } from 'express';
|
|
2
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
3
|
+
import { BaseRealtimeModel, RealtimeProxyRegistry, type RealtimeProxyTicketEntry } from '@memberjunction/ai';
|
|
4
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Middleware that extracts and consumes the realtime ticket from query parameters
|
|
8
|
+
* BEFORE any request body parsing occurs. This prevents anonymous/unauthorized callers
|
|
9
|
+
* from causing body-parser memory allocations.
|
|
10
|
+
*/
|
|
11
|
+
export function requireTicket(req: Request, res: Response, next: NextFunction): void {
|
|
12
|
+
const ticketId = (req.query['ticket'] as string) || '';
|
|
13
|
+
if (!ticketId) {
|
|
14
|
+
res.status(401).json({ error: 'Unauthorized: missing ticket' });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const entry = RealtimeProxyRegistry.Instance.Consume(ticketId);
|
|
19
|
+
if (!entry) {
|
|
20
|
+
res.status(401).json({ error: 'Unauthorized: invalid or expired ticket' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
res.locals.ticketEntry = entry;
|
|
25
|
+
res.locals.ticketId = ticketId;
|
|
26
|
+
next();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Builds the Express router handling the Realtime WebRTC SDP exchange:
|
|
31
|
+
* `POST /realtime/sdp-exchange?ticket=<ticketId>`
|
|
32
|
+
*
|
|
33
|
+
* In the Realtime WebRTC topology (e.g. OpenAI Live), the browser never contacts the upstream
|
|
34
|
+
* API directly and holds no project API key. Instead, the browser sends its offer SDP here using a
|
|
35
|
+
* short-lived ticket minted by the provider driver. This broker validates and consumes the ticket
|
|
36
|
+
* BEFORE body parsing, delegates to `driver.ExchangeWebRtcSdp` to exchange the SDP offer for an
|
|
37
|
+
* answer with upstream using the server's API key, and returns the answer SDP.
|
|
38
|
+
*/
|
|
39
|
+
export function createRealtimeSdpBrokerRouter(): Router {
|
|
40
|
+
const router = express.Router();
|
|
41
|
+
|
|
42
|
+
router.post(
|
|
43
|
+
'/',
|
|
44
|
+
requireTicket,
|
|
45
|
+
express.json({ limit: '2mb' }),
|
|
46
|
+
async (req: Request, res: Response): Promise<void> => {
|
|
47
|
+
const entry = res.locals.ticketEntry as RealtimeProxyTicketEntry;
|
|
48
|
+
const ticketId = (res.locals.ticketId as string) || '';
|
|
49
|
+
|
|
50
|
+
LogStatus(
|
|
51
|
+
`RealtimeSdpBrokerHandler: processing ticket '${ticketId}' for user '${entry.UserID ?? 'anonymous'}', driver '${entry.DriverClass ?? 'OpenAILiveRealtime'}'`
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const body = req.body as { sdp?: string } | undefined;
|
|
55
|
+
const sdp = body?.sdp;
|
|
56
|
+
if (!sdp || typeof sdp !== 'string') {
|
|
57
|
+
res.status(400).json({ error: 'Missing or invalid sdp in request body' });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const apiKey = entry.UpstreamAuthHeader;
|
|
62
|
+
if (!apiKey) {
|
|
63
|
+
LogError(`RealtimeSdpBrokerHandler: ticket '${ticketId}' has no upstream auth credentials`);
|
|
64
|
+
res.status(500).json({ error: 'Server configuration error: missing upstream credentials' });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const driverClass = entry.DriverClass || 'OpenAILiveRealtime';
|
|
70
|
+
const driver = MJGlobal.Instance.ClassFactory.CreateInstance<BaseRealtimeModel>(
|
|
71
|
+
BaseRealtimeModel,
|
|
72
|
+
driverClass,
|
|
73
|
+
apiKey,
|
|
74
|
+
entry.UpstreamUrl
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (!driver || !driver.ExchangeWebRtcSdp) {
|
|
78
|
+
LogError(`RealtimeSdpBrokerHandler: driver '${driverClass}' does not support ExchangeWebRtcSdp`);
|
|
79
|
+
res.status(500).json({ error: `Driver '${driverClass}' does not support WebRTC SDP exchange` });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
LogStatus(`RealtimeSdpBrokerHandler: exchanging WebRTC SDP offer via ${driverClass}`);
|
|
84
|
+
// Use authoritative session config recorded on ticket entry at mint time (prevents client tampering)
|
|
85
|
+
const result = await driver.ExchangeWebRtcSdp(sdp, entry.SessionConfig);
|
|
86
|
+
res.status(200).json(result);
|
|
87
|
+
} catch (err: unknown) {
|
|
88
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
89
|
+
LogError(`RealtimeSdpBrokerHandler failed for ticket '${ticketId}': ${message}`);
|
|
90
|
+
res.status(502).json({ error: 'Realtime WebRTC handshake failed' });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return router;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @deprecated Use `createRealtimeSdpBrokerRouter` instead.
|
|
100
|
+
*/
|
|
101
|
+
export const createOpenAILiveBrokerRouter = createRealtimeSdpBrokerRouter;
|
|
@@ -20,6 +20,8 @@ export const CORE_STATIC_RESERVED_SERVER_EXTENSION_ROOTS: readonly string[] = [
|
|
|
20
20
|
'/media',
|
|
21
21
|
'/oauth',
|
|
22
22
|
'/health',
|
|
23
|
+
'/realtime',
|
|
24
|
+
'/realtime-proxy',
|
|
23
25
|
];
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -30,9 +32,6 @@ export const CORE_CONSTANT_RESERVED_SERVER_EXTENSION_ROOTS: readonly string[] =
|
|
|
30
32
|
'/auth', // AUTH_CATALOG_MOUNT_PATH
|
|
31
33
|
'/magic-link', // MAGIC_LINK_MOUNT_PATH
|
|
32
34
|
'/widget', // WIDGET_MOUNT_PATH
|
|
33
|
-
'/telephony/twilio', // TWILIO_TELEPHONY_MOUNT_PATH
|
|
34
|
-
'/telephony/vonage', // VONAGE_TELEPHONY_MOUNT_PATH
|
|
35
|
-
'/meetings/teams', // TEAMS_MEETINGS_MOUNT_PATH
|
|
36
35
|
];
|
|
37
36
|
|
|
38
37
|
/**
|
|
@@ -1,27 +0,0 @@
|
|
|
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
|
-
import { AppContext } from '../types.js';
|
|
11
|
-
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
12
|
-
/** Result of an outbound RingCentral place-call attempt. */
|
|
13
|
-
export declare class PlaceRingCentralCallResult {
|
|
14
|
-
Success: boolean;
|
|
15
|
-
ErrorMessage?: string;
|
|
16
|
-
/** The placed RingCentral telephony session id (the bridge's external connection id). */
|
|
17
|
-
SessionId: string;
|
|
18
|
-
}
|
|
19
|
-
export declare class RingCentralTelephonyResolver extends ResolverBase {
|
|
20
|
-
/**
|
|
21
|
-
* Places an outbound call from the given agent identity (its phone number is the caller-id) to a
|
|
22
|
-
* destination number, connecting the pinned agent over the realtime bridge. Returns the telephony
|
|
23
|
-
* session id.
|
|
24
|
-
*/
|
|
25
|
-
PlaceRingCentralCall(agentIdentityId: string, toNumber: string, context?: AppContext): Promise<PlaceRingCentralCallResult>;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=RingCentralTelephonyResolver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RingCentralTelephonyResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/RingCentralTelephonyResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI1D,4DAA4D;AAC5D,qBACa,0BAA0B;IAEnC,OAAO,EAAE,OAAO,CAAC;IAGjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yFAAyF;IAEzF,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBACa,4BAA6B,SAAQ,YAAY;IAC1D;;;;OAIG;IAEG,oBAAoB,CACgB,eAAe,EAAE,MAAM,EAC9B,QAAQ,EAAE,MAAM,EACxC,OAAO,GAAE,UAA6B,GAC9C,OAAO,CAAC,0BAA0B,CAAC;CAoBzC"}
|
|
@@ -1,87 +0,0 @@
|
|
|
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
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
-
};
|
|
16
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
17
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
18
|
-
};
|
|
19
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
20
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
21
|
-
};
|
|
22
|
-
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
23
|
-
import { LogError } from '@memberjunction/core';
|
|
24
|
-
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
25
|
-
import { GetReadWriteProvider } from '../util.js';
|
|
26
|
-
import { GetRingCentralTelephonyService } from '../telephony/ringcentral-runtime.js';
|
|
27
|
-
/** Result of an outbound RingCentral place-call attempt. */
|
|
28
|
-
let PlaceRingCentralCallResult = class PlaceRingCentralCallResult {
|
|
29
|
-
};
|
|
30
|
-
__decorate([
|
|
31
|
-
Field(() => Boolean),
|
|
32
|
-
__metadata("design:type", Boolean)
|
|
33
|
-
], PlaceRingCentralCallResult.prototype, "Success", void 0);
|
|
34
|
-
__decorate([
|
|
35
|
-
Field(() => String, { nullable: true }),
|
|
36
|
-
__metadata("design:type", String)
|
|
37
|
-
], PlaceRingCentralCallResult.prototype, "ErrorMessage", void 0);
|
|
38
|
-
__decorate([
|
|
39
|
-
Field(() => String),
|
|
40
|
-
__metadata("design:type", String)
|
|
41
|
-
], PlaceRingCentralCallResult.prototype, "SessionId", void 0);
|
|
42
|
-
PlaceRingCentralCallResult = __decorate([
|
|
43
|
-
ObjectType()
|
|
44
|
-
], PlaceRingCentralCallResult);
|
|
45
|
-
export { PlaceRingCentralCallResult };
|
|
46
|
-
let RingCentralTelephonyResolver = class RingCentralTelephonyResolver extends ResolverBase {
|
|
47
|
-
/**
|
|
48
|
-
* Places an outbound call from the given agent identity (its phone number is the caller-id) to a
|
|
49
|
-
* destination number, connecting the pinned agent over the realtime bridge. Returns the telephony
|
|
50
|
-
* session id.
|
|
51
|
-
*/
|
|
52
|
-
async PlaceRingCentralCall(agentIdentityId, toNumber, context = {}) {
|
|
53
|
-
const failure = (msg) => ({ Success: false, ErrorMessage: msg, SessionId: '' });
|
|
54
|
-
try {
|
|
55
|
-
const user = this.GetUserFromPayload(context.userPayload);
|
|
56
|
-
if (!user) {
|
|
57
|
-
return failure('Unable to determine current user.');
|
|
58
|
-
}
|
|
59
|
-
const service = GetRingCentralTelephonyService();
|
|
60
|
-
if (!service) {
|
|
61
|
-
return failure('RingCentral telephony is not configured on this server.');
|
|
62
|
-
}
|
|
63
|
-
const provider = GetReadWriteProvider(context.providers);
|
|
64
|
-
const sessionId = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
|
|
65
|
-
return { Success: true, SessionId: sessionId };
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
69
|
-
LogError(`PlaceRingCentralCall failed: ${msg}`);
|
|
70
|
-
return failure(msg);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
__decorate([
|
|
75
|
-
Mutation(() => PlaceRingCentralCallResult),
|
|
76
|
-
__param(0, Arg('agentIdentityId', () => String)),
|
|
77
|
-
__param(1, Arg('toNumber', () => String)),
|
|
78
|
-
__param(2, Ctx()),
|
|
79
|
-
__metadata("design:type", Function),
|
|
80
|
-
__metadata("design:paramtypes", [String, String, Object]),
|
|
81
|
-
__metadata("design:returntype", Promise)
|
|
82
|
-
], RingCentralTelephonyResolver.prototype, "PlaceRingCentralCall", null);
|
|
83
|
-
RingCentralTelephonyResolver = __decorate([
|
|
84
|
-
Resolver()
|
|
85
|
-
], RingCentralTelephonyResolver);
|
|
86
|
-
export { RingCentralTelephonyResolver };
|
|
87
|
-
//# sourceMappingURL=RingCentralTelephonyResolver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RingCentralTelephonyResolver.js","sourceRoot":"","sources":["../../src/resolvers/RingCentralTelephonyResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;;;;;;;;;;;;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAqB,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,4DAA4D;AAErD,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;CAUtC,CAAA;AARG;IADC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;;2DACJ;AAGjB;IADC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;gEAClB;AAItB;IADC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC;;6DACF;AATT,0BAA0B;IADtC,UAAU,EAAE;GACA,0BAA0B,CAUtC;;AAGM,IAAM,4BAA4B,GAAlC,MAAM,4BAA6B,SAAQ,YAAY;IAC1D;;;;OAIG;IAEG,AAAN,KAAK,CAAC,oBAAoB,CACgB,eAAuB,EAC9B,QAAgB,EACxC,UAAsB,EAAgB;QAE7C,MAAM,OAAO,GAAG,CAAC,GAAW,EAA8B,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACpH,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;gBACR,OAAO,OAAO,CAAC,mCAAmC,CAAC,CAAC;YACxD,CAAC;YACD,MAAM,OAAO,GAAG,8BAA8B,EAAE,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,OAAO,OAAO,CAAC,yDAAyD,CAAC,CAAC;YAC9E,CAAC;YACD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,SAAS,CAAiC,CAAC;YACzF,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,QAAQ,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;YAChD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACL,CAAC;CACJ,CAAA;AAxBS;IADL,QAAQ,CAAC,GAAG,EAAE,CAAC,0BAA0B,CAAC;IAEtC,WAAA,GAAG,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAA;IACpC,WAAA,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAA;IAC7B,WAAA,GAAG,EAAE,CAAA;;;;wEAoBT;AA9BQ,4BAA4B;IADxC,QAAQ,EAAE;GACE,4BAA4B,CA+BxC"}
|
|
@@ -1,28 +0,0 @@
|
|
|
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
|
-
import { AppContext } from '../types.js';
|
|
13
|
-
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
14
|
-
/** Result of a Teams meeting join attempt. */
|
|
15
|
-
export declare class StartTeamsMeetingResult {
|
|
16
|
-
Success: boolean;
|
|
17
|
-
ErrorMessage?: string;
|
|
18
|
-
/** The Graph call id the bot joined (the bridge's external connection id), when successful. */
|
|
19
|
-
CallId: string;
|
|
20
|
-
}
|
|
21
|
-
export declare class TeamsMeetingsResolver extends ResolverBase {
|
|
22
|
-
/**
|
|
23
|
-
* Has the given agent identity join a Teams meeting by URL, connecting the pinned agent over the realtime
|
|
24
|
-
* bridge. Returns the Graph call id.
|
|
25
|
-
*/
|
|
26
|
-
StartTeamsMeetingSession(agentIdentityId: string, joinUrl: string, context?: AppContext): Promise<StartTeamsMeetingResult>;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=TeamsMeetingsResolver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TeamsMeetingsResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/TeamsMeetingsResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI1D,8CAA8C;AAC9C,qBACa,uBAAuB;IAEhC,OAAO,EAAE,OAAO,CAAC;IAGjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,+FAA+F;IAE/F,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,qBACa,qBAAsB,SAAQ,YAAY;IACnD;;;OAGG;IAEG,wBAAwB,CACY,eAAe,EAAE,MAAM,EAC/B,OAAO,EAAE,MAAM,EACtC,OAAO,GAAE,UAA6B,GAC9C,OAAO,CAAC,uBAAuB,CAAC;CAuBtC"}
|
|
@@ -1,91 +0,0 @@
|
|
|
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
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
13
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
14
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
15
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
16
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
17
|
-
};
|
|
18
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
19
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
20
|
-
};
|
|
21
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
22
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
23
|
-
};
|
|
24
|
-
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
25
|
-
import { LogError } from '@memberjunction/core';
|
|
26
|
-
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
27
|
-
import { GetReadWriteProvider } from '../util.js';
|
|
28
|
-
import { GetTeamsMeetingsService } from '../telephony/teams-meetings-runtime.js';
|
|
29
|
-
/** Result of a Teams meeting join attempt. */
|
|
30
|
-
let StartTeamsMeetingResult = class StartTeamsMeetingResult {
|
|
31
|
-
};
|
|
32
|
-
__decorate([
|
|
33
|
-
Field(() => Boolean),
|
|
34
|
-
__metadata("design:type", Boolean)
|
|
35
|
-
], StartTeamsMeetingResult.prototype, "Success", void 0);
|
|
36
|
-
__decorate([
|
|
37
|
-
Field(() => String, { nullable: true }),
|
|
38
|
-
__metadata("design:type", String)
|
|
39
|
-
], StartTeamsMeetingResult.prototype, "ErrorMessage", void 0);
|
|
40
|
-
__decorate([
|
|
41
|
-
Field(() => String),
|
|
42
|
-
__metadata("design:type", String)
|
|
43
|
-
], StartTeamsMeetingResult.prototype, "CallId", void 0);
|
|
44
|
-
StartTeamsMeetingResult = __decorate([
|
|
45
|
-
ObjectType()
|
|
46
|
-
], StartTeamsMeetingResult);
|
|
47
|
-
export { StartTeamsMeetingResult };
|
|
48
|
-
let TeamsMeetingsResolver = class TeamsMeetingsResolver extends ResolverBase {
|
|
49
|
-
/**
|
|
50
|
-
* Has the given agent identity join a Teams meeting by URL, connecting the pinned agent over the realtime
|
|
51
|
-
* bridge. Returns the Graph call id.
|
|
52
|
-
*/
|
|
53
|
-
async StartTeamsMeetingSession(agentIdentityId, joinUrl, context = {}) {
|
|
54
|
-
const failure = (msg) => ({ Success: false, ErrorMessage: msg, CallId: '' });
|
|
55
|
-
try {
|
|
56
|
-
const user = this.GetUserFromPayload(context.userPayload);
|
|
57
|
-
if (!user) {
|
|
58
|
-
return failure('Unable to determine current user.');
|
|
59
|
-
}
|
|
60
|
-
const service = GetTeamsMeetingsService();
|
|
61
|
-
if (!service) {
|
|
62
|
-
return failure('Teams meetings are not configured on this server.');
|
|
63
|
-
}
|
|
64
|
-
const provider = GetReadWriteProvider(context.providers);
|
|
65
|
-
const result = await service.JoinMeetingByUrl(agentIdentityId, joinUrl, user, provider);
|
|
66
|
-
if (!result.accepted) {
|
|
67
|
-
return failure(result.reason ?? 'The meeting join was not accepted.');
|
|
68
|
-
}
|
|
69
|
-
return { Success: true, CallId: result.callId ?? '' };
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
73
|
-
LogError(`StartTeamsMeetingSession failed: ${msg}`);
|
|
74
|
-
return failure(msg);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
__decorate([
|
|
79
|
-
Mutation(() => StartTeamsMeetingResult),
|
|
80
|
-
__param(0, Arg('agentIdentityId', () => String)),
|
|
81
|
-
__param(1, Arg('joinUrl', () => String)),
|
|
82
|
-
__param(2, Ctx()),
|
|
83
|
-
__metadata("design:type", Function),
|
|
84
|
-
__metadata("design:paramtypes", [String, String, Object]),
|
|
85
|
-
__metadata("design:returntype", Promise)
|
|
86
|
-
], TeamsMeetingsResolver.prototype, "StartTeamsMeetingSession", null);
|
|
87
|
-
TeamsMeetingsResolver = __decorate([
|
|
88
|
-
Resolver()
|
|
89
|
-
], TeamsMeetingsResolver);
|
|
90
|
-
export { TeamsMeetingsResolver };
|
|
91
|
-
//# sourceMappingURL=TeamsMeetingsResolver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TeamsMeetingsResolver.js","sourceRoot":"","sources":["../../src/resolvers/TeamsMeetingsResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;;;;;;;;;;;;;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAqB,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAEjF,8CAA8C;AAEvC,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;CAUnC,CAAA;AARG;IADC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;;wDACJ;AAGjB;IADC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;6DAClB;AAItB;IADC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC;;uDACL;AATN,uBAAuB;IADnC,UAAU,EAAE;GACA,uBAAuB,CAUnC;;AAGM,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,YAAY;IACnD;;;OAGG;IAEG,AAAN,KAAK,CAAC,wBAAwB,CACY,eAAuB,EAC/B,OAAe,EACtC,UAAsB,EAAgB;QAE7C,MAAM,OAAO,GAAG,CAAC,GAAW,EAA2B,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9G,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;gBACR,OAAO,OAAO,CAAC,mCAAmC,CAAC,CAAC;YACxD,CAAC;YACD,MAAM,OAAO,GAAG,uBAAuB,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,OAAO,OAAO,CAAC,mDAAmD,CAAC,CAAC;YACxE,CAAC;YACD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,SAAS,CAAiC,CAAC;YACzF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YACxF,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACnB,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,oCAAoC,CAAC,CAAC;YAC1E,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,QAAQ,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAC;YACpD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACL,CAAC;CACJ,CAAA;AA3BS;IADL,QAAQ,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC;IAEnC,WAAA,GAAG,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAA;IACpC,WAAA,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAA;IAC5B,WAAA,GAAG,EAAE,CAAA;;;;qEAuBT;AAhCQ,qBAAqB;IADjC,QAAQ,EAAE;GACE,qBAAqB,CAiCjC"}
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
import { AppContext } from '../types.js';
|
|
11
|
-
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
12
|
-
/** Result of an outbound place-call attempt. */
|
|
13
|
-
export declare class PlaceCallResult {
|
|
14
|
-
Success: boolean;
|
|
15
|
-
ErrorMessage?: string;
|
|
16
|
-
/** The placed Twilio Call SID (the bridge's external connection id). */
|
|
17
|
-
CallSid: string;
|
|
18
|
-
}
|
|
19
|
-
export declare class TelephonyResolver extends ResolverBase {
|
|
20
|
-
/**
|
|
21
|
-
* Places an outbound call from the given agent identity (its phone number is the caller-id) to a
|
|
22
|
-
* destination number, connecting the pinned agent over the realtime bridge. Returns the Call SID.
|
|
23
|
-
*/
|
|
24
|
-
PlaceTwilioCall(agentIdentityId: string, toNumber: string, context?: AppContext): Promise<PlaceCallResult>;
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=TelephonyResolver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TelephonyResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/TelephonyResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI1D,gDAAgD;AAChD,qBACa,eAAe;IAExB,OAAO,EAAE,OAAO,CAAC;IAGjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,wEAAwE;IAExE,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,qBACa,iBAAkB,SAAQ,YAAY;IAC/C;;;OAGG;IAEG,eAAe,CACqB,eAAe,EAAE,MAAM,EAC9B,QAAQ,EAAE,MAAM,EACxC,OAAO,GAAE,UAA6B,GAC9C,OAAO,CAAC,eAAe,CAAC;CAoB9B"}
|