@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.
Files changed (309) hide show
  1. package/dist/agentSessions/ReturningVisitorRecap.d.ts +39 -0
  2. package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -0
  3. package/dist/agentSessions/ReturningVisitorRecap.js +198 -0
  4. package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -0
  5. package/dist/agentSessions/SessionJanitor.d.ts +13 -0
  6. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  7. package/dist/agentSessions/SessionJanitor.js +65 -7
  8. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  9. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  10. package/dist/agentSessions/SessionManager.js +40 -0
  11. package/dist/agentSessions/SessionManager.js.map +1 -1
  12. package/dist/agentSessions/index.d.ts.map +1 -1
  13. package/dist/agentSessions/index.js +3 -1
  14. package/dist/agentSessions/index.js.map +1 -1
  15. package/dist/auth/magicLink/MagicLinkRouter.d.ts +10 -0
  16. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  17. package/dist/auth/magicLink/MagicLinkRouter.js +16 -0
  18. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  19. package/dist/auth/magicLink/index.d.ts +1 -1
  20. package/dist/auth/magicLink/index.d.ts.map +1 -1
  21. package/dist/auth/magicLink/index.js +1 -1
  22. package/dist/auth/magicLink/index.js.map +1 -1
  23. package/dist/auth/magicLink/types.d.ts +26 -0
  24. package/dist/auth/magicLink/types.d.ts.map +1 -1
  25. package/dist/config.d.ts +1883 -144
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +160 -36
  28. package/dist/config.js.map +1 -1
  29. package/dist/context.d.ts.map +1 -1
  30. package/dist/context.js +45 -2
  31. package/dist/context.js.map +1 -1
  32. package/dist/generated/generated.d.ts +1684 -54
  33. package/dist/generated/generated.d.ts.map +1 -1
  34. package/dist/generated/generated.js +57105 -48029
  35. package/dist/generated/generated.js.map +1 -1
  36. package/dist/generic/ResolverBase.d.ts +13 -0
  37. package/dist/generic/ResolverBase.d.ts.map +1 -1
  38. package/dist/generic/ResolverBase.js +22 -0
  39. package/dist/generic/ResolverBase.js.map +1 -1
  40. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  41. package/dist/generic/RunViewResolver.js +4 -0
  42. package/dist/generic/RunViewResolver.js.map +1 -1
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +110 -3
  46. package/dist/index.js.map +1 -1
  47. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  48. package/dist/integration/CustomColumnPromoter.js +6 -0
  49. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  50. package/dist/realtimeWidget/WidgetRouter.d.ts +26 -0
  51. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -0
  52. package/dist/realtimeWidget/WidgetRouter.js +182 -0
  53. package/dist/realtimeWidget/WidgetRouter.js.map +1 -0
  54. package/dist/realtimeWidget/WidgetSessionService.d.ts +265 -0
  55. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -0
  56. package/dist/realtimeWidget/WidgetSessionService.js +477 -0
  57. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -0
  58. package/dist/realtimeWidget/host-identity.d.ts +40 -0
  59. package/dist/realtimeWidget/host-identity.d.ts.map +1 -0
  60. package/dist/realtimeWidget/host-identity.js +58 -0
  61. package/dist/realtimeWidget/host-identity.js.map +1 -0
  62. package/dist/realtimeWidget/index.d.ts +10 -0
  63. package/dist/realtimeWidget/index.d.ts.map +1 -0
  64. package/dist/realtimeWidget/index.js +9 -0
  65. package/dist/realtimeWidget/index.js.map +1 -0
  66. package/dist/realtimeWidget/visitorIdentity.d.ts +76 -0
  67. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -0
  68. package/dist/realtimeWidget/visitorIdentity.js +202 -0
  69. package/dist/realtimeWidget/visitorIdentity.js.map +1 -0
  70. package/dist/realtimeWidget/widgetCore.d.ts +106 -0
  71. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -0
  72. package/dist/realtimeWidget/widgetCore.js +173 -0
  73. package/dist/realtimeWidget/widgetCore.js.map +1 -0
  74. package/dist/realtimeWidget/widgetGuestElevation.d.ts +51 -0
  75. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -0
  76. package/dist/realtimeWidget/widgetGuestElevation.js +79 -0
  77. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -0
  78. package/dist/resolvers/ComponentRegistryResolver.d.ts +7 -0
  79. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  80. package/dist/resolvers/ComponentRegistryResolver.js +31 -8
  81. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  82. package/dist/resolvers/EntityPermissionResolver.d.ts.map +1 -1
  83. package/dist/resolvers/EntityPermissionResolver.js +1 -2
  84. package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
  85. package/dist/resolvers/FileResolver.d.ts +74 -0
  86. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  87. package/dist/resolvers/FileResolver.js +211 -2
  88. package/dist/resolvers/FileResolver.js.map +1 -1
  89. package/dist/resolvers/QueryResolver.d.ts +6 -4
  90. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  91. package/dist/resolvers/QueryResolver.js +29 -14
  92. package/dist/resolvers/QueryResolver.js.map +1 -1
  93. package/dist/resolvers/QuerySystemUserResolver.d.ts +9 -6
  94. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  95. package/dist/resolvers/QuerySystemUserResolver.js +15 -13
  96. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  97. package/dist/resolvers/RealtimeBridgeResolver.d.ts +8 -1
  98. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  99. package/dist/resolvers/RealtimeBridgeResolver.js +28 -4
  100. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  101. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +91 -2
  102. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  103. package/dist/resolvers/RealtimeClientSessionResolver.js +337 -17
  104. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  105. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  106. package/dist/resolvers/RemoteBrowserActionResolver.js +17 -2
  107. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  108. package/dist/resolvers/RingCentralTelephonyResolver.d.ts +27 -0
  109. package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
  110. package/dist/resolvers/RingCentralTelephonyResolver.js +87 -0
  111. package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
  112. package/dist/resolvers/RunAIAgentResolver.d.ts +12 -3
  113. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  114. package/dist/resolvers/RunAIAgentResolver.js +50 -17
  115. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  116. package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
  117. package/dist/resolvers/SearchKnowledgeResolver.js +2 -0
  118. package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
  119. package/dist/resolvers/TeamsMeetingsResolver.d.ts +28 -0
  120. package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
  121. package/dist/resolvers/TeamsMeetingsResolver.js +91 -0
  122. package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
  123. package/dist/resolvers/TelephonyResolver.d.ts +26 -0
  124. package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
  125. package/dist/resolvers/TelephonyResolver.js +86 -0
  126. package/dist/resolvers/TelephonyResolver.js.map +1 -0
  127. package/dist/resolvers/TestQuerySQLResolver.d.ts +1 -1
  128. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  129. package/dist/resolvers/TestQuerySQLResolver.js +2 -3
  130. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  131. package/dist/resolvers/VonageTelephonyResolver.d.ts +26 -0
  132. package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
  133. package/dist/resolvers/VonageTelephonyResolver.js +86 -0
  134. package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
  135. package/dist/resolvers/meetingRecordingRegistration.d.ts +124 -0
  136. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -0
  137. package/dist/resolvers/meetingRecordingRegistration.js +311 -0
  138. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -0
  139. package/dist/resolvers/peaksSidecar.d.ts +30 -0
  140. package/dist/resolvers/peaksSidecar.d.ts.map +1 -0
  141. package/dist/resolvers/peaksSidecar.js +51 -0
  142. package/dist/resolvers/peaksSidecar.js.map +1 -0
  143. package/dist/rest/MediaAccessKeys.d.ts +68 -0
  144. package/dist/rest/MediaAccessKeys.d.ts.map +1 -0
  145. package/dist/rest/MediaAccessKeys.js +96 -0
  146. package/dist/rest/MediaAccessKeys.js.map +1 -0
  147. package/dist/rest/MediaStreamHandler.d.ts +26 -0
  148. package/dist/rest/MediaStreamHandler.d.ts.map +1 -0
  149. package/dist/rest/MediaStreamHandler.js +195 -0
  150. package/dist/rest/MediaStreamHandler.js.map +1 -0
  151. package/dist/rest/mediaRange.d.ts +41 -0
  152. package/dist/rest/mediaRange.d.ts.map +1 -0
  153. package/dist/rest/mediaRange.js +60 -0
  154. package/dist/rest/mediaRange.js.map +1 -0
  155. package/dist/telephony/RingCentralTelephonyService.d.ts +115 -0
  156. package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
  157. package/dist/telephony/RingCentralTelephonyService.js +262 -0
  158. package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
  159. package/dist/telephony/TeamsMeetingsRouter.d.ts +40 -0
  160. package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
  161. package/dist/telephony/TeamsMeetingsRouter.js +96 -0
  162. package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
  163. package/dist/telephony/TeamsMeetingsService.d.ts +113 -0
  164. package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
  165. package/dist/telephony/TeamsMeetingsService.js +196 -0
  166. package/dist/telephony/TeamsMeetingsService.js.map +1 -0
  167. package/dist/telephony/TwilioTelephonyRouter.d.ts +36 -0
  168. package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
  169. package/dist/telephony/TwilioTelephonyRouter.js +143 -0
  170. package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
  171. package/dist/telephony/TwilioTelephonyService.d.ts +95 -0
  172. package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
  173. package/dist/telephony/TwilioTelephonyService.js +193 -0
  174. package/dist/telephony/TwilioTelephonyService.js.map +1 -0
  175. package/dist/telephony/VonageTelephonyRouter.d.ts +41 -0
  176. package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
  177. package/dist/telephony/VonageTelephonyRouter.js +201 -0
  178. package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
  179. package/dist/telephony/VonageTelephonyService.d.ts +90 -0
  180. package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
  181. package/dist/telephony/VonageTelephonyService.js +191 -0
  182. package/dist/telephony/VonageTelephonyService.js.map +1 -0
  183. package/dist/telephony/calendar-scheduler.d.ts +67 -0
  184. package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
  185. package/dist/telephony/calendar-scheduler.js +133 -0
  186. package/dist/telephony/calendar-scheduler.js.map +1 -0
  187. package/dist/telephony/index.d.ts +29 -0
  188. package/dist/telephony/index.d.ts.map +1 -0
  189. package/dist/telephony/index.js +38 -0
  190. package/dist/telephony/index.js.map +1 -0
  191. package/dist/telephony/media-upgrade-router.d.ts +33 -0
  192. package/dist/telephony/media-upgrade-router.d.ts.map +1 -0
  193. package/dist/telephony/media-upgrade-router.js +56 -0
  194. package/dist/telephony/media-upgrade-router.js.map +1 -0
  195. package/dist/telephony/ringcentral-runtime.d.ts +14 -0
  196. package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
  197. package/dist/telephony/ringcentral-runtime.js +18 -0
  198. package/dist/telephony/ringcentral-runtime.js.map +1 -0
  199. package/dist/telephony/teams-meetings-runtime.d.ts +16 -0
  200. package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
  201. package/dist/telephony/teams-meetings-runtime.js +20 -0
  202. package/dist/telephony/teams-meetings-runtime.js.map +1 -0
  203. package/dist/telephony/teamsAcsMediaRegistry.d.ts +69 -0
  204. package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
  205. package/dist/telephony/teamsAcsMediaRegistry.js +118 -0
  206. package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
  207. package/dist/telephony/telephony-runtime.d.ts +14 -0
  208. package/dist/telephony/telephony-runtime.d.ts.map +1 -0
  209. package/dist/telephony/telephony-runtime.js +18 -0
  210. package/dist/telephony/telephony-runtime.js.map +1 -0
  211. package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
  212. package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
  213. package/dist/telephony/twilioMediaRegistry.js +106 -0
  214. package/dist/telephony/twilioMediaRegistry.js.map +1 -0
  215. package/dist/telephony/vonage-runtime.d.ts +14 -0
  216. package/dist/telephony/vonage-runtime.d.ts.map +1 -0
  217. package/dist/telephony/vonage-runtime.js +18 -0
  218. package/dist/telephony/vonage-runtime.js.map +1 -0
  219. package/dist/telephony/vonageMediaRegistry.d.ts +78 -0
  220. package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
  221. package/dist/telephony/vonageMediaRegistry.js +158 -0
  222. package/dist/telephony/vonageMediaRegistry.js.map +1 -0
  223. package/package.json +88 -82
  224. package/src/__tests__/FileResolverPeaks.test.ts +64 -0
  225. package/src/__tests__/MediaAccessKeys.test.ts +68 -0
  226. package/src/__tests__/MediaStreamHandler.test.ts +91 -0
  227. package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -1
  228. package/src/__tests__/RealtimeClientSessionResolver.test.ts +69 -0
  229. package/src/__tests__/RealtimeCoAgentAppAwareness.integration.test.ts +191 -0
  230. package/src/__tests__/RemoteBrowserSnapshot.test.ts +123 -0
  231. package/src/__tests__/SessionManager.test.ts +2 -0
  232. package/src/__tests__/meetingRecordingRegistration.test.ts +248 -0
  233. package/src/__tests__/search-knowledge-tags.test.ts +9 -9
  234. package/src/__tests__/teams-meetings-service.test.ts +65 -0
  235. package/src/__tests__/teamsAcsMediaRegistry.test.ts +82 -0
  236. package/src/__tests__/twilio-telephony-service.test.ts +23 -0
  237. package/src/__tests__/twilioMediaRegistry.test.ts +103 -0
  238. package/src/__tests__/vonageMediaRegistry.test.ts +180 -0
  239. package/src/__tests__/widget.test.ts +204 -0
  240. package/src/__tests__/widgetGuestElevation.test.ts +57 -0
  241. package/src/__tests__/widgetHostIdentity.test.ts +117 -0
  242. package/src/agentSessions/ReturningVisitorRecap.ts +242 -0
  243. package/src/agentSessions/SessionJanitor.ts +66 -6
  244. package/src/agentSessions/SessionManager.ts +41 -0
  245. package/src/agentSessions/index.ts +3 -1
  246. package/src/auth/magicLink/MagicLinkRouter.ts +17 -0
  247. package/src/auth/magicLink/index.ts +1 -0
  248. package/src/auth/magicLink/types.ts +26 -0
  249. package/src/config.ts +172 -38
  250. package/src/context.ts +50 -3
  251. package/src/generated/generated.ts +26726 -20464
  252. package/src/generic/ResolverBase.ts +28 -0
  253. package/src/generic/RunViewResolver.ts +4 -0
  254. package/src/index.ts +119 -3
  255. package/src/integration/CustomColumnPromoter.ts +6 -0
  256. package/src/realtimeWidget/WidgetRouter.ts +204 -0
  257. package/src/realtimeWidget/WidgetSessionService.ts +714 -0
  258. package/src/realtimeWidget/host-identity.ts +84 -0
  259. package/src/realtimeWidget/index.ts +15 -0
  260. package/src/realtimeWidget/visitorIdentity.ts +258 -0
  261. package/src/realtimeWidget/widgetCore.ts +231 -0
  262. package/src/realtimeWidget/widgetGuestElevation.ts +115 -0
  263. package/src/resolvers/ComponentRegistryResolver.ts +36 -10
  264. package/src/resolvers/EntityPermissionResolver.ts +1 -2
  265. package/src/resolvers/FileResolver.ts +199 -1
  266. package/src/resolvers/QueryResolver.ts +33 -19
  267. package/src/resolvers/QuerySystemUserResolver.ts +14 -10
  268. package/src/resolvers/RealtimeBridgeResolver.ts +36 -4
  269. package/src/resolvers/RealtimeClientSessionResolver.ts +383 -9
  270. package/src/resolvers/RemoteBrowserActionResolver.ts +18 -2
  271. package/src/resolvers/RingCentralTelephonyResolver.ts +64 -0
  272. package/src/resolvers/RunAIAgentResolver.ts +60 -15
  273. package/src/resolvers/SearchKnowledgeResolver.ts +2 -0
  274. package/src/resolvers/TeamsMeetingsResolver.ts +68 -0
  275. package/src/resolvers/TelephonyResolver.ts +63 -0
  276. package/src/resolvers/TestQuerySQLResolver.ts +2 -3
  277. package/src/resolvers/VonageTelephonyResolver.ts +63 -0
  278. package/src/resolvers/meetingRecordingRegistration.ts +432 -0
  279. package/src/resolvers/peaksSidecar.ts +52 -0
  280. package/src/rest/MediaAccessKeys.ts +121 -0
  281. package/src/rest/MediaStreamHandler.ts +223 -0
  282. package/src/rest/mediaRange.ts +76 -0
  283. package/src/telephony/RingCentralTelephonyService.ts +342 -0
  284. package/src/telephony/TeamsMeetingsRouter.ts +124 -0
  285. package/src/telephony/TeamsMeetingsService.ts +268 -0
  286. package/src/telephony/TwilioTelephonyRouter.ts +184 -0
  287. package/src/telephony/TwilioTelephonyService.ts +261 -0
  288. package/src/telephony/VonageTelephonyRouter.ts +239 -0
  289. package/src/telephony/VonageTelephonyService.ts +259 -0
  290. package/src/telephony/calendar-scheduler.ts +176 -0
  291. package/src/telephony/index.ts +43 -0
  292. package/src/telephony/media-upgrade-router.ts +62 -0
  293. package/src/telephony/ringcentral-runtime.ts +22 -0
  294. package/src/telephony/teams-meetings-runtime.ts +24 -0
  295. package/src/telephony/teamsAcsMediaRegistry.ts +152 -0
  296. package/src/telephony/telephony-runtime.ts +22 -0
  297. package/src/telephony/twilioMediaRegistry.ts +137 -0
  298. package/src/telephony/vonage-runtime.ts +22 -0
  299. package/src/telephony/vonageMediaRegistry.ts +200 -0
  300. package/dist/agents/skip-agent.d.ts +0 -111
  301. package/dist/agents/skip-agent.d.ts.map +0 -1
  302. package/dist/agents/skip-agent.js +0 -1487
  303. package/dist/agents/skip-agent.js.map +0 -1
  304. package/dist/agents/skip-sdk.d.ts +0 -261
  305. package/dist/agents/skip-sdk.d.ts.map +0 -1
  306. package/dist/agents/skip-sdk.js +0 -909
  307. package/dist/agents/skip-sdk.js.map +0 -1
  308. package/src/agents/skip-agent.ts +0 -1594
  309. package/src/agents/skip-sdk.ts +0 -1210
