npm package: @gearbox-built/sanity-vimeo
Description: An integration with Vimeo API to pull video data into Sanity Studio
Author: Gearbox Built
Latest version: 1.1.0

# @gearbox-built/sanity-vimeo

A modern Sanity Studio v3/v4 plugin that integrates with the Vimeo API, allowing content editors to search and select Vimeo videos directly within the Sanity Studio interface.

## Features

### v1.0 Highlights

✨ **Modern API Integration**
- Vimeo API v3.4 with optimized field selection
- Exponential backoff retry logic for rate limits
- 30-second timeout for network requests
- Comprehensive error handling with actionable messages

🎨 **Enhanced User Experience**
- Real-time search with 200ms debounce
- Context-aware loading states and helpful hints
- Visual indicators for playable status, privacy restrictions
- Aspect ratio display (16:9, 9:16, etc.)
- Upload date and duration metadata

🔒 **Privacy & Security**
- Visual badges for password-protected videos
- Embedding restriction indicators
- Private video detection
- Clear API key validation messages

🚀 **Performance & Compatibility**
- React 18/19 support
- Sanity v3/v4 compatibility
- TypeScript 5 with strict mode
- Comprehensive test coverage (42 tests)
- Backwards compatible with v0.x data

## Requirements

- **Node.js**: `>=20.19`
- **React**: `^18.0.0 || ^19.0.0`
- **Sanity**: `^3 || ^4`
- **Vimeo API Key**: Required for authentication

## Installation

```bash
npm install @gearbox-built/sanity-vimeo
```

Or with yarn:

```bash
yarn add @gearbox-built/sanity-vimeo
```

## Getting Your Vimeo API Key

