@experteam-mx/ngx-services 20.9.9 → 20.9.11

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.
@@ -1904,13 +1904,13 @@ class ApiCompaniesService {
1904
1904
  .pipe(map(({ data }) => data));
1905
1905
  }
1906
1906
  /**
1907
- * Exports the filtered employees list as a PDF file.
1907
+ * Exports the filtered employees list as an Excel file.
1908
1908
  *
1909
1909
  * @param {QueryParams} params - Query parameters used to filter the employees included in the export.
1910
- * @return {Observable<HttpResponse<ArrayBuffer>>} An observable that emits the HTTP response containing the PDF as an ArrayBuffer.
1910
+ * @return {Observable<HttpResponse<ArrayBuffer>>} An observable that emits the HTTP response containing the Excel file as an ArrayBuffer.
1911
1911
  */
1912
- getEmployeesExportPdf(params) {
1913
- return this.http.get(`${this.url}/employees/exportPdf`, {
1912
+ getEmployeesExportData(params) {
1913
+ return this.http.get(`${this.url}/employees/exportData`, {
1914
1914
  params,
1915
1915
  observe: 'response',
1916
1916
  responseType: 'arraybuffer'
@@ -5912,16 +5912,80 @@ var CustomerRoleType;
5912
5912
  CustomerRoleType["EXPORTER"] = "EP";
5913
5913
  })(CustomerRoleType || (CustomerRoleType = {}));
5914
5914
 
5915
+ const SOCKETS_AUTH_PATH = '/sockets/auth';
5915
5916
  class WebSocketsService {
5916
- pusher;
5917
+ pusher = null;
5918
+ appKey = null;
5919
+ connectPromise = null;
5917
5920
  environments = inject(ENVIRONMENT_TOKEN);
5918
- constructor() {
5919
- this.pusher = null;
5920
- this.connect()
5921
- .then((pusher) => {
5922
- if (!pusher)
5923
- return;
5921
+ getAuthToken = null;
5922
+ channelAuthHeaders = {};
5923
+ /**
5924
+ * Stores the Pusher/Soketi application key without opening a connection.
5925
+ * The first `channelSub` / `eventBind` opens Pusher via `ensureConnected`.
5926
+ *
5927
+ * @param {string} appKey - The Pusher/Soketi application key.
5928
+ */
5929
+ setAppKey(appKey) {
5930
+ this.appKey = appKey;
5931
+ }
5932
+ /**
5933
+ * Registers a live token provider used when authorizing private/presence channels.
5934
+ * The provider is called at subscribe/authorize time; the token is not snapshotted here.
5935
+ *
5936
+ * @param {() => string | null} getToken - Returns the current session token, or null.
5937
+ */
5938
+ setAuthTokenProvider(getToken) {
5939
+ this.getAuthToken = getToken;
5940
+ }
5941
+ /**
5942
+ * Connects to Pusher using the given app key and env `sockets` url/port/debug.
5943
+ * No-ops if already connected with the same key; reconnects if the key changed.
5944
+ * Resolves false when `sockets` is missing from the environment.
5945
+ * Apps should store the key with `setAppKey` and let subscribe open the client.
5946
+ *
5947
+ * @param {string} appKey - The Pusher/Soketi application key.
5948
+ * @return {Promise<Pusher | false>} The Pusher instance, or false when sockets are not configured.
5949
+ */
5950
+ connect(appKey) {
5951
+ this.setAppKey(appKey);
5952
+ return new Promise((resolve) => {
5953
+ if (this.pusher && this.appKey === appKey) {
5954
+ return resolve(this.pusher);
5955
+ }
5956
+ const { sockets } = this.environments;
5957
+ if (!sockets)
5958
+ return resolve(false);
5959
+ if (this.pusher) {
5960
+ this.pusher.disconnect();
5961
+ this.pusher = null;
5962
+ }
5963
+ const options = {
5964
+ wsHost: sockets.url,
5965
+ wsPort: sockets.port,
5966
+ enabledTransports: ['wss', 'ws'],
5967
+ forceTLS: false,
5968
+ enableStats: false,
5969
+ };
5970
+ const { apiSecurityUrl } = this.environments;
5971
+ if (apiSecurityUrl) {
5972
+ this.refreshChannelAuthHeader();
5973
+ options.channelAuthorization = {
5974
+ transport: 'ajax',
5975
+ endpoint: `${apiSecurityUrl}${SOCKETS_AUTH_PATH}`,
5976
+ headers: this.channelAuthHeaders,
5977
+ headersProvider: () => {
5978
+ this.refreshChannelAuthHeader();
5979
+ return this.channelAuthHeaders;
5980
+ },
5981
+ };
5982
+ }
5983
+ const pusher = new Pusher(appKey, options);
5984
+ if (sockets.debug) {
5985
+ Pusher.logToConsole = true;
5986
+ }
5924
5987
  this.pusher = pusher;
5988
+ return resolve(pusher);
5925
5989
  });
5926
5990
  }
5927
5991
  /**
@@ -5937,25 +6001,40 @@ class WebSocketsService {
5937
6001
  return channel.trigger(`client-${eventName}`, data);
5938
6002
  }
5939
6003
  /**
5940
- * Subscribes to a specified channel, retrying multiple times upon failure.
6004
+ * Subscribes to a specified channel and resolves when Pusher reports success.
5941
6005
  *
5942
6006
  * @param {string} channelName - The name of the channel to be subscribed to.
5943
6007
  * @return {Promise<Channel>} A promise that resolves to the subscribed channel object if successful.
5944
- * @throws {Error} If the subscription fails after the maximum number of retry attempts.
6008
+ * @throws {Error} If the subscription fails.
5945
6009
  */
5946
6010
  async channelSub(channelName) {
5947
- const attempts = 3;
5948
- for (let attempt = 0; attempt <= attempts; attempt++) {
5949
- const channel = this.pusher?.channel(channelName);
5950
- if (channel?.subscribed) {
5951
- return channel;
5952
- }
5953
- this.pusher?.subscribe(channelName);
5954
- if (attempt < attempts) {
5955
- await this.wait();
5956
- }
6011
+ const pusher = await this.ensureConnected();
6012
+ this.refreshChannelAuthHeader();
6013
+ const existing = pusher.channel(channelName);
6014
+ if (existing?.subscribed) {
6015
+ return existing;
5957
6016
  }
5958
- throw new Error(`Failed to subscribe to channel "${channelName}" after ${attempts} attempts.`);
6017
+ const channel = pusher.subscribe(channelName);
6018
+ if (channel.subscribed) {
6019
+ return channel;
6020
+ }
6021
+ await new Promise((resolve, reject) => {
6022
+ const onSuccess = () => {
6023
+ cleanup();
6024
+ resolve();
6025
+ };
6026
+ const onError = () => {
6027
+ cleanup();
6028
+ reject(new Error(`Failed to subscribe to channel "${channelName}".`));
6029
+ };
6030
+ const cleanup = () => {
6031
+ channel.unbind('pusher:subscription_succeeded', onSuccess);
6032
+ channel.unbind('pusher:subscription_error', onError);
6033
+ };
6034
+ channel.bind('pusher:subscription_succeeded', onSuccess);
6035
+ channel.bind('pusher:subscription_error', onError);
6036
+ });
6037
+ return channel;
5959
6038
  }
5960
6039
  /**
5961
6040
  * Binds an event listener to a specified event on a given channel using Pusher or a Channel object,
@@ -5969,11 +6048,19 @@ class WebSocketsService {
5969
6048
  return new Observable((subscriber) => {
5970
6049
  if (channel?.name) {
5971
6050
  channel.bind(event, (data) => subscriber.next(data));
6051
+ return;
5972
6052
  }
5973
- else {
5974
- this.pusher?.subscribe(channel)
5975
- .bind(event, (data) => subscriber.next(data));
5976
- }
6053
+ void (async () => {
6054
+ try {
6055
+ const pusher = await this.ensureConnected();
6056
+ this.refreshChannelAuthHeader();
6057
+ pusher.subscribe(channel)
6058
+ .bind(event, (data) => subscriber.next(data));
6059
+ }
6060
+ catch (error) {
6061
+ subscriber.error(error);
6062
+ }
6063
+ })();
5977
6064
  });
5978
6065
  }
5979
6066
  /**
@@ -5987,27 +6074,41 @@ class WebSocketsService {
5987
6074
  eventUnbind(channel, event) {
5988
6075
  return new Observable((subscriber) => channel.unbind(event, (data) => subscriber.next(data)));
5989
6076
  }
5990
- connect() {
5991
- return new Promise((resolve) => {
5992
- const { sockets } = this.environments;
5993
- if (!sockets)
5994
- return resolve(false);
5995
- const pusher = new Pusher(sockets.app_key, {
5996
- wsHost: sockets.url,
5997
- wsPort: sockets.port,
5998
- enabledTransports: ['wss', 'ws'],
5999
- forceTLS: false,
6000
- enableStats: false,
6001
- });
6002
- if (sockets.debug) {
6003
- Pusher.logToConsole = true;
6077
+ /**
6078
+ * Unsubscribes from a channel by name.
6079
+ *
6080
+ * @param {string} channelName - The channel name previously passed to subscribe.
6081
+ */
6082
+ unsubscribe(channelName) {
6083
+ this.pusher?.unsubscribe(channelName);
6084
+ }
6085
+ async ensureConnected() {
6086
+ if (this.pusher)
6087
+ return this.pusher;
6088
+ if (!this.appKey) {
6089
+ throw new Error('The sockets connection is not established.');
6090
+ }
6091
+ this.connectPromise ??= this.connect(this.appKey);
6092
+ try {
6093
+ const pusher = await this.connectPromise;
6094
+ if (!pusher) {
6095
+ throw new Error('The sockets connection is not established.');
6004
6096
  }
6005
- return resolve(pusher);
6006
- });
6097
+ return pusher;
6098
+ }
6099
+ catch (error) {
6100
+ this.connectPromise = null;
6101
+ throw error;
6102
+ }
6007
6103
  }
6008
- async wait() {
6009
- const waitTime = 3 * 1000;
6010
- return new Promise((resolve) => setTimeout(resolve, waitTime));
6104
+ refreshChannelAuthHeader() {
6105
+ const token = this.getAuthToken?.() ?? null;
6106
+ if (token) {
6107
+ this.channelAuthHeaders['Authorization'] = `Bearer ${token}`;
6108
+ }
6109
+ else {
6110
+ delete this.channelAuthHeaders['Authorization'];
6111
+ }
6011
6112
  }
6012
6113
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: WebSocketsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6013
6114
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: WebSocketsService, providedIn: 'root' });
@@ -6017,13 +6118,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
6017
6118
  args: [{
6018
6119
  providedIn: 'root',
6019
6120
  }]
6020
- }], ctorParameters: () => [] });
6121
+ }] });
6021
6122
 
