@adobe-commerce/aio-toolkit 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,117 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.4] - 2025-10-29
9
+
10
+ ### 🚀 Major Feature Release: Webhook Components & Shipping Carrier Builder
11
+
12
+ This minor release introduces powerful new components for Adobe Commerce webhook extensibility, including a comprehensive ShippingCarrier builder and WebhookAction component with signature verification. These additions enable developers to easily create custom shipping carriers and handle webhook requests securely.
13
+
14
+ #### 🎯 Commerce Components
15
+
16
+ - **ShippingCarrier** `[New]` - Fluent builder for custom shipping carrier creation
17
+ - Builder pattern implementation with method chaining support
18
+ - Comprehensive carrier configuration (title, stores, countries, sort order, active status)
19
+ - Shipping method management with add/remove capabilities
20
+ - Validation for carrier and method codes (alphanumeric and underscores only)
21
+ - Integration with WebhookActionResponse for seamless webhook responses
22
+ - Type-safe TypeScript interfaces for all data structures
23
+ - 100% test coverage with 67 comprehensive tests
24
+
25
+ - **ShippingCarrierMethod** `[New]` - Builder for individual shipping methods
26
+ - Configure method title, price, cost, and additional data
27
+ - Flexible additional data structure for custom metadata
28
+ - Returns structured method data via `getData()`
29
+ - Full TypeScript support with `ShippingCarrierMethodData` interface
30
+
31
+ - **ShippingCarrierResponse** `[New]` - Webhook response generator
32
+ - Generates WebhookActionResponse operations from ShippingCarrier instances
33
+ - Handles both added and removed shipping methods
34
+ - Creates proper operation structures for Adobe Commerce webhook extensibility
35
+
36
+ #### 🔧 Framework Components
37
+
38
+ - **WebhookAction** `[New]` - Secure webhook request handler with signature verification
39
+ - Built-in Adobe Commerce webhook signature verification
40
+ - Configurable signature verification (enabled/disabled)
41
+ - Wrapper around RuntimeAction for consistent request handling
42
+ - Support for required parameters and headers validation
43
+ - Integration with WebhookActionResponse for structured responses
44
+ - Comprehensive error handling and logging
45
+
46
+ - **WebhookActionResponse** `[New]` - Structured webhook response builder
47
+ - Success, exception, add, replace, and remove operations
48
+ - Type-safe response structures with TypeScript interfaces
49
+ - Compatible with Adobe Commerce webhook extensibility model
50
+ - Clean API for building complex webhook responses
51
+
52
+ #### 🛠️ Repository Components
53
+
54
+ - **FileRepository** `[Enhanced]` - File system timestamp integration
55
+ - Use file system properties for `createdAt` and `updatedAt` timestamps
56
+ - Retrieve timestamps using `files.getProperties()` method
57
+ - Timestamps reflect actual file system state
58
+ - Removed timestamps from file content for cleaner data storage
59
+ - Enhanced `metadata()` method for lightweight file listing without content
60
+
61
+ - **FileRepository** `[Enhanced]` - Metadata method for efficient file listing
62
+ - New `metadata()` method for retrieving file properties without reading content
63
+ - Significantly faster than `list()` for large file sets
64
+ - Returns file size, creation time, and modification time
65
+ - Supports both single file and batch metadata retrieval
66
+
67
+ - **FileRepository** `[Enhanced]` - Overwrite flag for controlled file writes
68
+ - New `overwrite` parameter in `save()` method
69
+ - Default behavior: merge with existing file (overwrite: false)
70
+ - Explicit overwrite: replace entire file (overwrite: true)
71
+ - Enhanced control over file update strategies
72
+
73
+ ## [1.0.3] - 2025-10-23
74
+
75
+ ### 🎨 New Experience Module & Enhanced Framework Components
76
+
77
+ This patch release introduces a comprehensive new Experience module with AdminUiSdk for Adobe Commerce Admin UI extensions, enhanced IMS token caching with State library integration, Adobe I/O event publishing capabilities with CloudEvents compliance, and critical bug fixes for authentication endpoints. All changes maintain backward compatibility while adding powerful new functionality.
78
+
79
+ #### 🎨 Experience Components
80
+
81
+ - **AdminUiSdk** `[New]` - Adobe Commerce Admin UI extension management
82
+ - Create and manage menu items, sections, and page configurations programmatically
83
+ - Full namespaced ID support (e.g., `dataMappingTool::appBuilderApplication`)
84
+ - Parent-child menu relationships with external references (`Magento_Backend::system`)
85
+ - Comprehensive validation and error handling with detailed error messages
86
+ - Type-safe TypeScript interfaces for MenuItem, Page, and AdminUiSdkRegistration
87
+ - **BREAKING CHANGE**: Accepts full IDs without automatic prefixing for real-world usage patterns
88
+
89
+ #### 🔧 Framework Components
90
+
91
+ - **CustomLogger** `[New]` - Centralized null-safe logging utility
92
+ - Consistent logging interface with debug, info, and error methods across all components
93
+ - Graceful handling of missing or null logger instances without throwing errors
94
+ - Seamless integration with Adobe I/O Runtime logger
95
+
96
+ - **PublishEvent** `[New]` - Adobe I/O Event Publishing with CloudEvents compliance
97
+ - CloudEvents specification compliance with proper event structure
98
+ - UUID generation for unique event tracking and correlation
99
+ - Comprehensive validation for IMS organization ID, API keys, and access tokens
100
+ - Integration with CustomLogger for consistent error handling and debugging
101
+ - Support for custom event subjects and structured payload data
102
+
103
+ #### 🛠️ Commerce Components
104
+
105
+ - **GenerateImsToken** `[Enhanced]` - IMS token caching using Adobe I/O State library
106
+ - Automatic token caching and refresh using Adobe I/O State library for performance optimization
107
+ - Token validation and automatic renewal before expiration
108
+ - Enhanced error handling and logging for token operations
109
+ - **BREAKING CHANGE**: ImsConnection constructor simplified - no longer requires currentContext parameter
110
+
111
+ #### 🐛 Critical Bug Fixes
112
+
113
+ - **BasicAuthConnection Token Endpoint Construction** `[Resolved]`
114
+ - **Problem**: Duplicate `/rest/rest/` segments in token endpoints for base URLs ending with '/rest'
115
+ - **Root Cause**: Improper URL concatenation when base URL already contained REST endpoint path
116
+ - **Solution**: Enhanced createTokenEndpoint() method with intelligent URL parsing and construction
117
+ - **Impact**: Correct token endpoint generation for all base URL formats, maintaining backward compatibility
118
+
8
119
  ## [1.0.2] - 2025-09-30
