# Autorender JavaScript SDK

[![npm version](https://img.shields.io/npm/v/@autorender/js)](https://www.npmjs.com/package/@autorender/js)
[![CI](https://github.com/autorender/autorender-js/workflows/CI/badge.svg)](https://github.com/autorender/autorender-js/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Follow on X](https://img.shields.io/twitter/follow/AutoRenderHQ?label=Follow&style=social)](https://x.com/AutoRenderHQ)

## Introduction

Autorender JavaScript SDK provides a simple way to integrate Autorender with any JavaScript or TypeScript application. It allows you to:

- Upload files with a fully-featured, customizable upload widget
- Serve optimized images and videos via the ViewTag SDK — automatic format selection, responsive sizes, and real-time transformations
- Apply powerful transformations (crop, resize, effects, overlays, and more) via URL parameters

For framework adapters, see `@autorender/react`, `@autorender/vue`, `@autorender/nextjs`, `@autorender/svelte`, and `@autorender/angular`.

## TypeScript support

The SDK is written in TypeScript with full type definitions included. No additional `@types` packages needed.

> **Browser-only:** The upload widget and ViewTag APIs use browser globals (`document`, `window`, XHR). In SSR frameworks (Next.js, Nuxt, SvelteKit), call `createUploader` / `createAR` inside `useEffect` / `onMounted`, or use your framework's client-only boundary.

## Installation

```bash
npm install @autorender/js
```

## Authentication

- **Upload API key**: Required for the upload widget. Never hardcode it in source — use an environment variable (e.g. `VITE_AUTORENDER_KEY`, `REACT_APP_AUTORENDER_KEY`) loaded at build time, or a server-side route that vends short-lived tokens. Scope and rotate keys in the Autorender dashboard.
- **Workspace**: The `workspace` value is not secret; it appears in public image URLs.
- **ViewTag (ARImage / createAR)**: No API key required — image delivery is public CDN.

## Upload SDK Usage

```javascript
import { createUploader } from '@autorender/js';
import '@autorender/js/styles';

const uploader = createUploader({
  apiKey: 'your-api-key',
  target: '#uploader-container',
  type: 'inline',
  allowMultiple: true,
  onSuccess: ({ files }) => {
    console.log('Uploaded:', files);
  },
});
```

## ViewTag SDK Usage

### Basic Setup

```javascript
import { createAR } from '@autorender/js/viewtag';

const AR = createAR({
  baseUrl: 'https://assets.autorender.io',
  workspace: 'ws_123',
  defaults: { f: 'auto', q: 'auto' }
});
```

### Generate Image URLs

```javascript
// Simple URL generation
const url = AR.url('products/shoe.jpg', {
  w: 400,
  h: 400,
  fit: 'cover'
});
// Output: https://assets.autorender.io/ws_123/w_400,h_400,c_fill,f_auto,q_auto/products/shoe.jpg

// Get transformation string only
const transformString = AR.transformString({ w: 300, h: 300, fit: 'cover', q: 70 });
// Output: w_300,h_300,c_fill,q_70

```

### Generate Video URLs

```javascript
// MP4
const mp4Url = AR.url('docs/skateboarding.mp4', { w: 960, h: 540 });

// HLS master playlist
const hlsUrl = AR.url('st_240_360_480_720/docs/skateboarding.mp4/ar-master.m3u8');

// DASH manifest
const dashUrl = AR.url('processing/docs/skateboarding.mp4/dash/manifest.mpd');
```

### Video transformations

```javascript
// Trim: start at 2s, end at 8s
const trimUrl = AR.url('docs/skateboarding.mp4', { so: 2, eo: 8 });

// Thumbnail frame (delivers as image — use in <img>, not <video>)
const thumbUrl = AR.url('docs/skateboarding.mp4', { thumb_ar: true });

// Animated GIF (delivers as image)
const gifUrl = AR.url('docs/skateboarding.mp4', { f: 'gif' });

// Pad to 16:9 with white background
const padUrl = AR.url('docs/skateboarding.mp4', {
  ar: '16:9',
  cm_pad_resize: true,
  bg: 'white',
});

// Flip horizontal
const flipUrl = AR.url('docs/skateboarding.mp4', { flip: 'h' });
```


### `<ARVideo>` and Video.js

Framework adapters expose an `<ARVideo>` component that wraps Video.js. Install it in **your app** (not bundled inside the SDK):

```bash
npm install video.js
```

Each adapter exposes `<ARVideo>` on its own entry point (`@autorender/react/viewtag/video` and equivalents), separate from the `viewtag` barrel, so image-only apps never resolve `video.js` at build time. Playback itself is lazy-loaded via `@autorender/js/viewtag/load-videojs` when the component mounts. Upload-only and image-only integrations do not need Video.js.

### Responsive Images

```javascript
// Generate responsive image attributes
const attrs = AR.responsiveImageAttributes({
  src: 'hero.jpg',
  width: 400,
  sizes: '(min-width: 800px) 33vw, 100vw'
});

// Returns: { src, srcSet, sizes, width }
```

### Device Detection

```javascript
// Get device pixel ratio
const dpr = AR.getDPR(); // 1 or 2
```

## API Reference

### `createAR(config: CreateARConfig): ARInstance`

Creates a new AutoRender client instance for image transformations.

**Config Options:**
- `baseUrl?: string` - Base URL (default: `'https://assets.autorender.io'`)
- `workspace: string` - Your workspace ID
- `defaults?: { f?: string, q?: string | number }` - Default transformations
- `deviceBreakpoints?: number[]` - Device breakpoints for responsive images
- `imageBreakpoints?: number[]` - Image breakpoints for responsive images

### `ARInstance`

- `url(src: string, transform?: TransformOptions): string` - Generate transformed image URL
  - `src` supports workspace paths (e.g., `products/shoe.jpg`) and absolute remote URLs (e.g., `https://example.com/image.jpg`).
- `transformString(transform: TransformOptions): string` - Get transformation string only
- `responsiveImageAttributes(options: ResponsiveOptions): ResponsiveAttributes` - Generate responsive image attributes
- `getDPR(): number` - Get device pixel ratio (1 or 2)

## ViewTag API Reference

### Format detection (`f: 'auto'`)

When `defaults.f` or a transform sets `f: 'auto'`, the SDK detects the best supported format synchronously in the browser:

1. Priority: AVIF → WebP → JPEG
2. Result is cached after the first detection
3. Applied to the transformation string as `f_avif`, `f_webp`, or `f_jpg`
4. Falls back to WebP if detection fails; no-ops during SSR

### Device pixel ratio (`enableDPR`)

`enableDPR: true` (default) adds a `2x` candidate to the `srcset` that `responsiveImageAttributes()` returns. Set it to `false` to emit the `1x` candidate only.

`url()` and `transformString()` never read `window.devicePixelRatio`. A single URL cannot be correct for every screen, and deriving it from the device produces a different string on the server than in the browser — a hydration mismatch on `src`, plus a second network fetch. Retina is handled by the `2x` candidate the browser picks. Set `dpr` explicitly in `TransformOptions` when you want a fixed ratio in a one-off URL.

### Connection-aware quality (`q: 'auto'`)

When quality is `'auto'` and connection detection is enabled:

| Connection | Quality applied |
|------------|-----------------|
| 2g         | `q_50`          |
| 3g         | `q_70`          |
| 4g / wifi  | `q_auto`        |

Uses the Network Information API when available; falls back to `q_auto`. Override with an explicit `q` value.

### Transformation flow

1. Create an instance: `createAR({ workspace, defaults: { f: 'auto', q: 'auto' } })`
2. Call `AR.url(src, transform)` or `AR.transformString(transform)`
3. The builder merges width/height, applies auto format and quality, sorts parameters deterministically
4. URL shape: `{baseUrl}/{workspace}/{transformations}/{file_path}`

Example:

```
https://assets.autorender.io/ws_123/w_400,h_400,c_fill,f_webp,q_auto/products/shoe.jpg
```

### Responsive images

`responsiveImageAttributes()` generates `src`, `srcSet`, `sizes`, and `width` using configurable device and image breakpoints. Pass `breakpoints` per call to override the instance defaults.

The defaults are the widths the delivery edge serves exactly — `320, 480, 720, 1080, 1440, 1920` for devices, plus smaller sizes for images. Widths above **240 px** are snapped to the nearest of those rungs before the origin renders, so a custom breakpoint like `600` returns the same bytes as `720` under a second cache key. Pick rungs unless you have a reason not to.

When you pass `width` and no `sizes`, the result carries `1x` and `2x` candidates and the browser picks. When you pass `sizes`, candidates carry `w` descriptors, which already state each candidate's pixel width — no `dpr_` is emitted in that case, because the browser multiplies by the device ratio itself.

See the [full documentation](https://autorender.io/docs) for the complete upload API reference.

## Typed upload errors

`@autorender/js` exports:

- `AutorenderAuthError` — 401/403 (invalid API key)
- `AutorenderUploadError` — other HTTP failures (`statusCode` property)
- `AutorenderNetworkError` — network / XHR transport failures

```typescript
import { AutorenderAuthError, createUploader } from '@autorender/js';

try {
  await uploader.startUpload();
} catch (err) {
  if (err instanceof AutorenderAuthError) {
    // rotate or fix API key
  }
}
```

## Content Security Policy (CSP)

The upload widget injects styles into its **shadow DOM** via a `<style>` tag at runtime. If your CSP blocks inline styles, allow:

```
Content-Security-Policy: style-src 'self' 'unsafe-inline';
```

Styles are scoped to the widget shadow root and do not affect the host page.
