@coventia/softphone 0.3.0 → 0.4.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.
@@ -240,6 +240,11 @@ interface CallHistoryEntry {
240
240
  readonly outcome?: CallOutcome;
241
241
  /** The org's own number that was dialled — present only (and only meaningful) for an inbound call. */
242
242
  readonly did?: string;
243
+ /**
244
+ * The org's own number an outbound call was made from (what the callee saw) — present only for outbound calls the
245
+ * backend recorded it for (outbound-number-per-agent.md §5.7). Digits, no `+`.
246
+ */
247
+ readonly from?: string;
243
248
  /** True when Coventia has at least one recording for this call. */
244
249
  readonly recorded: boolean;
245
250
  /**
@@ -415,6 +420,64 @@ interface RingtoneSource {
415
420
  */
416
421
  cached?(): Promise<RingtoneSettings | null>;
417
422
  }
423
+ /**
424
+ * What kind of number this is, for the tags next to it in "Llamar desde" (outbound-number-per-agent.md §5.5).
425
+ * Display only — it never blocks a choice. `mobile` must not be used for customer care or unsolicited commercial
426
+ * calls; `commercial` (the 400 range) is for outbound commercial calls only and receives no calls.
427
+ */
428
+ type OutboundNumberKind = 'landline' | 'mobile' | 'commercial' | 'other';
429
+ /** One of the organization's numbers an agent can call from. */
430
+ interface OutboundNumber {
431
+ /** Stable id — what is stored as the agent's choice. */
432
+ readonly id: string;
433
+ /** International format, digits only, no `+` — e.g. `34960000001`. */
434
+ readonly number: string;
435
+ /** The name the organization gave the number, or `null`. */
436
+ readonly label: string | null;
437
+ readonly kind: OutboundNumberKind;
438
+ }
439
+ /**
440
+ * Where the agent's extension stands. `pending`/`failed`: an assignment change could not update it yet, so the
441
+ * extension may still present an earlier number. `unassigned`: the agent has no extension in this organization.
442
+ */
443
+ type OutboundNumberState = 'applied' | 'pending' | 'failed' | 'unassigned';
444
+ /** The organization's numbers and the caller's choice, as the backend resolves them. */
445
+ interface OutboundNumberSettings {
446
+ /** The organization's active numbers, ordered by number. */
447
+ readonly numbers: readonly OutboundNumber[];
448
+ /** The organization default (an `OutboundNumber.id`), or `null`. */
449
+ readonly orgDefault: string | null;
450
+ /** This agent's own choice, or `null` = "use the organization default". */
451
+ readonly mine: string | null;
452
+ /** The number this agent's calls show: `mine`, else `orgDefault`. */
453
+ readonly effective: string | null;
454
+ /** The agent's extension ("100"), or `null` when they have none. */
455
+ readonly extension: string | null;
456
+ readonly state: OutboundNumberState;
457
+ /** 0 when a change could go out now; otherwise the seconds until it can. */
458
+ readonly changeAvailableInSeconds: number;
459
+ }
460
+ /**
461
+ * Why a change was refused before anything was sent. `platform`: the shared limit on number changes (nothing the
462
+ * agent did). `user`: the agent changed it moments ago. Either way the previous number stays in use.
463
+ */
464
+ interface OutboundNumberRefusal {
465
+ readonly reason: 'platform' | 'user';
466
+ /** Seconds until a change can go out — always at least 1. */
467
+ readonly retryAfterSeconds: number;
468
+ }
469
+ /** The outbound number of the agent the softphone is signed in as, in its organization. */
470
+ interface OutboundNumbersSource {
471
+ get(signal?: AbortSignal): Promise<OutboundNumberSettings>;
472
+ /**
473
+ * Changes this agent's number; `null` = back to the organization default. Resolves to the new settings once the
474
+ * change is in effect. When the request limits refuse it, rejects with an `Error` carrying
475
+ * `refusal: OutboundNumberRefusal` (check with `isOutboundNumberRefused`) — nothing was stored or sent.
476
+ */
477
+ setMine(id: string | null): Promise<OutboundNumberSettings>;
478
+ /** The settings this agent last had on this device, if remembered — instant, no network. Optional. */
479
+ cached?(): Promise<OutboundNumberSettings | null>;
480
+ }
418
481
 
