@adobe-commerce/aio-toolkit 1.2.5 → 1.2.7

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +250 -0
  2. package/README.md +450 -1
  3. package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
  4. package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
  5. package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
  6. package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
  7. package/dist/index.d.mts +61 -6
  8. package/dist/index.d.ts +61 -6
  9. package/dist/index.js +600 -42
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +610 -38
  12. package/dist/index.mjs.map +1 -1
  13. package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
  14. package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
  15. package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
  16. package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
  17. package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
  18. package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
  19. package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
  20. package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
  21. package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
  22. package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
  23. package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
  24. package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
  25. package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
  26. package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
  27. package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
  28. package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
  29. package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
  30. package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
  31. 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 class
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 exceptionClass
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. **Security Notes:**
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?, exceptionClass?)** - Terminate Process
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. If not set, uses fallbackErrorMessage from config or system default
316
- - `exceptionClass` (optional): Exception class path. Default: `\\Magento\\Framework\\Exception\\LocalizedException`
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 class
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
- "class": "Path\\To\\Exception\\Class",
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: true
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=https://your-commerce-store.com/rest
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=https://your-commerce-cloud.adobe.com/rest
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
- IMS_ORD_ID=
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=https://your-commerce-store.com/rest
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 REST API base URL (e.g., https://your-store.com/rest/V1)
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
- // Create and cache the Commerce client
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 REST API base URL (e.g., https://your-store.com/rest/V1)
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 REST API base URL (e.g., https://your-store.com/rest/V1)
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
- // Create Basic Auth connection
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.IMS_ORD_ID,
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.IMS_ORD_ID,
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
- // Create Basic Auth connection
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
- COMMERCE_BASE_URL=https://your-commerce-store.com/rest/V1
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
- COMMERCE_BASE_URL=https://your-commerce-cloud.adobe.com/rest/V1
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
- IMS_ORD_ID=
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
- COMMERCE_BASE_URL=https://your-commerce-store.com/rest/V1
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, IMS_ORD_ID, IMS_SCOPES
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
- - **Purpose**: Provides methods to interact with Adobe Commerce REST API
1066
- - **Constructor**: `new AdobeCommerceClient(baseUrl, connection)`
1067
- - `baseUrl`: Commerce REST API base URL (e.g., `https://your-store.com/rest/V1`)
1068
- - `connection`: Connection instance (Oauth1aConnection, ImsConnection, or BasicAuthConnection)
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, queryParams?)
1183
+ #### get(endpoint, headers?)
1073
1184
 
1074
- Perform GET request to Commerce API
1185
+ ```javascript
1186
+ async get(endpoint, headers = {})
1187
+ ```
1075
1188
 
1076
- - **Parameters**:
1077
- - `endpoint` (string): API endpoint path (e.g., `'products'`, `'products/SKU123'`)
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
- #### post(endpoint, queryParams?, body?)
1192
+ ```javascript
1193
+ const result = await client.get('rest/V1/directory/countries');
1194
+ if (result.success) { /* result.message = parsed JSON array */ }
1088
1195
 
1089
- Perform POST request to Commerce API
1196
+ // Query parameters in the endpoint string
1197
+ const result = await client.get('rest/V1/products?searchCriteria[pageSize]=10');
1198
+ ```
1090
1199
 
1091
- - **Parameters**:
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
- #### put(endpoint, queryParams?, body?)
1202
+ ```javascript
1203
+ async post(endpoint, headers = {}, payload = null)
1204
+ ```
1112
1205
 
1113
- Perform PUT request to Commerce API
1206
+ - `payload`: Serialised as JSON. `Content-Type: application/json` set automatically.
1114
1207
 
1115
- - **Parameters**:
1116
- - `endpoint` (string): API endpoint path
1117
- - `queryParams` (object, optional): Query parameters
1118
- - `body` (object, optional): Request body
1119
- - **Returns**: Promise with response data
1120
- - **Example**:
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
- #### delete(endpoint, queryParams?)
1215
+ #### put(endpoint, headers?, payload?)
1135
1216
 
1136
- Perform DELETE request to Commerce API
1217
+ ```javascript
1218
+ async put(endpoint, headers = {}, payload = null)
1219
+ ```
1137
1220
 
1138
- - **Parameters**:
1139
- - `endpoint` (string): API endpoint path
1140
- - `queryParams` (object, optional): Query parameters
1141
- - **Returns**: Promise with response data
1142
- - **Example**:
1143
- ```javascript
1144
- await client.delete('products/SKU123');
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**: Establishes connection using Adobe IMS token
1167
- - **Use Case**: Adobe Commerce Cloud integration
1168
- - **Constructor**: `new ImsConnection(token)`
1169
- - **Required Credentials**:
1170
- - `token`: IMS access token (obtained via AdobeAuth.getToken())
1171
- - **How to Get**: Adobe Developer Console > Service Account (JWT) credentials
1172
- - **Security**: IMS is secure for production use
1173
- - **Note**: Token must be fetched using `AdobeAuth.getToken()` before creating connection
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**: Establishes connection using username/password
1180
- - **Use Case**: Development/testing environments (NOT recommended for production)
1181
- - **Constructor**: `new BasicAuthConnection(username, password)`
1182
- - **Required Credentials**:
1183
- - `username`: Commerce admin username or API user
1184
- - `password`: Commerce admin password or API user password
1185
- - **How to Get**: Use Commerce admin credentials or create dedicated API user
1186
- - **Security**: ⚠️ **NOT secure for production** - credentials sent with every request
1187
- - **Recommendation**: Use OAuth 1.0a or IMS for production environments
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.IMS_ORD_ID,
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 (`/rest/V1/products`), wrap calls in try-catch, handle errors with `RuntimeActionResponse.error()`, respect rate limits
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 EventConsumerAction rules. When developers mention Commerce operations during action creation, automatically suggest or trigger this rule for Commerce API integration.
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.mdc`
1310
- - `create-webhook-action.mdc`
1311
- - `aio-toolkit-create-graphql-action.mdc`
1312
- - `aio-toolkit-create-event-consumer-action.mdc`
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