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

# Node.js SDK Migration

> Upgrade from v0.1.3 to v0.2.0: a cleaner API with direct property access and async/await

If you're upgrading from v0.1.3, this guide walks you through the two breaking changes you need to address. The migration is straightforward (mostly find-and-replace).

## What Changed

| Pattern          | Before (v0.1.3)                     | After (v0.2.0)                               |
| :--------------- | :---------------------------------- | :------------------------------------------- |
| Property Access  | `video.meta.id`                     | `video.id`                                   |
| Async Operations | `waitForJob(video.getTranscript())` | `await video.getTranscript()`                |
| Uploads          | Returns `UploadJob`                 | Returns `Video` / `Audio` / `Image` directly |
| Error Handling   | `.on('error', callback)`            | Standard `try/catch`                         |

***

## Breaking Change 1: Direct Property Access

In v0.1.3, all properties were wrapped in a `.meta` object. In v0.2.0, properties are accessed directly on the instance.

### Video

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  const video = await collection.getVideo('m-123');

  console.log(video.meta.id);           // 'm-123'
  console.log(video.meta.name);         // 'My Video'
  console.log(video.meta.streamUrl);    // 'https://stream.videodb.io/...'
  console.log(video.meta.playerUrl);    // 'https://console.videodb.io/player?...'
  console.log(video.meta.length);       // 120.5
  console.log(video.meta.collectionId); // 'c-123'

  const url = `https://example.com/video/${video.meta.id}`;
  ```

  ```typescript After (v0.2.0) theme={null}
  const video = await collection.getVideo('m-123');

  console.log(video.id);           // 'm-123'
  console.log(video.name);         // 'My Video'
  console.log(video.streamUrl);    // 'https://stream.videodb.io/...'
  console.log(video.playerUrl);    // 'https://console.videodb.io/player?...'
  console.log(video.length);       // 120.5
  console.log(video.collectionId); // 'c-123'

  const url = `https://example.com/video/${video.id}`;
  ```
</CodeGroup>

### Audio

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  const audio = await collection.getAudio('a-123');

  console.log(audio.meta.id);           // 'a-123'
  console.log(audio.meta.name);         // 'podcast.mp3'
  console.log(audio.meta.length);       // 3600.0
  console.log(audio.meta.collectionId); // 'c-123'
  ```

  ```typescript After (v0.2.0) theme={null}
  const audio = await collection.getAudio('a-123');

  console.log(audio.id);           // 'a-123'
  console.log(audio.name);         // 'podcast.mp3'
  console.log(audio.length);       // 3600.0
  console.log(audio.collectionId); // 'c-123'
  ```
</CodeGroup>

### Image

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  const image = await collection.getImage('img-123');

  console.log(image.meta.id);           // 'img-123'
  console.log(image.meta.name);         // 'thumbnail.png'
  console.log(image.meta.url);          // 'https://...'
  console.log(image.meta.collectionId); // 'c-123'
  ```

  ```typescript After (v0.2.0) theme={null}
  const image = await collection.getImage('img-123');

  console.log(image.id);           // 'img-123'
  console.log(image.name);         // 'thumbnail.png'
  console.log(image.url);          // 'https://...'
  console.log(image.collectionId); // 'c-123'
  ```
</CodeGroup>

### Collection

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  const collection = await conn.getCollection('c-123');

  console.log(collection.meta.id);          // 'c-123'
  console.log(collection.meta.name);        // 'My Videos'
  console.log(collection.meta.description); // 'Collection description'

  const videos = await fetchVideos(collection.meta.id);
  ```

  ```typescript After (v0.2.0) theme={null}
  const collection = await conn.getCollection('c-123');

  console.log(collection.id);          // 'c-123'
  console.log(collection.name);        // 'My Videos'
  console.log(collection.description); // 'Collection description'

  const videos = await fetchVideos(collection.id);
  ```
</CodeGroup>

