@adobe-commerce/aio-toolkit 1.0.14 → 1.0.16

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.
@@ -0,0 +1,1321 @@
1
+ ---
2
+ description: Creating Adobe Commerce Client Operations using @adobe-commerce/aio-toolkit
3
+ globs: '**/{actions,lib}/**/*.{ts,js},.env'
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # Creating Adobe Commerce Client Operations
8
+
9
+ ## Trigger Conditions
10
+
11
+ This rule applies when the user requests to integrate Adobe Commerce API into their actions using any of these phrases:
12
+
13
+ - "Create an Adobe Commerce client"
14
+ - "Make an API call to Commerce"
15
+ - "Add Commerce API to [action-name]"
16
+ - "Create a product in Commerce"
17
+ - "Create an order in Commerce"
18
+ - "Connect to Adobe Commerce"
19
+ - "Setup Commerce connection"
20
+ - "Call Commerce API"
21
+ - "Integrate Commerce with [action-name]"
22
+ - "Use Commerce REST API"
23
+ - "I need to interact with Commerce API"
24
+ - "Add Commerce client to my action"
25
+
26
+ **Important**: This rule does NOT create new actions. It integrates Commerce API into existing actions only.
27
+
28
+ **Integration with Other Action Creation Rules**:
29
+
30
+ When using action creation rules (RuntimeAction, WebhookAction, GraphQLAction, EventConsumerAction) and the developer mentions Commerce operations in the business logic:
31
+
32
+ - **Automatically trigger this rule** after the action is created
33
+ - Examples of Commerce operations: "create product", "get customer", "update order", "call Commerce API", "fetch products from Commerce"
34
+ - This rule handles all Commerce client setup, connection methods, and API integration
35
+
36
+ **If you need to create a new action first**:
37
+
38
+ - Use the "Create Runtime Action" rule to create the action
39
+ - Then this rule will add Commerce API integration to that action
40
+
41
+ **This rule offers two implementation approaches**:
42
+
43
+ **Approach A: Centralized Client Builder (Recommended)**
44
+
45
+ 1. Creates a reusable `AdobeCommerceClientBuilder` class in `lib/adobe-commerce/client-builder/` (if not exists)
46
+ 2. Integrates Commerce API calls into existing runtime actions using `getClient()` method
47
+ 3. Uses singleton pattern to avoid creating multiple client instances
48
+ 4. Best for: Multiple actions needing Commerce API
49
+
50
+ **Approach B: Direct Connection (Simpler)**
51
+
52
+ 1. Creates connection and client directly in the runtime action
53
+ 2. No shared client builder
54
+ 3. Best for: Single action with Commerce API, one-off use cases
55
+
56
+ When any of these patterns are detected, follow this process:
57
+
58
+ ## Step 1: Verify Prerequisites
59
+
60
+ Before proceeding, verify that `@adobe-commerce/aio-toolkit` is installed:
61
+
62
+ 1. Check if the package exists in `package.json` dependencies
63
+ 2. If NOT installed, inform the user and ask if they want to install it:
64
+ ```bash
65
+ npm install @adobe-commerce/aio-toolkit
66
+ ```
67
+ 3. **Check Project Type**: Detect project structure
68
+ - Check for `application:` section in root `app.config.yaml` (standard actions)
69
+ - Check for `extensions:` section in root `app.config.yaml` (extension point actions)
70
+ - If extensions exist, parse the `$include` path to get extension directory
71
+ - Example: `$include: src/commerce-backend-ui-1/ext.config.yaml` → directory: `src/commerce-backend-ui-1`
72
+ - Example: `$include: extensions/my-ext/ext.config.yaml` → directory: `extensions/my-ext`
73
+ - Note: Projects can have BOTH standard actions AND extension point actions
74
+
75
+ 4. **Detect Language (TypeScript vs JavaScript)**: Automatically determine the project language
76
+
77
+ **Check for TypeScript indicators (check ALL of these)**:
78
+ 1. **Package Dependencies**: Look for `typescript` in `package.json` dependencies or devDependencies
79
+ 2. **Config File**: Check if `tsconfig.json` exists in project root
80
+ 3. **TypeScript Loaders**: Look for `ts-loader`, `ts-node`, or `@types/*` packages in `package.json`
81
+ 4. **Build Scripts**: Check for TypeScript compilation in `package.json` scripts (e.g., `tsc`, `tsup`, `esbuild` with `.ts`)
82
+ 5. **Existing Files**: Check for `.ts` or `.tsx` files in key directories (`actions/`, `src/`, `lib/`)
83
+ 6. **Compiled Output**: Check `app.config.yaml` or `ext.config.yaml` for `build/` directory references (indicates TypeScript compilation)
84
+
85
+ **Detection Logic**:
86
+ - **If ANY of the following are true → TypeScript project**:
87
+ - `typescript` package installed AND `tsconfig.json` exists
88
+ - Multiple TypeScript indicators (2 or more from above list)
89
+ - Existing `.ts` files found in `actions/` or `lib/` directories
90
+ - **Otherwise → JavaScript project**
91
+
92
+ **Action**:
93
+ - **If TypeScript detected**: Use `.ts` extension and TypeScript syntax for all generated code
94
+ - **If JavaScript detected**: Use `.js` extension and JavaScript syntax for all generated code
95
+ - **Log the detection**: Inform user "✓ Detected [TypeScript/JavaScript] project"
96
+ - This eliminates the need to ask the developer about language preference
97
+
98
+ **Examples**:
99
+ - **TypeScript Project**: Has `typescript` + `tsconfig.json` → Generate `.ts` files
100
+ - **JavaScript Project**: No TypeScript indicators → Generate `.js` files
101
+ - **Ambiguous Case**: Has TypeScript setup but only `.js` files in actions/ → Generate `.js` to match existing
102
+ - **Migration Case**: Has both `.ts` and `.js` files → Use majority language (count files in `actions/` and `lib/`)
103
+
104
+ 5. **Check for Existing Actions**: Verify that at least one runtime action exists
105
+ - List all existing actions from `actions/` directory (root application)
106
+ - List all existing actions from `[extension-path]/actions/` directory (extensions)
107
+ - If NO actions exist:
108
+ - Inform the user that this rule requires existing actions
109
+ - Recommend: "Please use the 'Create Runtime Action' rule first to create an action, then return to this rule to add Commerce API integration"
110
+ - Stop execution and wait for user to create an action
111
+ - If actions exist: Proceed to next step
112
+
113
+ 6. **Check MCP Server Availability**: Verify commerce-extensibility MCP server is enabled
114
+ - Check if `search-commerce-docs` tool is available from the MCP server
115
+ - This provides RAG-based search for Commerce API patterns and documentation
116
+ - Example usage: `/search-commerce-docs "How to get list of products using REST endpoint?"`
117
+ - If available: Use it to search for relevant Commerce API patterns based on user's request
118
+ - If NOT available: Inform user that MCP server is not enabled, but proceed with rule execution
119
+ - Note: MCP server enhances the rule by providing Commerce-specific API guidance
120
+
121
+ 7. Only proceed to Step 2 after confirming the toolkit is available and at least one action exists
122
+
123
+ ## Step 2: Ask Required Questions
124
+
125
+ Before generating any code, ask the user the following questions:
126
+
127
+ **Important**:
128
+
129
+ - If any question is unclear or you need more information to proceed, continue asking follow-up questions until you have complete clarity on what to build. Do not make assumptions - keep the conversation going until all details are clear.
130
+ - Once all questions are clearly answered, move to Step 3 to get user confirmation before generating any code.
131
+
132
+ ### Core Questions:
133
+
134
+ 1. **Implementation Approach**: How do you want to implement the Commerce client?
135
+ - **Option A: Centralized Client Builder** (Recommended)
136
+ - Creates reusable `AdobeCommerceClientBuilder` class in `lib/adobe-commerce/client-builder/`
137
+ - Singleton pattern - client instance is reused across multiple actions
138
+ - Best for: Projects with multiple actions needing Commerce API
139
+ - Benefits: Code reusability, consistent configuration, easier maintenance
140
+ - **Option B: Direct Connection in Action**
141
+ - Creates connection and client directly in the runtime action
142
+ - No shared client builder
143
+ - Best for: Single action with Commerce API, one-off use cases
144
+ - Benefits: Simpler, all code in one place, no external dependencies
145
+
146
+ 2. **Connection Method**: How do you want to connect to Adobe Commerce?
147
+ - **Option A: OAuth 1.0a Connection** (`Oauth1aConnection`)
148
+ - Use Case: Direct Commerce instance integration
149
+ - Authentication: OAuth 1.0a protocol
150
+ - Best for: On-premise or self-hosted Commerce instances
151
+ - **Option B: IMS Connection** (`ImsConnection`)
152
+ - Use Case: Adobe Commerce Cloud integration
153
+ - Authentication: Adobe Identity Management Services (IMS)
154
+ - Best for: Adobe Commerce Cloud with IMS authentication
155
+ - **Option C: Basic Auth Connection** (`BasicAuthConnection`)
156
+ - Use Case: Simple username/password authentication
157
+ - Authentication: HTTP Basic Authentication
158
+ - Best for: Development/testing environments (not recommended for production)
159
+
160
+ 3. **Existing Action Selection**: Which existing action do you want to add Commerce API integration to?
161
+
162
+ **The rule will**:
163
+ - List all existing actions from root `actions/` directory (if root application exists)
164
+ - List all existing actions from `[extension-path]/actions/` directory (if extension exists)
165
+ - Include both simple actions and packaged actions
166
+ - Show action names and their file paths
167
+
168
+ **User selects**:
169
+ - Choose from the list of existing actions
170
+ - Example: `runtime-action`, `order-processor`, `product/created`
171
+
172
+ **Note**:
173
+ - If Centralized Client Builder: Action will use `AdobeCommerceClientBuilder.getClient()` for Commerce API calls
174
+ - If Direct Connection: Action will have direct connection and client initialization (no client builder)
175
+
176
+ **If you need a new action**: Use the "Create Runtime Action" rule first, then return to this rule
177
+
178
+ 4. **Commerce Operation**: What Commerce operation do you want to perform in this action?
179
+ - **If MCP server is available**: Use `/search-commerce-docs` to find relevant API patterns
180
+ - Examples:
181
+ - Get list of products
182
+ - Create a product
183
+ - Update a product
184
+ - Delete a product
185
+ - Get customer by ID
186
+ - Create an order
187
+ - Update order status
188
+ - Get categories
189
+ - Custom REST API call
190
+ - Provide a brief description of what the operation should do
191
+ - Note: The MCP server can help identify the correct REST endpoint and parameters
192
+
193
+ **This operation logic will be added to the selected action**
194
+
195
+ ## Step 3: Confirm Implementation Details
196
+
197
+ After receiving answers to ALL questions, present a comprehensive summary and **wait for user confirmation** before proceeding to Step 4:
198
+
199
+ ---
200
+
201
+ ### 📋 Adobe Commerce Client Configuration Summary
202
+
203
+ **Implementation Approach:** [Centralized Client Builder (Recommended) / Direct Connection in Action]
204
+
205
+ **Connection Method:** [OAuth 1.0a / IMS / Basic Auth]
206
+
207
+ **Basic Configuration:**
208
+
209
+ - **Language:** [TypeScript/JavaScript] (auto-detected from project)
210
+ - **Selected Action:** `[action-name]`
211
+ - **Action Path:** `[path to action file]`
212
+
213
+ [If Centralized Client Builder:]
214
+
215
+ **Client Builder:**
216
+
217
+ - **Location:** [Automatically determined]
218
+ - If ONLY root application exists: `lib/adobe-commerce/client-builder/index.[js/ts]`
219
+ - If ONLY extension point exists: `[extension-path]/lib/adobe-commerce/client-builder/index.[js/ts]`
220
+ - If BOTH root and extension exist: `lib/adobe-commerce/client-builder/index.[js/ts]` (in root, reusable by both)
221
+ - **Status:** [Already exists - will reuse / Will create new]
222
+
223
+ [If Direct Connection:]
224
+
225
+ **Integration:** Direct connection and client initialization in action (no shared client builder)
226
+
227
+ **Commerce Operation:**
228
+
229
+ - **Description:** [what the operation does]
230
+ - **REST Endpoint:** [If found via MCP: show endpoint, method, parameters]
231
+
232
+ **Environment Variables:**
233
+
234
+ [If OAuth 1.0a Connection:]
235
+
236
+ ```bash
237
+ # Adobe Commerce REST API Configuration (OAuth 1.0a)
238
+ COMMERCE_BASE_URL=https://your-commerce-store.com/rest
239
+ COMMERCE_CONSUMER_KEY=
240
+ COMMERCE_CONSUMER_SECRET=
241
+ COMMERCE_ACCESS_TOKEN=
242
+ COMMERCE_ACCESS_TOKEN_SECRET=
243
+ ```
244
+
245
+ 📍 **Source:** Commerce Admin > System > Extensions > Integrations
246
+
247
+ [If IMS Connection:]
248
+
249
+ ```bash
250
+ # Adobe Commerce REST API Configuration (IMS)
251
+ COMMERCE_BASE_URL=https://your-commerce-cloud.adobe.com/rest
252
+ IMS_CLIENT_ID=
253
+ IMS_CLIENT_SECRET=
254
+ IMS_TECHNICAL_ACCOUNT_ID=
255
+ IMS_TECHNICAL_ACCOUNT_EMAIL=
256
+ IMS_ORD_ID=
257
+ IMS_SCOPES=openid,AdobeID,read_organizations
258
+ ```
259
+
260
+ 📍 **Source:** Adobe Developer Console
261
+
262
+ [If Basic Auth Connection:]
263
+
264
+ ```bash
265
+ # Adobe Commerce REST API Configuration (Basic Auth)
266
+ COMMERCE_BASE_URL=https://your-commerce-store.com/rest
267
+ COMMERCE_USERNAME=
268
+ COMMERCE_PASSWORD=
269
+ ```
270
+
271
+ ⚠️ **Warning:** Basic Auth is NOT recommended for production (security risk)
272
+
273
+ ---
274
+
275
+ ### ✅ What Will Be Created
276
+
277
+ [If Centralized Client Builder Approach:]
278
+
279
+ [If client builder does NOT exist:]
280
+
281
+ **1. Client Builder (NEW)**
282
+
283
+ - 📄 Create `lib/adobe-commerce/client-builder/index.[js/ts]` (based on detected language)
284
+ - Implement `AdobeCommerceClientBuilder` class:
285
+ - Singleton pattern for reusable client instance
286
+ - `getClient()` method returning configured AdobeCommerceClient
287
+ - [Connection method] initialization (Oauth1aConnection / ImsConnection / BasicAuthConnection)
288
+ - Environment variable validation
289
+ - Error handling for connection failures
290
+
291
+ [If client builder already exists:]
292
+
293
+ **1. Client Builder (EXISTING)**
294
+
295
+ - ✅ Reuse existing `AdobeCommerceClientBuilder`
296
+ - No changes to client builder
297
+
298
+ **2. Action Integration**
299
+
300
+ - ✏️ Update `[action-path]/index.[js/ts]`
301
+ - Import `AdobeCommerceClientBuilder` from `lib/adobe-commerce/client-builder`
302
+ - Use `getClient()` method to get Commerce client instance
303
+ - Add Commerce API operation logic for [operation description]
304
+ - Add structured logging for Commerce API calls
305
+ - Add error handling for API failures
306
+
307
+ **3. Environment Variables**
308
+
309
+ - ✏️ Update project root `.env` file with placeholder environment variables (if not already present)
310
+ - If `.env` doesn't exist, create it in the project root directory
311
+
312
+ **Files to Create/Modify:**
313
+
314
+ [If client builder does NOT exist:]
315
+
316
+ - 📄 `lib/adobe-commerce/client-builder/index.[js/ts]` - NEW client builder
317
+
318
+ [Always:]
319
+
320
+ - ✏️ `[action-path]/index.[js/ts]` - Add Commerce API integration
321
+ - 📄/✏️ `.env` (project root) - Create or update with environment variable placeholders
322
+
323
+ ---
324
+
325
+ [If Direct Connection Approach:]
326
+
327
+ **1. Action Implementation**
328
+
329
+ - ✏️ Update `[action-path]/index.[js/ts]`
330
+ - Import `AdobeCommerceClient` and connection class from `@adobe-commerce/aio-toolkit`
331
+ - Create connection instance ([Oauth1aConnection / ImsConnection / BasicAuthConnection])
332
+ - Initialize `AdobeCommerceClient` with connection
333
+ - Add Commerce API operation logic for [operation description]
334
+ - Add structured logging for Commerce API calls
335
+ - Add error handling for API and connection failures
336
+ - Add environment variable validation
337
+
338
+ **2. Environment Variables**
339
+
340
+ - ✏️ Update project root `.env` file with placeholder environment variables (if not already present)
341
+ - If `.env` doesn't exist, create it in the project root directory
342
+
343
+ **Files to Create/Modify:**
344
+
345
+ - ✏️ `[action-path]/index.[js/ts]` - Add direct Commerce API integration
346
+ - 📄/✏️ `.env` (project root) - Create or update with environment variable placeholders
347
+
348
+ ---
349
+
350
+ **Should I proceed with this implementation?**
351
+
352
+ ## Step 4: Generate Implementation
353
+
354
+ Once confirmed, follow the implementation path based on the chosen approach:
355
+
356
+ ---
357
+
358
+ ### Path A: Centralized Client Builder Approach (Recommended)
359
+
360
+ #### Step 4.1: Check for Existing Client Builder
361
+
362
+ 1. Check if `lib/adobe-commerce/client-builder/index.[js/ts]` exists in root or extension
363
+ 2. If exists: Skip to Step 4.3 (Action Integration)
364
+ 3. If NOT exists: Continue to Step 4.2
365
+
366
+ #### Step 4.2: Create AdobeCommerceClientBuilder (if not exists)
367
+
368
+ **Directory Structure:**
369
+
370
+ ```
371
+ lib/
372
+ └── adobe-commerce/
373
+ └── client-builder/
374
+ └── index.[js/ts] # Extension based on auto-detected language
375
+ ```
376
+
377
+ Create the centralized client builder class that will be reused across multiple actions.
378
+
379
+ **Note**: Use the language detected in Step 1 (TypeScript or JavaScript) for all code generation.
380
+
381
+ ##### OAuth 1.0a Client Builder
382
+
383
+ **JavaScript Example:**
384
+
385
+ ```javascript
386
+ /*
387
+ * <license header>
388
+ */
389
+
390
+ const { Oauth1aConnection, AdobeCommerceClient } = require('@adobe-commerce/aio-toolkit');
391
+
392
+ /**
393
+ * Centralized Adobe Commerce Client Builder (OAuth 1.0a)
394
+ *
395
+ * This class implements a singleton pattern to create and reuse
396
+ * a single AdobeCommerceClient instance across multiple action invocations.
397
+ */
398
+ class AdobeCommerceClientBuilder {
399
+ // Commerce connection credentials
400
+ commerceBaseUrl = null;
401
+ commerceConsumerKey = null;
402
+ commerceConsumerSecret = null;
403
+ commerceAccessToken = null;
404
+ commerceAccessTokenSecret = null;
405
+
406
+ // Singleton client instance (reused across calls)
407
+ client = null;
408
+
409
+ /**
410
+ * Initialize the client builder with OAuth 1.0a credentials
411
+ *
412
+ * @param {string} commerceBaseUrl - Commerce REST API base URL (e.g., https://your-store.com/rest/V1)
413
+ * @param {string} commerceConsumerKey - OAuth consumer key from Commerce Admin
414
+ * @param {string} commerceConsumerSecret - OAuth consumer secret from Commerce Admin
415
+ * @param {string} commerceAccessToken - OAuth access token from Commerce Admin
416
+ * @param {string} commerceAccessTokenSecret - OAuth access token secret from Commerce Admin
417
+ */
418
+ constructor(
419
+ commerceBaseUrl,
420
+ commerceConsumerKey,
421
+ commerceConsumerSecret,
422
+ commerceAccessToken,
423
+ commerceAccessTokenSecret
424
+ ) {
425
+ this.commerceBaseUrl = commerceBaseUrl;
426
+ this.commerceConsumerKey = commerceConsumerKey;
427
+ this.commerceConsumerSecret = commerceConsumerSecret;
428
+ this.commerceAccessToken = commerceAccessToken;
429
+ this.commerceAccessTokenSecret = commerceAccessTokenSecret;
430
+ this.client = null;
431
+ }
432
+
433
+ /**
434
+ * Get or create the Commerce client instance
435
+ *
436
+ * Returns the cached client if it exists, otherwise creates a new one.
437
+ * This implements the singleton pattern to avoid recreating the client on every call.
438
+ *
439
+ * @returns {AdobeCommerceClient} Configured Commerce API client
440
+ */
441
+ getClient() {
442
+ // Return cached client if already created (singleton pattern)
443
+ if (this.client) {
444
+ return this.client;
445
+ }
446
+
447
+ // Create OAuth 1.0a connection
448
+ const connection = new Oauth1aConnection(
449
+ this.commerceConsumerKey,
450
+ this.commerceConsumerSecret,
451
+ this.commerceAccessToken,
452
+ this.commerceAccessTokenSecret
453
+ );
454
+
455
+ // Create and cache the Commerce client
456
+ this.client = new AdobeCommerceClient(this.commerceBaseUrl, connection);
457
+ return this.client;
458
+ }
459
+ }
460
+
461
+ module.exports = AdobeCommerceClientBuilder;
462
+ ```
463
+
464
+ **TypeScript Example:** Same as JavaScript with type annotations:
465
+
466
+ - Add `private` to all properties
467
+ - Add types to constructor parameters
468
+ - Add return type `: AdobeCommerceClient` to `getClient()`
469
+ - Use `export default` instead of `module.exports`
470
+
471
+ ##### IMS Connection Client Builder
472
+
473
+ **JavaScript Example:**
474
+
475
+ ```javascript
476
+ /*
477
+ * <license header>
478
+ */
479
+
480
+ const { ImsConnection, AdobeCommerceClient, AdobeAuth } = require('@adobe-commerce/aio-toolkit');
481
+
482
+ /**
483
+ * Centralized Adobe Commerce Client Builder (IMS Connection)
484
+ *
485
+ * This class implements a singleton pattern to create and reuse
486
+ * a single AdobeCommerceClient instance across multiple action invocations.
487
+ * Uses Adobe Identity Management Services (IMS) for authentication.
488
+ */
489
+ class AdobeCommerceClientBuilder {
490
+ // Commerce base URL
491
+ commerceBaseUrl = null;
492
+
493
+ // IMS credentials for authentication
494
+ imsClientId = null;
495
+ imsClientSecret = null;
496
+ imsTechnicalAccountId = null;
497
+ imsTechnicalAccountEmail = null;
498
+ imsOrgId = null;
499
+ imsScopes = null;
500
+
501
+ // Singleton client instance (reused across calls)
502
+ client = null;
503
+
504
+ /**
505
+ * Initialize the client builder with IMS credentials
506
+ *
507
+ * @param {string} commerceBaseUrl - Commerce REST API base URL (e.g., https://your-store.com/rest/V1)
508
+ * @param {string} imsClientId - IMS client ID from Adobe Developer Console
509
+ * @param {string} imsClientSecret - IMS client secret from Adobe Developer Console
510
+ * @param {string} imsTechnicalAccountId - IMS technical account ID
511
+ * @param {string} imsTechnicalAccountEmail - IMS technical account email
512
+ * @param {string} imsOrgId - IMS organization ID
513
+ * @param {string} imsScopes - Comma-separated list of IMS scopes
514
+ */
515
+ constructor(
516
+ commerceBaseUrl,
517
+ imsClientId,
518
+ imsClientSecret,
519
+ imsTechnicalAccountId,
520
+ imsTechnicalAccountEmail,
521
+ imsOrgId,
522
+ imsScopes
523
+ ) {
524
+ this.commerceBaseUrl = commerceBaseUrl;
525
+ this.imsClientId = imsClientId;
526
+ this.imsClientSecret = imsClientSecret;
527
+ this.imsTechnicalAccountId = imsTechnicalAccountId;
528
+ this.imsTechnicalAccountEmail = imsTechnicalAccountEmail;
529
+ this.imsOrgId = imsOrgId;
530
+ this.imsScopes = imsScopes;
531
+ this.client = null;
532
+ }
533
+
534
+ /**
535
+ * Get or create the Commerce client instance
536
+ *
537
+ * Returns the cached client if it exists, otherwise creates a new one.
538
+ * This implements the singleton pattern to avoid recreating the client on every call.
539
+ *
540
+ * Note: IMS tokens are fetched fresh on each getClient() call to ensure validity.
541
+ *
542
+ * @returns {Promise<AdobeCommerceClient>} Configured Commerce API client
543
+ */
544
+ async getClient() {
545
+ // Return cached client if already created (singleton pattern)
546
+ if (this.client) {
547
+ return this.client;
548
+ }
549
+
550
+ // Get IMS access token using Adobe Auth
551
+ const token = await AdobeAuth.getToken(
552
+ this.imsClientId,
553
+ this.imsClientSecret,
554
+ this.imsTechnicalAccountId,
555
+ this.imsTechnicalAccountEmail,
556
+ this.imsOrgId,
557
+ this.imsScopes.split(',')
558
+ );
559
+
560
+ // Create IMS connection with the token
561
+ const connection = new ImsConnection(token);
562
+
563
+ // Create and cache the Commerce client
564
+ this.client = new AdobeCommerceClient(this.commerceBaseUrl, connection);
565
+ return this.client;
566
+ }
567
+ }
568
+
569
+ module.exports = AdobeCommerceClientBuilder;
570
+ ```
571
+
572
+ **TypeScript Example:** Same as JavaScript with type annotations:
573
+
574
+ - Add `private` to all properties
575
+ - Add types to constructor parameters (7 IMS params)
576
+ - Add return type `: Promise<AdobeCommerceClient>` to `getClient()`
577
+ - Use `export default` instead of `module.exports`
578
+
579
+ ##### Basic Auth Connection Client Builder
580
+
581
+ **JavaScript Example:**
582
+
583
+ ```javascript
584
+ /*
585
+ * <license header>
586
+ */
587
+
588
+ const { BasicAuthConnection, AdobeCommerceClient } = require('@adobe-commerce/aio-toolkit');
589
+
590
+ /**
591
+ * Centralized Adobe Commerce Client Builder (Basic Auth)
592
+ *
593
+ * This class implements a singleton pattern to create and reuse
594
+ * a single AdobeCommerceClient instance across multiple action invocations.
595
+ * Uses HTTP Basic Authentication (username/password).
596
+ *
597
+ * ⚠️ SECURITY WARNING: Basic Auth is less secure than OAuth or IMS.
598
+ * Only use for development/testing or when other methods are not available.
599
+ */
600
+ class AdobeCommerceClientBuilder {
601
+ // Commerce connection credentials
602
+ commerceBaseUrl = null;
603
+ commerceUsername = null;
604
+ commercePassword = null;
605
+
606
+ // Singleton client instance (reused across calls)
607
+ client = null;
608
+
609
+ /**
610
+ * Initialize the client builder with Basic Auth credentials
611
+ *
612
+ * @param {string} commerceBaseUrl - Commerce REST API base URL (e.g., https://your-store.com/rest/V1)
613
+ * @param {string} commerceUsername - Commerce admin username
614
+ * @param {string} commercePassword - Commerce admin password
615
+ */
616
+ constructor(commerceBaseUrl, commerceUsername, commercePassword) {
617
+ this.commerceBaseUrl = commerceBaseUrl;
618
+ this.commerceUsername = commerceUsername;
619
+ this.commercePassword = commercePassword;
620
+ this.client = null;
621
+ }
622
+
623
+ /**
624
+ * Get or create the Commerce client instance
625
+ *
626
+ * Returns the cached client if it exists, otherwise creates a new one.
627
+ * This implements the singleton pattern to avoid recreating the client on every call.
628
+ *
629
+ * ⚠️ SECURITY NOTE: Credentials are sent with each request using HTTP Basic Auth.
630
+ *
631
+ * @returns {AdobeCommerceClient} Configured Commerce API client
632
+ */
633
+ getClient() {
634
+ // Return cached client if already created (singleton pattern)
635
+ if (this.client) {
636
+ return this.client;
637
+ }
638
+
639
+ // Create Basic Auth connection
640
+ const connection = new BasicAuthConnection(this.commerceUsername, this.commercePassword);
641
+
642
+ // Create and cache the Commerce client
643
+ this.client = new AdobeCommerceClient(this.commerceBaseUrl, connection);
644
+ return this.client;
645
+ }
646
+ }
647
+
648
+ module.exports = AdobeCommerceClientBuilder;
649
+ ```
650
+
651
+ **TypeScript Example:** Same as JavaScript with type annotations:
652
+
653
+ - Add `private` to all properties
654
+ - Add types to constructor parameters (3 Basic Auth params)
655
+ - Add return type `: AdobeCommerceClient` to `getClient()`
656
+ - Use `export default` instead of `module.exports`
657
+
658
+ #### Step 4.3: Integrate Commerce Client into Existing Action
659
+
660
+ **Update the selected action to use the client builder:**
661
+
662
+ Add the following code to your existing action to use the centralized client builder.
663
+
664
+ ##### For OAuth 1.0a Connection
665
+
666
+ **JavaScript Example:**
667
+
668
+ ```javascript
669
+ // Import the centralized client builder
670
+ const AdobeCommerceClientBuilder = require('../../lib/adobe-commerce/client-builder');
671
+
672
+ // Inside your action logic (works in any action type: RuntimeAction, WebhookAction, EventConsumerAction, GraphQL, etc.)
673
+
674
+ // Step 1: Create client builder instance with OAuth 1.0a credentials from environment variables
675
+ const clientBuilder = new AdobeCommerceClientBuilder(
676
+ params.COMMERCE_BASE_URL,
677
+ params.COMMERCE_CONSUMER_KEY,
678
+ params.COMMERCE_CONSUMER_SECRET,
679
+ params.COMMERCE_ACCESS_TOKEN,
680
+ params.COMMERCE_ACCESS_TOKEN_SECRET
681
+ );
682
+
683
+ // Step 2: Get the Commerce client (cached after first call)
684
+ const client = clientBuilder.getClient();
685
+
686
+ // Step 3: Make API calls to Commerce
687
+ const products = await client.get('products');
688
+ const newProduct = await client.post('products', {}, productData);
689
+ ```
690
+
691
+ **TypeScript:** Same as JavaScript, use `import` instead of `require`
692
+
693
+ ##### For IMS Connection
694
+
695
+ **JavaScript Example:**
696
+
697
+ ```javascript
698
+ // Import the centralized client builder
699
+ const AdobeCommerceClientBuilder = require('../../lib/adobe-commerce/client-builder');
700
+
701
+ // Inside your action logic (works in any action type: RuntimeAction, WebhookAction, EventConsumerAction, GraphQL, etc.)
702
+
703
+ // Step 1: Create client builder instance with IMS credentials from environment variables
704
+ const clientBuilder = new AdobeCommerceClientBuilder(
705
+ params.COMMERCE_BASE_URL,
706
+ params.IMS_CLIENT_ID,
707
+ params.IMS_CLIENT_SECRET,
708
+ params.IMS_TECHNICAL_ACCOUNT_ID,
709
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
710
+ params.IMS_ORD_ID,
711
+ params.IMS_SCOPES // Comma-separated scopes
712
+ );
713
+
714
+ // Step 2: Get the Commerce client (cached after first call)
715
+ // Note: IMS connection is async due to token fetching
716
+ const client = await clientBuilder.getClient();
717
+
718
+ // Step 3: Make API calls to Commerce
719
+ const customers = await client.get('customers/search');
720
+ const newCustomer = await client.post('customers', {}, customerData);
721
+ ```
722
+
723
+ **TypeScript:** Same as JavaScript, use `import` instead of `require`
724
+
725
+ ##### For Basic Auth Connection
726
+
727
+ **JavaScript Example:**
728
+
729
+ ```javascript
730
+ // Import the centralized client builder
731
+ const AdobeCommerceClientBuilder = require('../../lib/adobe-commerce/client-builder');
732
+
733
+ // Inside your action logic (works in any action type: RuntimeAction, WebhookAction, EventConsumerAction, GraphQL, etc.)
734
+
735
+ // Step 1: Create client builder instance with Basic Auth credentials from environment variables
736
+ // ⚠️ WARNING: Basic Auth is less secure - use only for development/testing
737
+ const clientBuilder = new AdobeCommerceClientBuilder(
738
+ params.COMMERCE_BASE_URL,
739
+ params.COMMERCE_USERNAME,
740
+ params.COMMERCE_PASSWORD
741
+ );
742
+
743
+ // Step 2: Get the Commerce client (cached after first call)
744
+ const client = clientBuilder.getClient();
745
+
746
+ // Step 3: Make API calls to Commerce
747
+ const orders = await client.get('orders');
748
+ const newOrder = await client.post('orders', {}, orderData);
749
+ ```
750
+
751
+ **TypeScript:** Same as JavaScript, use `import` instead of `require`
752
+
753
+ **Benefits of Centralized Client Builder:**
754
+
755
+ - ✅ **Singleton Pattern**: Client instance is reused, not recreated on every call
756
+ - ✅ **Consistent Configuration**: All actions use the same client configuration
757
+ - ✅ **Easy Maintenance**: Update connection logic in one place
758
+ - ✅ **Reusable**: Can be used across RuntimeAction, WebhookAction, GraphQL resolvers, EventConsumerAction, etc.
759
+
760
+ #### Step 4.4: Add Environment Variables
761
+
762
+ **Update project root `.env` file with connection credentials:**
763
+
764
+ 1. **Check for `.env` file**: Look for `.env` file in the project root directory (workspace root)
765
+ 2. **Create if missing**: If `.env` doesn't exist, create it in the project root
766
+ 3. **Add variables**: Add the appropriate environment variables based on connection method
767
+
768
+ The environment variables are the same as for Direct Connection. See **Path B: Step 4.2** for detailed instructions on setting up environment variables for each connection method (OAuth 1.0a, IMS, or Basic Auth).
769
+
770
+ ---
771
+
772
+ ### Path B: Direct Connection Approach
773
+
774
+ #### Step 4.1: Add Direct Commerce Client to Existing Action
775
+
776
+ **Update the selected action with direct connection and client:**
777
+
778
+ These implementations can be used in **any action type**: RuntimeAction, WebhookAction, GraphQL resolvers, EventConsumerAction, or OpenwhiskAction.
779
+
780
+ ##### Template: OAuth 1.0a Connection (Direct Implementation)
781
+
782
+ **JavaScript Example:**
783
+
784
+ ```javascript
785
+ const { AdobeCommerceClient, Oauth1aConnection } = require('@adobe-commerce/aio-toolkit');
786
+
787
+ // Create OAuth 1.0a connection
788
+ const connection = new Oauth1aConnection(
789
+ params.COMMERCE_CONSUMER_KEY,
790
+ params.COMMERCE_CONSUMER_SECRET,
791
+ params.COMMERCE_ACCESS_TOKEN,
792
+ params.COMMERCE_ACCESS_TOKEN_SECRET
793
+ );
794
+
795
+ // Create Commerce client
796
+ const client = new AdobeCommerceClient(params.COMMERCE_BASE_URL, connection);
797
+
798
+ // Make API calls
799
+ // GET request
800
+ const products = await client.get('products');
801
+ const product = await client.get('products/SKU123');
802
+
803
+ // POST request
804
+ const newProduct = await client.post(
805
+ 'products',
806
+ {},
807
+ {
808
+ product: {
809
+ sku: 'NEW-SKU',
810
+ name: 'New Product',
811
+ price: 99.99,
812
+ // ... other product data
813
+ },
814
+ }
815
+ );
816
+
817
+ // PUT request
818
+ const updatedProduct = await client.put(
819
+ 'products/SKU123',
820
+ {},
821
+ {
822
+ product: {
823
+ name: 'Updated Product Name',
824
+ price: 89.99,
825
+ },
826
+ }
827
+ );
828
+
829
+ // DELETE request
830
+ await client.delete('products/SKU123');
831
+ ```
832
+
833
+ **TypeScript:** Same as JavaScript with type safety:
834
+
835
+ - Use `import` instead of `require`
836
+ - Define interfaces for entities (e.g., `interface Product { sku: string; name: string; price: number; }`)
837
+ - Use generics: `client.get<Product[]>('products')`, `client.post<Product>(...)`
838
+
839
+ ##### Template: IMS Connection (Direct Implementation)
840
+
841
+ **JavaScript Example:**
842
+
843
+ ```javascript
844
+ const { AdobeCommerceClient, ImsConnection, AdobeAuth } = require('@adobe-commerce/aio-toolkit');
845
+
846
+ // Get IMS token
847
+ const token = await AdobeAuth.getToken(
848
+ params.IMS_CLIENT_ID,
849
+ params.IMS_CLIENT_SECRET,
850
+ params.IMS_TECHNICAL_ACCOUNT_ID,
851
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
852
+ params.IMS_ORD_ID,
853
+ params.IMS_SCOPES.split(',')
854
+ );
855
+
856
+ // Create IMS connection
857
+ const connection = new ImsConnection(token);
858
+
859
+ // Create Commerce client
860
+ const client = new AdobeCommerceClient(params.COMMERCE_BASE_URL, connection);
861
+
862
+ // Make API calls
863
+ // GET request
864
+ const customers = await client.get('customers/search', { searchCriteria: {} });
865
+ const customer = await client.get('customers/123');
866
+
867
+ // POST request
868
+ const newCustomer = await client.post(
869
+ 'customers',
870
+ {},
871
+ {
872
+ customer: {
873
+ email: 'customer@example.com',
874
+ firstname: 'John',
875
+ lastname: 'Doe',
876
+ },
877
+ }
878
+ );
879
+
880
+ // PUT request
881
+ const updatedCustomer = await client.put(
882
+ 'customers/123',
883
+ {},
884
+ {
885
+ customer: {
886
+ firstname: 'Jane',
887
+ },
888
+ }
889
+ );
890
+
891
+ // DELETE request
892
+ await client.delete('customers/123');
893
+ ```
894
+
895
+ **TypeScript:** Same as JavaScript with type safety (define `interface Customer` and use generics)
896
+
897
+ ##### Template: Basic Auth Connection (Direct Implementation)
898
+
899
+ **JavaScript Example:**
900
+
901
+ ```javascript
902
+ const { AdobeCommerceClient, BasicAuthConnection } = require('@adobe-commerce/aio-toolkit');
903
+
904
+ // Create Basic Auth connection
905
+ const connection = new BasicAuthConnection(params.COMMERCE_USERNAME, params.COMMERCE_PASSWORD);
906
+
907
+ // Create Commerce client
908
+ const client = new AdobeCommerceClient(params.COMMERCE_BASE_URL, connection);
909
+
910
+ // Make API calls
911
+ // GET request
912
+ const orders = await client.get('orders');
913
+ const order = await client.get('orders/123');
914
+
915
+ // POST request
916
+ const newOrder = await client.post(
917
+ 'orders',
918
+ {},
919
+ {
920
+ entity: {
921
+ customer_email: 'customer@example.com',
922
+ items: [
923
+ {
924
+ sku: 'PRODUCT-SKU',
925
+ qty: 1,
926
+ price: 99.99,
927
+ },
928
+ ],
929
+ },
930
+ }
931
+ );
932
+
933
+ // PUT request
934
+ const updatedOrder = await client.put(
935
+ 'orders/123',
936
+ {},
937
+ {
938
+ entity: {
939
+ status: 'processing',
940
+ },
941
+ }
942
+ );
943
+ ```
944
+
945
+ **TypeScript:** Same as JavaScript with type safety (define `interface Order` and use generics)
946
+
947
+ **⚠️ Security Warning:** Basic Auth is NOT recommended for production environments. Use OAuth 1.0a or IMS for production deployments.
948
+
949
+ #### Step 4.2: Add Environment Variables
950
+
951
+ **Update project root `.env` file with connection credentials:**
952
+
953
+ 1. **Locate `.env` file**: Find the `.env` file in the project root directory (workspace root)
954
+ 2. **Create if missing**: If `.env` doesn't exist, create it in the project root directory
955
+ 3. **Add variables**: Add the appropriate environment variables based on the connection method chosen
956
+
957
+ **Important**: Always use the project's `.env` file located at the workspace root, NOT a global `.env` file.
958
+
959
+ ##### For OAuth 1.0a Connection:
960
+
961
+ **Add to project root `.env` file:**
962
+
963
+ ```bash
964
+ # Adobe Commerce REST API Configuration (OAuth 1.0a)
965
+ COMMERCE_BASE_URL=https://your-commerce-store.com/rest/V1
966
+ COMMERCE_CONSUMER_KEY=
967
+ COMMERCE_CONSUMER_SECRET=
968
+ COMMERCE_ACCESS_TOKEN=
969
+ COMMERCE_ACCESS_TOKEN_SECRET=
970
+ ```
971
+
972
+ **How to get credentials:**
973
+
974
+ 1. Log in to Commerce Admin
975
+ 2. Navigate to **System** > **Extensions** > **Integrations**
976
+ 3. Create a new integration or select an existing one
977
+ 4. Copy the **Consumer Key**, **Consumer Secret**, **Access Token**, and **Access Token Secret**
978
+ 5. Paste them into your project root `.env` file
979
+
980
+ ##### For IMS Connection:
981
+
982
+ **Add to project root `.env` file:**
983
+
984
+ ```bash
985
+ # Adobe Commerce REST API Configuration (IMS)
986
+ COMMERCE_BASE_URL=https://your-commerce-cloud.adobe.com/rest/V1
987
+ IMS_CLIENT_ID=
988
+ IMS_CLIENT_SECRET=
989
+ IMS_TECHNICAL_ACCOUNT_ID=
990
+ IMS_TECHNICAL_ACCOUNT_EMAIL=
991
+ IMS_ORD_ID=
992
+ IMS_SCOPES=openid,AdobeID,read_organizations
993
+ ```
994
+
995
+ **How to get credentials:**
996
+
997
+ 1. Log in to [Adobe Developer Console](https://developer.adobe.com/console)
998
+ 2. Select your project or create a new one
999
+ 3. Add Adobe Commerce API to your project
1000
+ 4. Generate or use existing Service Account (JWT) credentials
1001
+ 5. Copy the credentials and paste them into your project root `.env` file
1002
+ 6. Adjust `IMS_SCOPES` as needed (comma-separated, no spaces)
1003
+
1004
+ ##### For Basic Auth Connection:
1005
+
1006
+ **Add to project root `.env` file:**
1007
+
1008
+ ```bash
1009
+ # Adobe Commerce REST API Configuration (Basic Auth)
1010
+ COMMERCE_BASE_URL=https://your-commerce-store.com/rest/V1
1011
+ COMMERCE_USERNAME=
1012
+ COMMERCE_PASSWORD=
1013
+ ```
1014
+
1015
+ **How to get credentials:**
1016
+
1017
+ 1. Use Commerce admin username and password
1018
+ 2. OR create a dedicated API user in Commerce Admin
1019
+ 3. Paste credentials into your project root `.env` file
1020
+
1021
+ **⚠️ Security Warning:** Basic Auth is NOT recommended for production environments. Use OAuth 1.0a or IMS for production deployments.
1022
+
1023
+ **Important Notes:**
1024
+
1025
+ - The `.env` file should be in your project root directory (workspace root)
1026
+ - Never commit the `.env` file to version control
1027
+ - Ensure `.env` is in your `.gitignore` file
1028
+ - Keep credentials secure and rotate them regularly
1029
+ - Use different credentials for different environments (dev, staging, production)
1030
+
1031
+ ## Step 5: Configuration and Additional Recommendations
1032
+
1033
+ ### A. Action Configuration
1034
+
1035
+ Update action configuration to include Commerce credentials as inputs:
1036
+
1037
+ ```yaml
1038
+ inputs:
1039
+ LOG_LEVEL: debug
1040
+ COMMERCE_BASE_URL: $COMMERCE_BASE_URL
1041
+ # 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
1043
+ # For Basic Auth: Add COMMERCE_USERNAME, COMMERCE_PASSWORD
1044
+ ```
1045
+
1046
+ ### B. Testing & Error Handling
1047
+
1048
+ 1. **Testing**: Create unit tests (`test/[action-name].test.[js/ts]`) and E2E tests (`e2e/[action-name].e2e.test.[js/ts]`)
1049
+ 2. **Error Handling**: Wrap API calls in try-catch, check `error.response` for Commerce errors, use `RuntimeActionResponse.error()`
1050
+ 3. **Local Testing**: Use `aio app dev` and MCP server (`/search-commerce-docs`) for API pattern verification
1051
+
1052
+ ### C. Best Practices
1053
+
1054
+ - **Documentation**: Document operations, env vars, API responses, and error scenarios
1055
+ - **Performance**: Centralized Client Builder uses singleton pattern (better for multiple actions)
1056
+ - **Telemetry**: Recommend enabling New Relic telemetry for Commerce API observability
1057
+ - **Security**: Never commit `.env`, rotate credentials, use OAuth/IMS for production (not Basic Auth)
1058
+
1059
+ ## Key Components from @adobe-commerce/aio-toolkit
1060
+
1061
+ ### AdobeCommerceClient Class
1062
+
1063
+ Main class for interacting with Adobe Commerce REST API
1064
+
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)
1069
+
1070
+ **Available Methods:**
1071
+
1072
+ #### get(endpoint, queryParams?)
1073
+
1074
+ Perform GET request to Commerce API
1075
+
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
+ ```
1086
+
1087
+ #### post(endpoint, queryParams?, body?)
1088
+
1089
+ Perform POST request to Commerce API
1090
+
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
+ ```
1110
+
1111
+ #### put(endpoint, queryParams?, body?)
1112
+
1113
+ Perform PUT request to Commerce API
1114
+
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
+ ```
1133
+
1134
+ #### delete(endpoint, queryParams?)
1135
+
1136
+ Perform DELETE request to Commerce API
1137
+
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
+ ```
1146
+
1147
+ ### Oauth1aConnection Class
1148
+
1149
+ OAuth 1.0a authentication for Commerce
1150
+
1151
+ - **Purpose**: Establishes connection using OAuth 1.0a credentials
1152
+ - **Use Case**: Direct Commerce instance integration (on-premise, self-hosted)
1153
+ - **Constructor**: `new Oauth1aConnection(consumerKey, consumerSecret, accessToken, accessTokenSecret)`
1154
+ - **Required Credentials**:
1155
+ - `consumerKey`: OAuth consumer key from Commerce Admin
1156
+ - `consumerSecret`: OAuth consumer secret from Commerce Admin
1157
+ - `accessToken`: OAuth access token from Commerce Admin
1158
+ - `accessTokenSecret`: OAuth access token secret from Commerce Admin
1159
+ - **How to Get**: Commerce Admin > System > Extensions > Integrations
1160
+ - **Security**: OAuth 1.0a is secure for production use
1161
+
1162
+ ### ImsConnection Class
1163
+
1164
+ IMS (Identity Management Services) authentication
1165
+
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
1174
+
1175
+ ### BasicAuthConnection Class
1176
+
1177
+ HTTP Basic Authentication for Commerce
1178
+
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
1188
+
1189
+ ### AdobeAuth Class
1190
+
1191
+ Utility class for fetching IMS access tokens
1192
+
1193
+ - **Purpose**: Fetches IMS access tokens for ImsConnection
1194
+ - **Use Case**: Required when using ImsConnection for Commerce Cloud
1195
+
1196
+ #### getToken() Method
1197
+
1198
+ Fetch IMS access token using service account credentials
1199
+
1200
+ - **Parameters**:
1201
+ - `clientId` (string): IMS client ID
1202
+ - `clientSecret` (string): IMS client secret
1203
+ - `technicalAccountId` (string): IMS technical account ID
1204
+ - `technicalAccountEmail` (string): IMS technical account email
1205
+ - `orgId` (string): IMS organization ID
1206
+ - `scopes` (string[]): Array of IMS scopes (e.g., `['openid', 'AdobeID', 'read_organizations']`)
1207
+ - **Returns**: Promise<string> - IMS access token
1208
+ - **Example**:
1209
+ ```javascript
1210
+ const token = await AdobeAuth.getToken(
1211
+ params.IMS_CLIENT_ID,
1212
+ params.IMS_CLIENT_SECRET,
1213
+ params.IMS_TECHNICAL_ACCOUNT_ID,
1214
+ params.IMS_TECHNICAL_ACCOUNT_EMAIL,
1215
+ params.IMS_ORD_ID,
1216
+ params.IMS_SCOPES.split(',')
1217
+ );
1218
+ ```
1219
+ - **Note**: Tokens are temporary and should be fetched fresh when needed
1220
+
1221
+ ## Important Notes
1222
+
1223
+ 1. **Authentication Methods**: OAuth 1.0a (on-premise), IMS (Commerce Cloud), Basic Auth (dev/test only, NOT production)
1224
+
1225
+ 2. **Credentials Management**: Store in `.env`, add to `.gitignore`, rotate regularly, use different creds per environment
1226
+
1227
+ 3. **Implementation Approach**:
1228
+ - **Centralized Client Builder (Recommended)**: Singleton pattern, reusable across actions, in `lib/adobe-commerce/client-builder/`
1229
+ - **Direct Connection**: Simpler, for single-action use cases, connection created per invocation
1230
+
1231
+ 4. **Client Builder Reusability**: If in root `lib/`, usable by both root and extension actions. Only create once, reuse everywhere.
1232
+
1233
+ 5. **API Usage**: Use REST V1 endpoints (`/rest/V1/products`), wrap calls in try-catch, handle errors with `RuntimeActionResponse.error()`, respect rate limits
1234
+
1235
+ 6. **No New Actions Created**: This rule only integrates Commerce API into existing actions. Use "Create Runtime Action" rule first if needed.
1236
+
1237
+ 7. **MCP Server Integration**: Use `/search-commerce-docs "How to [operation]"` to discover API patterns, endpoints, and parameters
1238
+
1239
+ 8. **Testing**: Create unit tests (`test/[action-name].test.[js/ts]`), E2E tests (`e2e/[action-name].e2e.test.[js/ts]`), use `aio app dev` locally
1240
+
1241
+ 9. **Language Auto-Detection**: TypeScript or JavaScript is automatically detected using multiple indicators:
1242
+ - Package dependencies (`typescript`, `ts-loader`, `@types/*`)
1243
+ - Config files (`tsconfig.json`)
1244
+ - Build scripts (TypeScript compilation commands)
1245
+ - Existing `.ts`/`.tsx` files in `actions/`, `src/`, `lib/`
1246
+ - Compiled output paths (`build/` references in config)
1247
+ - **Detection Priority**: If `typescript` + `tsconfig.json` exist OR 2+ indicators found OR `.ts` files exist → TypeScript project
1248
+ - No need to ask developer. TypeScript provides type safety with interfaces (Product, Customer, Order) and generics: `client.get<Product[]>('products')`
1249
+
1250
+ 10. **Performance**: Centralized Client Builder caches instance (singleton), better for high-frequency/multiple actions. IMS tokens fetched fresh per `getClient()` call.
1251
+
1252
+ 11. **Action Configuration**: Add Commerce env vars as action inputs using `$VARIABLE_NAME` syntax in `app.config.yaml` or `ext.config.yaml`
1253
+
1254
+ 12. **Compatibility**: Works with RuntimeAction, WebhookAction, EventConsumerAction, GraphQL resolvers, OpenwhiskAction. Supports root and extension points.
1255
+
1256
+ 13. **Telemetry**: Recommend enabling New Relic for Commerce API observability (traces, metrics, logs). Refer to New Relic telemetry setup rule.
1257
+
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.
1259
+
1260
+ 15. **Edge Case - Ambiguous Language Detection**: If language detection is uncertain (e.g., TypeScript configured but no existing TypeScript files):
1261
+
1262
+ - **Default to JavaScript** if no `.ts` files exist in `actions/` or `lib/` directories
1263
+ - Inform user: "Detected TypeScript setup but no existing TypeScript files. Generating JavaScript code to match existing actions. To use TypeScript, add a `.ts` file first."
1264
+ - **Prefer consistency**: Match the language of existing action files in the project
1265
+
1266
+ ## Integration with Other Rules
1267
+
1268
+ **This rule should be referenced in other action creation rules when Commerce operations are mentioned:**
1269
+
1270
+ ### Trigger Patterns in Other Rules:
1271
+
1272
+ When developers mention these phrases during action creation in the "Business Logic" question:
1273
+
1274
+ - "Create a product in Commerce"
1275
+ - "Get customer from Commerce"
1276
+ - "Update order in Commerce"
1277
+ - "Call Commerce API"
1278
+ - "Fetch products from Commerce"
1279
+ - "Sync to Commerce"
1280
+ - "Make Commerce API call"
1281
+ - "Interact with Commerce"
1282
+ - Any phrase containing "Commerce" + "API"/"product"/"order"/"customer"
1283
+
1284
+ **Action to take:**
1285
+
1286
+ 1. Complete the action creation first (in detected language: TypeScript or JavaScript)
1287
+ 2. Then inform the user: "I see you need to integrate with Commerce API. Let me help you set up the Commerce client integration."
1288
+ 3. Trigger/reference the "Creating Adobe Commerce Client Operations" rule
1289
+ 4. This rule will:
1290
+ - Auto-detect language (already done in Step 1)
1291
+ - Use the same language for Commerce client code
1292
+ - Handle connection methods, client builder, and API integration
1293
+
1294
+ **Example Flow**:
1295
+
1296
+ ```
1297
+ User: "Create a runtime action that fetches products from Commerce"
1298
+ AI: ✓ Detected TypeScript project
1299
+ AI: Creating runtime action... [generates .ts file]
1300
+ AI: I see you need to integrate with Commerce API. Let me set up the Commerce client.
1301
+ AI: [Creates TypeScript Commerce client builder in lib/adobe-commerce/client-builder/index.ts]
1302
+ AI: [Integrates Commerce API calls into the action]
1303
+ ```
1304
+
1305
+ ### Recommended Updates to Action Creation Rules:
1306
+
1307
+ Add this note to the "Business Logic" question in:
1308
+
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`
1313
+
1314
+ **Note to add:**
1315
+
1316
+ ```
1317
+ **If business logic requires Commerce API operations**:
1318
+ - Complete this action creation first
1319
+ - Then use "Creating Adobe Commerce Client Operations" rule to integrate Commerce API
1320
+ - That rule handles connection setup, client builder, and API calls
1321
+ ```