@ipcom/asterisk-ari 0.0.139 → 0.0.140

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/dist/esm/index.js CHANGED
@@ -571,30 +571,55 @@ var require_backoff = __commonJS({
571
571
  });
572
572
 
573
573
  // src/ari-client/baseClient.ts
574
- import axios from "axios";
574
+ import axios, {
575
+ isAxiosError
576
+ } from "axios";
577
+ var HTTPError = class extends Error {
578
+ constructor(message, status, method, url) {
579
+ super(message);
580
+ this.status = status;
581
+ this.method = method;
582
+ this.url = url;
583
+ this.name = "HTTPError";
584
+ }
585
+ };
575
586
  var BaseClient = class {
587
+ /**
588
+ * Creates a new BaseClient instance.
589
+ *
590
+ * @param {string} baseUrl - The base URL for the API
591
+ * @param {string} username - Username for authentication
592
+ * @param {string} password - Password for authentication
593
+ * @param {number} [timeout=5000] - Request timeout in milliseconds
594
+ * @throws {Error} If the base URL format is invalid
595
+ */
576
596
  constructor(baseUrl, username, password, timeout = 5e3) {
577
597
  this.baseUrl = baseUrl;
578
598
  this.username = username;
579
599
  this.password = password;
580
600
  if (!/^https?:\/\/.+/.test(baseUrl)) {
581
- throw new Error(
582
- "Invalid base URL. It must start with http:// or https://"
583
- );
601
+ throw new Error("Invalid base URL. It must start with http:// or https://");
584
602
  }
585
603
  this.client = axios.create({
586
604
  baseURL: baseUrl,
587
605
  auth: { username, password },
588
- timeout
606
+ timeout,
607
+ headers: {
608
+ "Content-Type": "application/json"
609
+ }
589
610
  });
590
611
  this.addInterceptors();
612
+ console.log(`BaseClient initialized for ${baseUrl}`);
591
613
  }
592
614
  client;
615
+ /**
616
+ * Gets the base URL of the client.
617
+ */
593
618
  getBaseUrl() {
594
619
  return this.baseUrl;
595
620
  }
596
621
  /**
597
- * Retorna as credenciais configuradas.
622
+ * Gets the configured credentials.
598
623
  */
599
624
  getCredentials() {
600
625
  return {
@@ -604,123 +629,159 @@ var BaseClient = class {
604
629
  };
605
630
  }
606
631
  /**
607
- * Adds interceptors to the Axios instance.
632
+ * Adds request and response interceptors to the Axios instance.
608
633
  */
609
634
  addInterceptors() {
610
635
  this.client.interceptors.request.use(
611
636
  (config) => {
637
+ console.log(`[Request] ${config.method?.toUpperCase()} ${config.url}`);
612
638
  return config;
613
639
  },
614
640
  (error) => {
615
- console.error("[Request Error]", error.message);
616
- return Promise.reject(error);
641
+ const message = this.getErrorMessage(error);
642
+ console.error("[Request Error]", message);
643
+ return Promise.reject(new HTTPError(message));
617
644
  }
618
645
  );
619
646
  this.client.interceptors.response.use(
620
- (response) => response,
647
+ (response) => {
648
+ console.log(`[Response] ${response.status} ${response.config.url}`);
649
+ return response;
650
+ },
621
651
  (error) => {
622
- const status = error.response?.status;
623
- const message = error.response?.data?.message || error.message || "Unknown error";
624
- const errorDetails = {
625
- status,
626
- message,
627
- url: error.config?.url || "Unknown URL",
628
- method: error.config?.method?.toUpperCase() || "Unknown Method"
629
- };
630
- if (status === 404) {
631
- console.warn(`[404] Not Found: ${errorDetails.url}`);
632
- } else if (status >= 500) {
633
- console.error(`[500] Server Error: ${errorDetails.url}`);
634
- } else {
635
- console.warn(
636
- `[Response Error] ${errorDetails.method} ${errorDetails.url}: ${message}`
637
- );
652
+ if (isAxiosError(error)) {
653
+ const status = error.response?.status ?? 0;
654
+ const method = error.config?.method?.toUpperCase() ?? "UNKNOWN";
655
+ const url = error.config?.url ?? "unknown-url";
656
+ const message2 = error.response?.data?.message || error.message || "Unknown error";
657
+ if (status === 404) {
658
+ console.warn(`[404] Not Found: ${url}`);
659
+ } else if (status >= 500) {
660
+ console.error(`[${status}] Server Error: ${url}`);
661
+ } else if (status > 0) {
662
+ console.warn(`[${status}] ${method} ${url}: ${message2}`);
663
+ } else {
664
+ console.error(`[Network] Request failed: ${message2}`);
665
+ }
666
+ throw new HTTPError(message2, status || void 0, method, url);
638
667
  }
639
- return Promise.reject(
640
- new Error(
641
- `[Error] ${errorDetails.method} ${errorDetails.url} - ${message} (Status: ${status})`
642
- )
643
- );
668
+ const message = this.getErrorMessage(error);
669
+ console.error("[Unexpected Error]", message);
670
+ throw new Error(message);
644
671
  }
645
672
  );
646
673
  }
647
674
  /**
648
675
  * Executes a GET request.
649
- * @param path - The API endpoint path.
650
- * @param config - Optional Axios request configuration.
676
+ *
677
+ * @param path - API endpoint path
678
+ * @param config - Optional Axios request configuration
679
+ * @returns Promise with the response data
651
680
  */
652
681
  async get(path, config) {
653
682
  try {
654
683
  const response = await this.client.get(path, config);
655
684
  return response.data;
656
685
  } catch (error) {
657
- this.handleRequestError(error);
686
+ throw this.handleRequestError(error);
658
687
  }
659
688
  }
660
689
  /**
661
690
  * Executes a POST request.
662
- * @param path - The API endpoint path.
663
- * @param data - Optional payload to send with the request.
664
- * @param config - Optional Axios request configuration.
691
+ *
692
+ * @param path - API endpoint path
693
+ * @param data - Request payload
694
+ * @param config - Optional Axios request configuration
695
+ * @returns Promise with the response data
665
696
  */
666
697
  async post(path, data, config) {
667
698
  try {
668
699
  const response = await this.client.post(path, data, config);
669
700
  return response.data;
670
701
  } catch (error) {
671
- this.handleRequestError(error);
702
+ throw this.handleRequestError(error);
672
703
  }
673
704
  }
674
705
  /**
675
706
  * Executes a PUT request.
676
- * @param path - The API endpoint path.
677
- * @param data - Payload to send with the request.
678
- * @param config - Optional Axios request configuration.
707
+ *
708
+ * @param path - API endpoint path
709
+ * @param data - Request payload
710
+ * @param config - Optional Axios request configuration
711
+ * @returns Promise with the response data
679
712
  */
680
713
  async put(path, data, config) {
681
714
  try {
682
715
  const response = await this.client.put(path, data, config);
683
716
  return response.data;
684
717
  } catch (error) {
685
- this.handleRequestError(error);
718
+ throw this.handleRequestError(error);
686
719
  }
687
720
  }
688
721
  /**
689
722
  * Executes a DELETE request.
690
- * @param path - The API endpoint path.
691
- * @param config - Optional Axios request configuration.
723
+ *
724
+ * @param path - API endpoint path
725
+ * @param config - Optional Axios request configuration
726
+ * @returns Promise with the response data
692
727
  */
693
728
  async delete(path, config) {
694
729
  try {
695
730
  const response = await this.client.delete(path, config);
696
731
  return response.data;
697
732
  } catch (error) {
698
- this.handleRequestError(error);
733
+ throw this.handleRequestError(error);
699
734
  }
700
735
  }
701
736
  /**
702
- * Handles errors for HTTP requests.
703
- * @param error - The error to handle.
737
+ * Handles and formats error messages from various error types.
738
+ */
739
+ getErrorMessage(error) {
740
+ if (isAxiosError(error)) {
741
+ return error.response?.data?.message || error.message || "HTTP Error";
742
+ }
743
+ if (error instanceof Error) {
744
+ return error.message;
745
+ }
746
+ return "An unknown error occurred";
747
+ }
748
+ /**
749
+ * Handles errors from HTTP requests.
704
750
  */
705
751
  handleRequestError(error) {
706
- if (axios.isAxiosError(error)) {
707
- console.error(`[HTTP Error] ${error.message}`);
708
- throw new Error(error.message || "HTTP Error");
709
- } else {
710
- console.error(`[Unexpected Error] ${error}`);
711
- throw error;
752
+ const message = this.getErrorMessage(error);
753
+ if (isAxiosError(error)) {
754
+ throw new HTTPError(
755
+ message,
756
+ error.response?.status,
757
+ error.config?.method?.toUpperCase(),
758
+ error.config?.url
759
+ );
712
760
  }
761
+ throw new Error(message);
713
762
  }
714
763
  /**
715
764
  * Sets custom headers for the client instance.
716
- * Useful for adding dynamic tokens or specific API headers.
717
- * @param headers - Headers to merge with existing configuration.
718
765
  */
719
766
  setHeaders(headers) {
720
767
  this.client.defaults.headers.common = {
721
768
  ...this.client.defaults.headers.common,
722
769
  ...headers
723
770
  };
771
+ console.log("Updated client headers");
772
+ }
773
+ /**
774
+ * Gets the current request timeout setting.
775
+ */
776
+ getTimeout() {
777
+ return this.client.defaults.timeout || 5e3;
778
+ }
779
+ /**
780
+ * Updates the request timeout setting.
781
+ */
782
+ setTimeout(timeout) {
783
+ this.client.defaults.timeout = timeout;
784
+ console.log(`Updated timeout to ${timeout}ms`);
724
785
  }
725
786
  };
726
787
 
@@ -998,102 +1059,199 @@ function toQueryParams2(options) {
998
1059
  }
999
1060
 
1000
1061
  // src/ari-client/resources/channels.ts
1062
+ import { isAxiosError as isAxiosError2 } from "axios";
1063
+ var getErrorMessage = (error) => {
1064
+ if (isAxiosError2(error)) {
1065
+ return error.response?.data?.message || error.message || "An axios error occurred";
1066
+ }
1067
+ if (error instanceof Error) {
1068
+ return error.message;
1069
+ }
1070
+ return "An unknown error occurred";
1071
+ };
1001
1072
  var ChannelInstance = class {
1002
- // ID do canal
1003
- constructor(client, baseClient, channelId = `channel-${Date.now()}`) {
1073
+ constructor(client, baseClient, channelId) {
1004
1074
  this.client = client;
1005
1075
  this.baseClient = baseClient;
1006
- this.channelId = channelId;
1007
1076
  this.id = channelId || `channel-${Date.now()}`;
1077
+ console.log(`Channel instance initialized with ID: ${this.id}`);
1008
1078
  }
1009
1079
  eventEmitter = new EventEmitter();
1010
1080
  channelData = null;
1011
1081
  id;
1012
1082
  /**
1013
- * Registra um listener para eventos específicos deste canal.
1083
+ * Registers an event listener for specific channel events
1014
1084
  */
1015
1085
  on(event, listener) {
1086
+ if (!event) {
1087
+ throw new Error("Event type is required");
1088
+ }
1016
1089
  const wrappedListener = (data) => {
1017
1090
  if ("channel" in data && data.channel?.id === this.id) {
1018
1091
  listener(data);
1019
1092
  }
1020
1093
  };
1021
1094
  this.eventEmitter.on(event, wrappedListener);
1095
+ console.log(`Event listener registered for ${event} on channel ${this.id}`);
1022
1096
  }
1023
1097
  /**
1024
- * Registra um listener único para eventos específicos deste canal.
1098
+ * Registers a one-time event listener
1025
1099
  */
1026
1100
  once(event, listener) {
1101
+ if (!event) {
1102
+ throw new Error("Event type is required");
1103
+ }
1027
1104
  const wrappedListener = (data) => {
1028
1105
  if ("channel" in data && data.channel?.id === this.id) {
1029
1106
  listener(data);
1030
1107
  }
1031
1108
  };
1032
1109
  this.eventEmitter.once(event, wrappedListener);
1110
+ console.log(`One-time event listener registered for ${event} on channel ${this.id}`);
1033
1111
  }
1034
1112
  /**
1035
- * Remove um listener para eventos específicos deste canal.
1113
+ * Removes event listener(s) for a specific WebSocket event type.
1114
+ * If a specific listener is provided, only that listener is removed.
1115
+ * Otherwise, all listeners for the given event type are removed.
1116
+ *
1117
+ * @param {T} event - The type of WebSocket event to remove listener(s) for
1118
+ * @param {Function} [listener] - Optional specific listener to remove
1119
+ * @throws {Error} If no event type is provided
1036
1120
  */
1037
1121
  off(event, listener) {
1122
+ if (!event) {
1123
+ throw new Error("Event type is required");
1124
+ }
1038
1125
  if (listener) {
1039
1126
  this.eventEmitter.off(event, listener);
1127
+ console.log(`Specific listener removed for ${event} on channel ${this.id}`);
1040
1128
  } else {
1041
- const listeners = this.eventEmitter.listeners(event);
1042
- listeners.forEach((fn) => {
1043
- this.eventEmitter.off(event, fn);
1044
- });
1129
+ this.eventEmitter.removeAllListeners(event);
1130
+ console.log(`All listeners removed for ${event} on channel ${this.id}`);
1045
1131
  }
1046
1132
  }
1047
1133
  /**
1048
- * Obtém a quantidade de listeners registrados para o evento especificado.
1049
- */
1050
- getListenerCount(event) {
1051
- return this.eventEmitter.listenerCount(event);
1052
- }
1053
- /**
1054
- * Emite eventos internamente para o canal.
1055
- * Verifica o ID do canal antes de emitir.
1134
+ * Emits an event if it matches the current channel
1056
1135
  */
1057
1136
  emitEvent(event) {
1137
+ if (!event) {
1138
+ console.warn("Received invalid event");
1139
+ return;
1140
+ }
1058
1141
  if ("channel" in event && event.channel?.id === this.id) {
1059
1142
  this.eventEmitter.emit(event.type, event);
1143
+ console.log(`Event ${event.type} emitted for channel ${this.id}`);
1060
1144
  }
1061
1145
  }
1062
1146
  /**
1063
- * Remove todos os listeners para este canal.
1147
+ * Removes all event listeners associated with the current instance.
1148
+ * This ensures that there are no lingering event handlers for the channel.
1149
+ *
1150
+ * @return {void} This method does not return a value.
1064
1151
  */
1065
1152
  removeAllListeners() {
1066
1153
  console.log(`Removendo todos os listeners para o canal ${this.id}`);
1067
1154
  this.eventEmitter.removeAllListeners();
1068
1155
  }
1156
+ /**
1157
+ * Answers the channel
1158
+ */
1069
1159
  async answer() {
1070
- await this.baseClient.post(`/channels/${this.id}/answer`);
1160
+ try {
1161
+ await this.baseClient.post(`/channels/${this.id}/answer`);
1162
+ console.log(`Channel ${this.id} answered`);
1163
+ } catch (error) {
1164
+ const message = getErrorMessage(error);
1165
+ console.error(`Error answering channel ${this.id}:`, message);
1166
+ throw new Error(`Failed to answer channel: ${message}`);
1167
+ }
1071
1168
  }
1072
1169
  /**
1073
- * Origina um canal físico no Asterisk.
1170
+ * Originates a new channel
1171
+ *
1172
+ * @param data - Channel origination configuration
1173
+ * @returns Promise resolving to the created channel
1174
+ * @throws Error if channel already exists or origination fails
1074
1175
  */
1075
1176
  async originate(data) {
1076
1177
  if (this.channelData) {
1077
- throw new Error("O canal j\xE1 foi criado.");
1178
+ throw new Error("Channel has already been created");
1179
+ }
1180
+ try {
1181
+ this.channelData = await this.baseClient.post("/channels", data);
1182
+ console.log(`Channel originated successfully with ID: ${this.channelData.id}`);
1183
+ return this.channelData;
1184
+ } catch (error) {
1185
+ const message = getErrorMessage(error);
1186
+ console.error(`Error originating channel:`, message);
1187
+ throw new Error(`Failed to originate channel: ${message}`);
1078
1188
  }
1079
- const channel = await this.baseClient.post("/channels", data);
1080
- this.channelData = channel;
1081
- return channel;
1082
1189
  }
1083
1190
  /**
1084
- * Obtém os detalhes do canal.
1191
+ * Plays media on the channel
1085
1192
  */
1086
- async getDetails() {
1087
- if (this.channelData) {
1088
- return this.channelData;
1193
+ async play(options, playbackId) {
1194
+ if (!options.media) {
1195
+ throw new Error("Media URL is required");
1089
1196
  }
1090
- if (!this.id) {
1091
- throw new Error("Nenhum ID de canal associado a esta inst\xE2ncia.");
1197
+ try {
1198
+ if (!this.channelData) {
1199
+ console.log("Initializing channel details...");
1200
+ this.channelData = await this.getDetails();
1201
+ }
1202
+ const playback = this.client.Playback(playbackId || v4_default());
1203
+ await this.baseClient.post(
1204
+ `/channels/${this.id}/play/${playback.id}`,
1205
+ options
1206
+ );
1207
+ console.log(`Media playback started on channel ${this.id}`);
1208
+ return playback;
1209
+ } catch (error) {
1210
+ const message = getErrorMessage(error);
1211
+ console.error(`Error playing media on channel ${this.id}:`, message);
1212
+ throw new Error(`Failed to play media: ${message}`);
1213
+ }
1214
+ }
1215
+ /**
1216
+ * Gets the current channel details
1217
+ */
1218
+ async getDetails() {
1219
+ try {
1220
+ if (this.channelData) {
1221
+ return this.channelData;
1222
+ }
1223
+ if (!this.id) {
1224
+ throw new Error("No channel ID associated with this instance");
1225
+ }
1226
+ const details = await this.baseClient.get(`/channels/${this.id}`);
1227
+ this.channelData = details;
1228
+ console.log(`Retrieved channel details for ${this.id}`);
1229
+ return details;
1230
+ } catch (error) {
1231
+ const message = getErrorMessage(error);
1232
+ console.error(`Error retrieving channel details for ${this.id}:`, message);
1233
+ throw new Error(`Failed to get channel details: ${message}`);
1092
1234
  }
1093
- const details = await this.baseClient.get(`/channels/${this.id}`);
1094
- this.channelData = details;
1095
- return details;
1096
1235
  }
1236
+ /**
1237
+ * Checks if the channel has any listeners for a specific event
1238
+ */
1239
+ hasListeners(event) {
1240
+ return this.eventEmitter.listenerCount(event) > 0;
1241
+ }
1242
+ /**
1243
+ * Gets the count of listeners for a specific event
1244
+ */
1245
+ getListenerCount(event) {
1246
+ return this.eventEmitter.listenerCount(event);
1247
+ }
1248
+ /**
1249
+ * Fetches a specific channel variable.
1250
+ *
1251
+ * @param {string} variable - The name of the variable to retrieve. This parameter is required.
1252
+ * @return {Promise<ChannelVar>} A promise that resolves with the value of the requested channel variable.
1253
+ * @throws {Error} If the 'variable' parameter is not provided.
1254
+ */
1097
1255
  async getVariable(variable) {
1098
1256
  if (!variable) {
1099
1257
  throw new Error("The 'variable' parameter is required.");
@@ -1103,7 +1261,11 @@ var ChannelInstance = class {
1103
1261
  );
1104
1262
  }
1105
1263
  /**
1106
- * Encerra o canal, se ele foi criado.
1264
+ * Terminates the active call associated with the current channel.
1265
+ * This method ensures that channel details are initialized before attempting to hang up.
1266
+ * If the channel ID is invalid or cannot be determined, an error is thrown.
1267
+ *
1268
+ * @return {Promise<void>} A promise that resolves when the call is successfully terminated.
1107
1269
  */
1108
1270
  async hangup() {
1109
1271
  if (!this.channelData) {
@@ -1116,25 +1278,12 @@ var ChannelInstance = class {
1116
1278
  await this.baseClient.delete(`/channels/${this.channelData.id}`);
1117
1279
  }
1118
1280
  /**
1119
- * Reproduz mídia no canal.
1120
- */
1121
- async play(options, playbackId) {
1122
- if (!this.channelData) {
1123
- console.log("Canal n\xE3o inicializado, buscando detalhes...");
1124
- this.channelData = await this.getDetails();
1125
- }
1126
- const playback = this.client.Playback(playbackId || v4_default());
1127
- if (!this.channelData?.id) {
1128
- throw new Error("N\xE3o foi poss\xEDvel inicializar o canal. ID inv\xE1lido.");
1129
- }
1130
- await this.baseClient.post(
1131
- `/channels/${this.channelData.id}/play/${playback.id}`,
1132
- options
1133
- );
1134
- return playback;
1135
- }
1136
- /**
1137
- * Reproduz mídia em um canal.
1281
+ * Plays media on the specified channel using the provided media URL and optional playback options.
1282
+ *
1283
+ * @param {string} media - The URL or identifier of the media to be played.
1284
+ * @param {PlaybackOptions} [options] - Optional playback settings such as volume, playback speed, etc.
1285
+ * @return {Promise<ChannelPlayback>} A promise that resolves with the playback details for the channel.
1286
+ * @throws {Error} Throws an error if the channel has not been created.
1138
1287
  */
1139
1288
  async playMedia(media, options) {
1140
1289
  if (!this.channelData) {
@@ -1147,7 +1296,11 @@ var ChannelInstance = class {
1147
1296
  );
1148
1297
  }
1149
1298
  /**
1150
- * Para a reprodução de mídia.
1299
+ * Stops the playback for the given playback ID.
1300
+ *
1301
+ * @param {string} playbackId - The unique identifier for the playback to be stopped.
1302
+ * @return {Promise<void>} A promise that resolves when the playback is successfully stopped.
1303
+ * @throws {Error} Throws an error if the instance is not associated with a channel.
1151
1304
  */
1152
1305
  async stopPlayback(playbackId) {
1153
1306
  if (!this.channelData?.id) {
@@ -1158,7 +1311,11 @@ var ChannelInstance = class {
1158
1311
  );
1159
1312
  }
1160
1313
  /**
1161
- * Pausa a reprodução de mídia.
1314
+ * Pauses the playback of the specified media on a channel.
1315
+ *
1316
+ * @param {string} playbackId - The unique identifier of the playback to be paused.
1317
+ * @return {Promise<void>} A promise that resolves when the playback has been successfully paused.
1318
+ * @throws {Error} Throws an error if the channel is not associated with the current instance.
1162
1319
  */
1163
1320
  async pausePlayback(playbackId) {
1164
1321
  if (!this.channelData?.id) {
@@ -1169,7 +1326,11 @@ var ChannelInstance = class {
1169
1326
  );
1170
1327
  }
1171
1328
  /**
1172
- * Retoma a reprodução de mídia.
1329
+ * Resumes playback of the specified playback session on the associated channel.
1330
+ *
1331
+ * @param {string} playbackId - The unique identifier of the playback session to be resumed.
1332
+ * @return {Promise<void>} A promise that resolves when the playback has been successfully resumed.
1333
+ * @throws {Error} Throws an error if the channel is not associated with this instance.
1173
1334
  */
1174
1335
  async resumePlayback(playbackId) {
1175
1336
  if (!this.channelData?.id) {
@@ -1180,7 +1341,11 @@ var ChannelInstance = class {
1180
1341
  );
1181
1342
  }
1182
1343
  /**
1183
- * Retrocede a reprodução de mídia.
1344
+ * Rewinds the playback of a media by a specified amount of milliseconds.
1345
+ *
1346
+ * @param {string} playbackId - The unique identifier for the playback session to be rewound.
1347
+ * @param {number} skipMs - The number of milliseconds to rewind the playback.
1348
+ * @return {Promise<void>} A promise that resolves when the rewind operation is complete.
1184
1349
  */
1185
1350
  async rewindPlayback(playbackId, skipMs) {
1186
1351
  if (!this.channelData?.id) {
@@ -1192,7 +1357,12 @@ var ChannelInstance = class {
1192
1357
  );
1193
1358
  }
1194
1359
  /**
1195
- * Avança a reprodução de mídia.
1360
+ * Fast forwards the playback by a specific duration in milliseconds.
1361
+ *
1362
+ * @param {string} playbackId - The unique identifier of the playback to be fast-forwarded.
1363
+ * @param {number} skipMs - The number of milliseconds to fast forward the playback.
1364
+ * @return {Promise<void>} A Promise that resolves when the fast-forward operation is complete.
1365
+ * @throws {Error} If no channel is associated with this instance.
1196
1366
  */
1197
1367
  async fastForwardPlayback(playbackId, skipMs) {
1198
1368
  if (!this.channelData?.id) {
@@ -1204,7 +1374,11 @@ var ChannelInstance = class {
1204
1374
  );
1205
1375
  }
1206
1376
  /**
1207
- * Muta o canal.
1377
+ * Mutes the specified channel for the given direction.
1378
+ *
1379
+ * @param {("both" | "in" | "out")} [direction="both"] - The direction to mute the channel. It can be "both" to mute incoming and outgoing, "in" to mute incoming, or "out" to mute outgoing.
1380
+ * @return {Promise<void>} A promise that resolves when the channel is successfully muted.
1381
+ * @throws {Error} If the channel is not associated with this instance.
1208
1382
  */
1209
1383
  async muteChannel(direction = "both") {
1210
1384
  if (!this.channelData?.id) {
@@ -1215,7 +1389,12 @@ var ChannelInstance = class {
1215
1389
  );
1216
1390
  }
1217
1391
  /**
1218
- * Desmuta o canal.
1392
+ * Unmutes a previously muted channel in the specified direction.
1393
+ *
1394
+ * @param {"both" | "in" | "out"} direction - The direction in which to unmute the channel.
1395
+ * Defaults to "both", which unmutes both incoming and outgoing communication.
1396
+ * @return {Promise<void>} A promise that resolves once the channel has been successfully unmuted.
1397
+ * @throws {Error} If the channel is not associated with the current instance.
1219
1398
  */
1220
1399
  async unmuteChannel(direction = "both") {
1221
1400
  if (!this.channelData?.id) {
@@ -1226,7 +1405,10 @@ var ChannelInstance = class {
1226
1405
  );
1227
1406
  }
1228
1407
  /**
1229
- * Coloca o canal em espera.
1408
+ * Places the associated channel on hold if the channel is valid and linked to this instance.
1409
+ *
1410
+ * @return {Promise<void>} A promise that resolves when the hold action is successfully executed.
1411
+ * @throws {Error} Throws an error if the channel is not associated with this instance.
1230
1412
  */
1231
1413
  async holdChannel() {
1232
1414
  if (!this.channelData?.id) {
@@ -1235,7 +1417,12 @@ var ChannelInstance = class {
1235
1417
  await this.baseClient.post(`/channels/${this.channelData.id}/hold`);
1236
1418
  }
1237
1419
  /**
1238
- * Remove o canal da espera.
1420
+ * Removes the hold status from a specific channel associated with this instance.
1421
+ * The method sends a delete request to the server to release the hold on the channel.
1422
+ * If no channel is associated with this instance, an error will be thrown.
1423
+ *
1424
+ * @return {Promise<void>} A promise that resolves when the channel hold has been successfully removed.
1425
+ * @throws {Error} If no channel is associated with this instance.
1239
1426
  */
1240
1427
  async unholdChannel() {
1241
1428
  if (!this.channelData?.id) {
@@ -1250,73 +1437,125 @@ var Channels = class {
1250
1437
  this.client = client;
1251
1438
  }
1252
1439
  channelInstances = /* @__PURE__ */ new Map();
1440
+ /**
1441
+ * Creates or retrieves a ChannelInstance based on the provided id.
1442
+ */
1253
1443
  Channel({ id }) {
1254
- if (!id) {
1255
- const instance = new ChannelInstance(this.client, this.baseClient);
1256
- this.channelInstances.set(instance.id, instance);
1257
- return instance;
1258
- }
1259
- if (!this.channelInstances.has(id)) {
1260
- const instance = new ChannelInstance(this.client, this.baseClient, id);
1261
- this.channelInstances.set(id, instance);
1262
- return instance;
1444
+ try {
1445
+ if (!id) {
1446
+ const instance = new ChannelInstance(this.client, this.baseClient);
1447
+ this.channelInstances.set(instance.id, instance);
1448
+ console.log(`New channel instance created with ID: ${instance.id}`);
1449
+ return instance;
1450
+ }
1451
+ if (!this.channelInstances.has(id)) {
1452
+ const instance = new ChannelInstance(this.client, this.baseClient, id);
1453
+ this.channelInstances.set(id, instance);
1454
+ console.log(`New channel instance created with provided ID: ${id}`);
1455
+ return instance;
1456
+ }
1457
+ console.log(`Returning existing channel instance: ${id}`);
1458
+ return this.channelInstances.get(id);
1459
+ } catch (error) {
1460
+ const message = getErrorMessage(error);
1461
+ console.error(`Error creating/retrieving channel instance:`, message);
1462
+ throw new Error(`Failed to manage channel instance: ${message}`);
1263
1463
  }
1264
- return this.channelInstances.get(id);
1265
1464
  }
1266
1465
  /**
1267
- * Remove uma instância de canal.
1466
+ * Removes a channel instance from the collection.
1268
1467
  */
1269
1468
  removeChannelInstance(channelId) {
1469
+ if (!channelId) {
1470
+ throw new Error("Channel ID is required");
1471
+ }
1270
1472
  if (this.channelInstances.has(channelId)) {
1271
1473
  const instance = this.channelInstances.get(channelId);
1272
1474
  instance?.removeAllListeners();
1273
1475
  this.channelInstances.delete(channelId);
1274
- console.log(`Inst\xE2ncia do canal ${channelId} removida.`);
1476
+ console.log(`Channel instance removed: ${channelId}`);
1275
1477
  } else {
1276
- console.warn(
1277
- `Tentativa de remover uma inst\xE2ncia inexistente: ${channelId}`
1278
- );
1478
+ console.warn(`Attempt to remove non-existent instance: ${channelId}`);
1279
1479
  }
1280
1480
  }
1281
1481
  /**
1282
- * Propaga eventos do WebSocket para o canal correspondente.
1482
+ * Propagates a WebSocket event to a specific channel.
1283
1483
  */
1284
1484
  propagateEventToChannel(event) {
1485
+ if (!event) {
1486
+ console.warn("Invalid WebSocket event received");
1487
+ return;
1488
+ }
1285
1489
  if ("channel" in event && event.channel?.id) {
1286
1490
  const instance = this.channelInstances.get(event.channel.id);
1287
1491
  if (instance) {
1288
1492
  instance.emitEvent(event);
1493
+ console.log(`Event propagated to channel ${event.channel.id}: ${event.type}`);
1289
1494
  } else {
1290
- console.warn(
1291
- `Nenhuma inst\xE2ncia encontrada para o canal ${event.channel.id}`
1292
- );
1495
+ console.warn(`No instance found for channel ${event.channel.id}`);
1293
1496
  }
1294
1497
  }
1295
1498
  }
1296
1499
  /**
1297
- * Origina um canal físico diretamente, sem uma instância de `ChannelInstance`.
1500
+ * Initiates a new channel.
1298
1501
  */
1299
1502
  async originate(data) {
1300
- return this.baseClient.post("/channels", data);
1503
+ if (!data.endpoint) {
1504
+ throw new Error("Endpoint is required for channel origination");
1505
+ }
1506
+ try {
1507
+ const channel = await this.baseClient.post("/channels", data);
1508
+ console.log(`Channel originated successfully with ID: ${channel.id}`);
1509
+ return channel;
1510
+ } catch (error) {
1511
+ const message = getErrorMessage(error);
1512
+ console.error(`Error originating channel:`, message);
1513
+ throw new Error(`Failed to originate channel: ${message}`);
1514
+ }
1301
1515
  }
1302
1516
  /**
1303
- * Obtém detalhes de um canal específico.
1517
+ * Lists all active channels.
1304
1518
  */
1305
- async getDetails(channelId) {
1306
- return this.baseClient.get(`/channels/${channelId}`);
1519
+ async list() {
1520
+ try {
1521
+ const channels = await this.baseClient.get("/channels");
1522
+ if (!Array.isArray(channels)) {
1523
+ throw new Error("API response for /channels is not an array");
1524
+ }
1525
+ console.log(`Retrieved ${channels.length} active channels`);
1526
+ return channels;
1527
+ } catch (error) {
1528
+ const message = getErrorMessage(error);
1529
+ console.error(`Error listing channels:`, message);
1530
+ throw new Error(`Failed to list channels: ${message}`);
1531
+ }
1307
1532
  }
1308
1533
  /**
1309
- * Lista todos os canais ativos.
1534
+ * Gets the count of active channel instances.
1310
1535
  */
1311
- async list() {
1312
- const channels = await this.baseClient.get("/channels");
1313
- if (!Array.isArray(channels)) {
1314
- throw new Error("Resposta da API /channels n\xE3o \xE9 um array.");
1315
- }
1316
- return channels;
1536
+ getInstanceCount() {
1537
+ return this.channelInstances.size;
1317
1538
  }
1318
1539
  /**
1319
- * Encerra um canal específico.
1540
+ * Checks if a channel instance exists.
1541
+ */
1542
+ hasInstance(channelId) {
1543
+ return this.channelInstances.has(channelId);
1544
+ }
1545
+ /**
1546
+ * Gets all active channel instances.
1547
+ */
1548
+ getAllInstances() {
1549
+ return new Map(this.channelInstances);
1550
+ }
1551
+ /**
1552
+ * Terminates an active call on the specified channel.
1553
+ *
1554
+ * @param {string} channelId - The unique identifier of the channel to hang up.
1555
+ * @param {Object} [options] - Optional parameters for the hangup request.
1556
+ * @param {string} [options.reason_code] - A code indicating the reason for the hangup.
1557
+ * @param {string} [options.reason] - A descriptive reason for the hangup.
1558
+ * @return {Promise<void>} A promise that resolves when the call has been successfully terminated.
1320
1559
  */
1321
1560
  async hangup(channelId, options) {
1322
1561
  const queryParams = new URLSearchParams({
@@ -1328,7 +1567,11 @@ var Channels = class {
1328
1567
  );
1329
1568
  }
1330
1569
  /**
1331
- * Inicia a escuta em um canal.
1570
+ * Initiates snooping on a specified channel with the provided options.
1571
+ *
1572
+ * @param {string} channelId - The unique identifier of the channel to snoop on.
1573
+ * @param {SnoopOptions} options - Configuration options for the snooping operation.
1574
+ * @return {Promise<Channel>} A promise that resolves to the snooped channel data.
1332
1575
  */
1333
1576
  async snoopChannel(channelId, options) {
1334
1577
  const queryParams = toQueryParams2(options);
@@ -1336,23 +1579,56 @@ var Channels = class {
1336
1579
  `/channels/${channelId}/snoop?${queryParams}`
1337
1580
  );
1338
1581
  }
1582
+ /**
1583
+ * Starts a silence mode for the specified channel.
1584
+ *
1585
+ * @param {string} channelId - The unique identifier of the channel where silence mode should be started.
1586
+ * @return {Promise<void>} A promise that resolves when the silence mode is successfully started.
1587
+ */
1339
1588
  async startSilence(channelId) {
1340
1589
  return this.baseClient.post(`/channels/${channelId}/silence`);
1341
1590
  }
1591
+ /**
1592
+ * Stops the silence mode for a specific channel.
1593
+ *
1594
+ * @param {string} channelId - The unique identifier of the channel for which silence mode should be stopped.
1595
+ * @return {Promise<void>} A promise that resolves when the operation is complete.
1596
+ */
1342
1597
  async stopSilence(channelId) {
1343
1598
  return this.baseClient.delete(`/channels/${channelId}/silence`);
1344
1599
  }
1600
+ /**
1601
+ * Retrieves the Real-Time Protocol (RTP) statistics for a specific channel.
1602
+ *
1603
+ * @param {string} channelId - The unique identifier of the channel for which RTP statistics are fetched.
1604
+ * @return {Promise<RTPStats>} A promise that resolves to the RTP statistics for the specified channel.
1605
+ */
1345
1606
  async getRTPStatistics(channelId) {
1346
1607
  return this.baseClient.get(
1347
1608
  `/channels/${channelId}/rtp_statistics`
1348
1609
  );
1349
1610
  }
1611
+ /**
1612
+ * Creates an external media channel with the given options.
1613
+ *
1614
+ * @param {ExternalMediaOptions} options - The configuration options for creating the external media channel.
1615
+ * @return {Promise<Channel>} A promise that resolves with the created external media channel.
1616
+ */
1350
1617
  async createExternalMedia(options) {
1351
1618
  const queryParams = toQueryParams2(options);
1352
1619
  return this.baseClient.post(
1353
1620
  `/channels/externalMedia?${queryParams}`
1354
1621
  );
1355
1622
  }
1623
+ /**
1624
+ * Initiates playback of a specific media item on a channel using the provided playback ID.
1625
+ *
1626
+ * @param {string} channelId - The unique identifier of the channel where playback will occur.
1627
+ * @param {string} playbackId - The unique identifier for the specific playback session.
1628
+ * @param {string} media - The media content to be played.
1629
+ * @param {PlaybackOptions} [options] - Optional playback configuration parameters.
1630
+ * @return {Promise<ChannelPlayback>} A promise that resolves with the playback details for the channel.
1631
+ */
1356
1632
  async playWithId(channelId, playbackId, media, options) {
1357
1633
  const queryParams = options ? `?${toQueryParams2(options)}` : "";
1358
1634
  return this.baseClient.post(
@@ -1360,18 +1636,41 @@ var Channels = class {
1360
1636
  { media }
1361
1637
  );
1362
1638
  }
1639
+ /**
1640
+ * Initiates a snoop operation on a specific channel using the provided channel ID and snoop ID.
1641
+ *
1642
+ * @param {string} channelId - The unique identifier of the channel to snoop on.
1643
+ * @param {string} snoopId - The unique identifier for the snoop operation.
1644
+ * @param {SnoopOptions} options - Additional options and parameters for the snoop operation.
1645
+ * @return {Promise<Channel>} A promise that resolves to the channel details after the snoop operation is initiated.
1646
+ */
1363
1647
  async snoopChannelWithId(channelId, snoopId, options) {
1364
1648
  const queryParams = toQueryParams2(options);
1365
1649
  return this.baseClient.post(
1366
1650
  `/channels/${channelId}/snoop/${snoopId}?${queryParams}`
1367
1651
  );
1368
1652
  }
1653
+ /**
1654
+ * Starts Music on Hold for the specified channel with the provided Music on Hold class.
1655
+ *
1656
+ * @param {string} channelId - The unique identifier of the channel.
1657
+ * @param {string} mohClass - The Music on Hold class to be applied.
1658
+ * @return {Promise<void>} A promise that resolves when the operation is complete.
1659
+ */
1369
1660
  async startMohWithClass(channelId, mohClass) {
1370
1661
  const queryParams = `mohClass=${encodeURIComponent(mohClass)}`;
1371
1662
  await this.baseClient.post(
1372
1663
  `/channels/${channelId}/moh?${queryParams}`
1373
1664
  );
1374
1665
  }
1666
+ /**
1667
+ * Retrieves the value of a specified variable for a given channel.
1668
+ *
1669
+ * @param {string} channelId - The unique identifier of the channel.
1670
+ * @param {string} variable - The name of the variable to retrieve.
1671
+ * @return {Promise<ChannelVar>} A promise that resolves to the value of the channel variable.
1672
+ * @throws {Error} Throws an error if the 'variable' parameter is not provided.
1673
+ */
1375
1674
  async getChannelVariable(channelId, variable) {
1376
1675
  if (!variable) {
1377
1676
  throw new Error("The 'variable' parameter is required.");
@@ -1380,6 +1679,15 @@ var Channels = class {
1380
1679
  `/channels/${channelId}/variable?variable=${encodeURIComponent(variable)}`
1381
1680
  );
1382
1681
  }
1682
+ /**
1683
+ * Sets a variable for a specific channel.
1684
+ *
1685
+ * @param {string} channelId - The unique identifier of the channel.
1686
+ * @param {string} variable - The name of the variable to be set. This parameter is required.
1687
+ * @param {string} [value] - The value of the variable to be set. This parameter is optional.
1688
+ * @return {Promise<void>} A promise that resolves when the variable is successfully set.
1689
+ * @throws {Error} Throws an error if the `variable` parameter is not provided.
1690
+ */
1383
1691
  async setChannelVariable(channelId, variable, value) {
1384
1692
  if (!variable) {
1385
1693
  throw new Error("The 'variable' parameter is required.");
@@ -1392,12 +1700,30 @@ var Channels = class {
1392
1700
  `/channels/${channelId}/variable?${queryParams}`
1393
1701
  );
1394
1702
  }
1703
+ /**
1704
+ * Moves a specified channel to the given application with optional arguments.
1705
+ *
1706
+ * @param {string} channelId - The unique identifier of the channel to be moved.
1707
+ * @param {string} app - The target application to which the channel will be moved.
1708
+ * @param {string} [appArgs] - Optional arguments to be passed to the target application.
1709
+ * @return {Promise<void>} A promise that resolves when the operation is completed.
1710
+ */
1395
1711
  async moveToApplication(channelId, app, appArgs) {
1396
1712
  await this.baseClient.post(`/channels/${channelId}/move`, {
1397
1713
  app,
1398
1714
  appArgs
1399
1715
  });
1400
1716
  }
1717
+ /**
1718
+ * Continues the execution of a dialplan for a specific channel.
1719
+ *
1720
+ * @param {string} channelId - The unique identifier of the channel.
1721
+ * @param {string} [context] - The dialplan context to continue execution in, if specified.
1722
+ * @param {string} [extension] - The dialplan extension to proceed with, if provided.
1723
+ * @param {number} [priority] - The priority within the dialplan extension to resume at, if specified.
1724
+ * @param {string} [label] - The label to start from within the dialplan, if given.
1725
+ * @return {Promise<void>} Resolves when the dialplan is successfully continued.
1726
+ */
1401
1727
  async continueDialplan(channelId, context, extension, priority, label) {
1402
1728
  await this.baseClient.post(`/channels/${channelId}/continue`, {
1403
1729
  context,
@@ -1406,18 +1732,45 @@ var Channels = class {
1406
1732
  label
1407
1733
  });
1408
1734
  }
1735
+ /**
1736
+ * Stops the music on hold for the specified channel.
1737
+ *
1738
+ * @param {string} channelId - The unique identifier of the channel where music on hold should be stopped.
1739
+ * @return {Promise<void>} Resolves when the music on hold is successfully stopped.
1740
+ */
1409
1741
  async stopMusicOnHold(channelId) {
1410
1742
  await this.baseClient.delete(`/channels/${channelId}/moh`);
1411
1743
  }
1744
+ /**
1745
+ * Initiates the music on hold for the specified channel.
1746
+ *
1747
+ * @param {string} channelId - The unique identifier of the channel where the music on hold will be started.
1748
+ * @return {Promise<void>} A promise that resolves when the operation has been successfully invoked.
1749
+ */
1412
1750
  async startMusicOnHold(channelId) {
1413
1751
  await this.baseClient.post(`/channels/${channelId}/moh`);
1414
1752
  }
1753
+ /**
1754
+ * Starts recording for a specific channel based on the provided options.
1755
+ *
1756
+ * @param {string} channelId - The unique identifier of the channel to start recording.
1757
+ * @param {RecordingOptions} options - The recording options to configure the recording process.
1758
+ * @return {Promise<Channel>} A promise that resolves to the channel object with updated recording state.
1759
+ */
1415
1760
  async record(channelId, options) {
1416
1761
  const queryParams = toQueryParams2(options);
1417
1762
  return this.baseClient.post(
1418
1763
  `/channels/${channelId}/record?${queryParams}`
1419
1764
  );
1420
1765
  }
1766
+ /**
1767
+ * Initiates a call on the specified channel with optional parameters for caller identification and timeout duration.
1768
+ *
1769
+ * @param {string} channelId - The ID of the channel where the call will be initiated.
1770
+ * @param {string} [caller] - Optional parameter specifying the name or identifier of the caller.
1771
+ * @param {number} [timeout] - Optional parameter defining the timeout duration for the call in seconds.
1772
+ * @return {Promise<void>} A promise that resolves when the call has been successfully initiated.
1773
+ */
1421
1774
  async dial(channelId, caller, timeout) {
1422
1775
  const queryParams = new URLSearchParams({
1423
1776
  ...caller && { caller },
@@ -1427,45 +1780,126 @@ var Channels = class {
1427
1780
  `/channels/${channelId}/dial?${queryParams}`
1428
1781
  );
1429
1782
  }
1783
+ /**
1784
+ * Redirects a channel to the specified endpoint.
1785
+ *
1786
+ * This method sends a POST request to update the redirect endpoint for the given channel.
1787
+ *
1788
+ * @param {string} channelId - The unique identifier of the channel to be redirected.
1789
+ * @param {string} endpoint - The new endpoint to redirect the channel to.
1790
+ * @return {Promise<void>} A promise that resolves when the operation is complete.
1791
+ */
1430
1792
  async redirectChannel(channelId, endpoint) {
1431
1793
  await this.baseClient.post(
1432
1794
  `/channels/${channelId}/redirect?endpoint=${encodeURIComponent(endpoint)}`
1433
1795
  );
1434
1796
  }
1797
+ /**
1798
+ * Answers a specified channel by sending a POST request to the corresponding endpoint.
1799
+ *
1800
+ * @param {string} channelId - The unique identifier of the channel to be answered.
1801
+ * @return {Promise<void>} A promise that resolves when the channel has been successfully answered.
1802
+ */
1435
1803
  async answerChannel(channelId) {
1436
1804
  await this.baseClient.post(`/channels/${channelId}/answer`);
1437
1805
  }
1806
+ /**
1807
+ * Rings the specified channel by sending a POST request to the appropriate endpoint.
1808
+ *
1809
+ * @param {string} channelId - The unique identifier of the channel to be rung.
1810
+ * @return {Promise<void>} A promise that resolves when the operation completes successfully.
1811
+ */
1438
1812
  async ringChannel(channelId) {
1439
1813
  await this.baseClient.post(`/channels/${channelId}/ring`);
1440
1814
  }
1815
+ /**
1816
+ * Stops the ring channel for the specified channel ID.
1817
+ *
1818
+ * This method sends a DELETE request to the server to stop the ring action
1819
+ * associated with the provided channel ID.
1820
+ *
1821
+ * @param {string} channelId - The unique identifier of the channel for which the ring action should be stopped.
1822
+ * @return {Promise<void>} A promise that resolves when the ring channel is successfully stopped.
1823
+ */
1441
1824
  async stopRingChannel(channelId) {
1442
1825
  await this.baseClient.delete(`/channels/${channelId}/ring`);
1443
1826
  }
1827
+ /**
1828
+ * Sends DTMF (Dual-Tone Multi-Frequency) signals to a specified channel.
1829
+ *
1830
+ * @param {string} channelId - The ID of the channel to which the DTMF signals should be sent.
1831
+ * @param {string} dtmf - The DTMF tones to be sent, represented as a string. Each character corresponds to a specific tone.
1832
+ * @param {Object} [options] - Optional configuration for the DTMF signal timing.
1833
+ * @param {number} [options.before] - Time in milliseconds to wait before sending the first DTMF tone.
1834
+ * @param {number} [options.between] - Time in milliseconds to wait between sending successive DTMF tones.
1835
+ * @param {number} [options.duration] - Duration in milliseconds for each DTMF tone.
1836
+ * @param {number} [options.after] - Time in milliseconds to wait after sending the last DTMF tone.
1837
+ * @return {Promise<void>} A promise that resolves when the DTMF signals are successfully sent.
1838
+ */
1444
1839
  async sendDTMF(channelId, dtmf, options) {
1445
1840
  const queryParams = toQueryParams2({ dtmf, ...options });
1446
1841
  await this.baseClient.post(
1447
1842
  `/channels/${channelId}/dtmf?${queryParams}`
1448
1843
  );
1449
1844
  }
1845
+ /**
1846
+ * Mutes a specified channel in the given direction.
1847
+ *
1848
+ * @param {string} channelId - The unique identifier of the channel to be muted.
1849
+ * @param {"both" | "in" | "out"} [direction="both"] - The direction for muting, can be "both", "in", or "out". Default is "both".
1850
+ * @return {Promise<void>} A promise that resolves when the channel is successfully muted.
1851
+ */
1450
1852
  async muteChannel(channelId, direction = "both") {
1451
1853
  await this.baseClient.post(
1452
1854
  `/channels/${channelId}/mute?direction=${direction}`
1453
1855
  );
1454
1856
  }
1857
+ /**
1858
+ * Unmutes a previously muted channel, allowing communication in the specified direction(s).
1859
+ *
1860
+ * @param {string} channelId - The unique identifier of the channel to be unmuted.
1861
+ * @param {"both" | "in" | "out"} [direction="both"] - The direction of communication to unmute. Valid options are "both", "in" (incoming messages), or "out" (outgoing messages). Defaults to "both".
1862
+ * @return {Promise<void>} A promise that resolves when the channel is successfully unmuted.
1863
+ */
1455
1864
  async unmuteChannel(channelId, direction = "both") {
1456
1865
  await this.baseClient.delete(
1457
1866
  `/channels/${channelId}/mute?direction=${direction}`
1458
1867
  );
1459
1868
  }
1869
+ /**
1870
+ * Places a specific channel on hold by sending a POST request to the server.
1871
+ *
1872
+ * @param {string} channelId - The unique identifier of the channel to be placed on hold.
1873
+ * @return {Promise<void>} A promise that resolves when the channel hold operation is completed.
1874
+ */
1460
1875
  async holdChannel(channelId) {
1461
1876
  await this.baseClient.post(`/channels/${channelId}/hold`);
1462
1877
  }
1878
+ /**
1879
+ * Removes the hold status from a specific channel by its ID.
1880
+ *
1881
+ * @param {string} channelId - The unique identifier of the channel to unhold.
1882
+ * @return {Promise<void>} A promise that resolves when the channel hold is successfully removed.
1883
+ */
1463
1884
  async unholdChannel(channelId) {
1464
1885
  await this.baseClient.delete(`/channels/${channelId}/hold`);
1465
1886
  }
1887
+ /**
1888
+ * Creates a new communication channel with the specified configuration.
1889
+ *
1890
+ * @param {OriginateRequest} data - The configuration data required to create the channel, including relevant details such as endpoint and channel variables.
1891
+ * @return {Promise<Channel>} A promise that resolves with the details of the created channel.
1892
+ */
1466
1893
  async createChannel(data) {
1467
1894
  return this.baseClient.post("/channels/create", data);
1468
1895
  }
1896
+ /**
1897
+ * Initiates a new channel with the specified channel ID and originates a call using the provided data.
1898
+ *
1899
+ * @param {string} channelId - The unique identifier of the channel to be created.
1900
+ * @param {OriginateRequest} data - The data required to originate the call, including details such as endpoint and caller information.
1901
+ * @return {Promise<Channel>} A promise that resolves to the created Channel object.
1902
+ */
1469
1903
  async originateWithId(channelId, data) {
1470
1904
  return this.baseClient.post(`/channels/${channelId}`, data);
1471
1905
  }
@@ -1519,93 +1953,187 @@ var Endpoints = class {
1519
1953
 
1520
1954
  // src/ari-client/resources/playbacks.ts
1521
1955
  import { EventEmitter as EventEmitter2 } from "events";
1956
+ import { isAxiosError as isAxiosError3 } from "axios";
1957
+ var getErrorMessage2 = (error) => {
1958
+ if (isAxiosError3(error)) {
1959
+ return error.response?.data?.message || error.message || "An axios error occurred";
1960
+ }
1961
+ if (error instanceof Error) {
1962
+ return error.message;
1963
+ }
1964
+ return "An unknown error occurred";
1965
+ };
1522
1966
  var PlaybackInstance = class {
1967
+ /**
1968
+ * Creates a new PlaybackInstance.
1969
+ *
1970
+ * @param {AriClient} client - ARI client for communication
1971
+ * @param {BaseClient} baseClient - Base client for HTTP requests
1972
+ * @param {string} [playbackId] - Optional playback ID, generates timestamp-based ID if not provided
1973
+ */
1523
1974
  constructor(client, baseClient, playbackId = `playback-${Date.now()}`) {
1524
1975
  this.client = client;
1525
1976
  this.baseClient = baseClient;
1526
1977
  this.playbackId = playbackId;
1527
1978
  this.id = playbackId;
1979
+ console.log(`PlaybackInstance initialized with ID: ${this.id}`);
1528
1980
  }
1529
1981
  eventEmitter = new EventEmitter2();
1530
1982
  playbackData = null;
1531
1983
  id;
1532
1984
  /**
1533
- * Registra um listener para eventos específicos deste playback.
1985
+ * Registers an event listener for a specific WebSocket event type.
1986
+ *
1987
+ * @param {T} event - Event type to listen for
1988
+ * @param {Function} listener - Callback function for the event
1534
1989
  */
1535
1990
  on(event, listener) {
1991
+ if (!event) {
1992
+ throw new Error("Event type is required");
1993
+ }
1536
1994
  const wrappedListener = (data) => {
1537
1995
  if ("playback" in data && data.playback?.id === this.id) {
1538
1996
  listener(data);
1539
1997
  }
1540
1998
  };
1541
1999
  this.eventEmitter.on(event, wrappedListener);
2000
+ console.log(`Event listener registered for ${event} on playback ${this.id}`);
1542
2001
  }
1543
2002
  /**
1544
- * Registra um listener único para eventos específicos deste playback.
2003
+ * Registers a one-time event listener for a specific WebSocket event type.
2004
+ *
2005
+ * @param {T} event - Event type to listen for
2006
+ * @param {Function} listener - Callback function for the event
1545
2007
  */
1546
2008
  once(event, listener) {
2009
+ if (!event) {
2010
+ throw new Error("Event type is required");
2011
+ }
1547
2012
  const wrappedListener = (data) => {
1548
2013
  if ("playback" in data && data.playback?.id === this.id) {
1549
2014
  listener(data);
1550
2015
  }
1551
2016
  };
1552
2017
  this.eventEmitter.once(event, wrappedListener);
2018
+ console.log(`One-time event listener registered for ${event} on playback ${this.id}`);
1553
2019
  }
1554
2020
  /**
1555
- * Remove um listener para eventos específicos deste playback.
2021
+ * Removes event listener(s) for a specific WebSocket event type.
2022
+ *
2023
+ * @param {T} event - Event type to remove listener(s) for
2024
+ * @param {Function} [listener] - Optional specific listener to remove
1556
2025
  */
1557
2026
  off(event, listener) {
2027
+ if (!event) {
2028
+ throw new Error("Event type is required");
2029
+ }
1558
2030
  if (listener) {
1559
2031
  this.eventEmitter.off(event, listener);
2032
+ console.log(`Specific listener removed for ${event} on playback ${this.id}`);
1560
2033
  } else {
1561
2034
  this.eventEmitter.removeAllListeners(event);
2035
+ console.log(`All listeners removed for ${event} on playback ${this.id}`);
1562
2036
  }
1563
2037
  }
1564
2038
  /**
1565
- * Emite eventos internamente para o playback.
2039
+ * Emits a WebSocket event if it matches the current playback instance.
2040
+ *
2041
+ * @param {WebSocketEvent} event - Event to emit
1566
2042
  */
1567
2043
  emitEvent(event) {
2044
+ if (!event) {
2045
+ console.warn("Received invalid event");
2046
+ return;
2047
+ }
1568
2048
  if ("playback" in event && event.playback?.id === this.id) {
1569
2049
  this.eventEmitter.emit(event.type, event);
2050
+ console.log(`Event ${event.type} emitted for playback ${this.id}`);
1570
2051
  }
1571
2052
  }
1572
2053
  /**
1573
- * Obtém os detalhes do playback.
2054
+ * Retrieves current playback data.
2055
+ *
2056
+ * @returns {Promise<Playback>} Current playback data
2057
+ * @throws {Error} If playback is not properly initialized
1574
2058
  */
1575
2059
  async get() {
1576
2060
  if (!this.id) {
1577
- throw new Error("Nenhum playback associado a esta inst\xE2ncia.");
2061
+ throw new Error("No playback associated with this instance");
2062
+ }
2063
+ try {
2064
+ this.playbackData = await this.baseClient.get(
2065
+ `/playbacks/${this.id}`
2066
+ );
2067
+ console.log(`Retrieved playback data for ${this.id}`);
2068
+ return this.playbackData;
2069
+ } catch (error) {
2070
+ const message = getErrorMessage2(error);
2071
+ console.error(`Error retrieving playback data for ${this.id}:`, message);
2072
+ throw new Error(`Failed to get playback data: ${message}`);
1578
2073
  }
1579
- this.playbackData = await this.baseClient.get(
1580
- `/playbacks/${this.id}`
1581
- );
1582
- return this.playbackData;
1583
2074
  }
1584
2075
  /**
1585
- * Controla o playback.
2076
+ * Controls playback with specified operation.
2077
+ *
2078
+ * @param {"pause" | "unpause" | "reverse" | "forward"} operation - Control operation to perform
2079
+ * @throws {Error} If playback is not properly initialized or operation fails
1586
2080
  */
1587
2081
  async control(operation) {
1588
2082
  if (!this.id) {
1589
- throw new Error("Nenhum playback associado para controlar.");
2083
+ throw new Error("No playback associated with this instance");
2084
+ }
2085
+ try {
2086
+ await this.baseClient.post(
2087
+ `/playbacks/${this.id}/control?operation=${operation}`
2088
+ );
2089
+ console.log(`Operation ${operation} executed successfully on playback ${this.id}`);
2090
+ } catch (error) {
2091
+ const message = getErrorMessage2(error);
2092
+ console.error(`Error controlling playback ${this.id}:`, message);
2093
+ throw new Error(`Failed to control playback: ${message}`);
1590
2094
  }
1591
- await this.baseClient.post(
1592
- `/playbacks/${this.id}/control?operation=${operation}`
1593
- );
1594
2095
  }
1595
2096
  /**
1596
- * Encerra o playback.
2097
+ * Stops the current playback.
2098
+ *
2099
+ * @throws {Error} If playback is not properly initialized or stop operation fails
1597
2100
  */
1598
2101
  async stop() {
1599
2102
  if (!this.id) {
1600
- throw new Error("Nenhum playback associado para encerrar.");
2103
+ throw new Error("No playback associated with this instance");
2104
+ }
2105
+ try {
2106
+ await this.baseClient.delete(`/playbacks/${this.id}`);
2107
+ console.log(`Playback ${this.id} stopped successfully`);
2108
+ } catch (error) {
2109
+ const message = getErrorMessage2(error);
2110
+ console.error(`Error stopping playback ${this.id}:`, message);
2111
+ throw new Error(`Failed to stop playback: ${message}`);
1601
2112
  }
1602
- await this.baseClient.delete(`/playbacks/${this.id}`);
1603
2113
  }
1604
2114
  /**
1605
- * Remove todos os listeners para este playback.
2115
+ * Removes all event listeners from this playback instance.
1606
2116
  */
1607
2117
  removeAllListeners() {
1608
2118
  this.eventEmitter.removeAllListeners();
2119
+ console.log(`All listeners removed from playback ${this.id}`);
2120
+ }
2121
+ /**
2122
+ * Checks if the playback instance has any listeners for a specific event.
2123
+ *
2124
+ * @param {string} event - Event type to check
2125
+ * @returns {boolean} True if there are listeners for the event
2126
+ */
2127
+ hasListeners(event) {
2128
+ return this.eventEmitter.listenerCount(event) > 0;
2129
+ }
2130
+ /**
2131
+ * Gets the current playback data without making an API call.
2132
+ *
2133
+ * @returns {Playback | null} Current playback data or null if not available
2134
+ */
2135
+ getCurrentData() {
2136
+ return this.playbackData;
1609
2137
  }
1610
2138
  };
1611
2139
  var Playbacks = class {
@@ -1615,61 +2143,141 @@ var Playbacks = class {
1615
2143
  }
1616
2144
  playbackInstances = /* @__PURE__ */ new Map();
1617
2145
  /**
1618
- * Gerencia instâncias de playback.
2146
+ * Gets or creates a playback instance
2147
+ * @param {Object} params - Parameters for getting/creating a playback instance
2148
+ * @param {string} [params.id] - Optional ID of an existing playback
2149
+ * @returns {PlaybackInstance} The requested or new playback instance
1619
2150
  */
1620
2151
  Playback({ id }) {
1621
- if (!id) {
1622
- const instance = new PlaybackInstance(this.client, this.baseClient);
1623
- this.playbackInstances.set(instance.id, instance);
1624
- return instance;
1625
- }
1626
- if (!this.playbackInstances.has(id)) {
1627
- const instance = new PlaybackInstance(this.client, this.baseClient, id);
1628
- this.playbackInstances.set(id, instance);
1629
- return instance;
2152
+ try {
2153
+ if (!id) {
2154
+ const instance = new PlaybackInstance(this.client, this.baseClient);
2155
+ this.playbackInstances.set(instance.id, instance);
2156
+ console.log(`New playback instance created with ID: ${instance.id}`);
2157
+ return instance;
2158
+ }
2159
+ if (!this.playbackInstances.has(id)) {
2160
+ const instance = new PlaybackInstance(this.client, this.baseClient, id);
2161
+ this.playbackInstances.set(id, instance);
2162
+ console.log(`New playback instance created with provided ID: ${id}`);
2163
+ return instance;
2164
+ }
2165
+ console.log(`Returning existing playback instance: ${id}`);
2166
+ return this.playbackInstances.get(id);
2167
+ } catch (error) {
2168
+ const message = getErrorMessage2(error);
2169
+ console.error(`Error creating/retrieving playback instance:`, message);
2170
+ throw new Error(`Failed to manage playback instance: ${message}`);
1630
2171
  }
1631
- return this.playbackInstances.get(id);
1632
2172
  }
1633
2173
  /**
1634
- * Remove uma instância de playback.
2174
+ * Removes a playback instance and cleans up its resources
2175
+ * @param {string} playbackId - ID of the playback instance to remove
2176
+ * @throws {Error} If the playback instance doesn't exist
1635
2177
  */
1636
2178
  removePlaybackInstance(playbackId) {
2179
+ if (!playbackId) {
2180
+ throw new Error("Playback ID is required");
2181
+ }
1637
2182
  if (this.playbackInstances.has(playbackId)) {
1638
2183
  const instance = this.playbackInstances.get(playbackId);
1639
2184
  instance?.removeAllListeners();
1640
2185
  this.playbackInstances.delete(playbackId);
2186
+ console.log(`Playback instance removed: ${playbackId}`);
2187
+ } else {
2188
+ console.warn(`Attempt to remove non-existent instance: ${playbackId}`);
1641
2189
  }
1642
2190
  }
1643
2191
  /**
1644
- * Propaga eventos do WebSocket para o playback correspondente.
2192
+ * Propagates WebSocket events to the corresponding playback instance
2193
+ * @param {WebSocketEvent} event - The WebSocket event to propagate
1645
2194
  */
1646
2195
  propagateEventToPlayback(event) {
2196
+ if (!event) {
2197
+ console.warn("Invalid WebSocket event received");
2198
+ return;
2199
+ }
1647
2200
  if ("playback" in event && event.playback?.id) {
1648
2201
  const instance = this.playbackInstances.get(event.playback.id);
1649
2202
  if (instance) {
1650
2203
  instance.emitEvent(event);
2204
+ console.log(`Event propagated to playback ${event.playback.id}: ${event.type}`);
2205
+ } else {
2206
+ console.warn(`No instance found for playback ${event.playback.id}`);
1651
2207
  }
1652
2208
  }
1653
2209
  }
1654
2210
  /**
1655
- * Obtém detalhes de um playback específico.
2211
+ * Retrieves details of a specific playback
2212
+ * @param {string} playbackId - ID of the playback to get details for
2213
+ * @returns {Promise<Playback>} Promise resolving to playback details
2214
+ * @throws {Error} If the playback ID is invalid or the request fails
1656
2215
  */
1657
2216
  async getDetails(playbackId) {
1658
- return this.baseClient.get(`/playbacks/${playbackId}`);
2217
+ if (!playbackId) {
2218
+ throw new Error("Playback ID is required");
2219
+ }
2220
+ try {
2221
+ return await this.baseClient.get(`/playbacks/${playbackId}`);
2222
+ } catch (error) {
2223
+ const message = getErrorMessage2(error);
2224
+ console.error(`Error getting playback details ${playbackId}:`, message);
2225
+ throw new Error(`Failed to get playback details: ${message}`);
2226
+ }
1659
2227
  }
1660
2228
  /**
1661
- * Controla um playback específico.
2229
+ * Controls a specific playback instance
2230
+ * @param {string} playbackId - ID of the playback to control
2231
+ * @param {"pause" | "unpause" | "reverse" | "forward"} operation - Operation to perform
2232
+ * @throws {Error} If the playback ID is invalid or the operation fails
1662
2233
  */
1663
2234
  async control(playbackId, operation) {
1664
- const playback = this.Playback({ id: playbackId });
1665
- await playback.control(operation);
2235
+ if (!playbackId) {
2236
+ throw new Error("Playback ID is required");
2237
+ }
2238
+ try {
2239
+ const playback = this.Playback({ id: playbackId });
2240
+ await playback.control(operation);
2241
+ console.log(`Operation ${operation} executed on playback ${playbackId}`);
2242
+ } catch (error) {
2243
+ const message = getErrorMessage2(error);
2244
+ console.error(`Error controlling playback ${playbackId}:`, message);
2245
+ throw new Error(`Failed to control playback: ${message}`);
2246
+ }
1666
2247
  }
1667
2248
  /**
1668
- * Encerra um playback específico.
2249
+ * Stops a specific playback instance
2250
+ * @param {string} playbackId - ID of the playback to stop
2251
+ * @throws {Error} If the playback ID is invalid or the stop operation fails
1669
2252
  */
1670
2253
  async stop(playbackId) {
1671
- const playback = this.Playback({ id: playbackId });
1672
- await playback.stop();
2254
+ if (!playbackId) {
2255
+ throw new Error("Playback ID is required");
2256
+ }
2257
+ try {
2258
+ const playback = this.Playback({ id: playbackId });
2259
+ await playback.stop();
2260
+ console.log(`Playback ${playbackId} stopped`);
2261
+ } catch (error) {
2262
+ const message = getErrorMessage2(error);
2263
+ console.error(`Error stopping playback ${playbackId}:`, message);
2264
+ throw new Error(`Failed to stop playback: ${message}`);
2265
+ }
2266
+ }
2267
+ /**
2268
+ * Gets the count of active playback instances
2269
+ * @returns {number} Number of active playback instances
2270
+ */
2271
+ getInstanceCount() {
2272
+ return this.playbackInstances.size;
2273
+ }
2274
+ /**
2275
+ * Checks if a playback instance exists
2276
+ * @param {string} playbackId - ID of the playback to check
2277
+ * @returns {boolean} True if the playback instance exists
2278
+ */
2279
+ hasInstance(playbackId) {
2280
+ return this.playbackInstances.has(playbackId);
1673
2281
  }
1674
2282
  };
1675
2283
 
@@ -1708,40 +2316,51 @@ var Sounds = class {
1708
2316
  var import_exponential_backoff = __toESM(require_backoff(), 1);
1709
2317
  import { EventEmitter as EventEmitter3 } from "events";
1710
2318
  import WebSocket from "ws";
2319
+ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
2320
+ var DEFAULT_STARTING_DELAY = 500;
2321
+ var DEFAULT_MAX_DELAY = 1e4;
1711
2322
  var WebSocketClient = class extends EventEmitter3 {
2323
+ /**
2324
+ * Creates a new WebSocket client instance.
2325
+ *
2326
+ * @param {BaseClient} baseClient - The base client containing connection details
2327
+ * @param {string[]} apps - List of applications to connect to
2328
+ * @param {WebSocketEventType[]} [subscribedEvents] - Optional list of events to subscribe to
2329
+ * @param {AriClient} [ariClient] - Optional ARI client for handling channel and playback events
2330
+ */
1712
2331
  constructor(baseClient, apps, subscribedEvents, ariClient) {
1713
2332
  super();
1714
2333
  this.baseClient = baseClient;
1715
2334
  this.apps = apps;
1716
2335
  this.subscribedEvents = subscribedEvents;
1717
2336
  this.ariClient = ariClient;
2337
+ if (!apps.length) {
2338
+ throw new Error("At least one application name is required");
2339
+ }
1718
2340
  }
1719
2341
  ws;
1720
2342
  isReconnecting = false;
1721
- maxReconnectAttempts = 10;
2343
+ maxReconnectAttempts = DEFAULT_MAX_RECONNECT_ATTEMPTS;
1722
2344
  backOffOptions = {
1723
- numOfAttempts: 10,
1724
- // Máximo de tentativas de reconexão
1725
- startingDelay: 500,
1726
- // Início com 500ms de atraso
1727
- maxDelay: 1e4,
1728
- // Limite máximo de atraso de 10s
2345
+ numOfAttempts: DEFAULT_MAX_RECONNECT_ATTEMPTS,
2346
+ startingDelay: DEFAULT_STARTING_DELAY,
2347
+ maxDelay: DEFAULT_MAX_DELAY,
1729
2348
  timeMultiple: 2,
1730
- // Atraso aumenta exponencialmente
1731
2349
  jitter: "full",
1732
- // Randomização para evitar colisões
1733
2350
  delayFirstAttempt: false,
1734
- // Não atrase a primeira tentativa
1735
2351
  retry: (error, attemptNumber) => {
1736
2352
  console.warn(
1737
- `Tentativa #${attemptNumber} falhou:`,
1738
- error.message || error
2353
+ `Connection attempt #${attemptNumber} failed:`,
2354
+ error.message || "Unknown error"
1739
2355
  );
1740
- return true;
2356
+ return attemptNumber < this.maxReconnectAttempts;
1741
2357
  }
1742
2358
  };
1743
2359
  /**
1744
- * Conecta ao WebSocket.
2360
+ * Establishes a WebSocket connection.
2361
+ *
2362
+ * @returns {Promise<void>} Resolves when connection is established
2363
+ * @throws {Error} If connection fails
1745
2364
  */
1746
2365
  async connect() {
1747
2366
  const { baseUrl, username, password } = this.baseClient.getCredentials();
@@ -1749,7 +2368,7 @@ var WebSocketClient = class extends EventEmitter3 {
1749
2368
  const normalizedHost = baseUrl.replace(/^https?:\/\//, "").replace(/\/ari$/, "");
1750
2369
  const queryParams = new URLSearchParams();
1751
2370
  queryParams.append("app", this.apps.join(","));
1752
- if (this.subscribedEvents && this.subscribedEvents.length > 0) {
2371
+ if (this.subscribedEvents?.length) {
1753
2372
  this.subscribedEvents.forEach(
1754
2373
  (event) => queryParams.append("event", event)
1755
2374
  );
@@ -1757,48 +2376,57 @@ var WebSocketClient = class extends EventEmitter3 {
1757
2376
  queryParams.append("subscribeAll", "true");
1758
2377
  }
1759
2378
  const wsUrl = `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${normalizedHost}/ari/events?${queryParams.toString()}`;
1760
- console.log("Conectando ao WebSocket em:", wsUrl);
2379
+ console.log("Connecting to WebSocket...");
1761
2380
  return this.initializeWebSocket(wsUrl);
1762
2381
  }
1763
2382
  /**
1764
- * Inicializa a conexão WebSocket com lógica de reconexão.
2383
+ * Initializes WebSocket connection with reconnection logic.
2384
+ *
2385
+ * @param {string} wsUrl - The WebSocket URL to connect to
2386
+ * @returns {Promise<void>} Resolves when connection is established
1765
2387
  */
1766
2388
  async initializeWebSocket(wsUrl) {
1767
2389
  return (0, import_exponential_backoff.backOff)(async () => {
1768
2390
  return new Promise((resolve, reject) => {
1769
- this.ws = new WebSocket(wsUrl);
1770
- this.ws.on("open", () => {
1771
- console.log("WebSocket conectado com sucesso.");
1772
- this.isReconnecting = false;
1773
- this.emit("connected");
1774
- resolve();
1775
- });
1776
- this.ws.on("message", (data) => this.handleMessage(data.toString()));
1777
- this.ws.on("close", (code) => {
1778
- console.warn(
1779
- `WebSocket desconectado com c\xF3digo ${code}. Tentando reconectar...`
1780
- );
1781
- if (!this.isReconnecting) {
1782
- this.reconnect(wsUrl);
1783
- }
1784
- });
1785
- this.ws.on("error", (err) => {
1786
- console.error("Erro no WebSocket:", err.message);
1787
- if (!this.isReconnecting) {
1788
- this.reconnect(wsUrl);
1789
- }
1790
- reject(err);
1791
- });
2391
+ try {
2392
+ this.ws = new WebSocket(wsUrl);
2393
+ this.ws.on("open", () => {
2394
+ console.log("WebSocket connection established successfully");
2395
+ this.isReconnecting = false;
2396
+ this.emit("connected");
2397
+ resolve();
2398
+ });
2399
+ this.ws.on("message", (data) => this.handleMessage(data.toString()));
2400
+ this.ws.on("close", (code) => {
2401
+ console.warn(
2402
+ `WebSocket disconnected with code ${code}. Attempting to reconnect...`
2403
+ );
2404
+ if (!this.isReconnecting) {
2405
+ this.reconnect(wsUrl);
2406
+ }
2407
+ });
2408
+ this.ws.on("error", (err) => {
2409
+ console.error("WebSocket error:", err.message);
2410
+ if (!this.isReconnecting) {
2411
+ this.reconnect(wsUrl);
2412
+ }
2413
+ reject(err);
2414
+ });
2415
+ } catch (error) {
2416
+ reject(error);
2417
+ }
1792
2418
  });
1793
2419
  }, this.backOffOptions);
1794
2420
  }
1795
2421
  /**
1796
- * Processa as mensagens recebidas do WebSocket.
2422
+ * Processes incoming WebSocket messages.
2423
+ *
2424
+ * @param {string} rawMessage - The raw message received from WebSocket
1797
2425
  */
1798
2426
  handleMessage(rawMessage) {
1799
2427
  try {
1800
2428
  const event = JSON.parse(rawMessage);
1801
- if (this.subscribedEvents && !this.subscribedEvents.includes(event.type)) {
2429
+ if (this.subscribedEvents?.length && !this.subscribedEvents.includes(event.type)) {
1802
2430
  return;
1803
2431
  }
1804
2432
  if ("channel" in event && event.channel?.id && this.ariClient) {
@@ -1812,40 +2440,77 @@ var WebSocketClient = class extends EventEmitter3 {
1812
2440
  event.instancePlayback = instancePlayback;
1813
2441
  }
1814
2442
  this.emit(event.type, event);
1815
- } catch (err) {
1816
- console.error("Erro ao processar mensagem WebSocket:", err);
1817
- this.emit("error", new Error("Falha ao decodificar mensagem WebSocket."));
2443
+ console.log(`Event processed: ${event.type}`);
2444
+ } catch (error) {
2445
+ console.error("Error processing WebSocket message:", error instanceof Error ? error.message : "Unknown error");
2446
+ this.emit("error", new Error("Failed to decode WebSocket message"));
1818
2447
  }
1819
2448
  }
1820
2449
  /**
1821
- * Tenta reconectar ao WebSocket.
2450
+ * Attempts to reconnect to the WebSocket.
2451
+ *
2452
+ * @param {string} wsUrl - The WebSocket URL to reconnect to
1822
2453
  */
1823
2454
  reconnect(wsUrl) {
1824
2455
  this.isReconnecting = true;
1825
- console.log("Iniciando tentativa de reconex\xE3o...");
2456
+ console.log("Initiating reconnection attempt...");
1826
2457
  this.removeAllListeners();
1827
- (0, import_exponential_backoff.backOff)(() => this.initializeWebSocket(wsUrl), this.backOffOptions).catch(
1828
- (err) => {
1829
- console.error(
1830
- "Falha ao reconectar ap\xF3s v\xE1rias tentativas:",
1831
- err.message || err
1832
- );
1833
- }
1834
- );
2458
+ (0, import_exponential_backoff.backOff)(() => this.initializeWebSocket(wsUrl), this.backOffOptions).catch((error) => {
2459
+ console.error(
2460
+ "Failed to reconnect after multiple attempts:",
2461
+ error instanceof Error ? error.message : "Unknown error"
2462
+ );
2463
+ this.emit("reconnectFailed", error);
2464
+ });
1835
2465
  }
1836
2466
  /**
1837
- * Fecha o WebSocket manualmente.
2467
+ * Manually closes the WebSocket connection.
1838
2468
  */
1839
2469
  close() {
1840
- this.ws?.close();
1841
- this.ws = void 0;
2470
+ try {
2471
+ if (this.ws) {
2472
+ this.ws.close();
2473
+ this.ws = void 0;
2474
+ console.log("WebSocket connection closed");
2475
+ }
2476
+ } catch (error) {
2477
+ console.error(
2478
+ "Error closing WebSocket:",
2479
+ error instanceof Error ? error.message : "Unknown error"
2480
+ );
2481
+ }
2482
+ }
2483
+ /**
2484
+ * Checks if the WebSocket is currently connected.
2485
+ *
2486
+ * @returns {boolean} True if connected, false otherwise
2487
+ */
2488
+ isConnected() {
2489
+ return this.ws?.readyState === WebSocket.OPEN;
2490
+ }
2491
+ /**
2492
+ * Gets the current connection state.
2493
+ *
2494
+ * @returns {number} The WebSocket ready state
2495
+ */
2496
+ getState() {
2497
+ return this.ws?.readyState ?? WebSocket.CLOSED;
1842
2498
  }
1843
2499
  };
1844
2500
 
1845
2501
  // src/ari-client/ariClient.ts
1846
2502
  var AriClient = class {
2503
+ /**
2504
+ * Creates a new instance of the ARI client.
2505
+ *
2506
+ * @param {AriClientConfig} config - Configuration options for the ARI client
2507
+ * @throws {Error} If required configuration parameters are missing
2508
+ */
1847
2509
  constructor(config) {
1848
2510
  this.config = config;
2511
+ if (!config.host || !config.port || !config.username || !config.password) {
2512
+ throw new Error("Missing required configuration parameters");
2513
+ }
1849
2514
  const httpProtocol = config.secure ? "https" : "http";
1850
2515
  const normalizedHost = config.host.replace(/^https?:\/\//, "");
1851
2516
  const baseUrl = `${httpProtocol}://${normalizedHost}:${config.port}/ari`;
@@ -1857,6 +2522,7 @@ var AriClient = class {
1857
2522
  this.sounds = new Sounds(this.baseClient);
1858
2523
  this.asterisk = new Asterisk(this.baseClient);
1859
2524
  this.bridges = new Bridges(this.baseClient);
2525
+ console.log(`ARI Client initialized with base URL: ${baseUrl}`);
1860
2526
  }
1861
2527
  baseClient;
1862
2528
  webSocketClient;
@@ -1868,58 +2534,117 @@ var AriClient = class {
1868
2534
  asterisk;
1869
2535
  bridges;
1870
2536
  /**
1871
- * Inicializa uma conexão WebSocket.
2537
+ * Initializes a WebSocket connection for receiving events.
2538
+ *
2539
+ * @param {string[]} apps - List of application names to subscribe to
2540
+ * @param {WebSocketEventType[]} [subscribedEvents] - Optional list of specific event types to subscribe to
2541
+ * @returns {Promise<void>} Resolves when connection is established
2542
+ * @throws {Error} If connection fails or if WebSocket is already connected
1872
2543
  */
1873
2544
  async connectWebSocket(apps, subscribedEvents) {
2545
+ if (!apps.length) {
2546
+ throw new Error("At least one application name is required");
2547
+ }
1874
2548
  if (this.webSocketClient) {
1875
- console.warn("WebSocket j\xE1 est\xE1 conectado.");
2549
+ console.warn("WebSocket is already connected");
1876
2550
  return;
1877
2551
  }
1878
- this.webSocketClient = new WebSocketClient(
1879
- this.baseClient,
1880
- apps,
1881
- subscribedEvents,
1882
- this
1883
- );
1884
- await this.webSocketClient.connect();
2552
+ try {
2553
+ this.webSocketClient = new WebSocketClient(
2554
+ this.baseClient,
2555
+ apps,
2556
+ subscribedEvents,
2557
+ this
2558
+ );
2559
+ await this.webSocketClient.connect();
2560
+ console.log("WebSocket connection established successfully");
2561
+ } catch (error) {
2562
+ console.error("Failed to establish WebSocket connection:", error);
2563
+ this.webSocketClient = void 0;
2564
+ throw error;
2565
+ }
1885
2566
  }
1886
2567
  /**
1887
- * Adiciona um listener para eventos do WebSocket.
2568
+ * Registers an event listener for WebSocket events.
2569
+ *
2570
+ * @param {T} event - The event type to listen for
2571
+ * @param {Function} listener - Callback function for handling the event
2572
+ * @throws {Error} If WebSocket is not connected
1888
2573
  */
1889
2574
  on(event, listener) {
1890
- this.webSocketClient?.on(event, listener);
2575
+ if (!this.webSocketClient) {
2576
+ throw new Error("WebSocket is not connected");
2577
+ }
2578
+ this.webSocketClient.on(event, listener);
2579
+ console.log(`Event listener registered for ${event}`);
1891
2580
  }
1892
2581
  /**
1893
- * Adiciona um listener único para eventos do WebSocket.
2582
+ * Registers a one-time event listener for WebSocket events.
2583
+ *
2584
+ * @param {T} event - The event type to listen for
2585
+ * @param {Function} listener - Callback function for handling the event
2586
+ * @throws {Error} If WebSocket is not connected
1894
2587
  */
1895
2588
  once(event, listener) {
1896
- this.webSocketClient?.once(event, listener);
2589
+ if (!this.webSocketClient) {
2590
+ throw new Error("WebSocket is not connected");
2591
+ }
2592
+ this.webSocketClient.once(event, listener);
2593
+ console.log(`One-time event listener registered for ${event}`);
1897
2594
  }
1898
2595
  /**
1899
- * Remove um listener para eventos do WebSocket.
2596
+ * Removes an event listener for WebSocket events.
2597
+ *
2598
+ * @param {T} event - The event type to remove listener for
2599
+ * @param {Function} listener - The listener function to remove
1900
2600
  */
1901
2601
  off(event, listener) {
1902
- this.webSocketClient?.off(event, listener);
2602
+ if (!this.webSocketClient) {
2603
+ console.warn("No WebSocket connection to remove listener from");
2604
+ return;
2605
+ }
2606
+ this.webSocketClient.off(event, listener);
2607
+ console.log(`Event listener removed for ${event}`);
1903
2608
  }
1904
2609
  /**
1905
- * Fecha a conexão WebSocket.
2610
+ * Closes the WebSocket connection if one exists.
1906
2611
  */
1907
2612
  closeWebSocket() {
1908
- this.webSocketClient?.close();
2613
+ if (!this.webSocketClient) {
2614
+ console.warn("No WebSocket connection to close");
2615
+ return;
2616
+ }
2617
+ this.webSocketClient.close();
1909
2618
  this.webSocketClient = void 0;
2619
+ console.log("WebSocket connection closed");
1910
2620
  }
1911
2621
  /**
1912
- * Inicializa uma nova instância de `ChannelInstance` para manipular canais localmente.
2622
+ * Creates or retrieves a Channel instance.
2623
+ *
2624
+ * @param {string} [channelId] - Optional ID of an existing channel
2625
+ * @returns {ChannelInstance} A new or existing channel instance
1913
2626
  */
1914
2627
  Channel(channelId) {
1915
2628
  return this.channels.Channel({ id: channelId });
1916
2629
  }
1917
2630
  /**
1918
- * Inicializa uma nova instância de `PlaybackInstance` para manipular playbacks.
2631
+ * Creates or retrieves a Playback instance.
2632
+ *
2633
+ * @param {string} [playbackId] - Optional ID of an existing playback
2634
+ * @param {string} [_app] - Optional application name (deprecated)
2635
+ * @returns {PlaybackInstance} A new or existing playback instance
1919
2636
  */
1920
2637
  Playback(playbackId, _app) {
1921
2638
  return this.playbacks.Playback({ id: playbackId });
1922
2639
  }
2640
+ /**
2641
+ * Gets the current WebSocket connection status.
2642
+ *
2643
+ * @returns {boolean} True if WebSocket is connected, false otherwise
2644
+ */
2645
+ isWebSocketConnected() {
2646
+ return !!this.webSocketClient;
2647
+ }
1923
2648
  };
1924
2649
  export {
1925
2650
  Applications,