### Shot (Search Results)

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  const results = await video.search('hello world');

  for (const shot of results.shots) {
    console.log(shot.meta.videoId);     // 'm-123'
    console.log(shot.meta.start);       // 10.5
    console.log(shot.meta.end);         // 15.2
    console.log(shot.meta.text);        // 'hello world example'
    console.log(shot.meta.searchScore); // 0.95
  }
  ```

  ```typescript After (v0.2.0) theme={null}
  const results = await video.search('hello world');

  for (const shot of results.shots) {
    console.log(shot.videoId);     // 'm-123'
    console.log(shot.start);       // 10.5
    console.log(shot.end);         // 15.2
    console.log(shot.text);        // 'hello world example'
    console.log(shot.searchScore); // 0.95
  }
  ```
</CodeGroup>

<Tip>
  **Migration shortcut:** Search your codebase for `.meta.` and replace with `.`
  for each class type.
</Tip>

***

## Breaking Change 2: Async/Await Pattern

In v0.1.3, long-running operations returned `Job` objects that required callback registration. In v0.2.0, these are standard async functions. The SDK handles polling internally, errors propagate through `try/catch`, and there's no risk of silent failures from unregistered error handlers.

### Getting Transcripts

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  import { waitForJob } from 'videodb';

  // Option 1: Using callbacks
  const job = video.getTranscript();

  job.on('success', (transcript) => {
    console.log('Transcript:', transcript);
  });

  job.on('error', (err) => {
    console.error('Failed:', err);
  });

  await job.start();

  // Option 2: Using waitForJob helper
  const transcript = await waitForJob(video.getTranscript(true));
  ```

  ```typescript After (v0.2.0) theme={null}
  // No imports needed - async/await is built-in

  // Just await the method directly
  // SDK handles polling internally
  const transcript = await video.getTranscript();

  // Success! Use the result immediately
  console.log('Transcript:', transcript);

  // Errors? Use standard try/catch (see Error Handling section)




  ```
</CodeGroup>

### Indexing Spoken Words

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  import { waitForJob } from 'videodb';

  const indexJob = video.indexSpokenWords();

  indexJob.on('success', (result) => {
    console.log('Indexing complete:', result.success);
  });

  indexJob.on('error', (err) => {
    console.error('Indexing failed:', err);
  });

  await indexJob.start();
  ```

  ```typescript After (v0.2.0) theme={null}
  // No imports needed

  // Await the indexing operation directly
  const result = await video.indexSpokenWords();

  // SDK polls until complete, then returns
  console.log('Indexing complete:', result.success);



  ```
</CodeGroup>

### Uploading Media

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  import { waitForJob } from 'videodb';

  const uploadJob = await collection.uploadFile({
    filePath: '/path/to/video.mp4',
    name: 'My Video',
  });

  uploadJob.on('success', (video) => {
    console.log('Video ID:', video.meta.id);
  });

  uploadJob.on('error', (err) => {
    console.error('Upload failed:', err);
  });

  await uploadJob.start();
  ```

  ```typescript After (v0.2.0) theme={null}
  // No imports needed

  // Upload returns the Video object directly
  const video = await collection.uploadFile({
    filePath: '/path/to/video.mp4',
    name: 'My Video',
  });

  // Video is ready to use immediately
  console.log('Video ID:', video.id);



  ```
</CodeGroup>