419
482
  /**
420
483
  * The error taxonomy.
@@ -873,4 +936,4 @@ interface Call extends TypedEmitter<CallEventMap> {
873
936
  cancelConsult(): Promise<void>;
874
937
  }
875
938
 
876
- export { type AgentsDirectory as A, type PresenceSource as B, CALL_TRANSITIONS as C, type CallHistoryEntry as D, ERROR_CATALOGUE as E, type FatalErrorCode as F, type ContactsPage as G, type HangupReason as H, INITIAL_STATES as I, type LogLevel as L, type NonFatalErrorCode as N, type PresenceEntry as P, type RemoteParty as R, type SoftphoneConfig as S, type TokenEndpointOptions as T, type VoiceToken as V, type Call as a, type CallDirection as b, CallEvent as c, type CallEventMap as d, type CallOptions as e, type CallState as f, type Contact as g, type FatalSoftphoneError as h, type HoldOriginator as i, type NonFatalSoftphoneError as j, type RingtoneOption as k, type RingtoneSettings as l, type RingtoneSource as m, type SoftphoneError as n, type SoftphoneErrorCode as o, SoftphoneEvent as p, type SoftphoneEventMap as q, type SoftphoneState as r, type TokenSource as s, type TypedEmitter as t, canTransition as u, isFatal as v, isTerminal as w, type ContactsSource as x, type HistorySource as y, type TransferOutcomesPage as z };
939
+ export { isFatal as A, isTerminal as B, CALL_TRANSITIONS as C, type ContactsSource as D, ERROR_CATALOGUE as E, type FatalErrorCode as F, type HistorySource as G, type HangupReason as H, INITIAL_STATES as I, type AgentsDirectory as J, type TransferOutcomesPage as K, type LogLevel as L, type PresenceSource as M, type NonFatalErrorCode as N, type OutboundNumberRefusal as O, type PresenceEntry as P, type CallHistoryEntry as Q, type RemoteParty as R, type SoftphoneConfig as S, type TokenEndpointOptions as T, type ContactsPage as U, type VoiceToken as V, type Call as a, type CallDirection as b, CallEvent as c, type CallEventMap as d, type CallOptions as e, type CallState as f, type Contact as g, type FatalSoftphoneError as h, type HoldOriginator as i, type NonFatalSoftphoneError as j, type OutboundNumber as k, type OutboundNumberKind as l, type OutboundNumberSettings as m, type OutboundNumberState as n, type OutboundNumbersSource as o, type RingtoneOption as p, type RingtoneSettings as q, type RingtoneSource as r, type SoftphoneError as s, type SoftphoneErrorCode as t, SoftphoneEvent as u, type SoftphoneEventMap as v, type SoftphoneState as w, type TokenSource as x, type TypedEmitter as y, canTransition as z };
@@ -240,6 +240,11 @@ interface CallHistoryEntry {
240
240
  readonly outcome?: CallOutcome;
241
241
  /** The org's own number that was dialled — present only (and only meaningful) for an inbound call. */
242
242
  readonly did?: string;
243
+ /**
244
+ * The org's own number an outbound call was made from (what the callee saw) — present only for outbound calls the
245
+ * backend recorded it for (outbound-number-per-agent.md §5.7). Digits, no `+`.
246
+ */
247
+ readonly from?: string;
243
248
  /** True when Coventia has at least one recording for this call. */
244
249
  readonly recorded: boolean;
245
250
  /**
@@ -415,6 +420,64 @@ interface RingtoneSource {
415
420
  */
416
421
  cached?(): Promise<RingtoneSettings | null>;
417
422
  }
