@adobe-commerce/aio-toolkit 1.2.3 → 1.2.5
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/CHANGELOG.md +92 -0
- package/README.md +48 -7
- package/dist/aio-toolkit-onboard-events/bin/cli.js.map +1 -1
- package/dist/index.d.mts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +73 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +73 -74
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -5978,13 +5978,31 @@ var _AbdbRepository = class _AbdbRepository {
|
|
|
5978
5978
|
* Returns all documents matching `filter` as an array.
|
|
5979
5979
|
* Passing no filter (or an empty object) returns every document in the collection.
|
|
5980
5980
|
*
|
|
5981
|
+
* Pagination and sorting are applied in the following MongoDB cursor order:
|
|
5982
|
+
* `.find(filter)` → `.sort(...)` → `.skip(...)` → `.limit(...)` → `.toArray()`
|
|
5983
|
+
*
|
|
5981
5984
|
* @param filter - Optional query filter (default: `{}`)
|
|
5985
|
+
* @param options - Optional pagination and sort configuration
|
|
5986
|
+
* @param options.sort - Column and direction to sort by (`'asc'` maps to `1`, `'desc'` to `-1`)
|
|
5987
|
+
* @param options.page_size - Maximum number of documents to return
|
|
5988
|
+
* @param options.current_page - 1-based page index; combined with `page_size` to compute `.skip()`
|
|
5982
5989
|
* @returns Array of matched documents (may be empty)
|
|
5983
5990
|
*/
|
|
5984
|
-
async find(filter = {}) {
|
|
5991
|
+
async find(filter = {}, options = {}) {
|
|
5985
5992
|
return this._collection.run(
|
|
5986
5993
|
async (collection) => {
|
|
5987
|
-
|
|
5994
|
+
const { current_page, page_size, sort } = options;
|
|
5995
|
+
let cursor = collection.find(filter);
|
|
5996
|
+
if (sort?.column) {
|
|
5997
|
+
cursor = cursor.sort({ [sort.column]: sort.direction === "desc" ? -1 : 1 });
|
|
5998
|
+
}
|
|
5999
|
+
if (page_size !== void 0 && page_size > 0) {
|
|
6000
|
+
if (current_page !== void 0 && current_page > 1) {
|
|
6001
|
+
cursor = cursor.skip((current_page - 1) * page_size);
|
|
6002
|
+
}
|
|
6003
|
+
cursor = cursor.limit(page_size);
|
|
6004
|
+
}
|
|
6005
|
+
return cursor.toArray();
|
|
5988
6006
|
},
|
|
5989
6007
|
this._token,
|
|
5990
6008
|
this._region
|
|
@@ -6405,7 +6423,7 @@ var _WebhookActionResponse = class _WebhookActionResponse {
|
|
|
6405
6423
|
* processing the webhook. This helps with debugging and error tracking.
|
|
6406
6424
|
*
|
|
6407
6425
|
* @param message - Optional error message describing what went wrong
|
|
6408
|
-
* @param
|
|
6426
|
+
* @param exceptionType - Optional exception type name for categorization (e.g., 'Magento\\Framework\\Exception\\LocalizedException')
|
|
6409
6427
|
* @returns An exception response object
|
|
6410
6428
|
*
|
|
6411
6429
|
* @example
|
|
@@ -6427,15 +6445,15 @@ var _WebhookActionResponse = class _WebhookActionResponse {
|
|
|
6427
6445
|
* });
|
|
6428
6446
|
* ```
|
|
6429
6447
|
*/
|
|
6430
|
-
static exception(message,
|
|
6448
|
+
static exception(message, exceptionType) {
|
|
6431
6449
|
const response = {
|
|
6432
6450
|
op: "exception" /* EXCEPTION */
|
|
6433
6451
|
};
|
|
6434
6452
|
if (message !== void 0) {
|
|
6435
6453
|
response.message = message;
|
|
6436
6454
|
}
|
|
6437
|
-
if (
|
|
6438
|
-
response.
|
|
6455
|
+
if (exceptionType !== void 0) {
|
|
6456
|
+
response.type = exceptionType;
|
|
6439
6457
|
}
|
|
6440
6458
|
return response;
|
|
6441
6459
|
}
|
|
@@ -11708,11 +11726,11 @@ var _RabbitMQClient = class _RabbitMQClient {
|
|
|
11708
11726
|
this.credentials = credentials;
|
|
11709
11727
|
}
|
|
11710
11728
|
/**
|
|
11711
|
-
* Opens an AMQP connection, checks queue depth,
|
|
11712
|
-
*
|
|
11713
|
-
*
|
|
11714
|
-
*
|
|
11715
|
-
*
|
|
11729
|
+
* Opens an AMQP connection, checks queue depth, and pulls up to
|
|
11730
|
+
* `effectiveBatch = min(batchSize, messageCount)` messages via channel.get.
|
|
11731
|
+
* Messages are processed in parallel windows of `maxParallel`. channel.get returns
|
|
11732
|
+
* false when the queue is empty, so the method exits deterministically without any
|
|
11733
|
+
* cancellation logic. The connection is always closed in a `finally` block.
|
|
11716
11734
|
*
|
|
11717
11735
|
* @param queueName - Name of the queue to consume from.
|
|
11718
11736
|
* @param options - Consume configuration (batchSize, maxParallel, nackRequeue, exchange).
|
|
@@ -11734,16 +11752,20 @@ var _RabbitMQClient = class _RabbitMQClient {
|
|
|
11734
11752
|
}
|
|
11735
11753
|
return await this.processBatch(channel, queueName, options, handler);
|
|
11736
11754
|
} finally {
|
|
11737
|
-
|
|
11755
|
+
try {
|
|
11756
|
+
await channel?.close();
|
|
11757
|
+
} catch {
|
|
11758
|
+
}
|
|
11738
11759
|
await connection.close();
|
|
11739
11760
|
}
|
|
11740
11761
|
}
|
|
11741
11762
|
/**
|
|
11742
11763
|
* Opens an AMQP connection, asserts the queue, and enqueues each payload in `payloads`.
|
|
11743
11764
|
* Each payload is sent as a persistent message via `sendToQueue`. If the write buffer is
|
|
11744
|
-
* full (`sendToQueue` returns `false`)
|
|
11745
|
-
*
|
|
11746
|
-
*
|
|
11765
|
+
* full (`sendToQueue` returns `false`), the message is still counted as published and the
|
|
11766
|
+
* method waits for the channel's `drain` event before continuing, to respect backpressure
|
|
11767
|
+
* without losing messages. Only genuine send errors (thrown exceptions) are counted as
|
|
11768
|
+
* failures. The connection is always closed in a `finally` block regardless of outcome.
|
|
11747
11769
|
*
|
|
11748
11770
|
* @param queueName - Name of the queue to publish to.
|
|
11749
11771
|
* @param payloads - Array of string payloads to enqueue.
|
|
@@ -11756,27 +11778,30 @@ var _RabbitMQClient = class _RabbitMQClient {
|
|
|
11756
11778
|
try {
|
|
11757
11779
|
channel = await connection.createChannel();
|
|
11758
11780
|
await channel.assertQueue(queueName, { durable: true });
|
|
11759
|
-
return this.publishBatch(channel, queueName, payloads);
|
|
11781
|
+
return await this.publishBatch(channel, queueName, payloads);
|
|
11760
11782
|
} finally {
|
|
11761
|
-
|
|
11783
|
+
try {
|
|
11784
|
+
await channel?.close();
|
|
11785
|
+
} catch {
|
|
11786
|
+
}
|
|
11762
11787
|
await connection.close();
|
|
11763
11788
|
}
|
|
11764
11789
|
}
|
|
11765
11790
|
/**
|
|
11766
11791
|
* Sends each payload to the queue via `sendToQueue`. Tracks published and failed counts.
|
|
11767
|
-
*
|
|
11768
|
-
*
|
|
11792
|
+
* When `sendToQueue` returns `false` (write buffer full / backpressure), the message is
|
|
11793
|
+
* still counted as published — it is already accepted by the channel — and the loop
|
|
11794
|
+
* pauses until the channel emits `drain` before continuing, preventing unbounded memory
|
|
11795
|
+
* pressure. A payload is only counted as failed when `sendToQueue` throws an error.
|
|
11769
11796
|
*/
|
|
11770
|
-
publishBatch(channel, queueName, payloads) {
|
|
11797
|
+
async publishBatch(channel, queueName, payloads) {
|
|
11771
11798
|
const stats = { published: 0, failed: 0, errors: [] };
|
|
11772
11799
|
for (const payload of payloads) {
|
|
11773
11800
|
try {
|
|
11774
11801
|
const sent = channel.sendToQueue(queueName, Buffer.from(payload), { persistent: true });
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
stats.failed++;
|
|
11779
|
-
stats.errors.push({ payload, error: new Error("Write buffer full") });
|
|
11802
|
+
stats.published++;
|
|
11803
|
+
if (!sent) {
|
|
11804
|
+
await new Promise((resolve) => channel.once("drain", resolve));
|
|
11780
11805
|
}
|
|
11781
11806
|
} catch (error) {
|
|
11782
11807
|
stats.failed++;
|
|
@@ -11796,63 +11821,37 @@ var _RabbitMQClient = class _RabbitMQClient {
|
|
|
11796
11821
|
return `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${host}:${port}/${encodeURIComponent(vhost)}`;
|
|
11797
11822
|
}
|
|
11798
11823
|
/**
|
|
11799
|
-
* Checks queue depth via
|
|
11800
|
-
*
|
|
11801
|
-
*
|
|
11802
|
-
*
|
|
11824
|
+
* Checks queue depth via channel.checkQueue, then pulls up to
|
|
11825
|
+
* `effectiveBatch = min(batchSize, messageCount)` messages using channel.get
|
|
11826
|
+
* (AMQP basic.get). Messages are processed in parallel windows of `maxParallel`:
|
|
11827
|
+
* each window pulls up to `maxParallel` messages sequentially, then processes them
|
|
11828
|
+
* concurrently via Promise.all before moving to the next window.
|
|
11803
11829
|
*
|
|
11804
|
-
*
|
|
11805
|
-
*
|
|
11830
|
+
* channel.get returns false when the queue is empty, so the loop exits immediately
|
|
11831
|
+
* if siblings have drained the queue — no consumer registration, no cancel, no hang.
|
|
11806
11832
|
*/
|
|
11807
11833
|
async processBatch(channel, queueName, options, handler) {
|
|
11808
11834
|
const stats = { consumed: 0, acked: 0, nacked: 0, errors: [] };
|
|
11809
|
-
const maxParallel =
|
|
11810
|
-
const batchSize = Math.floor(options.batchSize);
|
|
11835
|
+
const { batchSize, maxParallel } = options;
|
|
11811
11836
|
const { messageCount } = await channel.checkQueue(queueName);
|
|
11812
11837
|
if (messageCount === 0) return stats;
|
|
11813
11838
|
const effectiveBatch = Math.min(batchSize, messageCount);
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
let
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
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++;
|
|
11839
|
+
while (stats.consumed < effectiveBatch) {
|
|
11840
|
+
const windowSize = Math.min(maxParallel, effectiveBatch - stats.consumed);
|
|
11841
|
+
const window = [];
|
|
11842
|
+
for (let i = 0; i < windowSize; i++) {
|
|
11843
|
+
const msg = await channel.get(queueName, { noAck: false });
|
|
11844
|
+
if (!msg) break;
|
|
11845
|
+
window.push(msg);
|
|
11829
11846
|
stats.consumed++;
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
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
|
-
});
|
|
11847
|
+
}
|
|
11848
|
+
if (window.length === 0) break;
|
|
11849
|
+
await Promise.all(
|
|
11850
|
+
window.map((msg) => this.processMessage(channel, queueName, msg, stats, options, handler))
|
|
11851
|
+
);
|
|
11852
|
+
if (window.length < windowSize) break;
|
|
11853
|
+
}
|
|
11854
|
+
return stats;
|
|
11856
11855
|
}
|
|
11857
11856
|
/**
|
|
11858
11857
|
* Invokes `handler` with the queue name and decoded message content. Acks on success.
|