@opencxh/domain 1.23.2 → 1.28.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.
@@ -0,0 +1 @@
1
+ export * from './types';
@@ -0,0 +1,55 @@
1
+ import { OwnerScope } from '../contact/types';
2
+ export type CalendarEventStatus = "confirmed" | "cancelled" | "tentative";
3
+ export type AttendeeResponse = "accepted" | "declined" | "tentative" | "none";
4
+ export interface EventAttendee {
5
+ email: string;
6
+ name?: string;
7
+ response?: AttendeeResponse;
8
+ optional?: boolean;
9
+ }
10
+ export interface EventConferencing {
11
+ provider: "teams" | "meet" | "zoom" | "other";
12
+ joinUrl: string;
13
+ conferenceId?: string;
14
+ passcode?: string;
15
+ }
16
+ export type RecurrenceFrequency = "daily" | "weekly" | "monthly" | "yearly";
17
+ /**
18
+ * RFC5545-subset. MVP: read-only — provider supplies, we display.
19
+ */
20
+ export interface RecurrenceRule {
21
+ frequency: RecurrenceFrequency;
22
+ interval?: number;
23
+ count?: number;
24
+ until?: number;
25
+ byWeekday?: ("MO" | "TU" | "WE" | "TH" | "FR" | "SA" | "SU")[];
26
+ }
27
+ export interface EventReminder {
28
+ minutesBefore: number;
29
+ }
30
+ export interface CalendarEvent {
31
+ id: string;
32
+ organizationId: string;
33
+ ownerScope: OwnerScope;
34
+ title: string;
35
+ description?: string;
36
+ location?: string;
37
+ startTime: number;
38
+ endTime: number;
39
+ allDay?: boolean;
40
+ timezone?: string;
41
+ organizer?: EventAttendee;
42
+ attendees?: EventAttendee[];
43
+ /** Link to a communication Interaction (e.g. Teams meeting chat). */
44
+ interactionId?: string;
45
+ /** Channel used for external sync (provider-resolved). */
46
+ channelId?: string;
47
+ /** Provider-side IDs for dedupe (e.g. Graph event id, iCalUId). */
48
+ externalIds?: string[];
49
+ status: CalendarEventStatus;
50
+ recurrence?: RecurrenceRule;
51
+ reminders?: EventReminder[];
52
+ conferencing?: EventConferencing;
53
+ createdAt?: number;
54
+ updatedAt?: number;
55
+ }
@@ -60,3 +60,48 @@ export interface Transcription {
60
60
  export interface SessionMetadata {
61
61
  [custom: string]: unknown;
62
62
  }
63
+ export type AuthState = {
64
+ type: "oauth2";
65
+ accessToken: string;
66
+ refreshToken?: string;
67
+ /** Epoch ms */
68
+ expiresAt: number;
69
+ scopes: string[];
70
+ idToken?: string;
71
+ } | {
72
+ type: "password";
73
+ username: string;
74
+ /** Reference into secret-store; never the raw password. */
75
+ passwordRef: string;
76
+ } | {
77
+ type: "certificate";
78
+ certRef: string;
79
+ } | {
80
+ type: "static";
81
+ };
82
+ export type ManagedAccountStatus = "connected" | "disconnected" | "error" | "expired";
83
+ export interface ManagedAccount {
84
+ id: string;
85
+ organizationId: string;
86
+ /** null = org-level account (geen specifieke user). */
87
+ userId?: string;
88
+ providerId: string;
89
+ /** "oauth2" | "imap" | "sip" | "webhook" | provider-eigen string */
90
+ protocol: string;
91
+ displayName: string;
92
+ status: ManagedAccountStatus;
93
+ auth: AuthState;
94
+ /** Provider-specifieke metadata (tenantId, externalUserId, scope-flags). */
95
+ metadata: Record<string, unknown>;
96
+ createdAt?: number;
97
+ updatedAt?: number;
98
+ }
99
+ /**
100
+ * Public-view zonder tokens — wat `account/list` en `account/get` aan
101
+ * UI/comm-server retourneren. `auth` is gestripped tot alleen het type.
102
+ */
103
+ export type ManagedAccountPublic = Omit<ManagedAccount, "auth"> & {
104
+ authType: AuthState["type"];
105
+ scopes?: string[];
106
+ expiresAt?: number;
107
+ };
package/dist/index.cjs CHANGED
@@ -1 +1 @@
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;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function d(t){return t.endpoints??[]}const c=t=>!!t.assignedUserId||!!t.assignedInboxId,u=t=>t.status==="closed",p=t=>({urgent:10,high:5,normal:2,low:1})[t.priority]||0,g=(t,e=30)=>t.title?.length<=e?t.title:`${t.title.substring(0,e)}...`;function l(t,e){const s=new Set(t.disabledIntents??[]),i=t.intentOverrides??{},n=e.intents.filter(r=>!s.has(r.intent)).map(r=>I(r,i[r.intent]));if(!t.extraIntents||t.extraIntents.length===0)return n;const o=new Set(n.map(r=>r.intent));for(const r of t.extraIntents)o.has(r.intent)||(n.push(r),o.add(r.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 y(t,e){const s=[];for(const i of t){if(!i.enabled)continue;const n=e[i.providerId];if(n)for(const o of l(i,n))s.push({channel:i,description:n,capability:o})}return s}function E(t,e){return e.filter(s=>s.capability.intent===t)}function a(t,e){return e.filter(s=>s.capability.targetSchemes.includes(t))}function T(t,e){return a(t.scheme,e)}function b(t,e,s){const i=[];for(const n of t)for(const o of s)o.capability.intent===e&&o.capability.targetSchemes.includes(n.scheme)&&i.push({channelIntent:o,endpoint:n});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.CALENDAR="calendar",t))(f||{});const h=(t,e)=>({intent:t,...e}),S={ok:!1,code:"UNSUPPORTED",message:"Provider does not support this op"};exports.CommunicationScheme=f;exports.UNSUPPORTED=S;exports.buildChannelIntents=y;exports.defineIntent=h;exports.filterByEndpoint=T;exports.filterByIntent=E;exports.filterByTargetScheme=a;exports.getContactEndpoints=d;exports.getShortTitle=g;exports.getUrgencyScore=p;exports.isAssigned=c;exports.isClosed=u;exports.matchContactToIntents=b;exports.resolveChannelIntents=l;
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from './entities/ai-profile';
8
8
  export * from './entities/channel';
9
9
  export * from './entities/communication';
10
10
  export * from './entities/contact';
11
+ export * from './entities/calendar-event';
11
12
  export * from './entities/inbox';
12
13
  export * from './entities/interaction';
13
14
  export * from './entities/note';
package/dist/index.js CHANGED
@@ -1,18 +1,18 @@
1
- function c(t) {
1
+ function u(t) {
2
2
  return t.endpoints ?? [];
3
3
  }
4
- const d = (t) => !!t.assignedUserId || !!t.assignedInboxId, p = (t) => t.status === "closed", g = (t) => ({
4
+ const p = (t) => !!t.assignedUserId || !!t.assignedInboxId, c = (t) => t.status === "closed", g = (t) => ({
5
5
  urgent: 10,
6
6
  high: 5,
7
7
  normal: 2,
8
8
  low: 1
9
9
  })[t.priority] || 0, I = (t, n = 30) => t.title?.length <= n ? t.title : `${t.title.substring(0, n)}...`;
10
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]));
11
+ const s = new Set(t.disabledIntents ?? []), i = t.intentOverrides ?? {}, e = n.intents.filter((r) => !s.has(r.intent)).map((r) => l(r, i[r.intent]));
12
12
  if (!t.extraIntents || t.extraIntents.length === 0) return e;
13
- const o = new Set(e.map((s) => s.intent));
14
- for (const s of t.extraIntents)
15
- o.has(s.intent) || (e.push(s), o.add(s.intent));
13
+ const o = new Set(e.map((r) => r.intent));
14
+ for (const r of t.extraIntents)
15
+ o.has(r.intent) || (e.push(r), o.add(r.intent));
16
16
  return e;
17
17
  }
18
18
  function l(t, n) {
@@ -22,45 +22,48 @@ function l(t, n) {
22
22
  transport: n.transport ?? t.transport
23
23
  } : t;
24
24
  }
25
- function b(t, n) {
26
- const r = [];
25
+ function E(t, n) {
26
+ const s = [];
27
27
  for (const i of t) {
28
28
  if (!i.enabled) continue;
29
29
  const e = n[i.providerId];
30
30
  if (e)
31
31
  for (const o of f(i, e))
32
- r.push({ channel: i, description: e, capability: o });
32
+ s.push({ channel: i, description: e, capability: o });
33
33
  }
34
- return r;
34
+ return s;
35
35
  }
36
- function y(t, n) {
37
- return n.filter((r) => r.capability.intent === t);
36
+ function b(t, n) {
37
+ return n.filter((s) => s.capability.intent === t);
38
38
  }
39
39
  function a(t, n) {
40
- return n.filter((r) => r.capability.targetSchemes.includes(t));
40
+ return n.filter((s) => s.capability.targetSchemes.includes(t));
41
41
  }
42
- function E(t, n) {
42
+ function T(t, n) {
43
43
  return a(t.scheme, n);
44
44
  }
45
- function T(t, n, r) {
45
+ function y(t, n, s) {
46
46
  const i = [];
47
47
  for (const e of t)
48
- for (const o of r)
48
+ for (const o of s)
49
49
  o.capability.intent === n && o.capability.targetSchemes.includes(e.scheme) && i.push({ channelIntent: o, endpoint: e });
50
50
  return i;
51
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 || {});
52
+ var d = /* @__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.CALENDAR = "calendar", t))(d || {});
53
+ const A = (t, n) => ({ intent: t, ...n }), U = { ok: !1, code: "UNSUPPORTED", message: "Provider does not support this op" };
53
54
  export {
54
- u as CommunicationScheme,
55
- b as buildChannelIntents,
56
- E as filterByEndpoint,
57
- y as filterByIntent,
55
+ d as CommunicationScheme,
56
+ U as UNSUPPORTED,
57
+ E as buildChannelIntents,
58
+ A as defineIntent,
59
+ T as filterByEndpoint,
60
+ b as filterByIntent,
58
61
  a as filterByTargetScheme,
59
- c as getContactEndpoints,
62
+ u as getContactEndpoints,
60
63
  I as getShortTitle,
61
64
  g as getUrgencyScore,
62
- d as isAssigned,
63
- p as isClosed,
64
- T as matchContactToIntents,
65
+ p as isAssigned,
66
+ c as isClosed,
67
+ y as matchContactToIntents,
65
68
  f as resolveChannelIntents
66
69
  };
@@ -6,7 +6,7 @@ import { CommunicationScheme, IntentCapability, ProviderDescription, Uri } from
6
6
  * default composers). Intent itself is an open string — providers may
7
7
  * declare anything. Unknown intents render as generic actions.
8
8
  */
9
- export type CommunicationIntent = "call" | "mail" | "message" | "video";
9
+ export type CommunicationIntent = "call" | "mail" | "message" | "video" | "calendar";
10
10
  /**
11
11
  * A channel's effective intent — the resolved IntentCapability for this
12
12
  * specific channel, ready for routing/UI decisions.
@@ -33,12 +33,13 @@ export interface ITransportProvider {
33
33
  sessionId: string;
34
34
  stream: MediaStream;
35
35
  }) => void): () => void;
36
- createSession(target: string, accountId: string): Promise<void>;
37
- hangupSession(sessionId: string): Promise<void>;
38
36
  registerAccount(orgId: string, userId: string, config: any): Promise<CommsAccount>;
39
37
  unregisterAccount(accountId: string): Promise<void>;
40
- setOutgoingStream(sessionId: string, stream: MediaStream | null): Promise<void>;
41
- handleAction(sessionId: string, actionId: string, ...args: any[]): void;
38
+ /**
39
+ * Uniforme entry voor alle session-ops (invite/answer/hangup/hold/
40
+ * transfer/dtmf/set-stream).
41
+ */
42
+ dispatch(op: TransportOp): Promise<void>;
42
43
  }
43
44
  export type CommunicationDispatch = "transport" | "compose";
44
45
  export declare enum CommunicationScheme {
@@ -55,7 +56,8 @@ export declare enum CommunicationScheme {
55
56
  VIBER = "viber",
56
57
  SMS = "sms",
57
58
  FAX = "fax",
58
- TEAMS = "teams"
59
+ TEAMS = "teams",
60
+ CALENDAR = "calendar"
59
61
  }
60
62
  /**
61
63
  * Account selector for `transport: session` intents. Tells the frontend
@@ -72,8 +74,18 @@ export interface AccountSelector {
72
74
  accountId?: string;
73
75
  matcherId?: string;
74
76
  }
77
+ /**
78
+ * Routing-hint voor de frontend en de comm-server: hoe wordt deze intent
79
+ * uitgevoerd?
80
+ *
81
+ * - `dispatch` — server-side via comm-server `provider/dispatch/` →
82
+ * `IProvider.dispatch(op)` op de provider-app's server. Dekt
83
+ * message.*, attachment.*, calendar.*, contact.* ServerOps.
84
+ * - `session` — client-side via `ITransportProvider.dispatch(op)` in
85
+ * de browser-UA (SIP/WebRTC). Geen server-roundtrip.
86
+ */
75
87
  export type TransportConfig = {
76
- kind: "compose";
88
+ kind: "dispatch";
77
89
  /** Optional federated composer resource as "<app>:<resource>". */
78
90
  composer?: string;
79
91
  /**
@@ -168,3 +180,274 @@ export interface RemoteStreamEvent {
168
180
  stream: MediaStream | null;
169
181
  label?: string;
170
182
  }
183
+ /**
184
+ * Helper voor compactere intent-declaraties in `/provider/describe`.
185
+ * defineIntent("mail", { targetSchemes: [MAILTO], transport: { kind: "dispatch" } })
186
+ */
187
+ export declare const defineIntent: (intent: string, opts: Omit<IntentCapability, "intent">) => IntentCapability;
188
+ export interface ExternalId {
189
+ providerId: string;
190
+ kind: string;
191
+ value: string;
192
+ }
193
+ export interface AuditTrace {
194
+ actorId?: string;
195
+ timestamp: number;
196
+ note?: string;
197
+ }
198
+ export interface MessageBody {
199
+ subject?: string;
200
+ text?: string;
201
+ html?: string;
202
+ attachments?: Array<{
203
+ id: string;
204
+ name: string;
205
+ mimeType?: string;
206
+ }>;
207
+ }
208
+ export interface NoteBody {
209
+ text: string;
210
+ visibility?: "internal" | "team";
211
+ }
212
+ export interface FileRef {
213
+ id: string;
214
+ name: string;
215
+ mimeType?: string;
216
+ size?: number;
217
+ }
218
+ export interface CalendarEventInput {
219
+ title: string;
220
+ start: number;
221
+ end: number;
222
+ attendees?: Array<{
223
+ uri: Uri;
224
+ required?: boolean;
225
+ }>;
226
+ location?: string;
227
+ description?: string;
228
+ conferencing?: {
229
+ provider: string;
230
+ joinUri?: string;
231
+ };
232
+ }
233
+ /**
234
+ * Server-side ops uitgevoerd door de provider-app's server, getriggerd
235
+ * door comm-server `provider/dispatch/`. Payloads dragen IDs, geen
236
+ * volledige entities — provider resolved zelf via platform-api.
237
+ */
238
+ export type ServerOp = {
239
+ kind: "message.new";
240
+ channelId: string;
241
+ intent: string;
242
+ recipient: Uri;
243
+ body: MessageBody;
244
+ } | {
245
+ kind: "message.reply";
246
+ channelId: string;
247
+ interactionId: string;
248
+ activityId?: string;
249
+ body: MessageBody;
250
+ } | {
251
+ kind: "message.comment";
252
+ channelId: string;
253
+ interactionId: string;
254
+ body: NoteBody;
255
+ } | {
256
+ kind: "message.forward";
257
+ channelId: string;
258
+ activityId: string;
259
+ recipient: Uri;
260
+ body?: MessageBody;
261
+ } | {
262
+ kind: "message.transcribe";
263
+ channelId: string;
264
+ activityId: string;
265
+ } | {
266
+ kind: "attachment.download";
267
+ channelId: string;
268
+ activityId: string;
269
+ attachmentId: string;
270
+ } | {
271
+ kind: "attachment.upload";
272
+ channelId: string;
273
+ interactionId: string;
274
+ file: FileRef;
275
+ } | {
276
+ kind: "calendar.create";
277
+ channelId: string;
278
+ event: CalendarEventInput;
279
+ } | {
280
+ kind: "calendar.update";
281
+ channelId: string;
282
+ eventId: string;
283
+ patch: Partial<CalendarEventInput>;
284
+ } | {
285
+ kind: "calendar.cancel";
286
+ channelId: string;
287
+ eventId: string;
288
+ reason?: string;
289
+ } | {
290
+ kind: "calendar.respond";
291
+ channelId: string;
292
+ eventId: string;
293
+ response: "accepted" | "tentative" | "declined";
294
+ } | {
295
+ kind: "contact.search";
296
+ channelId: string;
297
+ query: string;
298
+ } | {
299
+ kind: "contact.fetch";
300
+ channelId: string;
301
+ externalId: string;
302
+ };
303
+ /**
304
+ * Result-shape voor `IProvider.dispatch` en de comm-server `dispatchToProvider`-
305
+ * helper. Discriminated op `ok`. Bewust niet strict-null-discriminated zodat
306
+ * narrowing ook werkt zonder strictNullChecks (root tsconfig is non-strict).
307
+ */
308
+ export interface ServerResult<T = unknown> {
309
+ ok: boolean;
310
+ data?: T;
311
+ externalIds?: ExternalId[];
312
+ audit?: AuditTrace;
313
+ code?: string;
314
+ message?: string;
315
+ retryable?: boolean;
316
+ }
317
+ export declare const UNSUPPORTED: ServerResult;
318
+ /**
319
+ * Transport-ops uitgevoerd in de browser-UA (SIP/WebRTC), getriggerd
320
+ * door de frontend via `ITransportProvider.dispatch`. Geen server-
321
+ * roundtrip — directe controle over de lokale stack.
322
+ */
323
+ export type TransportOp = {
324
+ kind: "session.invite";
325
+ accountId: string;
326
+ target: string;
327
+ withVideo?: boolean;
328
+ } | {
329
+ kind: "session.answer";
330
+ sessionId: string;
331
+ withVideo?: boolean;
332
+ } | {
333
+ kind: "session.reject";
334
+ sessionId: string;
335
+ } | {
336
+ kind: "session.hangup";
337
+ sessionId: string;
338
+ } | {
339
+ kind: "session.hold";
340
+ sessionId: string;
341
+ on: boolean;
342
+ } | {
343
+ kind: "session.mute";
344
+ sessionId: string;
345
+ on?: boolean;
346
+ } | {
347
+ kind: "session.transfer";
348
+ sessionId: string;
349
+ target: string;
350
+ mode: "blind" | "attended";
351
+ } | {
352
+ kind: "session.dtmf";
353
+ sessionId: string;
354
+ digits: string;
355
+ } | {
356
+ kind: "session.set-stream";
357
+ sessionId: string;
358
+ stream: MediaStream | null;
359
+ } | {
360
+ kind: "session.toggle-camera";
361
+ sessionId: string;
362
+ } | {
363
+ kind: "session.toggle-screen-share";
364
+ sessionId: string;
365
+ };
366
+ export interface TokenResponse {
367
+ access_token: string;
368
+ refresh_token?: string;
369
+ expires_in?: number;
370
+ id_token?: string;
371
+ scope?: string;
372
+ token_type?: string;
373
+ [extra: string]: unknown;
374
+ }
375
+ export interface OAuthConfig {
376
+ authorizeEndpoint: string;
377
+ tokenEndpoint: string;
378
+ clientId: string;
379
+ /** Server-side only — uit provider's secret-store. Mag leeg blijven voor PKCE. */
380
+ clientSecret?: string;
381
+ scopes: string[];
382
+ /** Extra params voor authorize-URL (prompt, access_type, etc.). */
383
+ authorizeParams?: Record<string, string>;
384
+ /** Optionele identity-decoder voor OAuth-providers met JWT id_token (MS, Google). */
385
+ decodeIdentity?: (tokens: TokenResponse) => Promise<{
386
+ externalUserId: string;
387
+ displayName?: string;
388
+ metadata?: Record<string, unknown>;
389
+ }>;
390
+ refresh?: {
391
+ bufferMs?: number;
392
+ /** Hook voor provider-specifieke post-refresh acties (bv. tenant-inferentie MS). */
393
+ postRefresh?: (tokens: TokenResponse) => Promise<void>;
394
+ };
395
+ }
396
+ export type PersonalAuthConfig = {
397
+ mode: "oauth2";
398
+ oauth: OAuthConfig;
399
+ } | {
400
+ mode: "form";
401
+ fields: PersonalAuthField[];
402
+ message?: string;
403
+ } | {
404
+ mode: "unavailable";
405
+ message?: string;
406
+ };
407
+ export interface PersonalAuthCtx {
408
+ organizationId: string;
409
+ userId: string;
410
+ }
411
+ export interface FormAuthCtx {
412
+ userId: string;
413
+ organizationId: string;
414
+ }
415
+ /**
416
+ * Server-side contract per communication-provider. Provider-apps
417
+ * registreren zich via `Bridge.providers.role({ type: "provider", group: "communication" })`
418
+ * en exposen routes die overeenkomen met deze methods (comm-server roept ze
419
+ * via Bridge.rpc aan).
420
+ *
421
+ * Niet bedoeld voor frontend-consumptie — frontend praat alleen met
422
+ * comm-server's `provider/*` en `account/*` endpoints.
423
+ */
424
+ export interface IProvider {
425
+ readonly id: string;
426
+ describe(): Promise<ProviderDescription>;
427
+ listChannels(orgId: string, userId?: string): Promise<unknown[]>;
428
+ /**
429
+ * Comm-server vraagt provider om huidige auth-config. Reden om dit op
430
+ * IProvider te houden (i.p.v. statische registratie): clientId/secret/
431
+ * scopes komen vaak uit secret-store of tenant-config — niet code-statisch.
432
+ */
433
+ personalAuth(ctx: PersonalAuthCtx): Promise<PersonalAuthConfig>;
434
+ /**
435
+ * Voor `mode: "form"` — provider valideert credentials en bouwt het
436
+ * Account zelf. OAuth-mode hoeft dit niet; comm-server handelt token-
437
+ * exchange volledig.
438
+ */
439
+ completeFormAuth?(fields: Record<string, string>, ctx: FormAuthCtx): Promise<{
440
+ accountId: string;
441
+ }>;
442
+ /**
443
+ * Post-connect hook — provider mag eigen vervolgwerk doen (bv. MS
444
+ * user-connection channel-binding) NA dat het Account is opgeslagen.
445
+ */
446
+ onAccountConnected?(account: {
447
+ id: string;
448
+ providerId: string;
449
+ userId?: string;
450
+ organizationId: string;
451
+ }): Promise<void>;
452
+ dispatch(op: ServerOp): Promise<ServerResult>;
453
+ }
@@ -69,6 +69,40 @@ export interface FindActivityByExternalProviderIdPayload {
69
69
  activityType: string;
70
70
  interactionId?: string;
71
71
  }
72
+ /**
73
+ * Calendar/schedule transport payloads. Providers that declare an intent
74
+ * with `transport: { kind: "schedule" }` implement `/provider/schedule/*`
75
+ * routes. Communication-server dispatches CRUD on CalendarEvents to the
76
+ * corresponding provider via these payloads.
77
+ */
78
+ export type ScheduleResponse = "accepted" | "declined" | "tentative";
79
+ export interface SchedulePayload {
80
+ channelId: string;
81
+ /** Local CalendarEvent without storage-managed fields. */
82
+ event: any;
83
+ }
84
+ export interface ScheduleUpdatePayload {
85
+ channelId: string;
86
+ externalId: string;
87
+ patch: any;
88
+ }
89
+ export interface ScheduleCancelPayload {
90
+ channelId: string;
91
+ externalId: string;
92
+ comment?: string;
93
+ }
94
+ export interface ScheduleRespondPayload {
95
+ channelId: string;
96
+ externalId: string;
97
+ response: ScheduleResponse;
98
+ comment?: string;
99
+ sendResponse?: boolean;
100
+ }
101
+ export interface ScheduleResult {
102
+ externalId?: string;
103
+ /** Provider-side echo for caller persistence (e.g. Graph event id). */
104
+ providerData?: Record<string, unknown>;
105
+ }
72
106
  export interface FileUploadPayload {
73
107
  file: Uint8Array;
74
108
  filename: string;
@@ -49,12 +49,20 @@ export interface InternalSDK<LocalServices extends ServiceMap = {}, TranslationK
49
49
  sessions$: Observable<Session[]>;
50
50
  accounts$: Observable<CommsAccount[]>;
51
51
  activeSession$: Observable<Session | null>;
52
- createSession(target: string, accountId: string): Promise<void>;
53
- hangupSession(sessionId: string): Promise<void>;
52
+ /**
53
+ * Routeert een TransportOp naar de provider die de gegeven session bezit.
54
+ * Vervangt de losse hangupSession/handleSessionAction APIs.
55
+ */
56
+ dispatchSessionOp(sessionId: string, op: import('./communication').TransportOp): Promise<void>;
57
+ /**
58
+ * Initieert een nieuwe outbound sessie via `session.invite`. Sugar
59
+ * voor `dispatchSessionOp` op het juiste provider; sessieId bestaat
60
+ * pas na invite.
61
+ */
62
+ invite(target: string, accountId: string): Promise<void>;
54
63
  interceptStream(sessionId: string, callback: (stream: MediaStream) => void): Promise<() => void>;
55
64
  setActiveSession(sessionId: string): Promise<void>;
56
65
  registerAccount(organizationId: string, userId: string, providerId: string, config: any): Promise<CommsAccount>;
57
- handleSessionAction(sessionId: string, actionId: string, ...args: any[]): Promise<void>;
58
66
  transcripts: {
59
67
  ingest(segments: TranscriptSegment[]): void;
60
68
  byCallSession$(sessionId: string): Observable<TranscriptSegment[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencxh/domain",
3
- "version": "1.23.2",
3
+ "version": "1.28.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",