@opencxh/domain 1.18.1 → 1.20.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.
@@ -1,5 +1,4 @@
1
1
  import { AIMessageInput, AIMessageOutput } from '../ai-message/types';
2
- import { Transcript } from '../transcript/types';
3
2
  export type CallStatus = "new" | "connecting" | "ringing" | "connected" | "held" | "ended" | "failed";
4
3
  export type CallDirection = "inbound" | "outbound";
5
4
  export type CallType = "audio" | "video" | "data" | "screen-share";
@@ -111,8 +110,17 @@ export type ChatEventPayload = {
111
110
  initiator?: ChatMember;
112
111
  raw?: any;
113
112
  };
113
+ export type TranscriptAddedSegment = {
114
+ speaker: 'local' | 'remote';
115
+ speakerLabel?: string;
116
+ text: string;
117
+ startedAt: number;
118
+ endedAt: number;
119
+ };
114
120
  export type TranscriptAddedPayload = {
115
- transcript: Transcript;
121
+ text: string;
122
+ segments?: TranscriptAddedSegment[];
123
+ finalized: boolean;
116
124
  };
117
125
  export type MeetingPayload = {
118
126
  title: string;
@@ -1,6 +1,2 @@
1
1
  import { Contact, ContactEndpoint } from './types';
2
- /**
3
- * Returns the contact's communication endpoints, synthesising them from
4
- * legacy phone/email fields when `endpoints` is not populated yet.
5
- */
6
2
  export declare function getContactEndpoints(contact: Contact): ContactEndpoint[];
@@ -1,2 +1,3 @@
1
1
  export * from './types';
2
2
  export * from './endpoints';
3
+ export * from './provider';
@@ -0,0 +1,13 @@
1
+ import { CommunicationScheme } from '../../platform/communication';
2
+ import { Contact, OwnerScope } from './types';
3
+ export interface ContactSearchQuery {
4
+ text?: string;
5
+ scope?: OwnerScope[];
6
+ limit?: number;
7
+ }
8
+ export interface ContactProvider {
9
+ id: string;
10
+ searchContacts(q: ContactSearchQuery): Promise<Contact[]>;
11
+ resolveByEndpoint(scheme: CommunicationScheme, resource: string): Promise<Contact | null>;
12
+ listContacts?(scope: OwnerScope): Promise<Contact[]>;
13
+ }
@@ -5,17 +5,29 @@ export interface ContactEndpoint {
5
5
  label?: string;
6
6
  primary?: boolean;
7
7
  }
8
- /**
9
- * Data model for a single Contact.
10
- */
8
+ export type OwnerScope = {
9
+ kind: "personal";
10
+ userId: string;
11
+ } | {
12
+ kind: "team";
13
+ teamId: string;
14
+ } | {
15
+ kind: "org";
16
+ organizationId: string;
17
+ };
18
+ export interface ContactSource {
19
+ providerId: string;
20
+ externalId?: string;
21
+ readOnly?: boolean;
22
+ }
11
23
  export interface Contact {
12
24
  id: string;
13
25
  organizationId: string;
26
+ ownerScope: OwnerScope;
27
+ source: ContactSource;
14
28
  firstName: string;
15
29
  lastName?: string;
16
30
  company?: string;
17
- email?: string;
18
- phone?: string;
19
31
  address?: string;
20
32
  endpoints?: ContactEndpoint[];
21
33
  }
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var l=(t=>(t.MAILTO="mailto",t.SIP="sip",t.TEL="tel",t.WEBHOOK="webhook",t.USERNAME="username",t.ID="id",t.CUSTOM="custom",t.URL="url",t.TELEGRAM="telegram",t.WHATSAPP="whatsapp",t.VIBER="viber",t.SMS="sms",t.FAX="fax",t.TEAMS="teams",t))(l||{});function a(t){if(t.endpoints&&t.endpoints.length>0)return t.endpoints;const e=[];return t.phone&&e.push({scheme:l.TEL,resource:t.phone,primary:!0}),t.email&&e.push({scheme:l.MAILTO,resource:t.email,primary:!t.phone}),e}const p=t=>!!t.assignedUserId||!!t.assignedInboxId,d=t=>t.status==="closed",g=t=>({urgent:10,high:5,normal:2,low:1})[t.priority]||0,c=(t,e=30)=>t.title?.length<=e?t.title:`${t.title.substring(0,e)}...`;function f(t,e){const r=new Set(t.disabledIntents??[]),i=t.intentOverrides??{},n=e.intents.filter(s=>!r.has(s.intent)).map(s=>I(s,i[s.intent]));if(!t.extraIntents||t.extraIntents.length===0)return n;const o=new Set(n.map(s=>s.intent));for(const s of t.extraIntents)o.has(s.intent)||(n.push(s),o.add(s.intent));return n}function I(t,e){return e?{intent:e.intent??t.intent,targetSchemes:e.targetSchemes??t.targetSchemes,transport:e.transport??t.transport}:t}function h(t,e){const r=[];for(const i of t){if(!i.enabled)continue;const n=e[i.providerId];if(n)for(const o of f(i,n))r.push({channel:i,description:n,capability:o})}return r}function y(t,e){return e.filter(r=>r.capability.intent===t)}function u(t,e){return e.filter(r=>r.capability.targetSchemes.includes(t))}function T(t,e){return u(t.scheme,e)}function b(t,e,r){const i=[];for(const n of t)for(const o of r)o.capability.intent===e&&o.capability.targetSchemes.includes(n.scheme)&&i.push({channelIntent:o,endpoint:n});return i}exports.CommunicationScheme=l;exports.buildChannelIntents=h;exports.filterByEndpoint=T;exports.filterByIntent=y;exports.filterByTargetScheme=u;exports.getContactEndpoints=a;exports.getShortTitle=c;exports.getUrgencyScore=g;exports.isAssigned=p;exports.isClosed=d;exports.matchContactToIntents=b;exports.resolveChannelIntents=f;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function c(t){return t.endpoints??[]}const u=t=>!!t.assignedUserId||!!t.assignedInboxId,d=t=>t.status==="closed",g=t=>({urgent:10,high:5,normal:2,low:1})[t.priority]||0,p=(t,n=30)=>t.title?.length<=n?t.title:`${t.title.substring(0,n)}...`;function l(t,n){const s=new Set(t.disabledIntents??[]),i=t.intentOverrides??{},e=n.intents.filter(r=>!s.has(r.intent)).map(r=>I(r,i[r.intent]));if(!t.extraIntents||t.extraIntents.length===0)return e;const o=new Set(e.map(r=>r.intent));for(const r of t.extraIntents)o.has(r.intent)||(e.push(r),o.add(r.intent));return e}function I(t,n){return n?{intent:n.intent??t.intent,targetSchemes:n.targetSchemes??t.targetSchemes,transport:n.transport??t.transport}:t}function y(t,n){const s=[];for(const i of t){if(!i.enabled)continue;const e=n[i.providerId];if(e)for(const o of l(i,e))s.push({channel:i,description:e,capability:o})}return s}function b(t,n){return n.filter(s=>s.capability.intent===t)}function a(t,n){return n.filter(s=>s.capability.targetSchemes.includes(t))}function h(t,n){return a(t.scheme,n)}function T(t,n,s){const i=[];for(const e of t)for(const o of s)o.capability.intent===n&&o.capability.targetSchemes.includes(e.scheme)&&i.push({channelIntent:o,endpoint:e});return i}var f=(t=>(t.MAILTO="mailto",t.SIP="sip",t.TEL="tel",t.WEBHOOK="webhook",t.USERNAME="username",t.ID="id",t.CUSTOM="custom",t.URL="url",t.TELEGRAM="telegram",t.WHATSAPP="whatsapp",t.VIBER="viber",t.SMS="sms",t.FAX="fax",t.TEAMS="teams",t))(f||{});exports.CommunicationScheme=f;exports.buildChannelIntents=y;exports.filterByEndpoint=h;exports.filterByIntent=b;exports.filterByTargetScheme=a;exports.getContactEndpoints=c;exports.getShortTitle=p;exports.getUrgencyScore=g;exports.isAssigned=u;exports.isClosed=d;exports.matchContactToIntents=T;exports.resolveChannelIntents=l;
package/dist/index.js CHANGED
@@ -1,69 +1,66 @@
1
- var f = /* @__PURE__ */ ((t) => (t.MAILTO = "mailto", t.SIP = "sip", t.TEL = "tel", t.WEBHOOK = "webhook", t.USERNAME = "username", t.ID = "id", t.CUSTOM = "custom", t.URL = "url", t.TELEGRAM = "telegram", t.WHATSAPP = "whatsapp", t.VIBER = "viber", t.SMS = "sms", t.FAX = "fax", t.TEAMS = "teams", t))(f || {});
2
- function a(t) {
3
- if (t.endpoints && t.endpoints.length > 0)
4
- return t.endpoints;
5
- const e = [];
6
- return t.phone && e.push({ scheme: f.TEL, resource: t.phone, primary: !0 }), t.email && e.push({ scheme: f.MAILTO, resource: t.email, primary: !t.phone }), e;
1
+ function c(t) {
2
+ return t.endpoints ?? [];
7
3
  }
8
- const d = (t) => !!t.assignedUserId || !!t.assignedInboxId, g = (t) => t.status === "closed", I = (t) => ({
4
+ const d = (t) => !!t.assignedUserId || !!t.assignedInboxId, p = (t) => t.status === "closed", g = (t) => ({
9
5
  urgent: 10,
10
6
  high: 5,
11
7
  normal: 2,
12
8
  low: 1
13
- })[t.priority] || 0, c = (t, e = 30) => t.title?.length <= e ? t.title : `${t.title.substring(0, e)}...`;
14
- function l(t, e) {
15
- const r = new Set(t.disabledIntents ?? []), i = t.intentOverrides ?? {}, n = e.intents.filter((s) => !r.has(s.intent)).map((s) => u(s, i[s.intent]));
16
- if (!t.extraIntents || t.extraIntents.length === 0) return n;
17
- const o = new Set(n.map((s) => s.intent));
9
+ })[t.priority] || 0, I = (t, n = 30) => t.title?.length <= n ? t.title : `${t.title.substring(0, n)}...`;
10
+ function f(t, n) {
11
+ const r = new Set(t.disabledIntents ?? []), i = t.intentOverrides ?? {}, e = n.intents.filter((s) => !r.has(s.intent)).map((s) => l(s, i[s.intent]));
12
+ if (!t.extraIntents || t.extraIntents.length === 0) return e;
13
+ const o = new Set(e.map((s) => s.intent));
18
14
  for (const s of t.extraIntents)
19
- o.has(s.intent) || (n.push(s), o.add(s.intent));
20
- return n;
15
+ o.has(s.intent) || (e.push(s), o.add(s.intent));
16
+ return e;
21
17
  }
22
- function u(t, e) {
23
- return e ? {
24
- intent: e.intent ?? t.intent,
25
- targetSchemes: e.targetSchemes ?? t.targetSchemes,
26
- transport: e.transport ?? t.transport
18
+ function l(t, n) {
19
+ return n ? {
20
+ intent: n.intent ?? t.intent,
21
+ targetSchemes: n.targetSchemes ?? t.targetSchemes,
22
+ transport: n.transport ?? t.transport
27
23
  } : t;
28
24
  }
29
- function h(t, e) {
25
+ function b(t, n) {
30
26
  const r = [];
31
27
  for (const i of t) {
32
28
  if (!i.enabled) continue;
33
- const n = e[i.providerId];
34
- if (n)
35
- for (const o of l(i, n))
36
- r.push({ channel: i, description: n, capability: o });
29
+ const e = n[i.providerId];
30
+ if (e)
31
+ for (const o of f(i, e))
32
+ r.push({ channel: i, description: e, capability: o });
37
33
  }
38
34
  return r;
39
35
  }
40
- function y(t, e) {
41
- return e.filter((r) => r.capability.intent === t);
36
+ function y(t, n) {
37
+ return n.filter((r) => r.capability.intent === t);
42
38
  }
43
- function p(t, e) {
44
- return e.filter((r) => r.capability.targetSchemes.includes(t));
39
+ function a(t, n) {
40
+ return n.filter((r) => r.capability.targetSchemes.includes(t));
45
41
  }
46
- function b(t, e) {
47
- return p(t.scheme, e);
42
+ function E(t, n) {
43
+ return a(t.scheme, n);
48
44
  }
49
- function E(t, e, r) {
45
+ function T(t, n, r) {
50
46
  const i = [];
51
- for (const n of t)
47
+ for (const e of t)
52
48
  for (const o of r)
53
- o.capability.intent === e && o.capability.targetSchemes.includes(n.scheme) && i.push({ channelIntent: o, endpoint: n });
49
+ o.capability.intent === n && o.capability.targetSchemes.includes(e.scheme) && i.push({ channelIntent: o, endpoint: e });
54
50
  return i;
55
51
  }
52
+ var u = /* @__PURE__ */ ((t) => (t.MAILTO = "mailto", t.SIP = "sip", t.TEL = "tel", t.WEBHOOK = "webhook", t.USERNAME = "username", t.ID = "id", t.CUSTOM = "custom", t.URL = "url", t.TELEGRAM = "telegram", t.WHATSAPP = "whatsapp", t.VIBER = "viber", t.SMS = "sms", t.FAX = "fax", t.TEAMS = "teams", t))(u || {});
56
53
  export {
57
- f as CommunicationScheme,
58
- h as buildChannelIntents,
59
- b as filterByEndpoint,
54
+ u as CommunicationScheme,
55
+ b as buildChannelIntents,
56
+ E as filterByEndpoint,
60
57
  y as filterByIntent,
61
- p as filterByTargetScheme,
62
- a as getContactEndpoints,
63
- c as getShortTitle,
64
- I as getUrgencyScore,
58
+ a as filterByTargetScheme,
59
+ c as getContactEndpoints,
60
+ I as getShortTitle,
61
+ g as getUrgencyScore,
65
62
  d as isAssigned,
66
- g as isClosed,
67
- E as matchContactToIntents,
68
- l as resolveChannelIntents
63
+ p as isClosed,
64
+ T as matchContactToIntents,
65
+ f as resolveChannelIntents
69
66
  };
@@ -1,8 +1,40 @@
1
- export interface AudioChunk {
1
+ export type Speaker = 'local' | 'remote';
2
+ export interface AudioSegment {
2
3
  sessionId: string;
4
+ speaker: Speaker;
5
+ speakerId?: string;
3
6
  buffer: Float32Array;
4
7
  sampleRate: number;
5
- avgRMS?: number;
8
+ startedAt: number;
9
+ endedAt: number;
10
+ avgRMS: number;
11
+ isFinal: boolean;
12
+ }
13
+ export interface TranscriptWord {
14
+ text: string;
15
+ startedAt: number;
16
+ endedAt: number;
17
+ }
18
+ export interface TranscriptSegment {
19
+ sessionId: string;
20
+ speaker: Speaker;
21
+ speakerId?: string;
22
+ speakerLabel?: string;
23
+ text: string;
24
+ words?: TranscriptWord[];
25
+ partial: boolean;
26
+ startedAt: number;
27
+ endedAt: number;
28
+ language?: string;
29
+ confidence?: number;
30
+ }
31
+ export interface AudioPipelineOptions {
32
+ silenceThreshold: number;
33
+ minRMS: number;
34
+ speechFrameRatio: number;
35
+ silenceDurationMs: number;
36
+ maxSpeechDurationMs: number;
37
+ overlapMs: number;
6
38
  }
7
39
  export type MediaPermissionKind = "microphone" | "camera";
8
40
  export type MediaPermissionState = "granted" | "denied" | "prompt" | "unsupported";
@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
2
2
  import { InvokeOptions, SSEMessage } from './api';
3
3
  import { CommsAccount, Session } from './communication';
4
4
  import { PlatformConfig, PlatformContext } from './kernel';
5
- import { AudioChunk, MediaPermissionKind, MediaPermissionState, MediaPermissionStatus } from './media';
5
+ import { AudioPipelineOptions, AudioSegment, MediaPermissionKind, MediaPermissionState, MediaPermissionStatus, TranscriptSegment } from './media';
6
6
  import { ServiceCallOptions, ServiceMap } from './services';
7
7
  import { DeepPartial, DeviceList, UserSettings } from './settings';
8
8
  import { ExtensionConfig, ToastConfig } from './ui';
@@ -55,13 +55,26 @@ export interface InternalSDK<LocalServices extends ServiceMap = {}, TranslationK
55
55
  setActiveSession(sessionId: string): Promise<void>;
56
56
  registerAccount(organizationId: string, userId: string, providerId: string, config: any): Promise<CommsAccount>;
57
57
  handleSessionAction(sessionId: string, actionId: string, ...args: any[]): Promise<void>;
58
+ transcripts: {
59
+ ingest(segments: TranscriptSegment[]): void;
60
+ byCallSession$(sessionId: string): Observable<TranscriptSegment[]>;
61
+ deltas$(sessionId: string): Observable<TranscriptSegment[]>;
62
+ partials$(sessionId: string): Observable<TranscriptSegment>;
63
+ persist(sessionId: string): Promise<void>;
64
+ clear(sessionId: string): void;
65
+ setPersister(fn: (sessionId: string, segments: TranscriptSegment[], opts: {
66
+ finalize: boolean;
67
+ }) => Promise<void>): void;
68
+ };
58
69
  };
59
70
  readonly media: {
60
71
  localStream$: Observable<MediaStream | null>;
61
- audioChunks$: Observable<AudioChunk>;
72
+ audioSegments$: Observable<AudioSegment>;
62
73
  devices$: Observable<DeviceList>;
63
74
  permissions$: Observable<MediaPermissionStatus>;
64
- emitAudioChunk(chunk: AudioChunk): void;
75
+ emitAudioSegment(segment: AudioSegment): void;
76
+ configureAudioPipeline(opts: Partial<AudioPipelineOptions>): void;
77
+ setAudioPipelineEnabled(enabled: boolean): void;
65
78
  setInputDevice(deviceId: string): Promise<void>;
66
79
  toggleMute(mute?: boolean): void;
67
80
  attachProviderStream(sessionId: string, stream: MediaStream): void;
@@ -20,6 +20,7 @@ export interface ToastConfig {
20
20
  onClick: () => void;
21
21
  }[];
22
22
  }
23
+ export type ExtensionContext = 'global' | 'call' | 'interaction';
23
24
  export interface ExtensionConfig {
24
25
  id: string;
25
26
  slot: string;
@@ -27,6 +28,7 @@ export interface ExtensionConfig {
27
28
  resource: string;
28
29
  icon?: string;
29
30
  priority?: number;
31
+ contexts?: ExtensionContext[];
30
32
  conditions?: {
31
33
  [key: string]: any;
32
34
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.18.1",
3
+ "version": "1.20.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",