@adobe-commerce/aio-toolkit 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +136 -0
- package/README.md +145 -3
- package/dist/aio-toolkit-onboard-events/bin/cli.js.map +1 -1
- package/dist/index.d.mts +58 -4
- package/dist/index.d.ts +58 -4
- package/dist/index.js +193 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +192 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
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
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -5974,13 +5978,31 @@ var _AbdbRepository = class _AbdbRepository {
|
|
|
5974
5978
|
* Returns all documents matching `filter` as an array.
|
|
5975
5979
|
* Passing no filter (or an empty object) returns every document in the collection.
|
|
5976
5980
|
*
|
|
5981
|
+
* Pagination and sorting are applied in the following MongoDB cursor order:
|
|
5982
|
+
* `.find(filter)` → `.sort(...)` → `.skip(...)` → `.limit(...)` → `.toArray()`
|
|
5983
|
+
*
|
|
5977
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()`
|
|
5978
5989
|
* @returns Array of matched documents (may be empty)
|
|
5979
5990
|
*/
|
|
5980
|
-
async find(filter = {}) {
|
|
5991
|
+
async find(filter = {}, options = {}) {
|
|
5981
5992
|
return this._collection.run(
|
|
5982
5993
|
async (collection) => {
|
|
5983
|
-
|
|
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();
|
|
5984
6006
|
},
|
|
5985
6007
|
this._token,
|
|
5986
6008
|
this._region
|
|
@@ -6401,7 +6423,7 @@ var _WebhookActionResponse = class _WebhookActionResponse {
|
|
|
6401
6423
|
* processing the webhook. This helps with debugging and error tracking.
|
|
6402
6424
|
*
|
|
6403
6425
|
* @param message - Optional error message describing what went wrong
|
|
6404
|
-
* @param
|
|
6426
|
+
* @param exceptionType - Optional exception type name for categorization (e.g., 'Magento\\Framework\\Exception\\LocalizedException')
|
|
6405
6427
|
* @returns An exception response object
|
|
6406
6428
|
*
|
|
6407
6429
|
* @example
|
|
@@ -6423,15 +6445,15 @@ var _WebhookActionResponse = class _WebhookActionResponse {
|
|
|
6423
6445
|
* });
|
|
6424
6446
|
* ```
|
|
6425
6447
|
*/
|
|
6426
|
-
static exception(message,
|
|
6448
|
+
static exception(message, exceptionType) {
|
|
6427
6449
|
const response = {
|
|
6428
6450
|
op: "exception" /* EXCEPTION */
|
|
6429
6451
|
};
|
|
6430
6452
|
if (message !== void 0) {
|
|
6431
6453
|
response.message = message;
|
|
6432
6454
|
}
|
|
6433
|
-
if (
|
|
6434
|
-
response.
|
|
6455
|
+
if (exceptionType !== void 0) {
|
|
6456
|
+
response.type = exceptionType;
|
|
6435
6457
|
}
|
|
6436
6458
|
return response;
|
|
6437
6459
|
}
|
|
@@ -11694,6 +11716,166 @@ __name(_OnboardCommerce, "OnboardCommerce");
|
|
|
11694
11716
|
var OnboardCommerce = _OnboardCommerce;
|
|
11695
11717
|
var onboard_commerce_default = OnboardCommerce;
|
|
11696
11718
|
|
|
11719
|
+
// src/integration/rabbit-mq-client/index.ts
|
|
11720
|
+
import amqplib from "amqplib";
|
|
11721
|
+
var _RabbitMQClient = class _RabbitMQClient {
|
|
11722
|
+
/**
|
|
11723
|
+
* @param credentials - AMQP connection credentials (host, port, username, password, vhost).
|
|
11724
|
+
*/
|
|
11725
|
+
constructor(credentials) {
|
|
11726
|
+
this.credentials = credentials;
|
|
11727
|
+
}
|
|
11728
|
+
/**
|
|
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.
|
|
11734
|
+
*
|
|
11735
|
+
* @param queueName - Name of the queue to consume from.
|
|
11736
|
+
* @param options - Consume configuration (batchSize, maxParallel, nackRequeue, exchange).
|
|
11737
|
+
* @param handler - Callback invoked with the queue name and decoded string content of each message.
|
|
11738
|
+
* @returns Counts of consumed, acked, and nacked messages; plus per-failure details in `errors`.
|
|
11739
|
+
* @throws Propagates connection, exchange-assertion, or queue-assertion errors to the caller.
|
|
11740
|
+
*/
|
|
11741
|
+
async consume(queueName, options, handler) {
|
|
11742
|
+
const connection = await amqplib.connect(this.buildConnectionUrl());
|
|
11743
|
+
let channel;
|
|
11744
|
+
try {
|
|
11745
|
+
channel = await connection.createChannel();
|
|
11746
|
+
if (options.exchange) {
|
|
11747
|
+
await channel.assertExchange(options.exchange, "direct", { durable: true });
|
|
11748
|
+
await channel.assertQueue(queueName, { durable: true });
|
|
11749
|
+
await channel.bindQueue(queueName, options.exchange, queueName);
|
|
11750
|
+
} else {
|
|
11751
|
+
await channel.assertQueue(queueName, { durable: true });
|
|
11752
|
+
}
|
|
11753
|
+
return await this.processBatch(channel, queueName, options, handler);
|
|
11754
|
+
} finally {
|
|
11755
|
+
try {
|
|
11756
|
+
await channel?.close();
|
|
11757
|
+
} catch {
|
|
11758
|
+
}
|
|
11759
|
+
await connection.close();
|
|
11760
|
+
}
|
|
11761
|
+
}
|
|
11762
|
+
/**
|
|
11763
|
+
* Opens an AMQP connection, asserts the queue, and enqueues each payload in `payloads`.
|
|
11764
|
+
* Each payload is sent as a persistent message via `sendToQueue`. If the write buffer is
|
|
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.
|
|
11769
|
+
*
|
|
11770
|
+
* @param queueName - Name of the queue to publish to.
|
|
11771
|
+
* @param payloads - Array of string payloads to enqueue.
|
|
11772
|
+
* @returns Counts of published and failed messages; plus per-failure details in `errors`.
|
|
11773
|
+
* @throws Propagates connection or queue-assertion errors to the caller.
|
|
11774
|
+
*/
|
|
11775
|
+
async publish(queueName, payloads) {
|
|
11776
|
+
const connection = await amqplib.connect(this.buildConnectionUrl());
|
|
11777
|
+
let channel;
|
|
11778
|
+
try {
|
|
11779
|
+
channel = await connection.createChannel();
|
|
11780
|
+
await channel.assertQueue(queueName, { durable: true });
|
|
11781
|
+
return await this.publishBatch(channel, queueName, payloads);
|
|
11782
|
+
} finally {
|
|
11783
|
+
try {
|
|
11784
|
+
await channel?.close();
|
|
11785
|
+
} catch {
|
|
11786
|
+
}
|
|
11787
|
+
await connection.close();
|
|
11788
|
+
}
|
|
11789
|
+
}
|
|
11790
|
+
/**
|
|
11791
|
+
* Sends each payload to the queue via `sendToQueue`. Tracks published and failed counts.
|
|
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.
|
|
11796
|
+
*/
|
|
11797
|
+
async publishBatch(channel, queueName, payloads) {
|
|
11798
|
+
const stats = { published: 0, failed: 0, errors: [] };
|
|
11799
|
+
for (const payload of payloads) {
|
|
11800
|
+
try {
|
|
11801
|
+
const sent = channel.sendToQueue(queueName, Buffer.from(payload), { persistent: true });
|
|
11802
|
+
stats.published++;
|
|
11803
|
+
if (!sent) {
|
|
11804
|
+
await new Promise((resolve) => channel.once("drain", resolve));
|
|
11805
|
+
}
|
|
11806
|
+
} catch (error) {
|
|
11807
|
+
stats.failed++;
|
|
11808
|
+
stats.errors.push({ payload, error });
|
|
11809
|
+
}
|
|
11810
|
+
}
|
|
11811
|
+
return stats;
|
|
11812
|
+
}
|
|
11813
|
+
/**
|
|
11814
|
+
* Builds the AMQP connection URL from the stored credentials.
|
|
11815
|
+
* Uses `amqps://` when `secure` is true, `amqp://` otherwise.
|
|
11816
|
+
* Username, password, and vhost are percent-encoded to handle special characters.
|
|
11817
|
+
*/
|
|
11818
|
+
buildConnectionUrl() {
|
|
11819
|
+
const { host, port, username, password, vhost, secure = false } = this.credentials;
|
|
11820
|
+
const protocol = secure ? "amqps" : "amqp";
|
|
11821
|
+
return `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${host}:${port}/${encodeURIComponent(vhost)}`;
|
|
11822
|
+
}
|
|
11823
|
+
/**
|
|
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.
|
|
11829
|
+
*
|
|
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.
|
|
11832
|
+
*/
|
|
11833
|
+
async processBatch(channel, queueName, options, handler) {
|
|
11834
|
+
const stats = { consumed: 0, acked: 0, nacked: 0, errors: [] };
|
|
11835
|
+
const { batchSize, maxParallel } = options;
|
|
11836
|
+
const { messageCount } = await channel.checkQueue(queueName);
|
|
11837
|
+
if (messageCount === 0) return stats;
|
|
11838
|
+
const effectiveBatch = Math.min(batchSize, messageCount);
|
|
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);
|
|
11846
|
+
stats.consumed++;
|
|
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;
|
|
11855
|
+
}
|
|
11856
|
+
/**
|
|
11857
|
+
* Invokes `handler` with the queue name and decoded message content. Acks on success.
|
|
11858
|
+
* On failure, nacks the message and records the content and error in `stats.errors`.
|
|
11859
|
+
* Whether to requeue on nack is controlled by `options.nackRequeue` (default: true).
|
|
11860
|
+
*/
|
|
11861
|
+
async processMessage(channel, queueName, msg, stats, options, handler) {
|
|
11862
|
+
const { nackRequeue = true } = options;
|
|
11863
|
+
const content = msg.content.toString();
|
|
11864
|
+
try {
|
|
11865
|
+
await handler(queueName, content);
|
|
11866
|
+
channel.ack(msg);
|
|
11867
|
+
stats.acked++;
|
|
11868
|
+
} catch (error) {
|
|
11869
|
+
channel.nack(msg, false, nackRequeue);
|
|
11870
|
+
stats.errors.push({ content, error });
|
|
11871
|
+
stats.nacked++;
|
|
11872
|
+
}
|
|
11873
|
+
}
|
|
11874
|
+
};
|
|
11875
|
+
__name(_RabbitMQClient, "RabbitMQClient");
|
|
11876
|
+
var RabbitMQClient = _RabbitMQClient;
|
|
11877
|
+
var rabbit_mq_client_default = RabbitMQClient;
|
|
11878
|
+
|
|
11697
11879
|
// src/commerce/adobe-commerce-client/index.ts
|
|
11698
11880
|
import got from "got";
|
|
11699
11881
|
var _AdobeCommerceClient = class _AdobeCommerceClient {
|
|
@@ -12713,6 +12895,7 @@ export {
|
|
|
12713
12895
|
parameters_default as Parameters,
|
|
12714
12896
|
provider_default as ProviderManager,
|
|
12715
12897
|
publish_event_default as PublishEvent,
|
|
12898
|
+
rabbit_mq_client_default as RabbitMQClient,
|
|
12716
12899
|
registration_default as RegistrationManager,
|
|
12717
12900
|
rest_client_default as RestClient,
|
|
12718
12901
|
runtime_action_default as RuntimeAction,
|