Skip to content
Merged
23 changes: 21 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
# Changelog

## [0.2.1] (2026-03-10)
## [0.2.2] (2026-03-10)

### Added

- RTStream `generateStream(start, end, playerConfig?)` now supports `playerConfig.title`, `playerConfig.description`, and `playerConfig.slug` for player share metadata.
- RTStream `generateStream()` now returns `playerUrl` and stores both `streamUrl` and `playerUrl`
- RTStream `playerConfig` parameter with `title`, `description`, and `slug` for player share metadata
- CaptureSession `channels`, `primaryVideoChannelId`, and `exportStatus` properties
- CaptureSession `displays` getter for video channels
- CaptureSession `export()` method with optional `videoChannelId` and `wsConnectionId`

### Changed

- Updated capture binary to v0.2.8 with new checksums
- Binary distribution URL migrated to CloudFront (`https://artifacts.videodb.io/capture`)

---

## [0.2.1] (2026-02-06)

### Changed

- Binary distribution URL migrated and checksum updates

---

## [0.2.0] (2026-02-02)

Expand Down
50 changes: 44 additions & 6 deletions lib/installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ const fs = require('fs');
const path = require('path');
const https = require('https');
const crypto = require('crypto');
const { execFileSync } = require('child_process');
const tar = require('tar');

const MACOS_APP_BUNDLE = 'VideoDBCapture.app';

class Installer {
constructor(config) {
this.config = config;
Expand All @@ -19,18 +22,32 @@ class Installer {

getDownloadUrl() {
const platformKey = `${this.platform}-${this.arch}`;
return `${this.config.baseUrl}/v${this.config.version}/recorder-${platformKey}.tar.gz`;
return `${this.config.baseUrl}/v${this.config.version}/capture-${platformKey}.tar.gz`;
}

getExpectedChecksum() {
const platformKey = `${this.platform}-${this.arch}`;
return this.config.checksums[platformKey];
}

getBinaryPath() {
if (this.platform === 'darwin') {
return path.join(this.binDir, MACOS_APP_BUNDLE, 'Contents', 'MacOS', 'capture');
} else if (this.platform === 'win32') {
return path.join(this.binDir, 'capture.exe');
}
return path.join(this.binDir, 'capture');
}

async downloadFile(url, destPath) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(destPath);
https.get(url, (response) => {
const options = {
headers: {
'User-Agent': 'videodb-node-installer'
}
};
https.get(url, options, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
file.close();
fs.unlinkSync(destPath);
Expand Down Expand Up @@ -75,7 +92,7 @@ class Installer {
}

async install() {
console.log(`Installing VideoDB Recorder for ${this.platform}-${this.arch}...`);
console.log(`Installing VideoDB Capture for ${this.platform}-${this.arch}...`);

if (!this.isPlatformSupported()) {
const platformKey = `${this.platform}-${this.arch}`;
Expand All @@ -90,9 +107,8 @@ class Installer {
}

const platformKey = `${this.platform}-${this.arch}`;
const tarPath = path.join(this.binDir, `recorder-${platformKey}.tar.gz`);
const binaryName = this.platform === 'win32' ? 'recorder.exe' : 'recorder';
const binaryPath = path.join(this.binDir, binaryName);
const tarPath = path.join(this.binDir, `capture-${platformKey}.tar.gz`);
const binaryPath = this.getBinaryPath();
const url = this.getDownloadUrl();

if (fs.existsSync(binaryPath)) {
Expand All @@ -116,10 +132,32 @@ class Installer {

fs.unlinkSync(tarPath);

// Make binary executable (Unix)
if (this.platform !== 'win32') {
fs.chmodSync(binaryPath, 0o755);
}

// Re-sign the .app bundle on macOS (extraction can invalidate signatures)
if (this.platform === 'darwin') {
const appBundlePath = path.join(this.binDir, MACOS_APP_BUNDLE);
if (fs.existsSync(appBundlePath)) {
try {
const macosDir = path.join(appBundlePath, 'Contents', 'MacOS');
const dylibPath = path.join(macosDir, 'librecorder.dylib');
const capturePath = path.join(macosDir, 'capture');

if (fs.existsSync(dylibPath)) {
execFileSync('codesign', ['--force', '--sign', '-', dylibPath]);
}
execFileSync('codesign', ['--force', '--sign', '-', capturePath]);
execFileSync('codesign', ['--force', '--sign', '-', appBundlePath]);
console.log('Code signed .app bundle.');
} catch (e) {
console.warn('codesign failed, screen recording may not work on macOS 26+');
}
}
}

console.log('Installation complete!');
} catch (error) {
console.error('Installation failed:', error.message);
Expand Down
12 changes: 0 additions & 12 deletions package-lock.json

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

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "videodb",
"version": "0.2.1",
"version": "0.2.2",
"description": "A NodeJS wrapper for VideoDB's API written in TypeScript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -10,8 +10,8 @@
"default": "./dist/index.js"
},
"./capture": {
"types": "./dist/recorder/index.d.ts",
"default": "./dist/recorder/index.js"
"types": "./dist/capture/index.d.ts",
"default": "./dist/capture/index.js"
}
},
"files": [
Expand Down Expand Up @@ -39,12 +39,12 @@
"prepublishOnly": "npm run build"
},
"binaryConfig": {
"baseUrl": "https://recorder-sdk-binaries.s3.amazonaws.com",
"version": "0.2.7",
"baseUrl": "https://artifacts.videodb.io/capture",
"version": "0.2.8",
"checksums": {
"darwin-arm64": "3592c47331a5dd68b3d94474c307cf7da5bb182aa9600ba65d2c4257244e7670",
"darwin-x64": "2f66e228cbab0195090cc3628ceaf75d298e7f8c2269bac6446b6ba23fb778c2",
"win32-x64": "23ae68bfe8e017b1da960e6b33a258f47b7307c9005506a59f3af0802799d057"
"darwin-arm64": "4aab67e524c2541bebbae24b8dd845da5d7f74fba006ce860a4914844e185c5d",
"darwin-x64": "ac67dc1a9edd2094d36e6961ed1dabab3e8b3e3e2a61655a49195b7e518901ca",
"win32-x64": "f19110d9b632c0149088abc09f4c86e0f43f64ce4b52a73bca6eb20789e156d0"
}
},
"repository": {
Expand Down
Loading