npm package: @opencommerceprotocol/bridge-acp
Description: Open Commerce Protocol — ACP (Agent Commerce Protocol) checkout bridge
Latest version: 1.0.0

# @opencommerceprotocol/bridge-acp

ACP (Agent Commerce Protocol) checkout bridge for the [Open Commerce Protocol](https://opencommerceprotocol.org). Provides Express/Hono-compatible middleware that exposes ACP-compatible REST endpoints for agent-initiated checkout flows.

## Installation

```bash
npm install @opencommerceprotocol/bridge-acp
```

## ACP Endpoints

When mounted at `/acp`, the bridge provides:

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/acp/checkout` | Create a checkout session |
| `GET` | `/acp/checkout/:id` | Get session status |
| `POST` | `/acp/checkout/:id/complete` | Mark session as complete |
| `DELETE` | `/acp/checkout/:id` | Cancel a session |

## Express Middleware

```typescript
import express from 'express';
import { createACPExpressMiddleware } from '@opencommerceprotocol/bridge-acp';
import manifest from './.well-known/ocp.json';

const app = express();
app.use(express.json());

app.use('/acp', createACPExpressMiddleware({
  ocpManifest: manifest,
  checkoutUrl: 'https://mystore.com/checkout',
  sessionTtlMs: 30 * 60 * 1000,  // 30 minutes (default)
}));
```

## Framework-Agnostic Handlers

Use `createACPHandlers` to adapt the bridge to any HTTP framework:

```typescript
import { createACPHandlers } from '@opencommerceprotocol/bridge-acp';
import type { ACPRequest, ACPResponse } from '@opencommerceprotocol/bridge-acp';

const handlers = createACPHandlers({
  ocpManifest: manifest,
  checkoutUrl: 'https://mystore.com/checkout',
});

// handlers is: Record<string, (req: ACPRequest, res: ACPResponse) => Promise<void>>
// Keys: 'POST /checkout', 'GET /checkout/:id', 'POST /checkout/:id/complete', 'DELETE /checkout/:id'
```

### Hono Example

```typescript
import { Hono } from 'hono';
import { createACPHandlers } from '@opencommerceprotocol/bridge-acp';

const app = new Hono();
const handlers = createACPHandlers({ ocpManifest: manifest, checkoutUrl: '/checkout' });

app.post('/acp/checkout', async (c) => {
  let response: Response | null = null;
  const handler = handlers['POST /checkout'];
  if (!handler) return c.json({ error: 'Not implemented' }, 500);
  await handler(
    { method: 'POST', path: '/checkout', params: {}, body: await c.req.json() },
    {
      status: (code) => ({ json: (data) => { response = c.json(data, code as never); } }) as never,
      json: (data) => { response = c.json(data); },
    }
  );
  return response ?? c.json({ error: 'Internal error' }, 500);
});
```

## `ACPMiddlewareConfig`

| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| `ocpManifest` | `OCPManifest` | Yes | — | OCP manifest |
| `handlers` | `Partial<OCPHandlers>` | No | — | Custom tool handlers |
| `checkoutUrl` | `string` | Yes | — | Base URL for checkout redirects |
| `sessionTtlMs` | `number` | No | `1800000` | Session TTL in milliseconds (30 min) |

## `ACPSession`

```typescript
interface ACPSession {
  id: string;
  status: 'pending' | 'active' | 'complete' | 'failed' | 'expired';
  checkout_url: string;
  created_at: string;  // ISO 8601
  expires_at: string;  // ISO 8601
  items?: Array<{ product_id: string; quantity: number; price: number }>;
  total?: number;
  currency?: string;
}
```

## Session Lifecycle

```
POST /acp/checkout          → { status: 'pending', checkout_url: '...' }
  ↓ (user completes checkout)
POST /acp/checkout/:id/complete  → { status: 'complete' }

GET /acp/checkout/:id        → poll for current status
DELETE /acp/checkout/:id     → cancel the session
```

## Request / Response Types

```typescript
interface ACPRequest {
  method: string;
  path: string;
  params: Record<string, string>;  // path params, e.g. { id: 'sess-123' }
  body: unknown;
}

interface ACPResponse {
  status: (code: number) => ACPResponse;  // chainable
  json: (data: unknown) => void;
}
```

## Production Considerations

The default implementation uses an **in-memory session store**. For production, replace with a persistent store:

```typescript
import { createACPHandlers } from '@opencommerceprotocol/bridge-acp';

// Extend or wrap createACPHandlers with your Redis/DB session store
const handlers = createACPHandlers({
  ocpManifest: manifest,
  checkoutUrl: process.env.CHECKOUT_URL!,
  sessionTtlMs: 60 * 60 * 1000,  // 1 hour
});
```

## OCP Manifest Declaration

Declare your ACP endpoint in the OCP manifest to make it discoverable:

```json
{
  "bridge": {
    "acp": "https://mystore.com/acp"
  }
}
```