npm package: @opencommerceprotocol/runtime
Description: Open Commerce Protocol — Browser JavaScript runtime (~8KB gzipped)
Latest version: 1.0.0

# @opencommerceprotocol/runtime

Browser runtime for the [Open Commerce Protocol](https://opencommerceprotocol.org). Registers OCP tools with WebMCP (`navigator.modelContext`) in Chrome 146+ with graceful fallback to `window.__ocp` for all other browsers. Optionally mounts an embedded chat widget.

**~8KB gzipped.** Zero dependencies at runtime.

## Quick Start (CDN)

```html
<script src="https://cdn.opencommerceprotocol.org/runtime/v1/ocp-runtime.min.js"></script>
<script>
OCP.init({
  handlers: {
    search_products: async ({ query }) =>
      fetch(`/api/products?q=${encodeURIComponent(query)}`).then(r => r.json()),
    get_product: async ({ id }) =>
      fetch(`/api/products/${id}`).then(r => r.json()),
    add_to_cart: async ({ product_id, quantity }) =>
      fetch('/api/cart', { method: 'POST', body: JSON.stringify({ product_id, quantity }) }).then(r => r.json()),
    begin_checkout: async ({ prefill }) =>
      fetch('/api/checkout', { method: 'POST', body: JSON.stringify(prefill) }).then(r => r.json()),
  },
  widget: true,
});
</script>
```

## ESM Import

```bash
npm install @opencommerceprotocol/runtime
```

```typescript
import { OCP } from '@opencommerceprotocol/runtime';

const ocp = OCP.init({ handlers: { ... } });
```

## `OCP.init(config)`

Returns an `OCP` instance. Must be called once per page.

### `OCPConfig`

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `handlers` | `Partial<OCPHandlers>` | — | Tool handler implementations |
| `adapter` | `'shopify' \| 'woocommerce' \| 'custom'` | — | Use a preset adapter |
| `manifest` | `string` | `'/.well-known/ocp.json'` | URL to fetch the OCP manifest |
| `permissions` | `OCPPermissions` | — | Override agent permissions |
| `widget` | `boolean \| OCPWidgetConfig` | `false` | Mount the chat widget |
| `analytics` | `boolean \| AnalyticsConfig` | `false` | Enable opt-in analytics |
| `jsonld` | `{ enabled?, mode?, productSelector? }` | — | JSON-LD injection/augmentation |
| `silent` | `boolean` | `false` | Suppress console logs |

### `OCP` instance

```typescript
const ocp = OCP.init({ ... });

ocp.tools           // string[] — names of registered tools
ocp.webmcpSupported // boolean — is WebMCP available in this browser?
ocp.widget          // OCPWidget | null
ocp.analytics       // OCPAnalytics | null
```

## Chat Widget

Mount a conversational shopping assistant for human visitors:

```javascript
OCP.init({
  handlers: { ... },
  widget: {
    position: 'bottom-right',      // 'bottom-right' | 'bottom-left'
    theme: 'purple',               // CSS color or 'purple' | 'blue' | 'green'
    title: 'Shop Assistant',
    placeholder: 'Ask me anything about our products…',
    welcomeMessage: 'Hi! How can I help you shop today?',
    confidenceThreshold: 0.7,      // minimum confidence before escalating to cloud LLM
    maxResults: 5,
    showBranding: true,
  },
});
```

### Three-Tier Processing Pipeline

The widget uses a tiered approach to answer shopper questions:

| Tier | Mechanism | When Used |
|------|-----------|-----------|
| 1 | Regex intent matcher | High-confidence matches (≥ 0.85) |
| 2 | Browser LLM (WebGPU) | Mid-confidence (≥ 0.40, < 0.85) |
| 3 | Cloud LLM fallback | Low-confidence (< 0.40) |

## Platform Adapters

### Shopify

```typescript
import { OCP, createShopifyHandlers } from '@opencommerceprotocol/runtime';

OCP.init({
  handlers: createShopifyHandlers({
    storeDomain: 'mystore.myshopify.com',
    storefrontToken: 'your-storefront-api-token',
  }),
  widget: true,
});
```

### WooCommerce

```typescript
import { OCP, createWooCommerceHandlers } from '@opencommerceprotocol/runtime';

OCP.init({
  handlers: createWooCommerceHandlers({
    siteUrl: 'https://mystore.com',
    consumerKey: 'ck_xxx',
    consumerSecret: 'cs_xxx',
  }),
  widget: true,
});
```

### Custom

```typescript
import { OCP, createCustomHandlers } from '@opencommerceprotocol/runtime';

OCP.init({
  handlers: createCustomHandlers({
    searchUrl: '/api/products',
    productUrl: '/api/products/:id',
    cartUrl: '/api/cart',
    checkoutUrl: '/api/checkout',
  }),
});
```

## Browser LLM

Load a local language model (requires Chrome with WebGPU):

```typescript
import { BrowserLLM } from '@opencommerceprotocol/runtime';

const llm = new BrowserLLM({
  model: 'gemma-2b',               // model identifier
  loadStrategy: 'lazy',            // 'eager' | 'lazy' | 'idle'
  onProgress: (p) => console.log(`Loading: ${p.progress}%`),
  onStatusChange: (s) => console.log(`Status: ${s}`),
});

await llm.load();
const result = await llm.generate('Summarize this product: ...');
```

### `BrowserLLMStatus`

`'idle' | 'loading' | 'ready' | 'generating' | 'error'`

## Analytics (Opt-In)

```typescript
OCP.init({
  handlers: { ... },
  analytics: {
    enabled: true,
    endpoint: '/api/ocp-analytics',   // your analytics server
    storageKey: 'ocp_events',         // localStorage key for buffering
    flushInterval: 5000,              // ms between flushes
  },
});

// Access the analytics instance
const ocp = OCP.init({ ... });
ocp.analytics?.trackToolCall('search_products', { query: 'headphones' });
```

## JSON-LD Integration

```typescript
import { injectProductJsonLd, augmentExistingJsonLd, extractProductFromPage } from '@opencommerceprotocol/runtime';

// Inject Schema.org Product JSON-LD
injectProductJsonLd({
  id: 'prod-001',
  name: 'Headphones',
  price: 149.99,
  currency: 'USD',
  url: window.location.href,
});

// Augment existing JSON-LD with OCP fields
augmentExistingJsonLd({ agent_notes: 'Best noise-cancelling headphones under $200.' });

// Extract product data from existing Schema.org JSON-LD on the page
const product = extractProductFromPage();
```

## Auto-Init via HTML Attribute

Initialize OCP without JavaScript by adding an attribute to the script tag:

```html
<script
  src="https://cdn.opencommerceprotocol.org/runtime/v1/ocp-runtime.min.js"
  data-ocp-auto-init
  data-ocp-config='{"widget":true}'
></script>
```

## WebMCP Detection

```typescript
import { isWebMCPAvailable } from '@opencommerceprotocol/runtime';

if (isWebMCPAvailable()) {
  console.log('Chrome 146+ with WebMCP enabled');
}
```

## Exports Reference

| Export | Description |
|--------|-------------|
| `OCP` | Main runtime class |
| `OCPWidget` | Chat widget component |
| `OCPAnalytics` | Analytics tracker |
| `BrowserLLM` | WebGPU-based browser LLM |
| `createShopifyHandlers` | Shopify adapter factory |
| `createWooCommerceHandlers` | WooCommerce adapter factory |
| `createCustomHandlers` | Generic REST adapter factory |
| `isWebMCPAvailable` | WebMCP feature detection |
| `injectProductJsonLd` | Inject Schema.org JSON-LD |
| `augmentExistingJsonLd` | Augment existing JSON-LD |
| `extractProductFromPage` | Extract product data from page |