@adobe-commerce/aio-toolkit
v1.0.8
Published
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 coverag
Downloads
1,094
Readme
@adobe-commerce/aio-toolkit
Overview
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.
Installation
npm install @adobe-commerce/aio-toolkitUsage
The toolkit is organized into five main modules:
🛠️ Framework Components
Core infrastructure for Adobe App Builder applications
RuntimeAction
HTTP request handling and business logic execution for Adobe I/O Runtime.
const {
RuntimeAction,
RuntimeActionResponse,
HttpMethod,
HttpStatus,
} = require('@adobe-commerce/aio-toolkit');
// Create a simple action
const myAction = RuntimeAction.execute(
'process-user', // Action name
[HttpMethod.POST], // Allowed HTTP methods
['userId'], // Required parameters
['authorization'], // Required headers
async (params, ctx) => {
// Your business logic here
const { userId } = params;
const { logger } = ctx;
logger.info(`Processing request for user: ${userId}`);
// Return success response
return RuntimeActionResponse.success({
message: 'Action completed successfully',
userId: userId,
});
}
);
// Export for Adobe I/O Runtime
exports.main = myAction;EventConsumerAction
Event-driven processing for Adobe I/O Events with automatic validation.
const {
EventConsumerAction,
RuntimeActionResponse,
HttpStatus
} = require('@adobe-commerce/aio-toolkit');
// Create a simple event consumer
const myEventConsumer = EventConsumerAction.execute(
'commerce-event-handler',
['eventType'], // Required parameters
['x-adobe-signature'], // Required headers
async (params, ctx) => {
const { eventType } = params;
const { logger } = ctx;
logger.info(`Processing event: ${eventType}`);
// Process the event
await processCommerceEvent(eventType, params);
// Return success response
return RuntimeActionResponse.success({
message: 'Event processed successfully',
eventType: eventType,
processedAt: new Date().toISOString()
});
}
);
// Export for Adobe I/O Runtime
exports.main = myEventConsumer;WebhookAction
Secure webhook request handler with built-in Adobe Commerce signature verification.
const {
WebhookAction,
WebhookActionResponse,
SignatureVerification
} = require('@adobe-commerce/aio-toolkit');
// Create a webhook action with signature verification enabled
const myWebhook = WebhookAction.execute(
'order-webhook',
['orderId'], // Required parameters
['x-adobe-commerce-webhook-id'], // Required headers
SignatureVerification.ENABLED, // Enable signature verification
async (params, ctx) => {
const { orderId } = params;
const { logger } = ctx;
logger.info(`Processing order webhook: ${orderId}`);
// Your webhook logic here
// Return structured webhook response
return [
WebhookActionResponse.add('result', {
orderId: orderId,
status: 'processed',
timestamp: new Date().toISOString()
}),
WebhookActionResponse.success()
];
}
);
// Export for Adobe I/O Runtime
exports.main = myWebhook;
// Disable signature verification for testing
const testWebhook = WebhookAction.execute(
'test-webhook',
['data'],
[],
SignatureVerification.DISABLED,
async (params, ctx) => {
return WebhookActionResponse.success();
}
);WebhookActionResponse Operations:
success(): Indicates successful webhook processingexception(message?, exceptionClass?): Returns error responseadd(path, value, instance?): Adds data to responsereplace(path, value, instance?): Replaces data in responseremove(path): Removes data from response
PublishEvent
Event publishing component for Adobe I/O Events with CloudEvents support.
const { PublishEvent } = require('@adobe-commerce/aio-toolkit');
// Initialize the publisher
const publishEvent = new PublishEvent(
'your-ims-org-id@AdobeOrg',
'your-api-key',
'your-access-token',
logger // Optional custom logger
);
// Publish a simple event
const result = await publishEvent.execute(
'your-provider-id',
'commerce.order.created',
{
orderId: 'ORD-123456',
customerId: 'CUST-789',
amount: 199.99,
currency: 'USD'
}
);
console.log(`Event published: ${result.eventId}, Status: ${result.status}`);
// Publish an event with subject
const orderResult = await publishEvent.execute(
'commerce-provider',
'com.adobe.commerce.order.shipped',
{
orderId: 'ORD-123456',
trackingNumber: 'TRK-789',
carrier: 'UPS',
estimatedDelivery: '2023-12-05T18:00:00Z'
},
'orders/ORD-123456'
);
// Handle publishing results
if (orderResult.status === 'published') {
console.log(`Order shipped event published successfully: ${orderResult.eventId}`);
} else {
console.error(`Failed to publish event: ${orderResult.error}`);
}GraphQlAction
GraphQL server implementation with schema validation and introspection control.
const { GraphQlAction } = require('@adobe-commerce/aio-toolkit');
const schema = `
type Query {
hello: String
user(id: ID!): User
}
type User {
id: ID!
name: String!
email: String!
}
`;
const resolvers = async ctx => {
const { logger } = ctx;
return {
hello: () => 'Hello, World!',
user: ({ id }) => {
logger.debug(`Fetching user: ${id}`);
return {
id,
name: 'John Doe',
email: '[email protected]'
};
}
};
};
// Create and export GraphQL endpoint
exports.main = GraphQlAction.execute(schema, resolvers);OpenWhisk & OpenWhiskAction
OpenWhisk client for serverless action invocation and integration. OpenWhisk action wrapper with enhanced logging and error handling.
const { OpenWhisk, OpenwhiskAction, RuntimeActionResponse } = require('@adobe-commerce/aio-toolkit');
// Invoke another action
const invokeAction = async (params) => {
try {
// Initialize OpenWhisk client
const openwhisk = new Openwhisk(params.API_HOST, params.API_AUTH)
const result = await openwhisk.execute('hello-world', {
name: 'World'
});
console.log('Action result:', result);
return result;
} catch (error) {
console.error('Action invocation failed:', error);
throw error;
}
};
// Simple action with logging
const helloWorldAction = OpenwhiskAction.execute('hello-world', async (params, ctx) => {
const { logger } = ctx;
const { name = 'World' } = params;
logger.info(`Greeting request for: ${name}`);
const message = `Hello, ${name}!`;
logger.info(`Generated greeting: ${message}`);
return RuntimeActionResponse.success({
message,
timestamp: new Date().toISOString(),
action: 'hello-world'
});
});
// Export for Adobe I/O Runtime
exports.main = helloWorldAction;RuntimeApiGatewayService
Flexible Adobe I/O Runtime API Gateway client with automatic IMS token management and authentication.
const { RuntimeApiGatewayService } = require('@adobe-commerce/aio-toolkit');
// Initialize the service
const apiGatewayService = new RuntimeApiGatewayService(
'your-client-id',
'your-client-secret',
'your-technical-account-id',
'[email protected]',
'your-ims-org-id@AdobeOrg',
['openid', 'AdobeID', 'adobeio_api'],
'your-namespace-12345',
logger // Optional custom logger
);
// GET request
const data = await apiGatewayService.get('v1/web/my-package/my-action');
console.log('Action response:', data);
// POST request with payload
const result = await apiGatewayService.post('v1/web/my-package/process', {
orderId: 'ORD-123',
action: 'process'
});
// PUT request
const updateResult = await apiGatewayService.put('v1/web/my-package/update', {
id: '123',
status: 'completed'
});
// DELETE request
const deleteResult = await apiGatewayService.delete('v1/web/my-package/remove/123');Key Features:
- Automatic IMS token generation and caching
- Built-in authentication headers
- Support for GET, POST, PUT, DELETE methods
- Flexible endpoint configuration
- Comprehensive error handling
- Integration with ImsToken for token management
- CustomLogger integration
FileRepository
File-based storage with CRUD operations for Adobe I/O Runtime applications.
Key Methods:
save(payload, id?, overwrite?): Saves data with optional ID parameter and overwrite flag. Theidparameter takes precedence overpayload.id. IDs are automatically sanitized to alphanumeric + underscore characters. Setoverwrite: trueto replace entire file, orfalse(default) to merge with existing data.load(id): Loads data by ID with file system timestamps (createdAt,updatedAt)list(): Lists all stored records with file system timestampsmetadata(id?): Retrieves file metadata (size, timestamps) without reading content - faster thanlist()for large datasetsdelete(ids): Deletes records by ID array
New in v1.0.4:
- File System Timestamps:
createdAtandupdatedAtare now retrieved from actual file system properties instead of being stored in file content - Metadata Method: New
metadata()method for efficient file property retrieval without reading file content - Overwrite Flag: Control file update strategy with
save(payload, id, overwrite)- merge (default) or replace entire file
Best Practice: Create custom repository classes that extend FileRepository for specific entities.
1. Define Entity Repository
Create a custom repository class extending FileRepository:
const { FileRepository } = require("@adobe-commerce/aio-toolkit");
class EntityRepository extends FileRepository {
/**
* @constructor
*/
constructor() {
super("/toolkit-demo/entity");
}
}
module.exports = EntityRepository;2. List Action
Retrieve all entities from the repository:
const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
const EntityRepository = require("@lib/EntityRepository");
exports.main = RuntimeAction.execute(
"entity-list",
[HttpMethod.POST],
[],
['Authorization'],
async (params) => {
const entityRepository = new EntityRepository();
return RuntimeActionResponse.success(await entityRepository.list());
}
);3. Load Action
Load a specific entity by ID:
const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
const EntityRepository = require("@lib/EntityRepository");
exports.main = RuntimeAction.execute(
"entity-load",
[HttpMethod.POST],
['id'],
['Authorization'],
async (params) => {
const entityRepository = new EntityRepository();
return RuntimeActionResponse.success(await entityRepository.load(params.id));
}
);4. Save Action
Save entity data with flexible ID handling using the new optional ID parameter:
const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
const EntityRepository = require("@lib/EntityRepository");
const requiredParams = [
"name",
"status"
];
exports.main = RuntimeAction.execute(
"entity-save",
[HttpMethod.POST],
requiredParams,
['Authorization'],
async (params) => {
const entityRepository = new EntityRepository();
// Build payload with required fields
let payload = {};
for (const fieldName in requiredParams) {
payload[requiredParams[fieldName]] = params[requiredParams[fieldName]];
}
// Extract ID parameter for prioritized handling
const explicitId = params.id || params.customId || null;
// Save with optional ID parameter - it takes precedence over payload.id
const savedId = await entityRepository.save(payload, explicitId);
return RuntimeActionResponse.success({
id: savedId,
message: 'Entity saved successfully'
});
}
);5. Save with Overwrite Flag
Control file update strategy with the overwrite parameter:
const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
const EntityRepository = require("@lib/EntityRepository");
exports.main = RuntimeAction.execute(
"entity-save-overwrite",
[HttpMethod.POST],
['name', 'status'],
['Authorization'],
async (params) => {
const entityRepository = new EntityRepository();
const payload = {
name: params.name,
status: params.status
};
// Replace entire file instead of merging
const savedId = await entityRepository.save(payload, params.id, true);
return RuntimeActionResponse.success({
id: savedId,
message: 'Entity replaced successfully'
});
}
);6. Metadata Action
Retrieve file metadata without reading content (faster for large datasets):
const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
const EntityRepository = require("@lib/EntityRepository");
exports.main = RuntimeAction.execute(
"entity-metadata",
[HttpMethod.POST],
[],
['Authorization'],
async (params) => {
const entityRepository = new EntityRepository();
// Get metadata for all files
const allMetadata = await entityRepository.metadata();
// Or get metadata for specific file
const singleMetadata = params.id
? await entityRepository.metadata(params.id)
: null;
return RuntimeActionResponse.success({
all: allMetadata,
single: singleMetadata
});
}
);7. Delete Action
Delete entities by providing an array of IDs:
const { HttpMethod, RuntimeAction, RuntimeActionResponse } = require("@adobe-commerce/aio-toolkit");
const EntityRepository = require("@lib/EntityRepository");
exports.main = RuntimeAction.execute(
"entity-delete",
[HttpMethod.POST],
['ids'],
['Authorization'],
async (params) => {
const entityRepository = new EntityRepository();
return RuntimeActionResponse.success(await entityRepository.delete(params.ids));
}
);This approach provides:
- Separation of concerns: Each CRUD operation has its own action file
- Reusable repository: Custom repository can be shared across actions
- Proper validation: Required parameters and headers are enforced
- Consistent responses: All actions use RuntimeActionResponse for standardized output
- Flexible ID management: Support for explicit IDs, payload IDs, and auto-generation
- Automatic sanitization: IDs are cleaned to ensure file system compatibility
🏪 Commerce Components
Adobe Commerce API integration and authentication
AdobeAuth
Adobe IMS authentication and token management.
const { AdobeAuth } = require('@adobe-commerce/aio-toolkit');
// Get authentication token
const token = await AdobeAuth.getToken(
'your-client-id',
'your-client-secret',
'your-technical-account-id',
'your-technical-account-email',
'your-ims-org-id',
['AdobeID', 'openid', 'adobeio_api'] // Scopes
);
console.log('Authentication token:', token);AdobeCommerceClient
HTTP client for Adobe Commerce API integration with multiple authentication methods.
OAuth 1.0a Authentication
const { AdobeCommerceClient, Oauth1aConnection } = require('@adobe-commerce/aio-toolkit');
const connection = new Oauth1aConnection(
'consumer-key',
'consumer-secret',
'access-token',
'access-token-secret',
logger // Optional custom logger
);
// Create client
const client = new AdobeCommerceClient('https://your-commerce-store.com/rest', connection);
// Make API calls
const products = await client.get('V1/products');
const newProduct = await client.post('V1/products', {}, productData);IMS (Identity Management System) Authentication
const { AdobeCommerceClient, ImsConnection } = require('@adobe-commerce/aio-toolkit');
const connection = new ImsConnection(
'client-id',
'client-secret',
'technical-account-id',
'technical-account-email',
'ims-org-id',
['AdobeID', 'openid', 'adobeio_api'], // Scopes array
logger // Optional custom logger
);
// Create client with IMS authentication
const client = new AdobeCommerceClient('https://your-commerce-store.com', connection);
// Make API calls - tokens are automatically cached and refreshed
const products = await client.get('V1/products');
const newProduct = await client.post('V1/products', {}, productData);Enhanced IMS Token Caching
const { GenerateImsToken } = require('@adobe-commerce/aio-toolkit');
const tokenGenerator = new GenerateImsToken(
'client-id', 'client-secret', 'technical-account-id',
'technical-account-email', 'ims-org-id',
['AdobeID', 'openid', 'adobeio_api'], logger
);
const token = await tokenGenerator.execute();Basic Authentication
const { AdobeCommerceClient, BasicAuthConnection } = require('@adobe-commerce/aio-toolkit');
const connection = new BasicAuthConnection(
'username',
'password',
logger // Optional custom logger
);
// Create client
const client = new AdobeCommerceClient('https://your-commerce-store.com/rest', connection);
// Make API calls
const products = await client.get('V1/products');ShippingCarrier
Fluent builder for creating custom shipping carriers for Adobe Commerce webhook extensibility.
const {
ShippingCarrier,
ShippingCarrierResponse
} = require('@adobe-commerce/aio-toolkit');
// Create a custom shipping carrier with methods
const carrier = new ShippingCarrier('fedex', (carrier) => {
carrier
.setTitle('FedEx Express')
.setStores(['default', 'store1'])
.setCountries(['US', 'CA', 'MX'])
.setSortOrder(10)
.setActive(true)
.setTrackingAvailable(true)
.setShippingLabelsAvailable(true)
.addMethod('standard', (method) => {
method
.setMethodTitle('Standard Shipping')
.setPrice(9.99)
.setCost(5.00)
.addAdditionalData('delivery_time', '3-5 business days')
.addAdditionalData('tracking_available', true);
})
.addMethod('express', (method) => {
method
.setMethodTitle('Express Shipping')
.setPrice(19.99)
.setCost(12.00)
.addAdditionalData('delivery_time', '1-2 business days');
})
.removeMethod('overnight'); // Remove a method
});
// Get carrier configuration
const carrierData = carrier.getData();
console.log(carrierData);
// Access added and removed methods
const addedMethods = carrier.getAddedMethods(); // ['standard', 'express']
const removedMethods = carrier.getRemovedMethods(); // ['overnight']
// Generate webhook response operations
const response = new ShippingCarrierResponse(carrier);
const operations = response.generate();
return operations; // Use in webhook action
// Update carrier data (code is immutable)
carrier.setData({
code: 'ups', // This will be ignored - code remains 'fedex'
title: 'Demo Postal Service',
stores: ['default'],
countries: ['US', 'CA'],
sort_order: 10,
active: true,
tracking_available: true,
shipping_labels_available: true
});
// Code property is immutable - create new instance if you need different code
const newCarrier = new ShippingCarrier('ups', (c) => {
c.addMethod('ground', (m) => {
m.setMethodTitle('UPS Ground').setPrice(12.99);
});
});Key Features:
- Builder pattern with method chaining
- Validation for carrier and method codes (alphanumeric and underscores only)
- Add and remove shipping methods dynamically
- Configure carrier properties (title, stores, countries, sort order, etc.)
- Immutable code property - prevents accidental carrier identity changes
- Public getter methods:
getAddedMethods()andgetRemovedMethods() - Generate webhook response operations
- Type-safe TypeScript interfaces
Validation Rules:
- Carrier and method codes must contain only alphanumeric characters and underscores
- No spaces, hyphens, dots, or special characters allowed
- Empty or whitespace-only codes throw errors
- Code property cannot be changed after initialization
OnboardCommerce
Complete Adobe Commerce I/O Events configuration orchestration with automated provider setup and event subscription management.
const {
OnboardCommerce,
AdobeCommerceClient,
ImsConnection
} = require('@adobe-commerce/aio-toolkit');
const Core = require('@adobe/aio-sdk').Core;
// Initialize Adobe Commerce client
const connection = new ImsConnection(
'client-id',
'client-secret',
'technical-account-id',
'technical-account-email',
'ims-org-id',
['AdobeID', 'openid', 'adobeio_api'],
logger
);
const adobeCommerceClient = new AdobeCommerceClient(
'https://your-commerce-store.com',
connection
);
// Initialize logger
const logger = Core.Logger('onboard-client', {
level: 'debug'
});
// Initialize OnboardCommerce
const onboardCommerce = new OnboardCommerce(
adobeCommerceClient,
process.env.COMMERCE_ADOBE_IO_EVENTS_MERCHANT_ID || '',
process.env.COMMERCE_ADOBE_IO_EVENTS_ENVIRONMENT_ID || '',
logger,
false // isPaaS: set to true for PaaS instances (defaults to false)
);
// Define commerce provider
const commerceProvider = {
raw: {
id: 'commerce-provider-id',
label: 'Commerce Events Provider',
description: 'Provider for Adobe Commerce events',
docsUrl: 'https://developer.adobe.com/commerce/events'
}
};
// Define workspace configuration
const workspaceConfig = {
project: {
id: process.env.ADOBE_PROJECT_ID,
name: 'My Commerce Project',
title: 'Commerce Integration'
},
workspace: {
id: process.env.ADOBE_WORKSPACE_ID,
name: 'Production'
}
};
// Define commerce events configuration
const commerceEventsConfig = [
{
event: {
name: 'com.adobe.commerce.observer.catalog_product_save_after',
label: 'Product Saved',
description: 'Triggered when a product is saved'
}
},
{
event: {
name: 'com.adobe.commerce.observer.sales_order_save_after',
label: 'Order Saved',
description: 'Triggered when an order is saved'
}
}
];
// Execute configuration
const result = await onboardCommerce.process(
commerceProvider.raw,
workspaceConfig,
commerceEventsConfig
);
if (result.success) {
console.log('✅ Commerce events configured successfully');
console.log(`Provider: ${result.provider?.label}`);
} else {
console.error('❌ Configuration failed:', result.error);
}Key Features:
- Automated provider configuration with validation
- Event subscription management with duplicate detection
- Intelligent event metadata validation against supported Commerce events
- PaaS support for Adobe Commerce Cloud instances with native event handling
- Structured logging with prefixes:
[START],[CREATE],[SKIP],[ERROR],[IMPORTANT] - Comprehensive summary reporting with event subscription statistics
- Integration with Adobe Commerce API for event discovery
- Automatic post-subscription CLI instructions for PaaS instances
- 100% test coverage
PaaS Support:
For Adobe Commerce PaaS (Platform as a Service) instances, enable PaaS mode to support native events:
// Initialize OnboardCommerce for PaaS instances
const onboardCommercePaaS = new OnboardCommerce(
adobeCommerceClient,
merchantId,
environmentId,
logger,
true // Enable PaaS mode
);
// Define native PaaS events (observer.*, plugin.*)
const paasEventsConfig = [
{
event: {
name: 'observer.catalog_product_save_after',
label: 'Product Saved',
description: 'Native observer event'
}
},
{
event: {
name: 'plugin.magento.catalog.model.product.save',
label: 'Product Save Plugin',
description: 'Native plugin event'
}
}
];
// Process PaaS events
const result = await onboardCommercePaaS.process(
commerceProvider.raw,
workspaceConfig,
paasEventsConfig
);
// PaaS mode automatically:
// - Skips supported events validation for better performance
// - Handles native events without the 'parent' field
// - Displays post-subscription Magento CLI commandsAfter successful event subscription on PaaS, the system displays:
[IMPORTANT] ⚠️ Post-Subscription Steps for PaaS:
[IMPORTANT] 1. Run: bin/magento events:generate:module to generate module after successful event subscription
[IMPORTANT] 2. Run: bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush to install the generated module🎨 Experience Components
Adobe Commerce Admin UI extension and user experience tools
AdminUiSdk
Create and manage Adobe Commerce Admin UI extensions with menu items, sections, and page configurations.
const { AdminUiSdk } = require('@adobe-commerce/aio-toolkit');
const sdk = new AdminUiSdk('dataMappingTool');
// Add menu section with external parent
sdk.addMenuSection(
'dataMappingTool::checkout_integration',
'Checkout Integration',
100,
'Magento_Backend::system'
);
// Add menu item
sdk.addMenuItem(
'dataMappingTool::application',
'Application',
1,
'dataMappingTool::checkout_integration'
);
// Set page title and get registration
sdk.addPage('Data Mapping Tool Dashboard');
const registration = sdk.getRegistration();🔗 Integration Components
External API integration and utility functions
RestClient
HTTP client for external API integration with support for various payload types.
Basic Usage
const { RestClient } = require('@adobe-commerce/aio-toolkit');
const client = new RestClient();
// GET request
const response = await client.get('https://api.example.com/data', {
'Authorization': 'Bearer token'
});JSON Payloads (default)
// POST with JSON (automatic Content-Type: application/json)
const jsonData = { name: 'Product', price: 99.99 };
const response = await client.post('https://api.example.com/products', {
'Authorization': 'Bearer token'
}, jsonData);Form-Encoded Requests
// URLSearchParams for form-encoded data (automatic Content-Type: application/x-www-form-urlencoded)
const formData = new URLSearchParams({
grant_type: 'client_credentials',
client_id: 'your-client-id',
client_secret: 'your-client-secret'
});
const tokenResponse = await client.post('https://auth.example.com/token', {
Accept: 'application/json'
}, formData);File Upload
// FormData for file uploads (Content-Type boundary handled automatically)
const uploadData = new FormData();
uploadData.append('file', fileBuffer, 'document.pdf');
uploadData.append('description', 'Important document');
const uploadResponse = await client.post('https://api.example.com/upload', {
'Authorization': 'Bearer token'
}, uploadData);Text/XML Payloads
// String payloads with custom content type
const xmlData = '<?xml version="1.0"?><order><id>123</id></order>';
const xmlResponse = await client.post('https://api.example.com/orders', {
'Authorization': 'Bearer token',
'Content-Type': 'application/xml'
}, xmlData);BearerToken
Bearer token extraction and JWT analysis utility. Supports both standard HTTP headers and OpenWhisk format for maximum portability.
Extract from Standard HTTP Headers
const { BearerToken } = require('@adobe-commerce/aio-toolkit');
const headers = { authorization: 'Bearer abc123token' };
const tokenInfo = BearerToken.extract(headers);
console.log(tokenInfo);
// Output: {
// token: 'abc123token',
// tokenLength: 11,
// isValid: true,
// expiry: '2024-01-02T12:00:00.000Z',
// timeUntilExpiry: 86400000
// }Extract from OpenWhisk Params (Backward Compatibility)
const params = { __ow_headers: { authorization: 'Bearer abc123token' } };
const owTokenInfo = BearerToken.extract(params);
console.log(owTokenInfo); // Same output format as aboveDirect Token Analysis
const directInfo = BearerToken.info('jwt-token-string');
if (directInfo.isValid) {
console.log(`Token expires at: ${directInfo.expiry}`);
console.log(`Time until expiry: ${directInfo.timeUntilExpiry}ms`);
} else {
console.log('Token is invalid or expired');
}Methods:
extract(headersOrParams)- Extracts Bearer token from headers or OpenWhisk paramsinfo(token)- Analyzes token string and returns validation/expiry details
InfiniteLoopBreaker
Detect and prevent infinite loops in event-driven applications.
const { InfiniteLoopBreaker } = require('@adobe-commerce/aio-toolkit');
// Basic infinite loop detection
const isLoop = await InfiniteLoopBreaker.isInfiniteLoop({
keyFn: 'order-processing-key',
fingerprintFn: orderData,
eventTypes: ['order.created', 'order.updated'],
event: 'order.created'
});
if (isLoop) {
console.log('Infinite loop detected, skipping processing');
return;
}
// Process the event
await processOrderEvent(orderData);
// Store fingerprint to prevent future loops
await InfiniteLoopBreaker.storeFingerPrint(
'order-processing-key',
orderData,
300 // 5 minutes TTL
);OnboardIOEvents (formerly OnboardEvents)
Complete onboarding orchestration for Adobe I/O Events (providers, metadata, and registrations).
Note:
OnboardEventsis deprecated and will be removed in v2.0.0. Please useOnboardIOEventsinstead.
const { OnboardIOEvents } = require('@adobe-commerce/aio-toolkit');
// ✅ Recommended - Use OnboardIOEvents
const onboardEvents = new OnboardIOEvents(
'My E-commerce Store',
process.env.ADOBE_CONSUMER_ID!,
process.env.ADOBE_PROJECT_ID!,
process.env.ADOBE_WORKSPACE_ID!,
process.env.ADOBE_API_KEY!,
process.env.ADOBE_ACCESS_TOKEN!
);
const basicOnboardingExample = async () => {
const input = {
providers: [
{
key: 'ecommerce-provider',
label: 'E-commerce Events Provider',
description: 'Provider for e-commerce platform events',
docsUrl: 'https://docs.mystore.com/events',
registrations: [
{
key: 'order-events',
label: 'Order Events Registration',
description: 'Registration for order-related events',
events: [
{
eventCode: 'com.mystore.order.placed',
runtimeAction: 'mystore/order-placed-handler',
deliveryType: 'webhook',
sampleEventTemplate: {
orderId: 'ord_123456',
customerId: 'cust_789',
totalAmount: 99.99,
currency: 'USD',
status: 'placed',
timestamp: '2023-01-01T12:00:00Z'
}
},
{
eventCode: 'com.mystore.order.shipped',
runtimeAction: 'mystore/order-shipped-handler',
deliveryType: 'journal',
sampleEventTemplate: {
orderId: 'ord_123456',
trackingNumber: 'TN123456789',
carrier: 'UPS',
shippedAt: '2023-01-02T10:00:00Z'
}
}
]
}
]
}
]
};
try {
const result = await onboardEvents.process(input);
console.log('Onboarding completed successfully!');
console.log(`Providers: ${result.createdProviders.length} processed`);
console.log(`Events: ${result.createdEvents.length} processed`);
console.log(`Registrations: ${result.createdRegistrations.length} processed`);
// Check results
result.createdProviders.forEach(provider => {
if (provider.created) {
console.log(`✅ Created provider: ${provider.provider.label}`);
} else if (provider.skipped) {
console.log(`⏭️ Skipped existing provider: ${provider.provider.label}`);
} else {
console.log(`❌ Failed to create provider: ${provider.error}`);
}
});
return result;
} catch (error) {
console.error('Onboarding failed:', error.message);
return null;
}
};
basicOnboardingExample();📡 I/O Events Components
Adobe I/O Events management and orchestration
EventMetadataManager
Manage event metadata for Adobe I/O Events providers.
const { EventMetadataManager } = require('@adobe-commerce/aio-toolkit');
const manager = new EventMetadataManager({
apiKey: 'your-api-key',
accessToken: 'your-access-token',
consumerId: 'your-consumer-id',
projectId: 'your-project-id',
workspaceId: 'your-workspace-id'
});
// Create event metadata
const eventMetadata = await manager.create({
providerId: 'your-provider-id',
eventCode: 'commerce.order.created',
label: 'Order Created',
description: 'Triggered when a new order is created in the commerce system',
sampleEventTemplate: {
orderId: 'ORD-123456',
customerId: 'CUST-789',
amount: 199.99,
currency: 'USD',
items: [
{
sku: 'PRODUCT-001',
name: 'Premium Widget',
quantity: 2,
price: 99.99
}
],
timestamp: '2023-12-01T10:30:00Z'
}
});
// Get event metadata
const metadata = await manager.get('your-provider-id', 'commerce.order.created');
// List all event metadata for a provider
const allMetadata = await manager.list('your-provider-id');
// Delete specific event metadata
await manager.delete('your-provider-id', 'commerce.order.created');
// Delete all event metadata for a provider
await manager.delete('your-provider-id');ProviderManager
Manage event providers for Adobe I/O Events.
const { ProviderManager } = require('@adobe-commerce/aio-toolkit');
const manager = new ProviderManager({
apiKey: 'your-api-key',
accessToken: 'your-access-token',
consumerId: 'your-consumer-id',
projectId: 'your-project-id',
workspaceId: 'your-workspace-id'
});
// Create a new provider
const provider = await manager.create({
label: 'E-commerce Events Provider',
description: 'Provides events from our e-commerce platform including orders, customers, products, and inventory updates',
docsUrl: 'https://docs.mystore.com/events-api',
providerMetadata: {
region: 'us-east-1',
environment: 'production',
version: '2.1.0'
}
});
// Get provider details
const existingProvider = await manager.get('your-provider-id', {
eventmetadata: true // Include event metadata in response
});
// List all providers
const providers = await manager.list({
eventmetadata: true, // Include event metadata
providerMetadataIds: ['provider-1', 'provider-2'] // Filter by specific providers
});
// List providers with advanced filtering
const filteredProviders = await manager.list({
instanceId: 'your-instance-id',
providerMetadataId: 'specific-provider-metadata-id'
});
// Delete provider
await manager.delete('your-provider-id');RegistrationManager
Manage event registrations and subscriptions for Adobe I/O Events.
const { RegistrationManager } = require('@adobe-commerce/aio-toolkit');
const manager = new RegistrationManager({
apiKey: 'your-api-key',
accessToken: 'your-access-token',
consumerId: 'your-consumer-id',
projectId: 'your-project-id',
workspaceId: 'your-workspace-id'
});
// Create event registration
const registration = await manager.create({
name: 'Order Processing Registration',
description: 'Handles order-related events',
delivery: {
type: 'webhook',
url: 'https://your-app.com/webhook/orders'
},
eventsOfInterest: [
{
providerId: 'your-provider-id',
eventCode: 'commerce.order.created'
},
{
providerId: 'your-provider-id',
eventCode: 'commerce.order.updated'
}
]
});
// Get registration details
const existingRegistration = await manager.get('your-registration-id');
// List all registrations
const registrations = await manager.list();
// Delete registration
await manager.delete('your-registration-id');Environment Variables
Common environment variables used across components:
# Adobe commerce credentials
COMMERCE_BASE_URL=commerce-base-url
COMMERCE_CONSUMER_KEY=commerce-consumer-key
COMMERCE_CONSUMER_SECRET=commerce-consumer-secret
COMMERCE_ACCESS_TOKEN=commerce-access-token
COMMERCE_ACCESS_TOKEN_SECRET=commerce-access-token-secret
# Environment from DIST file
OAUTH_BASE_URL=https://ims-na1.adobelogin.com/ims/token/
IO_MANAGEMENT_BASE_URL=https://api.adobe.io/events/
# OAuth configs
# The following values can be copied from the Credential details page in AppBuilder under Organization > Project > Workspace > OAuth Server-to-Server
OAUTH_CLIENT_ID=client-id
OAUTH_CLIENT_SECRET=client-secret
OAUTH_TECHNICAL_ACCOUNT_ID=technical-account-id
OAUTH_TECHNICAL_ACCOUNT_EMAIL=technical-account-email
OAUTH_ORG_ID=org-id
OAUTH_SCOPES=scopes
# OAUTH_HOST=<string>
# Workspace configs
# The following values can be copied from the JSON downloadable in AppBuilder from Organization > Project > Workspace
# IO_CONSUMER corresponds to project.org.id
# IO_PROJECT_ID corresponds to project.id
# IO_WORKSPACE_ID corresponds to project.workspace.id
IO_CONSUMER_ID=consumer-id
IO_PROJECT_ID=project-id
IO_WORKSPACE_ID=workspace-idLicense
See the LICENSE file (in package) for license rights and limitations.
