@remotion/renderer
Version:
Render Remotion videos using Node.js or Bun
1,789 lines (1,758 loc) • 680 kB
JavaScript
import { createRequire } from "node:module";
var __defProp = Object.defineProperty;
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
var __require = /* @__PURE__ */ createRequire(import.meta.url);
// vendor/yauzl-patched/pend.js
var require_pend = __commonJS((exports, module) => {
module.exports = Pend;
function Pend() {
this.pending = 0;
this.max = Infinity;
this.listeners = [];
this.waiting = [];
this.error = null;
}
Pend.prototype.go = function(fn) {
if (this.pending < this.max) {
pendGo(this, fn);
} else {
this.waiting.push(fn);
}
};
Pend.prototype.wait = function(cb) {
if (this.pending === 0) {
cb(this.error);
} else {
this.listeners.push(cb);
}
};
Pend.prototype.hold = function() {
return pendHold(this);
};
function pendHold(self) {
self.pending += 1;
var called = false;
return onCb;
function onCb(err) {
if (called)
throw new Error("callback called twice");
called = true;
self.error = self.error || err;
self.pending -= 1;
if (self.waiting.length > 0 && self.pending < self.max) {
pendGo(self, self.waiting.shift());
} else if (self.pending === 0) {
var listeners = self.listeners;
self.listeners = [];
listeners.forEach(cbListener);
}
}
function cbListener(listener) {
listener(self.error);
}
}
function pendGo(self, fn) {
fn(pendHold(self));
}
});
// vendor/yauzl-patched/fd-slicer.js
var require_fd_slicer = __commonJS((exports) => {
var fs5 = __require("fs");
var util = __require("util");
var stream = __require("stream");
var Readable = stream.Readable;
var Writable = stream.Writable;
var PassThrough = stream.PassThrough;
var Pend = require_pend();
var EventEmitter2 = __require("events").EventEmitter;
exports.createFromBuffer = createFromBuffer;
exports.createFromFd = createFromFd;
exports.BufferSlicer = BufferSlicer;
exports.FdSlicer = FdSlicer;
util.inherits(FdSlicer, EventEmitter2);
function FdSlicer(fd, options2) {
options2 = options2 || {};
EventEmitter2.call(this);
this.fd = fd;
this.pend = new Pend;
this.pend.max = 1;
this.refCount = 0;
this.autoClose = !!options2.autoClose;
}
FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
var self = this;
self.pend.go(function(cb) {
fs5.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
cb();
callback(err, bytesRead, buffer2);
});
});
};
FdSlicer.prototype.write = function(buffer, offset, length, position, callback) {
var self = this;
self.pend.go(function(cb) {
fs5.write(self.fd, buffer, offset, length, position, function(err, written, buffer2) {
cb();
callback(err, written, buffer2);
});
});
};
FdSlicer.prototype.createReadStream = function(options2) {
return new ReadStream(this, options2);
};
FdSlicer.prototype.createWriteStream = function(options2) {
return new WriteStream(this, options2);
};
FdSlicer.prototype.ref = function() {
this.refCount += 1;
};
FdSlicer.prototype.unref = function() {
var self = this;
self.refCount -= 1;
if (self.refCount > 0)
return;
if (self.refCount < 0)
throw new Error("invalid unref");
if (self.autoClose) {
fs5.close(self.fd, onCloseDone);
}
function onCloseDone(err) {
if (err) {
self.emit("error", err);
} else {
self.emit("close");
}
}
};
util.inherits(ReadStream, Readable);
function ReadStream(context, options2) {
options2 = options2 || {};
Readable.call(this, options2);
this.context = context;
this.context.ref();
this.start = options2.start || 0;
this.endOffset = options2.end;
this.pos = this.start;
this._destroyed = false;
}
ReadStream.prototype._read = function(n) {
var self = this;
if (self._destroyed)
return;
var toRead = Math.min(self._readableState.highWaterMark, n);
if (self.endOffset != null) {
toRead = Math.min(toRead, self.endOffset - self.pos);
}
if (toRead <= 0) {
self._destroyed = true;
self.push(null);
self.context.unref();
return;
}
self.context.pend.go(function(cb) {
if (self._destroyed)
return cb();
var buffer = Buffer.allocUnsafe(toRead);
fs5.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
if (self._destroyed)
return cb();
if (err) {
self.destroy(err);
} else if (bytesRead === 0) {
self._destroyed = true;
self.push(null);
self.context.unref();
} else {
self.pos += bytesRead;
self.push(buffer.slice(0, bytesRead));
}
cb();
});
});
};
ReadStream.prototype.destroy = function(err) {
if (err == null && !this.readableEnded) {
err = new Error("stream _destroyed");
}
return Readable.prototype.destroy.call(this, err);
};
ReadStream.prototype._destroy = function(err, cb) {
if (!this._destroyed) {
this._destroyed = true;
this.context.unref();
}
cb(err);
};
util.inherits(WriteStream, Writable);
function WriteStream(context, options2) {
options2 = options2 || {};
Writable.call(this, options2);
this.context = context;
this.context.ref();
this.start = options2.start || 0;
this.endOffset = options2.end == null ? Infinity : +options2.end;
this.bytesWritten = 0;
this.pos = this.start;
this._destroyed = false;
this.on("finish", this.destroy.bind(this));
}
WriteStream.prototype._write = function(buffer, encoding, callback) {
var self = this;
if (self._destroyed)
return;
if (self.pos + buffer.length > self.endOffset) {
var err = new Error("maximum file length exceeded");
err.code = "ETOOBIG";
self.destroy();
callback(err);
return;
}
self.context.pend.go(function(cb) {
if (self._destroyed)
return cb();
fs5.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err2, bytes) {
if (err2) {
self.destroy();
cb();
callback(err2);
} else {
self.bytesWritten += bytes;
self.pos += bytes;
self.emit("progress");
cb();
callback();
}
});
});
};
WriteStream.prototype._destroy = function(err, cb) {
if (!this._destroyed) {
this._destroyed = true;
this.context.unref();
}
cb(err);
};
util.inherits(BufferSlicer, EventEmitter2);
function BufferSlicer(buffer, options2) {
EventEmitter2.call(this);
options2 = options2 || {};
this.refCount = 0;
this.buffer = buffer;
this.maxChunkSize = options2.maxChunkSize || Number.MAX_SAFE_INTEGER;
}
BufferSlicer.prototype.read = function(buffer, offset, length, position, callback) {
if (!(0 <= offset && offset <= buffer.length))
throw new RangeError("offset outside buffer: 0 <= " + offset + " <= " + buffer.length);
if (position < 0)
throw new RangeError("position is negative: " + position);
if (offset + length > buffer.length) {
length = buffer.length - offset;
}
if (position + length > this.buffer.length) {
length = this.buffer.length - position;
}
if (length <= 0) {
setImmediate(function() {
callback(null, 0);
});
return;
}
this.buffer.copy(buffer, offset, position, position + length);
setImmediate(function() {
callback(null, length);
});
};
BufferSlicer.prototype.write = function(buffer, offset, length, position, callback) {
buffer.copy(this.buffer, position, offset, offset + length);
setImmediate(function() {
callback(null, length, buffer);
});
};
BufferSlicer.prototype.createReadStream = function(options2) {
options2 = options2 || {};
var readStream = new PassThrough(options2);
readStream._destroyed = false;
readStream.start = options2.start || 0;
readStream.endOffset = options2.end;
readStream.pos = readStream.endOffset || this.buffer.length;
var entireSlice = this.buffer.slice(readStream.start, readStream.pos);
var offset = 0;
while (true) {
var nextOffset = offset + this.maxChunkSize;
if (nextOffset >= entireSlice.length) {
if (offset < entireSlice.length) {
readStream.write(entireSlice.slice(offset, entireSlice.length));
}
break;
}
readStream.write(entireSlice.slice(offset, nextOffset));
offset = nextOffset;
}
readStream.end();
readStream._destroy = function(err, cb) {
readStream._destroyed = true;
PassThrough.prototype._destroy.call(readStream, err, cb);
};
return readStream;
};
BufferSlicer.prototype.createWriteStream = function(options2) {
var bufferSlicer = this;
options2 = options2 || {};
var writeStream = new Writable(options2);
writeStream.start = options2.start || 0;
writeStream.endOffset = options2.end == null ? this.buffer.length : +options2.end;
writeStream.bytesWritten = 0;
writeStream.pos = writeStream.start;
writeStream._destroyed = false;
writeStream._write = function(buffer, encoding, callback) {
if (writeStream._destroyed)
return;
var end = writeStream.pos + buffer.length;
if (end > writeStream.endOffset) {
var err = new Error("maximum file length exceeded");
err.code = "ETOOBIG";
writeStream._destroyed = true;
callback(err);
return;
}
buffer.copy(bufferSlicer.buffer, writeStream.pos, 0, buffer.length);
writeStream.bytesWritten += buffer.length;
writeStream.pos = end;
writeStream.emit("progress");
callback();
};
writeStream._destroy = function(err, cb) {
writeStream._destroyed = true;
cb(err);
};
return writeStream;
};
BufferSlicer.prototype.ref = function() {
this.refCount += 1;
};
BufferSlicer.prototype.unref = function() {
this.refCount -= 1;
if (this.refCount < 0) {
throw new Error("invalid unref");
}
};
function createFromBuffer(buffer, options2) {
return new BufferSlicer(buffer, options2);
}
function createFromFd(fd, options2) {
return new FdSlicer(fd, options2);
}
});
// vendor/yauzl-patched/buffer-crc32.js
var require_buffer_crc32 = __commonJS((exports, module) => {
var Buffer2 = __require("buffer").Buffer;
var CRC_TABLE = [
0,
1996959894,
3993919788,
2567524794,
124634137,
1886057615,
3915621685,
2657392035,
249268274,
2044508324,
3772115230,
2547177864,
162941995,
2125561021,
3887607047,
2428444049,
498536548,
1789927666,
4089016648,
2227061214,
450548861,
1843258603,
4107580753,
2211677639,
325883990,
1684777152,
4251122042,
2321926636,
335633487,
1661365465,
4195302755,
2366115317,
997073096,
1281953886,
3579855332,
2724688242,
1006888145,
1258607687,
3524101629,
2768942443,
901097722,
1119000684,
3686517206,
2898065728,
853044451,
1172266101,
3705015759,
2882616665,
651767980,
1373503546,
3369554304,
3218104598,
565507253,
1454621731,
3485111705,
3099436303,
671266974,
1594198024,
3322730930,
2970347812,
795835527,
1483230225,
3244367275,
3060149565,
1994146192,
31158534,
2563907772,
4023717930,
1907459465,
112637215,
2680153253,
3904427059,
2013776290,
251722036,
2517215374,
3775830040,
2137656763,
141376813,
2439277719,
3865271297,
1802195444,
476864866,
2238001368,
4066508878,
1812370925,
453092731,
2181625025,
4111451223,
1706088902,
314042704,
2344532202,
4240017532,
1658658271,
366619977,
2362670323,
4224994405,
1303535960,
984961486,
2747007092,
3569037538,
1256170817,
1037604311,
2765210733,
3554079995,
1131014506,
879679996,
2909243462,
3663771856,
1141124467,
855842277,
2852801631,
3708648649,
1342533948,
654459306,
3188396048,
3373015174,
1466479909,
544179635,
3110523913,
3462522015,
1591671054,
702138776,
2966460450,
3352799412,
1504918807,
783551873,
3082640443,
3233442989,
3988292384,
2596254646,
62317068,
1957810842,
3939845945,
2647816111,
81470997,
1943803523,
3814918930,
2489596804,
225274430,
2053790376,
3826175755,
2466906013,
167816743,
2097651377,
4027552580,
2265490386,
503444072,
1762050814,
4150417245,
2154129355,
426522225,
1852507879,
4275313526,
2312317920,
282753626,
1742555852,
4189708143,
2394877945,
397917763,
1622183637,
3604390888,
2714866558,
953729732,
1340076626,
3518719985,
2797360999,
1068828381,
1219638859,
3624741850,
2936675148,
906185462,
1090812512,
3747672003,
2825379669,
829329135,
1181335161,
3412177804,
3160834842,
628085408,
1382605366,
3423369109,
3138078467,
570562233,
1426400815,
3317316542,
2998733608,
733239954,
1555261956,
3268935591,
3050360625,
752459403,
1541320221,
2607071920,
3965973030,
1969922972,
40735498,
2617837225,
3943577151,
1913087877,
83908371,
2512341634,
3803740692,
2075208622,
213261112,
2463272603,
3855990285,
2094854071,
198958881,
2262029012,
4057260610,
1759359992,
534414190,
2176718541,
4139329115,
1873836001,
414664567,
2282248934,
4279200368,
1711684554,
285281116,
2405801727,
4167216745,
1634467795,
376229701,
2685067896,
3608007406,
1308918612,
956543938,
2808555105,
3495958263,
1231636301,
1047427035,
2932959818,
3654703836,
1088359270,
936918000,
2847714899,
3736837829,
1202900863,
817233897,
3183342108,
3401237130,
1404277552,
615818150,
3134207493,
3453421203,
1423857449,
601450431,
3009837614,
3294710456,
1567103746,
711928724,
3020668471,
3272380065,
1510334235,
755167117
];
if (typeof Int32Array !== "undefined") {
CRC_TABLE = new Int32Array(CRC_TABLE);
}
function ensureBuffer(input) {
if (Buffer2.isBuffer(input)) {
return input;
}
var hasNewBufferAPI = typeof Buffer2.alloc === "function" && typeof Buffer2.from === "function";
if (typeof input === "number") {
return hasNewBufferAPI ? Buffer2.alloc(input) : new Buffer2(input);
} else if (typeof input === "string") {
return hasNewBufferAPI ? Buffer2.from(input) : new Buffer2(input);
} else {
throw new Error("input must be buffer, number, or string, received " + typeof input);
}
}
function bufferizeInt(num) {
var tmp = ensureBuffer(4);
tmp.writeInt32BE(num, 0);
return tmp;
}
function _crc32(buf, previous) {
buf = ensureBuffer(buf);
if (Buffer2.isBuffer(previous)) {
previous = previous.readUInt32BE(0);
}
var crc = ~~previous ^ -1;
for (var n = 0;n < buf.length; n++) {
crc = CRC_TABLE[(crc ^ buf[n]) & 255] ^ crc >>> 8;
}
return crc ^ -1;
}
function crc32() {
return bufferizeInt(_crc32.apply(null, arguments));
}
crc32.signed = function() {
return _crc32.apply(null, arguments);
};
crc32.unsigned = function() {
return _crc32.apply(null, arguments) >>> 0;
};
module.exports = crc32;
});
// src/index.ts
import execa2 from "execa";
// src/assets/download-file.ts
import { createWriteStream } from "node:fs";
// src/ensure-output-directory.ts
import fs from "node:fs";
import path from "node:path";
var ensureOutputDirectory = (outputLocation) => {
const dirName = path.dirname(outputLocation);
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName, {
recursive: true
});
}
};
// src/chalk/is-color-supported.ts
import * as tty from "tty";
var isColorSupported = () => {
const env = process.env || {};
const isForceDisabled = "NO_COLOR" in env;
if (isForceDisabled) {
return false;
}
const isForced = "FORCE_COLOR" in env;
if (isForced) {
return true;
}
const isWindows = process.platform === "win32";
const isCompatibleTerminal = tty?.isatty?.(1) && env.TERM && env.TERM !== "dumb";
const isCI = "CI" in env && (("GITHUB_ACTIONS" in env) || ("GITLAB_CI" in env) || ("CIRCLECI" in env));
return isWindows || isCompatibleTerminal || isCI;
};
// src/chalk/index.ts
var chalk = (() => {
const colors = {
enabled: () => isColorSupported(),
visible: true,
styles: {},
keys: {}
};
const ansi = (st) => {
const open = `\x1B[${st.codes[0]}m`;
const close = `\x1B[${st.codes[1]}m`;
const regex = new RegExp(`\\u001b\\[${st.codes[1]}m`, "g");
st.wrap = (input, newline) => {
if (input.includes(close))
input = input.replace(regex, close + open);
const output = open + input + close;
return newline ? output.replace(/\r*\n/g, `${close}$&${open}`) : output;
};
return st;
};
const wrap = (sty, input, newline) => {
return sty.wrap?.(input, newline);
};
const style = (input, stack) => {
if (input === "" || input === null || input === undefined)
return "";
if (colors.enabled() === false)
return input;
if (colors.visible === false)
return "";
let str = String(input);
const nl = str.includes(`
`);
let n = stack.length;
while (n-- > 0)
str = wrap(colors.styles[stack[n]], str, nl);
return str;
};
const define = (name, codes, type) => {
colors.styles[name] = ansi({ name, codes });
const keys = colors.keys[type] || (colors.keys[type] = []);
keys.push(name);
Reflect.defineProperty(colors, name, {
configurable: true,
enumerable: true,
set(value) {
colors.alias?.(name, value);
},
get() {
const color = (input) => style(input, color.stack);
Reflect.setPrototypeOf(color, colors);
color.stack = this.stack ? this.stack.concat(name) : [name];
return color;
}
});
};
define("reset", [0, 0], "modifier");
define("bold", [1, 22], "modifier");
define("dim", [2, 22], "modifier");
define("italic", [3, 23], "modifier");
define("underline", [4, 24], "modifier");
define("inverse", [7, 27], "modifier");
define("hidden", [8, 28], "modifier");
define("strikethrough", [9, 29], "modifier");
define("black", [30, 39], "color");
define("red", [31, 39], "color");
define("green", [32, 39], "color");
define("yellow", [33, 39], "color");
define("blue", [34, 39], "color");
define("magenta", [35, 39], "color");
define("cyan", [36, 39], "color");
define("white", [37, 39], "color");
define("gray", [90, 39], "color");
define("grey", [90, 39], "color");
define("bgBlack", [40, 49], "bg");
define("bgRed", [41, 49], "bg");
define("bgGreen", [42, 49], "bg");
define("bgYellow", [43, 49], "bg");
define("bgBlue", [44, 49], "bg");
define("bgMagenta", [45, 49], "bg");
define("bgWhite", [47, 49], "bg");
define("blackBright", [90, 39], "bright");
define("redBright", [91, 39], "bright");
define("greenBright", [92, 39], "bright");
define("yellowBright", [93, 39], "bright");
define("blueBright", [94, 39], "bright");
define("magentaBright", [95, 39], "bright");
define("whiteBright", [97, 39], "bright");
define("bgBlackBright", [100, 49], "bgBright");
define("bgRedBright", [101, 49], "bgBright");
define("bgGreenBright", [102, 49], "bgBright");
define("bgYellowBright", [103, 49], "bgBright");
define("bgBlueBright", [104, 49], "bgBright");
define("bgMagentaBright", [105, 49], "bgBright");
define("bgWhiteBright", [107, 49], "bgBright");
colors.alias = (name, color) => {
const fn = colors[color];
if (typeof fn !== "function") {
throw new TypeError("Expected alias to be the name of an existing color (string) or a function");
}
if (!fn.stack) {
Reflect.defineProperty(fn, "name", { value: name });
colors.styles[name] = fn;
fn.stack = [name];
}
Reflect.defineProperty(colors, name, {
configurable: true,
enumerable: true,
set(value) {
colors.alias?.(name, value);
},
get() {
const col = (input) => style(input, col.stack);
Reflect.setPrototypeOf(col, colors);
col.stack = this.stack ? this.stack.concat(fn.stack) : fn.stack;
return col;
}
});
};
return colors;
})();
// src/log-level.ts
var logLevels = ["trace", "verbose", "info", "warn", "error"];
var getNumberForLogLevel = (level) => {
return logLevels.indexOf(level);
};
var isValidLogLevel = (level) => {
return getNumberForLogLevel(level) > -1;
};
var isEqualOrBelowLogLevel = (currentLevel, level) => {
return getNumberForLogLevel(currentLevel) <= getNumberForLogLevel(level);
};
// src/repro.ts
import { execSync } from "node:child_process";
import fs3, { rmSync } from "node:fs";
import os from "node:os";
import path3 from "node:path";
import { VERSION } from "remotion/version";
// src/find-closest-package-json.ts
import fs2 from "node:fs";
import path2 from "node:path";
var recursionLimit = 5;
var findClosestPackageJson = () => {
let currentDir = process.cwd();
let possiblePackageJson = "";
for (let i = 0;i < recursionLimit; i++) {
possiblePackageJson = path2.join(currentDir, "package.json");
const exists = fs2.existsSync(possiblePackageJson);
if (exists) {
return possiblePackageJson;
}
currentDir = path2.dirname(currentDir);
}
return null;
};
var findRemotionRoot = () => {
const closestPackageJson = findClosestPackageJson();
if (closestPackageJson === null) {
return process.cwd();
}
return path2.dirname(closestPackageJson);
};
// src/is-serve-url.ts
var isServeUrl = (potentialUrl) => {
if (typeof potentialUrl === "undefined") {
throw new Error("serveUrl is undefined");
}
if (potentialUrl.startsWith("www.") || potentialUrl.includes("amazonaws.com")) {
return true;
}
return potentialUrl.startsWith("https://") || potentialUrl.startsWith("http://");
};
// src/repro.ts
var REPRO_DIR = ".remotionrepro";
var LOG_FILE_NAME = "logs.txt";
var INPUT_DIR = "bundle";
var OUTPUT_DIR = "output";
var LINE_SPLIT = `
`;
var getZipFileName = (name) => `remotion-repro-${name}-${Date.now()}.zip`;
var readyDirSync = (dir) => {
let items;
try {
items = fs3.readdirSync(dir);
} catch {
return fs3.mkdirSync(dir, { recursive: true });
}
items.forEach((item) => {
item = path3.join(dir, item);
fs3.rmSync(item, { recursive: true, force: true });
});
};
var zipFolder = ({
sourceFolder,
targetZip,
indent,
logLevel
}) => {
const platform = os.platform();
try {
Log.info({ indent, logLevel }, "+ Creating reproduction ZIP");
if (platform === "win32") {
execSync(`powershell.exe Compress-Archive -Path "${sourceFolder}" -DestinationPath "${targetZip}"`);
} else {
execSync(`zip -r "${targetZip}" "${sourceFolder}"`);
}
rmSync(sourceFolder, { recursive: true });
Log.info({ indent, logLevel }, `${chalk.blue(`+ Repro: ${targetZip}`)}`);
} catch (error) {
Log.error({ indent, logLevel }, `Failed to zip repro folder, The repro folder is ${sourceFolder}. You can try manually zip it.`);
Log.error({ indent, logLevel }, error);
}
};
var reproWriter = (name) => {
const root = findRemotionRoot();
const reproFolder = path3.join(root, REPRO_DIR);
const logPath = path3.join(reproFolder, LOG_FILE_NAME);
const zipFile = path3.join(root, getZipFileName(name));
readyDirSync(reproFolder);
const reproLogWriteStream = fs3.createWriteStream(logPath, { flags: "a" });
const serializeArgs = (args) => JSON.stringify(args);
const writeLine = (level, ...args) => {
if (!args.length)
return;
const startTime = new Date().toISOString();
const line = `[${startTime}] ${level} ${serializeArgs(args)}`;
reproLogWriteStream.write(line + LINE_SPLIT);
};
const start = ({
serveUrl,
serializedInputPropsWithCustomSchema,
serializedResolvedPropsWithCustomSchema
}) => {
const isServe = isServeUrl(serveUrl);
if (!isServe) {
const inputDir = path3.resolve(reproFolder, INPUT_DIR);
readyDirSync(inputDir);
fs3.cpSync(serveUrl, inputDir, { recursive: true });
}
const serializedProps = path3.resolve(reproFolder, "input-props.json");
fs3.writeFileSync(serializedProps, serializedInputPropsWithCustomSchema);
const serializedResolvedProps = path3.resolve(reproFolder, "resolved-props.json");
fs3.writeFileSync(serializedResolvedProps, serializedResolvedPropsWithCustomSchema);
writeLine("info", [`Args: ${JSON.stringify(process.argv)}`]);
writeLine("info", [`Node/Bun version: ${process.version}`]);
writeLine("info", [`OS: ${process.platform}-${process.arch}`]);
writeLine("info", [`Serve URL: ${serveUrl}`]);
writeLine("info", [`Remotion version: ${VERSION}`]);
};
const onRenderSucceed = ({
indent,
logLevel,
output
}) => {
return new Promise((resolve, reject) => {
try {
if (output) {
const outputDir = path3.resolve(reproFolder, OUTPUT_DIR);
readyDirSync(outputDir);
const fileName = path3.basename(output);
const targetPath = path3.join(outputDir, fileName);
fs3.copyFileSync(output, targetPath);
}
disableRepro();
reproLogWriteStream.end(() => {
reproLogWriteStream.close(() => {
zipFolder({
sourceFolder: reproFolder,
targetZip: zipFile,
indent,
logLevel
});
resolve();
});
});
} catch (error) {
Log.error({ indent: false, logLevel }, `repro render success error:`);
Log.error({ indent: false, logLevel }, error);
reject(error);
}
});
};
return {
start,
writeLine,
onRenderSucceed
};
};
var reproWriteInstance = null;
var getReproWriter = () => {
if (!reproWriteInstance) {
throw new Error("reproWriteInstance is not initialized");
}
return reproWriteInstance;
};
var writeInRepro = (level, ...args) => {
if (isReproEnabled()) {
getReproWriter().writeLine(level, ...args);
}
};
var shouldRepro = false;
var enableRepro = ({
serveUrl,
compositionName,
serializedInputPropsWithCustomSchema,
serializedResolvedPropsWithCustomSchema
}) => {
shouldRepro = true;
reproWriteInstance = reproWriter(compositionName);
getReproWriter().start({
serveUrl,
serializedInputPropsWithCustomSchema,
serializedResolvedPropsWithCustomSchema
});
};
var disableRepro = () => {
shouldRepro = false;
};
var isReproEnabled = () => shouldRepro;
// src/truthy.ts
function truthy(value) {
return Boolean(value);
}
// src/logger.ts
var INDENT_TOKEN = chalk.gray("│");
var verboseTag = (str) => {
return isColorSupported() ? chalk.bgBlack(` ${str} `) : `[${str}]`;
};
var Log = {
formatLogs: (logLevel, options2, args) => {
return [
options2.indent ? INDENT_TOKEN : null,
options2.tag ? verboseTag(options2.tag) : null
].filter(truthy).concat(args.map((a) => {
if (logLevel === "warn") {
return chalk.yellow(a);
}
if (logLevel === "error") {
return chalk.red(a);
}
if (logLevel === "verbose" || logLevel === "trace") {
return chalk.gray(a);
}
return a;
}));
},
trace: (options2, ...args) => {
writeInRepro("trace", ...args);
if (isEqualOrBelowLogLevel(options2.logLevel, "trace")) {
if (args.length === 0) {
return process.stdout.write(`
`);
}
return console.log(...Log.formatLogs("trace", options2, args));
}
},
verbose: (options2, ...args) => {
writeInRepro("verbose", ...args);
if (isEqualOrBelowLogLevel(options2.logLevel, "verbose")) {
if (args.length === 0) {
return process.stdout.write(`
`);
}
return console.log(...Log.formatLogs("verbose", options2, args));
}
},
info: (options2, ...args) => {
writeInRepro("info", ...args);
if (isEqualOrBelowLogLevel(options2.logLevel, "info")) {
if (args.length === 0) {
return process.stdout.write(`
`);
}
return console.log(...Log.formatLogs("info", options2, args));
}
},
warn: (options2, ...args) => {
writeInRepro("warn", ...args);
if (isEqualOrBelowLogLevel(options2.logLevel, "warn")) {
if (args.length === 0) {
return process.stdout.write(`
`);
}
return console.warn(...Log.formatLogs("warn", options2, args));
}
},
error: (options2, ...args) => {
writeInRepro("error", ...args);
if (isEqualOrBelowLogLevel(options2.logLevel, "error")) {
if (args.length === 0) {
return process.stdout.write(`
`);
}
return console.error(...Log.formatLogs("error", options2, args));
}
}
};
// src/assets/read-file.ts
import https from "https";
import http from "node:http";
// src/redirect-status-codes.ts
var redirectStatusCodes = [301, 302, 303, 307, 308];
// src/assets/read-file.ts
var getClient = (url) => {
if (url.startsWith("https://")) {
return https.get;
}
if (url.startsWith("http://")) {
return http.get;
}
throw new Error(`Can only download URLs starting with http:// or https://, got "${url}"`);
};
var readFileWithoutRedirect = (url) => {
return new Promise((resolve, reject) => {
const client = getClient(url);
const req = client(url, typeof Bun === "undefined" ? {
headers: {
"user-agent": "Mozilla/5.0 (@remotion/renderer - https://remotion.dev)"
}
} : {}, (res) => {
resolve({ request: req, response: res });
});
req.on("error", (err) => {
req.destroy();
return reject(err);
});
});
};
var readFile = async (url, redirectsSoFar = 0) => {
if (redirectsSoFar > 10) {
throw new Error(`Too many redirects while downloading ${url}`);
}
const { request, response } = await readFileWithoutRedirect(url);
if (redirectStatusCodes.includes(response.statusCode)) {
if (!response.headers.location) {
throw new Error(`Received a status code ${response.statusCode} but no "Location" header while calling ${response.headers.location}`);
}
const { origin } = new URL(url);
const redirectUrl = new URL(response.headers.location, origin).toString();
request.destroy();
response.destroy();
return readFile(redirectUrl, redirectsSoFar + 1);
}
if (response.statusCode >= 400) {
const body = await tryToObtainBody(response);
request.destroy();
response.destroy();
throw new Error([
`Received a status code of ${response.statusCode} while downloading file ${url}.`,
body ? `The response body was:` : null,
body ? `---` : null,
body ? body : null,
body ? `---` : null
].filter(truthy).join(`
`));
}
return { request, response };
};
var tryToObtainBody = async (file) => {
const success = new Promise((resolve) => {
let data = "";
file.on("data", (chunk) => {
data += chunk;
});
file.on("end", () => {
resolve(data);
});
file.on("error", () => resolve(data));
});
let timeout = null;
const body = await Promise.race([
success,
new Promise((resolve) => {
timeout = setTimeout(() => {
resolve(null);
}, 5000);
})
]);
if (timeout) {
clearTimeout(timeout);
}
return body;
};
// src/assets/download-file.ts
var CANCELLED_ERROR = "cancelled";
var incorrectContentLengthToken = "Download finished with";
var noDataSentToken = "but the server sent no data for";
var downloadFileWithoutRetries = ({
onProgress,
url,
to: toFn,
abortSignal
}) => {
return new Promise((resolve, reject) => {
let rejected = false;
let resolved = false;
let timeout;
const resolveAndFlag = (val) => {
abortSignal.removeEventListener("abort", onAbort);
resolved = true;
resolve(val);
if (timeout) {
clearTimeout(timeout);
}
};
const rejectAndFlag = (err) => {
abortSignal.removeEventListener("abort", onAbort);
if (timeout) {
clearTimeout(timeout);
}
reject(err);
rejected = true;
};
const refreshTimeout = () => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
if (resolved) {
return;
}
rejectAndFlag(new Error(`Tried to download file ${url}, ${noDataSentToken} 20 seconds`));
}, 20000);
};
refreshTimeout();
let finishEventSent = false;
let closeConnection = () => {
return;
};
const onAbort = () => {
rejectAndFlag(new Error(CANCELLED_ERROR));
closeConnection();
};
abortSignal.addEventListener("abort", onAbort);
readFile(url).then(({ response, request }) => {
closeConnection = () => {
request.destroy();
response.destroy();
};
if (abortSignal.aborted) {
onAbort();
return;
}
const contentDisposition = response.headers["content-disposition"] ?? null;
const contentType = response.headers["content-type"] ?? null;
const to = toFn(contentDisposition, contentType);
ensureOutputDirectory(to);
const sizeHeader = response.headers["content-length"];
const totalSize = typeof sizeHeader === "undefined" ? null : Number(sizeHeader);
const writeStream = createWriteStream(to);
let downloaded = 0;
writeStream.on("close", () => {
if (rejected) {
return;
}
if (!finishEventSent) {
onProgress?.({
downloaded,
percent: 1,
totalSize: downloaded
});
}
refreshTimeout();
return resolveAndFlag({ sizeInBytes: downloaded, to });
});
writeStream.on("error", (err) => rejectAndFlag(err));
response.on("error", (err) => {
closeConnection();
rejectAndFlag(err);
});
response.pipe(writeStream).on("error", (err) => rejectAndFlag(err));
response.on("data", (d) => {
refreshTimeout();
downloaded += d.length;
refreshTimeout();
const percent = totalSize === null ? null : downloaded / totalSize;
onProgress?.({
downloaded,
percent,
totalSize
});
if (percent === 1) {
finishEventSent = true;
}
});
response.on("close", () => {
if (totalSize !== null && downloaded !== totalSize) {
rejectAndFlag(new Error(`${incorrectContentLengthToken} ${downloaded} bytes, but expected ${totalSize} bytes from 'Content-Length'.`));
}
writeStream.close();
closeConnection();
});
}).catch((err) => {
rejectAndFlag(err);
});
});
};
var downloadFile = async (options2, retries = 2, attempt = 1) => {
try {
const res = await downloadFileWithoutRetries(options2);
return res;
} catch (err) {
const { message } = err;
if (message === CANCELLED_ERROR) {
throw err;
}
if (message === "aborted" || message.includes("ECONNRESET") || message.includes(incorrectContentLengthToken) || message.includes(noDataSentToken) || message.includes("503") || message.includes("502") || message.includes("504") || message.includes("500")) {
if (retries === 0) {
throw err;
}
Log.warn({ indent: options2.indent, logLevel: options2.logLevel }, `Downloading ${options2.url} failed (will retry): ${message}`);
const backoffInSeconds = (attempt + 1) ** 2;
await new Promise((resolve) => {
setTimeout(() => resolve(), backoffInSeconds * 1000);
});
return downloadFile(options2, retries - 1, attempt + 1);
}
throw err;
}
};
// src/browser.ts
var DEFAULT_BROWSER = "chrome";
// src/browser/assert.ts
var assert = (value, message) => {
if (!value) {
throw new Error(message);
}
};
// src/browser/BrowserPage.ts
import { NoReactInternals as NoReactInternals2 } from "remotion/no-react";
// src/format-logs.ts
import { NoReactInternals } from "remotion/no-react";
var formatRemoteObject = (remoteObject) => {
if (remoteObject.preview) {
return formatObjectPreview(remoteObject.preview);
}
if (remoteObject.type === "string") {
const isDelayRenderClear = remoteObject.value.includes(NoReactInternals.DELAY_RENDER_CLEAR_TOKEN);
if (isDelayRenderClear) {
return chalk.gray(`${remoteObject.value}`);
}
return `${remoteObject.value}`;
}
if (remoteObject.type === "number") {
return chalk.yellow(`${remoteObject.value}`);
}
if (remoteObject.type === "bigint") {
return chalk.yellow(`${remoteObject.description}`);
}
if (remoteObject.type === "boolean") {
return chalk.yellow(`${remoteObject.value}`);
}
if (remoteObject.type === "function") {
return chalk.cyan(String(remoteObject.description));
}
if (remoteObject.type === "object") {
if (remoteObject.subtype === "null") {
return `null`;
}
return chalk.reset(`Object`);
}
if (remoteObject.type === "symbol") {
return chalk.green(`${remoteObject.description}`);
}
if (remoteObject.type === "undefined") {
return chalk.gray(`undefined`);
}
throw new Error("unhandled remote object");
};
var formatObjectPreview = (preview) => {
if (typeof preview === "undefined") {
return "";
}
if (preview.type === "object") {
if (preview.subtype === "date") {
return chalk.reset(`Date { ${chalk.magenta(String(preview.description))} }`);
}
const properties = preview.properties.map((property) => {
return chalk.reset(`${property.name}: ${formatProperty(property)}`);
});
if (preview.subtype === "array") {
if (preview.overflow) {
return chalk.reset(`[ ${preview.properties.map((p) => formatProperty(p)).join(", ")}, …]`);
}
return chalk.reset(`[ ${preview.properties.map((p) => formatProperty(p)).join(", ")} ]`);
}
if (preview.subtype === "arraybuffer") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "dataview") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "generator") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "iterator") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "map") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "node") {
return chalk.magenta(`<${preview.description}>`);
}
if (preview.subtype === "null") {
return chalk.white(String(preview.description));
}
if (preview.subtype === "promise") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "proxy") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "regexp") {
return chalk.red(String(preview.description));
}
if (preview.subtype === "set") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "typedarray") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "error") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "wasmvalue") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "weakmap") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "weakset") {
return chalk.reset(String(preview.description));
}
if (preview.subtype === "webassemblymemory") {
return chalk.reset(String(preview.description));
}
if (properties.length === 0) {
return chalk.reset("{}");
}
if (preview.overflow) {
return chalk.reset(`{ ${properties.join(", ")}, …}`);
}
return chalk.reset(`{ ${properties.join(", ")} }`);
}
return "";
};
var formatProperty = (property) => {
if (property.type === "string") {
return chalk.green(`"${property.value}"`);
}
if (property.type === "object") {
if (!property.subtype && property.value === "Object") {
return chalk.reset(`{…}`);
}
if (property.subtype === "date") {
return chalk.reset(`Date { ${chalk.magenta(String(property.value))} }`);
}
if (property.subtype === "arraybuffer") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "array") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "dataview") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "error") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "generator") {
return chalk.reset(`[generator ${property.value}]`);
}
if (property.subtype === "iterator") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "map") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "node") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "null") {
return chalk.white(`${property.value}`);
}
if (property.subtype === "promise") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "proxy") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "regexp") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "set") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "typedarray") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "wasmvalue") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "webassemblymemory") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "weakmap") {
return chalk.reset(`${property.value}`);
}
if (property.subtype === "weakset") {
return chalk.reset(`${property.value}`);
}
return chalk.reset(`${property.value}`);
}
if (property.type === "accessor") {
return chalk.gray(`get()`);
}
if (property.type === "bigint") {
return chalk.yellow(`${property.value}`);
}
if (property.type === "boolean") {
return chalk.yellow(`${property.value}`);
}
if (property.type === "function") {
return chalk.cyan(`Function`);
}
if (property.type === "number") {
return chalk.yellow(`${property.value}`);
}
if (property.type === "symbol") {
return chalk.green(`${property.value}`);
}
if (property.type === "undefined") {
return chalk.gray(`undefined`);
}
throw new Error("unexpected property type " + JSON.stringify(property));
};
// src/browser/ConsoleMessage.ts
class ConsoleMessage {
type;
text;
args;
previewString;
#stackTraceLocations;
logLevel;
tag;
constructor({
type,
text,
args,
stackTraceLocations,
previewString,
logLevel,
tag
}) {
this.type = type;
this.text = text;
this.args = args;
this.previewString = previewString;
this.#stackTraceLocations = stackTraceLocations;
this.logLevel = logLevel;
this.tag = tag;
}
stackTrace() {
return this.#stackTraceLocations;
}
}
// src/browser/mitt/index.ts
function mitt(all) {
all = all || new Map;
return {
all,
on: (type, handler) => {
const handlers = all?.get(type);
const added = handlers?.push(handler);
if (!added) {
all?.set(type, [handler]);
}
},
off: (type, handler) => {
const handlers = all?.get(type);
if (handlers) {
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
}
},
emit: (type, evt) => {
(all?.get(type) || []).slice().forEach((handler) => {
handler(evt);
});
(all?.get("*") || []).slice().forEach((handler) => {
handler(type, evt);
});
}
};
}
// src/browser/EventEmitter.ts
class EventEmitter {
emitter;
eventsMap = new Map;
constructor() {
this.emitter = mitt(this.eventsMap);
}
on(event, handler) {
this.emitter.on(event, handler);
return this;
}
off(event, handler) {
this.emitter.off(event, handler);
return this;
}
addListener(event, handler) {
this.on(event, handler);
return this;
}
emit(event, eventData) {
this.emitter.emit(event, eventData);
return this.eventListenersCount(event) > 0;
}
once(event, handler) {
const onceHandler = (eventData) => {
handler(eventData);
this.off(event, onceHandler);
};
return this.on(event, onceHandler);
}
listenerCount(event) {
return this.eventListenersCount(event);
}
removeAllListeners(event) {
if (event) {
this.eventsMap.delete(event);
} else {
this.eventsMap.clear();
}
return this;
}
eventListenersCount(event) {
return this.eventsMap.get(event)?.length || 0;
}
}
// src/browser/Errors.ts
class CustomError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
class TimeoutError extends CustomError {
}
class ProtocolError extends CustomError {
code;
originalMessage = "";
}
// src/browser/Connection.ts
var ConnectionEmittedEvents = {
Disconnected: Symbol("Connection.Disconnected")
};
class Connection extends EventEmitter {
transport;
#lastId = 0;
#sessions = new Map;
#closed = false;
#callbacks = new Map;
constructor(transport) {
super();
this.transport = transport;
this.transport.onmessage = this.#onMessage.bind(this);
this.transport.onclose = this.#onClose.bind(this);
}
static fromSession(session) {
return session.connection();
}
session(sessionId) {
return this.#sessions.get(sessionId) || null;
}
send(method, ...paramArgs) {
const params = paramArgs.length ? paramArgs[0] : undefined;
const id = this._rawSend({ method, params });
return new Promise((resolve, reject) => {
this.#callbacks.set(id, {
resolve,
reject,
method,
returnSize: true,
stack: new Error().stack ?? "",
fn: method + JSON.stringify(params)
});
});
}
_rawSend(message) {
const id = ++this.#lastId;
const stringifiedMessage = JSON.stringify({ ...message, id });
this.transport.send(stringifiedMessage);
return id;
}
#onMessage(message) {
const object = JSON.parse(message);
if (object.method === "Target.attachedToTarget") {
const { sessionId } = object.params;
const session = new CDPSession(this, object.params.targetInfo.type, sessionId);
this.#sessions.set(sessionId, session);
this.emit("sessionattached", session);
const parentSession = this.#sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit("sessionattached", session);
}
} else if (object.method === "Target.detachedFromTarget") {
const session = this.#sessions.get(object.params.sessionId);
if (session) {
session._onClosed();
this.#sessions.delete(object.params.sessionId);
this.emit("sessiondetached", session);
const parentSession = this.#sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit("sessiondetached", session);
}
}
}
if (object.sessionId) {
const session = this.#sessions.get(object.sessionId);
if (session) {
session._onMessage(object, message.length);
}
} else if (object.id) {
const callback = this.#callbacks.get(object.id);
if (callback) {
this.#callbacks.delete(object.id);
if (object.error) {
callback.reject(createProtocolError(callback.method, object));
} else if (callback.returnSize) {
callback.resolve({ value: object.result, size: message.length });
} else {
callback.resolve(object.result);
}
}
} else {
this.emit(object.method, object.params);
}
}
#onClose() {
if (this.#closed) {
return;
}
this.transport.onmessage = undefined;
this.transport.onclose = undefined;
for (const callback of this.#callbacks.values()) {
callback.reject(rewriteError(new ProtocolError, `Protocol error (${callback.method}): Target closed. https://www.remotion.dev/docs/target-closed`));
}
this.#callbacks.clear();
for (const session of this.#sessions.values()) {
session._onClosed();
}
this.#sessions.clear();
this.emit(ConnectionEmittedEvents.Disconnected);
}
dispose() {
this.#onClose();
this.transport.close();
}
async createSession(targetInfo) {
const {
value: { sessionId }
} = await this.send("Target.attachToTarget", {
targetId: targetInfo.targetId,
flatten: true
});
const session = this