@opencxh/domain 1.38.0 → 1.40.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 +1,2 @@
1
1
  export * from './types';
2
+ export * from './signature';
@@ -0,0 +1,17 @@
1
+ import { CommunicationIntent } from '../../platform/capabilities';
2
+ import { Channel } from './types';
3
+ export interface ChannelSignature {
4
+ body: string;
5
+ enabled: boolean;
6
+ updatedAt?: number;
7
+ }
8
+ export type ChannelSignaturesMap = Partial<Record<CommunicationIntent | string, ChannelSignature>>;
9
+ /**
10
+ * Resolve the signature a provider should append for an outbound message
11
+ * on this channel + intent. Returns null when no signature is configured,
12
+ * disabled, or empty. Providers MUST call this in their send path for
13
+ * intents where signatures apply (e.g. "mail", "message") and merge the
14
+ * body before wire-send. The merged body is what gets persisted on the
15
+ * resulting activity/interaction.
16
+ */
17
+ export declare function resolveSignature(channel: Channel, intent: CommunicationIntent | string): ChannelSignature | null;
@@ -1,4 +1,9 @@
1
1
  import { IntentCapability, Uri } from '../../platform/communication';
2
+ import { ChannelSignaturesMap } from './signature';
3
+ export interface ChannelSettings {
4
+ signatures?: ChannelSignaturesMap;
5
+ [key: string]: unknown;
6
+ }
2
7
  export interface Channel {
3
8
  id: string;
4
9
  organizationId: string;
@@ -11,7 +16,7 @@ export interface Channel {
11
16
  inboxId?: string;
12
17
  ownerId: string;
13
18
  externalIds?: string[];
14
- settings: Record<string, any>;
19
+ settings: ChannelSettings;
15
20
  disabledIntents?: string[];
16
21
  intentOverrides?: Record<string, Partial<IntentCapability>>;
17
22
  extraIntents?: IntentCapability[];
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=140;function p(e){return e.replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\s+/g," ").trim()}function I(e){const t=e.trim();return t.length<=l?t:t.slice(0,l-1).trimEnd()+"…"}function E(e){if(!e||e<0)return"";const t=Math.floor(e/60),n=Math.floor(e%60);return`${t}:${n.toString().padStart(2,"0")}`}function i(e){switch(e.type){case"EMAIL_RECEIVED":case"EMAIL_SENT":{const t=e.payload,n=t.bodySnippet?.trim()||p(t.body??"");return t.subject?`${t.subject} — ${n}`:n}case"CHAT_MESSAGE_SENT":case"CHAT_MESSAGE_RECEIVED":return e.payload.text??"";case"CHAT_RENAMED":return`Hernoemd naar "${e.payload.newName}"`;case"CHAT_MEMBER_JOINED":return`${e.payload.members.map(t=>t.name).join(", ")} toegevoegd`;case"CHAT_MEMBER_LEFT":return`${e.payload.members.map(t=>t.name).join(", ")} verlaten`;case"CHAT_CALL_STARTED":return"Gesprek gestart";case"CHAT_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"CHAT_EVENT":return e.payload.text??e.payload.eventType;case"VOICE_CALL_STARTED":case"VIDEO_CALL_STARTED":return"Gesprek gestart";case"VOICE_CALL_ANSWERED":case"VIDEO_CALL_ANSWERED":return"Gesprek aangenomen";case"VOICE_CALL_HOLD":case"VIDEO_CALL_HOLD":return"In de wacht";case"VOICE_CALL_UNHOLD":case"VIDEO_CALL_UNHOLD":return"Hervat";case"VOICE_CALL_ENDED":case"VIDEO_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"VOICE_CALL_MISSED":case"VIDEO_CALL_MISSED":return"Gemiste oproep";case"VOICE_CALL_FAILED":case"VIDEO_CALL_FAILED":return"Gesprek mislukt";case"VOICE_CALL_VOICEMAIL":return e.payload.transcription?.trim()?e.payload.transcription:"Voicemail ontvangen";case"TRANSCRIPT_ADDED":return(e.payload.segments??[]).map(t=>t.text).join(" ");case"AI_MESSAGE_ADDED":return e.payload.output?.text??e.payload.input?.text??"";case"MEETING_SCHEDULED":return`Vergadering gepland: ${e.payload.title}`;case"MEETING_STARTED":return`Vergadering gestart: ${e.payload.title}`;case"MEETING_ENDED":return`Vergadering beëindigd${e.payload.duration?` (${E(e.payload.duration)})`:""}`;case"MEETING_PARTICIPANT_JOINED":return`${e.payload.name} deelgenomen`;case"MEETING_PARTICIPANT_LEFT":return`${e.payload.name} verlaten`;case"COMMENT_ADDED":return e.payload.text??"";case"FILE_UPLOADED":return`Bestand: ${e.payload.fileName}`;case"INTERACTION_CREATED":return"Interactie aangemaakt";case"INTERACTION_STATUS_CHANGED":return`Status: ${e.payload.fromStatus} → ${e.payload.toStatus}`;case"INTERACTION_ASSIGNED":return"Interactie toegewezen";default:return""}}function A(e){return{activityId:e.id,type:e.type,snippet:I(i(e)),authorName:e.author?.name??"",direction:e.direction,createdAt:e.createdAt??Date.now()}}function _(e){return e.endpoints??[]}const g=e=>!!e.assignedUserId||!!e.assignedInboxId,T=e=>e.status==="closed",D=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,f=(e,t=30)=>e.title?.length<=t?e.title:`${e.title.substring(0,t)}...`;function L(e,t){return e.lastActivityAt?!(e.seenBy??[]).includes(t):!1}function u(e,t){const n=new Set(e.disabledIntents??[]),a=e.intentOverrides??{},r=t.intents.filter(s=>!n.has(s.intent)).map(s=>C(s,a[s.intent]));if(!e.extraIntents||e.extraIntents.length===0)return r;const o=new Set(r.map(s=>s.intent));for(const s of e.extraIntents)o.has(s.intent)||(r.push(s),o.add(s.intent));return r}function C(e,t){return t?{intent:t.intent??e.intent,targetSchemes:t.targetSchemes??e.targetSchemes,transport:t.transport??e.transport}:e}function S(e,t){const n=[];for(const a of e){if(!a.enabled)continue;const r=t[a.providerId];if(r)for(const o of u(a,r))n.push({channel:a,description:r,capability:o})}return n}function N(e,t){return t.filter(n=>n.capability.intent===e)}function d(e,t){return t.filter(n=>n.capability.targetSchemes.includes(e))}function O(e,t){return d(e.scheme,t)}function M(e,t,n){const a=[];for(const r of e)for(const o of n)o.capability.intent===t&&o.capability.targetSchemes.includes(r.scheme)&&a.push({channelIntent:o,endpoint:r});return a}var c=(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.CALENDAR="calendar",e))(c||{});const b=(e,t)=>({intent:e,...t}),R={ok:!1,code:"UNSUPPORTED",message:"Provider does not support this op"};exports.CommunicationScheme=c;exports.UNSUPPORTED=R;exports.buildActivityPreview=A;exports.buildChannelIntents=S;exports.defineIntent=b;exports.filterByEndpoint=O;exports.filterByIntent=N;exports.filterByTargetScheme=d;exports.getContactEndpoints=_;exports.getShortTitle=f;exports.getUrgencyScore=D;exports.isAssigned=g;exports.isClosed=T;exports.isInteractionUnseen=L;exports.matchContactToIntents=M;exports.resolveChannelIntents=u;exports.stripHtml=p;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=140;function i(e){return e.replace(/<style[\s\S]*?<\/style>/gi," ").replace(/<script[\s\S]*?<\/script>/gi," ").replace(/<[^>]+>/g," ").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\s+/g," ").trim()}function I(e){const t=e.trim();return t.length<=u?t:t.slice(0,u-1).trimEnd()+"…"}function l(e){if(!e||e<0)return"";const t=Math.floor(e/60),n=Math.floor(e%60);return`${t}:${n.toString().padStart(2,"0")}`}function A(e){switch(e.type){case"EMAIL_RECEIVED":case"EMAIL_SENT":{const t=e.payload,n=t.bodySnippet?.trim()||i(t.body??"");return t.subject?`${t.subject} — ${n}`:n}case"CHAT_MESSAGE_SENT":case"CHAT_MESSAGE_RECEIVED":return e.payload.text??"";case"CHAT_RENAMED":return`Hernoemd naar "${e.payload.newName}"`;case"CHAT_MEMBER_JOINED":return`${e.payload.members.map(t=>t.name).join(", ")} toegevoegd`;case"CHAT_MEMBER_LEFT":return`${e.payload.members.map(t=>t.name).join(", ")} verlaten`;case"CHAT_CALL_STARTED":return"Gesprek gestart";case"CHAT_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${l(e.payload.duration)})`:""}`;case"CHAT_EVENT":return e.payload.text??e.payload.eventType;case"VOICE_CALL_STARTED":case"VIDEO_CALL_STARTED":return"Gesprek gestart";case"VOICE_CALL_ANSWERED":case"VIDEO_CALL_ANSWERED":return"Gesprek aangenomen";case"VOICE_CALL_HOLD":case"VIDEO_CALL_HOLD":return"In de wacht";case"VOICE_CALL_UNHOLD":case"VIDEO_CALL_UNHOLD":return"Hervat";case"VOICE_CALL_ENDED":case"VIDEO_CALL_ENDED":return`Gesprek beëindigd${e.payload.duration?` (${l(e.payload.duration)})`:""}`;case"VOICE_CALL_MISSED":case"VIDEO_CALL_MISSED":return"Gemiste oproep";case"VOICE_CALL_FAILED":case"VIDEO_CALL_FAILED":return"Gesprek mislukt";case"VOICE_CALL_VOICEMAIL":return e.payload.transcription?.trim()?e.payload.transcription:"Voicemail ontvangen";case"TRANSCRIPT_ADDED":return(e.payload.segments??[]).map(t=>t.text).join(" ");case"AI_MESSAGE_ADDED":return e.payload.output?.text??e.payload.input?.text??"";case"MEETING_SCHEDULED":return`Vergadering gepland: ${e.payload.title}`;case"MEETING_STARTED":return`Vergadering gestart: ${e.payload.title}`;case"MEETING_ENDED":return`Vergadering beëindigd${e.payload.duration?` (${l(e.payload.duration)})`:""}`;case"MEETING_PARTICIPANT_JOINED":return`${e.payload.name} deelgenomen`;case"MEETING_PARTICIPANT_LEFT":return`${e.payload.name} verlaten`;case"COMMENT_ADDED":return e.payload.text??"";case"FILE_UPLOADED":return`Bestand: ${e.payload.fileName}`;case"INTERACTION_CREATED":return"Interactie aangemaakt";case"INTERACTION_STATUS_CHANGED":return`Status: ${e.payload.fromStatus} → ${e.payload.toStatus}`;case"INTERACTION_ASSIGNED":return"Interactie toegewezen";default:return""}}function g(e){return{activityId:e.id,type:e.type,snippet:I(A(e)),authorName:e.author?.name??"",direction:e.direction,createdAt:e.createdAt??Date.now()}}function f(e,t){const n=e.settings?.signatures?.[t];return!n||!n.enabled||!n.body||n.body.trim()===""?null:n}function _(e){return e.endpoints??[]}const T=e=>!!e.assignedUserId||!!e.assignedInboxId,D=e=>e.status==="closed",L=e=>({urgent:10,high:5,normal:2,low:1})[e.priority]||0,C=(e,t=30)=>e.title?.length<=t?e.title:`${e.title.substring(0,t)}...`;function S(e,t){return e.lastActivityAt?!(e.seenBy??[]).includes(t):!1}function E(e,t){const n=new Set(e.disabledIntents??[]),r=e.intentOverrides??{},s=t.intents.filter(a=>!n.has(a.intent)).map(a=>b(a,r[a.intent]));if(!e.extraIntents||e.extraIntents.length===0)return s;const o=new Set(s.map(a=>a.intent));for(const a of e.extraIntents)o.has(a.intent)||(s.push(a),o.add(a.intent));return s}function d(e,t){const n={};for(const r of e.intents){if(!r.togglable)continue;const s=t?.[r.intent];n[r.intent]=s??r.defaultEnabled??!0}return n}function N(e,t){const n=d(e,t);return Object.entries(n).filter(([,r])=>!r).map(([r])=>r)}function b(e,t){return t?{intent:t.intent??e.intent,targetSchemes:t.targetSchemes??e.targetSchemes,transport:t.transport??e.transport}:e}function O(e,t){const n=[];for(const r of e){if(!r.enabled)continue;const s=t[r.providerId];if(s)for(const o of E(r,s))n.push({channel:r,description:s,capability:o})}return n}function M(e,t){return t.filter(n=>n.capability.intent===e)}function p(e,t){return t.filter(n=>n.capability.targetSchemes.includes(e))}function y(e,t){return p(e.scheme,t)}function R(e,t,n){const r=[];for(const s of e)for(const o of n)o.capability.intent===t&&o.capability.targetSchemes.includes(s.scheme)&&r.push({channelIntent:o,endpoint:s});return r}var c=(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.CALENDAR="calendar",e))(c||{});const V=(e,t)=>({intent:e,...t}),h={ok:!1,code:"UNSUPPORTED",message:"Provider does not support this op"};exports.CommunicationScheme=c;exports.UNSUPPORTED=h;exports.buildActivityPreview=g;exports.buildChannelIntents=O;exports.defineIntent=V;exports.disabledIntentsFromCapabilities=N;exports.filterByEndpoint=y;exports.filterByIntent=M;exports.filterByTargetScheme=p;exports.getContactEndpoints=_;exports.getShortTitle=C;exports.getUrgencyScore=L;exports.isAssigned=T;exports.isClosed=D;exports.isInteractionUnseen=S;exports.matchContactToIntents=R;exports.resolveAccountCapabilities=d;exports.resolveChannelIntents=E;exports.resolveSignature=f;exports.stripHtml=i;
package/dist/index.d.ts CHANGED
@@ -36,4 +36,5 @@ export * from './platform/services';
36
36
  export * from './platform/ui';
37
37
  export * from './platform/media';
38
38
  export * from './platform/provider';
39
+ export * from './platform/push';
39
40
  export * from './platform/storage';
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
- function p(e) {
1
+ function l(e) {
2
2
  return e.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\s+/g, " ").trim();
3
3
  }
4
- function u(e) {
4
+ function E(e) {
5
5
  const t = e.trim();
6
6
  return t.length <= 140 ? t : t.slice(0, 139).trimEnd() + "…";
7
7
  }
8
- function E(e) {
8
+ function u(e) {
9
9
  if (!e || e < 0) return "";
10
- const t = Math.floor(e / 60), r = Math.floor(e % 60);
11
- return `${t}:${r.toString().padStart(2, "0")}`;
10
+ const t = Math.floor(e / 60), n = Math.floor(e % 60);
11
+ return `${t}:${n.toString().padStart(2, "0")}`;
12
12
  }
13
- function l(e) {
13
+ function p(e) {
14
14
  switch (e.type) {
15
15
  case "EMAIL_RECEIVED":
16
16
  case "EMAIL_SENT": {
17
- const t = e.payload, r = t.bodySnippet?.trim() || p(t.body ?? "");
18
- return t.subject ? `${t.subject} — ${r}` : r;
17
+ const t = e.payload, n = t.bodySnippet?.trim() || l(t.body ?? "");
18
+ return t.subject ? `${t.subject} — ${n}` : n;
19
19
  }
20
20
  case "CHAT_MESSAGE_SENT":
21
21
  case "CHAT_MESSAGE_RECEIVED":
@@ -29,7 +29,7 @@ function l(e) {
29
29
  case "CHAT_CALL_STARTED":
30
30
  return "Gesprek gestart";
31
31
  case "CHAT_CALL_ENDED":
32
- return `Gesprek beëindigd${e.payload.duration ? ` (${E(e.payload.duration)})` : ""}`;
32
+ return `Gesprek beëindigd${e.payload.duration ? ` (${u(e.payload.duration)})` : ""}`;
33
33
  case "CHAT_EVENT":
34
34
  return e.payload.text ?? e.payload.eventType;
35
35
  case "VOICE_CALL_STARTED":
@@ -46,7 +46,7 @@ function l(e) {
46
46
  return "Hervat";
47
47
  case "VOICE_CALL_ENDED":
48
48
  case "VIDEO_CALL_ENDED":
49
- return `Gesprek beëindigd${e.payload.duration ? ` (${E(e.payload.duration)})` : ""}`;
49
+ return `Gesprek beëindigd${e.payload.duration ? ` (${u(e.payload.duration)})` : ""}`;
50
50
  case "VOICE_CALL_MISSED":
51
51
  case "VIDEO_CALL_MISSED":
52
52
  return "Gemiste oproep";
@@ -64,7 +64,7 @@ function l(e) {
64
64
  case "MEETING_STARTED":
65
65
  return `Vergadering gestart: ${e.payload.title}`;
66
66
  case "MEETING_ENDED":
67
- return `Vergadering beëindigd${e.payload.duration ? ` (${E(e.payload.duration)})` : ""}`;
67
+ return `Vergadering beëindigd${e.payload.duration ? ` (${u(e.payload.duration)})` : ""}`;
68
68
  case "MEETING_PARTICIPANT_JOINED":
69
69
  return `${e.payload.name} deelgenomen`;
70
70
  case "MEETING_PARTICIPANT_LEFT":
@@ -87,84 +87,104 @@ function _(e) {
87
87
  return {
88
88
  activityId: e.id,
89
89
  type: e.type,
90
- snippet: u(l(e)),
90
+ snippet: E(p(e)),
91
91
  authorName: e.author?.name ?? "",
92
92
  direction: e.direction,
93
93
  createdAt: e.createdAt ?? Date.now()
94
94
  };
95
95
  }
96
- function T(e) {
96
+ function f(e, t) {
97
+ const n = e.settings?.signatures?.[t];
98
+ return !n || !n.enabled || !n.body || n.body.trim() === "" ? null : n;
99
+ }
100
+ function g(e) {
97
101
  return e.endpoints ?? [];
98
102
  }
99
- const D = (e) => !!e.assignedUserId || !!e.assignedInboxId, g = (e) => e.status === "closed", i = (e) => ({
103
+ const T = (e) => !!e.assignedUserId || !!e.assignedInboxId, D = (e) => e.status === "closed", L = (e) => ({
100
104
  urgent: 10,
101
105
  high: 5,
102
106
  normal: 2,
103
107
  low: 1
104
- })[e.priority] || 0, L = (e, t = 30) => e.title?.length <= t ? e.title : `${e.title.substring(0, t)}...`;
105
- function f(e, t) {
108
+ })[e.priority] || 0, C = (e, t = 30) => e.title?.length <= t ? e.title : `${e.title.substring(0, t)}...`;
109
+ function N(e, t) {
106
110
  return e.lastActivityAt ? !(e.seenBy ?? []).includes(t) : !1;
107
111
  }
108
112
  function d(e, t) {
109
- const r = new Set(e.disabledIntents ?? []), a = e.intentOverrides ?? {}, n = t.intents.filter((s) => !r.has(s.intent)).map((s) => A(s, a[s.intent]));
110
- if (!e.extraIntents || e.extraIntents.length === 0) return n;
111
- const o = new Set(n.map((s) => s.intent));
112
- for (const s of e.extraIntents)
113
- o.has(s.intent) || (n.push(s), o.add(s.intent));
113
+ const n = new Set(e.disabledIntents ?? []), r = e.intentOverrides ?? {}, s = t.intents.filter((a) => !n.has(a.intent)).map((a) => i(a, r[a.intent]));
114
+ if (!e.extraIntents || e.extraIntents.length === 0) return s;
115
+ const o = new Set(s.map((a) => a.intent));
116
+ for (const a of e.extraIntents)
117
+ o.has(a.intent) || (s.push(a), o.add(a.intent));
118
+ return s;
119
+ }
120
+ function c(e, t) {
121
+ const n = {};
122
+ for (const r of e.intents) {
123
+ if (!r.togglable) continue;
124
+ const s = t?.[r.intent];
125
+ n[r.intent] = s ?? r.defaultEnabled ?? !0;
126
+ }
114
127
  return n;
115
128
  }
116
- function A(e, t) {
129
+ function S(e, t) {
130
+ const n = c(e, t);
131
+ return Object.entries(n).filter(([, r]) => !r).map(([r]) => r);
132
+ }
133
+ function i(e, t) {
117
134
  return t ? {
118
135
  intent: t.intent ?? e.intent,
119
136
  targetSchemes: t.targetSchemes ?? e.targetSchemes,
120
137
  transport: t.transport ?? e.transport
121
138
  } : e;
122
139
  }
123
- function N(e, t) {
124
- const r = [];
125
- for (const a of e) {
126
- if (!a.enabled) continue;
127
- const n = t[a.providerId];
128
- if (n)
129
- for (const o of d(a, n))
130
- r.push({ channel: a, description: n, capability: o });
140
+ function O(e, t) {
141
+ const n = [];
142
+ for (const r of e) {
143
+ if (!r.enabled) continue;
144
+ const s = t[r.providerId];
145
+ if (s)
146
+ for (const o of d(r, s))
147
+ n.push({ channel: r, description: s, capability: o });
131
148
  }
132
- return r;
149
+ return n;
133
150
  }
134
- function S(e, t) {
135
- return t.filter((r) => r.capability.intent === e);
151
+ function b(e, t) {
152
+ return t.filter((n) => n.capability.intent === e);
136
153
  }
137
- function I(e, t) {
138
- return t.filter((r) => r.capability.targetSchemes.includes(e));
154
+ function A(e, t) {
155
+ return t.filter((n) => n.capability.targetSchemes.includes(e));
139
156
  }
140
- function C(e, t) {
141
- return I(e.scheme, t);
157
+ function M(e, t) {
158
+ return A(e.scheme, t);
142
159
  }
143
- function O(e, t, r) {
144
- const a = [];
145
- for (const n of e)
146
- for (const o of r)
147
- o.capability.intent === t && o.capability.targetSchemes.includes(n.scheme) && a.push({ channelIntent: o, endpoint: n });
148
- return a;
160
+ function R(e, t, n) {
161
+ const r = [];
162
+ for (const s of e)
163
+ for (const o of n)
164
+ o.capability.intent === t && o.capability.targetSchemes.includes(s.scheme) && r.push({ channelIntent: o, endpoint: s });
165
+ return r;
149
166
  }
150
- var c = /* @__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.CALENDAR = "calendar", e))(c || {});
151
- const M = (e, t) => ({ intent: e, ...t }), R = { ok: !1, code: "UNSUPPORTED", message: "Provider does not support this op" };
167
+ var I = /* @__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.CALENDAR = "calendar", e))(I || {});
168
+ const V = (e, t) => ({ intent: e, ...t }), P = { ok: !1, code: "UNSUPPORTED", message: "Provider does not support this op" };
152
169
  export {
153
- c as CommunicationScheme,
154
- R as UNSUPPORTED,
170
+ I as CommunicationScheme,
171
+ P as UNSUPPORTED,
155
172
  _ as buildActivityPreview,
156
- N as buildChannelIntents,
157
- M as defineIntent,
158
- C as filterByEndpoint,
159
- S as filterByIntent,
160
- I as filterByTargetScheme,
161
- T as getContactEndpoints,
162
- L as getShortTitle,
163
- i as getUrgencyScore,
164
- D as isAssigned,
165
- g as isClosed,
166
- f as isInteractionUnseen,
167
- O as matchContactToIntents,
173
+ O as buildChannelIntents,
174
+ V as defineIntent,
175
+ S as disabledIntentsFromCapabilities,
176
+ M as filterByEndpoint,
177
+ b as filterByIntent,
178
+ A as filterByTargetScheme,
179
+ g as getContactEndpoints,
180
+ C as getShortTitle,
181
+ L as getUrgencyScore,
182
+ T as isAssigned,
183
+ D as isClosed,
184
+ N as isInteractionUnseen,
185
+ R as matchContactToIntents,
186
+ c as resolveAccountCapabilities,
168
187
  d as resolveChannelIntents,
169
- p as stripHtml
188
+ f as resolveSignature,
189
+ l as stripHtml
170
190
  };
@@ -33,6 +33,18 @@ export interface ChannelIntentMatch {
33
33
  * source of truth, channel patches it.
34
34
  */
35
35
  export declare function resolveChannelIntents(channel: Channel, description: ProviderDescription): IntentCapability[];
36
+ /**
37
+ * Resolve per-account capability-state vanuit provider description + user-keuze.
38
+ * Alleen `togglable` intents worden teruggegeven. Onbekende keys in `accountCaps`
39
+ * worden genegeerd — provider is source of truth.
40
+ */
41
+ export declare function resolveAccountCapabilities(description: ProviderDescription, accountCaps: Record<string, boolean> | undefined): Record<string, boolean>;
42
+ /**
43
+ * Lijst van intent-namen die UIT staan voor dit account. Mapt 1-op-1 naar
44
+ * `Channel.disabledIntents`. Niet-togglable intents komen nooit op de lijst —
45
+ * die kan provider hardcode'n via eigen channel-kind constraint.
46
+ */
47
+ export declare function disabledIntentsFromCapabilities(description: ProviderDescription, accountCaps: Record<string, boolean> | undefined): string[];
36
48
  /**
37
49
  * Builds the full set of (channel × intent) entries across all channels —
38
50
  * the source for the starter palette.
@@ -116,6 +116,12 @@ export interface IntentCapability {
116
116
  intent: string;
117
117
  targetSchemes: CommunicationScheme[];
118
118
  transport: TransportConfig;
119
+ /** User mag deze intent aan/uit zetten per account. Default false (provider-locked). */
120
+ togglable?: boolean;
121
+ /** Default-state als togglable=true en user nog geen keuze maakte. Default true. */
122
+ defaultEnabled?: boolean;
123
+ /** Optionele i18n-key voor toggle-label; UI valt anders terug op `cap_${intent}`. */
124
+ labelKey?: string;
119
125
  }
120
126
  /**
121
127
  * Provider-level feature flag (no routing relevance). Used for things
@@ -0,0 +1,57 @@
1
+ export type PushTransport = "webpush" | "apns" | "apns-voip" | "fcm" | "tauri";
2
+ export type PushPlatform = "web" | "ios" | "android" | "desktop";
3
+ export interface PushSubscription {
4
+ id: string;
5
+ userId: string;
6
+ transport: PushTransport;
7
+ token: string;
8
+ keys?: {
9
+ p256dh: string;
10
+ auth: string;
11
+ };
12
+ platform: PushPlatform;
13
+ appVersion: string;
14
+ providerId?: string;
15
+ createdAt: number;
16
+ lastSeenAt: number;
17
+ }
18
+ export type PushKind = "wake" | "incoming-call" | "message" | "presence" | "notification" | "custom";
19
+ export interface PushDisplay {
20
+ title: string;
21
+ body?: string;
22
+ icon?: string;
23
+ tag?: string;
24
+ actions?: {
25
+ id: string;
26
+ title: string;
27
+ }[];
28
+ url?: string;
29
+ }
30
+ export interface PushEnvelope<P = unknown> {
31
+ providerId: string;
32
+ accountId?: string;
33
+ kind: PushKind;
34
+ display?: PushDisplay;
35
+ payload: P;
36
+ ts: number;
37
+ ttl?: number;
38
+ voip?: boolean;
39
+ }
40
+ export type PushSubscribeInput = Omit<PushSubscription, "id" | "userId" | "createdAt" | "lastSeenAt">;
41
+ export interface PushSendRequest<P = unknown> {
42
+ to: {
43
+ userIds: string[];
44
+ } | {
45
+ userId: string;
46
+ };
47
+ envelope: Omit<PushEnvelope<P>, "ts">;
48
+ platforms?: PushPlatform[];
49
+ collapseKey?: string;
50
+ }
51
+ export interface PushSendResult {
52
+ delivered: number;
53
+ }
54
+ export interface IPushChannel {
55
+ readonly providerId: string;
56
+ handle(env: PushEnvelope): Promise<void>;
57
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.38.0",
3
+ "version": "1.40.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",