@adobe-commerce/aio-toolkit 1.2.3 → 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 +81 -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/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,87 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.4] - 2026-04-20
|
|
9
|
+
|
|
10
|
+
### ✨ Features
|
|
11
|
+
|
|
12
|
+
- **feat(repository): Add pagination and sort options to `AbdbRepository.find`**
|
|
13
|
+
|
|
14
|
+
`find` now accepts an optional second parameter `options: AbdbFindOptions` for
|
|
15
|
+
server-side pagination and sorting, applied via the MongoDB cursor chain:
|
|
16
|
+
`.sort(...)` → `.skip(...)` → `.limit(...)`.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// Page 2, 20 per page, newest first
|
|
20
|
+
await repo.find(
|
|
21
|
+
{ active: true },
|
|
22
|
+
{ current_page: 2, page_size: 20, sort: { column: '_created_at', direction: 'desc' } }
|
|
23
|
+
);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**`AbdbFindOptions` fields (all optional):**
|
|
27
|
+
| Field | Type | Description |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `sort` | `AbdbFindSort` | `{ column: string; direction?: 'asc' \| 'desc' }` — direction defaults to `'asc'` |
|
|
30
|
+
| `page_size` | `number` | Maximum documents to return; enables `.limit()` |
|
|
31
|
+
| `current_page` | `number` | 1-based page index; combined with `page_size` to compute `.skip()`. Page 1 skips the `.skip()` call. |
|
|
32
|
+
|
|
33
|
+
Calling `find` without options is fully backward compatible — no sort, skip, or limit is applied.
|
|
34
|
+
|
|
35
|
+
**New exported types:** `AbdbFindOptions`, `AbdbFindSort`, `AbdbFindSortDirection`
|
|
36
|
+
|
|
37
|
+
- **feat(integration): Refactor `RabbitMQClient` from push-based to pull-based consumption**
|
|
38
|
+
|
|
39
|
+
`RabbitMQClient.consume` now uses `channel.get` (AMQP `basic.get`) instead of
|
|
40
|
+
`channel.consume` (push subscription). This makes batch termination fully deterministic —
|
|
41
|
+
`channel.get` returns `false` immediately when the queue is empty, so there is no consumer
|
|
42
|
+
tag to cancel, no cancellation race condition, and no activation-timeout hang.
|
|
43
|
+
|
|
44
|
+
**What changed:**
|
|
45
|
+
- `processBatch` rewritten: windowed `Promise.all(maxParallel)` replaces `channel.prefetch` +
|
|
46
|
+
`channel.consume`. Each window pulls up to `maxParallel` messages sequentially via
|
|
47
|
+
`channel.get`, then processes them concurrently before moving to the next window.
|
|
48
|
+
- `publish` backpressure improved: `sendToQueue` returning `false` (write buffer full) now
|
|
49
|
+
counts the message as published and waits for the channel's `drain` event before
|
|
50
|
+
continuing. Previously, a full buffer was counted as a failure.
|
|
51
|
+
- `finally` blocks in `consume` and `publish` now wrap `channel.close()` in a try/catch so
|
|
52
|
+
a close error never prevents the connection from closing.
|
|
53
|
+
|
|
54
|
+
**No API changes** — `consume(queueName, options, handler)` and `publish(queueName, payloads)`
|
|
55
|
+
signatures, `RabbitMQConsumeOptions`, `ConsumeStats`, and `PublishStats` are unchanged.
|
|
56
|
+
|
|
57
|
+
### 🐛 Bug Fixes
|
|
58
|
+
|
|
59
|
+
- **fix(webhook-action): Rename `WebhookActionExceptionResponse.class` → `type`**
|
|
60
|
+
|
|
61
|
+
Adobe Commerce webhooks expect `"type"` in the exception response payload,
|
|
62
|
+
not `"class"`. The previous field name was silently sending the wrong key,
|
|
63
|
+
causing an **Internal Server Error** instead of the intended exception
|
|
64
|
+
(e.g. `GraphQlInputException`).
|
|
65
|
+
|
|
66
|
+
**Before (broken):**
|
|
67
|
+
```typescript
|
|
68
|
+
WebhookActionResponse.exception(
|
|
69
|
+
'Lease term not available for this cart',
|
|
70
|
+
'Magento\\Framework\\GraphQl\\Exception\\GraphQlInputException'
|
|
71
|
+
);
|
|
72
|
+
// sent: { "op": "exception", "class": "...", "message": "..." } ❌
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**After (correct):**
|
|
76
|
+
```typescript
|
|
77
|
+
WebhookActionResponse.exception(
|
|
78
|
+
'Lease term not available for this cart',
|
|
79
|
+
'Magento\\Framework\\GraphQl\\Exception\\GraphQlInputException'
|
|
80
|
+
);
|
|
81
|
+
// sent: { "op": "exception", "type": "...", "message": "..." } ✅
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Migration:** Replace any direct use of the `class` field on
|
|
85
|
+
`WebhookActionExceptionResponse` with `type`.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
8
89
|
## [1.2.3] - 2026-04-01
|
|
9
90
|
|
|
10
91
|
### ✨ Features
|
package/README.md
CHANGED
|
@@ -151,11 +151,21 @@ const testWebhook = WebhookAction.execute(
|
|
|
151
151
|
|
|
152
152
|
**WebhookActionResponse Operations:**
|
|
153
153
|
- `success()`: Indicates successful webhook processing
|
|
154
|
-
- `exception(message?,
|
|
154
|
+
- `exception(message?, exceptionType?)`: Returns error response with an optional Magento exception type (e.g. `'Magento\\Framework\\GraphQl\\Exception\\GraphQlInputException'`)
|
|
155
155
|
- `add(path, value, instance?)`: Adds data to response
|
|
156
156
|
- `replace(path, value, instance?)`: Replaces data in response
|
|
157
157
|
- `remove(path)`: Removes data from response
|
|
158
158
|
|
|
159
|
+
**Exception response example:**
|
|
160
|
+
```typescript
|
|
161
|
+
// Return a typed Magento exception — Commerce will surface it as a proper error
|
|
162
|
+
return WebhookActionResponse.exception(
|
|
163
|
+
'Lease term not available for this cart',
|
|
164
|
+
'Magento\\Framework\\GraphQl\\Exception\\GraphQlInputException'
|
|
165
|
+
);
|
|
166
|
+
// Produces: { "op": "exception", "type": "Magento\\...", "message": "..." }
|
|
167
|
+
```
|
|
168
|
+
|
|
159
169
|
#### `PublishEvent`
|
|
160
170
|
Event publishing component for Adobe I/O Events with CloudEvents support.
|
|
161
171
|
|
|
@@ -868,9 +878,10 @@ exports.main = async (params) => {
|
|
|
868
878
|
// Read one by any field
|
|
869
879
|
const byEmail = await repo.findOne({ email: 'jane@example.com' });
|
|
870
880
|
|
|
871
|
-
// Read all (optional filter)
|
|
881
|
+
// Read all (optional filter + optional pagination/sort)
|
|
872
882
|
const all = await repo.find();
|
|
873
883
|
const active = await repo.find({ active: true });
|
|
884
|
+
const paged = await repo.find({ active: true }, { current_page: 2, page_size: 20, sort: { column: '_created_at', direction: 'desc' } });
|
|
874
885
|
|
|
875
886
|
// Partial update — only provided fields are validated; required fields already in the DB are not re-checked
|
|
876
887
|
await repo.save({ first_name: 'Janet' }, id);
|
|
@@ -903,7 +914,7 @@ These are added once per collection instance, so re-using the same collection ac
|
|
|
903
914
|
| `updateOne(payload, filter?, options?)` | Single-document update via `{ $set: payload }` (partial validation, stamps `_updated_at`) | `Promise<Record<string, any>>` — raw `updateOne` result (e.g. `modifiedCount`) |
|
|
904
915
|
| `findOne(filter)` | First document matching filter, e.g. `{ email: 'a@b.com' }` | `Promise<T \| null>` |
|
|
905
916
|
| `findById(id)` | Shorthand for `findOne({ _id: new ObjectId(id) })` | `Promise<T \| null>` |
|
|
906
|
-
| `find(filter?)` | All documents matching filter (
|
|
917
|
+
| `find(filter?, options?)` | All documents matching filter with optional pagination and sort (`AbdbFindOptions`) | `Promise<T[]>` |
|
|
907
918
|
| `isIdExists(id)` | Returns `true` if a document with the given `_id` exists (no-op for empty id) | `Promise<boolean>` |
|
|
908
919
|
| `exists(filter?, options?)` | Returns `true` if any document matching `filter` exists via `countDocuments` | `Promise<boolean>` |
|
|
909
920
|
| `deleteOne(filter?)` | Delete first matching document via `deleteOne` | `Promise<Record<string, any>>` — raw `deleteOne` result |
|
|
@@ -925,6 +936,36 @@ These are added once per collection instance, so re-using the same collection ac
|
|
|
925
936
|
| `getName()` | Returns the underlying collection name |
|
|
926
937
|
| `getCollection()` | Returns the underlying `AbdbCollection` instance |
|
|
927
938
|
|
|
939
|
+
##### Pagination and sorting
|
|
940
|
+
|
|
941
|
+
`find` accepts an optional second argument for server-side pagination and sorting:
|
|
942
|
+
|
|
943
|
+
```javascript
|
|
944
|
+
// All active users, newest first
|
|
945
|
+
const all = await repo.find(
|
|
946
|
+
{ active: true },
|
|
947
|
+
{ sort: { column: '_created_at', direction: 'desc' } }
|
|
948
|
+
);
|
|
949
|
+
|
|
950
|
+
// Page 2, 20 results per page, sorted ascending by name
|
|
951
|
+
const page2 = await repo.find(
|
|
952
|
+
{},
|
|
953
|
+
{ current_page: 2, page_size: 20, sort: { column: 'name', direction: 'asc' } }
|
|
954
|
+
);
|
|
955
|
+
|
|
956
|
+
// Just limit — no pagination offset
|
|
957
|
+
const top10 = await repo.find({}, { page_size: 10 });
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
`AbdbFindOptions` fields (all optional):
|
|
961
|
+
|
|
962
|
+
| Field | Type | Default | Description |
|
|
963
|
+
|---|---|---|---|
|
|
964
|
+
| `sort.column` | `string` | — | Field to sort by |
|
|
965
|
+
| `sort.direction` | `'asc' \| 'desc'` | `'asc'` | Sort direction |
|
|
966
|
+
| `page_size` | `number` | — | Max documents to return (enables `.limit()`) |
|
|
967
|
+
| `current_page` | `number` | — | 1-based page index; computes `.skip((page-1) * page_size)` |
|
|
968
|
+
|
|
928
969
|
##### Custom region
|
|
929
970
|
|
|
930
971
|
```javascript
|
|
@@ -1509,7 +1550,7 @@ if (directInfo.isValid) {
|
|
|
1509
1550
|
- `info(token)` - Analyzes token string and returns validation/expiry details
|
|
1510
1551
|
|
|
1511
1552
|
#### `RabbitMQClient`
|
|
1512
|
-
|
|
1553
|
+
Pull-based AMQP consumer and publisher for RabbitMQ. Manages the full connection lifecycle per call (connect → channel → close) and exposes a clean, typed interface without exposing raw AMQP primitives to the caller.
|
|
1513
1554
|
|
|
1514
1555
|
**Installation**
|
|
1515
1556
|
```bash
|
|
@@ -1578,7 +1619,7 @@ if (stats.errors.length) {
|
|
|
1578
1619
|
|
|
1579
1620
|
| Method | Description | Returns |
|
|
1580
1621
|
|---|---|---|
|
|
1581
|
-
| `consume(queueName, options, handler)` | Checks queue depth
|
|
1622
|
+
| `consume(queueName, options, handler)` | Checks queue depth and pull-consumes up to `batchSize` messages via `channel.get` in parallel windows of `maxParallel` | `Promise<ConsumeStats>` |
|
|
1582
1623
|
| `publish(queueName, payloads)` | Asserts queue and enqueues each payload as a persistent message | `Promise<PublishStats>` |
|
|
1583
1624
|
|
|
1584
1625
|
**`RabbitMQConsumeOptions`**
|
|
@@ -1586,7 +1627,7 @@ if (stats.errors.length) {
|
|
|
1586
1627
|
| Field | Type | Required | Description |
|
|
1587
1628
|
|---|---|---|---|
|
|
1588
1629
|
| `batchSize` | `number` | ✅ | Maximum number of messages to process in this call |
|
|
1589
|
-
| `maxParallel` | `number` | ✅ | Max
|
|
1630
|
+
| `maxParallel` | `number` | ✅ | Max messages processed concurrently per window (client-side) |
|
|
1590
1631
|
| `nackRequeue` | `boolean` | — | Requeue on nack (default: `true`) |
|
|
1591
1632
|
| `exchange` | `string` | — | If set, asserts a `direct` exchange and binds the queue before consuming |
|
|
1592
1633
|
|
|
@@ -1605,7 +1646,7 @@ if (stats.errors.length) {
|
|
|
1605
1646
|
|---|---|---|
|
|
1606
1647
|
| `published` | `number` | Messages successfully enqueued |
|
|
1607
1648
|
| `failed` | `number` | Messages that could not be enqueued |
|
|
1608
|
-
| `errors` | `Array<{ payload: string; error: unknown }>` | Per-failure details (buffer
|
|
1649
|
+
| `errors` | `Array<{ payload: string; error: unknown }>` | Per-failure details (thrown errors only; write-buffer-full is handled via backpressure) |
|
|
1609
1650
|
|
|
1610
1651
|
---
|
|
1611
1652
|
|