@echo-shadow/echo-sdk
v0.1.0
Published
ECHO Shadow Traffic SDK — send shadow test results to your ECHO dashboard
Maintainers
Readme
What is ECHO?
ECHO is a shadow traffic testing platform. It mirrors your production API traffic to a shadow (staging) environment, compares the responses, and uses AI to classify every difference as intentional (e.g. a user updated their bio) or regressive (e.g. a rounding error in checkout totals).
This SDK is the official TypeScript client for sending shadow test results to your ECHO dashboard.
Why shadow testing?
| Problem | How ECHO solves it | |---|---| | Regressions slip through staging | ECHO compares real production traffic against your shadow env | | Manual QA can't cover every edge case | 100% of traffic is compared automatically | | Diff noise is overwhelming | AI classifies diffs as intentional vs. regressive | | You find bugs after users report them | ECHO catches mismatches before users notice |
How it works
Your API → ECHO SDK → ingest-traffic Edge Function → Dashboard
↓ ↓
Live response Compares live vs. shadow
↓ ↓
Shadow response Stores results + AI verdictInstall
npm install echo-shadow
# or
yarn add echo-shadow
# or
pnpm add echo-shadowRequirements: Node.js 18+, TypeScript 5+ (optional but recommended)
Quick Start
import { createEchoClient } from "echo-shadow";
const echo = createEchoClient({
apiKey: process.env.ECHO_API_KEY!, // echo_sk_...
});
// In your API middleware or test harness:
const liveResponse = await callProductionAPI(req);
const shadowResponse = await callShadowAPI(req);
const result = await echo.logShadowTest({
endpoint: "/api/v1/checkout",
liveResponse,
shadowResponse,
latencyMs: 142,
});
console.log(result);
// → { success: true, test_run_id: "tr_abc123", status: "fail" }Examples
Express Middleware (fire-and-forget)
Shadow comparisons run in the background and never add latency to your live responses:
import { createEchoClient } from "echo-shadow";
const echo = createEchoClient({ apiKey: process.env.ECHO_API_KEY! });
app.use(async (req, res, next) => {
const start = Date.now();
const originalJson = res.json.bind(res);
res.json = (body) => {
// Fire-and-forget — never blocks the live response
callShadowAPI(req).then((shadowBody) => {
echo.logShadowTest({
endpoint: req.path,
liveResponse: body,
shadowResponse: shadowBody,
latencyMs: Date.now() - start,
});
}).catch(() => {});
return originalJson(body);
};
next();
});Next.js API Route
import { createEchoClient } from "echo-shadow";
import { NextResponse } from "next/server";
const echo = createEchoClient({ apiKey: process.env.ECHO_API_KEY! });
export async function POST(req: Request) {
const body = await req.json();
const start = Date.now();
const liveResult = await processCheckout(body);
// Non-blocking shadow comparison
processCheckoutV2(body).then((shadowResult) => {
echo.logShadowTest({
endpoint: "/api/checkout",
liveResponse: liveResult,
shadowResponse: shadowResult,
latencyMs: Date.now() - start,
});
}).catch(() => {});
return NextResponse.json(liveResult);
}Health Check
Verify your setup before sending real data:
const { reachable, authenticated } = await echo.ping();
if (!reachable) console.error("Cannot reach ECHO endpoint");
else if (!authenticated) console.error("API key is invalid");
else console.log("✅ ECHO is ready");API Reference
createEchoClient(config: EchoConfig)
Create a new ECHO client instance.
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| apiKey | string | ✅ | — | Your ECHO API key (echo_sk_...) |
| endpoint | string | ❌ | Hosted ECHO URL | Custom ingest endpoint |
echo.logShadowTest(params)
Send a shadow test result to ECHO for comparison.
| Param | Type | Required | Description |
|---|---|---|---|
| endpoint | string | ✅ | The API endpoint being tested (e.g. /api/checkout) |
| liveResponse | Record<string, unknown> | ✅ | The response from your production environment |
| shadowResponse | Record<string, unknown> | ✅ | The response from your shadow/staging environment |
| latencyMs | number | ❌ | Round-trip latency in milliseconds (default: 0) |
Returns: Promise<ShadowTestResult>
interface ShadowTestResult {
success: boolean;
test_run_id?: string; // Unique ID for this test run
status?: "pass" | "fail" | "review";
error?: string; // Error message if success is false
}Status meanings:
pass— Live and shadow responses are identicalfail— Structural or value mismatch detected (different keys or significant value differences)review— Same structure, different values — needs human review
echo.ping()
Verify connectivity and API key validity.
Returns: Promise<{ reachable: boolean; authenticated: boolean }>
Error Handling
The SDK never throws. It always returns a result object:
const result = await echo.logShadowTest({ ... });
if (!result.success) {
console.error("ECHO error:", result.error);
// Possible errors:
// "Invalid API key"
// "Missing required fields: api_key, endpoint"
// "HTTP 500" (server error)
}TypeScript Types
All types are exported for full type safety:
import type { EchoConfig, ShadowTestResult } from "echo-shadow";Troubleshooting
| Issue | Solution |
|---|---|
| Invalid API key | Regenerate a key in the ECHO dashboard → Settings |
| Cannot reach endpoint | Check your network/firewall allows HTTPS to *.supabase.co |
| Missing required fields | Ensure both api_key and endpoint are provided |
| Status always review | This means keys match but values differ — check your shadow env data |
Self-Hosting
If you self-host the ECHO backend, pass your custom endpoint:
const echo = createEchoClient({
apiKey: "echo_sk_...",
endpoint: "https://your-supabase-project.supabase.co/functions/v1/ingest-traffic",
});Publishing
cd packages/echo-sdk
npm install
npm run build
npm publish --access publicLicense
MIT © ECHO
