█████ ██████╗ ███████╗███╗ ██╗ ██████╗██╗ ██╗
██╔══██╗██╔════╝ ██╔════╝████╗ ██║██╔════╝╚██╗ ██╔╝
███████║██║ ███╗█████╗ ██╔██╗ ██║██║ ███╗╚████╔╝
██╔══██║██║ ██║██╔══╝ ██║╚██╗██║██║ ██║ ╚██╔╝
██║ ██║╚██████╔╝███████╗██║ ╚████║╚██████╔╝ ██║
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝
The Agency to Brand solution is an active proof of concept being developed using Adobe App Builder. It’s designed to connect asset workflows between agencies and brand-owned AEM environments in a secure and auditable way—without requiring direct access to the brand’s systems. This POC establishes a repeatable pattern that can be shared with agencies and partners to build their own Agency-to-Brand extension using Adobe App Builder and distributing on Adobe Exchange.
- Node.js = 22
- Adobe I/O CLI (
aio) - Adobe Developer Console access
- Clone the repository
- Install dependencies:
npm install
- Populate the
.envfile in the project root and fill it as shown below - Start the development server:
npm run run:application
- Actions only (Node/OpenWhisk):
aio app run -e application --no-serve
- Web only (Experience Cloud Shell):
aio app run -e dx/excshell/1 --no-actions
- You must choose one
-eextension when running.
-
Project layout:
src/actions/**Node 22 OpenWhisk actions (TypeScript)src/dx-excshell-1/web-src/**JAMstack web app (React + React Spectrum)docs/**all documentation (Cursor-generated notes indocs/cursor/).cursor/rules/**repository automation rules
-
TypeScript configuration:
tsconfig.base.json: shared strict, interop, resolutiontsconfig.actions.json(Node/CommonJS):module: CommonJS,target/lib: ES2020,types: ["node"],allowJs: true- consumed by actions build; do not move compilerOptions back into the loader
tsconfig.web.json(browser/ESNext):module: ESNext,lib: ["ES2020","DOM","DOM.Iterable"],jsx: react-jsx
-
Actions webpack:
webpack-config.jsusests-loaderwithoptions.configFile = tsconfig.actions.jsonDefinePluginis limited toAIO_*envs; secrets are not baked into bundles- Runtime inputs come from
app.config.yaml
-
Module interop:
- With
esModuleInteropenabled, import CommonJS libs with default import:import aioLogger from '@adobe/aio-lib-core-logging'
- With
-
Strict typing:
- Avoid implicit
any(e.g., type arrays:const requiredHeaders: string[] = []) - In
catch, usecatch (error: unknown)and cast as needed
- Avoid implicit
-
Actions vs Web boundaries:
- Do not import Node-only modules (
openwhisk,@adobe/aio-lib-*) fromsrc/dx-excshell-1/** - If code must be shared, place browser-safe types/models under
src/shared/**
- Do not import Node-only modules (
-
JS utilities in actions:
- JS files under
src/actions/utils/**may be imported (actions tsconfig enablesallowJs) - Prefer adding minimal
.d.tsshims when introducing new JS utils
- JS files under
-
Runtime isolation contract:
- Every action accepts
APPLICATION_RUNTIME_INFO(JSON string) - All emitted events include
data.app_runtime_infowithconsoleId,projectName,workspace,app_name,action_package_name
- Every action accepts
-
Tests:
- Store all tests under the root
test/directory
- Store all tests under the root
-
Documentation structure:
- Keep all docs under
docs/ - Cursor-generated notes/summaries live under
docs/cursor/
- Keep all docs under
This project includes comprehensive testing with automated CI/CD pipelines. For detailed testing information, see Testing and CI/CD Setup.
# Run all tests
npm test
# Run tests with Adobe I/O CLI
aio app test
# Run specific test suites
npm test -- --testPathPattern=BrandManager.test.ts- ✅ All tests must pass before merging to main
- ✅ Automated testing on every PR
- ✅ Branch protection rules enforced
- ✅ Security scans prevent vulnerabilities
aio app deployto build and deploy all actions on Runtime and static files to CDNaio app undeployto undeploy the app
This project uses several key Adobe and React libraries:
- @adobe/aio-sdk
- @adobe/exc-app
- @adobe/react-spectrum
- React 16.13.1
- TypeScript
- Jest for testing
You can generate the .env file using the command aio app use.
# This file must **not** be committed to source control
# Adobe I/O Runtime
AIO_RUNTIME_AUTH=
AIO_RUNTIME_NAMESPACE=
AIO_app_name=
# Adobe I/O Events
AIO_AGENCY_EVENTS_REGISTRATION_PROVIDER_ID=
AIO_AGENCY_EVENTS_AEM_ASSET_SYNC_PROVIDER_ID=
# Adobe Internal Calls
ADOBE_INTERNAL_URL_ENDPOINT=
# AEM Authentication
AEM_AUTH_CLIENT_SECRET=
AEM_AUTH_SCOPES=
AEM_AUTH_CLIENT_ID=
AEM_AUTH_TECH_ACCOUNT_ID=
AEM_AUTH_PRIVATE_KEY=
AEM_AUTH_TYPE=
# Service-to-Service Authentication
S2S_API_KEY=
S2S_CLIENT_SECRET=
S2S_SCOPES=
# Organization
ORG_ID=To run this application, you need to configure several environment variables with values from your Adobe Developer Console and AEM Cloud Service settings.
Update these variables with values from your Adobe Developer Console project:
# Organization ID from your Adobe Developer Console
ORG_ID=your-org-id@AdobeOrg
# Service Account (JWT) credentials from your project
S2S_API_KEY=your-service-account-api-key
S2S_CLIENT_ID=your-service-account-client-id
S2S_CLIENT_SECRET=your-service-account-client-secret
S2S_SCOPES=["AdobeID","openid","read_organizations","additional_info.projectedProductContext","additional_info.roles","adobeio_api","read_client_secret","manage_client_secrets"]Set these to your own target values:
# Your agency name (used for events and identification)
AGENCY_NAME=Your Agency Name
# Generate a UUID for your agency (use a UUID generator)
AGENCY_ID=12345678-1234-1234-1234-123456789abc
# Your application name (should match your Adobe Developer Console project)
AIO_app_name=your-app-name
# Adobe Internal Calls Configuration
# Endpoint for getting presigned read URLs from Adobe internal services
ADOBE_INTERNAL_URL_ENDPOINT=https://27200-609silverstork-stage.adobeioruntime.net/api/v1/web/a2b-agencyThese values come from your AEM Cloud Service Developer Console:
# AEM JWT Integration credentials
AEM_AUTH_CLIENT_ID=your-aem-client-id
AEM_AUTH_TECH_ACCOUNT_ID=your-aem-tech-account-id@techacct.adobe.com
AEM_AUTH_CLIENT_SECRET=your-aem-client-secret
AEM_AUTH_SCOPES=ent_aem_cloud_api
AEM_AUTH_TYPE=jwtThe AEM_AUTH_PRIVATE_KEY requires special handling:
- Download the JWT token from your AEM Developer Console
- Remove the last
\r\nfrom the key - Replace all other
\r\nwith\n - Surround the entire key with double quotes
Example:
AEM_AUTH_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nFAKE\n-----END RSA PRIVATE KEY-----"These are generated when you register event providers in Adobe I/O Events. You need to find existing providers or create new ones.
Use the Adobe I/O CLI to list existing event providers:
# List all event providers in your organization
aio event provider list
# Look for providers with names like:
# - "Agency Asset Sync Events" or similar for asset sync
# - "Agency Brand Registration Events" or similar for registrationIf you don't have the required event providers, create them:
# Create asset sync event provider
aio event provider create --name "Agency Asset Sync Events" --description "Events for AEM asset synchronization"
# Create brand registration event provider
aio event provider create --name "Agency Brand Registration Events" --description "Events for brand registration workflows"After finding or creating the providers, update these variables with the provider UUIDs:
# Registration events provider ID (from aio event provider list)
AIO_AGENCY_EVENTS_REGISTRATION_PROVIDER_ID=your-registration-provider-uuid
# Asset sync events provider ID (from aio event provider list)
AIO_AGENCY_EVENTS_AEM_ASSET_SYNC_PROVIDER_ID=your-asset-sync-provider-uuidNote: The provider UUIDs are required for the application to publish events. If you don't have these set up, the application will fail to publish events.
- Adobe Developer Console project created
- Server to Server Account credentials configured
- AEM Cloud Service JWT integration set up
- JWT private key properly formatted
- Event providers checked with
aio event provider list - Event providers created if needed with
aio event provider create - Event provider UUIDs copied to environment variables
- All environment variables populated
- Application deployed with
aio app deploy
The application can integrate with Adobe internal services to retrieve presigned URLs for assets. This is configured through the ADOBE_INTERNAL_URL_ENDPOINT environment variable.
# Adobe Internal Calls Configuration
# Endpoint for getting presigned read URLs from Adobe internal services
ADOBE_INTERNAL_URL_ENDPOINT=https://27200-609silverstork-stage.adobeioruntime.net/api/v1/web/a2b-agencyNote: This endpoint is used by the agency-assetsync-internal-handler action to retrieve presigned URLs when processing asset sync events. The endpoint should be configured to point to your Adobe internal service that provides presigned URLs for AEM assets.
The application implements a sophisticated runtime environment isolation system to prevent cross-contamination of events between different development environments. This is crucial when multiple developers are working simultaneously on the same IMS organization.
-
Runtime Information Injection: Every action receives an
APPLICATION_RUNTIME_INFOparameter containing:{ "namespace": "your-runtime-namespace", "app_name": "your-app-name" } -
Event Enrichment: All events published by the EventManager are automatically enriched with
app_runtime_infoin their data payload:{ "app_runtime_info": { "consoleId": "12345", "projectName": "a2b", "workspace": "benge", "app_name": "a2b-agency" } } -
Namespace Parsing: The runtime namespace is parsed into three components:
consoleId: The Adobe Developer Console ID (first part of namespace)projectName: The project name (second part of namespace)workspace: The workspace identifier (remaining parts)
- Event Isolation: Events from different development environments can be filtered based on
app_runtime_info - Debugging Clarity: Developers can easily identify which environment generated specific events
- Multi-Developer Support: Multiple developers can work simultaneously without interference
- Environment Tracking: Clear visibility into which runtime environment is processing events
The isolation system is implemented through:
- EventManager: Automatically adds
app_runtime_infoto all published events - IoCustomEventManager: Parses namespace and enriches event data
- Action Configuration: All actions receive
APPLICATION_RUNTIME_INFOparameter - Event Filtering: Consumers can filter events based on runtime information
This architecture ensures that when multiple developers deploy their own instances of the application, each instance will only process events from its own runtime environment, eliminating confusion and cross-contamination issues.
benge app project in TMD dev org: 27200-brand2agency-stage
title: brand to agency.
├── src/ # Source code
│ ├── actions/ # Adobe I/O Runtime actions
│ │ ├── assetsync-event-handler/ # Asset sync event handling
│ │ ├── get-brands/ # Brand retrieval functionality
│ │ ├── new-brand-registration/ # Brand registration handling
│ │ ├── classes/ # Shared classes
│ │ ├── types/ # TypeScript type definitions
│ │ ├── utils/ # Utility functions
│ │ └── constants.ts # Shared constants
│ └── dx-excshell-1/ # Experience Cloud Shell configuration
│ ├── web-src/ # Web application source
│ ├── test/ # Unit tests
│ ├── e2e/ # End-to-end tests
│ └── ext.config.yaml # Extension configuration
├── test/ # Test files
├── docs/ # Documentation
├── setup/ # Setup scripts
└── dist/ # Build output
The application exposes the following endpoints:
GET /api/v1/web/a2b-agency/get-brands- Retrieve list of brandsPOST /api/v1/web/a2b-agency/new-brand-registration- Register a new brandPOST /api/v1/web/a2b-agency/assetsync-event-handler- Handle asset sync events
For more information, visit the Unified Shell API documentation.
- Create event provider:
aio event provider createLabel: "a2b Brand Registration Event Provider"
- Create event metadata:
aio event eventmetadata create <id>- a2b Brand Registration Received
- Label: "a2b Brand Registration Received"
- Code:
com.adobe.a2b.registration.received - Description: "This contains an echo of event that was received from remote brand"
{
"specversion": "1.0",
"id": "20daaf84-c938-48e6-815c-3d3dfcf8c900",
"source": "urn:uuid:fefcd900-66b6-4a46-9494-1b9ff1c5d0ac",
"type": "com.adobe.a2b.registration.received",
"datacontenttype": "application/json",
"time": "2025-06-08T05:44:51.686Z",
"eventid": "591c4e47-6ba1-4599-a136-5ccb43157353",
"event_id": "591c4e47-6ba1-4599-a136-5ccb43157353",
"recipient_client_id": "4ab33463139e4f96b851589286cd46e4",
"recipientclientid": "4ab33463139e4f96b851589286cd46e4",
"data": {
"brandId": "2e59b727-4f9c-4653-a6b9-a49a602ec983",
"secret": "PFVZNkBLH9iquYvr8hGSctesInK4QlRh",
"name": "test client benge 37",
"endPointUrl": "https://pathtoendpoint/37",
"enabled": false,
"createdAt": "2025-06-08T05:44:51.219Z",
"updatedAt": "2025-06-08T05:44:51.219Z"
}
}- a2b Brand Registration Enabled
- Label: "a2b Brand Registration Enabled"
- Code:
com.adobe.a2b.registration.enabled - Description: "When an admin approves a brand registration this event is thrown"
{
"specversion": "1.0",
"id": "381691a0-a5c6-4c97-b1ac-662a06686856",
"source": "urn:uuid:fefcd900-66b6-4a46-9494-1b9ff1c5d0ac",
"type": "com.adobe.a2b.registration.enabled",
"datacontenttype": "application/json",
"time": "2025-06-08T05:39:47.227Z",
"eventid": "d72bccdb-1af0-4c01-b802-fea422383017",
"event_id": "d72bccdb-1af0-4c01-b802-fea422383017",
"recipient_client_id": "4ab33463139e4f96b851589286cd46e4",
"recipientclientid": "4ab33463139e4f96b851589286cd46e4",
"data": {
"brandId": "f94496b9-a40c-4d7a-8c4e-e59db029f247",
"secret": "Uebq3tGYkoDoxonUxQizqKFHzHG703F1",
"name": "test client benge 36",
"endPointUrl": "https://pathtoendpoint/36",
"enabled": false,
"createdAt": "2025-06-08T05:39:46.778Z",
"updatedAt": "2025-06-08T05:39:46.778Z"
}
}- a2b Brand Registration Disabled
- Label: "a2b Brand Registration Disabled"
- Code:
com.adobe.a2b.registration.disabled - Description: "When an admin disables a brand registration this event is thrown"
{
"specversion": "1.0",
"id": "706c19f6-2975-49a3-9e33-39672aed756e",
"source": "urn:uuid:fefcd900-66b6-4a46-9494-1b9ff1c5d0ac",
"type": "com.adobe.a2b.registration.disabled",
"datacontenttype": "application/json",
"time": "2025-06-08T05:42:22.333Z",
"eventid": "175cf397-6b9f-4bb9-9aaa-943d5c42333d",
"event_id": "175cf397-6b9f-4bb9-9aaa-943d5c42333d",
"recipient_client_id": "4ab33463139e4f96b851589286cd46e4",
"recipientclientid": "4ab33463139e4f96b851589286cd46e4",
"data": {
"brandId": "4e9976ab-95ea-47c1-a2e3-7e266aa47935",
"secret": "OMWwg3qNE5Mxlwye1KGXj3zYy7ORT9FC",
"name": "test client benge 36",
"endPointUrl": "https://pathtoendpoint/36",
"enabled": false,
"createdAt": "2025-06-08T05:42:21.855Z",
"updatedAt": "2025-06-08T05:42:21.855Z"
}
}The Brand Manager is a comprehensive web application for managing brand registrations and configurations within the Adobe Experience Cloud Shell environment. It provides a modern, intuitive interface for brand administrators to register, view, edit, and manage brand information.
The Brand Manager includes a powerful demo mode for development and testing:
📖 For detailed demo mode instructions, see the Demo Mode Guide
Key Features:
- Full CRUD Operations: Create, read, update, delete brands with mock data
- No Backend Required: Complete functionality without authentication or API setup
- Real-time Development: Hot reload with instant feedback
- Safe Testing: No risk of affecting production data
Quick Start:
# Enable demo mode
REACT_APP_ENABLE_DEMO_MODE=true
# Start the application
aio app run -e dx/excshell/1 --no-actions- Brand Registration: Create new brand profiles with essential information
- Brand Listing: View all registered brands in a sortable, filterable table
- Brand Editing: Update existing brand information and settings
- Brand Details: View comprehensive brand information including metadata
- Brand Deletion: Remove brands from the system with confirmation
- Logo Upload: Modern drag-and-drop file upload using React Spectrum components
- File Validation: Automatic validation of file type (images only) and size (max 5MB)
- Logo Preview: Real-time preview of uploaded logos
- Logo Display: Visual logo representation in brand listings and details
- Logo Removal: Easy removal of existing logos
- Demo Mode: Full functionality testing with mock data (no backend required)
- Responsive Design: Optimized for various screen sizes and devices
- Search & Filter: Advanced filtering by brand name, URL, and status
- Sorting: Multi-column sorting for better data organization
- Status Indicators: Visual status lights for enabled/disabled brands
- Loading States: Proper loading indicators and error handling
- BrandManagerView: Main component handling brand listing and management
- BrandForm: Form component for brand creation, editing, and viewing
- React Spectrum: Adobe's design system components for consistent UI/UX
interface IBrand {
brandId: string; // Brand ID (unique identifier)
secret: string; // Authentication secret
name: string; // Brand name
endPointUrl: string; // API endpoint URL
enabled: boolean; // Brand status
logo?: string; // Base64 encoded logo image
createdAt: Date; // Creation timestamp
updatedAt: Date; // Last update timestamp
enabledAt: Date; // Enable timestamp
}The Brand Manager includes a comprehensive demo mode that allows:
- Local Testing: Full functionality without backend dependencies
- Mock Data: Pre-populated with sample brands and logos
- State Management: In-memory data persistence during session
- CRUD Operations: Complete create, read, update, delete functionality
- Node.js and npm installed
- Adobe App Builder CLI (
aio) configured - Valid Adobe I/O Runtime credentials
-
Start the application:
cd src/dx-excshell-1 aio app run -
Access the Brand Manager:
- Navigate to the Brand Manager section in the application
- Demo mode is automatically enabled in development
-
Test Logo Upload:
- Create a new brand or edit an existing one
- Use the logo upload section to test file uploads
- Supported formats: PNG, JPG, GIF, SVG, WebP (max 5MB)
-
Deploy the application:
aio app deploy
-
Configure environment variables:
- Set
AIO_ENABLE_DEMO_MODE=falsefor production (web-only; only AIO_* vars are exposed in the bundle) - Configure backend API endpoints
- Set
The Brand Manager is designed to integrate with backend APIs for production use:
GET /get-brands- Retrieve all brandsGET /get-brand/{brandId}- Retrieve specific brandPOST /new-brand-registration- Create new brandPUT /update-brand/{brandId}- Update existing brandDELETE /delete-brand/{brandId}- Delete brand
- Logos are stored as Base64 encoded strings in the brand record
- Production implementation should include:
- File storage service integration
- Image optimization and compression
- CDN integration for fast delivery
- Backup and recovery procedures
The application uses React Spectrum components for consistent styling:
- Follow Adobe's design system guidelines
- Customize theme colors and spacing as needed
- Maintain accessibility standards
- Extend the Brand model for additional fields
- Add custom validation rules
- Implement additional file upload features
- Integrate with external services
- Logo upload fails: Check file type and size limits
- Demo mode not working: Verify environment variables
- Table not loading: Check network connectivity and API endpoints
- File validation errors: Ensure files are valid image formats
Enable debug logging by setting:
LOG_LEVEL=debugWhen contributing to the Brand Manager:
- Follow React Spectrum design patterns
- Maintain TypeScript type safety
- Include proper error handling
- Test in both demo and production modes
- Update documentation for new features
For more information about the Brand Manager implementation, see the technical documentation in the docs/ directory.
=======
Update your .env with the provider id returned by aio event provider create:
AIO_AGENCY_EVENTS_REGISTRATION_PROVIDER_ID=5c3431a2-bd91-4eff-a356-26b747d0aad4AssetSync is a comprehensive system that handles synchronization of AEM assets between Adobe Experience Manager (AEM) and brand systems. It processes asset events, validates metadata, and distributes asset data to registered brands.
📖 For detailed AssetSync implementation, configuration, and troubleshooting, see the AssetSync Detailed Guide
aio event provider createLabel: "a2b Asset Sync Event Provider"
-
New Asset Published
- Label: "a2b New Asset Published"
- Code:
com.adobe.a2b.assetsync.new - Description: "Asset that has never been synced before is coming over for the first time"
-
Asset Updated
- Label: "a2b Asset Updated"
- Code:
com.adobe.a2b.assetsync.update - Description: "Asset that has been synced before has changed"
-
Asset Deleted
- Label: "a2b Asset Deleted"
- Code:
com.adobe.a2b.assetsync.delete - Description: "Asset that has been synced before has been deleted"
Using the AEM Assets Author API, subscribe to the following events at:
https://your_adobe_developer_project.adobeioruntime.net/api/v1/web/a2b-agency/assetsync-event-handler
This is done in the Adobe Developer Console. See setup documentation
Events to subscribe to:
- Asset deleted event:
aem.assets.asset.deleted - Asset metadata updated event:
aem.assets.asset.metadata_updated
These events will be published to the BRAND and also echoed locally for secondary in-house systems use.
- Main Handler:
agency-assetsync-internal-handler - Environment Variable:
AIO_AGENCY_EVENTS_AEM_ASSET_SYNC_PROVIDER_ID - AEM Metadata Required:
a2b__sync_on_change,a2b__customers - Brand Requirements: Enabled status, valid endpoint URL
removing all your runtime actions
aio rt actions list --json | jq -r '.[] | (.namespace + "/" + .name)' | while read -r a; do [ -n "$a" ] && aio rt action delete "$a"; done
-
Authentication Issues
- Ensure all required environment variables are set
- Verify Adobe I/O credentials are valid
- Check AEM authentication configuration
-
Asset Sync Issues
- Verify AEM event subscriptions
- Check asset sync provider configuration
- Review logs for detailed error messages
- all event are cloud events see (cloud events)[https://github.com/cloudevents/spec]
- Make a branch or fork
- Follow the coding standards (ESLint configuration is provided)
- Write tests for new features that are actions. UI is nice to have but not wired
- Submit a pull request
- git pull the repo local
- go to adobe developer console and setup a workspace in org Tech Marketing Development in the project "agency to brand"
- inside your new project add the following services
- Adobe Workfront and use a server to server credential
- I/O Mangement API
- For testing reasons add in Custom Event listeners for Brand Registration
- Test registration provider events is the name
- Add Event
- Select 3rd Party Custom Events
- Select a2b Brand Registration Event Provider
- Add event subscriptions for all the listed events
- For testing reasons add in Custom Event listeners for Asset Event Provider
- Test asset events provider events is the name
- Add Event
- Select 3rd Party Custom Events
- Select a2b Brand Registration Event Provider
- Add event subscriptions for all the listed events (a2b Asset Deleted, a2b Asset Updated, a2b New Asset Published)
- Navigate back to your new workspace home
- in top right
download alland pull the json file down that has all the workspace config - install Node Version Manager nvm
- install Node version 22
nvm install 22 - set node 22 current
nvm use 22 - alias 22 to default
nvm alias default 22 - install aio cli
npm install -g @adobe/aio-cli - import the adobe developer console config to project
aio app use ~/Downloads/a2b-27200-benge.jsonor simular command to your downloaded workspace config - .env needs to be updated with values from _dot.env. Every thing in that file from
###### do not change the items in your .env above this.down goes in your new .env that was created with the aio app use command - Update any of the values needed from the values in your adobe developer console. see above in readme for help on vars
- run the application with
aio app run -e applicationornpm run run:application - Stop the running application
- verify actions were installed
aio rt actions list - you can now run the local web app if you would like to work on it
aio app run -e dx/excshell/1ornpm run run:excshell
-
Install and configure
- Node.js 20, Adobe I/O CLI (
npm i -g @adobe/aio-cli) npm installaio app use ~/Downloads/<your-console-config>.jsonto generate.env- Copy any required values from
_dot.envinto your.env
- Node.js 20, Adobe I/O CLI (
-
Run locally (choose one extension)
- Actions only:
aio app run -e application --no-serve - Web only:
aio app run -e dx/excshell/1 --no-actions(openhttps://localhost:9080)
- Actions only:
-
Coding rules (must follow)
- Use default logger import:
import aioLogger from '@adobe/aio-lib-core-logging' - Keep actions and web separate; no Node-only imports in
src/dx-excshell-1/** - TS configs are split:
tsconfig.actions.json(Node/CommonJS) andtsconfig.web.json(browser/ESNext) - Actions webpack reads
tsconfig.actions.jsonviats-loaderconfigFile - Avoid implicit
any; type arrays andcatch (error: unknown) - Put shared browser-safe types/models in
src/shared/**
- Use default logger import:
-
Docs and tests
- All docs live under
docs/; Cursor notes underdocs/cursor/ - All tests belong under the root
test/folder
- All docs live under
-
Deploy
aio app deploy
This repository uses Gitleaks for comprehensive secret detection:
# Install Gitleaks (recommended)
brew install gitleaks # macOS
# Or download from: https://github.com/gitleaks/gitleaks/releases
# Security commands
npm run security:check # Check current changes
npm run security:scan-history # Scan entire git history
npm run precommit # Full pre-commit check (security + lint + test)❌ NEVER commit real private keys or secrets!
✅ ALWAYS use this exact format for testing:
-----BEGIN RSA PRIVATE KEY-----
FAKE
-----END RSA PRIVATE KEY-----
For more details: See docs/SECURITY_GUIDELINES.md