@opencxh/domain 1.16.0 → 1.18.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,4 +1,4 @@
1
- import { Uri } from '../../platform/communication';
1
+ import { Capability, Uri } from '../../platform/communication';
2
2
  export interface Channel {
3
3
  id: string;
4
4
  organizationId: string;
@@ -12,6 +12,7 @@ export interface Channel {
12
12
  ownerId: string;
13
13
  externalIds?: string[];
14
14
  settings: Record<string, any>;
15
+ capabilities?: Capability[];
15
16
  enabled: boolean;
16
17
  verified: boolean;
17
18
  }
@@ -0,0 +1,6 @@
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
+ export declare function getContactEndpoints(contact: Contact): ContactEndpoint[];
@@ -1 +1,2 @@
1
1
  export * from './types';
2
+ export * from './endpoints';
@@ -1,3 +1,10 @@
1
+ import { CommunicationScheme } from '../../platform/communication';
2
+ export interface ContactEndpoint {
3
+ scheme: CommunicationScheme;
4
+ resource: string;
5
+ label?: string;
6
+ primary?: boolean;
7
+ }
1
8
  /**
2
9
  * Data model for a single Contact.
3
10
  */
@@ -10,4 +17,5 @@ export interface Contact {
10
17
  email?: string;
11
18
  phone?: string;
12
19
  address?: string;
20
+ endpoints?: ContactEndpoint[];
13
21
  }
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=s=>!!s.assignedUserId||!!s.assignedInboxId,l=s=>s.status==="closed",g=s=>({urgent:10,high:5,normal:2,low:1})[s.priority]||0,d=(s,r=30)=>s.title.length<=r?s.title:`${s.title.substring(0,r)}...`;var t=(s=>(s.MAILTO="mailto",s.SIP="sip",s.TEL="tel",s.WEBHOOK="webhook",s.USERNAME="username",s.ID="id",s.CUSTOM="custom",s.URL="url",s.TELEGRAM="telegram",s.WHATSAPP="whatsapp",s.VIBER="viber",s.SMS="sms",s.FAX="fax",s.TEAMS="teams",s))(t||{});exports.CommunicationScheme=t;exports.getShortTitle=d;exports.getUrgencyScore=g;exports.isAssigned=e;exports.isClosed=l;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var o=(e=>(e.MAILTO="mailto",e.SIP="sip",e.TEL="tel",e.WEBHOOK="webhook",e.USERNAME="username",e.ID="id",e.CUSTOM="custom",e.URL="url",e.TELEGRAM="telegram",e.WHATSAPP="whatsapp",e.VIBER="viber",e.SMS="sms",e.FAX="fax",e.TEAMS="teams",e))(o||{});function h(e){if(e.endpoints&&e.endpoints.length>0)return e.endpoints;const s=[];return e.phone&&s.push({scheme:o.TEL,resource:e.phone,primary:!0}),e.email&&s.push({scheme:o.MAILTO,resource:e.email,primary:!e.phone}),s}const g=e=>!!e.assignedUserId||!!e.assignedInboxId,b=e=>e.status==="closed",T=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,v=(e,s=30)=>e.title.length<=s?e.title:`${e.title.substring(0,s)}...`,E={[o.TEL]:["call"],[o.SIP]:["call"],[o.MAILTO]:["mail"],[o.SMS]:["message"],[o.WHATSAPP]:["message"],[o.TELEGRAM]:["message"],[o.VIBER]:["message"],[o.TEAMS]:["call","message","video"],[o.FAX]:["message"]},p={call:"transport",video:"transport",message:"transport",mail:"compose"},u=["call","mail","message","video"];function a(e,s){if(!e.supportedSchemes.includes(s))return[];const n=e.capabilities.filter(t=>t.scheme===s&&t.value===!0&&u.includes(t.key));return n.length>0?n.map(t=>t.key):E[s]??[]}function d(e){const s=new Set;for(const n of e.supportedSchemes)for(const t of a(e,n))s.add(t);return Array.from(s)}function f(e,s,n){return e.capabilities.find(r=>r.scheme===s&&r.key===n&&r.value===!0)?.dispatch??p[n]}function A(e,s){return Object.entries(e).map(([n,t])=>({providerId:n,description:t,intents:d(t)}))}function y(e,s){const n=[];for(const t of e){if(!t.enabled)continue;const r=s[t.providerId];if(r){if(t.capabilities&&t.capabilities.length>0){for(const i of t.capabilities){if(!i.value||!u.includes(i.key))continue;const c=i.scheme,l=i.key;n.push({channel:t,description:r,scheme:c,intent:l,dispatch:i.dispatch??p[l]})}continue}for(const i of r.supportedSchemes){const c=a(r,i);for(const l of c)n.push({channel:t,description:r,scheme:i,intent:l,dispatch:f(r,i,l)})}}}return n}function I(e,s){return s.filter(n=>n.intents.includes(e))}function S(e,s){return s.filter(n=>n.description.supportedSchemes.includes(e.scheme))}function F(e,s,n){const t=[];for(const r of e)for(const i of n)i.description.supportedSchemes.includes(r.scheme)&&a(i.description,r.scheme).includes(s)&&t.push({capability:i,endpoint:r});return t}function M(e,s,n){const t=[];for(const r of e)for(const i of n)i.scheme===r.scheme&&i.intent===s&&t.push({capability:i,endpoint:r});return t}exports.CommunicationScheme=o;exports.buildChannelCapabilities=y;exports.buildResolvedCapabilities=A;exports.dispatchForCapability=f;exports.getContactEndpoints=h;exports.getShortTitle=v;exports.getUrgencyScore=T;exports.intentsForProvider=d;exports.intentsForScheme=a;exports.isAssigned=g;exports.isClosed=b;exports.resolveContactChannelCapabilities=M;exports.resolveForContact=F;exports.resolveForEndpoint=S;exports.resolveForIntent=I;
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export * from './entities/transcript';
17
17
  export * from './entities/user';
18
18
  export * from './platform/api';
19
19
  export * from './platform/common';
20
+ export * from './platform/capabilities';
20
21
  export * from './platform/communication';
21
22
  export * from './platform/federated';
22
23
  export * from './platform/intents';
package/dist/index.js CHANGED
@@ -1,14 +1,125 @@
1
- const l = (s) => !!s.assignedUserId || !!s.assignedInboxId, g = (s) => s.status === "closed", d = (s) => ({
1
+ var o = /* @__PURE__ */ ((e) => (e.MAILTO = "mailto", e.SIP = "sip", e.TEL = "tel", e.WEBHOOK = "webhook", e.USERNAME = "username", e.ID = "id", e.CUSTOM = "custom", e.URL = "url", e.TELEGRAM = "telegram", e.WHATSAPP = "whatsapp", e.VIBER = "viber", e.SMS = "sms", e.FAX = "fax", e.TEAMS = "teams", e))(o || {});
2
+ function g(e) {
3
+ if (e.endpoints && e.endpoints.length > 0)
4
+ return e.endpoints;
5
+ const s = [];
6
+ return e.phone && s.push({ scheme: o.TEL, resource: e.phone, primary: !0 }), e.email && s.push({ scheme: o.MAILTO, resource: e.email, primary: !e.phone }), s;
7
+ }
8
+ const T = (e) => !!e.assignedUserId || !!e.assignedInboxId, E = (e) => e.status === "closed", b = (e) => ({
2
9
  urgent: 10,
3
10
  high: 5,
4
11
  normal: 2,
5
12
  low: 1
6
- })[s.priority] || 0, A = (s, r = 30) => s.title.length <= r ? s.title : `${s.title.substring(0, r)}...`;
7
- var t = /* @__PURE__ */ ((s) => (s.MAILTO = "mailto", s.SIP = "sip", s.TEL = "tel", s.WEBHOOK = "webhook", s.USERNAME = "username", s.ID = "id", s.CUSTOM = "custom", s.URL = "url", s.TELEGRAM = "telegram", s.WHATSAPP = "whatsapp", s.VIBER = "viber", s.SMS = "sms", s.FAX = "fax", s.TEAMS = "teams", s))(t || {});
13
+ })[e.priority] || 0, A = (e, s = 30) => e.title.length <= s ? e.title : `${e.title.substring(0, s)}...`, d = {
14
+ [o.TEL]: ["call"],
15
+ [o.SIP]: ["call"],
16
+ [o.MAILTO]: ["mail"],
17
+ [o.SMS]: ["message"],
18
+ [o.WHATSAPP]: ["message"],
19
+ [o.TELEGRAM]: ["message"],
20
+ [o.VIBER]: ["message"],
21
+ [o.TEAMS]: ["call", "message", "video"],
22
+ [o.FAX]: ["message"]
23
+ }, u = {
24
+ call: "transport",
25
+ video: "transport",
26
+ message: "transport",
27
+ mail: "compose"
28
+ }, p = ["call", "mail", "message", "video"];
29
+ function a(e, s) {
30
+ if (!e.supportedSchemes.includes(s)) return [];
31
+ const n = e.capabilities.filter(
32
+ (t) => t.scheme === s && t.value === !0 && p.includes(t.key)
33
+ );
34
+ return n.length > 0 ? n.map((t) => t.key) : d[s] ?? [];
35
+ }
36
+ function f(e) {
37
+ const s = /* @__PURE__ */ new Set();
38
+ for (const n of e.supportedSchemes)
39
+ for (const t of a(e, n)) s.add(t);
40
+ return Array.from(s);
41
+ }
42
+ function h(e, s, n) {
43
+ return e.capabilities.find(
44
+ (r) => r.scheme === s && r.key === n && r.value === !0
45
+ )?.dispatch ?? u[n];
46
+ }
47
+ function I(e, s) {
48
+ return Object.entries(e).map(([n, t]) => ({
49
+ providerId: n,
50
+ description: t,
51
+ intents: f(t)
52
+ }));
53
+ }
54
+ function v(e, s) {
55
+ const n = [];
56
+ for (const t of e) {
57
+ if (!t.enabled) continue;
58
+ const r = s[t.providerId];
59
+ if (r) {
60
+ if (t.capabilities && t.capabilities.length > 0) {
61
+ for (const i of t.capabilities) {
62
+ if (!i.value || !p.includes(i.key)) continue;
63
+ const c = i.scheme, l = i.key;
64
+ n.push({
65
+ channel: t,
66
+ description: r,
67
+ scheme: c,
68
+ intent: l,
69
+ dispatch: i.dispatch ?? u[l]
70
+ });
71
+ }
72
+ continue;
73
+ }
74
+ for (const i of r.supportedSchemes) {
75
+ const c = a(r, i);
76
+ for (const l of c)
77
+ n.push({
78
+ channel: t,
79
+ description: r,
80
+ scheme: i,
81
+ intent: l,
82
+ dispatch: h(r, i, l)
83
+ });
84
+ }
85
+ }
86
+ }
87
+ return n;
88
+ }
89
+ function y(e, s) {
90
+ return s.filter((n) => n.intents.includes(e));
91
+ }
92
+ function M(e, s) {
93
+ return s.filter((n) => n.description.supportedSchemes.includes(e.scheme));
94
+ }
95
+ function S(e, s, n) {
96
+ const t = [];
97
+ for (const r of e)
98
+ for (const i of n)
99
+ i.description.supportedSchemes.includes(r.scheme) && a(i.description, r.scheme).includes(s) && t.push({ capability: i, endpoint: r });
100
+ return t;
101
+ }
102
+ function F(e, s, n) {
103
+ const t = [];
104
+ for (const r of e)
105
+ for (const i of n)
106
+ i.scheme === r.scheme && i.intent === s && t.push({ capability: i, endpoint: r });
107
+ return t;
108
+ }
8
109
  export {
9
- t as CommunicationScheme,
110
+ o as CommunicationScheme,
111
+ v as buildChannelCapabilities,
112
+ I as buildResolvedCapabilities,
113
+ h as dispatchForCapability,
114
+ g as getContactEndpoints,
10
115
  A as getShortTitle,
11
- d as getUrgencyScore,
12
- l as isAssigned,
13
- g as isClosed
116
+ b as getUrgencyScore,
117
+ f as intentsForProvider,
118
+ a as intentsForScheme,
119
+ T as isAssigned,
120
+ E as isClosed,
121
+ F as resolveContactChannelCapabilities,
122
+ S as resolveForContact,
123
+ M as resolveForEndpoint,
124
+ y as resolveForIntent
14
125
  };
@@ -0,0 +1,60 @@
1
+ import { Channel } from '../entities/channel/types';
2
+ import { ContactEndpoint } from '../entities/contact/types';
3
+ import { CommsAccount, CommunicationDispatch, CommunicationScheme, ProviderDescription, Uri } from './communication';
4
+ export type CommunicationIntent = "call" | "mail" | "message" | "video";
5
+ export interface ResolvedCapability {
6
+ providerId: string;
7
+ description: ProviderDescription;
8
+ intents: CommunicationIntent[];
9
+ }
10
+ export interface ChannelCapability {
11
+ channel: Channel;
12
+ description: ProviderDescription;
13
+ scheme: CommunicationScheme;
14
+ intent: CommunicationIntent;
15
+ dispatch: CommunicationDispatch;
16
+ }
17
+ export interface ResolvedCapabilityMatch {
18
+ capability: ResolvedCapability;
19
+ endpoint: ContactEndpoint;
20
+ }
21
+ export interface ChannelCapabilityMatch {
22
+ capability: ChannelCapability;
23
+ endpoint: ContactEndpoint;
24
+ }
25
+ /**
26
+ * Returns which intents a provider offers for a given scheme.
27
+ * Capability rows whose `key` is a known user-intent (`call|mail|message|video`)
28
+ * are treated as explicit declarations; anything else is ignored. Empty
29
+ * declared list falls back to a conventional default per scheme.
30
+ */
31
+ export declare function intentsForScheme(description: ProviderDescription, scheme: CommunicationScheme): CommunicationIntent[];
32
+ export declare function intentsForProvider(description: ProviderDescription): CommunicationIntent[];
33
+ /**
34
+ * Returns how a given (scheme, intent) on this provider should be dispatched.
35
+ * Honours an explicit `dispatch` on the capability row; otherwise falls back
36
+ * to the intent default (mail=compose, rest=transport).
37
+ */
38
+ export declare function dispatchForCapability(description: ProviderDescription, scheme: CommunicationScheme, intent: CommunicationIntent): CommunicationDispatch;
39
+ export declare function buildResolvedCapabilities(descriptions: Record<string, ProviderDescription>, _accounts?: CommsAccount[]): ResolvedCapability[];
40
+ /**
41
+ * Builds (channel × scheme × intent) capabilities.
42
+ *
43
+ * Precedence:
44
+ * 1. `channel.capabilities` when present — the precise truth for *this*
45
+ * specific channel (e.g. one Microsoft account exposes only Teams,
46
+ * another only mailto). Each capability row maps directly to one
47
+ * ChannelCapability.
48
+ * 2. Fallback: provider-level `description.capabilities` × `supportedSchemes`
49
+ * — coarse default for backends that don't yet declare per-channel.
50
+ */
51
+ export declare function buildChannelCapabilities(channels: Channel[], descriptions: Record<string, ProviderDescription>): ChannelCapability[];
52
+ export declare function resolveForIntent(intent: CommunicationIntent, capabilities: ResolvedCapability[]): ResolvedCapability[];
53
+ export declare function resolveForEndpoint(uri: Uri, capabilities: ResolvedCapability[]): ResolvedCapability[];
54
+ export declare function resolveForContact(endpoints: ContactEndpoint[], intent: CommunicationIntent, capabilities: ResolvedCapability[]): ResolvedCapabilityMatch[];
55
+ /**
56
+ * Channel-aware variant: matches contact endpoints against (channel × intent)
57
+ * capabilities. Each match identifies *exactly* which channel will send and
58
+ * how. Drives both contact-detail buttons and contact-named palette rows.
59
+ */
60
+ export declare function resolveContactChannelCapabilities(endpoints: ContactEndpoint[], intent: CommunicationIntent, capabilities: ChannelCapability[]): ChannelCapabilityMatch[];
@@ -40,10 +40,18 @@ export interface ITransportProvider {
40
40
  setOutgoingStream(sessionId: string, stream: MediaStream | null): Promise<void>;
41
41
  handleAction(sessionId: string, actionId: string, ...args: any[]): void;
42
42
  }
43
+ export type CommunicationDispatch = "transport" | "compose";
43
44
  export interface Capability {
44
45
  scheme: string;
45
46
  key: string;
46
47
  value: boolean;
48
+ /**
49
+ * How this (scheme,intent) is delivered. `transport` goes through
50
+ * ITransportProvider.createSession (live SIP/Teams call). `compose`
51
+ * goes through the server-side compose endpoint with a channelId
52
+ * (mail, async messaging). Defaults to intent: mail=compose, rest=transport.
53
+ */
54
+ dispatch?: CommunicationDispatch;
47
55
  }
48
56
  export declare enum CommunicationScheme {
49
57
  MAILTO = "mailto",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",