@adobe-commerce/aio-toolkit 1.2.5 → 1.2.6
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 +134 -0
- package/README.md +169 -0
- package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
- package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
- package/dist/index.d.mts +51 -6
- package/dist/index.d.ts +51 -6
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +213 -0
- package/dist/index.mjs.map +1 -1
- package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
- package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
- package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
- package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
- package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
- package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
- package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
- package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
- package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
- package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
- package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
- package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
- package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
- package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
- package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
- package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
- package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
- package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
- package/package.json +4 -2
|
@@ -53,8 +53,7 @@ Ask the user:
|
|
|
53
53
|
7. **Error Handling**
|
|
54
54
|
- Specific error scenarios to handle
|
|
55
55
|
- Example: Invalid signature, missing data, processing errors
|
|
56
|
-
- Note: WebhookActionResponse.exception() accepts optional message and exception
|
|
57
|
-
- Default exception class (if not provided): `\\Magento\\Framework\\Exception\\LocalizedException`
|
|
56
|
+
- Note: WebhookActionResponse.exception() accepts optional message and exception type
|
|
58
57
|
|
|
59
58
|
8. **Business Logic Description**
|
|
60
59
|
- Brief description of what the webhook should do
|
|
@@ -141,7 +140,7 @@ exports.main = WebhookAction.execute(
|
|
|
141
140
|
return WebhookActionResponse.success();
|
|
142
141
|
} catch (error) {
|
|
143
142
|
logger.error({ message: `${name}-error`, error: error.message, stack: error.stack });
|
|
144
|
-
// Optional parameters: message and
|
|
143
|
+
// Optional parameters: message and exceptionType
|
|
145
144
|
return WebhookActionResponse.exception(
|
|
146
145
|
`Failed: ${error.message}`,
|
|
147
146
|
'\\Magento\\Framework\\Exception\\LocalizedException'
|
|
@@ -183,6 +182,8 @@ application:
|
|
|
183
182
|
annotations:
|
|
184
183
|
require-adobe-auth: [true/false]
|
|
185
184
|
final: true
|
|
185
|
+
# Required when signature verification is enabled:
|
|
186
|
+
raw-http: true
|
|
186
187
|
# If API Gateway requested:
|
|
187
188
|
apis:
|
|
188
189
|
[action-name]:
|
|
@@ -219,7 +220,12 @@ If signature verification enabled:
|
|
|
219
220
|
PUBLIC_KEY_BASE64="[your base64 encoded key]"
|
|
220
221
|
```
|
|
221
222
|
|
|
222
|
-
3. **
|
|
223
|
+
3. **Ensure `raw-http: true` is set in `app.config.yaml`:**
|
|
224
|
+
- `raw-http: true` is **required** for signature verification to work
|
|
225
|
+
- Without it, `__ow_body` is never populated and signature verification always fails
|
|
226
|
+
- The annotation must be under `annotations:` in the action configuration
|
|
227
|
+
|
|
228
|
+
4. **Security Notes:**
|
|
223
229
|
- Never commit `.env` to version control
|
|
224
230
|
- Add `.env` to `.gitignore`
|
|
225
231
|
- Regenerate keys regularly
|
|
@@ -307,16 +313,16 @@ Returns:
|
|
|
307
313
|
{ "op": "success" }
|
|
308
314
|
```
|
|
309
315
|
|
|
310
|
-
#### **exception(message?,
|
|
316
|
+
#### **exception(message?, exceptionType?)** - Terminate Process
|
|
311
317
|
|
|
312
318
|
Causes Commerce to terminate the process that triggered the original event. The exception is logged in Commerce's system.log.
|
|
313
319
|
|
|
314
320
|
**Parameters:**
|
|
315
|
-
- `message` (optional): Exception message
|
|
316
|
-
- `
|
|
321
|
+
- `message` (optional): Exception message shown to the end user
|
|
322
|
+
- `exceptionType` (optional): Fully qualified Magento exception class name (e.g., `\\Magento\\Framework\\Exception\\LocalizedException`). Only fields that are provided are included in the response.
|
|
317
323
|
|
|
318
324
|
```javascript
|
|
319
|
-
// With custom message and
|
|
325
|
+
// With custom message and exception type
|
|
320
326
|
return WebhookActionResponse.exception(
|
|
321
327
|
'The product cannot be added to the cart because it is out of stock',
|
|
322
328
|
'Path\\To\\Exception\\Class'
|
|
@@ -330,7 +336,7 @@ Returns:
|
|
|
330
336
|
```json
|
|
331
337
|
{
|
|
332
338
|
"op": "exception",
|
|
333
|
-
"
|
|
339
|
+
"type": "Path\\To\\Exception\\Class",
|
|
334
340
|
"message": "The product cannot be added to the cart because it is out of stock"
|
|
335
341
|
}
|
|
336
342
|
```
|
|
@@ -436,4 +442,11 @@ Returns:
|
|
|
436
442
|
### Related Rules
|
|
437
443
|
|
|
438
444
|
- **Setting up New Relic Telemetry**: Add observability to your webhook action
|
|
445
|
+
- **Using PublishEvent**: Publish CloudEvents to Adobe I/O Events from your webhook action
|
|
446
|
+
- **Using RuntimeApiGatewayService**: Call another web-exposed Runtime action via API Gateway from your webhook
|
|
447
|
+
- **Using FileRepository**: Persist and retrieve records using Adobe I/O Files storage from your webhook action
|
|
448
|
+
- **Using AbdbCollection**: Add MongoDB-backed App Builder Data storage with schema validation to your webhook action
|
|
449
|
+
- **Using AbdbRepository**: Add full CRUD operations (insert, find, update, delete, pagination) on top of an AbdbCollection in your webhook action
|
|
450
|
+
- **Create Shipping Carrier**: If this webhook action handles Adobe Commerce OOPE shipping rates, use the `aio-toolkit-create-shipping-carrier` command instead — it generates both the carrier class (`lib/shipping-carriers/`) and the webhook action together, including optional Commerce OOPE API management methods
|
|
451
|
+
- **Using Amazon SQS — Publish**: Publish messages to an Amazon SQS queue from your webhook action
|
|
439
452
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Creating Adobe Commerce Client Operations using @adobe-commerce/aio-toolkit
|
|
3
3
|
globs: '**/{actions,lib}/**/*.{ts,js},.env'
|
|
4
|
-
alwaysApply:
|
|
4
|
+
alwaysApply: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Creating Adobe Commerce Client Operations
|
|
@@ -27,7 +27,7 @@ This rule applies when the user requests to integrate Adobe Commerce API into th
|
|
|
27
27
|
|
|
28
28
|
**Integration with Other Action Creation Rules**:
|
|
29
29
|
|
|
30
|
-
When using action creation rules (RuntimeAction, WebhookAction, GraphQLAction, EventConsumerAction) and the developer mentions Commerce operations in the business logic:
|
|
30
|
+
When using action creation rules (RuntimeAction, WebhookAction, GraphQLAction, EventConsumerAction, OpenwhiskAction) and the developer mentions Commerce operations in the business logic:
|
|
31
31
|
|
|
32
32
|
- **Automatically trigger this rule** after the action is created
|
|
33
33
|
- Examples of Commerce operations: "create product", "get customer", "update order", "call Commerce API", "fetch products from Commerce"
|
|
@@ -235,7 +235,8 @@ After receiving answers to ALL questions, present a comprehensive summary and **
|
|
|
235
235
|
|
|
236
236
|
```bash
|
|
237
237
|
# Adobe Commerce REST API Configuration (OAuth 1.0a)
|
|
238
|
-
COMMERCE_BASE_URL
|
|
238
|
+
# COMMERCE_BASE_URL is the store root — do NOT include /rest or /V1
|
|
239
|
+
COMMERCE_BASE_URL=https://your-commerce-store.com
|
|
239
240
|
COMMERCE_CONSUMER_KEY=
|
|
240
241
|
COMMERCE_CONSUMER_SECRET=
|
|
241
242
|
COMMERCE_ACCESS_TOKEN=
|
|
@@ -248,12 +249,13 @@ COMMERCE_ACCESS_TOKEN_SECRET=
|
|
|
248
249
|
|
|
249
250
|
```bash
|
|
250
251
|
# Adobe Commerce REST API Configuration (IMS)
|
|
251
|
-
COMMERCE_BASE_URL
|
|
252
|
+
# COMMERCE_BASE_URL is the store root — do NOT include /rest or /V1
|
|
253
|
+
COMMERCE_BASE_URL=https://your-commerce-cloud.adobe.com
|
|
252
254
|
IMS_CLIENT_ID=
|
|
253
255
|
IMS_CLIENT_SECRET=
|
|
254
256
|
IMS_TECHNICAL_ACCOUNT_ID=
|
|
255
257
|
IMS_TECHNICAL_ACCOUNT_EMAIL=
|
|
256
|
-
|
|
258
|
+
IMS_ORG_ID=
|
|
257
259
|
IMS_SCOPES=openid,AdobeID,read_organizations
|
|
258
260
|
```
|
|
259
261
|
|
|
@@ -263,7 +265,8 @@ IMS_SCOPES=openid,AdobeID,read_organizations
|
|
|
263
265
|
|
|
264
266
|
```bash
|
|
265
267
|
# Adobe Commerce REST API Configuration (Basic Auth)
|
|
266
|
-
COMMERCE_BASE_URL
|
|
268
|
+
# COMMERCE_BASE_URL is the store root — do NOT include /rest or /V1
|
|
269
|
+
COMMERCE_BASE_URL=https://your-commerce-store.com
|
|
267
270
|
COMMERCE_USERNAME=
|
|
268
271
|
COMMERCE_PASSWORD=
|
|
269
272
|
```
|
|
@@ -409,7 +412,7 @@ class AdobeCommerceClientBuilder {
|
|
|
409
412
|
/**
|
|
410
413
|
* Initialize the client builder with OAuth 1.0a credentials
|
|
411
414
|
*
|
|
412
|
-
* @param {string} commerceBaseUrl - Commerce
|
|
415
|
+
* @param {string} commerceBaseUrl - Commerce store root URL (e.g., https://your-store.com) — do NOT include /rest or /V1
|
|
413
416
|
* @param {string} commerceConsumerKey - OAuth consumer key from Commerce Admin
|
|
414
417
|
* @param {string} commerceConsumerSecret - OAuth consumer secret from Commerce Admin
|
|
415
418
|
* @param {string} commerceAccessToken - OAuth access token from Commerce Admin
|
|
@@ -452,8 +455,8 @@ class AdobeCommerceClientBuilder {
|
|
|
452
455
|
this.commerceAccessTokenSecret
|
|
453
456
|
);
|
|
454
457
|
|
|
455
|
-
//
|
|
456
|
-
this.client = new AdobeCommerceClient(this.commerceBaseUrl, connection);
|
|
458
|
+
// Pass logger to the client so HTTP-level debug logs flow into telemetry automatically
|
|
459
|
+
this.client = new AdobeCommerceClient(this.commerceBaseUrl, connection, this.params.logger || null);
|
|
457
460
|
return this.client;
|
|
458
461
|
}
|
|
459
462
|
}
|
|
@@ -504,7 +507,7 @@ class AdobeCommerceClientBuilder {
|
|
|
504
507
|
/**
|
|
505
508
|
* Initialize the client builder with IMS credentials
|
|
506
509
|
*
|
|
507
|
-
* @param {string} commerceBaseUrl - Commerce
|
|
510
|
+
* @param {string} commerceBaseUrl - Commerce store root URL (e.g., https://your-store.com) — do NOT include /rest or /V1
|
|
508
511
|
* @param {string} imsClientId - IMS client ID from Adobe Developer Console
|
|
509
512
|
* @param {string} imsClientSecret - IMS client secret from Adobe Developer Console
|
|
510
513
|
* @param {string} imsTechnicalAccountId - IMS technical account ID
|
|
@@ -609,7 +612,7 @@ class AdobeCommerceClientBuilder {
|
|
|
609
612
|
/**
|
|
610
613
|
* Initialize the client builder with Basic Auth credentials
|
|
611
614
|
*
|
|
612
|
-
* @param {string} commerceBaseUrl - Commerce
|
|
615
|
+
* @param {string} commerceBaseUrl - Commerce store root URL (e.g., https://your-store.com)
|
|
613
616
|
* @param {string} commerceUsername - Commerce admin username
|
|
614
617
|
* @param {string} commercePassword - Commerce admin password
|
|
615
618
|
*/
|
|
@@ -636,8 +639,8 @@ class AdobeCommerceClientBuilder {
|
|
|
636
639
|
return this.client;
|
|
637
640
|
}
|
|
638
641
|
|
|
639
|
-
//
|
|
640
|
-
const connection = new BasicAuthConnection(this.commerceUsername, this.commercePassword);
|
|
642
|
+
// BasicAuthConnection requires baseUrl as its first argument so it can fetch the admin token
|
|
643
|
+
const connection = new BasicAuthConnection(this.commerceBaseUrl, this.commerceUsername, this.commercePassword);
|
|
641
644
|
|
|
642
645
|
// Create and cache the Commerce client
|
|
643
646
|
this.client = new AdobeCommerceClient(this.commerceBaseUrl, connection);
|
|
@@ -655,6 +658,86 @@ module.exports = AdobeCommerceClientBuilder;
|
|
|
655
658
|
- Add return type `: AdobeCommerceClient` to `getClient()`
|
|
656
659
|
- Use `export default` instead of `module.exports`
|
|
657
660
|
|
|
661
|
+
#### Step 4.2b: Create Entity Class (Recommended for Domain-Specific APIs)
|
|
662
|
+
|
|
663
|
+
For each Commerce domain area (e.g. `Countries`, `Products`, `Orders`), create a dedicated entity class in `lib/adobe-commerce/[entity-name]/`. This keeps the action thin, encapsulates the API calls and lazy init, and makes the class reusable across multiple actions.
|
|
664
|
+
|
|
665
|
+
```
|
|
666
|
+
lib/
|
|
667
|
+
└── adobe-commerce/
|
|
668
|
+
├── client-builder/
|
|
669
|
+
│ └── index.[js/ts] ← wraps AdobeCommerceClient construction
|
|
670
|
+
└── [entity-name]/
|
|
671
|
+
└── index.[js/ts] ← entity class (API calls + lazy client init)
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
**JavaScript entity class template:**
|
|
675
|
+
|
|
676
|
+
```javascript
|
|
677
|
+
// lib/adobe-commerce/[entity-name]/index.js
|
|
678
|
+
const { AdobeCommerceClientBuilder } = require('@lib/adobe-commerce/client-builder');
|
|
679
|
+
|
|
680
|
+
class [EntityName] {
|
|
681
|
+
constructor(params) {
|
|
682
|
+
this.params = params;
|
|
683
|
+
this.client = null;
|
|
684
|
+
this.clientInitPromise = null;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Lazy init with concurrent-call guard — both callers share the same promise
|
|
688
|
+
async getClient() {
|
|
689
|
+
if (this.client) return this.client;
|
|
690
|
+
if (this.clientInitPromise) return this.clientInitPromise;
|
|
691
|
+
|
|
692
|
+
this.clientInitPromise = AdobeCommerceClientBuilder.generate({
|
|
693
|
+
commerceBaseUrl: this.params.COMMERCE_BASE_URL,
|
|
694
|
+
oauthConsumerKey: this.params.COMMERCE_CONSUMER_KEY,
|
|
695
|
+
oauthConsumerSecret: this.params.COMMERCE_CONSUMER_SECRET,
|
|
696
|
+
oauthAccessToken: this.params.COMMERCE_ACCESS_TOKEN,
|
|
697
|
+
oauthAccessTokenSecret: this.params.COMMERCE_ACCESS_TOKEN_SECRET,
|
|
698
|
+
logger: this.params.logger || null,
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
this.client = await this.clientInitPromise;
|
|
702
|
+
this.clientInitPromise = null;
|
|
703
|
+
return this.client;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
async fetch[EntityName]() {
|
|
707
|
+
const client = await this.getClient();
|
|
708
|
+
const result = await client.get('rest/V1/[endpoint]');
|
|
709
|
+
|
|
710
|
+
if (!result.success) {
|
|
711
|
+
return result;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Transform result.message as needed
|
|
715
|
+
return { success: true, data: result.message };
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
module.exports = { [EntityName] };
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**In the action — keeps the action thin:**
|
|
723
|
+
|
|
724
|
+
```javascript
|
|
725
|
+
const { [EntityName] } = require('@lib/adobe-commerce/[entity-name]');
|
|
726
|
+
|
|
727
|
+
// Inside handler:
|
|
728
|
+
const entityClient = new [EntityName](params);
|
|
729
|
+
const result = await entityClient.fetch[EntityName]();
|
|
730
|
+
|
|
731
|
+
if (!result.success) {
|
|
732
|
+
return RuntimeActionResponse.error(result.statusCode, result.message);
|
|
733
|
+
}
|
|
734
|
+
return RuntimeActionResponse.success(result.data);
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
> The entity class pattern is optional but strongly recommended when an action calls multiple endpoints on the same domain, or when the same domain is used across multiple actions.
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
658
741
|
#### Step 4.3: Integrate Commerce Client into Existing Action
|
|
659
742
|
|
|
660
743
|
**Update the selected action to use the client builder:**
|
|
@@ -707,7 +790,7 @@ const clientBuilder = new AdobeCommerceClientBuilder(
|
|
|
707
790
|
params.IMS_CLIENT_SECRET,
|
|
708
791
|
params.IMS_TECHNICAL_ACCOUNT_ID,
|
|
709
792
|
params.IMS_TECHNICAL_ACCOUNT_EMAIL,
|
|
710
|
-
params.
|
|
793
|
+
params.IMS_ORG_ID,
|
|
711
794
|
params.IMS_SCOPES // Comma-separated scopes
|
|
712
795
|
);
|
|
713
796
|
|
|
@@ -849,7 +932,7 @@ const token = await AdobeAuth.getToken(
|
|
|
849
932
|
params.IMS_CLIENT_SECRET,
|
|
850
933
|
params.IMS_TECHNICAL_ACCOUNT_ID,
|
|
851
934
|
params.IMS_TECHNICAL_ACCOUNT_EMAIL,
|
|
852
|
-
params.
|
|
935
|
+
params.IMS_ORG_ID,
|
|
853
936
|
params.IMS_SCOPES.split(',')
|
|
854
937
|
);
|
|
855
938
|
|
|
@@ -901,8 +984,8 @@ await client.delete('customers/123');
|
|
|
901
984
|
```javascript
|
|
902
985
|
const { AdobeCommerceClient, BasicAuthConnection } = require('@adobe-commerce/aio-toolkit');
|
|
903
986
|
|
|
904
|
-
//
|
|
905
|
-
const connection = new BasicAuthConnection(params.COMMERCE_USERNAME, params.COMMERCE_PASSWORD);
|
|
987
|
+
// BasicAuthConnection requires baseUrl as first argument — it uses it to fetch the admin token
|
|
988
|
+
const connection = new BasicAuthConnection(params.COMMERCE_BASE_URL, params.COMMERCE_USERNAME, params.COMMERCE_PASSWORD);
|
|
906
989
|
|
|
907
990
|
// Create Commerce client
|
|
908
991
|
const client = new AdobeCommerceClient(params.COMMERCE_BASE_URL, connection);
|
|
@@ -962,7 +1045,8 @@ const updatedOrder = await client.put(
|
|
|
962
1045
|
|
|
963
1046
|
```bash
|
|
964
1047
|
# Adobe Commerce REST API Configuration (OAuth 1.0a)
|
|
965
|
-
|
|
1048
|
+
# Store root URL — do NOT include /rest or /V1 here
|
|
1049
|
+
COMMERCE_BASE_URL=https://your-commerce-store.com
|
|
966
1050
|
COMMERCE_CONSUMER_KEY=
|
|
967
1051
|
COMMERCE_CONSUMER_SECRET=
|
|
968
1052
|
COMMERCE_ACCESS_TOKEN=
|
|
@@ -983,12 +1067,13 @@ COMMERCE_ACCESS_TOKEN_SECRET=
|
|
|
983
1067
|
|
|
984
1068
|
```bash
|
|
985
1069
|
# Adobe Commerce REST API Configuration (IMS)
|
|
986
|
-
|
|
1070
|
+
# Store root URL — do NOT include /rest or /V1 here
|
|
1071
|
+
COMMERCE_BASE_URL=https://your-commerce-cloud.adobe.com
|
|
987
1072
|
IMS_CLIENT_ID=
|
|
988
1073
|
IMS_CLIENT_SECRET=
|
|
989
1074
|
IMS_TECHNICAL_ACCOUNT_ID=
|
|
990
1075
|
IMS_TECHNICAL_ACCOUNT_EMAIL=
|
|
991
|
-
|
|
1076
|
+
IMS_ORG_ID=
|
|
992
1077
|
IMS_SCOPES=openid,AdobeID,read_organizations
|
|
993
1078
|
```
|
|
994
1079
|
|
|
@@ -1007,7 +1092,8 @@ IMS_SCOPES=openid,AdobeID,read_organizations
|
|
|
1007
1092
|
|
|
1008
1093
|
```bash
|
|
1009
1094
|
# Adobe Commerce REST API Configuration (Basic Auth)
|
|
1010
|
-
|
|
1095
|
+
# Store root URL — do NOT include /rest or /V1 here
|
|
1096
|
+
COMMERCE_BASE_URL=https://your-commerce-store.com
|
|
1011
1097
|
COMMERCE_USERNAME=
|
|
1012
1098
|
COMMERCE_PASSWORD=
|
|
1013
1099
|
```
|
|
@@ -1039,7 +1125,7 @@ inputs:
|
|
|
1039
1125
|
LOG_LEVEL: debug
|
|
1040
1126
|
COMMERCE_BASE_URL: $COMMERCE_BASE_URL
|
|
1041
1127
|
# For OAuth: Add COMMERCE_CONSUMER_KEY, COMMERCE_CONSUMER_SECRET, COMMERCE_ACCESS_TOKEN, COMMERCE_ACCESS_TOKEN_SECRET
|
|
1042
|
-
# For IMS: Add IMS_CLIENT_ID, IMS_CLIENT_SECRET, IMS_TECHNICAL_ACCOUNT_ID, IMS_TECHNICAL_ACCOUNT_EMAIL,
|
|
1128
|
+
# For IMS: Add IMS_CLIENT_ID, IMS_CLIENT_SECRET, IMS_TECHNICAL_ACCOUNT_ID, IMS_TECHNICAL_ACCOUNT_EMAIL, IMS_ORG_ID, IMS_SCOPES
|
|
1043
1129
|
# For Basic Auth: Add COMMERCE_USERNAME, COMMERCE_PASSWORD
|
|
1044
1130
|
```
|
|
1045
1131
|
|
|
@@ -1060,89 +1146,94 @@ inputs:
|
|
|
1060
1146
|
|
|
1061
1147
|
### AdobeCommerceClient Class
|
|
1062
1148
|
|
|
1063
|
-
Main class for interacting with Adobe Commerce REST API
|
|
1149
|
+
Main class for interacting with Adobe Commerce REST API. **Never throws** — all outcomes are returned as `{ success, ... }` objects.
|
|
1150
|
+
|
|
1151
|
+
- **Constructor**: `new AdobeCommerceClient(baseUrl, connection, logger?, httpsOptions?)`
|
|
1152
|
+
- `baseUrl`: Commerce store root URL (e.g. `https://your-store.com`) — **do not include `/rest`**; it is passed as Got's `prefixUrl`
|
|
1153
|
+
- `connection`: Connection instance (`Oauth1aConnection`, `ImsConnection`, or `BasicAuthConnection`)
|
|
1154
|
+
- `logger`: Optional logger instance — pass `ctx.logger` to get automatic HTTP-level debug logs in telemetry
|
|
1155
|
+
- `httpsOptions`: Optional Got `https` options — use `{ rejectUnauthorized: false }` for self-signed certs (never in production)
|
|
1156
|
+
|
|
1157
|
+
**URL construction rule**: `baseUrl` + endpoint are concatenated by Got. Do **not** include a leading slash in the endpoint. Query parameters go directly in the endpoint string:
|
|
1158
|
+
|
|
1159
|
+
```javascript
|
|
1160
|
+
// Correct
|
|
1161
|
+
await client.get('rest/V1/products');
|
|
1162
|
+
await client.get('rest/V1/orders?searchCriteria[pageSize]=10&searchCriteria[currentPage]=1');
|
|
1163
|
+
|
|
1164
|
+
// Wrong — leading slash breaks Got's prefixUrl resolution
|
|
1165
|
+
await client.get('/rest/V1/products');
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
**Response shape** — every method resolves with one of:
|
|
1169
|
+
|
|
1170
|
+
```javascript
|
|
1171
|
+
// Success
|
|
1172
|
+
{ success: true, message: any } // message = parsed JSON response body
|
|
1064
1173
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1174
|
+
// Failure
|
|
1175
|
+
{ success: false, statusCode: number, message: string, body?: any }
|
|
1176
|
+
// statusCode 500 for network/DNS failures; HTTP status for 4xx/5xx
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
Always check `result.success` — never wrap calls in try/catch for HTTP errors.
|
|
1069
1180
|
|
|
1070
1181
|
**Available Methods:**
|
|
1071
1182
|
|
|
1072
|
-
#### get(endpoint,
|
|
1183
|
+
#### get(endpoint, headers?)
|
|
1073
1184
|
|
|
1074
|
-
|
|
1185
|
+
```javascript
|
|
1186
|
+
async get(endpoint, headers = {})
|
|
1187
|
+
```
|
|
1075
1188
|
|
|
1076
|
-
-
|
|
1077
|
-
|
|
1078
|
-
- `queryParams` (object, optional): Query parameters for the request
|
|
1079
|
-
- **Returns**: Promise with response data
|
|
1080
|
-
- **Example**:
|
|
1081
|
-
```javascript
|
|
1082
|
-
const products = await client.get('products');
|
|
1083
|
-
const product = await client.get('products/SKU123');
|
|
1084
|
-
const searchResults = await client.get('products', { searchCriteria: { pageSize: 10 } });
|
|
1085
|
-
```
|
|
1189
|
+
- `endpoint`: REST path (e.g. `'rest/V1/products/24'`). Append query string directly here.
|
|
1190
|
+
- `headers`: Additional request headers merged on top of client defaults.
|
|
1086
1191
|
|
|
1087
|
-
|
|
1192
|
+
```javascript
|
|
1193
|
+
const result = await client.get('rest/V1/directory/countries');
|
|
1194
|
+
if (result.success) { /* result.message = parsed JSON array */ }
|
|
1088
1195
|
|
|
1089
|
-
|
|
1196
|
+
// Query parameters in the endpoint string
|
|
1197
|
+
const result = await client.get('rest/V1/products?searchCriteria[pageSize]=10');
|
|
1198
|
+
```
|
|
1090
1199
|
|
|
1091
|
-
|
|
1092
|
-
- `endpoint` (string): API endpoint path
|
|
1093
|
-
- `queryParams` (object, optional): Query parameters
|
|
1094
|
-
- `body` (object, optional): Request body
|
|
1095
|
-
- **Returns**: Promise with response data
|
|
1096
|
-
- **Example**:
|
|
1097
|
-
```javascript
|
|
1098
|
-
const newProduct = await client.post(
|
|
1099
|
-
'products',
|
|
1100
|
-
{},
|
|
1101
|
-
{
|
|
1102
|
-
product: {
|
|
1103
|
-
sku: 'NEW-SKU',
|
|
1104
|
-
name: 'New Product',
|
|
1105
|
-
price: 99.99,
|
|
1106
|
-
},
|
|
1107
|
-
}
|
|
1108
|
-
);
|
|
1109
|
-
```
|
|
1200
|
+
#### post(endpoint, headers?, payload?)
|
|
1110
1201
|
|
|
1111
|
-
|
|
1202
|
+
```javascript
|
|
1203
|
+
async post(endpoint, headers = {}, payload = null)
|
|
1204
|
+
```
|
|
1112
1205
|
|
|
1113
|
-
|
|
1206
|
+
- `payload`: Serialised as JSON. `Content-Type: application/json` set automatically.
|
|
1114
1207
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
```javascript
|
|
1122
|
-
const updated = await client.put(
|
|
1123
|
-
'products/SKU123',
|
|
1124
|
-
{},
|
|
1125
|
-
{
|
|
1126
|
-
product: {
|
|
1127
|
-
name: 'Updated Name',
|
|
1128
|
-
price: 89.99,
|
|
1129
|
-
},
|
|
1130
|
-
}
|
|
1131
|
-
);
|
|
1132
|
-
```
|
|
1208
|
+
```javascript
|
|
1209
|
+
const result = await client.post('rest/V1/products', {}, {
|
|
1210
|
+
product: { sku: 'MY-SKU', name: 'My Product', price: 29.99, status: 1, type_id: 'simple', attribute_set_id: 4 },
|
|
1211
|
+
});
|
|
1212
|
+
if (!result.success) { /* result.statusCode, result.message, result.body */ }
|
|
1213
|
+
```
|
|
1133
1214
|
|
|
1134
|
-
####
|
|
1215
|
+
#### put(endpoint, headers?, payload?)
|
|
1135
1216
|
|
|
1136
|
-
|
|
1217
|
+
```javascript
|
|
1218
|
+
async put(endpoint, headers = {}, payload = null)
|
|
1219
|
+
```
|
|
1137
1220
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1221
|
+
```javascript
|
|
1222
|
+
const result = await client.put('rest/V1/products/MY-SKU', {}, {
|
|
1223
|
+
product: { price: 39.99 },
|
|
1224
|
+
});
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
#### delete(endpoint, headers?)
|
|
1228
|
+
|
|
1229
|
+
```javascript
|
|
1230
|
+
async delete(endpoint, headers = {})
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
```javascript
|
|
1234
|
+
const result = await client.delete('rest/V1/products/MY-SKU');
|
|
1235
|
+
if (result.success) { /* result.message = true for Commerce DELETE responses */ }
|
|
1236
|
+
```
|
|
1146
1237
|
|
|
1147
1238
|
### Oauth1aConnection Class
|
|
1148
1239
|
|
|
@@ -1163,28 +1254,66 @@ OAuth 1.0a authentication for Commerce
|
|
|
1163
1254
|
|
|
1164
1255
|
IMS (Identity Management Services) authentication
|
|
1165
1256
|
|
|
1166
|
-
- **Purpose**:
|
|
1167
|
-
- **Use Case**: Adobe Commerce Cloud
|
|
1168
|
-
- **Constructor**: `new ImsConnection(
|
|
1169
|
-
- **
|
|
1170
|
-
- `
|
|
1171
|
-
- **
|
|
1172
|
-
- **
|
|
1173
|
-
|
|
1257
|
+
- **Purpose**: Sets `Authorization: Bearer <token>` as a static header on the client; same token applied to every request
|
|
1258
|
+
- **Use Case**: Adobe Commerce Cloud with Adobe Identity (IMS) enabled
|
|
1259
|
+
- **Constructor**: `new ImsConnection(imsToken, logger?)`
|
|
1260
|
+
- `imsToken`: Pre-generated IMS bearer token — **throws** if blank/whitespace
|
|
1261
|
+
- `logger`: Optional logger instance
|
|
1262
|
+
- **Security**: Secure for production use
|
|
1263
|
+
- **Token refresh**: Entirely the caller's responsibility — `ImsConnection` does not refresh tokens
|
|
1264
|
+
|
|
1265
|
+
**Two ways to obtain the token:**
|
|
1266
|
+
|
|
1267
|
+
**Option A — `Core.AuthClient.generateAccessToken(params)` (recommended for App Builder actions)**
|
|
1268
|
+
|
|
1269
|
+
Uses the action's own injected IMS credentials. Requires `include-ims-credentials: true` in `app.config.yaml`:
|
|
1270
|
+
|
|
1271
|
+
```javascript
|
|
1272
|
+
const { Core } = require('@adobe/aio-sdk');
|
|
1273
|
+
|
|
1274
|
+
const tokenResponse = await Core.AuthClient.generateAccessToken(params);
|
|
1275
|
+
const imsToken = tokenResponse && tokenResponse.access_token;
|
|
1276
|
+
const connection = new ImsConnection(imsToken, logger);
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
YAML annotation required:
|
|
1280
|
+
```yaml
|
|
1281
|
+
annotations:
|
|
1282
|
+
include-ims-credentials: true # injects IMS credential params automatically
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
**Option B — `AdobeAuth.getToken()` (Service Account / OAuth S2S)**
|
|
1286
|
+
|
|
1287
|
+
Fetches a token using explicit S2S credentials from environment variables:
|
|
1288
|
+
|
|
1289
|
+
```javascript
|
|
1290
|
+
const { AdobeAuth } = require('@adobe-commerce/aio-toolkit');
|
|
1291
|
+
|
|
1292
|
+
const imsToken = await AdobeAuth.getToken(
|
|
1293
|
+
params.IMS_CLIENT_ID,
|
|
1294
|
+
params.IMS_CLIENT_SECRET,
|
|
1295
|
+
params.IMS_TECHNICAL_ACCOUNT_ID,
|
|
1296
|
+
params.IMS_TECHNICAL_ACCOUNT_EMAIL,
|
|
1297
|
+
params.IMS_ORG_ID,
|
|
1298
|
+
params.IMS_SCOPES.split(',')
|
|
1299
|
+
);
|
|
1300
|
+
const connection = new ImsConnection(imsToken, logger);
|
|
1301
|
+
```
|
|
1174
1302
|
|
|
1175
1303
|
### BasicAuthConnection Class
|
|
1176
1304
|
|
|
1177
1305
|
HTTP Basic Authentication for Commerce
|
|
1178
1306
|
|
|
1179
|
-
- **Purpose**:
|
|
1180
|
-
- **Use Case**: Development/testing environments (NOT recommended for production)
|
|
1181
|
-
- **Constructor**: `new BasicAuthConnection(username, password)`
|
|
1182
|
-
- **
|
|
1183
|
-
- `username`: Commerce admin username
|
|
1184
|
-
- `password`: Commerce admin password
|
|
1185
|
-
-
|
|
1186
|
-
- **
|
|
1187
|
-
- **
|
|
1307
|
+
- **Purpose**: Exchanges username/password for a bearer token via `POST /rest/V1/integration/admin/token`, then caches the token in Adobe I/O State (1-hour TTL) so subsequent invocations reuse it without another round-trip
|
|
1308
|
+
- **Use Case**: Development/testing environments or PaaS instances without an Integration or IMS configured (NOT recommended for production)
|
|
1309
|
+
- **Constructor**: `new BasicAuthConnection(baseUrl, username, password, logger?)`
|
|
1310
|
+
- `baseUrl`: Commerce store root URL — **same value as `AdobeCommerceClient` baseUrl**
|
|
1311
|
+
- `username`: Commerce admin username
|
|
1312
|
+
- `password`: Commerce admin password
|
|
1313
|
+
- `logger`: Optional logger instance
|
|
1314
|
+
- **How to Get**: Use Commerce admin credentials or create a dedicated API user
|
|
1315
|
+
- **Security**: ⚠️ **NOT secure for production** — use OAuth 1.0a or IMS instead
|
|
1316
|
+
- **Token caching**: Tokens cached in Adobe I/O State with 1-hour TTL; if State is unavailable (e.g. local dev), a fresh token is fetched every invocation silently
|
|
1188
1317
|
|
|
1189
1318
|
### AdobeAuth Class
|
|
1190
1319
|
|
|
@@ -1212,7 +1341,7 @@ Fetch IMS access token using service account credentials
|
|
|
1212
1341
|
params.IMS_CLIENT_SECRET,
|
|
1213
1342
|
params.IMS_TECHNICAL_ACCOUNT_ID,
|
|
1214
1343
|
params.IMS_TECHNICAL_ACCOUNT_EMAIL,
|
|
1215
|
-
params.
|
|
1344
|
+
params.IMS_ORG_ID,
|
|
1216
1345
|
params.IMS_SCOPES.split(',')
|
|
1217
1346
|
);
|
|
1218
1347
|
```
|
|
@@ -1230,7 +1359,8 @@ Fetch IMS access token using service account credentials
|
|
|
1230
1359
|
|
|
1231
1360
|
4. **Client Builder Reusability**: If in root `lib/`, usable by both root and extension actions. Only create once, reuse everywhere.
|
|
1232
1361
|
|
|
1233
|
-
5. **API Usage**: Use REST V1 endpoints (
|
|
1362
|
+
5. **API Usage**: Use REST V1 endpoints (e.g. `rest/V1/products`) — include the full REST path in the endpoint argument, not in `COMMERCE_BASE_URL`. The client **never throws** on HTTP errors — always check `result.success` instead of wrapping calls in try/catch. `result.message` is the parsed JSON body on success; `result.statusCode`, `result.message`, and `result.body` describe the failure.
|
|
1363
|
+
5a. **URL construction**: `COMMERCE_BASE_URL` is the store root (e.g. `https://your-store.com`). Do NOT include `/rest` or `/V1` in the base URL. Do NOT use a leading slash in endpoint strings. Query params go directly in the endpoint string: `rest/V1/orders?searchCriteria[pageSize]=10`.
|
|
1234
1364
|
|
|
1235
1365
|
6. **No New Actions Created**: This rule only integrates Commerce API into existing actions. Use "Create Runtime Action" rule first if needed.
|
|
1236
1366
|
|
|
@@ -1247,15 +1377,16 @@ Fetch IMS access token using service account credentials
|
|
|
1247
1377
|
- **Detection Priority**: If `typescript` + `tsconfig.json` exist OR 2+ indicators found OR `.ts` files exist → TypeScript project
|
|
1248
1378
|
- No need to ask developer. TypeScript provides type safety with interfaces (Product, Customer, Order) and generics: `client.get<Product[]>('products')`
|
|
1249
1379
|
|
|
1250
|
-
10. **Performance**: Centralized Client Builder caches instance (singleton), better for high-frequency/multiple actions. IMS tokens fetched fresh per `getClient()` call.
|
|
1380
|
+
10. **Performance**: Centralized Client Builder caches instance (singleton), better for high-frequency/multiple actions. IMS tokens fetched fresh per `getClient()` call. Entity classes add a second lazy-init layer — `clientInitPromise` guard prevents double-init when `getClient()` is called concurrently.
|
|
1381
|
+
10a. **Logger threading**: Always pass `ctx.logger` to connections and the client — e.g. `new Oauth1aConnection(..., logger)` and `new AdobeCommerceClient(baseUrl, connection, logger)`. This routes automatic HTTP-level debug logs (request, retry, response) into the action's telemetry pipeline.
|
|
1251
1382
|
|
|
1252
1383
|
11. **Action Configuration**: Add Commerce env vars as action inputs using `$VARIABLE_NAME` syntax in `app.config.yaml` or `ext.config.yaml`
|
|
1253
1384
|
|
|
1254
|
-
12. **Compatibility**: Works with RuntimeAction, WebhookAction, EventConsumerAction, GraphQL resolvers, OpenwhiskAction. Supports root and extension points.
|
|
1385
|
+
12. **Compatibility**: Works with RuntimeAction, WebhookAction, EventConsumerAction, GraphQL resolvers, OpenwhiskAction (sub-actions and orchestrators). Supports root and extension points.
|
|
1255
1386
|
|
|
1256
1387
|
13. **Telemetry**: Recommend enabling New Relic for Commerce API observability (traces, metrics, logs). Refer to New Relic telemetry setup rule.
|
|
1257
1388
|
|
|
1258
|
-
14. **Integration with Action Creation Rules**: This rule is designed to work seamlessly with RuntimeAction, WebhookAction, GraphQLAction, and
|
|
1389
|
+
14. **Integration with Action Creation Rules**: This rule is designed to work seamlessly with RuntimeAction, WebhookAction, GraphQLAction, EventConsumerAction, and OpenwhiskAction rules. When developers mention Commerce operations during action creation, automatically suggest or trigger this rule for Commerce API integration.
|
|
1259
1390
|
|
|
1260
1391
|
15. **Edge Case - Ambiguous Language Detection**: If language detection is uncertain (e.g., TypeScript configured but no existing TypeScript files):
|
|
1261
1392
|
|
|
@@ -1306,10 +1437,11 @@ AI: [Integrates Commerce API calls into the action]
|
|
|
1306
1437
|
|
|
1307
1438
|
Add this note to the "Business Logic" question in:
|
|
1308
1439
|
|
|
1309
|
-
- `create-runtime-action.
|
|
1310
|
-
- `create-webhook-action.
|
|
1311
|
-
- `aio-toolkit-create-graphql-action.
|
|
1312
|
-
- `aio-toolkit-create-event-consumer-action.
|
|
1440
|
+
- `aio-toolkit-create-runtime-action.md`
|
|
1441
|
+
- `aio-toolkit-create-webhook-action.md`
|
|
1442
|
+
- `aio-toolkit-create-graphql-action.md`
|
|
1443
|
+
- `aio-toolkit-create-event-consumer-action.md`
|
|
1444
|
+
- `aio-toolkit-create-openwhisk-action.md`
|
|
1313
1445
|
|
|
1314
1446
|
**Note to add:**
|
|
1315
1447
|
|
|
@@ -1319,3 +1451,7 @@ Add this note to the "Business Logic" question in:
|
|
|
1319
1451
|
- Then use "Creating Adobe Commerce Client Operations" rule to integrate Commerce API
|
|
1320
1452
|
- That rule handles connection setup, client builder, and API calls
|
|
1321
1453
|
```
|
|
1454
|
+
|
|
1455
|
+
## Related Rules
|
|
1456
|
+
|
|
1457
|
+
- **"Using AdobeAuth"** (`aio-toolkit-use-adobe-auth.mdc`) — primary reference for `AdobeAuth.getToken()` usage, caching patterns, scope selection, and error handling when using `ImsConnection` with explicit S2S credentials
|