@snugdesk/avaya-ipo-widget 0.2.2 → 0.2.4

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.
package/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { NgZone, OnInit, OnDestroy, EventEmitter, ChangeDetectorRef, AfterViewInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core';
2
+ import { NgZone, OnInit, OnDestroy, OnChanges, EventEmitter, ChangeDetectorRef, SimpleChanges, AfterViewInit, ElementRef } from '@angular/core';
3
3
  import * as i14 from '@angular/forms';
4
4
  import { FormGroup, FormBuilder } from '@angular/forms';
5
5
  import * as rxjs from 'rxjs';
6
6
  import { BehaviorSubject, Subject } from 'rxjs';
7
7
  import { HttpClient } from '@angular/common/http';
8
- import { SnugdeskAuthenticationService } from '@snugdesk/core';
8
+ import { SnugdeskAuthenticationService, AppSyncHelperService } from '@snugdesk/core';
9
9
  import * as i19 from 'ngx-intl-tel-input';
10
10
  import { CountryISO, SearchCountryField } from 'ngx-intl-tel-input';
11
11
  import * as i13 from '@angular/common';
@@ -62,6 +62,9 @@ declare class AvayaIPOService {
62
62
  getActiveCallCount(): number;
63
63
  setLastIncomingCall(callId: string, farEndNumber: string): void;
64
64
  private startRingTone;
65
+ private ringRetryHandler;
66
+ private armRingRetryOnGesture;
67
+ private disarmRingRetry;
65
68
  private stopRingTone;
66
69
  private agentId;
67
70
  private loginStatusSubject;
@@ -69,7 +72,6 @@ declare class AvayaIPOService {
69
72
  private readonly DOM_TAGS;
70
73
  private configTemplate;
71
74
  private readonly agentStatusApiUrl;
72
- private readonly CALL_HISTORY_API_URL;
73
75
  private prewarmedStream?;
74
76
  private isSafari;
75
77
  private _rpcPatched;
@@ -178,12 +180,18 @@ declare class EntitiesSearchService {
178
180
  private http;
179
181
  private authenticationService;
180
182
  private nameCache;
183
+ private entityIdCache;
181
184
  constructor(http: HttpClient, authenticationService: AuthenticationService);
182
185
  fetchContacts(tenantId: string, size?: number, searchAfter?: [string, string]): Promise<any>;
183
186
  searchByPhone(tenantId: string, phoneNumber: string, size?: number): Promise<any>;
184
187
  searchEntities(tenantId: string, query: string, size?: number, from?: number): Promise<any>;
185
188
  getCachedName(tenantId: string, phoneNumber: string): string | null;
186
189
  lookupNameByPhone(tenantId: string, phoneNumber: string, size?: number): Promise<string | null>;
190
+ /** Resolve the entity (id + name) matching a phone number; both are cached per tenant+number. */
191
+ lookupEntityByPhone(tenantId: string, phoneNumber: string, size?: number): Promise<{
192
+ id: string | null;
193
+ name: string | null;
194
+ }>;
187
195
  private postEntities;
188
196
  private cacheKey;
189
197
  private ensureWildcard;
@@ -191,7 +199,7 @@ declare class EntitiesSearchService {
191
199
  static ɵprov: i0.ɵɵInjectableDeclaration<EntitiesSearchService>;
192
200
  }
193
201
 
194
- declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
202
+ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy, OnChanges {
195
203
  private formBuilder;
196
204
  private avayaIPOService;
197
205
  private cdr;
@@ -200,9 +208,22 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
200
208
  private entitiesSearchService;
201
209
  private snugdeskAuthService;
202
210
  hostDarkMode: boolean;
211
+ get hostModeStandalone(): boolean;
212
+ get hostModePopup(): boolean;
203
213
  private readonly STORAGE_KEY;
204
214
  isVisible: boolean;
215
+ /**
216
+ * Render mode for the widget shell:
217
+ * - 'popup' (default): owns no dimensions — fills whatever box the host gives it (e.g. the snugdesk-app
218
+ * header popover), with a min-size guard and its own internal scroll. Preserves 100% of current behavior.
219
+ * - 'standalone': provides its own full-page frame — a centered card on desktop, full-bleed on mobile —
220
+ * for running the softphone independently.
221
+ */
222
+ displayMode: 'popup' | 'standalone';
205
223
  configurationMode?: string;
224
+ /** Recording upload strategy: 'complete' (one upload at call end) or 'chunked' (live-streamed
225
+ * over the recording WebSocket, survives a dead tab). Defaults to APP_CONFIG.RECORDING_UPLOAD_MODE. */
226
+ recordingUploadMode?: 'complete' | 'chunked';
206
227
  avayaIPOServerIP?: string;
207
228
  avayaIPOServerPort?: number;
208
229
  avayaIPOServerStunServerIP?: string;
@@ -212,8 +233,34 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
212
233
  token?: string;
213
234
  tenantId: string;
214
235
  userId: string;
236
+ /**
237
+ * Optional Avaya IP Office credentials. When BOTH `extension` and `password` are supplied (via the
238
+ * host binding), the widget patches the login form and auto-logs-in once — no manual login needed.
239
+ * If they are not supplied, the widget falls back to any saved localStorage session, otherwise it
240
+ * shows the login form as before.
241
+ */
242
+ extension?: string;
243
+ password?: string;
244
+ /** Show/hide the History tab. Default true keeps current behavior. */
245
+ showHistory: boolean;
246
+ /** Show/hide the Contacts tab. Default true keeps current behavior. */
247
+ showContacts: boolean;
248
+ /**
249
+ * The bottom tab bar only earns its space when at least one of History/Contacts is visible.
250
+ * With both hidden only Keypad (the default view) would remain, so the whole bar is hidden.
251
+ */
252
+ get showTabBar(): boolean;
215
253
  notificationEvent: EventEmitter<number>;
216
- readonly avayaLogoUrl: string;
254
+ /**
255
+ * Fires when an inbound call starts ringing, so the host app can open/focus the widget popover.
256
+ * Payload: the call id, the caller's number, and the resolved caller name (null if not yet known).
257
+ */
258
+ incomingCall: EventEmitter<{
259
+ callId: string;
260
+ number: string;
261
+ name: string | null;
262
+ }>;
263
+ readonly widgetVersion: "0.2.4";
217
264
  isReconnectingInProgress: boolean;
218
265
  isFailoverInProgress: boolean;
219
266
  isFailbackInProgress: boolean;
@@ -227,23 +274,30 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
227
274
  private awlScriptPromise?;
228
275
  loginForm: FormGroup;
229
276
  activeTab: 'history' | 'contacts' | 'keypad' | 'settings';
277
+ private previousTab;
230
278
  private loginSub?;
231
279
  private incomingCallSub?;
232
280
  private callStateSub?;
233
281
  hideTabs: boolean;
234
282
  darkModeEnabled: boolean;
235
283
  activeCallNumber: string | null;
284
+ /** Entity id of the current call's counterpart (resolved via OpenSearch); sent with the
285
+ * chunked-recording socket so chunks land under <tenantId>/<entityId>/avaya-ipo-chunks/. */
286
+ activeCallEntityId: string | null;
236
287
  incomingCallName: string | null;
237
288
  incomingNameResolved: boolean;
238
289
  activeCallName: string | null;
239
290
  authErrorMessage: string;
240
291
  authLoading: boolean;
241
292
  private hasInitialized;
293
+ private autoLoginAttempted;
242
294
  private callLogIndex;
243
295
  private pendingDisconnectSide;
244
296
  private callStartTimes;
245
297
  constructor(formBuilder: FormBuilder, avayaIPOService: AvayaIPOService, cdr: ChangeDetectorRef, countryService: CountryService, phoneNumberLookupService: PhoneNumberLookupService, entitiesSearchService: EntitiesSearchService, snugdeskAuthService: SnugdeskAuthenticationService);
246
298
  ngOnInit(): Promise<void>;
299
+ ngOnChanges(changes: SimpleChanges): void;
300
+ private ensureVisibleTab;
247
301
  private initAfterAuth;
248
302
  private authenticateWithToken;
249
303
  onAuthLoginClick(): Promise<void>;
@@ -251,6 +305,8 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
251
305
  onLogout(): void;
252
306
  private handleLoginStatus;
253
307
  selectTab(tab: 'history' | 'contacts' | 'keypad' | 'settings'): void;
308
+ /** Leave Settings and return to the screen the user came from (guards against a now-hidden tab). */
309
+ closeSettings(): void;
254
310
  onHistoryMakeCall(payload: {
255
311
  dialOut: string;
256
312
  name?: string;
@@ -260,6 +316,15 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
260
316
  dialOut: string;
261
317
  name?: string;
262
318
  }): void;
319
+ /**
320
+ * Public API — place an outbound call programmatically (e.g. click-to-call from the host app).
321
+ * Switches to the keypad view and dials `number`. Requires the widget to be registered;
322
+ * if it is still on the login screen the call is skipped with a warning.
323
+ *
324
+ * Usage from the host app (via @ViewChild(AvayaIPOWidgetComponent)):
325
+ * this.avayaWidget?.makeCall('9876543210');
326
+ */
327
+ makeCall(number: string): void;
263
328
  onPhoneEndCall(): void;
264
329
  onDeviceChange(change: {
265
330
  audioInputId: string;
@@ -274,17 +339,25 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
274
339
  private getOpenSearchCallerName;
275
340
  private normalizePhoneForSearch;
276
341
  private persistSession;
342
+ private hasInputCredentials;
343
+ /**
344
+ * Auto-login when both `extension` and `password` are supplied via @Input. Fires at most once for the
345
+ * widget's lifetime (so a manual logout is respected and we never loop). Returns true if it kicked off
346
+ * a login, so the caller can skip the localStorage fallback.
347
+ */
348
+ private tryAutoLoginFromInputs;
277
349
  private restoreSession;
278
350
  private restoreThemePreference;
279
351
  private clearSession;
280
352
  private loadAwlScript;
281
353
  static ɵfac: i0.ɵɵFactoryDeclaration<AvayaIPOWidgetComponent, never>;
282
- static ɵcmp: i0.ɵɵComponentDeclaration<AvayaIPOWidgetComponent, "snugdesk-avaya-ipo-widget", never, { "isVisible": { "alias": "isVisible"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; "avayaIPOServerIP": { "alias": "avayaIPOServerIP"; "required": false; }; "avayaIPOServerPort": { "alias": "avayaIPOServerPort"; "required": false; }; "avayaIPOServerStunServerIP": { "alias": "avayaIPOServerStunServerIP"; "required": false; }; "avayaIPOServerStunServerPort": { "alias": "avayaIPOServerStunServerPort"; "required": false; }; "avayaIPOServerTurnServerIP": { "alias": "avayaIPOServerTurnServerIP"; "required": false; }; "avayaIPOServerTurnServerPort": { "alias": "avayaIPOServerTurnServerPort"; "required": false; }; "token": { "alias": "token"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "userId": { "alias": "userId"; "required": false; }; }, { "notificationEvent": "notificationEvent"; }, never, never, false, never>;
354
+ static ɵcmp: i0.ɵɵComponentDeclaration<AvayaIPOWidgetComponent, "snugdesk-avaya-ipo-widget", never, { "isVisible": { "alias": "isVisible"; "required": false; }; "displayMode": { "alias": "displayMode"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; "recordingUploadMode": { "alias": "recordingUploadMode"; "required": false; }; "avayaIPOServerIP": { "alias": "avayaIPOServerIP"; "required": false; }; "avayaIPOServerPort": { "alias": "avayaIPOServerPort"; "required": false; }; "avayaIPOServerStunServerIP": { "alias": "avayaIPOServerStunServerIP"; "required": false; }; "avayaIPOServerStunServerPort": { "alias": "avayaIPOServerStunServerPort"; "required": false; }; "avayaIPOServerTurnServerIP": { "alias": "avayaIPOServerTurnServerIP"; "required": false; }; "avayaIPOServerTurnServerPort": { "alias": "avayaIPOServerTurnServerPort"; "required": false; }; "token": { "alias": "token"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "userId": { "alias": "userId"; "required": false; }; "extension": { "alias": "extension"; "required": false; }; "password": { "alias": "password"; "required": false; }; "showHistory": { "alias": "showHistory"; "required": false; }; "showContacts": { "alias": "showContacts"; "required": false; }; }, { "notificationEvent": "notificationEvent"; "incomingCall": "incomingCall"; }, never, never, false, never>;
283
355
  }
284
356
 
285
357
  declare class CallHistoryComponent implements OnInit {
286
- private http;
287
358
  private cdr;
359
+ private appSync;
360
+ private auth;
288
361
  mode: 'dial' | 'transfer';
289
362
  tenantId?: string;
290
363
  agentId?: string;
@@ -293,17 +366,19 @@ declare class CallHistoryComponent implements OnInit {
293
366
  name?: string;
294
367
  }>;
295
368
  transferEv: EventEmitter<any>;
296
- private readonly CALL_HISTORY_API_URL;
297
369
  showHistoryLoader: boolean;
298
370
  callHistory: any[];
299
371
  searchTerm: string;
300
372
  recentCallactiveTab: 'recentCall' | 'missedCall';
301
373
  selectedCall: any;
302
- constructor(http: HttpClient, cdr: ChangeDetectorRef);
374
+ private readonly LIST_PHONE_INTERACTIONS_QUERY;
375
+ constructor(cdr: ChangeDetectorRef, appSync: AppSyncHelperService, auth: SnugdeskAuthenticationService);
303
376
  ngOnInit(): Promise<void>;
304
377
  recentSelectTab(tab: 'recentCall' | 'missedCall'): void;
305
378
  loadCallHistory(): Promise<void>;
306
- getCallHistory(tenantId: string, agentId: string): Promise<any>;
379
+ private fetchPhoneInteractions;
380
+ private mapInteractionToHistoryItem;
381
+ private safeParse;
307
382
  makeCall(phoneNumber: string, name?: string): void;
308
383
  get callerDropped(): any[];
309
384
  get filteredRecent(): any[];
@@ -321,9 +396,6 @@ declare class CallHistoryComponent implements OnInit {
321
396
  selectFromHistory(item: any): void;
322
397
  private resolveDialable;
323
398
  private resolveName;
324
- private formatDialOutFromInput;
325
- private getTenantIdFromSession;
326
- private getUserIdFromSession;
327
399
  getPhoneDisplay(item: any): string;
328
400
  getPhoneBadge(item: any): string;
329
401
  private getInitials;
@@ -337,28 +409,47 @@ type TranscriptLine = {
337
409
  speaker?: string;
338
410
  text?: string;
339
411
  };
340
- declare class CallDetailsComponent {
341
- private http;
412
+ /**
413
+ * Shows the same AI call analysis as snugdesk-app's conversation view: the data is read
414
+ * from the Interaction record (metadata.aiAnalysis), which the server-side pipeline fills
415
+ * after the recording is uploaded — no client-side transcription is run here.
416
+ */
417
+ declare class CallDetailsComponent implements OnChanges {
418
+ private appSync;
342
419
  call: any;
343
420
  transcriptLines: TranscriptLine[];
344
- summaryText: string;
421
+ conversationSummary: string[];
422
+ nextActions: string[];
423
+ keyConcerns: string[];
424
+ callType: string;
425
+ customerIntent: string;
345
426
  customerSentiment: string;
346
- isTranscribing: boolean;
347
- transcriptionError: string;
427
+ aiConfidenceScore: number | null;
428
+ summaryText: string;
429
+ aiProcessingStatus: string;
430
+ hasAnalysis: boolean;
431
+ isRefreshing: boolean;
432
+ refreshError: string;
348
433
  isTranscriptFullscreen: boolean;
349
- hasGeneratedTranscript: boolean;
350
- private readonly ANALYZE_CALL_API;
351
- constructor(http: HttpClient);
434
+ private readonly GET_INTERACTION_QUERY;
435
+ constructor(appSync: AppSyncHelperService);
436
+ ngOnChanges(changes: SimpleChanges): void;
437
+ get isAnalysisPending(): boolean;
352
438
  getBadge(): string;
353
439
  getDisplayName(): string;
354
440
  getPhone(): string;
355
441
  getTranscriptSpeaker(line: TranscriptLine): string;
356
- runTranscription(): Promise<void>;
357
- private normalizeTranscript;
358
442
  getSentimentEmoji(): string;
359
- private parseSpeakerLine;
443
+ /** Re-read the Interaction record (the AI pipeline fills metadata.aiAnalysis asynchronously). */
444
+ refreshAnalysis(): Promise<void>;
360
445
  toggleTranscriptFullscreen(): void;
361
- private getRecordingFilename;
446
+ /** Pull the structured AI analysis off the interaction's metadata — same shape snugdesk-app reads. */
447
+ private parseAnalysisFromCall;
448
+ private normalizeText;
449
+ private normalizeBulletItems;
450
+ private normalizeTranscript;
451
+ private parseSpeakerLine;
452
+ private safeParse;
362
453
  static ɵfac: i0.ɵɵFactoryDeclaration<CallDetailsComponent, never>;
363
454
  static ɵcmp: i0.ɵɵComponentDeclaration<CallDetailsComponent, "app-call-details", never, { "call": { "alias": "call"; "required": false; }; }, {}, never, never, false, never>;
364
455
  }
@@ -447,6 +538,7 @@ declare class SettingsComponent implements OnInit, OnDestroy {
447
538
  logout: EventEmitter<void>;
448
539
  audioInputs: MediaDeviceInfo[];
449
540
  audioOutputs: MediaDeviceInfo[];
541
+ readonly widgetVersion: "0.2.4";
450
542
  ngOnInit(): void;
451
543
  onLogout(): void;
452
544
  onToggleDarkMode(): void;
@@ -482,35 +574,72 @@ interface CallMetadata {
482
574
  agentId: string;
483
575
  phoneNumber: string;
484
576
  callId: string;
577
+ /** Entity id of the call counterpart, when the widget has resolved one (chunked recordings
578
+ * use it so chunks land under <tenantId>/<entityId>/avaya-ipo-chunks/). */
579
+ entityId?: string | null;
485
580
  }
486
581
 
582
+ type RecordingUploadMode = 'complete' | 'chunked';
487
583
  interface RecordingSession {
488
584
  audioContext: AudioContext;
489
585
  recordingStream: MediaStreamAudioDestinationNode;
490
586
  recorder?: MediaRecorder | null;
491
587
  metadata: CallMetadata;
492
588
  stopping: boolean;
493
- chunkIndex: number;
494
- chunkTimer?: number;
589
+ chunks: Blob[];
590
+ mimeType: string;
591
+ uploaded: boolean;
592
+ mode: RecordingUploadMode;
593
+ socket?: WebSocket | null;
594
+ seq: number;
595
+ pendingChunks: string[];
596
+ sentAny: boolean;
597
+ reconnectTimer?: any;
598
+ reconnectAttempts: number;
599
+ sourceNodes: AudioNode[];
600
+ /** Index into `chunks` up to which slices have been streamed (rewound to 0 on reconnect). */
601
+ streamCursor: number;
602
+ pumping: boolean;
603
+ everConnected: boolean;
604
+ completedSent: boolean;
495
605
  }
496
606
  declare class RecordingManagerService {
497
607
  private http;
498
608
  private sessions;
499
609
  private readonly MIME_TYPE_PREFERRED;
500
610
  private readonly MIME_TYPE_FALLBACK;
501
- private readonly CHUNK_DURATION_MS;
611
+ private readonly TIMESLICE_MS;
612
+ private readonly CHUNKED_TIMESLICE_MS;
613
+ private readonly CHUNKED_AUDIO_BPS;
614
+ private readonly MAX_WS_DATA_CHARS;
502
615
  private readonly AUDIO_CONTEXT_CLOSE_DELAY_MS;
503
- private readonly CALL_HISTORY_API_URL;
616
+ private readonly SOCKET_RECONNECT_DELAY_MS;
617
+ private readonly CALL_COMPLETED_DELAY_MS;
618
+ private readonly SOCKET_MAX_RECONNECT_ATTEMPTS;
619
+ private readonly SOCKET_FINALIZE_GRACE_MS;
620
+ private readonly RECORDING_API_URL;
621
+ private readonly RECORDING_WS_URL;
504
622
  constructor(http: HttpClient);
505
- startRecording(localMediaStream: MediaStream, remoteMediaStream: MediaStream, metadata: CallMetadata): RecordingSession | undefined;
623
+ startRecording(localMediaStream: MediaStream, remoteMediaStream: MediaStream, metadata: CallMetadata, mode?: RecordingUploadMode): RecordingSession | undefined;
506
624
  getSession(callId: string): RecordingSession | undefined;
507
625
  stopRecording(callId: string): void;
508
- private startNextChunk;
626
+ private finalizeRecording;
627
+ /**
628
+ * Rewire fresh local/remote streams into the SAME recording destination. The MediaRecorder (and
629
+ * therefore the single WebM byte stream, the socket and the seq counter) continue uninterrupted —
630
+ * restarting the recorder would inject a second WebM header mid-file and break playback of the
631
+ * stitched recording.
632
+ */
633
+ private rebindMedia;
634
+ private openRecordingSocket;
635
+ /** Stream session.chunks in strict order; safe to call repeatedly (single active pump). */
636
+ private pumpChunks;
637
+ private streamChunk;
638
+ private flushPendingChunks;
639
+ private finalizeChunked;
509
640
  private uploadCallRecording;
510
641
  private convertBlobToBase64;
511
642
  private generateFilename;
512
- private generateChunkFilename;
513
- private normalizePhoneNumberForUpload;
514
643
  static ɵfac: i0.ɵɵFactoryDeclaration<RecordingManagerService, never>;
515
644
  static ɵprov: i0.ɵɵInjectableDeclaration<RecordingManagerService>;
516
645
  }
@@ -530,18 +659,19 @@ declare class TranscriptionStreamService implements OnDestroy {
530
659
  private readonly BUFFER_SIZE;
531
660
  private readonly SILENCE_RMS_THRESHOLD;
532
661
  private readonly VOICE_RMS_THRESHOLD;
662
+ private readonly CUSTOMER_SILENCE_RMS_THRESHOLD;
663
+ private readonly CUSTOMER_VOICE_RMS_THRESHOLD;
533
664
  private readonly NOISE_FLOOR_MULTIPLIER;
534
665
  private readonly NOISE_FLOOR_SMOOTHING;
535
- private readonly CHUNK_INTERVAL_MS;
666
+ private readonly MIN_VOICE_FRAMES;
536
667
  private readonly CUSTOM_WS_URL;
537
- private readonly CUSTOM_WS_MIME_TYPE;
538
- private readonly LANGUAGE_CODE;
539
- private readonly ALT_LANGUAGE_CODES;
668
+ private readonly LANGUAGE;
540
669
  private readonly TRANSCRIPTION_MODEL;
541
670
  constructor();
542
671
  ngOnDestroy(): void;
543
672
  startSession(callId: string, localStream: MediaStream, remoteStream: MediaStream, allowSendBinary?: boolean): Promise<void>;
544
673
  stopSession(callId: string): void;
674
+ destroyAll(): void;
545
675
  enableBinary(callId: string): void;
546
676
  setStreamMuted(callId: string, label: 'agent' | 'customer', muted: boolean): void;
547
677
  private mixToMono;
@@ -549,8 +679,6 @@ declare class TranscriptionStreamService implements OnDestroy {
549
679
  private encodePcm16;
550
680
  private downsampleBuffer;
551
681
  private queueAudio;
552
- private flushPendingAudio;
553
- private mergeChunks;
554
682
  private handleTranscriptPayload;
555
683
  private parseSpeakerLine;
556
684
  private createStreamSession;
@@ -558,7 +686,7 @@ declare class TranscriptionStreamService implements OnDestroy {
558
686
  static ɵprov: i0.ɵɵInjectableDeclaration<TranscriptionStreamService>;
559
687
  }
560
688
 
561
- declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
689
+ declare class PhoneComponent implements OnInit, AfterViewInit, OnDestroy {
562
690
  private cdr;
563
691
  private formBuilder;
564
692
  private avayaIpoService;
@@ -583,6 +711,9 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
583
711
  turnIp?: string;
584
712
  turnPort?: number;
585
713
  configurationMode?: string;
714
+ recordingUploadMode?: 'complete' | 'chunked';
715
+ /** Entity id of the call counterpart (resolved by the shell) — included in recording metadata. */
716
+ entityId?: string | null;
586
717
  makeCallEv: EventEmitter<string>;
587
718
  endCallEv: EventEmitter<void>;
588
719
  audioElement: any;
@@ -602,7 +733,6 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
602
733
  private pendingTranscriptionCallId;
603
734
  private pendingTranscriptionAllowBinary;
604
735
  private lastPartialIndex;
605
- private pendingIncomingCall;
606
736
  dialForm: FormGroup;
607
737
  directoryForm: FormGroup;
608
738
  showDirectoryPhonebook: boolean;
@@ -649,7 +779,6 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
649
779
  get isConnecting(): boolean;
650
780
  constructor(cdr: ChangeDetectorRef, formBuilder: FormBuilder, avayaIpoService: AvayaIPOService, authenticationService: AuthenticationService, recordingManagerService: RecordingManagerService, transcriptionStreamService: TranscriptionStreamService);
651
781
  ngOnInit(): void;
652
- ngOnChanges(changes: SimpleChanges): void;
653
782
  ngAfterViewInit(): void;
654
783
  ngOnDestroy(): void;
655
784
  makeCall(): void;
@@ -720,8 +849,10 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
720
849
  private formatDialOutFromInput;
721
850
  private formatTransferTargetFromInput;
722
851
  private startRecordingForCall;
852
+ /** Per-embed [recordingUploadMode] wins; otherwise the APP_CONFIG default applies. */
853
+ private resolvedRecordingMode;
723
854
  static ɵfac: i0.ɵɵFactoryDeclaration<PhoneComponent, never>;
724
- static ɵcmp: i0.ɵɵComponentDeclaration<PhoneComponent, "app-phone", never, { "contacts": { "alias": "contacts"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "agentId": { "alias": "agentId"; "required": false; }; "isActiveCall": { "alias": "isActiveCall"; "required": false; }; "activeCallNumber": { "alias": "activeCallNumber"; "required": false; }; "incomingCallName": { "alias": "incomingCallName"; "required": false; }; "incomingNameResolved": { "alias": "incomingNameResolved"; "required": false; }; "activeCallName": { "alias": "activeCallName"; "required": false; }; "serverIp": { "alias": "serverIp"; "required": false; }; "serverPort": { "alias": "serverPort"; "required": false; }; "stunIp": { "alias": "stunIp"; "required": false; }; "stunPort": { "alias": "stunPort"; "required": false; }; "turnIp": { "alias": "turnIp"; "required": false; }; "turnPort": { "alias": "turnPort"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; }, { "callScreenChange": "callScreenChange"; "makeCallEv": "makeCallEv"; "endCallEv": "endCallEv"; }, never, never, false, never>;
855
+ static ɵcmp: i0.ɵɵComponentDeclaration<PhoneComponent, "app-phone", never, { "contacts": { "alias": "contacts"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "agentId": { "alias": "agentId"; "required": false; }; "isActiveCall": { "alias": "isActiveCall"; "required": false; }; "activeCallNumber": { "alias": "activeCallNumber"; "required": false; }; "incomingCallName": { "alias": "incomingCallName"; "required": false; }; "incomingNameResolved": { "alias": "incomingNameResolved"; "required": false; }; "activeCallName": { "alias": "activeCallName"; "required": false; }; "serverIp": { "alias": "serverIp"; "required": false; }; "serverPort": { "alias": "serverPort"; "required": false; }; "stunIp": { "alias": "stunIp"; "required": false; }; "stunPort": { "alias": "stunPort"; "required": false; }; "turnIp": { "alias": "turnIp"; "required": false; }; "turnPort": { "alias": "turnPort"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; "recordingUploadMode": { "alias": "recordingUploadMode"; "required": false; }; "entityId": { "alias": "entityId"; "required": false; }; }, { "callScreenChange": "callScreenChange"; "makeCallEv": "makeCallEv"; "endCallEv": "endCallEv"; }, never, never, false, never>;
725
856
  }
726
857
 
727
858
  declare class PhoneIdleComponent {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snugdesk/avaya-ipo-widget",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Snugdesk - Avaya IPO widget for Angular",
5
5
  "peerDependencies": {
6
6
  "@angular/animations": ">=19.0.0",
File without changes
@@ -1,20 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
2
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
4
- <desc>Created with Fabric.js 5.2.4</desc>
5
- <defs>
6
- </defs>
7
- <rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
8
- <g transform="matrix(1 0 0 1 540 540)" id="46946dc3-9491-43cb-8fe7-5b8ffbba78af" >
9
- <rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
10
- </g>
11
- <g transform="matrix(1 0 0 1 540 540)" id="863c060c-d63b-4daf-a3bc-022136480777" >
12
- </g>
13
- <g transform="matrix(1 0 0 1 540 540)" id="facf6309-efdf-434e-a753-661bb2577e88" >
14
- <polygon style="stroke: rgb(0,0,0); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(218,40,28); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" points="-232.07,221.69 106.75,221.69 161.6,357.36 -295.67,357.36 -368.7,513.14 -570.6,513.14 -69.8,-513.14 69.88,-513.14 570.6,513.14 368.77,513.14 -0.04,-279.29 -232.07,221.69 -232.07,221.69 -232.07,221.69 " />
15
- </g>
16
- <g transform="matrix(NaN NaN NaN NaN 0 0)" >
17
- <g style="" >
18
- </g>
19
- </g>
20
- </svg>
@@ -1,16 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
2
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
4
- <desc>Created with Fabric.js 5.2.4</desc>
5
- <defs>
6
- </defs>
7
- <rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
8
- <g transform="matrix(1 0 0 1 540 540)" id="46946dc3-9491-43cb-8fe7-5b8ffbba78af" >
9
- <rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
10
- </g>
11
- <g transform="matrix(1 0 0 1 540 540)" id="863c060c-d63b-4daf-a3bc-022136480777" >
12
- </g>
13
- <g transform="matrix(1 0 0 1 540 540)" id="facf6309-efdf-434e-a753-661bb2577e88" >
14
- <polygon style="stroke: rgb(0,0,0); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(136,136,136); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" points="-232.07,221.69 106.75,221.69 161.6,357.36 -295.67,357.36 -368.7,513.14 -570.6,513.14 -69.8,-513.14 69.88,-513.14 570.6,513.14 368.77,513.14 -0.04,-279.29 -232.07,221.69 -232.07,221.69 -232.07,221.69 " />
15
- </g>
16
- </svg>