@opencxh/domain 1.17.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
  }
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var t=(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))(t||{});function d(e){if(e.endpoints&&e.endpoints.length>0)return e.endpoints;const s=[];return e.phone&&s.push({scheme:t.TEL,resource:e.phone,primary:!0}),e.email&&s.push({scheme:t.MAILTO,resource:e.email,primary:!e.phone}),s}const p=e=>!!e.assignedUserId||!!e.assignedInboxId,a=e=>e.status==="closed",f=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,g=(e,s=30)=>e.title.length<=s?e.title:`${e.title.substring(0,s)}...`,c={[t.TEL]:["call"],[t.SIP]:["call"],[t.MAILTO]:["mail"],[t.SMS]:["message"],[t.WHATSAPP]:["message"],[t.TELEGRAM]:["message"],[t.VIBER]:["message"],[t.TEAMS]:["call","message","video"],[t.FAX]:["message"]},E=["call","mail","message","video"];function l(e,s){if(!e.supportedSchemes.includes(s))return[];const n=e.capabilities.filter(r=>r.scheme===s&&r.value===!0&&E.includes(r.key));return n.length>0?n.map(r=>r.key):c[s]??[]}function u(e){const s=new Set;for(const n of e.supportedSchemes)for(const r of l(e,n))s.add(r);return Array.from(s)}function T(e,s){return Object.entries(e).map(([n,r])=>({providerId:n,description:r,intents:u(r)}))}function A(e,s){return s.filter(n=>n.intents.includes(e))}function v(e,s){return s.filter(n=>n.description.supportedSchemes.includes(e.scheme))}function I(e,s,n){const r=[];for(const o of e)for(const i of n)i.description.supportedSchemes.includes(o.scheme)&&l(i.description,o.scheme).includes(s)&&r.push({capability:i,endpoint:o});return r}exports.CommunicationScheme=t;exports.buildResolvedCapabilities=T;exports.getContactEndpoints=d;exports.getShortTitle=g;exports.getUrgencyScore=f;exports.intentsForProvider=u;exports.intentsForScheme=l;exports.isAssigned=p;exports.isClosed=a;exports.resolveForContact=I;exports.resolveForEndpoint=v;exports.resolveForIntent=A;
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.js CHANGED
@@ -1,70 +1,125 @@
1
- var n = /* @__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))(n || {});
2
- function f(e) {
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
3
  if (e.endpoints && e.endpoints.length > 0)
4
4
  return e.endpoints;
5
5
  const s = [];
6
- return e.phone && s.push({ scheme: n.TEL, resource: e.phone, primary: !0 }), e.email && s.push({ scheme: n.MAILTO, resource: e.email, primary: !e.phone }), 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
7
  }
8
- const a = (e) => !!e.assignedUserId || !!e.assignedInboxId, g = (e) => e.status === "closed", E = (e) => ({
8
+ const T = (e) => !!e.assignedUserId || !!e.assignedInboxId, E = (e) => e.status === "closed", b = (e) => ({
9
9
  urgent: 10,
10
10
  high: 5,
11
11
  normal: 2,
12
12
  low: 1
13
- })[e.priority] || 0, T = (e, s = 30) => e.title.length <= s ? e.title : `${e.title.substring(0, s)}...`, u = {
14
- [n.TEL]: ["call"],
15
- [n.SIP]: ["call"],
16
- [n.MAILTO]: ["mail"],
17
- [n.SMS]: ["message"],
18
- [n.WHATSAPP]: ["message"],
19
- [n.TELEGRAM]: ["message"],
20
- [n.VIBER]: ["message"],
21
- [n.TEAMS]: ["call", "message", "video"],
22
- [n.FAX]: ["message"]
23
- }, d = ["call", "mail", "message", "video"];
24
- function i(e, s) {
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) {
25
30
  if (!e.supportedSchemes.includes(s)) return [];
26
- const t = e.capabilities.filter(
27
- (r) => r.scheme === s && r.value === !0 && d.includes(r.key)
31
+ const n = e.capabilities.filter(
32
+ (t) => t.scheme === s && t.value === !0 && p.includes(t.key)
28
33
  );
29
- return t.length > 0 ? t.map((r) => r.key) : u[s] ?? [];
34
+ return n.length > 0 ? n.map((t) => t.key) : d[s] ?? [];
30
35
  }
31
- function p(e) {
36
+ function f(e) {
32
37
  const s = /* @__PURE__ */ new Set();