423
+ /**
424
+ * What kind of number this is, for the tags next to it in "Llamar desde" (outbound-number-per-agent.md §5.5).
425
+ * Display only — it never blocks a choice. `mobile` must not be used for customer care or unsolicited commercial
426
+ * calls; `commercial` (the 400 range) is for outbound commercial calls only and receives no calls.
427
+ */
428
+ type OutboundNumberKind = 'landline' | 'mobile' | 'commercial' | 'other';
429
+ /** One of the organization's numbers an agent can call from. */
430
+ interface OutboundNumber {
431
+ /** Stable id — what is stored as the agent's choice. */
432
+ readonly id: string;
433
+ /** International format, digits only, no `+` — e.g. `34960000001`. */
434
+ readonly number: string;
435
+ /** The name the organization gave the number, or `null`. */
436
+ readonly label: string | null;
437
+ readonly kind: OutboundNumberKind;
438
+ }
439
+ /**
440
+ * Where the agent's extension stands. `pending`/`failed`: an assignment change could not update it yet, so the
441
+ * extension may still present an earlier number. `unassigned`: the agent has no extension in this organization.
442
+ */
443
+ type OutboundNumberState = 'applied' | 'pending' | 'failed' | 'unassigned';
444
+ /** The organization's numbers and the caller's choice, as the backend resolves them. */
445
+ interface OutboundNumberSettings {
446
+ /** The organization's active numbers, ordered by number. */
447
+ readonly numbers: readonly OutboundNumber[];
448
+ /** The organization default (an `OutboundNumber.id`), or `null`. */
449
+ readonly orgDefault: string | null;
450
+ /** This agent's own choice, or `null` = "use the organization default". */
451
+ readonly mine: string | null;
452
+ /** The number this agent's calls show: `mine`, else `orgDefault`. */
453
+ readonly effective: string | null;
454
+ /** The agent's extension ("100"), or `null` when they have none. */
455
+ readonly extension: string | null;
456
+ readonly state: OutboundNumberState;
457
+ /** 0 when a change could go out now; otherwise the seconds until it can. */
458
+ readonly changeAvailableInSeconds: number;
459
+ }
460
+ /**
461
+ * Why a change was refused before anything was sent. `platform`: the shared limit on number changes (nothing the
462
+ * agent did). `user`: the agent changed it moments ago. Either way the previous number stays in use.
463
+ */
464
+ interface OutboundNumberRefusal {
465
+ readonly reason: 'platform' | 'user';
466
+ /** Seconds until a change can go out — always at least 1. */
467
+ readonly retryAfterSeconds: number;
468
+ }
469
+ /** The outbound number of the agent the softphone is signed in as, in its organization. */
470
+ interface OutboundNumbersSource {
471
+ get(signal?: AbortSignal): Promise<OutboundNumberSettings>;
472
+ /**
473
+ * Changes this agent's number; `null` = back to the organization default. Resolves to the new settings once the
474
+ * change is in effect. When the request limits refuse it, rejects with an `Error` carrying
475
+ * `refusal: OutboundNumberRefusal` (check with `isOutboundNumberRefused`) — nothing was stored or sent.
476
+ */
477
+ setMine(id: string | null): Promise<OutboundNumberSettings>;
478
+ /** The settings this agent last had on this device, if remembered — instant, no network. Optional. */
479
+ cached?(): Promise<OutboundNumberSettings | null>;
480
+ }
418
481
 
