> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK

> Integrate Anon migrations with the @anon-dot-com/frontend package

# Anon Frontend SDK

The `@anon-dot-com/frontend` package provides a lightweight JavaScript library for embedding the Anon Enterprise Data Migration platform directly into your web application. This SDK handles user authentication, migration status checking, and provides seamless integration through a secure iframe modal.

## Overview

The SDK creates a responsive iframe modal that displays the Anon migration interface within any web application. It provides event-driven communication and handles the complete migration lifecycle using a secure token-based authentication flow.

<Note>
  The SDK uses a two-step authentication process: your backend generates a link token using your API key, and the frontend exchanges it for an access token that's stored securely in the browser.
</Note>

## Installation

This is a private npm package that requires authentication to install.

### Configure npm Authentication

Create or update your `.npmrc` file in your project root with the authentication token:

```bash theme={"system"}
@anon-dot-com:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=YOUR_ACCESS_TOKEN
```

<Info>
  Contact your Anon point-of-contact to obtain the access token for your `.npmrc` configuration.
</Info>

### Install the Package

Once your `.npmrc` is configured, you can install the package using your preferred package manager:

<CodeGroup>
  ```bash npm theme={"system"}
  npm install @anon-dot-com/frontend
  ```

  ```bash yarn theme={"system"}
  yarn add @anon-dot-com/frontend
  ```

  ```bash pnpm theme={"system"}
  pnpm add @anon-dot-com/frontend
  ```
</CodeGroup>

<Warning>
  Never commit your `.npmrc` file with the access token to version control. Add `.npmrc` to your `.gitignore` file to prevent accidental exposure of credentials.
</Warning>

## Quick Start

### Basic Integration

The SDK provides two main methods for integrating the migration modal:

<CodeGroup>
  ```javascript Initialize Existing Migration theme={"system"}
  import { init } from '@anon-dot-com/frontend';

  // Initialize the Anon Link (finds existing migration)
  await init({
    onEvent: (event) => {
      console.log('Migration event:', event);
    }
  });
  ```

  ```javascript Start New Migration theme={"system"}
  import { startModal } from '@anon-dot-com/frontend';

  // Get link token from your backend first
  const linkToken = await fetch('/api/anon/link-token', {
    method: 'POST'
  }).then(res => res.json()).then(data => data.link_token);

  // Start a new migration
  await startModal({
    linkToken,
    userId: 'user@example.com',
    onEvent: (event) => {
      console.log('Migration event:', event);
    }
  });
  ```
</CodeGroup>

### Advanced Configuration

Configure the modal with additional options for more control over the migration process:

```javascript theme={"system"}
import { startModal } from '@anon-dot-com/frontend';

// Get link token from your backend
const linkToken = await fetch('/api/anon/link-token', {
  method: 'POST'
}).then(res => res.json()).then(data => data.link_token);

await startModal({
  userId: 'user@example.com',
  linkToken: linkToken,
  sourceProviders: ['gusto', 'rippling'], // Pre-configure source providers
  target: '#migration-container', // Custom target element
  baseURL: 'https://worker.anon.com', // Optional: Override base URL
  onEvent: (event) => {
    switch (event.event.type) {
      case 'migration_modal.completed':
        console.log('Migration completed:', event.event.data);
        break;
      case 'migration_modal.failed':
        console.log('Migration failed:', event.event.data);
        break;
    }
  }
});
```

### Global Script Usage

If you're not using a module bundler, include the library as a global script:

```html theme={"system"}
<script src="https://cdn.jsdelivr.net/npm/@anon-dot-com/frontend/index.umd.js"></script>
<script>
  // First get link token from your backend
  fetch('/api/anon/link-token', { method: 'POST' })
    .then(res => res.json())
    .then(data => {
      // Initialize the Anon Link (finds existing migration)
      window.Anon.init({
        onEvent: (event) => {
          console.log('Migration event:', event);
        }
      });
    });
</script>
```

## API Reference

### Methods