33
- for (const t of e.supportedSchemes)
34
- for (const r of i(e, t)) s.add(r);
38
+ for (const n of e.supportedSchemes)
39
+ for (const t of a(e, n)) s.add(t);
35
40
  return Array.from(s);
36
41
  }
37
- function c(e, s) {
38
- return Object.entries(e).map(([t, r]) => ({
39
- providerId: t,
40
- description: r,
41
- intents: p(r)
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)
42
52
  }));
43
53
  }
44
- function A(e, s) {
45
- return s.filter((t) => t.intents.includes(e));
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;
46
88
  }
47
- function I(e, s) {
48
- return s.filter((t) => t.description.supportedSchemes.includes(e.scheme));
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;
49
101
  }
50
- function h(e, s, t) {
51
- const r = [];
52
- for (const l of e)
53
- for (const o of t)
54
- o.description.supportedSchemes.includes(l.scheme) && i(o.description, l.scheme).includes(s) && r.push({ capability: o, endpoint: l });
55
- return r;
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;
56
108
  }
57
109
  export {
58
- n as CommunicationScheme,
59
- c as buildResolvedCapabilities,
60
- f as getContactEndpoints,
61
- T as getShortTitle,
62
- E as getUrgencyScore,
63
- p as intentsForProvider,
64
- i as intentsForScheme,
65
- a as isAssigned,
66
- g as isClosed,
67
- h as resolveForContact,
68
- I as resolveForEndpoint,
69
- A as resolveForIntent
110
+ o as CommunicationScheme,
111
+ v as buildChannelCapabilities,
112
+ I as buildResolvedCapabilities,
113
+ h as dispatchForCapability,
114
+ g as getContactEndpoints,
115
+ A as getShortTitle,
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
70
125
  };
@@ -1,31 +1,60 @@
1
+ import { Channel } from '../entities/channel/types';
1
2
  import { ContactEndpoint } from '../entities/contact/types';
2
- import { CommsAccount, CommunicationScheme, ProviderDescription, Uri } from './communication';
3
+ import { CommsAccount, CommunicationDispatch, CommunicationScheme, ProviderDescription, Uri } from './communication';
3
4
  export type CommunicationIntent = "call" | "mail" | "message" | "video";
4
5
  export interface ResolvedCapability {
5
6
  providerId: string;
6
7
  description: ProviderDescription;
7
8
  intents: CommunicationIntent[];
8
9
  }
10
+ export interface ChannelCapability {
11
+ channel: Channel;
12
+ description: ProviderDescription;
13
+ scheme: CommunicationScheme;
14
+ intent: CommunicationIntent;
15
+ dispatch: CommunicationDispatch;
16
+ }
9
17
  export interface ResolvedCapabilityMatch {
10
18
  capability: ResolvedCapability;
11
19
  endpoint: ContactEndpoint;
12
20
  }
21
+ export interface ChannelCapabilityMatch {
22
+ capability: ChannelCapability;
23
+ endpoint: ContactEndpoint;
24
+ }
13
25
  /**
14
26
  * Returns which intents a provider offers for a given scheme.
15
- *
16
27
  * Capability rows whose `key` is a known user-intent (`call|mail|message|video`)
17
- * are treated as explicit declarations. Anything else (e.g. `call_forward`,
18
- * `call_hold` those are session-action feature flags) is ignored here.
19
- *
20
- * When a scheme has no explicit intent rows, the conventional default
21
- * mapping kicks in so providers can ship just `supportedSchemes`.
28
+ * are treated as explicit declarations; anything else is ignored. Empty
29
+ * declared list falls back to a conventional default per scheme.
22
30
  */
23
31
  export declare function intentsForScheme(description: ProviderDescription, scheme: CommunicationScheme): CommunicationIntent[];
32
+ export declare function intentsForProvider(description: ProviderDescription): CommunicationIntent[];
24
33
  /**
25
- * Unions intents across all schemes a provider supports.
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).
26
37
  */
27
- export declare function intentsForProvider(description: ProviderDescription): CommunicationIntent[];
38
+ export declare function dispatchForCapability(description: ProviderDescription, scheme: CommunicationScheme, intent: CommunicationIntent): CommunicationDispatch;
28
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[];
29
52
  export declare function resolveForIntent(intent: CommunicationIntent, capabilities: ResolvedCapability[]): ResolvedCapability[];
30
53
  export declare function resolveForEndpoint(uri: Uri, capabilities: ResolvedCapability[]): ResolvedCapability[];
31
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.17.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",