### Error Handling

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  import { waitForJob } from 'videodb';

  const job = video.getTranscript();

  job.on('success', (transcript) => {
    console.log('Got transcript:', transcript);
  });

  job.on('error', (err) => {
    // If you forget this handler, errors are silently logged
    console.error('Transcript failed:', err);
    notifyUser('Could not generate transcript');
  });

  await job.start();
  ```

  ```typescript After (v0.2.0) theme={null}
  // No imports needed

  // Standard try/catch - errors can't be silently ignored
  try {
    const transcript = await video.getTranscript();
    console.log('Got transcript:', transcript);
  } catch (err) {
    // Errors bubble up naturally
    console.error('Transcript failed:', err);
    notifyUser('Could not generate transcript');
  }
  ```
</CodeGroup>

***

## Removed Exports

The following exports no longer exist in v0.2.0:

```typescript theme={null}
// These imports will fail in v0.2.0
import {
  Job, // REMOVED
  TranscriptJob, // REMOVED
  UploadJob, // REMOVED
  IndexJob, // REMOVED
  waitForJob, // REMOVED
} from "videodb";
```

<Warning>
  If your code imports any of these, remove the imports and refactor to use
  `await` directly on the method calls.
</Warning>

***

## Migration Checklist

### Property Access

<Steps>
  <Step title="Search for .meta. patterns">
    Use your IDE or grep to find all occurrences of `.meta.` in your codebase.
  </Step>

  <Step title="Replace with direct access">
    * `video.meta.*` → `video.*` - `audio.meta.*` → `audio.*` - `image.meta.*` →
      `image.*` - `collection.meta.*` → `collection.*` - `shot.meta.*` → `shot.*`
  </Step>
</Steps>

### Job Pattern

<Steps>
  <Step title="Remove Job imports">
    Delete imports for `Job`, `TranscriptJob`, `UploadJob`, `IndexJob`,
    `waitForJob`
  </Step>

  <Step title="Remove callback registrations">
    Delete `.on('success', ...)` and `.on('error', ...)` blocks
  </Step>

  <Step title="Remove .start() calls">
    Delete any `job.start()` or `await job.start()` calls
  </Step>

  <Step title="Add await to method calls">
    Change `const job = video.getTranscript()` to `const transcript = await
            video.getTranscript()`
  </Step>

  <Step title="Update error handling">
    Wrap calls in `try/catch` instead of using `.on('error', ...)`
  </Step>
</Steps>

***

## Complete Example

<CodeGroup>
  ```typescript Before (v0.1.3) theme={null}
  import { connect, waitForJob } from 'videodb';

  async function processVideo() {
    const conn = connect(process.env.VIDEO_DB_API_KEY);
    const collection = await conn.getCollection();

    // Upload
    const uploadJob = await collection.uploadFile({
      filePath: './video.mp4',
      name: 'My Video',
    });
    const video = await waitForJob(uploadJob);
    console.log('Uploaded:', video.meta.id);

    // Transcript
    const transcriptJob = video.getTranscript();
    const transcript = await waitForJob(transcriptJob);

    // Index
    const indexJob = video.indexSpokenWords();
    await waitForJob(indexJob);

    // Search
    const results = await video.search('keyword');
    for (const shot of results.shots) {
      console.log(`${shot.meta.start}s: ${shot.meta.text}`);
    }
  }
  ```

  ```typescript After (v0.2.0) theme={null}
  import { connect } from 'videodb';

  async function processVideo() {
    const conn = connect(process.env.VIDEO_DB_API_KEY);
    const collection = await conn.getCollection();

    // Upload - returns Video directly
    const video = await collection.uploadFile({
      filePath: './video.mp4',
      name: 'My Video',
    });
    console.log('Uploaded:', video.id);

    // Transcript - just await
    const transcript = await video.getTranscript();

    // Index - just await
    await video.indexSpokenWords();

    // Search
    const results = await video.search('keyword');
    for (const shot of results.shots) {
      console.log(`${shot.start}s: ${shot.text}`);
    }
  }
  ```
</CodeGroup>

***

## Need Help?

<CardGroup cols={2}>
  <Card icon="github" title="GitHub Issues" href="https://github.com/video-db/videodb-node/issues">
    Report bugs or ask questions
  </Card>

  <Card icon="discord" title="Discord Community" href="https://discord.com/invite/py9P639jGz">
    Get help from the community
  </Card>
</CardGroup>