@@ -36,16 +36,17 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
36
36
  *
37
37
  * @module @memberjunction/server
38
38
  */
39
- import { Resolver, Mutation, Arg, Ctx, Int, ObjectType, Field, PubSub, PubSubEngine } from 'type-graphql';
39
+ import { Resolver, Mutation, Arg, Ctx, Int, Float, ObjectType, Field, PubSub, PubSubEngine } from 'type-graphql';
40
40
  import { AuthorizationEvaluator, LogError, LogStatus, RunView } from '@memberjunction/core';
41
- import { UUIDsEqual } from '@memberjunction/global';
41
+ import { UUIDsEqual, IsValidUUID } from '@memberjunction/global';
42
42
  import { AIEngine } from '@memberjunction/aiengine';
43
43
  import { AIAgentPermissionHelper, AIEngineBase } from '@memberjunction/ai-engine-base';
44
- import { RealtimeClientSessionService, RealtimeChannelServerHost, EvaluateRuntimeOverrideAuthorization, ParseRealtimeTypeConfiguration, ResolveEffectiveRealtimeConfig, REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION, } from '@memberjunction/ai-agents';
44
+ import { RealtimeClientSessionService, RealtimeChannelServerHost, EvaluateRuntimeOverrideAuthorization, ParseRealtimeTypeConfiguration, ResolveEffectiveRealtimeConfig, REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION, resolveRecordingStorageAccountID, storeRealtimeRecording, writeRealtimeRecordingSegment, deleteRealtimeRecordingSegments, } from '@memberjunction/ai-agents';
45
45
  import { ResolverBase } from '../generic/ResolverBase.js';