<AccordionGroup>
  <Accordion title="init(options: AnonInitOptions)">
    Initializes the SDK and finds any existing migration for the user. This method checks localStorage for previous migration options and attempts to continue an existing migration if found.

    **Parameters:**

    * `options`: Configuration object of type `AnonInitOptions`

    **Returns:**

    * Promise that resolves with migration metadata if an existing migration is found, or undefined
  </Accordion>

  <Accordion title="startModal(options: AnonLinkOptions)">
    Creates a new modal link for the user and immediately shows the iframe modal. This method requires a link token obtained from your backend.

    **Parameters:**

    * `options`: Configuration object of type `AnonLinkOptions`

    **Returns:**

    * Promise that resolves when the modal is started
  </Accordion>
</AccordionGroup>

### Configuration Options

#### AnonInitOptions

The `AnonInitOptions` interface accepts the following properties:

| Property  | Type                         | Required | Description                                                                                  |
| --------- | ---------------------------- | -------- | -------------------------------------------------------------------------------------------- |
| `onEvent` | `(event: EventData) => void` | No       | Callback for migration events                                                                |
| `target`  | `string`                     | No       | CSS selector for target element (defaults to "body")                                         |
| `baseURL` | `string`                     | No       | Base URL for API requests (defaults to "[https://worker.anon.com](https://worker.anon.com)") |

#### AnonLinkOptions

The `AnonLinkOptions` interface extends `AnonInitOptions` and accepts additional properties:

| Property          | Type       | Required | Description                                                           |
| ----------------- | ---------- | -------- | --------------------------------------------------------------------- |
| `userId`          | `string`   | Yes      | User identifier (UUID or email address)                               |
| `linkToken`       | `string`   | Yes      | Link token obtained from your backend's `/api/v1/link-token` endpoint |
| `sourceProviders` | `string[]` | No       | Pre-configured source providers for migration                         |

### Event Structure

The `onEvent` callback receives events with the following structure:

```typescript theme={"system"}
type AnonEventData = {
  source: 'anon_modal';
  event: {
    type: string;
    data: any;
  };
};
```

<Info>
  Common event types include `migration_modal.completed`, `migration_modal.failed`, and `migration_modal.cancelled`.
</Info>

## Authentication Flow

The SDK uses a secure two-step authentication process:

1. **Link Token Generation**: Your backend calls the Anon API to create a link token
2. **Access Token Exchange**: The frontend exchanges the link token for a browser-safe access token

### Step 1: Backend Link Token Generation

Your backend must implement an endpoint that generates link tokens:

