-
Notifications
You must be signed in to change notification settings - Fork 107
Description
What happened?
Express Dependency Issues in A2A-JS Library
Problem Statement
The current implementation of the a2a-js library has two significant issues related to Express.js dependency that prevent its usage in edge computing environments like Cloudflare Workers and Vercel Edge Functions.
Issues
1. 🔴 [MAJOR/BLOCKER] Hard Express Dependency in Core Exports
Current Issue:
- The main server export (
src/server/index.ts) includesA2AExpressAppwhich has a hard import of Express.js - This means Express is imported even when consumers don't intend to use the Express wrapper
- Line 22 in
src/server/index.ts:export { A2AExpressApp } from "./a2a_express_app.js"; - Line 1 in
src/server/a2a_express_app.ts:import express, { Request, Response, Express, RequestHandler, ErrorRequestHandler } from 'express';
Impact:
- ❌ Breaks compatibility with edge runtime environments (Cloudflare Workers, Vercel Edge Functions, Deno Deploy)
- ❌ Prevents usage in V8-based runtimes that don't support Node.js core APIs
- ❌ Forces Express dependency even for users who only need the core A2A protocol functionality
2. 🟡 [MINOR] Express as Direct Dependency Instead of Peer Dependency
Current Issue:
- Express is listed as a direct dependency in
package.json - Should be either a
peerDependency(if intended for existing Express projects) ordevDependency(if only for testing/examples)
Current Package.json Dependencies
"dependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.23",
"body-parser": "^2.2.0",
"cors": "^2.8.5",
"express": "^4.21.2", // ← This should not be a direct dependency
"uuid": "^11.1.0"
}Proposed Solutions
Option 1: Move Express Wrapper to Examples Directory (Recommended)
Approach:
Move A2AExpressApp completely out of the main library exports and into examples/documentation.
Implementation:
src/
├── server/
│ ├── index.ts // ← Remove A2AExpressApp export entirely
│ └── ... // ← Keep core A2A functionality only
└── examples/
└── express-integration/
├── a2a_express_app.ts
├── example-server.ts
└── README.md
Benefits:
- ✅ Zero runtime errors: No peer dependency issues
- ✅ Edge runtime compatible: Core library has no Express imports
- ✅ Clear separation: Express integration is clearly an example/pattern
- ✅ Framework agnostic: Users can adapt the pattern to any HTTP framework
- ✅ No dependency confusion: Express is only needed if you copy the example
Usage Pattern:
// Core A2A functionality (works everywhere)
import { DefaultRequestHandler, JsonRpcTransportHandler } from '@a2a-js/sdk/server';
// Users copy and adapt the Express example when needed
// No hidden dependencies or runtime surprisesOption 2: Subpath Exports with Runtime Safety (Alternative)
Moving Express to peer dependencies creates runtime errors is express is not installed separately:
# User installs the library
npm install @a2a-js/sdk
# User tries to use Express integration
import { A2AExpressApp } from '@a2a-js/sdk/server/express';
// ❌ Error: Cannot find module 'express'
// User forgot to install Express separatelyIf subpath exports are used, they need runtime safety:
// src/server/express/index.ts
let express: any;
let Express: any;
try {
const expressModule = await import('express');
express = expressModule.default;
Express = expressModule.Express;
} catch (error) {
throw new Error(
'Express is required to use A2AExpressApp. Install it with: npm install express'
);
}
export class A2AExpressApp {
// Implementation using the dynamically imported express
}But this adds complexity and still has issues:
- ❌ Runtime errors instead of install-time errors
- ❌ Dynamic imports complicate TypeScript types
- ❌ Worse developer experience
- ❌ Still breaks in edge environments that don't support dynamic imports
Why Option 1 (Examples) is Better
Current Problems with Peer Dependencies:
- Silent failures:
npm installsucceeds, runtime fails - Complex error messages: Users don't understand peer dependency warnings
- Version conflicts: Different projects might need different Express versions
- Edge runtime issues: Dynamic imports don't work in all environments
Examples Directory Advantages:
- Explicit choice: Users consciously decide to use Express integration
- No hidden dependencies: What you see is what you get
- Adaptable patterns: Users can modify for their framework (Fastify, Koa, etc.)
- Clear documentation: Example includes setup instructions
- Version freedom: Users choose their Express version
Implementation Plan
Step 1: Remove Express from Core Exports
// src/server/index.ts - Remove this line:
// export { A2AExpressApp } from "./a2a_express_app.js";Step 2: Move to Examples
examples/
└── express-integration/
├── README.md // ← Setup and usage instructions
├── a2a-express-app.ts // ← Moved from src/server/
├── basic-server.ts // ← Simple example
└── advanced-server.ts // ← With middleware, error handling
Step 3: Update Package.json
{
"dependencies": {
"@types/cors": "^2.8.17",
"cors": "^2.8.5",
"uuid": "^11.1.0"
// ← Remove Express and @types/express
},
"devDependencies": {
"express": "^4.21.2", // ← Only for examples/testing
"@types/express": "^4.17.23"
}
}Step 4: Documentation
Create comprehensive documentation showing:
- Core A2A usage (framework agnostic)
- Express integration example
- Other framework examples (Fastify, Koa, etc.)
Migration Guide for Existing Users
// Before (current)
import { A2AExpressApp } from '@a2a-js/sdk/server';
// After (copy example to your project)
// 1. Copy examples/express-integration/a2a-express-app.ts to your project
// 2. Install Express: npm install express @types/express
// 3. Import from your local copy
import { A2AExpressApp } from './utils/a2a-express-app';Benefits Summary
✅ Edge Runtime Compatible: Core library works in all environments
✅ No Runtime Surprises: No hidden peer dependencies
✅ Framework Agnostic: Examples for multiple HTTP frameworks
✅ Smaller Bundle: Core library has minimal dependencies
✅ Clear Intent: Users explicitly choose their HTTP framework integration
✅ Better Maintenance: Examples are easier to update than library code
✅ Community Contributions: Easy for community to add framework examples
Related Issues
- Addresses concerns raised in [Bug]: Cannot use other frameworks apart from express for sdk #45
- Enables usage in modern edge computing environments
- Follows Node.js best practices for minimal library dependencies
- Prevents runtime dependency errors
Priority
High Priority - This blocks adoption in the growing edge computing ecosystem and affects developer experience with unexpected runtime errors.
Relevant log output
Code of Conduct
- I agree to follow this project's Code of Conduct