9
120
 
10
121
  ### 🛠️ Framework Component Enhancements & Critical Bug Fixes
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- A comprehensive TypeScript toolkit for Adobe App Builder applications providing standardized Adobe Commerce integrations, I/O Events orchestration, file storage utilities, authentication helpers, and robust backend development tools with 100% test coverage.
5
+ A comprehensive TypeScript toolkit for Adobe App Builder applications providing standardized Adobe Commerce integrations, I/O Events orchestration, file storage utilities, authentication helpers, and robust backend development tools with 100% test coverage and enterprise-grade reliability.
6
6
 
7
7
  ## Installation
8
8
 
@@ -12,7 +12,7 @@ npm install @adobe-commerce/aio-toolkit
12
12
 
13
13
  ## Usage
14
14
 
15
- The toolkit is organized into four main modules:
15
+ The toolkit is organized into five main modules:
16
16
 
17
17
  ### 🛠️ Framework Components
18
18
 
@@ -91,6 +91,112 @@ const myEventConsumer = EventConsumerAction.execute(
91
91
  exports.main = myEventConsumer;
92
92
  ```
93
93
 
94
+ #### `WebhookAction`
95
+ Secure webhook request handler with built-in Adobe Commerce signature verification.
96
+
97
+ ```typescript
98
+ const {
99
+ WebhookAction,
100
+ WebhookActionResponse,
101
+ SignatureVerification
102
+ } = require('@adobe-commerce/aio-toolkit');
103
+
104
+ // Create a webhook action with signature verification enabled
105
+ const myWebhook = WebhookAction.execute(
106
+ 'order-webhook',
107
+ ['orderId'], // Required parameters
108
+ ['x-adobe-commerce-webhook-id'], // Required headers
109
+ SignatureVerification.ENABLED, // Enable signature verification
110
+ async (params, ctx) => {
111
+ const { orderId } = params;
112
+ const { logger } = ctx;
113
+
114
+ logger.info(`Processing order webhook: ${orderId}`);
115
+
116
+ // Your webhook logic here
117
+ // Return structured webhook response
118
+ return [
119
+ WebhookActionResponse.add('result', {
120
+ orderId: orderId,
121
+ status: 'processed',
122
+ timestamp: new Date().toISOString()
123
+ }),
124
+ WebhookActionResponse.success()
125
+ ];
126
+ }
127
+ );
128
+
129
+ // Export for Adobe I/O Runtime
130
+ exports.main = myWebhook;
131
+
132
+ // Disable signature verification for testing
133
+ const testWebhook = WebhookAction.execute(
134
+ 'test-webhook',
135
+ ['data'],
136
+ [],
137
+ SignatureVerification.DISABLED,
138
+ async (params, ctx) => {
139
+ return WebhookActionResponse.success();
140
+ }
141
+ );
142
+ ```
143
+
144
+ **WebhookActionResponse Operations:**
145
+ - `success()`: Indicates successful webhook processing
146
+ - `exception(message?, exceptionClass?)`: Returns error response
147
+ - `add(path, value, instance?)`: Adds data to response
148
+ - `replace(path, value, instance?)`: Replaces data in response
149
+ - `remove(path)`: Removes data from response
150
+
151
+ #### `PublishEvent`
152
+ Event publishing component for Adobe I/O Events with CloudEvents support.
153
+
154
+ ```typescript
155
+ const { PublishEvent } = require('@adobe-commerce/aio-toolkit');
156
+
157
+ // Initialize the publisher
158
+ const publishEvent = new PublishEvent(
159
+ 'your-ims-org-id@AdobeOrg',
160
+ 'your-api-key',
161
+ 'your-access-token',
162
+ logger // Optional custom logger
163
+ );
164
+
165
+ // Publish a simple event
166
+ const result = await publishEvent.execute(
167
+ 'your-provider-id',
168
+ 'commerce.order.created',
169
+ {
170
+ orderId: 'ORD-123456',
171
+ customerId: 'CUST-789',
172
+ amount: 199.99,
173
+ currency: 'USD'
174
+ }
175
+ );
176
+
177
+ console.log(`Event published: ${result.eventId}, Status: ${result.status}`);
178
+
179
+ // Publish an event with subject
180
+ const orderResult = await publishEvent.execute(
181
+ 'commerce-provider',
182
+ 'com.adobe.commerce.order.shipped',
183
+ {
184
+ orderId: 'ORD-123456',
185
+ trackingNumber: 'TRK-789',
186
+ carrier: 'UPS',
187
+ estimatedDelivery: '2023-12-05T18:00:00Z'
188
+ },
189
+ 'orders/ORD-123456'
190
+ );
191
+
192
+ // Handle publishing results
193
+ if (orderResult.status === 'published') {
194
+ console.log(`Order shipped event published successfully: ${orderResult.eventId}`);
195
+ } else {
196
+ console.error(`Failed to publish event: ${orderResult.error}`);
197
+ }
198
+ ```
199
+
94
200
  #### `GraphQlAction`
95
201
  GraphQL server implementation with schema validation and introspection control.
96
202
 
@@ -180,11 +286,17 @@ exports.main = helloWorldAction;
180
286
  File-based storage with CRUD operations for Adobe I/O Runtime applications.
181
287
 
182
288
  **Key Methods:**
183
- - `save(payload, id?)`: Saves data with optional ID parameter. The `id` parameter takes precedence over `payload.id`. IDs are automatically sanitized to alphanumeric + underscore characters.
184
- - `load(id)`: Loads data by ID
185
- - `list()`: Lists all stored records
289
+ - `save(payload, id?, overwrite?)`: Saves data with optional ID parameter and overwrite flag. The `id` parameter takes precedence over `payload.id`. IDs are automatically sanitized to alphanumeric + underscore characters. Set `overwrite: true` to replace entire file, or `false` (default) to merge with existing data.
290
+ - `load(id)`: Loads data by ID with file system timestamps (`createdAt`, `updatedAt`)
291
+ - `list()`: Lists all stored records with file system timestamps
292
+ - `metadata(id?)`: Retrieves file metadata (size, timestamps) without reading content - faster than `list()` for large datasets
186
293
  - `delete(ids)`: Deletes records by ID array
187
294
 
295
+ **New in v1.0.4:**
296
+ - **File System Timestamps**: `createdAt` and `updatedAt` are now retrieved from actual file system properties instead of being stored in file content
297
+ - **Metadata Method**: New `metadata()` method for efficient file property retrieval without reading file content
298
+ - **Overwrite Flag**: Control file update strategy with `save(payload, id, overwrite)` - merge (default) or replace entire file
299
+
188
300
  **Best Practice:** Create custom repository classes that extend FileRepository for specific entities.
189
301
 
190
302
  ##### **1. Define Entity Repository**
@@ -283,7 +395,69 @@ exports.main = RuntimeAction.execute(
283
395
  );
284
396
  ```
285
397
 
286
- ##### **5. Delete Action**
398
+ ##### **5. Save with Overwrite Flag**
399
+ Control file update strategy with the overwrite parameter:
400
+
401
+ ```javascript
402
+ const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
403
+ const EntityRepository = require("@lib/EntityRepository");
404
+
405
+ exports.main = RuntimeAction.execute(
406
+ "entity-save-overwrite",
407
+ [HttpMethod.POST],
408
+ ['name', 'status'],
409
+ ['Authorization'],
410
+ async (params) => {
411
+ const entityRepository = new EntityRepository();
412
+
413
+ const payload = {
414
+ name: params.name,
415
+ status: params.status
416
+ };
417
+
418
+ // Replace entire file instead of merging
419
+ const savedId = await entityRepository.save(payload, params.id, true);
420
+
421
+ return RuntimeActionResponse.success({
422
+ id: savedId,
423
+ message: 'Entity replaced successfully'
424
+ });
425
+ }
426
+ );
427
+ ```
428
+
429
+ ##### **6. Metadata Action**
430
+ Retrieve file metadata without reading content (faster for large datasets):
431
+
432
+ ```javascript
433
+ const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
434
+ const EntityRepository = require("@lib/EntityRepository");
435
+
436
+ exports.main = RuntimeAction.execute(
437
+ "entity-metadata",
438
+ [HttpMethod.POST],
439
+ [],
440
+ ['Authorization'],
441
+ async (params) => {
442
+ const entityRepository = new EntityRepository();
443
+
444
+ // Get metadata for all files
445
+ const allMetadata = await entityRepository.metadata();
446
+
447
+ // Or get metadata for specific file
448
+ const singleMetadata = params.id
449
+ ? await entityRepository.metadata(params.id)
450
+ : null;
451
+
452
+ return RuntimeActionResponse.success({
453
+ all: allMetadata,
454
+ single: singleMetadata
455
+ });
456
+ }
457
+ );
458
+ ```
459
+
460
+ ##### **7. Delete Action**
287
461
  Delete entities by providing an array of IDs:
288
462
 
289
463
  ```javascript
@@ -336,24 +510,188 @@ console.log('Authentication token:', token);
336
510
  #### `AdobeCommerceClient`
337
511
  HTTP client for Adobe Commerce API integration with multiple authentication methods.
338
512
 
513
+ **OAuth 1.0a Authentication**
339
514
  ```typescript
340
- const { AdobeCommerceClient } = require('@adobe-commerce/aio-toolkit');
341
- const { Oauth1aConnection } = require('@adobe-commerce/aio-toolkit');
515
+ const { AdobeCommerceClient, Oauth1aConnection } = require('@adobe-commerce/aio-toolkit');
342
516
 
343
517
  const connection = new Oauth1aConnection(
344
518
  'consumer-key',
345
519
  'consumer-secret',
346
520
  'access-token',
347
521
  'access-token-secret',
348
- logger? // Optional custom logger
522
+ logger // Optional custom logger
349
523
  );
350
524
 
351
525
  // Create client
526
+ const client = new AdobeCommerceClient('https://your-commerce-store.com/rest', connection);
527
+
528
+ // Make API calls
529
+ const products = await client.get('V1/products');
530
+ const newProduct = await client.post('V1/products', {}, productData);
531
+ ```
532
+
533
+ **IMS (Identity Management System) Authentication**
534
+ ```typescript
535
+ const { AdobeCommerceClient, ImsConnection } = require('@adobe-commerce/aio-toolkit');
536
+
537
+ const connection = new ImsConnection(
538
+ 'client-id',
539
+ 'client-secret',
540
+ 'technical-account-id',
541
+ 'technical-account-email',
542
+ 'ims-org-id',
543
+ ['AdobeID', 'openid', 'adobeio_api'], // Scopes array
544
+ logger // Optional custom logger
545
+ );
546
+
547
+ // Create client with IMS authentication
352
548
  const client = new AdobeCommerceClient('https://your-commerce-store.com', connection);
353
549
 
550
+ // Make API calls - tokens are automatically cached and refreshed
551
+ const products = await client.get('V1/products');
552
+ const newProduct = await client.post('V1/products', {}, productData);
553
+ ```
554
+
555
+ **Enhanced IMS Token Caching**
556
+
557
+ ```typescript
558
+ const { GenerateImsToken } = require('@adobe-commerce/aio-toolkit');
559
+
560
+ const tokenGenerator = new GenerateImsToken(
561
+ 'client-id', 'client-secret', 'technical-account-id',
562
+ 'technical-account-email', 'ims-org-id',
563
+ ['AdobeID', 'openid', 'adobeio_api'], logger
564
+ );
565
+
566
+ const token = await tokenGenerator.execute();
567
+ ```
568
+
569
+ **Basic Authentication**
570
+ ```typescript
571
+ const { AdobeCommerceClient, BasicAuthConnection } = require('@adobe-commerce/aio-toolkit');
572
+
573
+ const connection = new BasicAuthConnection(
574
+ 'username',
575
+ 'password',
576
+ logger // Optional custom logger
577
+ );
578
+
579
+ // Create client
580
+ const client = new AdobeCommerceClient('https://your-commerce-store.com/rest', connection);
581
+
354
582
  // Make API calls
355
- const products = await client.get('rest/V1/products');
356
- const newProduct = await client.post('rest/V1/products', {}, productData);
583
+ const products = await client.get('V1/products');
584
+ ```
585
+
586
+ #### `ShippingCarrier`
587
+ Fluent builder for creating custom shipping carriers for Adobe Commerce webhook extensibility.
588
+
589
+ ```typescript
590
+ const {
591
+ ShippingCarrier,
592
+ ShippingCarrierResponse
593
+ } = require('@adobe-commerce/aio-toolkit');
594
+
595
+ // Create a custom shipping carrier with methods
596
+ const carrier = new ShippingCarrier('fedex', (carrier) => {
597
+ carrier
598
+ .setTitle('FedEx Express')
599
+ .setStores(['default', 'store1'])
600
+ .setCountries(['US', 'CA', 'MX'])
601
+ .setSortOrder(10)
602
+ .setActive(true)
603
+ .setTrackingAvailable(true)
604
+ .setShippingLabelsAvailable(true)
605
+ .addMethod('standard', (method) => {
606
+ method
607
+ .setMethodTitle('Standard Shipping')
608
+ .setPrice(9.99)
609
+ .setCost(5.00)
610
+ .addAdditionalData('delivery_time', '3-5 business days')
611
+ .addAdditionalData('tracking_available', true);
612
+ })
613
+ .addMethod('express', (method) => {
614
+ method
615
+ .setMethodTitle('Express Shipping')
616
+ .setPrice(19.99)
617
+ .setCost(12.00)
618
+ .addAdditionalData('delivery_time', '1-2 business days');
619
+ })
620
+ .removeMethod('overnight'); // Remove a method
621
+ });
622
+
623
+ // Get carrier configuration
624
+ const carrierData = carrier.getData();
625
+ console.log(carrierData);
626
+
627
+ // Generate webhook response operations
628
+ const response = new ShippingCarrierResponse(carrier);
629
+ const operations = response.generate();
630
+ return operations; // Use in webhook action
631
+
632
+ carrier.setData({
633
+ code: 'dps',
634
+ title: 'Demo Postal Service',
635
+ stores: ['default'],
636
+ countries: ['US', 'CA'],
637
+ sort_order: 10,
638
+ active: true,
639
+ tracking_available: true,
640
+ shipping_labels_available: true
641
+ });
642
+
643
+ // Reset carrier with new code
644
+ carrier.reset('ups', (c) => {
645
+ c.addMethod('ground', (m) => {
646
+ m.setMethodTitle('UPS Ground').setPrice(12.99);
647
+ });
648
+ });
649
+ ```
650
+
651
+ **Key Features:**
652
+ - Builder pattern with method chaining
653
+ - Validation for carrier and method codes (alphanumeric and underscores only)
654
+ - Add and remove shipping methods dynamically
655
+ - Configure carrier properties (title, stores, countries, sort order, etc.)
656
+ - Generate webhook response operations
657
+ - Type-safe TypeScript interfaces
658
+
659
+ **Validation Rules:**
660
+ - Carrier and method codes must contain only alphanumeric characters and underscores
661
+ - No spaces, hyphens, dots, or special characters allowed
662
+ - Empty or whitespace-only codes throw errors
663
+
664
+ ### 🎨 Experience Components
665
+
666
+ **Adobe Commerce Admin UI extension and user experience tools**
667
+
668
+ #### `AdminUiSdk`
669
+ Create and manage Adobe Commerce Admin UI extensions with menu items, sections, and page configurations.
670
+
671
+ ```typescript
672
+ const { AdminUiSdk } = require('@adobe-commerce/aio-toolkit');
673
+
674
+ const sdk = new AdminUiSdk('dataMappingTool');
675
+
676
+ // Add menu section with external parent
677
+ sdk.addMenuSection(
678
+ 'dataMappingTool::checkout_integration',
679
+ 'Checkout Integration',
680
+ 100,
681
+ 'Magento_Backend::system'
682
+ );
683
+
684
+ // Add menu item
685
+ sdk.addMenuItem(
686
+ 'dataMappingTool::application',
687
+ 'Application',
688
+ 1,
689
+ 'dataMappingTool::checkout_integration'
690
+ );
691
+
692
+ // Set page title and get registration
693
+ sdk.addPage('Data Mapping Tool Dashboard');
694
+ const registration = sdk.getRegistration();
357
695
  ```
358
696
 
359
697
  ### 🔗 Integration Components