@memberjunction/server 5.44.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 (254) 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 +37 -0
  11. package/dist/agentSessions/SessionManager.js.map +1 -1
  12. package/dist/auth/magicLink/MagicLinkRouter.d.ts +10 -0
  13. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  14. package/dist/auth/magicLink/MagicLinkRouter.js +16 -0
  15. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  16. package/dist/auth/magicLink/index.d.ts +1 -1
  17. package/dist/auth/magicLink/index.d.ts.map +1 -1
  18. package/dist/auth/magicLink/index.js +1 -1
  19. package/dist/auth/magicLink/index.js.map +1 -1
  20. package/dist/auth/magicLink/types.d.ts +26 -0
  21. package/dist/auth/magicLink/types.d.ts.map +1 -1
  22. package/dist/config.d.ts +1883 -144
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +160 -36
  25. package/dist/config.js.map +1 -1
  26. package/dist/context.d.ts.map +1 -1
  27. package/dist/context.js +45 -2
  28. package/dist/context.js.map +1 -1
  29. package/dist/generated/generated.d.ts +522 -0
  30. package/dist/generated/generated.d.ts.map +1 -1
  31. package/dist/generated/generated.js +2860 -0
  32. package/dist/generated/generated.js.map +1 -1
  33. package/dist/generic/ResolverBase.d.ts +13 -0
  34. package/dist/generic/ResolverBase.d.ts.map +1 -1
  35. package/dist/generic/ResolverBase.js +22 -0
  36. package/dist/generic/ResolverBase.js.map +1 -1
  37. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  38. package/dist/generic/RunViewResolver.js +4 -0
  39. package/dist/generic/RunViewResolver.js.map +1 -1
  40. package/dist/index.d.ts +0 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +101 -3
  43. package/dist/index.js.map +1 -1
  44. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  45. package/dist/integration/CustomColumnPromoter.js +6 -0
  46. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  47. package/dist/realtimeWidget/WidgetRouter.d.ts +26 -0
  48. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -0
  49. package/dist/realtimeWidget/WidgetRouter.js +182 -0
  50. package/dist/realtimeWidget/WidgetRouter.js.map +1 -0
  51. package/dist/realtimeWidget/WidgetSessionService.d.ts +265 -0
  52. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -0
  53. package/dist/realtimeWidget/WidgetSessionService.js +477 -0
  54. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -0
  55. package/dist/realtimeWidget/host-identity.d.ts +40 -0
  56. package/dist/realtimeWidget/host-identity.d.ts.map +1 -0
  57. package/dist/realtimeWidget/host-identity.js +58 -0
  58. package/dist/realtimeWidget/host-identity.js.map +1 -0
  59. package/dist/realtimeWidget/index.d.ts +10 -0
  60. package/dist/realtimeWidget/index.d.ts.map +1 -0
  61. package/dist/realtimeWidget/index.js +9 -0
  62. package/dist/realtimeWidget/index.js.map +1 -0
  63. package/dist/realtimeWidget/visitorIdentity.d.ts +76 -0
  64. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -0
  65. package/dist/realtimeWidget/visitorIdentity.js +202 -0
  66. package/dist/realtimeWidget/visitorIdentity.js.map +1 -0
  67. package/dist/realtimeWidget/widgetCore.d.ts +106 -0
  68. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -0
  69. package/dist/realtimeWidget/widgetCore.js +173 -0
  70. package/dist/realtimeWidget/widgetCore.js.map +1 -0
  71. package/dist/realtimeWidget/widgetGuestElevation.d.ts +51 -0
  72. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -0
  73. package/dist/realtimeWidget/widgetGuestElevation.js +79 -0
  74. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -0
  75. package/dist/resolvers/ComponentRegistryResolver.d.ts +7 -0
  76. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  77. package/dist/resolvers/ComponentRegistryResolver.js +31 -8
  78. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  79. package/dist/resolvers/EntityPermissionResolver.d.ts.map +1 -1
  80. package/dist/resolvers/EntityPermissionResolver.js +1 -2
  81. package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
  82. package/dist/resolvers/QuerySystemUserResolver.d.ts +9 -6
  83. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  84. package/dist/resolvers/QuerySystemUserResolver.js +15 -13
  85. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  86. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +10 -0
  87. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  88. package/dist/resolvers/RealtimeClientSessionResolver.js +47 -3
  89. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  90. package/dist/resolvers/RingCentralTelephonyResolver.d.ts +27 -0
  91. package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
  92. package/dist/resolvers/RingCentralTelephonyResolver.js +87 -0
  93. package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
  94. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  95. package/dist/resolvers/RunAIAgentResolver.js +14 -3
  96. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  97. package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
  98. package/dist/resolvers/SearchKnowledgeResolver.js +2 -0
  99. package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
  100. package/dist/resolvers/TeamsMeetingsResolver.d.ts +28 -0
  101. package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
  102. package/dist/resolvers/TeamsMeetingsResolver.js +91 -0
  103. package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
  104. package/dist/resolvers/TelephonyResolver.d.ts +26 -0
  105. package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
  106. package/dist/resolvers/TelephonyResolver.js +86 -0
  107. package/dist/resolvers/TelephonyResolver.js.map +1 -0
  108. package/dist/resolvers/TestQuerySQLResolver.d.ts +1 -1
  109. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  110. package/dist/resolvers/TestQuerySQLResolver.js +2 -3
  111. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  112. package/dist/resolvers/VonageTelephonyResolver.d.ts +26 -0
  113. package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
  114. package/dist/resolvers/VonageTelephonyResolver.js +86 -0
  115. package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
  116. package/dist/rest/MediaStreamHandler.js +4 -1
  117. package/dist/rest/MediaStreamHandler.js.map +1 -1
  118. package/dist/telephony/RingCentralTelephonyService.d.ts +115 -0
  119. package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
  120. package/dist/telephony/RingCentralTelephonyService.js +262 -0
  121. package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
  122. package/dist/telephony/TeamsMeetingsRouter.d.ts +40 -0
  123. package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
  124. package/dist/telephony/TeamsMeetingsRouter.js +96 -0
  125. package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
  126. package/dist/telephony/TeamsMeetingsService.d.ts +113 -0
  127. package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
  128. package/dist/telephony/TeamsMeetingsService.js +196 -0
  129. package/dist/telephony/TeamsMeetingsService.js.map +1 -0
  130. package/dist/telephony/TwilioTelephonyRouter.d.ts +36 -0
  131. package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
  132. package/dist/telephony/TwilioTelephonyRouter.js +143 -0
  133. package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
  134. package/dist/telephony/TwilioTelephonyService.d.ts +95 -0
  135. package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
  136. package/dist/telephony/TwilioTelephonyService.js +193 -0
  137. package/dist/telephony/TwilioTelephonyService.js.map +1 -0
  138. package/dist/telephony/VonageTelephonyRouter.d.ts +41 -0
  139. package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
  140. package/dist/telephony/VonageTelephonyRouter.js +201 -0
  141. package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
  142. package/dist/telephony/VonageTelephonyService.d.ts +90 -0
  143. package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
  144. package/dist/telephony/VonageTelephonyService.js +191 -0
  145. package/dist/telephony/VonageTelephonyService.js.map +1 -0
  146. package/dist/telephony/calendar-scheduler.d.ts +67 -0
  147. package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
  148. package/dist/telephony/calendar-scheduler.js +133 -0
  149. package/dist/telephony/calendar-scheduler.js.map +1 -0
  150. package/dist/telephony/index.d.ts +29 -0
  151. package/dist/telephony/index.d.ts.map +1 -0
  152. package/dist/telephony/index.js +38 -0
  153. package/dist/telephony/index.js.map +1 -0
  154. package/dist/telephony/media-upgrade-router.d.ts +33 -0
  155. package/dist/telephony/media-upgrade-router.d.ts.map +1 -0
  156. package/dist/telephony/media-upgrade-router.js +56 -0
  157. package/dist/telephony/media-upgrade-router.js.map +1 -0
  158. package/dist/telephony/ringcentral-runtime.d.ts +14 -0
  159. package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
  160. package/dist/telephony/ringcentral-runtime.js +18 -0
  161. package/dist/telephony/ringcentral-runtime.js.map +1 -0
  162. package/dist/telephony/teams-meetings-runtime.d.ts +16 -0
  163. package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
  164. package/dist/telephony/teams-meetings-runtime.js +20 -0
  165. package/dist/telephony/teams-meetings-runtime.js.map +1 -0
  166. package/dist/telephony/teamsAcsMediaRegistry.d.ts +69 -0
  167. package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
  168. package/dist/telephony/teamsAcsMediaRegistry.js +118 -0
  169. package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
  170. package/dist/telephony/telephony-runtime.d.ts +14 -0
  171. package/dist/telephony/telephony-runtime.d.ts.map +1 -0
  172. package/dist/telephony/telephony-runtime.js +18 -0
  173. package/dist/telephony/telephony-runtime.js.map +1 -0
  174. package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
  175. package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
  176. package/dist/telephony/twilioMediaRegistry.js +106 -0
  177. package/dist/telephony/twilioMediaRegistry.js.map +1 -0
  178. package/dist/telephony/vonage-runtime.d.ts +14 -0
  179. package/dist/telephony/vonage-runtime.d.ts.map +1 -0
  180. package/dist/telephony/vonage-runtime.js +18 -0
  181. package/dist/telephony/vonage-runtime.js.map +1 -0
  182. package/dist/telephony/vonageMediaRegistry.d.ts +78 -0
  183. package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
  184. package/dist/telephony/vonageMediaRegistry.js +158 -0
  185. package/dist/telephony/vonageMediaRegistry.js.map +1 -0
  186. package/package.json +88 -83
  187. package/src/__tests__/search-knowledge-tags.test.ts +9 -9
  188. package/src/__tests__/teams-meetings-service.test.ts +65 -0
  189. package/src/__tests__/teamsAcsMediaRegistry.test.ts +82 -0
  190. package/src/__tests__/twilio-telephony-service.test.ts +23 -0
  191. package/src/__tests__/twilioMediaRegistry.test.ts +103 -0
  192. package/src/__tests__/vonageMediaRegistry.test.ts +180 -0
  193. package/src/__tests__/widget.test.ts +204 -0
  194. package/src/__tests__/widgetGuestElevation.test.ts +57 -0
  195. package/src/__tests__/widgetHostIdentity.test.ts +117 -0
  196. package/src/agentSessions/ReturningVisitorRecap.ts +242 -0
  197. package/src/agentSessions/SessionJanitor.ts +66 -6
  198. package/src/agentSessions/SessionManager.ts +38 -0
  199. package/src/auth/magicLink/MagicLinkRouter.ts +17 -0
  200. package/src/auth/magicLink/index.ts +1 -0
  201. package/src/auth/magicLink/types.ts +26 -0
  202. package/src/config.ts +172 -38
  203. package/src/context.ts +50 -3
  204. package/src/generated/generated.ts +1991 -1
  205. package/src/generic/ResolverBase.ts +28 -0
  206. package/src/generic/RunViewResolver.ts +4 -0
  207. package/src/index.ts +109 -3
  208. package/src/integration/CustomColumnPromoter.ts +6 -0
  209. package/src/realtimeWidget/WidgetRouter.ts +204 -0
  210. package/src/realtimeWidget/WidgetSessionService.ts +714 -0
  211. package/src/realtimeWidget/host-identity.ts +84 -0
  212. package/src/realtimeWidget/index.ts +15 -0
  213. package/src/realtimeWidget/visitorIdentity.ts +258 -0
  214. package/src/realtimeWidget/widgetCore.ts +231 -0
  215. package/src/realtimeWidget/widgetGuestElevation.ts +115 -0
  216. package/src/resolvers/ComponentRegistryResolver.ts +36 -10
  217. package/src/resolvers/EntityPermissionResolver.ts +1 -2
  218. package/src/resolvers/QuerySystemUserResolver.ts +14 -10
  219. package/src/resolvers/RealtimeClientSessionResolver.ts +59 -2
  220. package/src/resolvers/RingCentralTelephonyResolver.ts +64 -0
  221. package/src/resolvers/RunAIAgentResolver.ts +16 -4
  222. package/src/resolvers/SearchKnowledgeResolver.ts +2 -0
  223. package/src/resolvers/TeamsMeetingsResolver.ts +68 -0
  224. package/src/resolvers/TelephonyResolver.ts +63 -0
  225. package/src/resolvers/TestQuerySQLResolver.ts +2 -3
  226. package/src/resolvers/VonageTelephonyResolver.ts +63 -0
  227. package/src/rest/MediaStreamHandler.ts +4 -1
  228. package/src/telephony/RingCentralTelephonyService.ts +342 -0
  229. package/src/telephony/TeamsMeetingsRouter.ts +124 -0
  230. package/src/telephony/TeamsMeetingsService.ts +268 -0
  231. package/src/telephony/TwilioTelephonyRouter.ts +184 -0
  232. package/src/telephony/TwilioTelephonyService.ts +261 -0
  233. package/src/telephony/VonageTelephonyRouter.ts +239 -0
  234. package/src/telephony/VonageTelephonyService.ts +259 -0
  235. package/src/telephony/calendar-scheduler.ts +176 -0
  236. package/src/telephony/index.ts +43 -0
  237. package/src/telephony/media-upgrade-router.ts +62 -0
  238. package/src/telephony/ringcentral-runtime.ts +22 -0
  239. package/src/telephony/teams-meetings-runtime.ts +24 -0
  240. package/src/telephony/teamsAcsMediaRegistry.ts +152 -0
  241. package/src/telephony/telephony-runtime.ts +22 -0
  242. package/src/telephony/twilioMediaRegistry.ts +137 -0
  243. package/src/telephony/vonage-runtime.ts +22 -0
  244. package/src/telephony/vonageMediaRegistry.ts +200 -0
  245. package/dist/agents/skip-agent.d.ts +0 -111
  246. package/dist/agents/skip-agent.d.ts.map +0 -1
  247. package/dist/agents/skip-agent.js +0 -1487
  248. package/dist/agents/skip-agent.js.map +0 -1
  249. package/dist/agents/skip-sdk.d.ts +0 -261
  250. package/dist/agents/skip-sdk.d.ts.map +0 -1
  251. package/dist/agents/skip-sdk.js +0 -909
  252. package/dist/agents/skip-sdk.js.map +0 -1
  253. package/src/agents/skip-agent.ts +0 -1594
  254. package/src/agents/skip-sdk.ts +0 -1210