419
482
  /**
420
483
  * The error taxonomy.
@@ -873,4 +936,4 @@ interface Call extends TypedEmitter<CallEventMap> {
873
936
  cancelConsult(): Promise<void>;
874
937
  }
875
938
 
876
- export { type AgentsDirectory as A, type PresenceSource as B, CALL_TRANSITIONS as C, type CallHistoryEntry as D, ERROR_CATALOGUE as E, type FatalErrorCode as F, type ContactsPage as G, type HangupReason as H, INITIAL_STATES as I, type LogLevel as L, type NonFatalErrorCode as N, type PresenceEntry as P, type RemoteParty as R, type SoftphoneConfig as S, type TokenEndpointOptions as T, type VoiceToken as V, type Call as a, type CallDirection as b, CallEvent as c, type CallEventMap as d, type CallOptions as e, type CallState as f, type Contact as g, type FatalSoftphoneError as h, type HoldOriginator as i, type NonFatalSoftphoneError as j, type RingtoneOption as k, type RingtoneSettings as l, type RingtoneSource as m, type SoftphoneError as n, type SoftphoneErrorCode as o, SoftphoneEvent as p, type SoftphoneEventMap as q, type SoftphoneState as r, type TokenSource as s, type TypedEmitter as t, canTransition as u, isFatal as v, isTerminal as w, type ContactsSource as x, type HistorySource as y, type TransferOutcomesPage as z };
939
+ export { isFatal as A, isTerminal as B, CALL_TRANSITIONS as C, type ContactsSource as D, ERROR_CATALOGUE as E, type FatalErrorCode as F, type HistorySource as G, type HangupReason as H, INITIAL_STATES as I, type AgentsDirectory as J, type TransferOutcomesPage as K, type LogLevel as L, type PresenceSource as M, type NonFatalErrorCode as N, type OutboundNumberRefusal as O, type PresenceEntry as P, type CallHistoryEntry as Q, type RemoteParty as R, type SoftphoneConfig as S, type TokenEndpointOptions as T, type ContactsPage as U, type VoiceToken as V, type Call as a, type CallDirection as b, CallEvent as c, type CallEventMap as d, type CallOptions as e, type CallState as f, type Contact as g, type FatalSoftphoneError as h, type HoldOriginator as i, type NonFatalSoftphoneError as j, type OutboundNumber as k, type OutboundNumberKind as l, type OutboundNumberSettings as m, type OutboundNumberState as n, type OutboundNumbersSource as o, type RingtoneOption as p, type RingtoneSettings as q, type RingtoneSource as r, type SoftphoneError as s, type SoftphoneErrorCode as t, SoftphoneEvent as u, type SoftphoneEventMap as v, type SoftphoneState as w, type TokenSource as x, type TypedEmitter as y, canTransition as z };
@@ -0,0 +1,14 @@
1
+ // src/core/outbound-numbers.ts
2
+ function isOutboundNumberRefused(value) {
3
+ const refusal = value?.refusal;
4
+ return value instanceof Error && !!refusal && (refusal.reason === "platform" || refusal.reason === "user") && typeof refusal.retryAfterSeconds === "number";
5
+ }
6
+ function outboundNumberRefused(refusal) {
7
+ const error = new Error(`Outbound number change refused (${refusal.reason}); retry in ${refusal.retryAfterSeconds}s`);
8
+ error.name = "OutboundNumberRefused";
9
+ return Object.assign(error, { refusal });
10
+ }
11
+
12
+ export { isOutboundNumberRefused, outboundNumberRefused };
13
+ //# sourceMappingURL=chunk-5E5OEXS2.js.map
14
+ //# sourceMappingURL=chunk-5E5OEXS2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/outbound-numbers.ts"],"names":[],"mappings":";AAWO,SAAS,wBAAwB,KAAA,EAAqD;AAC3F,EAAA,MAAM,UAAW,KAAA,EAA+D,OAAA;AAChF,EAAA,OACE,KAAA,YAAiB,KAAA,IACjB,CAAC,CAAC,OAAA,KACD,OAAA,CAAQ,MAAA,KAAW,UAAA,IAAc,OAAA,CAAQ,MAAA,KAAW,MAAA,CAAA,IACrD,OAAO,QAAQ,iBAAA,KAAsB,QAAA;AAEzC;AAGO,SAAS,sBAAsB,OAAA,EAA4D;AAChG,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,QAAQ,MAAM,CAAA,YAAA,EAAe,OAAA,CAAQ,iBAAiB,CAAA,CAAA,CAAG,CAAA;AACpH,EAAA,KAAA,CAAM,IAAA,GAAO,uBAAA;AACb,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,EAAE,SAAS,CAAA;AACzC","file":"chunk-5E5OEXS2.js","sourcesContent":["import type { OutboundNumberRefusal } from './types.js';\r\n\r\n/**\r\n * A change of outbound number the request limits refused (outbound-number-per-agent.md §5.3–§5.5). Structural,\r\n * like `isSoftphoneError`: the concrete error is a plain `Error` with a `refusal`, so a host — or a second copy\r\n * of the SDK on the page — can recognise it without sharing a class.\r\n */\r\nexport interface OutboundNumberRefusedError extends Error {\r\n readonly refusal: OutboundNumberRefusal;\r\n}\r\n\r\nexport function isOutboundNumberRefused(value: unknown): value is OutboundNumberRefusedError {\r\n const refusal = (value as { refusal?: Partial<OutboundNumberRefusal> } | null)?.refusal;\r\n return (\r\n value instanceof Error &&\r\n !!refusal &&\r\n (refusal.reason === 'platform' || refusal.reason === 'user') &&\r\n typeof refusal.retryAfterSeconds === 'number'\r\n );\r\n}\r\n\r\n/** @internal — raised by the Coventia source; hosts only read these. */\r\nexport function outboundNumberRefused(refusal: OutboundNumberRefusal): OutboundNumberRefusedError {\r\n const error = new Error(`Outbound number change refused (${refusal.reason}); retry in ${refusal.retryAfterSeconds}s`);\r\n error.name = 'OutboundNumberRefused';\r\n return Object.assign(error, { refusal });\r\n}\r\n"]}
@@ -109,6 +109,11 @@ interface CallHistoryEntry {
109
109
  readonly outcome?: CallOutcome;
110
110
  /** The org's own number that was dialled — present only (and only meaningful) for an inbound call. */
111
111
  readonly did?: string;
112
+ /**
113
+ * The org's own number an outbound call was made from (what the callee saw) — present only for outbound calls the
114
+ * backend recorded it for (outbound-number-per-agent.md §5.7). Digits, no `+`.
115
+ */
116
+ readonly from?: string;
112
117
  /** True when Coventia has at least one recording for this call. */
113
118
  readonly recorded: boolean;
114
119
  /**
@@ -276,6 +281,55 @@ interface RingtoneSource {
276
281
  */
277
282
  cached?(): Promise<RingtoneSettings | null>;
278
283
  }
