@adobe-commerce/aio-toolkit 1.2.2 → 1.2.3

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/index.mjs CHANGED
@@ -5877,11 +5877,15 @@ var _AbdbCollection = class _AbdbCollection {
5877
5877
  const collection = await client.collection(this._name);
5878
5878
  return await callback(collection, client);
5879
5879
  } catch (error) {
5880
- if (error instanceof DbError) {
5881
- throw new Error(`AbdbCollection: database error: ${error.message}`);
5880
+ if (DbError && error instanceof DbError) {
5881
+ const dbErr = new Error(`AbdbCollection: database error: ${error.message}`);
5882
+ dbErr.cause = error;
5883
+ throw dbErr;
5882
5884
  }
5883
5885
  const detail = error instanceof Error ? error.message : String(error);
5884
- throw new Error(`AbdbCollection: unexpected error: ${detail}`);
5886
+ const unexpectedErr = new Error(`AbdbCollection: unexpected error: ${detail}`);
5887
+ unexpectedErr.cause = error;
5888
+ throw unexpectedErr;
5885
5889
  } finally {
5886
5890
  await client?.close();
5887
5891
  }
@@ -11694,6 +11698,185 @@ __name(_OnboardCommerce, "OnboardCommerce");
11694
11698
  var OnboardCommerce = _OnboardCommerce;
11695
11699
  var onboard_commerce_default = OnboardCommerce;
11696
11700
 
11701
+ // src/integration/rabbit-mq-client/index.ts
11702
+ import amqplib from "amqplib";
11703
+ var _RabbitMQClient = class _RabbitMQClient {
11704
+ /**
11705
+ * @param credentials - AMQP connection credentials (host, port, username, password, vhost).
11706
+ */
11707
+ constructor(credentials) {
11708
+ this.credentials = credentials;
11709
+ }
11710
+ /**
11711
+ * Opens an AMQP connection, checks queue depth, sets prefetch for concurrency control,
11712
+ * and starts a push consumer. The broker delivers at most `maxParallel` unacked messages
11713
+ * at a time, so processing concurrency is naturally bounded without a separate semaphore.
11714
+ * The consumer is cancelled once `effectiveBatch = min(batchSize, messageCount)` messages
11715
+ * are received and processed. The connection is always closed in a `finally` block.
11716
+ *
11717
+ * @param queueName - Name of the queue to consume from.
11718
+ * @param options - Consume configuration (batchSize, maxParallel, nackRequeue, exchange).
11719
+ * @param handler - Callback invoked with the queue name and decoded string content of each message.
11720
+ * @returns Counts of consumed, acked, and nacked messages; plus per-failure details in `errors`.
11721
+ * @throws Propagates connection, exchange-assertion, or queue-assertion errors to the caller.
11722
+ */
11723
+ async consume(queueName, options, handler) {
11724
+ const connection = await amqplib.connect(this.buildConnectionUrl());
11725
+ let channel;
11726
+ try {
11727
+ channel = await connection.createChannel();
11728
+ if (options.exchange) {
11729
+ await channel.assertExchange(options.exchange, "direct", { durable: true });
11730
+ await channel.assertQueue(queueName, { durable: true });
11731
+ await channel.bindQueue(queueName, options.exchange, queueName);
11732
+ } else {
11733
+ await channel.assertQueue(queueName, { durable: true });
11734
+ }
11735
+ return await this.processBatch(channel, queueName, options, handler);
11736
+ } finally {
11737
+ await channel?.close();
11738
+ await connection.close();
11739
+ }
11740
+ }
11741
+ /**
11742
+ * Opens an AMQP connection, asserts the queue, and enqueues each payload in `payloads`.
11743
+ * Each payload is sent as a persistent message via `sendToQueue`. If the write buffer is
11744
+ * full (`sendToQueue` returns `false`) or the call throws, the payload is recorded in
11745
+ * `stats.errors` and counted as failed. The connection is always closed in a `finally`
11746
+ * block regardless of outcome.
11747
+ *
11748
+ * @param queueName - Name of the queue to publish to.
11749
+ * @param payloads - Array of string payloads to enqueue.
11750
+ * @returns Counts of published and failed messages; plus per-failure details in `errors`.
11751
+ * @throws Propagates connection or queue-assertion errors to the caller.
11752
+ */
11753
+ async publish(queueName, payloads) {
11754
+ const connection = await amqplib.connect(this.buildConnectionUrl());
11755
+ let channel;
11756
+ try {
11757
+ channel = await connection.createChannel();
11758
+ await channel.assertQueue(queueName, { durable: true });
11759
+ return this.publishBatch(channel, queueName, payloads);
11760
+ } finally {
11761
+ await channel?.close();
11762
+ await connection.close();
11763
+ }
11764
+ }
11765
+ /**
11766
+ * Sends each payload to the queue via `sendToQueue`. Tracks published and failed counts.
11767
+ * A payload is considered failed when `sendToQueue` returns `false` (write buffer full)
11768
+ * or throws an error.
11769
+ */
11770
+ publishBatch(channel, queueName, payloads) {
11771
+ const stats = { published: 0, failed: 0, errors: [] };
11772
+ for (const payload of payloads) {
11773
+ try {
11774
+ const sent = channel.sendToQueue(queueName, Buffer.from(payload), { persistent: true });
11775
+ if (sent) {
11776
+ stats.published++;
11777
+ } else {
11778
+ stats.failed++;
11779
+ stats.errors.push({ payload, error: new Error("Write buffer full") });
11780
+ }
11781
+ } catch (error) {
11782
+ stats.failed++;
11783
+ stats.errors.push({ payload, error });
11784
+ }
11785
+ }
11786
+ return stats;
11787
+ }
11788
+ /**
11789
+ * Builds the AMQP connection URL from the stored credentials.
11790
+ * Uses `amqps://` when `secure` is true, `amqp://` otherwise.
11791
+ * Username, password, and vhost are percent-encoded to handle special characters.
11792
+ */
11793
+ buildConnectionUrl() {
11794
+ const { host, port, username, password, vhost, secure = false } = this.credentials;
11795
+ const protocol = secure ? "amqps" : "amqp";
11796
+ return `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${host}:${port}/${encodeURIComponent(vhost)}`;
11797
+ }
11798
+ /**
11799
+ * Checks queue depth via `channel.checkQueue`, then sets `channel.prefetch(maxParallel)`
11800
+ * for broker-side concurrency control. Registers a push consumer that receives
11801
+ * `effectiveBatch = min(batchSize, messageCount)` messages. The Promise resolves after
11802
+ * `channel.consume` setup completes and all in-flight handlers have settled.
11803
+ *
11804
+ * Because the broker delivers at most `maxParallel` unacked messages at a time, processing
11805
+ * concurrency is bounded without a separate semaphore — each ack/nack releases a slot.
11806
+ */
11807
+ async processBatch(channel, queueName, options, handler) {
11808
+ const stats = { consumed: 0, acked: 0, nacked: 0, errors: [] };
11809
+ const maxParallel = Math.floor(options.maxParallel);
11810
+ const batchSize = Math.floor(options.batchSize);
11811
+ const { messageCount } = await channel.checkQueue(queueName);
11812
+ if (messageCount === 0) return stats;
11813
+ const effectiveBatch = Math.min(batchSize, messageCount);
11814
+ await channel.prefetch(maxParallel);
11815
+ return new Promise((resolve, reject) => {
11816
+ let consumerTag = "";
11817
+ let cancelRequested = false;
11818
+ let received = 0;
11819
+ let pending = 0;
11820
+ let setupDone = false;
11821
+ const maybeResolve = /* @__PURE__ */ __name(() => {
11822
+ if ((received >= effectiveBatch || cancelRequested) && pending === 0 && setupDone) {
11823
+ resolve(stats);
11824
+ }
11825
+ }, "maybeResolve");
11826
+ const msgCallback = /* @__PURE__ */ __name(async (msg) => {
11827
+ if (!msg || received >= effectiveBatch) return;
11828
+ received++;
11829
+ stats.consumed++;
11830
+ pending++;
11831
+ if (received >= effectiveBatch) {
11832
+ cancelRequested = true;
11833
+ if (consumerTag) {
11834
+ channel.cancel(consumerTag).catch(reject);
11835
+ }
11836
+ }
11837
+ await this.processMessage(channel, queueName, msg, stats, options, handler);
11838
+ pending--;
11839
+ maybeResolve();
11840
+ }, "msgCallback");
11841
+ channel.consume(queueName, msgCallback, { noAck: false }).then(async ({ consumerTag: tag }) => {
11842
+ consumerTag = tag;
11843
+ setupDone = true;
11844
+ if (cancelRequested) {
11845
+ channel.cancel(tag).catch(reject);
11846
+ } else if (received === 0) {
11847
+ const { messageCount: remaining } = await channel.checkQueue(queueName);
11848
+ if (remaining === 0) {
11849
+ cancelRequested = true;
11850
+ channel.cancel(tag).catch(reject);
11851
+ }
11852
+ }
11853
+ maybeResolve();
11854
+ }).catch(reject);
11855
+ });
11856
+ }
11857
+ /**
11858
+ * Invokes `handler` with the queue name and decoded message content. Acks on success.
11859
+ * On failure, nacks the message and records the content and error in `stats.errors`.
11860
+ * Whether to requeue on nack is controlled by `options.nackRequeue` (default: true).
11861
+ */
11862
+ async processMessage(channel, queueName, msg, stats, options, handler) {
11863
+ const { nackRequeue = true } = options;
11864
+ const content = msg.content.toString();
11865
+ try {
11866
+ await handler(queueName, content);
11867
+ channel.ack(msg);
11868
+ stats.acked++;
11869
+ } catch (error) {
11870
+ channel.nack(msg, false, nackRequeue);
11871
+ stats.errors.push({ content, error });
11872
+ stats.nacked++;
11873
+ }
11874
+ }
11875
+ };
11876
+ __name(_RabbitMQClient, "RabbitMQClient");
11877
+ var RabbitMQClient = _RabbitMQClient;
11878
+ var rabbit_mq_client_default = RabbitMQClient;
11879
+
11697
11880
  // src/commerce/adobe-commerce-client/index.ts
11698
11881
  import got from "got";
11699
11882
  var _AdobeCommerceClient = class _AdobeCommerceClient {
@@ -12713,6 +12896,7 @@ export {
12713
12896
  parameters_default as Parameters,
12714
12897
  provider_default as ProviderManager,
12715
12898
  publish_event_default as PublishEvent,
12899
+ rabbit_mq_client_default as RabbitMQClient,
12716
12900
  registration_default as RegistrationManager,
12717
12901
  rest_client_default as RestClient,
12718
12902
  runtime_action_default as RuntimeAction,