1. Go to [Vimeo Developer Console](https://developer.vimeo.com/apps)
2. Create a new app or select an existing one
3. Generate a new access token with the following scopes:
   - `public` - Read public video data
   - `private` - Read private video data (if needed)
4. Copy the access token - you'll use this as your API key

**Important**: Keep your API key secure. Never commit it to version control.

## Configuration

### Step 1: Environment Variables

Add your Vimeo API key to your environment variables:

```bash
# .env.local
SANITY_STUDIO_VIMEO_API_KEY=your_vimeo_access_token_here
```

### Step 2: Plugin Configuration

Add the plugin to your `sanity.config.ts` (or `.js`):

```ts
import {defineConfig} from 'sanity'
import vimeoPlugin from '@gearbox-built/sanity-vimeo'

export default defineConfig({
  // ... other config
  plugins: [
    vimeoPlugin({
      apiKey: process.env.SANITY_STUDIO_VIMEO_API_KEY || '',
    }),
  ],
})
```

### Step 3: Add to Your Schema

Use the `vimeoVideo` type in your document schemas:

```ts
import {defineType, defineField} from 'sanity'

export default defineType({
  name: 'myDocument',
  type: 'document',
  title: 'My Document',
  fields: [
    defineField({
      name: 'video',
      type: 'vimeoVideo',
      title: 'Featured Video',
      description: 'Search and select a video from your Vimeo library',
    }),
    // ... other fields
  ],
})
```

## Usage

### Searching for Videos

1. Open a document with a `vimeoVideo` field
2. Click on the video input field
3. Type at least 3 characters to search your Vimeo library
4. Select a video from the dropdown

The plugin provides helpful feedback:
- **< 3 characters**: "Type at least 3 characters to search videos"
- **Loading**: "Searching your Vimeo library..."
- **No results**: "No videos found. Try different keywords or check your spelling."
- **> 25 results**: Shows info notification suggesting to refine search

### Video Data Structure

Selected videos are stored with the following structure:

```typescript
{
  _type: 'vimeoVideo',
  name: 'Video Title',
  description: 'Video description',
  link: 'https://vimeo.com/123456789',
  duration: 120, // seconds
  width: 1920,
  height: 1080,
  aspectRatio: 0.5625,
  created_time: '2024-01-15T10:30:00+00:00',
  modified_time: '2024-01-15T10:30:00+00:00',
  release_time: '2024-01-15T10:30:00+00:00',
  resource_key: 'video123',
  status: 'available',
  is_playable: true,
  manage_link: 'https://vimeo.com/manage/videos/123456789',
  pictures: {
    sizes: [
      {
        width: 640,
        height: 360,
        link: 'https://i.vimeocdn.com/video/...',
      },
      // ... more sizes
    ],
  },
  files: [
    {
      quality: 'hd',
      type: 'video/mp4',
      width: 1920,
      height: 1080,
      link: 'https://player.vimeo.com/...',
      size: 52428800,
    },
    // ... more files
  ],
  privacy: {
    view: 'anybody',
    embed: 'public',
  },
}
```

### Querying Videos in GROQ

```groq
*[_type == "myDocument"] {
  _id,
  title,
  video {
    name,
    link,
    duration,
    "thumbnail": pictures.sizes[0].link,
    "aspectRatio": aspectRatio
  }
}
```

## Migration from v0.x

### Upgrading to v1.0

If you're upgrading from version 0.x, **your existing data is safe**. We've maintained backwards compatibility.

#### What Changed

- **Field name**: `file` → `files` (both fields exist for compatibility)
- **React support**: Added React 19 support alongside React 18
- **Node.js requirement**: Now requires Node.js >=20.19
- **API improvements**: Modern Vimeo API v3.4 with better error handling

#### Migration Options

You have three options for migrating your data:

**Option A: Re-selection (Easiest)**
- Open documents and re-select videos
- No scripts needed
- Safe and gradual

**Option B: Batch Migration**
- Use Sanity CLI migrations
- Automated for all documents
- Recommended for large datasets

**Option C: GROQ Patch Script**
- Full control with custom script
- Good for complex scenarios

📖 **Full Migration Guide**: See [MIGRATION_v1.md](./MIGRATION_v1.md) for detailed instructions and code examples.

#### Do I Need to Migrate Immediately?

**No.** Your existing videos will continue to work without any changes. Migration is recommended but not urgent. We'll maintain backwards compatibility for a long time (2+ years notice before any breaking changes).

### Backwards Compatibility Details

For a comprehensive analysis of backwards compatibility, see [BACKWARDS_COMPATIBILITY.md](./BACKWARDS_COMPATIBILITY.md).

## Error Handling

The plugin provides clear, actionable error messages:

| Error | Message | Action |
|-------|---------|--------|
| Missing API Key | "No Vimeo API Key Found" | Check your .env file |
| Invalid API Key (401) | "Invalid API Key" | Verify your Vimeo API credentials |
| Permission Denied (403) | "Permission Denied" | Check API key permissions in Vimeo |
| Rate Limit (429) | "Rate Limit Exceeded" | Automatically retries with backoff |
| Timeout (408) | "Request Timed Out" | Check network connection |
| Server Error (5xx) | "Vimeo Service Unavailable" | Try again later |

All errors include specific guidance on how to resolve them.

## Development

### Building

```bash
yarn build
```

Runs the full build pipeline: cleans dist, verifies package, builds with pkg-utils in strict mode.

### Development with Hot Reload

```bash
yarn watch
```

Runs pkg-utils in watch mode with strict type checking for active development.

### Testing

```bash
# Run all tests
yarn test

# Run tests in watch mode
yarn test:watch

# Run tests with UI
yarn test:ui

# Generate coverage report
yarn test:coverage
```

### Code Quality

```bash
# Run linter
yarn lint

# Format code
yarn format
```

### Link to Another Studio

To test the plugin in another Sanity Studio with hot reload:

```bash
yarn link-watch
```

Then in your test Studio:

```bash
yarn link @gearbox-built/sanity-vimeo
```

See [@sanity/plugin-kit docs](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio) for more details.

## API Key Best Practices

### Security

1. **Never commit API keys** to version control
2. **Use environment variables** for all environments
3. **Rotate keys regularly** if you suspect compromise
4. **Use minimal permissions** - only grant necessary scopes

### Rate Limits

The plugin automatically handles Vimeo's rate limits:

- **Exponential backoff** - Retries with increasing delays
- **Retry-After header** - Respects Vimeo's suggested retry time
- **Max retries** - Up to 3 automatic retries for rate limits
- **Warning logs** - Console warnings when rate limit is low (< 10 requests remaining)

### Performance Optimization

The plugin uses several strategies to minimize API calls:

- **Debouncing** - 200ms delay prevents excessive API calls while typing
- **Minimum query length** - Requires 3+ characters before searching
- **Field selection** - Only requests needed fields to improve rate limit capacity
- **SWR caching** - Caches responses to reduce duplicate requests

## Troubleshooting

### Videos Not Loading

1. **Check API key**: Ensure `SANITY_STUDIO_VIMEO_API_KEY` is set correctly
2. **Check network**: Open browser DevTools → Network tab
3. **Check permissions**: Verify API key has proper scopes in Vimeo
4. **Check rate limits**: Look for 429 errors in console

### Search Not Working

1. **Type 3+ characters**: Search requires minimum 3 characters
2. **Wait for debounce**: 200ms delay after typing
3. **Check query**: Try simpler search terms
4. **Check API response**: Look for errors in console

### Private Videos Not Appearing

1. **Check API key scopes**: Ensure `private` scope is enabled
2. **Check video privacy**: Verify video settings in Vimeo
3. **Look for privacy badges**: Plugin shows 🔒 icon for restricted videos

## License

[MIT](LICENSE) © Gearbox Built

## Support

- **Issues**: [GitHub Issues](https://github.com/gearbox-built/housing/issues)
- **Documentation**: See MIGRATION_v1.md and BACKWARDS_COMPATIBILITY.md
- **API Reference**: [Vimeo API Docs](https://developer.vimeo.com/api/reference)

## Credits

Developed and maintained by [Gearbox Built](https://gearboxbuilt.com)

---

**Note**: This plugin requires a Vimeo account and API access. Vimeo's API is subject to rate limits and terms of service.