284
+ /**
285
+ * What kind of number this is, for the tags next to it in "Llamar desde" (outbound-number-per-agent.md §5.5).
286
+ * Display only — it never blocks a choice. `mobile` must not be used for customer care or unsolicited commercial
287
+ * calls; `commercial` (the 400 range) is for outbound commercial calls only and receives no calls.
288
+ */
289
+ type OutboundNumberKind = 'landline' | 'mobile' | 'commercial' | 'other';
290
+ /** One of the organization's numbers an agent can call from. */
291
+ interface OutboundNumber {
292
+ /** Stable id — what is stored as the agent's choice. */
293
+ readonly id: string;
294
+ /** International format, digits only, no `+` — e.g. `34960000001`. */
295
+ readonly number: string;
296
+ /** The name the organization gave the number, or `null`. */
297
+ readonly label: string | null;
298
+ readonly kind: OutboundNumberKind;
299
+ }
300
+ /**
301
+ * Where the agent's extension stands. `pending`/`failed`: an assignment change could not update it yet, so the
302
+ * extension may still present an earlier number. `unassigned`: the agent has no extension in this organization.
303
+ */
304
+ type OutboundNumberState = 'applied' | 'pending' | 'failed' | 'unassigned';
305
+ /** The organization's numbers and the caller's choice, as the backend resolves them. */
306
+ interface OutboundNumberSettings {
307
+ /** The organization's active numbers, ordered by number. */
308
+ readonly numbers: readonly OutboundNumber[];
309
+ /** The organization default (an `OutboundNumber.id`), or `null`. */
310
+ readonly orgDefault: string | null;
311
+ /** This agent's own choice, or `null` = "use the organization default". */
312
+ readonly mine: string | null;
313
+ /** The number this agent's calls show: `mine`, else `orgDefault`. */
314
+ readonly effective: string | null;
315
+ /** The agent's extension ("100"), or `null` when they have none. */
316
+ readonly extension: string | null;
317
+ readonly state: OutboundNumberState;
318
+ /** 0 when a change could go out now; otherwise the seconds until it can. */
319
+ readonly changeAvailableInSeconds: number;
320
+ }
321
+ /** The outbound number of the agent the softphone is signed in as, in its organization. */
322
+ interface OutboundNumbersSource {
323
+ get(signal?: AbortSignal): Promise<OutboundNumberSettings>;
324
+ /**
325
+ * Changes this agent's number; `null` = back to the organization default. Resolves to the new settings once the
326
+ * change is in effect. When the request limits refuse it, rejects with an `Error` carrying
327
+ * `refusal: OutboundNumberRefusal` (check with `isOutboundNumberRefused`) — nothing was stored or sent.
328
+ */
329
+ setMine(id: string | null): Promise<OutboundNumberSettings>;
330
+ /** The settings this agent last had on this device, if remembered — instant, no network. Optional. */
331
+ cached?(): Promise<OutboundNumberSettings | null>;
332
+ }
279
333
 
280
334
  /** Contacts, history, caller ID, the agents directory, transfer outcomes, presence and ringtone
281
335
  * settings, all from one config. */
@@ -293,6 +347,8 @@ interface BackendSources {
293
347
  readonly presence: PresenceSource;
294
348
  /** The caller's ringtone settings (custom-ringtone.md §4.4). Always Coventia's — no override. */
295
349
  readonly ringtones: RingtoneSource;
350
+ /** The caller's outbound number (outbound-number-per-agent.md §5.5). Always Coventia's — no override. */
351
+ readonly outboundNumbers: OutboundNumbersSource;
296
352
  }
297
353
 
298
354
  /**