package/src/config.ts CHANGED
@@ -68,23 +68,6 @@ const zodBooleanWithTransforms = () => {
68
68
  })
69
69
  }
70
70
 
71
- const askSkipInfoSchema = z.object({
72
- url: z.string().optional(), // Base URL for Skip API
73
- apiKey: z.string().optional(),
74
- orgID: z.string().optional(),
75
- organizationInfo: z.string().optional(),
76
- entitiesToSend: z
77
- .object({
78
- excludeSchemas: z.array(z.string()).optional(),
79
- includeEntitiesFromExcludedSchemas: z.array(z.string()).optional(),
80
- })
81
- .optional(),
82
- chatURL: z.string().optional(),
83
- learningCycleRunUponStartup: zodBooleanWithTransforms(),
84
- learningCycleEnabled: zodBooleanWithTransforms(),
85
- learningCycleURL: z.string().optional(),
86
- learningCycleIntervalInMinutes: z.coerce.number().optional(),
87
- });
88
71
 
89
72
  const sqlLoggingOptionsSchema = z.object({
90
73
  formatAsMigration: z.boolean().optional().default(false),
@@ -330,13 +313,178 @@ const magicLinkSchema = z.object({
330
313
  explorerUrl: z.string().optional(),
331
314
  }).passthrough();
332
315
 
316
+ /**
317
+ * Public web widget config (plans/realtime/bridges-and-widget/public-web-widget.md).
318
+ * The widget REUSES the magic-link RS256 key + `anonymous-embed` synthesis, so it
319
+ * shares the magic-link `audience`/issuer/JWKS by default — the same auth provider
320
+ * validates both. When `enabled`, the server ensures the magic-link key manager is
321
+ * initialized and the provider registered even if `magicLink.enabled` is false.
322
+ */
323
+ const widgetSchema = z.object({
324
+ /** Master switch. When false, the /widget routes are not mounted. */
325
+ enabled: zodBooleanWithTransforms().default(false),
326
+ /**
327
+ * Which signing mechanism the widget reuses. Only `magic-link` is supported today
328
+ * (shares MagicLinkKeyManager + the magic-link auth provider). Recorded so a future
329
+ * dedicated widget key is a config flip, not a code change.
330
+ */
331
+ signingReuse: z.enum(['magic-link']).optional().default('magic-link'),
332
+ /**
333
+ * Audience claim for minted guest JWTs. MUST equal the magic-link audience so the
334
+ * auto-registered `magic-link` auth provider validates widget tokens.
335
+ */
336
+ audience: z.string().optional().default('mj-magic-link'),
337
+ /** Email of the shared Anonymous principal used in guest claims (resolves the synthesized guest user). */
338
+ anonymousEmail: z.string().optional().default('anonymous@magic-link.local'),
339
+ /** Fallback session-token TTL (minutes) when a widget instance does not set its own. */
340
+ defaultSessionTtlMinutes: z.coerce.number().optional().default(15),
341
+ /** Fallback mint rate-limit (per IP per window) when a widget instance does not set its own. */
342
+ defaultRateLimitPerMinute: z.coerce.number().optional().default(30),
343
+ /** Rate-limit window (ms) for the public /widget/session endpoints. Default 60s. */
344
+ rateLimitWindowMs: z.coerce.number().optional().default(60_000),
345
+ /** Server-wide default hard ceiling (minutes) on a voice session when an instance omits one (W4). */
346
+ voiceDefaultMaxSessionMinutes: z.coerce.number().optional().default(10),
347
+ /** Email/name of the internal user whose context READS widget config at mint time (falls back to system/Owner). */
348
+ contextUserForLookup: z.string().optional(),
349
+ /**
350
+ * Host-identity public keys (PEM), keyed by widget PublicKey, for the `host-identity` auth
351
+ * strategy (D1). The host signs a short-lived RS256 assertion; the mint verifies it against
352
+ * the key here. INTERIM location — production should store the host key per widget instance
353
+ * (a HostPublicKey column on WidgetInstance, pending a migration). When a widget's strategy is
354
+ * HostIdentity and no key is configured here, host mints fail closed.
355
+ */
356
+ hostPublicKeys: z.record(z.string(), z.string()).optional().default({}),
357
+ /**
358
+ * Returning-visitor identity-resolution target (RV4). When a visitor verifies (magic-link upgrade)
359
+ * or a host asserts their identity, their email is resolved to a record `(entityName, recordId)`
360
+ * and prior anonymous memory is merged onto that polymorphic pair. Deployment-configurable so the
361
+ * resolved record need NOT be an MJ User — point it at any entity that carries the visitor's email
362
+ * (e.g. a CRM `Persons` table). Defaults to the core `Users` entity keyed by `Email`.
363
+ */
364
+ identityResolution: z.object({
365
+ entityName: z.string().optional().default('Users'),
366
+ emailField: z.string().optional().default('Email'),
367
+ }).optional(),
368
+ }).passthrough();
369
+
370
+ /**
371
+ * Telephony bridge config (plans/realtime/bridges-and-widget/telephony-vendor-bindings.md).
372
+ * Holds the per-vendor credentials + public stream URL the MJAPI telephony ingress wires onto
373
+ * the already-stubbed native SDK seams. Credentials resolve here from `mj.config.cjs` / env —
374
+ * never inlined in code. When `twilio` is omitted, the Twilio telephony routes are not mounted.
375
+ */
376
+ const twilioTelephonySchema = z.object({
377
+ /** Twilio Account SID (`AC…`). */
378
+ accountSid: z.string(),
379
+ /** Account auth token — REST auth (when no API key pair) AND the HMAC key for X-Twilio-Signature verification. */
380
+ authToken: z.string().optional(),
381
+ /** API Key SID (`SK…`) — preferred over the auth token for REST auth when paired with apiKeySecret. */
382
+ apiKeySid: z.string().optional(),
383
+ /** API Key secret — paired with apiKeySid. */
384
+ apiKeySecret: z.string().optional(),
385
+ /** The publicly reachable `wss://…/telephony/twilio/media` URL Twilio's <Connect><Stream> connects to. */
386
+ streamPublicUrl: z.string(),
387
+ /** Optional shared secret gating the public webhook/WSS endpoints (defense-in-depth beyond signature verification). */
388
+ webhookSigningSecret: z.string().optional(),
389
+ /** Optional status-callback URL Twilio posts call lifecycle events to. */
390
+ statusCallbackUrl: z.string().optional(),
391
+ }).passthrough();
392
+
393
+ /**
394
+ * Vonage Voice + WebSocket-media telephony binding. Voice-API auth is application-scoped
395
+ * (application id + RSA private key) with an optional account API key pair for key-scoped ops;
396
+ * signatureSecret is the HMAC key for signed-request `sig` AND HS256 webhook-JWT verification.
397
+ * When `vonage` is omitted, the Vonage telephony routes are not mounted.
398
+ */
399
+ const vonageTelephonySchema = z.object({
400
+ /** Vonage Application ID (UUID) — the JWT-auth identity for the Voice API. */
401
+ applicationId: z.string().optional(),
402
+ /** The application's RSA private key (PEM) used to sign Voice-API JWTs. */
403
+ privateKey: z.string().optional(),
404
+ /** Account API key — used for key-scoped operations when no application credential pair is supplied. */
405
+ apiKey: z.string().optional(),
406
+ /** Account API secret — paired with apiKey. */
407
+ apiSecret: z.string().optional(),
408
+ /** The publicly reachable `wss://…/telephony/vonage/media` URL the call's connect NCCO opens. */
409
+ mediaPublicUrl: z.string(),
410
+ /** Vonage account signature secret — HMAC key for signed-request `sig` AND HS256 webhook-JWT verification. */
411
+ signatureSecret: z.string().optional(),
412
+ /** Optional event-webhook URL Vonage posts call lifecycle events to (passed on outbound createCall). */
413
+ eventUrl: z.string().optional(),
414
+ }).passthrough();
415
+
416
+ /**
417
+ * RingCentral telephony binding: **SIP device credentials** for the headless softphone (the
418
+ * `ringcentral-softphone` SIP/RTP path — the only RingCentral product that carries bidirectional call
419
+ * audio; the WebSocket "Call Streaming" product is receive-only). These come from a RingCentral
420
+ * "Other Phone" (BYO-device) registration's SIP info, resolved here from `mj.config.cjs` / env — never
421
+ * inlined. When `ringcentral` is omitted, the RingCentral softphone is not started.
422
+ *
423
+ * Unlike Twilio/Vonage, there is NO public HTTP webhook or media WSS: the softphone is an outbound SIP
424
+ * registration that receives inbound INVITEs directly over its own SIP/TLS connection. So this block has
425
+ * no signing secret or public URL — just the SIP device creds + codec.
426
+ */
427
+ const ringcentralTelephonySchema = z.object({
428
+ /** SIP domain (e.g. `sip.ringcentral.com`). */
429
+ sipDomain: z.string(),
430
+ /** SIP outbound proxy (`host:port`, e.g. `sip10.ringcentral.com:5096`). */
431
+ sipOutboundProxy: z.string(),
432
+ /** SIP auth username (the device's phone number / extension). */
433
+ sipUsername: z.string(),
434
+ /** SIP auth password (resolved upstream — never inlined). */
435
+ sipPassword: z.string(),
436
+ /** SIP authorization id (the device's RingCentral authorization id). */
437
+ sipAuthorizationId: z.string(),
438
+ /** Codec to negotiate. Defaults to `OPUS/16000` (clean wideband PCM16 — the least-friction realtime path). */
439
+ codec: z.enum(['OPUS/16000', 'OPUS/48000/2', 'PCMU/8000']).optional(),
440
+ /** Skip TLS cert validation (sandbox/test only — never in production). */
441
+ ignoreTlsCertErrors: zodBooleanWithTransforms().optional().default(false),
442
+ }).passthrough();
443
+
444
+ /**
445
+ * Teams meetings bridge config (plans/realtime/bridges-and-widget/meeting-vendor-bindings-teams-slack.md M1).
446
+ * Holds the bot credentials + Graph webhook shared secret + ACS audio rate the MJAPI meetings ingress wires
447
+ * onto the Teams binding seams. Credentials resolve here from `mj.config.cjs` / env — never inlined in code.
448
+ * When `teams` is omitted (or disabled), the Teams meetings routes are not mounted.
449
+ */
450
+ const teamsMeetingsSchema = z.object({
451
+ /** Master switch for the Teams meetings ingress. */
452
+ enabled: zodBooleanWithTransforms().default(false),
453
+ /** The bot's Azure AD application (client) id (resolved upstream; carried for diagnostics). */
454
+ appId: z.string().optional(),
455
+ /** The Azure tenant id the bot operates in. */
456
+ tenantId: z.string().optional(),
457
+ /** A pre-resolved OAuth bearer / application token for the bot's Graph calls (resolved upstream — never inline). */
458
+ botAccessToken: z.string().optional(),
459
+ /** The shared secret set as `clientState` on the Graph subscription; gates the change-notification webhook. */
460
+ notificationClientState: z.string().optional(),
461
+ /** The ACS application-hosted-media PCM sample rate (Hz) the audio plane negotiates. Defaults to 16000. */
462
+ acsSampleRate: z.coerce.number().optional().default(16000),
463
+ /** The realtime model's PCM16 sample rate (Hz) the binding resamples to/from. Defaults to 16000. */
464
+ modelSampleRate: z.coerce.number().optional().default(16000),
465
+ }).passthrough();
466
+
467
+ const telephonySchema = z.object({
468
+ /** Master switch. When false (or when no vendor block is present), telephony routes are not mounted. */
469
+ enabled: zodBooleanWithTransforms().default(false),
470
+ /** Twilio Programmable Voice + Media Streams binding. */
471
+ twilio: twilioTelephonySchema.optional(),
472
+ /** Vonage Voice + WebSocket-media binding. */
473
+ vonage: vonageTelephonySchema.optional(),
474
+ /** RingCentral Call Control + media-stream binding. */
475
+ ringcentral: ringcentralTelephonySchema.optional(),
476
+ /** Microsoft Teams meetings (Graph cloud-communications + ACS application-hosted media) binding. */
477
+ teams: teamsMeetingsSchema.optional(),
478
+ }).passthrough();
479
+
333
480
  const configInfoSchema = z.object({
334
481
  userHandling: userHandlingInfoSchema,
335
482
  magicLink: magicLinkSchema.optional().default({}),
483
+ widget: widgetSchema.optional().default({}),
484
+ telephony: telephonySchema.optional().default({}),
336
485
  databaseSettings: databaseSettingsInfoSchema,
337
486
  viewingSystem: viewingSystemInfoSchema.optional(),
338
487
  restApiOptions: restApiOptionsSchema.optional().default({}),
339
- askSkip: askSkipInfoSchema.optional(),
340
488
  sqlLogging: sqlLoggingSchema.optional(),
341
489
  authProviders: z.array(authProviderSchema).optional(),
342
490
  componentRegistries: z.array(componentRegistrySchema).optional(),
@@ -384,10 +532,15 @@ const configInfoSchema = z.object({
384
532
 
385
533
  export type UserHandlingInfo = z.infer<typeof userHandlingInfoSchema>;
386
534
  export type MagicLinkConfig = z.infer<typeof magicLinkSchema>;
535
+ export type WidgetConfig = z.infer<typeof widgetSchema>;
536
+ export type TelephonyConfig = z.infer<typeof telephonySchema>;
537
+ export type TwilioTelephonyConfig = z.infer<typeof twilioTelephonySchema>;
538
+ export type VonageTelephonyConfig = z.infer<typeof vonageTelephonySchema>;
539
+ export type RingCentralTelephonyConfig = z.infer<typeof ringcentralTelephonySchema>;
540
+ export type TeamsMeetingsConfig = z.infer<typeof teamsMeetingsSchema>;
387
541
  export type DatabaseSettingsInfo = z.infer<typeof databaseSettingsInfoSchema>;
388
542
  export type ViewingSystemSettingsInfo = z.infer<typeof viewingSystemInfoSchema>;
389
543
  export type RESTApiOptions = z.infer<typeof restApiOptionsSchema>;
390
- export type AskSkipInfo = z.infer<typeof askSkipInfoSchema>;
391
544
  export type SqlLoggingOptions = z.infer<typeof sqlLoggingOptionsSchema>;
392
545
  export type SqlLoggingInfo = z.infer<typeof sqlLoggingSchema>;
393
546
  export type AuthProviderConfig = z.infer<typeof authProviderSchema>;
@@ -477,25 +630,6 @@ export const DEFAULT_SERVER_CONFIG: Partial<ConfigInfo> = {
477
630
  enabled: false,
478
631
  },
479
632
 
480
- // Ask Skip configuration (environment-driven)
481
- askSkip: {
482
- url: process.env.ASK_SKIP_URL,
483
- chatURL: process.env.ASK_SKIP_CHAT_URL,
484
- learningCycleURL: process.env.ASK_SKIP_LEARNING_URL,
485
- learningCycleIntervalInMinutes: process.env.ASK_SKIP_LEARNING_CYCLE_INTERVAL_IN_MINUTES
486
- ? parseInt(process.env.ASK_SKIP_LEARNING_CYCLE_INTERVAL_IN_MINUTES, 10)
487
- : undefined,
488
- learningCycleEnabled: process.env.ASK_SKIP_RUN_LEARNING_CYCLES === 'true',
489
- learningCycleRunUponStartup: process.env.ASK_SKIP_RUN_LEARNING_CYCLES_UPON_STARTUP === 'true',
490
- orgID: process.env.ASK_SKIP_ORGANIZATION_ID,
491
- apiKey: process.env.ASK_SKIP_API_KEY,
492
- organizationInfo: process.env.ASK_SKIP_ORGANIZATION_INFO,
493
- entitiesToSend: {
494
- excludeSchemas: [],
495
- includeEntitiesFromExcludedSchemas: [],
496
- },
497
- },
498
-
499
633
  // SQL logging defaults
500
634
  sqlLogging: {
501
635
  enabled: true,
package/src/context.ts CHANGED
@@ -15,7 +15,7 @@ import { GetReadOnlyDataSource, GetReadWriteDataSource } from './util.js';
15
15
  import { v4 as uuidv4 } from 'uuid';
16
16
  import e from 'express';
17
17
  import type { RequestHandler, Request, Response, NextFunction } from 'express';
18
- import { DatabaseProviderBase, UserInfo, type MagicLinkScope } from '@memberjunction/core';
18
+ import { DatabaseProviderBase, UserInfo, type MagicLinkScope, type ReturningVisitorContext, type WidgetGuestContext } from '@memberjunction/core';
19
19
  import { SQLServerDataProvider, SQLServerProviderConfigData, UserCache } from '@memberjunction/sqlserver-dataprovider';
20
20
  import { Metadata } from '@memberjunction/core';
21
21
  import { UUIDsEqual } from '@memberjunction/global';
@@ -242,8 +242,17 @@ function buildMagicLinkSessionUser(userRecord: UserInfo, payload: jwt.JwtPayload
242
242
  }
243
243
  }
244
244
 
245
- // Named session with no resource scope no per-request state needed, use the cached user.
246
- if (!isAnon && !scope) {
245
+ // Returning-visitor context (RV1/RV2/RV4): carried on a widget guest token so the voice path
246
+ // (server-created conversation) stamps the same returning-visitor anchor + resolved identity.
247
+ const visitorContext = extractReturningVisitorContext(payload);
248
+
249
+ // Widget-instance identity (mj_widget_id): present on every public web-widget guest token. The
250
+ // privileged agent-dispatch path reads it to resolve the AUTHORITATIVE pinned agent for the guest
251
+ // (so a guest can never run an arbitrary agent under the elevated server principal).
252
+ const widgetGuestContext = extractWidgetGuestContext(payload);
253
+
254
+ // Named session with no resource scope and no widget/visitor context → no per-request state needed.
255
+ if (!isAnon && !scope && !visitorContext && !widgetGuestContext) {
247
256
  return userRecord;
248
257
  }
249
258
 
@@ -255,6 +264,12 @@ function buildMagicLinkSessionUser(userRecord: UserInfo, payload: jwt.JwtPayload
255
264
  if (scope) {
256
265
  sessionUser.MagicLinkScope = scope;
257
266
  }
267
+ if (visitorContext) {
268
+ sessionUser.ReturningVisitorContext = visitorContext;
269
+ }
270
+ if (widgetGuestContext) {
271
+ sessionUser.WidgetGuestContext = widgetGuestContext;
272
+ }
258
273
  if (isAnon) {
259
274
  // Mark the session so the CurrentUser field resolver serves these synthesized roles
260
275
  // (the shared Anonymous principal holds none in the DB). See UserInfo.IsMagicLinkAnonymous.
@@ -263,6 +278,38 @@ function buildMagicLinkSessionUser(userRecord: UserInfo, payload: jwt.JwtPayload
263
278
  return sessionUser;
264
279
  }
265
280
 
281
+ /**
282
+ * Extracts the returning-visitor context (RV1/RV2/RV4) from a widget guest token's claims, or
283
+ * undefined when the token carries no VisitorKey (the default, remembering-off case). Used so the
284
+ * voice path can stamp the conversation with the same anchor/identity the text path stamps client-side.
285
+ */
286
+ function extractReturningVisitorContext(payload: jwt.JwtPayload): ReturningVisitorContext | undefined {
287
+ const visitorKey = payload['mj_visitor_key'];
288
+ if (typeof visitorKey !== 'string' || !visitorKey) {
289
+ return undefined;
290
+ }
291
+ const str = (v: unknown): string | undefined => (typeof v === 'string' && v ? v : undefined);
292
+ return {
293
+ VisitorKey: visitorKey,
294
+ LastConversationID: str(payload['mj_last_conversation_id']),
295
+ LinkedEntityID: str(payload['mj_linked_entity_id']),
296
+ LinkedRecordID: str(payload['mj_linked_record_id']),
297
+ };
298
+ }
299
+
300
+ /**
301
+ * Extracts the widget-instance identity (`mj_widget_id`) from a public web-widget guest token, or
302
+ * undefined when the token carries none (every non-widget session). Carried so the privileged
303
+ * agent-dispatch path can resolve the authoritative pinned agent for the guest from the trusted token.
304
+ */
305
+ function extractWidgetGuestContext(payload: jwt.JwtPayload): WidgetGuestContext | undefined {
306
+ const widgetId = payload['mj_widget_id'];
307
+ if (typeof widgetId !== 'string' || !widgetId) {
308
+ return undefined;
309
+ }
310
+ return { WidgetID: widgetId };
311
+ }
312
+
266
313
  const verifyAsync = async (issuer: string, token: string): Promise<jwt.JwtPayload> =>
267
314
  new Promise((resolve, reject) => {
268
315
  const options = getValidationOptions(issuer);