# JavaScript SDK

Browser-only JavaScript SDK for the AIDP API. No build tools required!

## Installation

### CDN (Recommended)

```html
<script src="https://cdn.aidp.dev/sdk/v1/aidp.min.js"></script>
```

### npm (for bundlers)

```bash
npm install @aidp/sdk-browser
```

***

## Quick Start

```html
<!DOCTYPE html>
<html>
  <head>
    <title>AIDP Search</title>
    <script src="https://cdn.aidp.dev/sdk/v1/aidp.min.js"></script>
  </head>
  <body>
    <input id="search" type="text" placeholder="Search businesses..." />
    <div id="results"></div>

    <script>
      const client = new AIDP.Client({
        apiKey: 'your-api-key',
      });

      document.getElementById('search').addEventListener('input', async (e) => {
        const query = e.target.value;
        if (!query) return;

        const results = await client.search({
          query,
          location: { lat: 45.5231, lon: -122.6765, distance: '5km' },
        });

        const html = results.data.businesses
          .map((b) => `<div>${b.name} - ${b.category}</div>`)
          .join('');

        document.getElementById('results').innerHTML = html;
      });
    </script>
  </body>
</html>
```

***

## Configuration

### Basic Configuration

```javascript
const client = new AIDP.Client({
  apiKey: 'your-api-key',
  environment: 'production', // or 'sandbox'
});
```

### Advanced Configuration

```javascript
const client = new AIDP.Client({
  apiKey: 'your-api-key',
  environment: 'production',
  timeout: 30000, // Request timeout (ms)
  retries: 3, // Number of retries
  baseURL: 'https://api.aidp.dev/v1',
  headers: {
    // Custom headers
    'X-Custom-Header': 'value',
  },
});
```

***

## API Methods

### Search

Search for businesses using natural language queries.

```javascript
const results = await client.search({
  query: 'coffee shops',
  location: {
    lat: 45.5231,
    lon: -122.6765,
    distance: '5km',
  },
  category: 'restaurants',
  limit: 10,
});

console.log(`Found ${results.data.total} businesses`);
console.log(`AI Response: ${results.data.response}`);

results.data.businesses.forEach((business) => {
  console.log(`${business.name} - ${business.distance}m away`);
});
```

### Get Business

Get detailed information about a specific business.

```javascript
const business = await client.businesses.get('biz_abc123');

console.log(`Name: ${business.data.name}`);
console.log(`Category: ${business.data.category}`);
console.log(`Rating: ${business.data.averageRating}`);
```

### Directory Search

Browse the business directory with filters.

```javascript
const directory = await client.directory({
  category: 'restaurants',
  city: 'Portland',
  state: 'OR',
  verificationLevel: 'verified',
  sortBy: 'aiVisibilityScore',
  limit: 20,
});

directory.data.businesses.forEach((business) => {
  console.log(`${business.name} - Score: ${business.aiVisibilityScore}`);
});
```

***

## Error Handling

```javascript
try {
  const results = await client.search({ query: 'coffee' });
  console.log(results.data.businesses);
} catch (error) {
  if (error.code === 'RATE_LIMIT_EXCEEDED') {
    console.log(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error.code === 'VALIDATION_ERROR') {
    console.log('Validation errors:', error.details);
  } else {
    console.log(`Error: ${error.message}`);
  }
}
```

***

## Examples

### Search with Autocomplete

```html
<input id="search" type="text" placeholder="Search..." />
<div id="suggestions"></div>

<script>
  const client = new AIDP.Client({ apiKey: 'your-api-key' });
  let timeout;

  document.getElementById('search').addEventListener('input', (e) => {
    clearTimeout(timeout);

    timeout = setTimeout(async () => {
      const query = e.target.value;
      if (!query) return;

      const results = await client.search({ query, limit: 5 });

      const html = results.data.businesses
        .map(
          (b) => `
          <div class="suggestion" onclick="selectBusiness('${b.id}')">
            <strong>${b.name}</strong>
            <p>${b.description}</p>
          </div>
        `
        )
        .join('');

      document.getElementById('suggestions').innerHTML = html;
    }, 300);
  });

  async function selectBusiness(id) {
    const business = await client.businesses.get(id);
    console.log('Selected:', business.data);
  }
</script>
```

### Location-Based Search

