npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@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-toolkit

Usage

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 processing
  • exception(message?, exceptionClass?): Returns error response
  • add(path, value, instance?): Adds data to response
  • replace(path, value, instance?): Replaces data in response
  • remove(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. 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.
  • load(id): Loads data by ID with file system timestamps (createdAt, updatedAt)
  • list(): Lists all stored records with file system timestamps
  • metadata(id?): Retrieves file metadata (size, timestamps) without reading content - faster than list() for large datasets
  • delete(ids): Deletes records by ID array

New in v1.0.4:

  • File System Timestamps: createdAt and updatedAt are 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() and getRemovedMethods()
  • 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 commands

After 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 above

Direct 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 params
  • info(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: OnboardEvents is deprecated and will be removed in v2.0.0. Please use OnboardIOEvents instead.

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-id

License

See the LICENSE file (in package) for license rights and limitations.