# @websolutespa/ask-scavolini

[![npm version](https://badge.fury.io/js/%40websolutespa%2Fask-scavolini.svg)](https://badge.fury.io/js/%40websolutespa%2Fask-scavolini)

[![status alpha](https://img.shields.io/badge/status-alpha-red.svg)](https://shields.io/)

Ask Scavolini plugin module of the [Ask Repository](https://github.com/websolutespa/ask) by [websolute](https://www.websolute.com/).

## Docs

This guide shows how to embed Ask Scavolini into a web page using the browser bundle.

The integration has five steps:

1. Include the browser JavaScript bundle.
2. Prepare the plugin options.
3. Initialize the plugin instance.
4. Create the web component element.
5. Append the element to the page.

## Basic Integration

```html
<!DOCTYPE html>
<html lang="it">
  <head>
    <meta charset="utf-8" />
    <script type="module" src="https://cdn.jsdelivr.net/npm/@websolutespa/ask-scavolini/dist/browser.js"></script>
  </head>
  <body>
    <div class="ask-scavolini"></div>

    <script type="module">
      const mount = () => {
        const target = document.querySelector('.ask-scavolini');
        if (!target || !window.askScavolini) {
          return;
        }

        const searchParams = new URLSearchParams(window.location.search);
        const options = {
          appKey: 'ask-scavolini',
          apiKey: 'YOUR_API_KEY',
          endpoint: 'https://ask.websolute.ai',
          styles: 'https://cdn.jsdelivr.net/npm/@websolutespa/ask-scavolini/dist/styles.css',
          threadId: searchParams.get('threadId') || undefined,
        };

        const instance = window.askScavolini(options);
        if (!instance) {
          return;
        }

        const element = document.createElement('ask-scavolini');
        element.style.display = 'contents';
        target.appendChild(element);
      };

      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', mount, { once: true });
      } else {
        mount();
      }
    </script>
  </body>
</html>
```

## Step By Step

### 1. Include the Browser JS

Load the browser entrypoint with a module script:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@websolutespa/ask-scavolini/dist/browser.js"></script>
```

This bundle exposes the `askScavolini(...)` initializer on `window`.

### 2. Configure the Options

Create an options object before initializing the plugin.

Common example:

```js
const options = {
  appKey: 'ask-scavolini',
  apiKey: 'YOUR_API_KEY',
  endpoint: 'https://ask.websolute.ai',
  styles: 'https://cdn.jsdelivr.net/npm/@websolutespa/ask-scavolini/dist/styles.css',
  threadId: new URLSearchParams(window.location.search).get('threadId') || undefined,
};
```

### 3. Initialize the Instance

Call the browser initializer with the options object:

```js
const instance = window.askScavolini(options);
```

The initializer returns a plugin instance when creation succeeds.

Available instance methods:

- `opened()` returns the current open state.
- `setOpened(boolean)` explicitly opens or closes the widget.
- `toggle()` toggles the widget state.
- `send(message)` sends a message programmatically.
- `clear()` clears the current conversation state.
- `create(target?)` creates or mounts the plugin programmatically.

### 4. Create the Web Component Element

Create the custom element used by the UI:

```js
const element = document.createElement('ask-scavolini');
element.style.display = 'contents';
```

Using `display: contents` keeps the wrapper element visually neutral when the page layout should be controlled by the component content.

### 5. Append the Component to the Page

Append the element to a target container already present in the DOM:

```js
const target = document.querySelector('.ask-scavolini');
target.appendChild(element);
```

## Supported Options

The published type declarations expose the following plugin options.

| Option | Type | Description |
| --- | --- | --- |
| `apiKey` | `string` | API key used by the plugin requests. |
| `appKey` | `string` | Application identifier for the embedded experience. |
| `contexts` | `ChatUserContext[]` | User context entries passed to the chat. |
| `draft` | `boolean` | Enables draft mode when supported by the backend. |
| `embedded` | `boolean` | Marks the plugin as embedded in an existing page. |
| `endpoint` | `string` | Base API endpoint used by the widget. |
| `initialSpec` | `Spec \| null` | Initial UI spec payload, if you want to preload a generated UI state. |
| `instance` | `PluginInstance` | Existing instance reference, when reusing plugin state manually. |
| `mock` | `boolean \| object` | Mock mode for local or controlled test data. |
| `preview` | `boolean` | Enables preview behavior when supported. |
| `styles` | `string` | URL of the stylesheet to load for the widget UI. |
| `threadId` | `string` | Conversation thread identifier to resume an existing thread. |
| `userId` | `string` | User identifier for session association or personalization. |

### `contexts`

`contexts` accepts an array of objects with this shape:

```js
const contexts = [
  {
    title: 'Customer',
    context: {
      id: '12345',
      market: 'it',
    },
  },
];
```

### `mock`

`mock` can be a boolean or an object used for mocked data flows.

Supported mock payload fields from the published types:

- `contents`
- `history`
- `messages`
- `stream`

## Clean Integration Pattern

For better readability and fewer global checks, keep the embed logic in a small initializer function:

```html
<script type="module">
  const mount = () => {
    const target = document.querySelector('.ask-scavolini');
    if (!target || !window.askScavolini) {
      return;
    }

    const searchParams = new URLSearchParams(window.location.search);
    const options = {
      appKey: 'ask-scavolini',
      apiKey: 'YOUR_API_KEY',
      endpoint: 'https://ask.websolute.ai',
      styles: 'https://cdn.jsdelivr.net/npm/@websolutespa/ask-scavolini/dist/styles.css',
      threadId: searchParams.get('threadId') || undefined,
    };

    const instance = window.askScavolini(options);
    if (!instance) {
      return;
    }

    const element = document.createElement('ask-scavolini');
    element.style.display = 'contents';
    target.appendChild(element);
  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', mount, { once: true });
  } else {
    mount();
  }
</script>
```

## Performance And Readability Notes

To keep the embed clean and efficient:

- Load the browser bundle once with `type="module"`.
- Reuse a single mount container.
- Resolve `threadId` only once during initialization.
- Guard against missing target nodes or missing bundle globals.
- Use `DOMContentLoaded` only when needed; if the document is already ready, initialize immediately.
- Keep the stylesheet URL inside the options object so the component can manage its own styles consistently.

## Hints

Replace `YOUR_API_KEY` with the correct key for the target environment before publishing.  

Replace `Scavolini` with the actual exported name of the Ask Plugin.

---

##### *this library is for internal usage and not production ready*