46
46
  import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
47
47
  import { GetReadWriteProvider } from '../util.js';
48
48
  import { SessionManager } from '../agentSessions/index.js';
49
+ import { resolveWidgetGuestRunContext } from '../realtimeWidget/widgetGuestElevation.js';
49
50
  /**
50
51
  * Progress steps worth narrating to the realtime model — mirrors the normal agent-run path's filter
51
52
  * in {@link import('./RunAIAgentResolver.js').RunAIAgentResolver}. Initialization/validation/finalization
@@ -222,6 +223,30 @@ CancelRealtimeSessionToolResult = __decorate([
222
223
  ObjectType()
223
224
  ], CancelRealtimeSessionToolResult);
224
225
  export { CancelRealtimeSessionToolResult };
226
+ /**
227
+ * Result of {@link RealtimeClientSessionResolver.UploadRealtimeRecording} — a structured
228
+ * success/failure envelope. A recording-storage failure must never throw to the browser (the
229
+ * session it belongs to has already ended), so problems come back as `Success: false` with a
230
+ * human-readable reason; only ownership/authn violations (from `loadOwnedSession`) still throw.
231
+ */
232
+ let UploadRealtimeRecordingResult = class UploadRealtimeRecordingResult {
233
+ };
234
+ __decorate([
235
+ Field(() => Boolean),
236
+ __metadata("design:type", Boolean)
237
+ ], UploadRealtimeRecordingResult.prototype, "Success", void 0);
238
+ __decorate([
239
+ Field(() => String, { nullable: true }),
240
+ __metadata("design:type", String)
241
+ ], UploadRealtimeRecordingResult.prototype, "ErrorMessage", void 0);
242
+ __decorate([
243
+ Field(() => String, { nullable: true }),
244
+ __metadata("design:type", String)
245
+ ], UploadRealtimeRecordingResult.prototype, "FileID", void 0);
246
+ UploadRealtimeRecordingResult = __decorate([
247
+ ObjectType()
248
+ ], UploadRealtimeRecordingResult);
249
+ export { UploadRealtimeRecordingResult };
225
250
  /**
226
251
  * Resolver for the client-direct realtime voice topology. A single {@link SessionManager} and a
227
252
  * single {@link RealtimeClientSessionService} are shared across requests — neither holds per-user or
@@ -272,7 +297,7 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
272
297
  *
273
298
  * @returns The ephemeral config + session linkage the browser needs to open its socket.
274
299
  */
