Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# Changelog

## [0.3.0] (2026-07-25)

Indexing v2 — a new retrieval architecture plus a generation/compute stack, ported from `videodb-python`'s `feat/add-indexing-v2`.

### Added

- **Search v2 on `Video` and `Collection`** — new `search()` dispatcher with dedicated `ask()`, `semanticSearch()`, `query()`, and `aggregate()` methods, returning the v2 `SearchResponse` / `AskResponse` envelopes (iterable `SearchResult`). `legacySearch()` preserves the old behavior behind a one-time deprecation warning
- **Understanding runs** — `Video.understand()` / `getUnderstanding()` / `listUnderstandings()` / `deleteUnderstanding()`, backed by new `Understanding` and `UnderstandingAnalyzer` classes and analyzer-normalization helpers (`normalizeUnderstandingAnalyzers`, `normalizeAnalyzerType`, `defaultAnalyzerName`)
- **Index manifest** — `Video.index()` / `getIndex()` / `listIndexes()` / `deleteIndex()`, backed by new `Index`, `IndexRecord`, `FieldSchema`, and `RecordPage` classes with `IndexCapability` and `FieldGroup` constants
- **Sandboxes (persistent GPU compute pools)** — `Connection.createSandbox()` / `getSandbox()` / `listSandboxes()`, a `Sandbox` class with `waitForReady()` / `stop()` / `waitForStop()` lifecycle polling, and `SandboxTier` / `SandboxStatus` constants
- **Async generation jobs** — `GenerationJob` with `wait()` polling, plus `Connection.getJobStatus()` and `waitForJob()`. `Collection.generateImage()` / `generateVoice()` / `generateText()` gain self-inference model routing (`SandboxModel`), `sandboxId`, and `wait` options, returning a `GenerationJob` when the server dispatches async work
- **Voice clones** — `VoiceClone` class and CRUD on both `Connection` and `Collection` (`createVoiceClone` / `getVoiceClone` / `listVoiceClones` / `deleteVoiceClone`), plus `voiceCloneId` support in `generateVoice()`
- **Real-time stream understanding & indexing** — new `RTStreamUnderstanding` and `RTStreamIndex` classes with `understand()` / `index()` on `RTStream`, alert management (`createAlert` / `listAlerts` / `enableAlert` / `disableAlert`), and record retrieval
- **Embed-code helpers** — `getEmbedCode()` on `Video`, `Shot`, `Timeline`, and RTStream types, plus `buildIframeEmbedCode()` / `playerUrlToEmbedUrl()` utilities. `Video`, `Shot`, and RTStream types now carry `playerUrl`
- **`sandboxId` threading** into `Video.indexScenes()` / `indexVisuals()`, `Scene.describe()` (also gains `modelConfig`), and all `RTStream` indexing methods, to route inference to a specific sandbox
- **`Connection.getAsyncResponse()`** to fetch a stored async response without polling

### Changed

- `HttpClient` `get`/`post` accept a `wait` flag and per-call poll overrides (`maxPollTime` / `pollInterval`); the async-output poll loop was rewritten from `backoff` to a monotonic-clock loop that throws `RequestTimeoutError` on timeout
- `uploadBytes()` helper added for in-memory uploads; `upload()` refactored to reuse it, and large `generateText()` prompts are now offloaded to a presigned URL (`prompt_url`) above ~250 KB to avoid gateway payload limits
- `ResponseStatus` gains `complete`; new `ApiPath` segments and polling defaults added

### Fixed