6022
6123
  const AES_KEY_USAGES = ['encrypt', 'decrypt'];
6023
6124
  class CryptoService {
6024
- environments = inject(ENVIRONMENT_TOKEN);
6025
- async encryptAES(plaintext) {
6026
- const cryptoKey = await this.loadKey();
6125
+ async encryptAES(plaintext, secretKey) {
6126
+ const cryptoKey = await this.loadKey(secretKey);
6027
6127
  // Convert the plaintext in Uint8Array
6028
6128
  const encoder = new TextEncoder();
6029
6129
  const encoded = encoder.encode(plaintext);
@@ -6036,13 +6136,13 @@ class CryptoService {
6036
6136
  }, cryptoKey, encoded);
6037
6137
  return `${this.uint8ArrayToBase64(iv)}:${this.arrayBufferToBase64(ciphertext)}`;
6038
6138
  }
6039
- async decryptAES(payload) {
6139
+ async decryptAES(payload, secretKey) {
6040
6140
  // Extract the Initialization Vector (IV), and the cypher text
6041
6141
  const [base64IV, base64Ciphertext] = payload.split(':');
6042
6142
  if (!base64IV || !base64Ciphertext) {
6043
6143
  throw new Error('The payload must contain the IV and the cipher text.');
6044
6144
  }
6045
- const cryptoKey = await this.loadKey();
6145
+ const cryptoKey = await this.loadKey(secretKey);
6046
6146
  const iv = this.base64ToUint8Array(base64IV);
6047
6147
  const cipherText = this.base64ToArrayBuffer(base64Ciphertext);
6048
6148
  // Decrypt the cypher text
@@ -6054,14 +6154,12 @@ class CryptoService {
6054
6154
  const decoder = new TextDecoder();
6055
6155
  return decoder.decode(decrypted);
6056
6156
  }
6057
- async loadKey() {
6058
- if (!this.environments.secretKey) {
6059
- throw new Error('The secret key is not defined in the environment configuration.');
6157
+ async loadKey(secretKey) {
6158
+ if (!secretKey) {
6159
+ throw new Error('The secret key is not defined.');
6060
6160
  }
6061
- // Decode the base64 key to Uint8Array
6062
- const rawKey = this.base64ToUint8Array(this.environments.secretKey);
6063
- // Import the key to API Crypto
6064
- return await crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, AES_KEY_USAGES);
6161
+ const rawKey = new TextEncoder().encode(secretKey);
6162
+ return crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, AES_KEY_USAGES);
6065
6163
  }
6066
6164
  uint8ArrayToBase64(data) {
6067
6165
  let binary = '';