<Tabs>
  <Tab title="Next.js">
    ```typescript theme={"system"}
    // /api/anon/link-token/route.ts
    export async function POST() {
      const response = await fetch('https://worker.anon.com/api/v1/link-token', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.ANON_API_KEY}`,
          'Content-Type': 'application/json'
        }
      });

      const data = await response.json();
      return Response.json(data);
    }
    ```
  </Tab>

  <Tab title="Express.js">
    ```javascript theme={"system"}
    app.post('/api/anon/link-token', async (req, res) => {
      const response = await fetch('https://worker.anon.com/api/v1/link-token', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.ANON_API_KEY}`,
          'Content-Type': 'application/json'
        }
      });

      const data = await response.json();
      res.json(data);
    });
    ```
  </Tab>
</Tabs>

### Step 2: Frontend Access Token Exchange

The SDK automatically handles the access token exchange when you call `startModal()` with a link token. The access token is stored in localStorage and used for subsequent API calls.

<Warning>
  Link tokens are short-lived (60 seconds) and single-use. Access tokens are longer-lived (1 hour) and stored securely in the browser.
</Warning>

## Migration Persistence

The SDK automatically persists migration state in the browser's localStorage. When you call `init()`, it checks for any existing migration options and attempts to continue where the user left off.

```javascript theme={"system"}
import { init, startModal } from '@anon-dot-com/frontend';

// On page load, check for existing migration
const existingMigration = await init({
  onEvent: (event) => console.log('Migration event:', event)
});

if (!existingMigration) {
  // No existing migration found, user can start a new one
  document.getElementById('start-migration').addEventListener('click', async () => {
    const linkToken = await fetch('/api/anon/link-token', { method: 'POST' })
      .then(res => res.json())
      .then(data => data.link_token);
    
    await startModal({
      userId: 'user@example.com',
      linkToken: linkToken
    });
  });
}
```

## Architecture Flow

The following diagram illustrates the new authentication flow:

```mermaid theme={"system"}
sequenceDiagram
    participant Client as Client App
    participant Frontend as @anon-dot-com/frontend
    participant Backend as Your Backend
    participant Worker as Anon Worker API
    participant Dashboard as Anon Dashboard

    Note over Client,Dashboard: Authentication Flow
    Client->>Backend: POST /api/anon/link-token
    Backend->>Worker: POST /api/v1/link-token (with API key)
    Worker-->>Backend: {link_token: "link-token-xxx"}
    Backend-->>Client: {link_token: "link-token-xxx"}
    
    Note over Client,Dashboard: Starting Migration
    Client->>Frontend: startModal({userId, linkToken})
    Frontend->>Worker: POST /api/v1/access-token {link_token}
    Worker-->>Frontend: {access_token: "access-token-xxx"} + Set-Cookie
    Frontend->>Frontend: Store access token in localStorage
    Frontend->>Worker: POST /api/v1/migration-modal (with access token)
    Worker-->>Frontend: {url: "https://dashboard.anon.com/v1/modal/abc123"}
    Frontend->>Frontend: createIframe(url, visible: true)
    Frontend-->>Client: Migration modal displayed

    Note over Client,Dashboard: Resuming Migration  
    Client->>Frontend: init({onEvent})
    Frontend->>Frontend: Check localStorage for options & access token
    Frontend->>Worker: GET /api/v1/migration-modal (with access token)
    Worker-->>Frontend: {url: "https://dashboard.anon.com/v1/modal/abc123", status}
    Frontend->>Frontend: createIframe(url, visible: false/true based on status)
    Frontend-->>Client: Migration resumed or completed
```

## Backend Requirements

### Required Endpoints

Your backend needs to implement the following endpoint:

| Endpoint               | Method | Purpose                                           |
| ---------------------- | ------ | ------------------------------------------------- |
| `/api/anon/link-token` | POST   | Generate a link token for frontend authentication |

### Security Considerations

* Store your Anon API key securely in environment variables
* Implement proper authentication/authorization for the link token endpoint
* Consider rate limiting the link token endpoint to prevent abuse
* Link tokens are short-lived (60 seconds) and single-use for security

<Warning>
  Never expose your Anon API key in client-side code. The new token-based flow eliminates the need for a catch-all proxy while maintaining security.
</Warning>

## Migration from Previous Versions

If you're migrating from a previous version that used `loadModal()` and proxy URLs:

### Before (v0.x)

```javascript theme={"system"}
await loadModal({
  userId: 'user@example.com',
  proxyUrl: 'https://your-backend.com/anon-proxy'
});
```

### After (v1.x)

```javascript theme={"system"}
// Initialize existing migrations
await init();

// Start new migrations
const linkToken = await fetch('/api/anon/link-token', { method: 'POST' })
  .then(res => res.json()).then(data => data.link_token);

await startModal({
  userId: 'user@example.com',
  linkToken: linkToken
});
```

### Breaking Changes

* `loadModal()` has been replaced with `init()` for resuming existing migrations
* `proxyUrl` is no longer required; the SDK communicates directly with Anon APIs
* `linkToken` is now required for `startModal()`
* New `/api/v1/link-token` endpoint required on your backend

## Next Steps

<CardGroup cols={2}>
  <Card title="Embedding the Modal" icon="window-maximize" href="/v1/modal/embed">
    Learn more about iframe integration best practices
  </Card>

  <Card title="Webhooks" icon="webhook" href="/v1/modal/webhooks">
    Set up webhooks to receive migration status updates
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference">
    Explore the complete Anon API documentation
  </Card>

  <Card title="Messages" icon="comments" href="/v1/modal/messages">
    Handle migration events and messages
  </Card>
</CardGroup>
