@remotion/vercel 4.0.468 → 4.0.470
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.mjs +267 -64
- package/dist/get-render-progress.d.ts +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/render-media-on-vercel.d.ts +24 -6
- package/dist/types.d.ts +32 -10
- package/package.json +4 -4
package/dist/esm/index.mjs
CHANGED
|
@@ -167,8 +167,8 @@ function checkValidInputRange(arr) {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
function checkInfiniteRange(name, arr) {
|
|
170
|
-
if (arr.length <
|
|
171
|
-
throw new Error(name + " must have at least
|
|
170
|
+
if (arr.length < 1) {
|
|
171
|
+
throw new Error(name + " must have at least 1 element");
|
|
172
172
|
}
|
|
173
173
|
for (const element of arr) {
|
|
174
174
|
if (typeof element !== "number") {
|
|
@@ -196,6 +196,14 @@ function assertValidInterpolateEasingOption(easing, inputRangeLength) {
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
+
function assertValidInterpolatePosterizeOption(posterize) {
|
|
200
|
+
if (posterize === undefined) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (typeof posterize !== "number" || !Number.isFinite(posterize) || posterize <= 0) {
|
|
204
|
+
throw new Error(\`posterize must be a positive finite number, but got \${posterize}\`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
199
207
|
function interpolate(input, inputRange, outputRange, options) {
|
|
200
208
|
if (typeof input === "undefined") {
|
|
201
209
|
throw new Error("input can not be undefined");
|
|
@@ -213,6 +221,7 @@ function interpolate(input, inputRange, outputRange, options) {
|
|
|
213
221
|
checkInfiniteRange("outputRange", outputRange);
|
|
214
222
|
checkValidInputRange(inputRange);
|
|
215
223
|
assertValidInterpolateEasingOption(options?.easing, inputRange.length);
|
|
224
|
+
assertValidInterpolatePosterizeOption(options?.posterize);
|
|
216
225
|
const easingOption = options?.easing;
|
|
217
226
|
const defaultEasing = (num) => num;
|
|
218
227
|
const resolveEasingForSegment = (segmentIndex) => {
|
|
@@ -235,8 +244,12 @@ function interpolate(input, inputRange, outputRange, options) {
|
|
|
235
244
|
if (typeof input !== "number") {
|
|
236
245
|
throw new TypeError("Cannot interpolate an input which is not a number");
|
|
237
246
|
}
|
|
238
|
-
|
|
239
|
-
|
|
247
|
+
if (inputRange.length === 1) {
|
|
248
|
+
return outputRange[0];
|
|
249
|
+
}
|
|
250
|
+
const posterizedInput = options?.posterize === undefined ? input : Math.floor(input / options.posterize) * options.posterize;
|
|
251
|
+
const range = findRange(posterizedInput, inputRange);
|
|
252
|
+
return interpolateFunction(posterizedInput, [inputRange[range], inputRange[range + 1]], [outputRange[range], outputRange[range + 1]], {
|
|
240
253
|
easing: resolveEasingForSegment(range),
|
|
241
254
|
extrapolateLeft,
|
|
242
255
|
extrapolateRight
|
|
@@ -1140,8 +1153,10 @@ try {
|
|
|
1140
1153
|
|
|
1141
1154
|
// script-embed:render-video-script
|
|
1142
1155
|
var script2 = `// src/scripts/render-video.ts
|
|
1143
|
-
import {
|
|
1156
|
+
import { randomUUID } from "crypto";
|
|
1157
|
+
import { stat, readFile, rename, writeFile } from "fs/promises";
|
|
1144
1158
|
import { RenderInternals } from "@remotion/renderer";
|
|
1159
|
+
import { put } from "@vercel/blob";
|
|
1145
1160
|
|
|
1146
1161
|
// ../core/dist/esm/no-react.mjs
|
|
1147
1162
|
function interpolateFunction(input, inputRange, outputRange, options) {
|
|
@@ -1196,8 +1211,8 @@ function checkValidInputRange(arr) {
|
|
|
1196
1211
|
}
|
|
1197
1212
|
}
|
|
1198
1213
|
function checkInfiniteRange(name, arr) {
|
|
1199
|
-
if (arr.length <
|
|
1200
|
-
throw new Error(name + " must have at least
|
|
1214
|
+
if (arr.length < 1) {
|
|
1215
|
+
throw new Error(name + " must have at least 1 element");
|
|
1201
1216
|
}
|
|
1202
1217
|
for (const element of arr) {
|
|
1203
1218
|
if (typeof element !== "number") {
|
|
@@ -1225,6 +1240,14 @@ function assertValidInterpolateEasingOption(easing, inputRangeLength) {
|
|
|
1225
1240
|
}
|
|
1226
1241
|
}
|
|
1227
1242
|
}
|
|
1243
|
+
function assertValidInterpolatePosterizeOption(posterize) {
|
|
1244
|
+
if (posterize === undefined) {
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
if (typeof posterize !== "number" || !Number.isFinite(posterize) || posterize <= 0) {
|
|
1248
|
+
throw new Error(\`posterize must be a positive finite number, but got \${posterize}\`);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1228
1251
|
function interpolate(input, inputRange, outputRange, options) {
|
|
1229
1252
|
if (typeof input === "undefined") {
|
|
1230
1253
|
throw new Error("input can not be undefined");
|
|
@@ -1242,6 +1265,7 @@ function interpolate(input, inputRange, outputRange, options) {
|
|
|
1242
1265
|
checkInfiniteRange("outputRange", outputRange);
|
|
1243
1266
|
checkValidInputRange(inputRange);
|
|
1244
1267
|
assertValidInterpolateEasingOption(options?.easing, inputRange.length);
|
|
1268
|
+
assertValidInterpolatePosterizeOption(options?.posterize);
|
|
1245
1269
|
const easingOption = options?.easing;
|
|
1246
1270
|
const defaultEasing = (num) => num;
|
|
1247
1271
|
const resolveEasingForSegment = (segmentIndex) => {
|
|
@@ -1264,8 +1288,12 @@ function interpolate(input, inputRange, outputRange, options) {
|
|
|
1264
1288
|
if (typeof input !== "number") {
|
|
1265
1289
|
throw new TypeError("Cannot interpolate an input which is not a number");
|
|
1266
1290
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1291
|
+
if (inputRange.length === 1) {
|
|
1292
|
+
return outputRange[0];
|
|
1293
|
+
}
|
|
1294
|
+
const posterizedInput = options?.posterize === undefined ? input : Math.floor(input / options.posterize) * options.posterize;
|
|
1295
|
+
const range = findRange(posterizedInput, inputRange);
|
|
1296
|
+
return interpolateFunction(posterizedInput, [inputRange[range], inputRange[range + 1]], [outputRange[range], outputRange[range + 1]], {
|
|
1269
1297
|
easing: resolveEasingForSegment(range),
|
|
1270
1298
|
extrapolateLeft,
|
|
1271
1299
|
extrapolateRight
|
|
@@ -2064,17 +2092,58 @@ var NoReactInternals = {
|
|
|
2064
2092
|
};
|
|
2065
2093
|
|
|
2066
2094
|
// src/scripts/render-video.ts
|
|
2095
|
+
var PROGRESS_FILE = "/vercel/sandbox/progress.json";
|
|
2067
2096
|
var config = JSON.parse(process.argv[2]);
|
|
2068
2097
|
var noop = () => {
|
|
2069
2098
|
return;
|
|
2070
2099
|
};
|
|
2100
|
+
var progressWrite = Promise.resolve();
|
|
2101
|
+
function getExtension(filePath) {
|
|
2102
|
+
const lastDot = filePath.lastIndexOf(".");
|
|
2103
|
+
if (lastDot === -1) {
|
|
2104
|
+
return "";
|
|
2105
|
+
}
|
|
2106
|
+
return filePath.slice(lastDot);
|
|
2107
|
+
}
|
|
2108
|
+
var writeProgress = (message) => {
|
|
2109
|
+
const tmpFile = \`\${PROGRESS_FILE}.tmp\`;
|
|
2110
|
+
progressWrite = progressWrite.then(async () => {
|
|
2111
|
+
await writeFile(tmpFile, JSON.stringify(message));
|
|
2112
|
+
await rename(tmpFile, PROGRESS_FILE);
|
|
2113
|
+
});
|
|
2114
|
+
return progressWrite;
|
|
2115
|
+
};
|
|
2116
|
+
var reportProgress = async (message) => {
|
|
2117
|
+
console.log(JSON.stringify(message));
|
|
2118
|
+
await writeProgress(message);
|
|
2119
|
+
};
|
|
2120
|
+
var uploadToVercelBlob = async ({
|
|
2121
|
+
sandboxFilePath,
|
|
2122
|
+
contentType,
|
|
2123
|
+
access,
|
|
2124
|
+
blobPath
|
|
2125
|
+
}) => {
|
|
2126
|
+
const blobToken = process.env.BLOB_READ_WRITE_TOKEN;
|
|
2127
|
+
if (!blobToken) {
|
|
2128
|
+
throw new Error("BLOB_READ_WRITE_TOKEN is not set.");
|
|
2129
|
+
}
|
|
2130
|
+
const actualBlobPath = blobPath ?? \`renders/\${randomUUID()}\${getExtension(sandboxFilePath)}\`;
|
|
2131
|
+
const fileBuffer = await readFile(sandboxFilePath);
|
|
2132
|
+
const { size } = await stat(sandboxFilePath);
|
|
2133
|
+
const blob = await put(actualBlobPath, fileBuffer, {
|
|
2134
|
+
access,
|
|
2135
|
+
contentType,
|
|
2136
|
+
token: blobToken
|
|
2137
|
+
});
|
|
2138
|
+
return { url: blob.downloadUrl, size };
|
|
2139
|
+
};
|
|
2071
2140
|
try {
|
|
2072
2141
|
const serializedInputProps = NoReactInternals.serializeJSONWithSpecialTypes({
|
|
2073
2142
|
data: config.inputProps,
|
|
2074
2143
|
indent: undefined,
|
|
2075
2144
|
staticBase: null
|
|
2076
2145
|
}).serializedString;
|
|
2077
|
-
|
|
2146
|
+
await reportProgress({ stage: "opening-browser", overallProgress: 0 });
|
|
2078
2147
|
const browser = await RenderInternals.internalOpenBrowser({
|
|
2079
2148
|
browser: "chrome",
|
|
2080
2149
|
browserExecutable: config.browserExecutable,
|
|
@@ -2089,7 +2158,7 @@ try {
|
|
|
2089
2158
|
}),
|
|
2090
2159
|
chromeMode: config.chromeMode
|
|
2091
2160
|
});
|
|
2092
|
-
|
|
2161
|
+
await reportProgress({ stage: "selecting-composition", overallProgress: 0.02 });
|
|
2093
2162
|
const { metadata: composition } = await RenderInternals.internalSelectComposition({
|
|
2094
2163
|
serializedInputPropsWithCustomSchema: serializedInputProps,
|
|
2095
2164
|
envVariables: config.envVariables,
|
|
@@ -2169,7 +2238,7 @@ try {
|
|
|
2169
2238
|
sampleRate: config.sampleRate,
|
|
2170
2239
|
puppeteerInstance: browser,
|
|
2171
2240
|
onProgress: (progress) => {
|
|
2172
|
-
|
|
2241
|
+
reportProgress({
|
|
2173
2242
|
stage: "render-progress",
|
|
2174
2243
|
progress: {
|
|
2175
2244
|
renderedFrames: progress.renderedFrames,
|
|
@@ -2180,8 +2249,10 @@ try {
|
|
|
2180
2249
|
progress: progress.progress,
|
|
2181
2250
|
stitchStage: progress.stitchStage
|
|
2182
2251
|
},
|
|
2183
|
-
overallProgress: 0.04 + progress.progress * 0.
|
|
2184
|
-
}))
|
|
2252
|
+
overallProgress: 0.04 + progress.progress * 0.94
|
|
2253
|
+
}).catch((error) => {
|
|
2254
|
+
console.error(error.message);
|
|
2255
|
+
});
|
|
2185
2256
|
},
|
|
2186
2257
|
onDownload: () => {
|
|
2187
2258
|
return;
|
|
@@ -2203,12 +2274,44 @@ try {
|
|
|
2203
2274
|
onProgress: noop
|
|
2204
2275
|
})
|
|
2205
2276
|
});
|
|
2206
|
-
|
|
2277
|
+
await progressWrite;
|
|
2278
|
+
console.log(JSON.stringify({ stage: "render-complete", overallProgress: 0.98 }));
|
|
2207
2279
|
await browser.close({ silent: false });
|
|
2208
|
-
const
|
|
2209
|
-
|
|
2280
|
+
const sandboxFilePath = config.outputLocation ?? "/tmp/video.mp4";
|
|
2281
|
+
if (config.vercelBlob) {
|
|
2282
|
+
await reportProgress({ stage: "uploading", overallProgress: 0.99 });
|
|
2283
|
+
const { url, size } = await uploadToVercelBlob({
|
|
2284
|
+
sandboxFilePath,
|
|
2285
|
+
contentType,
|
|
2286
|
+
access: config.vercelBlob.access,
|
|
2287
|
+
blobPath: config.vercelBlob.blobPath
|
|
2288
|
+
});
|
|
2289
|
+
await reportProgress({
|
|
2290
|
+
stage: "done",
|
|
2291
|
+
url,
|
|
2292
|
+
size,
|
|
2293
|
+
contentType,
|
|
2294
|
+
overallProgress: 1
|
|
2295
|
+
});
|
|
2296
|
+
} else {
|
|
2297
|
+
const { size } = await stat(sandboxFilePath);
|
|
2298
|
+
await reportProgress({
|
|
2299
|
+
stage: "done",
|
|
2300
|
+
size,
|
|
2301
|
+
contentType,
|
|
2302
|
+
overallProgress: 1
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2210
2305
|
} catch (err) {
|
|
2211
|
-
|
|
2306
|
+
const message = err.message;
|
|
2307
|
+
await writeProgress({
|
|
2308
|
+
stage: "error",
|
|
2309
|
+
message,
|
|
2310
|
+
overallProgress: 1
|
|
2311
|
+
}).catch(() => {
|
|
2312
|
+
return;
|
|
2313
|
+
});
|
|
2314
|
+
console.error(message);
|
|
2212
2315
|
process.exit(1);
|
|
2213
2316
|
}
|
|
2214
2317
|
`;
|
|
@@ -2501,50 +2604,135 @@ async function createSandbox({
|
|
|
2501
2604
|
await report(1, "Sandbox ready");
|
|
2502
2605
|
return sandbox;
|
|
2503
2606
|
}
|
|
2504
|
-
// src/render-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
metadata,
|
|
2526
|
-
licenseKey,
|
|
2527
|
-
videoBitrate,
|
|
2528
|
-
audioBitrate,
|
|
2529
|
-
encodingMaxRate,
|
|
2530
|
-
encodingBufferSize,
|
|
2531
|
-
muted = false,
|
|
2532
|
-
numberOfGifLoops,
|
|
2533
|
-
x264Preset,
|
|
2534
|
-
gopSize,
|
|
2535
|
-
colorSpace = "default",
|
|
2536
|
-
jpegQuality = 80,
|
|
2537
|
-
audioCodec,
|
|
2538
|
-
logLevel = "info",
|
|
2539
|
-
timeoutInMilliseconds = 30000,
|
|
2540
|
-
forSeamlessAacConcatenation = false,
|
|
2541
|
-
separateAudioTo,
|
|
2542
|
-
hardwareAcceleration = "disable",
|
|
2543
|
-
offthreadVideoCacheSizeInBytes,
|
|
2544
|
-
mediaCacheSizeInBytes,
|
|
2545
|
-
offthreadVideoThreads,
|
|
2546
|
-
sampleRate
|
|
2607
|
+
// src/get-render-progress.ts
|
|
2608
|
+
import { Sandbox as Sandbox2 } from "@vercel/sandbox";
|
|
2609
|
+
var PROGRESS_FILE = "/vercel/sandbox/progress.json";
|
|
2610
|
+
var isStoppedOrExpiredSandboxError = (error) => {
|
|
2611
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
2612
|
+
return error.code === "sandbox_stopped";
|
|
2613
|
+
}
|
|
2614
|
+
if (!(error instanceof Error)) {
|
|
2615
|
+
return false;
|
|
2616
|
+
}
|
|
2617
|
+
return error.message.includes("sandbox_stopped") || error.message.includes("Sandbox has stopped execution") || error.message.includes("no longer available");
|
|
2618
|
+
};
|
|
2619
|
+
var getCommandError = async (command) => {
|
|
2620
|
+
const stderr = await command.stderr().catch(() => "");
|
|
2621
|
+
const stdout = await command.stdout().catch(() => "");
|
|
2622
|
+
const output = [stderr, stdout].filter(Boolean).join(" ");
|
|
2623
|
+
return output || `Render command exited with code ${command.exitCode}.`;
|
|
2624
|
+
};
|
|
2625
|
+
async function getRenderProgress({
|
|
2626
|
+
sandboxId,
|
|
2627
|
+
cmdId
|
|
2547
2628
|
}) {
|
|
2629
|
+
let sandbox;
|
|
2630
|
+
try {
|
|
2631
|
+
sandbox = await Sandbox2.get({ sandboxId });
|
|
2632
|
+
} catch {
|
|
2633
|
+
return { stage: "expired" };
|
|
2634
|
+
}
|
|
2635
|
+
let command;
|
|
2636
|
+
try {
|
|
2637
|
+
command = await sandbox.getCommand(cmdId);
|
|
2638
|
+
} catch (err) {
|
|
2639
|
+
if (isStoppedOrExpiredSandboxError(err)) {
|
|
2640
|
+
return { stage: "expired" };
|
|
2641
|
+
}
|
|
2642
|
+
return {
|
|
2643
|
+
stage: "error",
|
|
2644
|
+
message: err.message,
|
|
2645
|
+
overallProgress: 1
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
let buffer;
|
|
2649
|
+
try {
|
|
2650
|
+
buffer = await sandbox.readFileToBuffer({ path: PROGRESS_FILE });
|
|
2651
|
+
} catch (err) {
|
|
2652
|
+
if (isStoppedOrExpiredSandboxError(err)) {
|
|
2653
|
+
return { stage: "expired" };
|
|
2654
|
+
}
|
|
2655
|
+
return {
|
|
2656
|
+
stage: "error",
|
|
2657
|
+
message: err.message,
|
|
2658
|
+
overallProgress: 1
|
|
2659
|
+
};
|
|
2660
|
+
}
|
|
2661
|
+
if (!buffer) {
|
|
2662
|
+
if (command.exitCode === null) {
|
|
2663
|
+
return { stage: "starting", overallProgress: 0 };
|
|
2664
|
+
}
|
|
2665
|
+
const message = await getCommandError(command);
|
|
2666
|
+
return { stage: "error", message, overallProgress: 1 };
|
|
2667
|
+
}
|
|
2668
|
+
let progress;
|
|
2669
|
+
try {
|
|
2670
|
+
progress = JSON.parse(buffer.toString("utf-8"));
|
|
2671
|
+
} catch {
|
|
2672
|
+
return {
|
|
2673
|
+
stage: "error",
|
|
2674
|
+
message: "Could not parse the render progress file.",
|
|
2675
|
+
overallProgress: 1
|
|
2676
|
+
};
|
|
2677
|
+
}
|
|
2678
|
+
if (command.exitCode !== null && command.exitCode !== 0) {
|
|
2679
|
+
const message = await getCommandError(command);
|
|
2680
|
+
return { stage: "error", message, overallProgress: 1 };
|
|
2681
|
+
}
|
|
2682
|
+
return progress;
|
|
2683
|
+
}
|
|
2684
|
+
// src/render-media-on-vercel.ts
|
|
2685
|
+
var DEFAULT_DETACHED_SANDBOX_TIMEOUT = 30 * 60 * 1000;
|
|
2686
|
+
var internalRenderMediaOnVercel = async (options) => {
|
|
2687
|
+
const {
|
|
2688
|
+
sandbox,
|
|
2689
|
+
compositionId,
|
|
2690
|
+
inputProps,
|
|
2691
|
+
onProgress,
|
|
2692
|
+
outputFile = "/tmp/video.mp4",
|
|
2693
|
+
codec = "h264",
|
|
2694
|
+
crf,
|
|
2695
|
+
imageFormat,
|
|
2696
|
+
pixelFormat,
|
|
2697
|
+
envVariables = {},
|
|
2698
|
+
frameRange,
|
|
2699
|
+
everyNthFrame = 1,
|
|
2700
|
+
proResProfile,
|
|
2701
|
+
chromiumOptions = {},
|
|
2702
|
+
scale = 1,
|
|
2703
|
+
preferLossless = false,
|
|
2704
|
+
enforceAudioTrack = false,
|
|
2705
|
+
disallowParallelEncoding = false,
|
|
2706
|
+
concurrency,
|
|
2707
|
+
metadata,
|
|
2708
|
+
licenseKey,
|
|
2709
|
+
videoBitrate,
|
|
2710
|
+
audioBitrate,
|
|
2711
|
+
encodingMaxRate,
|
|
2712
|
+
encodingBufferSize,
|
|
2713
|
+
muted = false,
|
|
2714
|
+
numberOfGifLoops,
|
|
2715
|
+
x264Preset,
|
|
2716
|
+
gopSize,
|
|
2717
|
+
colorSpace = "default",
|
|
2718
|
+
jpegQuality = 80,
|
|
2719
|
+
audioCodec,
|
|
2720
|
+
logLevel = "info",
|
|
2721
|
+
timeoutInMilliseconds = 30000,
|
|
2722
|
+
forSeamlessAacConcatenation = false,
|
|
2723
|
+
separateAudioTo,
|
|
2724
|
+
hardwareAcceleration = "disable",
|
|
2725
|
+
offthreadVideoCacheSizeInBytes,
|
|
2726
|
+
mediaCacheSizeInBytes,
|
|
2727
|
+
offthreadVideoThreads,
|
|
2728
|
+
sampleRate,
|
|
2729
|
+
detached = false,
|
|
2730
|
+
detachedSandboxTimeoutInMilliseconds = DEFAULT_DETACHED_SANDBOX_TIMEOUT
|
|
2731
|
+
} = options;
|
|
2732
|
+
const vercelBlob = options.detached ? options.vercelBlob : undefined;
|
|
2733
|
+
if (detached && !vercelBlob) {
|
|
2734
|
+
throw new Error("The vercelBlob option is required when detached is set to true.");
|
|
2735
|
+
}
|
|
2548
2736
|
const serveUrl = `/vercel/sandbox/${REMOTION_SANDBOX_BUNDLE_DIR}`;
|
|
2549
2737
|
const renderConfig = {
|
|
2550
2738
|
serveUrl,
|
|
@@ -2590,13 +2778,26 @@ async function renderMediaOnVercel({
|
|
|
2590
2778
|
browserExecutable: null,
|
|
2591
2779
|
binariesDirectory: null,
|
|
2592
2780
|
repro: false,
|
|
2593
|
-
sampleRate: sampleRate ?? 48000
|
|
2781
|
+
sampleRate: sampleRate ?? 48000,
|
|
2782
|
+
vercelBlob: vercelBlob ? {
|
|
2783
|
+
blobPath: vercelBlob.blobPath ?? null,
|
|
2784
|
+
access: vercelBlob.access
|
|
2785
|
+
} : null
|
|
2594
2786
|
};
|
|
2595
2787
|
const renderCmd = await sandbox.runCommand({
|
|
2596
2788
|
cmd: "node",
|
|
2597
2789
|
args: ["render-video.mjs", JSON.stringify(renderConfig)],
|
|
2598
|
-
detached: true
|
|
2790
|
+
detached: true,
|
|
2791
|
+
env: vercelBlob ? { BLOB_READ_WRITE_TOKEN: vercelBlob.blobToken } : undefined
|
|
2599
2792
|
});
|
|
2793
|
+
if (detached) {
|
|
2794
|
+
await sandbox.extendTimeout(detachedSandboxTimeoutInMilliseconds);
|
|
2795
|
+
return {
|
|
2796
|
+
sandboxId: sandbox.sandboxId,
|
|
2797
|
+
cmdId: renderCmd.cmdId,
|
|
2798
|
+
outputFile
|
|
2799
|
+
};
|
|
2800
|
+
}
|
|
2600
2801
|
let contentType = "application/octet-stream";
|
|
2601
2802
|
for await (const log of renderCmd.logs()) {
|
|
2602
2803
|
if (log.stream === "stdout") {
|
|
@@ -2617,7 +2818,8 @@ async function renderMediaOnVercel({
|
|
|
2617
2818
|
throw new Error(`Render failed: ${stderr} ${stdout}`);
|
|
2618
2819
|
}
|
|
2619
2820
|
return { sandboxFilePath: outputFile, contentType };
|
|
2620
|
-
}
|
|
2821
|
+
};
|
|
2822
|
+
var renderMediaOnVercel = internalRenderMediaOnVercel;
|
|
2621
2823
|
// src/render-still-on-vercel.ts
|
|
2622
2824
|
async function renderStillOnVercel({
|
|
2623
2825
|
sandbox,
|
|
@@ -2749,6 +2951,7 @@ export {
|
|
|
2749
2951
|
uploadToVercelBlob,
|
|
2750
2952
|
renderStillOnVercel,
|
|
2751
2953
|
renderMediaOnVercel,
|
|
2954
|
+
getRenderProgress,
|
|
2752
2955
|
createSandbox,
|
|
2753
2956
|
addBundleToSandbox
|
|
2754
2957
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { addBundleToSandbox } from './add-bundle-to-sandbox';
|
|
2
2
|
export { createSandbox } from './create-sandbox';
|
|
3
|
+
export { getRenderProgress } from './get-render-progress';
|
|
3
4
|
export { renderMediaOnVercel } from './render-media-on-vercel';
|
|
4
5
|
export { renderStillOnVercel } from './render-still-on-vercel';
|
|
5
|
-
export type { AudioCodec, Bitrate, ChromeMode, ChromiumOptions, Codec, ColorSpace, CreateSandboxOnProgress, FrameRange, HardwareAccelerationOption, LogLevel, OpenGlRenderer, PixelFormat, ProResProfile, RenderMediaOnProgress, RenderMediaOnVercelProgress, RenderMediaProgress, RenderStillOnVercelProgress, StillImageFormat, StitchingState, VercelBlobAccess, VercelSandbox, VideoImageFormat, X264Preset, } from './types';
|
|
6
|
+
export type { AudioCodec, Bitrate, ChromeMode, ChromiumOptions, Codec, ColorSpace, CreateSandboxOnProgress, FrameRange, HardwareAccelerationOption, LogLevel, OpenGlRenderer, PixelFormat, ProResProfile, RenderMediaOnProgress, RenderMediaOnVercelProgress, RenderMediaProgress, RenderProgress, RenderStillOnVercelProgress, StillImageFormat, StitchingState, VercelBlobAccess, VercelBlobUploadOptions, VercelSandbox, VideoImageFormat, X264Preset, } from './types';
|
|
6
7
|
export { uploadToVercelBlob } from './upload-to-vercel-blob';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Sandbox } from '@vercel/sandbox';
|
|
2
|
-
import type { AudioCodec, Bitrate, ChromiumOptions, Codec, ColorSpace, FrameRange, HardwareAccelerationOption, LogLevel, PixelFormat, ProResProfile, RenderMediaOnVercelProgress, VideoImageFormat, X264Preset } from './types';
|
|
3
|
-
|
|
2
|
+
import type { AudioCodec, Bitrate, ChromiumOptions, Codec, ColorSpace, FrameRange, HardwareAccelerationOption, LogLevel, PixelFormat, ProResProfile, RenderMediaOnVercelProgress, VercelBlobUploadOptions, VideoImageFormat, X264Preset } from './types';
|
|
3
|
+
type RenderMediaOnVercelBaseOptions = {
|
|
4
4
|
sandbox: Sandbox;
|
|
5
5
|
compositionId: string;
|
|
6
6
|
inputProps: Record<string, unknown>;
|
|
@@ -42,7 +42,25 @@ export declare function renderMediaOnVercel({ sandbox, compositionId, inputProps
|
|
|
42
42
|
mediaCacheSizeInBytes?: number | null;
|
|
43
43
|
offthreadVideoThreads?: number | null;
|
|
44
44
|
sampleRate?: number;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
detachedSandboxTimeoutInMilliseconds?: number;
|
|
46
|
+
};
|
|
47
|
+
type RenderMediaOnVercelRegularOptions = RenderMediaOnVercelBaseOptions & {
|
|
48
|
+
detached?: false;
|
|
49
|
+
};
|
|
50
|
+
type RenderMediaOnVercelDetachedOptions = RenderMediaOnVercelBaseOptions & {
|
|
51
|
+
detached: true;
|
|
52
|
+
vercelBlob: VercelBlobUploadOptions;
|
|
53
|
+
};
|
|
54
|
+
type RenderMediaOnVercelFunction = {
|
|
55
|
+
(options: RenderMediaOnVercelDetachedOptions): Promise<{
|
|
56
|
+
sandboxId: string;
|
|
57
|
+
cmdId: string;
|
|
58
|
+
outputFile: string;
|
|
59
|
+
}>;
|
|
60
|
+
(options: RenderMediaOnVercelRegularOptions): Promise<{
|
|
61
|
+
sandboxFilePath: string;
|
|
62
|
+
contentType: string;
|
|
63
|
+
}>;
|
|
64
|
+
};
|
|
65
|
+
export declare const renderMediaOnVercel: RenderMediaOnVercelFunction;
|
|
66
|
+
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -17,33 +17,55 @@ export type RenderMediaOnVercelProgress = {
|
|
|
17
17
|
progress: RenderMediaProgress;
|
|
18
18
|
overallProgress: number;
|
|
19
19
|
};
|
|
20
|
-
export type
|
|
21
|
-
stage: '
|
|
20
|
+
export type RenderProgress = {
|
|
21
|
+
stage: 'starting';
|
|
22
|
+
overallProgress: number;
|
|
23
|
+
} | RenderMediaOnVercelProgress | {
|
|
24
|
+
stage: 'uploading';
|
|
22
25
|
overallProgress: number;
|
|
23
26
|
} | {
|
|
24
|
-
stage: '
|
|
27
|
+
stage: 'done';
|
|
28
|
+
url: string;
|
|
29
|
+
size: number;
|
|
30
|
+
contentType: string;
|
|
25
31
|
overallProgress: number;
|
|
32
|
+
} | {
|
|
33
|
+
stage: 'error';
|
|
34
|
+
message: string;
|
|
35
|
+
overallProgress: number;
|
|
36
|
+
} | {
|
|
37
|
+
stage: 'expired';
|
|
26
38
|
};
|
|
27
|
-
export type
|
|
28
|
-
export type VercelBlobAccess = 'public' | 'private';
|
|
29
|
-
export type SandboxRenderMediaMessage = {
|
|
39
|
+
export type RenderStillOnVercelProgress = {
|
|
30
40
|
stage: 'opening-browser';
|
|
31
41
|
overallProgress: number;
|
|
32
42
|
} | {
|
|
33
43
|
stage: 'selecting-composition';
|
|
34
44
|
overallProgress: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
};
|
|
46
|
+
export type { HardwareAccelerationOption, ProResProfile, } from '@remotion/renderer/client';
|
|
47
|
+
export type VercelBlobAccess = 'public' | 'private';
|
|
48
|
+
export type VercelBlobUploadOptions = {
|
|
49
|
+
blobToken: string;
|
|
50
|
+
access: VercelBlobAccess;
|
|
51
|
+
blobPath?: string;
|
|
52
|
+
};
|
|
53
|
+
export type SandboxRenderMediaMessage = RenderMediaOnVercelProgress | {
|
|
54
|
+
stage: 'render-complete';
|
|
38
55
|
overallProgress: number;
|
|
39
56
|
} | {
|
|
40
|
-
stage: '
|
|
57
|
+
stage: 'uploading';
|
|
41
58
|
overallProgress: number;
|
|
42
59
|
} | {
|
|
43
60
|
stage: 'done';
|
|
44
61
|
size: number;
|
|
45
62
|
contentType: string;
|
|
46
63
|
overallProgress: number;
|
|
64
|
+
url?: string;
|
|
65
|
+
} | {
|
|
66
|
+
stage: 'error';
|
|
67
|
+
message: string;
|
|
68
|
+
overallProgress: number;
|
|
47
69
|
};
|
|
48
70
|
export type SandboxRenderStillMessage = {
|
|
49
71
|
type: 'opening-browser';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/vercel",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.470",
|
|
4
4
|
"description": "Render Remotion videos on Vercel Sandbox",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"url": "https://github.com/remotion-dev/remotion/issues"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@remotion/renderer": "4.0.
|
|
27
|
-
"remotion": "4.0.
|
|
26
|
+
"@remotion/renderer": "4.0.470",
|
|
27
|
+
"remotion": "4.0.470"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@vercel/sandbox": ">=1.0.0"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"./package.json": "./package.json"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
41
|
+
"@remotion/eslint-config-internal": "4.0.470",
|
|
42
42
|
"@vercel/blob": "2.3.0",
|
|
43
43
|
"@vercel/sandbox": "1.6.0",
|
|
44
44
|
"eslint": "9.19.0",
|