- `Sandbox.isReady` and `waitForReady()` now treat `alert` as a ready state (matching `videodb-python`'s `READY_STATUSES`) and no longer report `provisioning` as ready

---

## [0.2.7] (2026-06-03)

### Added
Expand Down
45 changes: 45 additions & 0 deletions docs/PR-feat-indexing-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Pull Request

**Description:**

Ports `videodb-python`'s `feat/add-indexing-v2` drop to the NodeJS SDK (`feat/indexing-v2` → `main`), bringing the SDK to parity across two related workstreams:

1. **Indexing v2** — a new retrieval architecture (Search v2 dispatcher, Understanding runs, and an Index manifest) that supersedes the legacy single-shot search.
2. **Generation / compute stack** — persistent GPU **sandboxes**, async **generation jobs** for self-inference TTS/image models, and reusable **voice clones**, wired into the `generate*` methods.

Also adds embed-code helpers and threads `sandboxId` through the inference-bearing methods. Bodies are authored in snake_case at the call site and responses are auto-camelCased by `HttpClient`, per existing SDK conventions; every new public symbol is re-exported from the `src/index.ts` barrel. Bumps the package `0.2.7` → `0.3.0` (minor) and updates the changelog.

Scope: 25 files changed, ~+3,700 / −133. New source modules: `understanding.ts`, `indexManifest.ts`, `job.ts`, `sandbox.ts`, `sandboxModels.ts`, `voiceClone.ts`, `search/responses.ts`.

**Changes:**
- [x] Search v2 on `Video` & `Collection` — `search()` dispatcher + `ask()` / `semanticSearch()` / `query()` / `aggregate()`, v2 `SearchResponse` / `AskResponse` envelopes, iterable `SearchResult`; `legacySearch()` behind a one-time deprecation warning
- [x] Understanding runs — `Understanding` + `UnderstandingAnalyzer` classes and `Video.understand()` / `getUnderstanding()` / `listUnderstandings()` / `deleteUnderstanding()`
- [x] Index manifest — `Index` / `IndexRecord` / `FieldSchema` / `RecordPage` and `Video.index()` / `getIndex()` / `listIndexes()` / `deleteIndex()`, with `IndexCapability` / `FieldGroup` constants
- [x] Sandboxes — `Sandbox` (lifecycle polling) + `Connection.createSandbox()` / `getSandbox()` / `listSandboxes()`, `SandboxTier` / `SandboxStatus` / `SandboxModel`
- [x] Generation jobs — `GenerationJob` + `Connection.getJobStatus()` / `waitForJob()`; `generateImage()` / `generateVoice()` / `generateText()` gain self-inference routing, `sandboxId`, and `wait`
- [x] Voice clones — `VoiceClone` CRUD on `Connection` and `Collection`; `voiceCloneId` in `generateVoice()`
- [x] RTStream understanding & indexing — `RTStreamUnderstanding` / `RTStreamIndex`, `understand()` / `index()`, alert management, record retrieval
- [x] Embed-code helpers — `getEmbedCode()` on `Video` / `Shot` / `Timeline` / RTStream, `buildIframeEmbedCode()` / `playerUrlToEmbedUrl()`, `playerUrl` fields
- [x] `sandboxId` threading into `Video.indexScenes()` / `indexVisuals()`, `Scene.describe()` (+ `modelConfig`), and RTStream indexing; `Connection.getAsyncResponse()`
- [x] Infra — `wait` flag + per-call poll overrides on `HttpClient`, monotonic-clock poll loop w/ `RequestTimeoutError`, `uploadBytes()` helper, `prompt_url` offload for large `generateText()` prompts
- [x] Bugfix: `Sandbox.isReady` / `waitForReady()` treat `alert` as ready (matching Python `READY_STATUSES`) and no longer report `provisioning` as ready
- [x] Version bump `0.2.7` → `0.3.0` + `CHANGELOG.md`

**Related Issues:**
- N/A

**Testing:**

Validated against the companion **`nodejs-test-suite`** (symlinked to this package's built `dist/`), across pure, mocked, and live-API layers:

- **Offline (pure + mock):** full suite green — sandbox constant/getter behavior, poll-loop branches (terminal-state, timeout, `alert`-resolves-ready), and `createSandbox` / `listSandboxes` wire payloads. `npm run typecheck` passes.
- **Live API:** `Sandbox` provision → wait-ready → stop lifecycle; `VoiceClone` CRUD (via `Connection` and `Collection`); `GenerationJob` polling; and all `generate*` methods (text, image, music, sound-effect, voice, video). The only live failures observed were pre-existing backend/account flakiness (semantic/title search, one upload stream-link generation, billing `getInvoices`) — unrelated to this change.

Re-test after merge: because this rebuilds the SDK `dist/`, downstream consumers of `search()` should confirm the v2 dispatcher / legacy fallback behaves as expected, and the sandbox-routed `generate*` paths should be smoke-tested once a sandbox is provisioned.

**Checklist:**
- [x] Code follows project coding standards
- [x] Tests have been added or updated
- [ ] Code Review
- [ ] Manual test after merge
- [ ] All checks passed
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "videodb",
"version": "0.2.7",
"version": "0.3.0",
"description": "A NodeJS wrapper for VideoDB's API written in TypeScript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
60 changes: 60 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,68 @@ export const ApiPath = {
start: 'start',
stop: 'stop',
export: 'export',
// indexing-v2 additions
indexes: 'indexes',
records: 'records',
understand: 'understand',
ask: 'ask',
semantic_search: 'semantic-search',
query: 'query',
aggregate: 'aggregate',
job: 'job',
sandbox: 'sandbox',
voice_clone: 'voice_clone',
identities: 'identities',
merge: 'merge',
split: 'split',
async_response: 'async-response',
} as const;

/**
* Retrieval capabilities an index can be built for (the `use_for` values).
*/
export const IndexCapability = {
semantic: 'semantic',
query: 'query',
aggregate: 'aggregate',
} as const;

/**
* Field groups that map artifact fields to retrieval capabilities.
*/
export const FieldGroup = {
semantic: 'semantic',
fts: 'fts',
filter: 'filter',
aggregate: 'aggregate',
sort: 'sort',
} as const;

/**
* Compute tier a sandbox can be provisioned at.
*/
export const SandboxTier = {
small: 'small',
medium: 'medium',
} as const;

/**
* Lifecycle status of a sandbox.
*/
export const SandboxStatus = {
provisioning: 'provisioning',
active: 'active',
stopping: 'stopping',
stopped: 'stopped',
failed: 'failed',
alert: 'alert',
} as const;

export const ResponseStatus = {
processing: 'processing',
in_progress: 'in progress',
success: 'success',
complete: 'complete',
} as const;

export const MeetingStatus = {
Expand Down Expand Up @@ -190,6 +246,10 @@ export const HttpClientDefaultValues = {
max_retries: 3,
timeout: 60 * 1000,
backoff_factor: 0.1,
/** Max time (ms) to poll an async output URL before timing out. */
maxPollTime: 500 * 1000,
/** Interval (ms) between polls of an async output URL. */
pollInterval: 5 * 1000,
} as const;

export const MaxSupported = {
Expand Down
Loading
Loading