[![npm](https://img.shields.io/npm/v/@varvara-io/sdk.svg?style=flat)](https://npmjs.org/package/@varvara-io/sdk)
[![](https://data.jsdelivr.com/v1/package/npm/@varvara-io/sdk/badge?style=rounded)](https://www.jsdelivr.com/package/npm/@varvara-io/sdk)

# Varvara JavaScript SDK

Virtual Fitting Javascript SDK for online retailers. SDK is event-based library written in Typescript, and transpiled in
ECMAScript5 using Babel and the TypeScript compiler.

## Installation

Install the `@varvara-io/sdk` as a dependency of your project:

```typescript
import '@varvara-io/sdk/build/varvara-sdk.css'; // ~ 73 KB
import varvaraSdk from '@varvara-io/sdk'; // ~ 155 KB
```

### Embedding

Directly include `build/varvara-sdk.var.js` in a script tag and `build/varvara-sdk.css` in a link tag on the page.

```html
<link
  rel="stylesheet"
  href="https://unpkg.com/@varvara-io/sdk/build/varvara-sdk.css"
  type="text/css"
/>
<script src="https://unpkg.com/@varvara-io/sdk/build/varvara-sdk.var.js"></script>

<script>
  varvaraSdk.tryOn(
    '/awesome-category/clothes-image.png',
    {
      userId: '42',
      itemId: '102349',
    },
  );
</script>
```

## Try on

Invoke to following method `varvaraSdk.tryOn(clothesSrc: string, payload: TryOnPayload) => Fitting`,
and provide clothes image src (and payload if necessary) to start fitting.

You must provide `payload` argument which should at a minimum contains as `itemId` and `userId` values. 

```typescript
type TryOnPayload = {
  itemId: string;
  userId: string;
} & Record<string, unknown>;

const fittingId = varvaraSdk.tryOn(clothesSrc, {
  itemId: '42',
  userId: '102349',
  anotherField: Math.random()
});
```

Each calling of `tryOn` create an [object `Fitting`](#object-fitting).

## Events and Fitting

The `varvaraSdk` fires a bunch of events.
Each event links with [object `Fitting`](#object-fitting) and contains `fittingId`.
Event listener could be registered and unregistered as below:

```typescript
// Import package or inject directly before using

function handleEvent<T extends EventType>(
  event: EventsMap[T],
  fitting: Fitting,
): void {
  // make some noise
}

// subscribe event
varvaraSdk.addEventListener('fittingFinish', handleEvent);
// unsubscribe event
varvaraSdk.removeEventListener('fittingFinish', handleEvent);
```

### Object `Event<Meta = void>`

A `Event` object has the following structure:

```typescript
type Event<Meta = void> = {
  // Key of EventsMap interface (see below)
  type: string;

  // Client timestamp of event
  timestamp: number;

  // Route name of the screen inside varvara app
  routeName: 'PHOTO' | 'RESULT' | 'SIGN' | 'TERMS' | 'PRIVACY' | 'SIGN_ERROR' | 'FITTING_ERROR';

  // Unique ID generated when varvaraSdk.tryOn() method invoked
  fittingId: string;

  // Event-specific information (see beloow)
  meta: Meta;
};
```

Full list of events types (`keys of EventsMap`) described below:

- `'open': Event` - fired after Varvara App is opened
- `'clothesImageLoaded': Event` - fired when provided clothes image loading is finished successfully
- `'clothesImageFailed': Event` - fired when provided clothes image loading is failed
- `'clothesContinueClick': Event` - fired after user clicks on Continue button
- `'clientPhotoLoaded': Event<ClientPhotoCropMeta>` - fired when loading and crop of photo provided by user is finished successfully
  - ```typescript
    type ClientPhotoCropMeta = {
      inputWidth: number;
      inputHeight: number;
      outputWidth: number;
      outputHeight: number;
      outputSize: number; // bytes
      minCropSize: number; // 512px
    };
    ```
- `'clientPhotoFailed': Event<ClientPhotoCropMeta>` - fired when loading and crop of photo provided by user is failed
  - ```typescript
    type ClientPhotoCropMeta = {
      inputWidth: number;
      inputHeight: number;
      outputWidth: number;
      outputHeight: number;
      outputSize: number; // bytes
      minCropSize: number; // 512px
    };
    ```
- `'clientPhotoRemove': Event` - fired after user removes own photo
- `'signStart': Event` - fired when sign request sent
- `'signFinish': Event` - fired when sign request get success response
- `'signError': Event` - fired when sign request failed
- `'fittingStart': Event` - fired when the Fitting starts
- `'fittingFinish': Event` - fired when the Fitting was finished successfully
- `'fittingError': Event` - fired when the Fitting was failed
- `'measureStart': Event<MeasureStartMeta>` - fired when the measure starts
  - ```typescript
    type MeasureStartMeta = {
      height: number;
    };
    ```
- `'measureFinish': Event<MeasureFinishMeta>` - fired when the measure starts
  - ```typescript
    type MeasureFinishMeta = {
      gender: 'female' | 'male' | 'neutral';
      size: string;
    };
    ```
- `'measureError': Event` - fired when the measure was failed
- `'resultPhotoLoaded': Event<SuccessResultMeta>` - fired when the Fitting was finished successfully, and the resulting image was shown to user
  - ```typescript
    type SuccessResultMeta = {
      src: string;
    };
    ```
- `'resultPhotoFailed': Event<FailedResultMeta>` - fired when the Fitting was finished successfully, but the resulting image was not shown to user
  - ```typescript
    type FailedResultMeta = {
      src: string;
    };
    ```
- `'download': Event` - fired when user was clicked on Download button
- `'toggleLike': Event<ToggleLikeMeta>`- fired when user toggle Like button
  - ```typescript
    type ToggleLikeMeta = {
      liked: number;
    };
    ```
- `'continueShopping': Event` - fired when user was clicked on Continue Shopping button
- `'close': Event` - fired when user was closed Varvara App or clicked Continue shopping

### Object `Fitting`

A `Fitting` object has the following structure:

```typescript
type Fitting = {
  // Unique ID generates when varvaraSdk.tryOn() method invokes
  fittingId: string;

  // Clothes image was provided at the moment of varvaraSdk.tryOn() method was invoked
  clothesSrc: string;

  // Contain inforamtion about successed fitting
  result: { src: string } | null;

  // Status of fitting
  status: FittingStatus;

  // User timestamp of open Varvara App
  openTimestamp: number;

  // User timestamp of close Varvara App. Default value is 0
  closeTimestamp: number;

  // Payload information was provided at the moment of varvaraSdk.tryOn() method was invoked
  payload: TryOnPayload;
};

type Result = {
  src: string;
};

type FittingStatus =
  | 'opened' // sets after 'open' event fires
  | 'closed' // sets after 'close' event fires and fitting has 'opened' status
  | 'pending' // sets after 'fittingStart' event fires
  | 'canceled' // sets after 'close' event fires and fitting has 'pending' status
  | 'failed' // sets after 'resultPhotoFailed' event fires
  | 'succeed'; // sets after 'resultPhotoLoaded' event fires
```

### Storages and cookies

SDK don't read or write any cookies on your site. Instead of this, SDK uses LocalStorage to store `logLevel` value and
generate unique `browserGuid`.

## Secure fitting

You have to control every fitting. You need to generate a signature on your backend, and a trusted user should use this signature to start a new fitting.

The signature is an [HMAC/SHA256](https://en.wikipedia.org/wiki/HMAC) with two parameters:

- `signature` — a generated signature
- `date` — signature generation date (use ISO 8601 in UTC)
- `publicKey` - your api public key

```javascript
const crypto = require('crypto');

function generateSignature(secret, fittingId, date) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(`${fittingId}:${date}`);
  return hmac.digest('hex');
}

// secret key
const secret = 'project_secret_key';

// define expiry (e.g. 120 seconds)
const date = new Date().toISOString();
const signature = generateSignature(secret, fittinId, date);
```

Your signature endpoint should receive POST requests and response should be json like this

```js
{
  date: "2022-02-12T04:42:56.666Z"
  publicApiKey: "Kgw7jvGHLxK7lV5HZr2nvy2a09d3LoJV"
  signature: "e7f168df02ad437f94f2082d8d12a477d49896a7"
}
```

Set up your endpoint before working with fittings

```js
varvaraSdk.setConfig({
  signEndpoint: 'https://demo.varvara.ai/api/fitting/sign',
});
```

### Debug

Set log level to get more console information

```typescript

varvaraSdk.setConfig({ level: LogLevelDesc }); // Default value is 'warn'
```
### Debug



```typescript
type LogLevelDesc = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
varvaraSdk.setConfig({ level: LogLevelDesc }); // Default value is 'warn'
```


## Config

```ts
type LogLevelDesc = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';

// default values
varvaraSdk.setConfig({
  signEndpoint: '', // Paste your own sign endpoint
  lng: 'en', // Avaliable languages: 'en' | 'ru',
  logLevel: 'warn', // Set log level to get more console information (see type LogLevelDesc)
  publicApiKey: '' // Paste your project`s publicApiKey
});
```

## Compatibility

A [Promise polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) is required in browsers missing native promise support.