275
- async StartRealtimeClientSession(targetAgentId, { userPayload, providers }, conversationId, lastSessionId, preferredModelId, clientToolsJson, coAgentId, configOverridesJson) {
300
+ async StartRealtimeClientSession(targetAgentId, { userPayload, providers }, conversationId, lastSessionId, preferredModelId, clientToolsJson, coAgentId, configOverridesJson, recordingStartedAt, recordingConsent, mediaCollectionId, applicationId, appContextJson) {
276
301
  const { contextUser, provider } = this.requireUserAndProvider(userPayload, providers);
277
302
  const coAgentID = await this.resolveCoAgentID(targetAgentId, coAgentId, contextUser, provider);
278
303
  // PAIRING CONSTRAINTS: a co-agent with pairing rows is restricted to that target list
@@ -284,7 +309,28 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
284
309
  // the 'Realtime: Advanced Session Controls' authorization (structured rejection, never a
285
310
  // silent ignore). Plain starts and within-pairing target selection are never gated here.
286
311
  await this.assertRuntimeOverridesAuthorized(coAgentID, configOverridesJson, preferredModelId, contextUser, provider);
312
+ // PUBLIC WEB-WIDGET VOICE CAP (public-web-widget.md W4): when the caller is a widget guest,
313
+ // resolve the deployment's hard duration ceiling and stamp an absolute deadline on the session.
314
+ // The SessionJanitor force-closes (finalizing runs) past the deadline — a server-authoritative
315
+ // bound that does not depend on the client honoring its own abuse guard or the ephemeral token TTL.
316
+ const maxSessionSeconds = await this.resolveWidgetVoiceCapSeconds(userPayload, providers);
287
317
  const config = { targetAgentID: effectiveTargetId };
318
+ if (maxSessionSeconds) {
319
+ config.maxSessionDeadlineIso = new Date(Date.now() + maxSessionSeconds * 1000).toISOString();
320
+ }
321
+ // Per-session media-kit override: stored on the session config so the server-side MediaChannelServer
322
+ // resolves it (over the agent default) at start. Validate the id here — a malformed value is
323
+ // dropped (logged), never interpolated; the session still starts and falls back to the agent kit.
324
+ const mediaOverride = mediaCollectionId?.trim();
325
+ if (mediaOverride) {
326
+ if (IsValidUUID(mediaOverride)) {
327
+ config.mediaCollectionID = mediaOverride;
328
+ }
329
+ else {
330
+ LogStatus(`StartRealtimeClientSession: ignoring malformed mediaCollectionId '${mediaCollectionId}' — ` +
331
+ 'using the agent default media kit.');
332
+ }
333
+ }
288
334
  const session = await this.sessionManager.CreateSession({
289
335
  agentID: coAgentID,
290
336
  userID: contextUser.ID,
@@ -292,12 +338,14 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
292
338
  lastSessionID: lastSessionId,
293
339
  config: JSON.stringify(config),
294
340
  }, contextUser, provider);
341
+ // Best-effort: stamp recording-start metadata when the browser captured (with consent) at start.
342
+ await this.stampRecordingStart(session, recordingConsent, recordingStartedAt);
295
343
  const clientTools = this.parseClientTools(clientToolsJson);
296
344
  // Best-effort model-context hydration: the PRIOR session chain's transcript (ownership-
297
345
  // checked, capped) is framed into the system prompt so the model REMEMBERS the last leg.
298
346
  // Strictly tolerant — any problem yields no hydration, never a failed start.
299
347
  const priorTranscript = await this.loadPriorTranscript(lastSessionId, contextUser, provider);
300
- const result = await this.prepareClientSessionOrClose(session, coAgentID, effectiveTargetId, contextUser, provider, preferredModelId, clientTools, priorTranscript, configOverridesJson);
348
+ const result = await this.prepareClientSessionOrClose(session, coAgentID, effectiveTargetId, contextUser, provider, preferredModelId, clientTools, priorTranscript, configOverridesJson, maxSessionSeconds, applicationId, this.parseAppContext(appContextJson));
301
349
  // Best-effort restore of the PRIOR session's persisted channel states (e.g. the whiteboard
302
350
  // board). Strictly tolerant — any problem yields a null field, never a failed start.
303
351
  result.PriorChannelStatesJson = (await this.loadPriorChannelStatesJson(lastSessionId, contextUser, provider)) ?? undefined;
@@ -319,6 +367,9 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
319
367
  const { ResultJson, PausedRunID, Artifacts } = await this.clientSessionService.ExecuteRelayedTool({
320
368
  AgentSessionID: agentSessionId,
321
369
  TargetAgentID: config.targetAgentID,
370
+ // Multi-target (Move 4): the session's persisted allowed-agent union — a model-named
371
+ // colleague in the call is validated against this; absent ⇒ single-target behavior.
372
+ AllowedAgents: config.allowedAgents,
322
373
  // Nest the delegated target-agent run under the co-agent observability run (when present).
323
374
  ParentRunID: config.coAgentRunID,
324
375
  Call: { CallID: callId, ToolName: toolName, Arguments: argsJson },
@@ -378,6 +429,10 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
378
429
  promptRunID: config.promptRunID,
379
430
  coAgentRunStepID: config.coAgentRunStepID,
380
431
  pendingFeedbackRunID: pausedRunID,
432
+ // Preserve the server-authoritative voice deadline across config rewrites.
433
+ maxSessionDeadlineIso: config.maxSessionDeadlineIso,
434
+ applicationID: config.applicationID,
435
+ allowedAgents: config.allowedAgents,
381
436
  };
382
437
  session.Config_ = JSON.stringify(next);
383
438
  if (!(await session.Save())) {
@@ -397,12 +452,12 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
397
452
  *
398
453
  * @returns `true` when the transcript turn was persisted.
399
454
  */
400
- async RelayRealtimeTranscript(agentSessionId, role, text, { userPayload, providers }, replacesPrevious) {
455
+ async RelayRealtimeTranscript(agentSessionId, role, text, { userPayload, providers }, replacesPrevious, utteranceStartMs, utteranceEndMs) {
401
456
  const { contextUser, provider } = this.requireUserAndProvider(userPayload, providers);
402
457
  const session = await this.loadOwnedActiveSession(agentSessionId, contextUser, provider);
403
458
  const saved = replacesPrevious
404
- ? await this.replacePreviousTranscriptTurn(session, role, text, contextUser, provider)
405
- : await this.persistTranscriptTurn(session, role, text, contextUser, provider);
459
+ ? await this.replacePreviousTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs)
460
+ : await this.persistTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs);
406
461
  if (!saved) {
407
462
  return false;
408
463
  }
@@ -423,6 +478,122 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
423
478
  mapTranscriptRoleToChatRole(role) {
424
479
  return role.trim().toLowerCase() === 'user' ? 'user' : 'assistant';
425
480
  }
481
+ /**
482
+ * Upload a CLIENT-DIRECT session audio recording, store it in MJStorage, link it to the owning
483
+ * `AIAgentSession`, and stamp the session's recording fields. The browser records locally during
484
+ * the call and uploads the assembled blob (base64) once the session ends.
485
+ *
486
+ * Hard gates (in order):
487
+ * 1. Ownership — `loadOwnedSession` enforces `UserID === contextUser.ID` (throws on violation).
488
+ * 2. Consent — `consent !== true` is a hard refusal: no audio is ever stored without it.
489
+ * 3. Storage configuration — the session's agent must resolve a recording storage account (the
490
+ * agent's `RecordingStorageProviderID`, else `AttachmentStorageProviderID`).
491
+ *
492
+ * Storage failures (and any unexpected throw) come back as `Success: false` with a reason — they
493
+ * NEVER throw to the browser, mirroring the shared {@link storeRealtimeRecording} contract.
494
+ *
495
+ * @param agentSessionId The session the recording belongs to (ownership-gated).
496
+ * @param audioBase64 The base64-encoded recording bytes (client-direct: seekable WAV/PCM).
497
+ * @param mimeType The audio MIME type (`audio/wav` for client-direct; legacy `audio/webm`/`ogg`/`mp4`).
498
+ * @param durationMs Optional client-measured recording duration (ms) — informational.
499
+ * @param consent Whether the user consented to recording. MUST be `true` or the upload is refused.
500
+ * @param peaks Optional capture-time waveform peaks (max-abs per bucket, normalized 0..1). When
501
+ * present, persisted as a `peaks.json` sidecar beside the recording for fast waveform rendering
502
+ * without re-decoding the audio.
503
+ * @returns A structured {@link UploadRealtimeRecordingResult} with the created `MJ: Files` id.
504
+ */
505
+ async UploadRealtimeRecording(agentSessionId, audioBase64, mimeType, ctx, durationMs, consent, peaks) {
506
+ const { contextUser, provider } = this.requireUserAndProvider(ctx.userPayload, ctx.providers);
507
+ const session = await this.loadOwnedSession(agentSessionId, contextUser, provider);
508
+ // HARD consent gate — no audio is ever stored without an explicit grant.
509
+ if (consent !== true) {
510
+ return { Success: false, ErrorMessage: 'Recording consent was not granted.' };
511
+ }
512
+ try {
513
+ const agent = await provider.GetEntityObject('MJ: AI Agents', contextUser);
514
+ if (!(await agent.Load(session.AgentID))) {
515
+ return { Success: false, ErrorMessage: `Co-agent ${session.AgentID} for the session could not be loaded.` };
516
+ }
517
+ const accountID = await resolveRecordingStorageAccountID(agent, contextUser, provider);
518
+ if (!accountID) {
519
+ return { Success: false, ErrorMessage: 'No recording storage account is configured for this agent.' };
520
+ }
521
+ const buffer = Buffer.from(audioBase64, 'base64');
522
+ if (buffer.length === 0) {
523
+ return { Success: false, ErrorMessage: 'The uploaded recording was empty.' };
524
+ }
525
+ const fileID = await storeRealtimeRecording({
526
+ Audio: buffer,
527
+ MimeType: mimeType,
528
+ Media: 'Audio',
529
+ StartedAt: session.RecordingStartedAt ?? new Date(),
530
+ StorageAccountID: accountID,
531
+ SessionID: agentSessionId,
532
+ ContextUser: contextUser,
533
+ Provider: provider,
534
+ // Sanitized capture-time waveform peaks → persisted as a peaks.json sidecar.
535
+ Peaks: this.sanitizePeaks(peaks),
536
+ });
537
+ // Canonical consolidated file written — drop the crash-recovery shards (best-effort).
538
+ if (fileID) {
539
+ await deleteRealtimeRecordingSegments(agentSessionId, accountID, contextUser);
540
+ }
541
+ return {
542
+ Success: !!fileID,
543
+ FileID: fileID ?? undefined,
544
+ ErrorMessage: fileID ? undefined : 'Storage upload failed.',
545
+ };
546
+ }
547
+ catch (error) {
548
+ const message = error instanceof Error ? error.message : String(error);
549
+ LogError(`RealtimeClientSessionResolver.UploadRealtimeRecording failed for session ${agentSessionId}: ${message}`);
550
+ return { Success: false, ErrorMessage: message };
551
+ }
552
+ }
553
+ /**
554
+ * Uploads ONE crash-recovery audio shard (~15s) for an IN-PROGRESS recording into the session's
555
+ * folder (`realtime-recordings/<sessionId>/seg-NNNN.<ext>`) as a raw storage object. Durability
556
+ * insurance during a live call so a browser/tab death loses at most the last window; the shards are
557
+ * deleted once the canonical consolidated file lands via {@link UploadRealtimeRecording}. Ownership-
558
+ * gated; consent was already established at session start. Best-effort — returns `false` (never
559
+ * throws) on any problem so a failed shard never disrupts the live call.
560
+ *
561
+ * @param agentSessionId The in-progress session (ownership-gated).
562
+ * @param segmentIndex 0-based shard index within the session.
563
+ * @param audioBase64 The base64-encoded shard bytes.
564
+ * @param mimeType The audio MIME type.
565
+ * @returns `true` when the shard was stored.
566
+ */
567
+ async UploadRealtimeRecordingSegment(agentSessionId, segmentIndex, audioBase64, mimeType, ctx) {
568
+ try {
569
+ const { contextUser, provider } = this.requireUserAndProvider(ctx.userPayload, ctx.providers);
570
+ const session = await this.loadOwnedSession(agentSessionId, contextUser, provider);
571
+ const agent = await provider.GetEntityObject('MJ: AI Agents', contextUser);
572
+ if (!(await agent.Load(session.AgentID))) {
573
+ return false;
574
+ }
575
+ const accountID = await resolveRecordingStorageAccountID(agent, contextUser, provider);
576
+ if (!accountID) {
577
+ return false;
578
+ }
579
+ const buffer = Buffer.from(audioBase64, 'base64');
580
+ if (buffer.length === 0) {
581
+ return false;
582
+ }
583
+ return await writeRealtimeRecordingSegment({
584
+ SessionID: agentSessionId,
585
+ SegmentIndex: segmentIndex,
586
+ Audio: buffer,
587
+ MimeType: mimeType,
588
+ StorageAccountID: accountID,
589
+ ContextUser: contextUser,
590
+ });
591
+ }
592
+ catch (error) {
593
+ LogError(`RealtimeClientSessionResolver.UploadRealtimeRecordingSegment failed for session ${agentSessionId}: ${error instanceof Error ? error.message : String(error)}`);
594
+ return false;
595
+ }
596
+ }
426
597
  /**
427
598
  * Relays a co-agent CHANNEL tool-call (browser_ / Whiteboard_ etc.) onto the session's co-agent
428
599
  * AIPromptRun.Messages — run-only observability so the run captures what the co-agent DID, not just
@@ -525,6 +696,22 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
525
696
  clampTokenDelta(value) {
526
697
  return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
527
698
  }
699
+ /**
700
+ * Sanitizes client-supplied waveform peaks before they're persisted: drops anything that isn't a
701
+ * finite number, clamps each to `[0, 1]`, and caps the array length so a hostile client can't bloat
702
+ * the sidecar. Returns `undefined` for a missing/empty array (no sidecar written).
703
+ */
704
+ sanitizePeaks(peaks) {
705
+ if (!Array.isArray(peaks) || peaks.length === 0) {
706
+ return undefined;
707
+ }
708
+ const MAX_PEAKS = 4096; // generous ceiling above the client's ~600-bucket target
709
+ const cleaned = peaks
710
+ .slice(0, MAX_PEAKS)
711
+ .filter((v) => Number.isFinite(v))
712
+ .map((v) => (v < 0 ? 0 : v > 1 ? 1 : v));
713
+ return cleaned.length > 0 ? cleaned : undefined;
714
+ }
528
715
  /**
529
716
  * Reads the co-agent `AIPromptRun` id from the session config WITHOUT the relay path's
530
717
  * throw-on-missing-target semantics — usage relay is best-effort, so a missing/malformed
@@ -1014,12 +1201,15 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1014
1201
  * (from {@link loadPriorTranscript}) — the service frames it into the system prompt so a
1015
1202
  * resumed session remembers the previous leg(s).
1016
1203
  */
1017
- async prepareClientSessionOrClose(session, coAgentID, targetAgentId, contextUser, provider, preferredModelId, clientTools, priorTranscript, configOverridesJson) {
1204
+ async prepareClientSessionOrClose(session, coAgentID, targetAgentId, contextUser, provider, preferredModelId, clientTools, priorTranscript, configOverridesJson, maxSessionSeconds, applicationId, appContext) {
1018
1205
  const prep = await this.clientSessionService.PrepareClientSession({
1019
1206
  CoAgentID: coAgentID,
1020
1207
  TargetAgentID: targetAgentId,
1021
1208
  AgentSessionID: session.ID,
1022
1209
  ConversationID: session.ConversationID ?? undefined,
1210
+ // Server-authoritative voice duration cap (widget guests) — bounds the driver session
1211
+ // where supported; the janitor enforces the session deadline regardless.
1212
+ MaxSessionSeconds: maxSessionSeconds,
1023
1213
  // MVP: conversation history is not yet hydrated into ChatMessage[]; the co-agent
1024
1214
  // companion prompt runs without prior turns. A later phase loads the session's
1025
1215
  // Conversation into ChatMessage[] for richer context.
@@ -1033,13 +1223,17 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1033
1223
  PriorTranscript: priorTranscript,
1034
1224
  // Pre-authorized runtime override layer (assertRuntimeOverridesAuthorized gated it).
1035
1225
  ConfigOverridesJson: configOverridesJson,
1226
+ // App awareness (Move 1/3/4): the app sources the app cascade layer + RelevantAgents
1227
+ // (allowed-agent union); the snapshot is injected into the system prompt at mint.
1228
+ ApplicationID: applicationId,
1229
+ AppContext: appContext,
1036
1230
  }, contextUser, provider);
1037
1231
  if (!prep.Success || !prep.ClientConfig) {
1038
1232
  // Prep failure is an ERROR close, not an explicit user hang-up — stamp it as such.
1039
1233
  await this.sessionManager.CloseSession(session.ID, contextUser, provider, 'Error');
1040
1234
  throw new Error(prep.ErrorMessage ?? 'Failed to prepare the client realtime session.');
1041
1235
  }
1042
- await this.persistObservabilityRunIDs(session, targetAgentId, prep.CoAgentRunID, prep.PromptRunID, prep.CoAgentRunStepID);
1236
+ await this.persistObservabilityRunIDs(session, targetAgentId, prep.CoAgentRunID, prep.PromptRunID, prep.CoAgentRunStepID, applicationId, prep.EffectiveConfig?.realtime?.allowedAgents);
1043
1237
  const cfg = prep.ClientConfig;
1044
1238
  return {
1045
1239
  AgentSessionId: session.ID,
@@ -1061,8 +1255,19 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1061
1255
  * finalize the runs (and on relay to nest delegated runs). Best-effort: a save failure is logged,
1062
1256
  * not thrown — the voice session still proceeds, it just won't carry the run ids.
1063
1257
  */
1064
- async persistObservabilityRunIDs(session, targetAgentID, coAgentRunID, promptRunID, coAgentRunStepID) {
1065
- const config = { targetAgentID, coAgentRunID, promptRunID, coAgentRunStepID };
1258
+ async persistObservabilityRunIDs(session, targetAgentID, coAgentRunID, promptRunID, coAgentRunStepID, applicationID, allowedAgents) {
1259
+ // Preserve any server-authoritative voice deadline stamped at session start (this rebuilds the
1260
+ // full config, so read the existing value forward rather than dropping it).
1261
+ const existing = this.tryReadSessionConfig(session);
1262
+ const config = {
1263
+ targetAgentID,
1264
+ coAgentRunID,
1265
+ promptRunID,
1266
+ coAgentRunStepID,
1267
+ maxSessionDeadlineIso: existing?.maxSessionDeadlineIso,
1268
+ applicationID,
1269
+ allowedAgents: allowedAgents && allowedAgents.length > 0 ? allowedAgents : undefined,
1270
+ };
1066
1271
  session.Config_ = JSON.stringify(config);
1067
1272
  const saved = await session.Save();
1068
1273
  if (!saved) {
@@ -1545,6 +1750,28 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1545
1750
  LogError(`SaveSessionChannelArtifact: LastActiveAt stamp failed: ${error.message}`);
1546
1751
  }
1547
1752
  }
1753
+ /**
1754
+ * Tolerantly parses the `appContextJson` mutation arg into an {@link AppContextSnapshot}. Returns
1755
+ * `undefined` for absent/blank/malformed/non-object payloads — app context is best-effort enrichment
1756
+ * and must never fail a session start.
1757
+ *
1758
+ * @param appContextJson The raw JSON string the browser sent, or undefined.
1759
+ * @returns The parsed snapshot, or `undefined`.
1760
+ */
1761
+ parseAppContext(appContextJson) {
1762
+ if (!appContextJson || !appContextJson.trim()) {
1763
+ return undefined;
1764
+ }
1765
+ try {
1766
+ const parsed = JSON.parse(appContextJson);
1767
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
1768
+ ? parsed
1769
+ : undefined;
1770
+ }
1771
+ catch {
1772
+ return undefined;
1773
+ }
1774
+ }
1548
1775
  /**
1549
1776
  * Tolerantly parses + validates client-declared UI tool definitions (see the SECURITY NOTE on
1550
1777
  * {@link StartRealtimeClientSession}). Never throws — any rejection logs and returns
@@ -1613,6 +1840,9 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1613
1840
  promptRunID: typeof parsed.promptRunID === 'string' ? parsed.promptRunID : undefined,
1614
1841
  coAgentRunStepID: typeof parsed.coAgentRunStepID === 'string' ? parsed.coAgentRunStepID : undefined,
1615
1842
  pendingFeedbackRunID: typeof parsed.pendingFeedbackRunID === 'string' ? parsed.pendingFeedbackRunID : undefined,
1843
+ maxSessionDeadlineIso: typeof parsed.maxSessionDeadlineIso === 'string' ? parsed.maxSessionDeadlineIso : undefined,
1844
+ applicationID: typeof parsed.applicationID === 'string' ? parsed.applicationID : undefined,
1845
+ allowedAgents: Array.isArray(parsed.allowedAgents) ? parsed.allowedAgents : undefined,
1616
1846
  };
1617
1847
  }
1618
1848
  }
@@ -1622,13 +1852,58 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1622
1852
  }
1623
1853
  throw new Error(`Realtime session ${session.ID} has no target agent configured`);
1624
1854
  }
1855
+ /** Like {@link readSessionConfig} but returns `undefined` instead of throwing (for best-effort reads). */
1856
+ tryReadSessionConfig(session) {
1857
+ try {
1858
+ return this.readSessionConfig(session);
1859
+ }
1860
+ catch {
1861
+ return undefined;
1862
+ }
1863
+ }
1864
+ /**
1865
+ * Resolves the server-authoritative voice duration cap (seconds) for a session start, or `undefined`
1866
+ * when no cap applies (the common, uncapped case). A cap applies only when the caller is a public
1867
+ * web-widget guest with a configured `VoiceMaxSessionMinutes` on its widget instance (the same value
1868
+ * surfaced to the client guard at mint). Never throws — a resolution failure yields no cap rather
1869
+ * than blocking the start.
1870
+ */
1871
+ async resolveWidgetVoiceCapSeconds(userPayload, providers) {
1872
+ const elevation = await resolveWidgetGuestRunContext(userPayload, GetReadWriteProvider(providers));
1873
+ const minutes = elevation?.widget.VoiceMaxSessionMinutes;
1874
+ return minutes && minutes > 0 ? minutes * 60 : undefined;
1875
+ }
1625
1876
  /**
1626
1877
  * Persists a single transcript turn as a `Conversation Detail` stamped with the session's
1627
1878
  * conversation, the mapped role, the turn text, the session id, and the owning user.
1628
1879
  *
1629
1880
  * @returns The boolean save result (logs `CompleteMessage` on failure).
1630
1881
  */
1631
- async persistTranscriptTurn(session, role, text, contextUser, provider) {
1882
+ /**
1883
+ * Stamps `RecordingStartedAt` (the recording `t0` alignment origin) + `RecordingMedia` on a
1884
+ * just-started session when the browser captured WITH consent. Best-effort: a parse/save failure
1885
+ * is logged and swallowed — a recording-metadata problem must never fail the session start.
1886
+ *
1887
+ * @param session The freshly created/loaded session.
1888
+ * @param recordingConsent Whether the user consented to recording — only `true` stamps anything.
1889
+ * @param recordingStartedAt ISO-8601 recording start timestamp from the browser.
1890
+ */
1891
+ async stampRecordingStart(session, recordingConsent, recordingStartedAt) {
1892
+ if (recordingConsent !== true || !recordingStartedAt) {
1893
+ return;
1894
+ }
1895
+ const startedAt = new Date(recordingStartedAt);
1896
+ if (Number.isNaN(startedAt.getTime())) {
1897
+ LogError(`RealtimeClientSessionResolver.stampRecordingStart: invalid recordingStartedAt '${recordingStartedAt}' for session ${session.ID}`);
1898
+ return;
1899
+ }
1900
+ session.RecordingStartedAt = startedAt;
1901
+ session.RecordingMedia = 'Audio';
1902
+ if (!(await session.Save())) {
1903
+ LogError(`RealtimeClientSessionResolver.stampRecordingStart save failed: ${session.LatestResult?.CompleteMessage ?? 'unknown error'}`);
1904
+ }
1905
+ }
1906
+ async persistTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs) {
1632
1907
  const detail = await provider.GetEntityObject(CONVERSATION_DETAIL_ENTITY, contextUser);
1633
1908
  detail.NewRecord();
1634
1909
  detail.ConversationID = session.ConversationID;
@@ -1636,6 +1911,12 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1636
1911
  detail.Message = text;
1637
1912
  detail.AgentSessionID = session.ID;
1638
1913
  detail.UserID = contextUser.ID;
1914
+ if (typeof utteranceStartMs === 'number' && utteranceStartMs >= 0) {
1915
+ detail.UtteranceStartMs = utteranceStartMs;
1916
+ }
1917
+ if (typeof utteranceEndMs === 'number' && utteranceEndMs >= 0) {
1918
+ detail.UtteranceEndMs = utteranceEndMs;
1919
+ }
1639
1920
  const saved = await detail.Save();
1640
1921
  if (!saved) {
1641
1922
  LogError(`RealtimeClientSessionResolver.persistTranscriptTurn save failed: ${detail.LatestResult?.CompleteMessage ?? 'unknown error'}`);
@@ -1649,7 +1930,7 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1649
1930
  * appending a near-duplicate. Falls back to a plain insert when no prior turn exists
1650
1931
  * (the superseded turn may have failed to persist) — a correction is never dropped.
1651
1932
  */
1652
- async replacePreviousTranscriptTurn(session, role, text, contextUser, provider) {
1933
+ async replacePreviousTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs) {
1653
1934
  const mappedRole = this.mapTranscriptRole(role);
1654
1935
  const rv = RunView.FromMetadataProvider(provider);
1655
1936
  const result = await rv.RunView({
@@ -1661,9 +1942,17 @@ let RealtimeClientSessionResolver = class RealtimeClientSessionResolver extends
1661
1942
  }, contextUser);
1662
1943
  const previous = result.Success ? (result.Results?.[0] ?? null) : null;
1663
1944
  if (!previous) {
1664
- return this.persistTranscriptTurn(session, role, text, contextUser, provider);
1945
+ return this.persistTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs);
1665
1946
  }
1666
1947
  previous.Message = text;
1948
+ // The correction extends the existing turn: always refresh the end boundary when provided,
1949
+ // but only set the start when it wasn't already captured on the superseded turn.
1950
+ if (typeof utteranceEndMs === 'number' && utteranceEndMs >= 0) {
1951
+ previous.UtteranceEndMs = utteranceEndMs;
1952
+ }
1953
+ if (typeof utteranceStartMs === 'number' && utteranceStartMs >= 0 && previous.UtteranceStartMs == null) {
1954
+ previous.UtteranceStartMs = utteranceStartMs;
1955
+ }
1667
1956
  const saved = await previous.Save();
1668
1957
  if (!saved) {
1669
1958
  LogError(`RealtimeClientSessionResolver.replacePreviousTranscriptTurn save failed: ${previous.LatestResult?.CompleteMessage ?? 'unknown error'}`);
@@ -1689,8 +1978,13 @@ __decorate([
1689
1978
  __param(5, Arg('clientToolsJson', () => String, { nullable: true })),
1690
1979
  __param(6, Arg('coAgentId', () => String, { nullable: true })),
1691
1980
  __param(7, Arg('configOverridesJson', () => String, { nullable: true })),
1981
+ __param(8, Arg('recordingStartedAt', () => String, { nullable: true })),
1982
+ __param(9, Arg('recordingConsent', () => Boolean, { nullable: true })),
1983
+ __param(10, Arg('mediaCollectionId', () => String, { nullable: true })),
1984
+ __param(11, Arg('applicationId', () => String, { nullable: true })),
1985
+ __param(12, Arg('appContextJson', () => String, { nullable: true })),
1692
1986
  __metadata("design:type", Function),
1693
- __metadata("design:paramtypes", [String, Object, String, String, String, String, String, String]),
1987
+ __metadata("design:paramtypes", [String, Object, String, String, String, String, String, String, String, Boolean, String, String, String]),
1694
1988
  __metadata("design:returntype", Promise)
1695
1989
  ], RealtimeClientSessionResolver.prototype, "StartRealtimeClientSession", null);
1696
1990
  __decorate([
@@ -1712,10 +2006,36 @@ __decorate([
1712
2006
  __param(2, Arg('text', () => String)),
1713
2007
  __param(3, Ctx()),
1714
2008
  __param(4, Arg('replacesPrevious', () => Boolean, { nullable: true })),
2009
+ __param(5, Arg('utteranceStartMs', () => Int, { nullable: true })),
2010
+ __param(6, Arg('utteranceEndMs', () => Int, { nullable: true })),
1715
2011
  __metadata("design:type", Function),
1716
- __metadata("design:paramtypes", [String, String, String, Object, Boolean]),
2012
+ __metadata("design:paramtypes", [String, String, String, Object, Boolean, Number, Number]),
1717
2013
  __metadata("design:returntype", Promise)
1718
2014
  ], RealtimeClientSessionResolver.prototype, "RelayRealtimeTranscript", null);
2015
+ __decorate([
2016
+ Mutation(() => UploadRealtimeRecordingResult),
2017
+ __param(0, Arg('agentSessionId', () => String)),
2018
+ __param(1, Arg('audioBase64', () => String)),
2019
+ __param(2, Arg('mimeType', () => String)),
2020
+ __param(3, Ctx()),
2021
+ __param(4, Arg('durationMs', () => Int, { nullable: true })),
2022
+ __param(5, Arg('consent', () => Boolean, { nullable: true })),
2023
+ __param(6, Arg('peaks', () => [Float], { nullable: true })),
2024
+ __metadata("design:type", Function),
2025
+ __metadata("design:paramtypes", [String, String, String, Object, Number, Boolean, Array]),
2026
+ __metadata("design:returntype", Promise)
2027
+ ], RealtimeClientSessionResolver.prototype, "UploadRealtimeRecording", null);
2028
+ __decorate([
2029
+ Mutation(() => Boolean),
2030
+ __param(0, Arg('agentSessionId', () => String)),
2031
+ __param(1, Arg('segmentIndex', () => Int)),
2032
+ __param(2, Arg('audioBase64', () => String)),
2033
+ __param(3, Arg('mimeType', () => String)),
2034
+ __param(4, Ctx()),
2035
+ __metadata("design:type", Function),
2036
+ __metadata("design:paramtypes", [String, Number, String, String, Object]),
2037
+ __metadata("design:returntype", Promise)
2038
+ ], RealtimeClientSessionResolver.prototype, "UploadRealtimeRecordingSegment", null);
1719
2039
  __decorate([
1720
2040
  Mutation(() => Boolean),
1721
2041
  __param(0, Arg('agentSessionId', () => String)),