```html
<button onclick="searchNearby()">Find Nearby Businesses</button>
<div id="results"></div>

<script>
  const client = new AIDP.Client({ apiKey: 'your-api-key' });

  async function searchNearby() {
    // Get user's location
    navigator.geolocation.getCurrentPosition(async (position) => {
      const results = await client.search({
        query: 'coffee shops',
        location: {
          lat: position.coords.latitude,
          lon: position.coords.longitude,
          distance: '5km',
        },
      });

      const html = results.data.businesses
        .map(
          (b) => `
          <div>
            <h3>${b.name}</h3>
            <p>${b.distance}m away</p>
            <p>${b.address.street}, ${b.address.city}</p>
          </div>
        `
        )
        .join('');

      document.getElementById('results').innerHTML = html;
    });
  }
</script>
```

### Search with Map

```html
<div id="map" style="height: 400px;"></div>
<script src="https://cdn.aidp.dev/sdk/v1/aidp.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY"></script>

<script>
  const client = new AIDP.Client({ apiKey: 'your-api-key' });

  async function searchAndMap(query, location) {
    const results = await client.search({ query, location });

    const map = new google.maps.Map(document.getElementById('map'), {
      center: { lat: location.lat, lng: location.lon },
      zoom: 13,
    });

    results.data.businesses.forEach((business) => {
      new google.maps.Marker({
        position: {
          lat: business.coordinates.lat,
          lng: business.coordinates.lon,
        },
        map: map,
        title: business.name,
      });
    });
  }

  searchAndMap('coffee shops', { lat: 45.5231, lon: -122.6765 });
</script>
```

### Pagination

```html
<div id="results"></div>
<button id="loadMore">Load More</button>

<script>
  const client = new AIDP.Client({ apiKey: 'your-api-key' });
  let offset = 0;
  const limit = 10;

  async function loadResults() {
    const results = await client.search({
      query: 'restaurants',
      limit,
      offset,
    });

    const html = results.data.businesses.map((b) => `<div>${b.name}</div>`).join('');

    document.getElementById('results').innerHTML += html;

    if (!results.data.pagination.hasMore) {
      document.getElementById('loadMore').style.display = 'none';
    }

    offset += limit;
  }

  document.getElementById('loadMore').addEventListener('click', loadResults);
  loadResults(); // Initial load
</script>
```

***

## Browser Compatibility

The SDK works in all modern browsers:

* ✅ Chrome 90+
* ✅ Firefox 88+
* ✅ Safari 14+
* ✅ Edge 90+

**Not supported**:

* ❌ Internet Explorer

***

## Security Best Practices

### Never Expose API Keys

❌ **Don't** hardcode API keys in client-side code:

```javascript
// DON'T DO THIS!
const client = new AIDP.Client({
  apiKey: 'sk_live_abc123...', // Exposed to users!
});
```

✅ **Do** use a backend proxy:

```javascript
// Frontend
async function search(query) {
  const response = await fetch('/api/search', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query }),
  });
  return response.json();
}

// Backend (Node.js)
app.post('/api/search', async (req, res) => {
  const client = new AIDPClient({
    apiKey: process.env.AIDP_API_KEY, // Secure!
  });
  const results = await client.search(req.body);
  res.json(results);
});
```

### Use Public API Keys

For client-side usage, use public API keys with restricted permissions:

```javascript
const client = new AIDP.Client({
  apiKey: 'pk_live_abc123...', // Public key, safe for client-side
});
```

***

## Performance Tips

### Debounce Search Input

```javascript
function debounce(func, wait) {
  let timeout;
  return function (...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

const debouncedSearch = debounce(async (query) => {
  const results = await client.search({ query });
  displayResults(results);
}, 300);

document.getElementById('search').addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});
```

### Cache Results

```javascript
const cache = new Map();

async function searchWithCache(query) {
  if (cache.has(query)) {
    return cache.get(query);
  }

  const results = await client.search({ query });
  cache.set(query, results);

  // Clear cache after 5 minutes
  setTimeout(() => cache.delete(query), 5 * 60 * 1000);

  return results;
}
```

***

## Need Help?

* 📧 Email: <sdk@aidp.dev>
* 💬 GitHub Discussions: [github.com/aidp/platform/discussions](https://github.com/aidp/platform/discussions)
* 📚 API Reference: [docs.aidp.dev/api](https://docs.aidp.dev/api)
* 🐛 Issues: [github.com/aidp/sdk-browser/issues](https://github.com/aidp/sdk-browser/issues)
