@remotion/vercel 4.0.426
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/README.md +18 -0
- package/dist/add-bundle-to-sandbox.d.ts +5 -0
- package/dist/create-sandbox.d.ts +9 -0
- package/dist/esm/index.mjs +2096 -0
- package/dist/index.d.ts +6 -0
- package/dist/internals/add-bundle.d.ts +1 -0
- package/dist/internals/disposable.d.ts +2 -0
- package/dist/internals/install-browser.d.ts +5 -0
- package/dist/internals/install-js-dependencies.d.ts +4 -0
- package/dist/internals/install-system-dependencies.d.ts +5 -0
- package/dist/internals/patch-compositor.d.ts +14 -0
- package/dist/render-media-on-vercel.d.ts +46 -0
- package/dist/render-still-on-vercel.d.ts +24 -0
- package/dist/render-video-on-vercel.d.ts +51 -0
- package/dist/restore-snapshot.d.ts +2 -0
- package/dist/save-snapshot.d.ts +7 -0
- package/dist/scripts/ensure-browser.d.ts +1 -0
- package/dist/scripts/render-still.d.ts +1 -0
- package/dist/scripts/render-video.d.ts +1 -0
- package/dist/scripts/upload-blob.d.ts +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/upload-to-vercel-blob.d.ts +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,2096 @@
|
|
|
1
|
+
// src/add-bundle-to-sandbox.ts
|
|
2
|
+
import { readdir, readFile } from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/internals/add-bundle.ts
|
|
6
|
+
var REMOTION_SANDBOX_BUNDLE_DIR = "remotion-bundle";
|
|
7
|
+
|
|
8
|
+
// src/add-bundle-to-sandbox.ts
|
|
9
|
+
async function getRemotionBundleFiles(bundleDir) {
|
|
10
|
+
const fullBundleDir = path.join(process.cwd(), bundleDir);
|
|
11
|
+
const files = [];
|
|
12
|
+
async function readDirRecursive(dir, basePath = "") {
|
|
13
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const fullPath = path.join(dir, entry.name);
|
|
16
|
+
const relativePath = path.join(basePath, entry.name);
|
|
17
|
+
if (entry.isDirectory()) {
|
|
18
|
+
await readDirRecursive(fullPath, relativePath);
|
|
19
|
+
} else {
|
|
20
|
+
const content = await readFile(fullPath);
|
|
21
|
+
files.push({ path: relativePath, content });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
await readDirRecursive(fullBundleDir);
|
|
26
|
+
return files;
|
|
27
|
+
}
|
|
28
|
+
async function addBundleToSandbox({
|
|
29
|
+
sandbox,
|
|
30
|
+
bundleDir
|
|
31
|
+
}) {
|
|
32
|
+
const bundleFiles = await getRemotionBundleFiles(bundleDir);
|
|
33
|
+
const dirs = new Set;
|
|
34
|
+
for (const file of bundleFiles) {
|
|
35
|
+
const dir = path.dirname(file.path);
|
|
36
|
+
if (dir && dir !== ".") {
|
|
37
|
+
dirs.add(dir);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const dir of Array.from(dirs).sort()) {
|
|
41
|
+
await sandbox.mkDir(REMOTION_SANDBOX_BUNDLE_DIR + "/" + dir);
|
|
42
|
+
}
|
|
43
|
+
await sandbox.writeFiles(bundleFiles.map((file) => ({
|
|
44
|
+
path: REMOTION_SANDBOX_BUNDLE_DIR + "/" + file.path,
|
|
45
|
+
content: file.content
|
|
46
|
+
})));
|
|
47
|
+
}
|
|
48
|
+
// script-embed:render-still-script
|
|
49
|
+
var script = `// src/scripts/render-still.ts
|
|
50
|
+
import { RenderInternals } from "@remotion/renderer";
|
|
51
|
+
import { statSync } from "fs";
|
|
52
|
+
|
|
53
|
+
// ../core/dist/esm/no-react.mjs
|
|
54
|
+
function interpolateFunction(input, inputRange, outputRange, options) {
|
|
55
|
+
const { extrapolateLeft, extrapolateRight, easing } = options;
|
|
56
|
+
let result = input;
|
|
57
|
+
const [inputMin, inputMax] = inputRange;
|
|
58
|
+
const [outputMin, outputMax] = outputRange;
|
|
59
|
+
if (result < inputMin) {
|
|
60
|
+
if (extrapolateLeft === "identity") {
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
if (extrapolateLeft === "clamp") {
|
|
64
|
+
result = inputMin;
|
|
65
|
+
} else if (extrapolateLeft === "wrap") {
|
|
66
|
+
const range = inputMax - inputMin;
|
|
67
|
+
result = ((result - inputMin) % range + range) % range + inputMin;
|
|
68
|
+
} else if (extrapolateLeft === "extend") {}
|
|
69
|
+
}
|
|
70
|
+
if (result > inputMax) {
|
|
71
|
+
if (extrapolateRight === "identity") {
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
if (extrapolateRight === "clamp") {
|
|
75
|
+
result = inputMax;
|
|
76
|
+
} else if (extrapolateRight === "wrap") {
|
|
77
|
+
const range = inputMax - inputMin;
|
|
78
|
+
result = ((result - inputMin) % range + range) % range + inputMin;
|
|
79
|
+
} else if (extrapolateRight === "extend") {}
|
|
80
|
+
}
|
|
81
|
+
if (outputMin === outputMax) {
|
|
82
|
+
return outputMin;
|
|
83
|
+
}
|
|
84
|
+
result = (result - inputMin) / (inputMax - inputMin);
|
|
85
|
+
result = easing(result);
|
|
86
|
+
result = result * (outputMax - outputMin) + outputMin;
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
function findRange(input, inputRange) {
|
|
90
|
+
let i;
|
|
91
|
+
for (i = 1;i < inputRange.length - 1; ++i) {
|
|
92
|
+
if (inputRange[i] >= input) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return i - 1;
|
|
97
|
+
}
|
|
98
|
+
function checkValidInputRange(arr) {
|
|
99
|
+
for (let i = 1;i < arr.length; ++i) {
|
|
100
|
+
if (!(arr[i] > arr[i - 1])) {
|
|
101
|
+
throw new Error(\`inputRange must be strictly monotonically increasing but got [\${arr.join(",")}]\`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function checkInfiniteRange(name, arr) {
|
|
106
|
+
if (arr.length < 2) {
|
|
107
|
+
throw new Error(name + " must have at least 2 elements");
|
|
108
|
+
}
|
|
109
|
+
for (const element of arr) {
|
|
110
|
+
if (typeof element !== "number") {
|
|
111
|
+
throw new Error(\`\${name} must contain only numbers\`);
|
|
112
|
+
}
|
|
113
|
+
if (!Number.isFinite(element)) {
|
|
114
|
+
throw new Error(\`\${name} must contain only finite numbers, but got [\${arr.join(",")}]\`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function interpolate(input, inputRange, outputRange, options) {
|
|
119
|
+
if (typeof input === "undefined") {
|
|
120
|
+
throw new Error("input can not be undefined");
|
|
121
|
+
}
|
|
122
|
+
if (typeof inputRange === "undefined") {
|
|
123
|
+
throw new Error("inputRange can not be undefined");
|
|
124
|
+
}
|
|
125
|
+
if (typeof outputRange === "undefined") {
|
|
126
|
+
throw new Error("outputRange can not be undefined");
|
|
127
|
+
}
|
|
128
|
+
if (inputRange.length !== outputRange.length) {
|
|
129
|
+
throw new Error("inputRange (" + inputRange.length + ") and outputRange (" + outputRange.length + ") must have the same length");
|
|
130
|
+
}
|
|
131
|
+
checkInfiniteRange("inputRange", inputRange);
|
|
132
|
+
checkInfiniteRange("outputRange", outputRange);
|
|
133
|
+
checkValidInputRange(inputRange);
|
|
134
|
+
const easing = options?.easing ?? ((num) => num);
|
|
135
|
+
let extrapolateLeft = "extend";
|
|
136
|
+
if (options?.extrapolateLeft !== undefined) {
|
|
137
|
+
extrapolateLeft = options.extrapolateLeft;
|
|
138
|
+
}
|
|
139
|
+
let extrapolateRight = "extend";
|
|
140
|
+
if (options?.extrapolateRight !== undefined) {
|
|
141
|
+
extrapolateRight = options.extrapolateRight;
|
|
142
|
+
}
|
|
143
|
+
if (typeof input !== "number") {
|
|
144
|
+
throw new TypeError("Cannot interpolate an input which is not a number");
|
|
145
|
+
}
|
|
146
|
+
const range = findRange(input, inputRange);
|
|
147
|
+
return interpolateFunction(input, [inputRange[range], inputRange[range + 1]], [outputRange[range], outputRange[range + 1]], {
|
|
148
|
+
easing,
|
|
149
|
+
extrapolateLeft,
|
|
150
|
+
extrapolateRight
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function truthy(value) {
|
|
154
|
+
return Boolean(value);
|
|
155
|
+
}
|
|
156
|
+
if (typeof window !== "undefined") {
|
|
157
|
+
window.remotion_renderReady = false;
|
|
158
|
+
if (!window.remotion_delayRenderTimeouts) {
|
|
159
|
+
window.remotion_delayRenderTimeouts = {};
|
|
160
|
+
}
|
|
161
|
+
window.remotion_delayRenderHandles = [];
|
|
162
|
+
}
|
|
163
|
+
var DELAY_RENDER_CALLSTACK_TOKEN = "The delayRender was called:";
|
|
164
|
+
var DELAY_RENDER_RETRIES_LEFT = "Retries left: ";
|
|
165
|
+
var DELAY_RENDER_RETRY_TOKEN = "- Rendering the frame will be retried.";
|
|
166
|
+
var DELAY_RENDER_CLEAR_TOKEN = "handle was cleared after";
|
|
167
|
+
var DATE_TOKEN = "remotion-date:";
|
|
168
|
+
var FILE_TOKEN = "remotion-file:";
|
|
169
|
+
var serializeJSONWithSpecialTypes = ({
|
|
170
|
+
data,
|
|
171
|
+
indent,
|
|
172
|
+
staticBase
|
|
173
|
+
}) => {
|
|
174
|
+
let customDateUsed = false;
|
|
175
|
+
let customFileUsed = false;
|
|
176
|
+
let mapUsed = false;
|
|
177
|
+
let setUsed = false;
|
|
178
|
+
try {
|
|
179
|
+
const serializedString = JSON.stringify(data, function(key, value) {
|
|
180
|
+
const item = this[key];
|
|
181
|
+
if (item instanceof Date) {
|
|
182
|
+
customDateUsed = true;
|
|
183
|
+
return \`\${DATE_TOKEN}\${item.toISOString()}\`;
|
|
184
|
+
}
|
|
185
|
+
if (item instanceof Map) {
|
|
186
|
+
mapUsed = true;
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
if (item instanceof Set) {
|
|
190
|
+
setUsed = true;
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
if (typeof item === "string" && staticBase !== null && item.startsWith(staticBase)) {
|
|
194
|
+
customFileUsed = true;
|
|
195
|
+
return \`\${FILE_TOKEN}\${item.replace(staticBase + "/", "")}\`;
|
|
196
|
+
}
|
|
197
|
+
return value;
|
|
198
|
+
}, indent);
|
|
199
|
+
return { serializedString, customDateUsed, customFileUsed, mapUsed, setUsed };
|
|
200
|
+
} catch (err) {
|
|
201
|
+
throw new Error("Could not serialize the passed input props to JSON: " + err.message);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
var deserializeJSONWithSpecialTypes = (data) => {
|
|
205
|
+
return JSON.parse(data, (_, value) => {
|
|
206
|
+
if (typeof value === "string" && value.startsWith(DATE_TOKEN)) {
|
|
207
|
+
return new Date(value.replace(DATE_TOKEN, ""));
|
|
208
|
+
}
|
|
209
|
+
if (typeof value === "string" && value.startsWith(FILE_TOKEN)) {
|
|
210
|
+
return \`\${window.remotion_staticBase}/\${value.replace(FILE_TOKEN, "")}\`;
|
|
211
|
+
}
|
|
212
|
+
return value;
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
var NUMBER = "[-+]?\\\\d*\\\\.?\\\\d+";
|
|
216
|
+
var PERCENTAGE = NUMBER + "%";
|
|
217
|
+
function call(...args) {
|
|
218
|
+
return "\\\\(\\\\s*(" + args.join(")\\\\s*,\\\\s*(") + ")\\\\s*\\\\)";
|
|
219
|
+
}
|
|
220
|
+
function getMatchers() {
|
|
221
|
+
const cachedMatchers = {
|
|
222
|
+
rgb: undefined,
|
|
223
|
+
rgba: undefined,
|
|
224
|
+
hsl: undefined,
|
|
225
|
+
hsla: undefined,
|
|
226
|
+
hex3: undefined,
|
|
227
|
+
hex4: undefined,
|
|
228
|
+
hex5: undefined,
|
|
229
|
+
hex6: undefined,
|
|
230
|
+
hex8: undefined
|
|
231
|
+
};
|
|
232
|
+
if (cachedMatchers.rgb === undefined) {
|
|
233
|
+
cachedMatchers.rgb = new RegExp("rgb" + call(NUMBER, NUMBER, NUMBER));
|
|
234
|
+
cachedMatchers.rgba = new RegExp("rgba" + call(NUMBER, NUMBER, NUMBER, NUMBER));
|
|
235
|
+
cachedMatchers.hsl = new RegExp("hsl" + call(NUMBER, PERCENTAGE, PERCENTAGE));
|
|
236
|
+
cachedMatchers.hsla = new RegExp("hsla" + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER));
|
|
237
|
+
cachedMatchers.hex3 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
|
|
238
|
+
cachedMatchers.hex4 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
|
|
239
|
+
cachedMatchers.hex6 = /^#([0-9a-fA-F]{6})$/;
|
|
240
|
+
cachedMatchers.hex8 = /^#([0-9a-fA-F]{8})$/;
|
|
241
|
+
}
|
|
242
|
+
return cachedMatchers;
|
|
243
|
+
}
|
|
244
|
+
function hue2rgb(p, q, t) {
|
|
245
|
+
if (t < 0) {
|
|
246
|
+
t += 1;
|
|
247
|
+
}
|
|
248
|
+
if (t > 1) {
|
|
249
|
+
t -= 1;
|
|
250
|
+
}
|
|
251
|
+
if (t < 1 / 6) {
|
|
252
|
+
return p + (q - p) * 6 * t;
|
|
253
|
+
}
|
|
254
|
+
if (t < 1 / 2) {
|
|
255
|
+
return q;
|
|
256
|
+
}
|
|
257
|
+
if (t < 2 / 3) {
|
|
258
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
259
|
+
}
|
|
260
|
+
return p;
|
|
261
|
+
}
|
|
262
|
+
function hslToRgb(h, s, l) {
|
|
263
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
264
|
+
const p = 2 * l - q;
|
|
265
|
+
const r = hue2rgb(p, q, h + 1 / 3);
|
|
266
|
+
const g = hue2rgb(p, q, h);
|
|
267
|
+
const b = hue2rgb(p, q, h - 1 / 3);
|
|
268
|
+
return Math.round(r * 255) << 24 | Math.round(g * 255) << 16 | Math.round(b * 255) << 8;
|
|
269
|
+
}
|
|
270
|
+
function parse255(str) {
|
|
271
|
+
const int = Number.parseInt(str, 10);
|
|
272
|
+
if (int < 0) {
|
|
273
|
+
return 0;
|
|
274
|
+
}
|
|
275
|
+
if (int > 255) {
|
|
276
|
+
return 255;
|
|
277
|
+
}
|
|
278
|
+
return int;
|
|
279
|
+
}
|
|
280
|
+
function parse360(str) {
|
|
281
|
+
const int = Number.parseFloat(str);
|
|
282
|
+
return (int % 360 + 360) % 360 / 360;
|
|
283
|
+
}
|
|
284
|
+
function parse1(str) {
|
|
285
|
+
const num = Number.parseFloat(str);
|
|
286
|
+
if (num < 0) {
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
if (num > 1) {
|
|
290
|
+
return 255;
|
|
291
|
+
}
|
|
292
|
+
return Math.round(num * 255);
|
|
293
|
+
}
|
|
294
|
+
function parsePercentage(str) {
|
|
295
|
+
const int = Number.parseFloat(str);
|
|
296
|
+
if (int < 0) {
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
if (int > 100) {
|
|
300
|
+
return 1;
|
|
301
|
+
}
|
|
302
|
+
return int / 100;
|
|
303
|
+
}
|
|
304
|
+
var colorNames = {
|
|
305
|
+
transparent: 0,
|
|
306
|
+
aliceblue: 4042850303,
|
|
307
|
+
antiquewhite: 4209760255,
|
|
308
|
+
aqua: 16777215,
|
|
309
|
+
aquamarine: 2147472639,
|
|
310
|
+
azure: 4043309055,
|
|
311
|
+
beige: 4126530815,
|
|
312
|
+
bisque: 4293182719,
|
|
313
|
+
black: 255,
|
|
314
|
+
blanchedalmond: 4293643775,
|
|
315
|
+
blue: 65535,
|
|
316
|
+
blueviolet: 2318131967,
|
|
317
|
+
brown: 2771004159,
|
|
318
|
+
burlywood: 3736635391,
|
|
319
|
+
burntsienna: 3934150143,
|
|
320
|
+
cadetblue: 1604231423,
|
|
321
|
+
chartreuse: 2147418367,
|
|
322
|
+
chocolate: 3530104575,
|
|
323
|
+
coral: 4286533887,
|
|
324
|
+
cornflowerblue: 1687547391,
|
|
325
|
+
cornsilk: 4294499583,
|
|
326
|
+
crimson: 3692313855,
|
|
327
|
+
cyan: 16777215,
|
|
328
|
+
darkblue: 35839,
|
|
329
|
+
darkcyan: 9145343,
|
|
330
|
+
darkgoldenrod: 3095792639,
|
|
331
|
+
darkgray: 2846468607,
|
|
332
|
+
darkgreen: 6553855,
|
|
333
|
+
darkgrey: 2846468607,
|
|
334
|
+
darkkhaki: 3182914559,
|
|
335
|
+
darkmagenta: 2332068863,
|
|
336
|
+
darkolivegreen: 1433087999,
|
|
337
|
+
darkorange: 4287365375,
|
|
338
|
+
darkorchid: 2570243327,
|
|
339
|
+
darkred: 2332033279,
|
|
340
|
+
darksalmon: 3918953215,
|
|
341
|
+
darkseagreen: 2411499519,
|
|
342
|
+
darkslateblue: 1211993087,
|
|
343
|
+
darkslategray: 793726975,
|
|
344
|
+
darkslategrey: 793726975,
|
|
345
|
+
darkturquoise: 13554175,
|
|
346
|
+
darkviolet: 2483082239,
|
|
347
|
+
deeppink: 4279538687,
|
|
348
|
+
deepskyblue: 12582911,
|
|
349
|
+
dimgray: 1768516095,
|
|
350
|
+
dimgrey: 1768516095,
|
|
351
|
+
dodgerblue: 512819199,
|
|
352
|
+
firebrick: 2988581631,
|
|
353
|
+
floralwhite: 4294635775,
|
|
354
|
+
forestgreen: 579543807,
|
|
355
|
+
fuchsia: 4278255615,
|
|
356
|
+
gainsboro: 3705462015,
|
|
357
|
+
ghostwhite: 4177068031,
|
|
358
|
+
gold: 4292280575,
|
|
359
|
+
goldenrod: 3668254975,
|
|
360
|
+
gray: 2155905279,
|
|
361
|
+
green: 8388863,
|
|
362
|
+
greenyellow: 2919182335,
|
|
363
|
+
grey: 2155905279,
|
|
364
|
+
honeydew: 4043305215,
|
|
365
|
+
hotpink: 4285117695,
|
|
366
|
+
indianred: 3445382399,
|
|
367
|
+
indigo: 1258324735,
|
|
368
|
+
ivory: 4294963455,
|
|
369
|
+
khaki: 4041641215,
|
|
370
|
+
lavender: 3873897215,
|
|
371
|
+
lavenderblush: 4293981695,
|
|
372
|
+
lawngreen: 2096890111,
|
|
373
|
+
lemonchiffon: 4294626815,
|
|
374
|
+
lightblue: 2916673279,
|
|
375
|
+
lightcoral: 4034953471,
|
|
376
|
+
lightcyan: 3774873599,
|
|
377
|
+
lightgoldenrodyellow: 4210742015,
|
|
378
|
+
lightgray: 3553874943,
|
|
379
|
+
lightgreen: 2431553791,
|
|
380
|
+
lightgrey: 3553874943,
|
|
381
|
+
lightpink: 4290167295,
|
|
382
|
+
lightsalmon: 4288707327,
|
|
383
|
+
lightseagreen: 548580095,
|
|
384
|
+
lightskyblue: 2278488831,
|
|
385
|
+
lightslategray: 2005441023,
|
|
386
|
+
lightslategrey: 2005441023,
|
|
387
|
+
lightsteelblue: 2965692159,
|
|
388
|
+
lightyellow: 4294959359,
|
|
389
|
+
lime: 16711935,
|
|
390
|
+
limegreen: 852308735,
|
|
391
|
+
linen: 4210091775,
|
|
392
|
+
magenta: 4278255615,
|
|
393
|
+
maroon: 2147483903,
|
|
394
|
+
mediumaquamarine: 1724754687,
|
|
395
|
+
mediumblue: 52735,
|
|
396
|
+
mediumorchid: 3126187007,
|
|
397
|
+
mediumpurple: 2473647103,
|
|
398
|
+
mediumseagreen: 1018393087,
|
|
399
|
+
mediumslateblue: 2070474495,
|
|
400
|
+
mediumspringgreen: 16423679,
|
|
401
|
+
mediumturquoise: 1221709055,
|
|
402
|
+
mediumvioletred: 3340076543,
|
|
403
|
+
midnightblue: 421097727,
|
|
404
|
+
mintcream: 4127193855,
|
|
405
|
+
mistyrose: 4293190143,
|
|
406
|
+
moccasin: 4293178879,
|
|
407
|
+
navajowhite: 4292783615,
|
|
408
|
+
navy: 33023,
|
|
409
|
+
oldlace: 4260751103,
|
|
410
|
+
olive: 2155872511,
|
|
411
|
+
olivedrab: 1804477439,
|
|
412
|
+
orange: 4289003775,
|
|
413
|
+
orangered: 4282712319,
|
|
414
|
+
orchid: 3664828159,
|
|
415
|
+
palegoldenrod: 4008225535,
|
|
416
|
+
palegreen: 2566625535,
|
|
417
|
+
paleturquoise: 2951671551,
|
|
418
|
+
palevioletred: 3681588223,
|
|
419
|
+
papayawhip: 4293907967,
|
|
420
|
+
peachpuff: 4292524543,
|
|
421
|
+
peru: 3448061951,
|
|
422
|
+
pink: 4290825215,
|
|
423
|
+
plum: 3718307327,
|
|
424
|
+
powderblue: 2967529215,
|
|
425
|
+
purple: 2147516671,
|
|
426
|
+
rebeccapurple: 1714657791,
|
|
427
|
+
red: 4278190335,
|
|
428
|
+
rosybrown: 3163525119,
|
|
429
|
+
royalblue: 1097458175,
|
|
430
|
+
saddlebrown: 2336560127,
|
|
431
|
+
salmon: 4202722047,
|
|
432
|
+
sandybrown: 4104413439,
|
|
433
|
+
seagreen: 780883967,
|
|
434
|
+
seashell: 4294307583,
|
|
435
|
+
sienna: 2689740287,
|
|
436
|
+
silver: 3233857791,
|
|
437
|
+
skyblue: 2278484991,
|
|
438
|
+
slateblue: 1784335871,
|
|
439
|
+
slategray: 1887473919,
|
|
440
|
+
slategrey: 1887473919,
|
|
441
|
+
snow: 4294638335,
|
|
442
|
+
springgreen: 16744447,
|
|
443
|
+
steelblue: 1182971135,
|
|
444
|
+
tan: 3535047935,
|
|
445
|
+
teal: 8421631,
|
|
446
|
+
thistle: 3636451583,
|
|
447
|
+
tomato: 4284696575,
|
|
448
|
+
turquoise: 1088475391,
|
|
449
|
+
violet: 4001558271,
|
|
450
|
+
wheat: 4125012991,
|
|
451
|
+
white: 4294967295,
|
|
452
|
+
whitesmoke: 4126537215,
|
|
453
|
+
yellow: 4294902015,
|
|
454
|
+
yellowgreen: 2597139199
|
|
455
|
+
};
|
|
456
|
+
function normalizeColor(color) {
|
|
457
|
+
const matchers = getMatchers();
|
|
458
|
+
let match;
|
|
459
|
+
if (matchers.hex6) {
|
|
460
|
+
if (match = matchers.hex6.exec(color)) {
|
|
461
|
+
return Number.parseInt(match[1] + "ff", 16) >>> 0;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (colorNames[color] !== undefined) {
|
|
465
|
+
return colorNames[color];
|
|
466
|
+
}
|
|
467
|
+
if (matchers.rgb) {
|
|
468
|
+
if (match = matchers.rgb.exec(color)) {
|
|
469
|
+
return (parse255(match[1]) << 24 | parse255(match[2]) << 16 | parse255(match[3]) << 8 | 255) >>> 0;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (matchers.rgba) {
|
|
473
|
+
if (match = matchers.rgba.exec(color)) {
|
|
474
|
+
return (parse255(match[1]) << 24 | parse255(match[2]) << 16 | parse255(match[3]) << 8 | parse1(match[4])) >>> 0;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (matchers.hex3) {
|
|
478
|
+
if (match = matchers.hex3.exec(color)) {
|
|
479
|
+
return Number.parseInt(match[1] + match[1] + match[2] + match[2] + match[3] + match[3] + "ff", 16) >>> 0;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (matchers.hex8) {
|
|
483
|
+
if (match = matchers.hex8.exec(color)) {
|
|
484
|
+
return Number.parseInt(match[1], 16) >>> 0;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (matchers.hex4) {
|
|
488
|
+
if (match = matchers.hex4.exec(color)) {
|
|
489
|
+
return Number.parseInt(match[1] + match[1] + match[2] + match[2] + match[3] + match[3] + match[4] + match[4], 16) >>> 0;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (matchers.hsl) {
|
|
493
|
+
if (match = matchers.hsl.exec(color)) {
|
|
494
|
+
return (hslToRgb(parse360(match[1]), parsePercentage(match[2]), parsePercentage(match[3])) | 255) >>> 0;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (matchers.hsla) {
|
|
498
|
+
if (match = matchers.hsla.exec(color)) {
|
|
499
|
+
return (hslToRgb(parse360(match[1]), parsePercentage(match[2]), parsePercentage(match[3])) | parse1(match[4])) >>> 0;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
throw new Error(\`invalid color string \${color} provided\`);
|
|
503
|
+
}
|
|
504
|
+
function processColor(color) {
|
|
505
|
+
const normalizedColor = normalizeColor(color);
|
|
506
|
+
return (normalizedColor << 24 | normalizedColor >>> 8) >>> 0;
|
|
507
|
+
}
|
|
508
|
+
var proResProfileOptions = [
|
|
509
|
+
"4444-xq",
|
|
510
|
+
"4444",
|
|
511
|
+
"hq",
|
|
512
|
+
"standard",
|
|
513
|
+
"light",
|
|
514
|
+
"proxy"
|
|
515
|
+
];
|
|
516
|
+
var ENABLE_V5_BREAKING_CHANGES = false;
|
|
517
|
+
var validateFrame = ({
|
|
518
|
+
allowFloats,
|
|
519
|
+
durationInFrames,
|
|
520
|
+
frame
|
|
521
|
+
}) => {
|
|
522
|
+
if (typeof frame === "undefined") {
|
|
523
|
+
throw new TypeError(\`Argument missing for parameter "frame"\`);
|
|
524
|
+
}
|
|
525
|
+
if (typeof frame !== "number") {
|
|
526
|
+
throw new TypeError(\`Argument passed for "frame" is not a number: \${frame}\`);
|
|
527
|
+
}
|
|
528
|
+
if (!Number.isFinite(frame)) {
|
|
529
|
+
throw new RangeError(\`Frame \${frame} is not finite\`);
|
|
530
|
+
}
|
|
531
|
+
if (frame % 1 !== 0 && !allowFloats) {
|
|
532
|
+
throw new RangeError(\`Argument for frame must be an integer, but got \${frame}\`);
|
|
533
|
+
}
|
|
534
|
+
if (frame < 0 && frame < -durationInFrames) {
|
|
535
|
+
throw new RangeError(\`Cannot use frame \${frame}: Duration of composition is \${durationInFrames}, therefore the lowest frame that can be rendered is \${-durationInFrames}\`);
|
|
536
|
+
}
|
|
537
|
+
if (frame > durationInFrames - 1) {
|
|
538
|
+
throw new RangeError(\`Cannot use frame \${frame}: Duration of composition is \${durationInFrames}, therefore the highest frame that can be rendered is \${durationInFrames - 1}\`);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
var validCodecs = [
|
|
542
|
+
"h264",
|
|
543
|
+
"h265",
|
|
544
|
+
"vp8",
|
|
545
|
+
"vp9",
|
|
546
|
+
"mp3",
|
|
547
|
+
"aac",
|
|
548
|
+
"wav",
|
|
549
|
+
"prores",
|
|
550
|
+
"h264-mkv",
|
|
551
|
+
"h264-ts",
|
|
552
|
+
"gif"
|
|
553
|
+
];
|
|
554
|
+
function validateCodec(defaultCodec, location, name) {
|
|
555
|
+
if (typeof defaultCodec === "undefined") {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (typeof defaultCodec !== "string") {
|
|
559
|
+
throw new TypeError(\`The "\${name}" prop \${location} must be a string, but you passed a value of type \${typeof defaultCodec}.\`);
|
|
560
|
+
}
|
|
561
|
+
if (!validCodecs.includes(defaultCodec)) {
|
|
562
|
+
throw new Error(\`The "\${name}" prop \${location} must be one of \${validCodecs.join(", ")}, but you passed \${defaultCodec}.\`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
var validateDefaultAndInputProps = (defaultProps, name, compositionId) => {
|
|
566
|
+
if (!defaultProps) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (typeof defaultProps !== "object") {
|
|
570
|
+
throw new Error(\`"\${name}" must be an object, but you passed a value of type \${typeof defaultProps}\`);
|
|
571
|
+
}
|
|
572
|
+
if (Array.isArray(defaultProps)) {
|
|
573
|
+
throw new Error(\`"\${name}" must be an object, an array was passed \${compositionId ? \`for composition "\${compositionId}"\` : ""}\`);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
function validateDimension(amount, nameOfProp, location) {
|
|
577
|
+
if (typeof amount !== "number") {
|
|
578
|
+
throw new Error(\`The "\${nameOfProp}" prop \${location} must be a number, but you passed a value of type \${typeof amount}\`);
|
|
579
|
+
}
|
|
580
|
+
if (isNaN(amount)) {
|
|
581
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must not be NaN, but is NaN.\`);
|
|
582
|
+
}
|
|
583
|
+
if (!Number.isFinite(amount)) {
|
|
584
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must be finite, but is \${amount}.\`);
|
|
585
|
+
}
|
|
586
|
+
if (amount % 1 !== 0) {
|
|
587
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must be an integer, but is \${amount}.\`);
|
|
588
|
+
}
|
|
589
|
+
if (amount <= 0) {
|
|
590
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must be positive, but got \${amount}.\`);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
function validateDurationInFrames(durationInFrames, options) {
|
|
594
|
+
const { allowFloats, component } = options;
|
|
595
|
+
if (typeof durationInFrames === "undefined") {
|
|
596
|
+
throw new Error(\`The "durationInFrames" prop \${component} is missing.\`);
|
|
597
|
+
}
|
|
598
|
+
if (typeof durationInFrames !== "number") {
|
|
599
|
+
throw new Error(\`The "durationInFrames" prop \${component} must be a number, but you passed a value of type \${typeof durationInFrames}\`);
|
|
600
|
+
}
|
|
601
|
+
if (durationInFrames <= 0) {
|
|
602
|
+
throw new TypeError(\`The "durationInFrames" prop \${component} must be positive, but got \${durationInFrames}.\`);
|
|
603
|
+
}
|
|
604
|
+
if (!allowFloats && durationInFrames % 1 !== 0) {
|
|
605
|
+
throw new TypeError(\`The "durationInFrames" prop \${component} must be an integer, but got \${durationInFrames}.\`);
|
|
606
|
+
}
|
|
607
|
+
if (!Number.isFinite(durationInFrames)) {
|
|
608
|
+
throw new TypeError(\`The "durationInFrames" prop \${component} must be finite, but got \${durationInFrames}.\`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function validateFps(fps, location, isGif) {
|
|
612
|
+
if (typeof fps !== "number") {
|
|
613
|
+
throw new Error(\`"fps" must be a number, but you passed a value of type \${typeof fps} \${location}\`);
|
|
614
|
+
}
|
|
615
|
+
if (!Number.isFinite(fps)) {
|
|
616
|
+
throw new Error(\`"fps" must be a finite, but you passed \${fps} \${location}\`);
|
|
617
|
+
}
|
|
618
|
+
if (isNaN(fps)) {
|
|
619
|
+
throw new Error(\`"fps" must not be NaN, but got \${fps} \${location}\`);
|
|
620
|
+
}
|
|
621
|
+
if (fps <= 0) {
|
|
622
|
+
throw new TypeError(\`"fps" must be positive, but got \${fps} \${location}\`);
|
|
623
|
+
}
|
|
624
|
+
if (isGif && fps > 50) {
|
|
625
|
+
throw new TypeError(\`The FPS for a GIF cannot be higher than 50. Use the --every-nth-frame option to lower the FPS: https://remotion.dev/docs/render-as-gif\`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
var getExpectedMediaFrameUncorrected = ({
|
|
629
|
+
frame,
|
|
630
|
+
playbackRate,
|
|
631
|
+
startFrom
|
|
632
|
+
}) => {
|
|
633
|
+
return interpolate(frame, [-1, startFrom, startFrom + 1], [-1, startFrom, startFrom + playbackRate]);
|
|
634
|
+
};
|
|
635
|
+
var getAbsoluteSrc = (relativeSrc) => {
|
|
636
|
+
if (typeof window === "undefined") {
|
|
637
|
+
return relativeSrc;
|
|
638
|
+
}
|
|
639
|
+
if (relativeSrc.startsWith("http://") || relativeSrc.startsWith("https://") || relativeSrc.startsWith("file://") || relativeSrc.startsWith("blob:") || relativeSrc.startsWith("data:")) {
|
|
640
|
+
return relativeSrc;
|
|
641
|
+
}
|
|
642
|
+
return new URL(relativeSrc, window.origin).href;
|
|
643
|
+
};
|
|
644
|
+
var getOffthreadVideoSource = ({
|
|
645
|
+
src,
|
|
646
|
+
transparent,
|
|
647
|
+
currentTime,
|
|
648
|
+
toneMapped
|
|
649
|
+
}) => {
|
|
650
|
+
return \`http://localhost:\${window.remotion_proxyPort}/proxy?src=\${encodeURIComponent(getAbsoluteSrc(src))}&time=\${encodeURIComponent(Math.max(0, currentTime))}&transparent=\${String(transparent)}&toneMapped=\${String(toneMapped)}\`;
|
|
651
|
+
};
|
|
652
|
+
var NoReactInternals = {
|
|
653
|
+
processColor,
|
|
654
|
+
truthy,
|
|
655
|
+
validateFps,
|
|
656
|
+
validateDimension,
|
|
657
|
+
validateDurationInFrames,
|
|
658
|
+
validateDefaultAndInputProps,
|
|
659
|
+
validateFrame,
|
|
660
|
+
serializeJSONWithSpecialTypes,
|
|
661
|
+
bundleName: "bundle.js",
|
|
662
|
+
bundleMapName: "bundle.js.map",
|
|
663
|
+
deserializeJSONWithSpecialTypes,
|
|
664
|
+
DELAY_RENDER_CALLSTACK_TOKEN,
|
|
665
|
+
DELAY_RENDER_RETRY_TOKEN,
|
|
666
|
+
DELAY_RENDER_CLEAR_TOKEN,
|
|
667
|
+
DELAY_RENDER_ATTEMPT_TOKEN: DELAY_RENDER_RETRIES_LEFT,
|
|
668
|
+
getOffthreadVideoSource,
|
|
669
|
+
getExpectedMediaFrameUncorrected,
|
|
670
|
+
ENABLE_V5_BREAKING_CHANGES,
|
|
671
|
+
MIN_NODE_VERSION: ENABLE_V5_BREAKING_CHANGES ? 18 : 16,
|
|
672
|
+
MIN_BUN_VERSION: ENABLE_V5_BREAKING_CHANGES ? "1.1.3" : "1.0.3",
|
|
673
|
+
colorNames,
|
|
674
|
+
DATE_TOKEN,
|
|
675
|
+
FILE_TOKEN,
|
|
676
|
+
validateCodec,
|
|
677
|
+
proResProfileOptions
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
// src/scripts/render-still.ts
|
|
681
|
+
var config = JSON.parse(process.argv[2]);
|
|
682
|
+
var noop = () => {
|
|
683
|
+
return;
|
|
684
|
+
};
|
|
685
|
+
try {
|
|
686
|
+
const serializedInputProps = NoReactInternals.serializeJSONWithSpecialTypes({
|
|
687
|
+
data: config.inputProps,
|
|
688
|
+
indent: undefined,
|
|
689
|
+
staticBase: null
|
|
690
|
+
}).serializedString;
|
|
691
|
+
console.log(JSON.stringify({ type: "opening-browser" }));
|
|
692
|
+
const browser = await RenderInternals.internalOpenBrowser({
|
|
693
|
+
browser: "chrome",
|
|
694
|
+
browserExecutable: config.browserExecutable,
|
|
695
|
+
chromiumOptions: config.chromiumOptions,
|
|
696
|
+
forceDeviceScaleFactor: undefined,
|
|
697
|
+
viewport: null,
|
|
698
|
+
indent: false,
|
|
699
|
+
logLevel: config.logLevel,
|
|
700
|
+
onBrowserDownload: () => ({
|
|
701
|
+
version: null,
|
|
702
|
+
onProgress: noop
|
|
703
|
+
}),
|
|
704
|
+
chromeMode: config.chromeMode
|
|
705
|
+
});
|
|
706
|
+
console.log(JSON.stringify({ type: "selecting-composition" }));
|
|
707
|
+
const { metadata: composition } = await RenderInternals.internalSelectComposition({
|
|
708
|
+
serializedInputPropsWithCustomSchema: serializedInputProps,
|
|
709
|
+
envVariables: config.envVariables,
|
|
710
|
+
puppeteerInstance: browser,
|
|
711
|
+
onBrowserLog: null,
|
|
712
|
+
browserExecutable: config.browserExecutable,
|
|
713
|
+
chromiumOptions: config.chromiumOptions,
|
|
714
|
+
port: null,
|
|
715
|
+
indent: false,
|
|
716
|
+
server: undefined,
|
|
717
|
+
serveUrl: config.serveUrl,
|
|
718
|
+
id: config.compositionId,
|
|
719
|
+
onServeUrlVisited: noop,
|
|
720
|
+
logLevel: config.logLevel,
|
|
721
|
+
timeoutInMilliseconds: config.timeoutInMilliseconds,
|
|
722
|
+
binariesDirectory: config.binariesDirectory,
|
|
723
|
+
onBrowserDownload: () => ({
|
|
724
|
+
version: null,
|
|
725
|
+
onProgress: noop
|
|
726
|
+
}),
|
|
727
|
+
chromeMode: config.chromeMode,
|
|
728
|
+
mediaCacheSizeInBytes: config.mediaCacheSizeInBytes,
|
|
729
|
+
offthreadVideoCacheSizeInBytes: config.offthreadVideoCacheSizeInBytes,
|
|
730
|
+
offthreadVideoThreads: config.offthreadVideoThreads
|
|
731
|
+
});
|
|
732
|
+
const serializedResolvedProps = NoReactInternals.serializeJSONWithSpecialTypes({
|
|
733
|
+
data: composition.props,
|
|
734
|
+
indent: undefined,
|
|
735
|
+
staticBase: null
|
|
736
|
+
}).serializedString;
|
|
737
|
+
const { contentType } = await RenderInternals.internalRenderStill({
|
|
738
|
+
output: config.output,
|
|
739
|
+
composition,
|
|
740
|
+
serializedInputPropsWithCustomSchema: serializedInputProps,
|
|
741
|
+
serializedResolvedPropsWithCustomSchema: serializedResolvedProps,
|
|
742
|
+
serveUrl: config.serveUrl,
|
|
743
|
+
frame: config.frame,
|
|
744
|
+
imageFormat: config.imageFormat,
|
|
745
|
+
jpegQuality: config.jpegQuality,
|
|
746
|
+
envVariables: config.envVariables,
|
|
747
|
+
overwrite: true,
|
|
748
|
+
browserExecutable: config.browserExecutable,
|
|
749
|
+
chromiumOptions: config.chromiumOptions,
|
|
750
|
+
scale: config.scale,
|
|
751
|
+
logLevel: config.logLevel,
|
|
752
|
+
timeoutInMilliseconds: config.timeoutInMilliseconds,
|
|
753
|
+
binariesDirectory: config.binariesDirectory,
|
|
754
|
+
chromeMode: config.chromeMode,
|
|
755
|
+
offthreadVideoCacheSizeInBytes: config.offthreadVideoCacheSizeInBytes,
|
|
756
|
+
mediaCacheSizeInBytes: config.mediaCacheSizeInBytes,
|
|
757
|
+
offthreadVideoThreads: config.offthreadVideoThreads,
|
|
758
|
+
licenseKey: config.licenseKey,
|
|
759
|
+
puppeteerInstance: browser,
|
|
760
|
+
onBrowserLog: null,
|
|
761
|
+
onDownload: null,
|
|
762
|
+
cancelSignal: null,
|
|
763
|
+
indent: false,
|
|
764
|
+
server: undefined,
|
|
765
|
+
port: null,
|
|
766
|
+
onArtifact: null,
|
|
767
|
+
onLog: RenderInternals.defaultOnLog,
|
|
768
|
+
isProduction: true,
|
|
769
|
+
onBrowserDownload: () => ({
|
|
770
|
+
version: null,
|
|
771
|
+
onProgress: noop
|
|
772
|
+
})
|
|
773
|
+
});
|
|
774
|
+
console.log(JSON.stringify({ type: "render-complete" }));
|
|
775
|
+
await browser.close({ silent: false });
|
|
776
|
+
const { size } = statSync(config.output ?? "/tmp/still.png");
|
|
777
|
+
console.log(JSON.stringify({ type: "done", size, contentType }));
|
|
778
|
+
} catch (err) {
|
|
779
|
+
console.error(err.message);
|
|
780
|
+
process.exit(1);
|
|
781
|
+
}
|
|
782
|
+
`;
|
|
783
|
+
|
|
784
|
+
// script-embed:render-video-script
|
|
785
|
+
var script2 = `// src/scripts/render-video.ts
|
|
786
|
+
import { RenderInternals } from "@remotion/renderer";
|
|
787
|
+
import { statSync } from "fs";
|
|
788
|
+
|
|
789
|
+
// ../core/dist/esm/no-react.mjs
|
|
790
|
+
function interpolateFunction(input, inputRange, outputRange, options) {
|
|
791
|
+
const { extrapolateLeft, extrapolateRight, easing } = options;
|
|
792
|
+
let result = input;
|
|
793
|
+
const [inputMin, inputMax] = inputRange;
|
|
794
|
+
const [outputMin, outputMax] = outputRange;
|
|
795
|
+
if (result < inputMin) {
|
|
796
|
+
if (extrapolateLeft === "identity") {
|
|
797
|
+
return result;
|
|
798
|
+
}
|
|
799
|
+
if (extrapolateLeft === "clamp") {
|
|
800
|
+
result = inputMin;
|
|
801
|
+
} else if (extrapolateLeft === "wrap") {
|
|
802
|
+
const range = inputMax - inputMin;
|
|
803
|
+
result = ((result - inputMin) % range + range) % range + inputMin;
|
|
804
|
+
} else if (extrapolateLeft === "extend") {}
|
|
805
|
+
}
|
|
806
|
+
if (result > inputMax) {
|
|
807
|
+
if (extrapolateRight === "identity") {
|
|
808
|
+
return result;
|
|
809
|
+
}
|
|
810
|
+
if (extrapolateRight === "clamp") {
|
|
811
|
+
result = inputMax;
|
|
812
|
+
} else if (extrapolateRight === "wrap") {
|
|
813
|
+
const range = inputMax - inputMin;
|
|
814
|
+
result = ((result - inputMin) % range + range) % range + inputMin;
|
|
815
|
+
} else if (extrapolateRight === "extend") {}
|
|
816
|
+
}
|
|
817
|
+
if (outputMin === outputMax) {
|
|
818
|
+
return outputMin;
|
|
819
|
+
}
|
|
820
|
+
result = (result - inputMin) / (inputMax - inputMin);
|
|
821
|
+
result = easing(result);
|
|
822
|
+
result = result * (outputMax - outputMin) + outputMin;
|
|
823
|
+
return result;
|
|
824
|
+
}
|
|
825
|
+
function findRange(input, inputRange) {
|
|
826
|
+
let i;
|
|
827
|
+
for (i = 1;i < inputRange.length - 1; ++i) {
|
|
828
|
+
if (inputRange[i] >= input) {
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return i - 1;
|
|
833
|
+
}
|
|
834
|
+
function checkValidInputRange(arr) {
|
|
835
|
+
for (let i = 1;i < arr.length; ++i) {
|
|
836
|
+
if (!(arr[i] > arr[i - 1])) {
|
|
837
|
+
throw new Error(\`inputRange must be strictly monotonically increasing but got [\${arr.join(",")}]\`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function checkInfiniteRange(name, arr) {
|
|
842
|
+
if (arr.length < 2) {
|
|
843
|
+
throw new Error(name + " must have at least 2 elements");
|
|
844
|
+
}
|
|
845
|
+
for (const element of arr) {
|
|
846
|
+
if (typeof element !== "number") {
|
|
847
|
+
throw new Error(\`\${name} must contain only numbers\`);
|
|
848
|
+
}
|
|
849
|
+
if (!Number.isFinite(element)) {
|
|
850
|
+
throw new Error(\`\${name} must contain only finite numbers, but got [\${arr.join(",")}]\`);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
function interpolate(input, inputRange, outputRange, options) {
|
|
855
|
+
if (typeof input === "undefined") {
|
|
856
|
+
throw new Error("input can not be undefined");
|
|
857
|
+
}
|
|
858
|
+
if (typeof inputRange === "undefined") {
|
|
859
|
+
throw new Error("inputRange can not be undefined");
|
|
860
|
+
}
|
|
861
|
+
if (typeof outputRange === "undefined") {
|
|
862
|
+
throw new Error("outputRange can not be undefined");
|
|
863
|
+
}
|
|
864
|
+
if (inputRange.length !== outputRange.length) {
|
|
865
|
+
throw new Error("inputRange (" + inputRange.length + ") and outputRange (" + outputRange.length + ") must have the same length");
|
|
866
|
+
}
|
|
867
|
+
checkInfiniteRange("inputRange", inputRange);
|
|
868
|
+
checkInfiniteRange("outputRange", outputRange);
|
|
869
|
+
checkValidInputRange(inputRange);
|
|
870
|
+
const easing = options?.easing ?? ((num) => num);
|
|
871
|
+
let extrapolateLeft = "extend";
|
|
872
|
+
if (options?.extrapolateLeft !== undefined) {
|
|
873
|
+
extrapolateLeft = options.extrapolateLeft;
|
|
874
|
+
}
|
|
875
|
+
let extrapolateRight = "extend";
|
|
876
|
+
if (options?.extrapolateRight !== undefined) {
|
|
877
|
+
extrapolateRight = options.extrapolateRight;
|
|
878
|
+
}
|
|
879
|
+
if (typeof input !== "number") {
|
|
880
|
+
throw new TypeError("Cannot interpolate an input which is not a number");
|
|
881
|
+
}
|
|
882
|
+
const range = findRange(input, inputRange);
|
|
883
|
+
return interpolateFunction(input, [inputRange[range], inputRange[range + 1]], [outputRange[range], outputRange[range + 1]], {
|
|
884
|
+
easing,
|
|
885
|
+
extrapolateLeft,
|
|
886
|
+
extrapolateRight
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
function truthy(value) {
|
|
890
|
+
return Boolean(value);
|
|
891
|
+
}
|
|
892
|
+
if (typeof window !== "undefined") {
|
|
893
|
+
window.remotion_renderReady = false;
|
|
894
|
+
if (!window.remotion_delayRenderTimeouts) {
|
|
895
|
+
window.remotion_delayRenderTimeouts = {};
|
|
896
|
+
}
|
|
897
|
+
window.remotion_delayRenderHandles = [];
|
|
898
|
+
}
|
|
899
|
+
var DELAY_RENDER_CALLSTACK_TOKEN = "The delayRender was called:";
|
|
900
|
+
var DELAY_RENDER_RETRIES_LEFT = "Retries left: ";
|
|
901
|
+
var DELAY_RENDER_RETRY_TOKEN = "- Rendering the frame will be retried.";
|
|
902
|
+
var DELAY_RENDER_CLEAR_TOKEN = "handle was cleared after";
|
|
903
|
+
var DATE_TOKEN = "remotion-date:";
|
|
904
|
+
var FILE_TOKEN = "remotion-file:";
|
|
905
|
+
var serializeJSONWithSpecialTypes = ({
|
|
906
|
+
data,
|
|
907
|
+
indent,
|
|
908
|
+
staticBase
|
|
909
|
+
}) => {
|
|
910
|
+
let customDateUsed = false;
|
|
911
|
+
let customFileUsed = false;
|
|
912
|
+
let mapUsed = false;
|
|
913
|
+
let setUsed = false;
|
|
914
|
+
try {
|
|
915
|
+
const serializedString = JSON.stringify(data, function(key, value) {
|
|
916
|
+
const item = this[key];
|
|
917
|
+
if (item instanceof Date) {
|
|
918
|
+
customDateUsed = true;
|
|
919
|
+
return \`\${DATE_TOKEN}\${item.toISOString()}\`;
|
|
920
|
+
}
|
|
921
|
+
if (item instanceof Map) {
|
|
922
|
+
mapUsed = true;
|
|
923
|
+
return value;
|
|
924
|
+
}
|
|
925
|
+
if (item instanceof Set) {
|
|
926
|
+
setUsed = true;
|
|
927
|
+
return value;
|
|
928
|
+
}
|
|
929
|
+
if (typeof item === "string" && staticBase !== null && item.startsWith(staticBase)) {
|
|
930
|
+
customFileUsed = true;
|
|
931
|
+
return \`\${FILE_TOKEN}\${item.replace(staticBase + "/", "")}\`;
|
|
932
|
+
}
|
|
933
|
+
return value;
|
|
934
|
+
}, indent);
|
|
935
|
+
return { serializedString, customDateUsed, customFileUsed, mapUsed, setUsed };
|
|
936
|
+
} catch (err) {
|
|
937
|
+
throw new Error("Could not serialize the passed input props to JSON: " + err.message);
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
var deserializeJSONWithSpecialTypes = (data) => {
|
|
941
|
+
return JSON.parse(data, (_, value) => {
|
|
942
|
+
if (typeof value === "string" && value.startsWith(DATE_TOKEN)) {
|
|
943
|
+
return new Date(value.replace(DATE_TOKEN, ""));
|
|
944
|
+
}
|
|
945
|
+
if (typeof value === "string" && value.startsWith(FILE_TOKEN)) {
|
|
946
|
+
return \`\${window.remotion_staticBase}/\${value.replace(FILE_TOKEN, "")}\`;
|
|
947
|
+
}
|
|
948
|
+
return value;
|
|
949
|
+
});
|
|
950
|
+
};
|
|
951
|
+
var NUMBER = "[-+]?\\\\d*\\\\.?\\\\d+";
|
|
952
|
+
var PERCENTAGE = NUMBER + "%";
|
|
953
|
+
function call(...args) {
|
|
954
|
+
return "\\\\(\\\\s*(" + args.join(")\\\\s*,\\\\s*(") + ")\\\\s*\\\\)";
|
|
955
|
+
}
|
|
956
|
+
function getMatchers() {
|
|
957
|
+
const cachedMatchers = {
|
|
958
|
+
rgb: undefined,
|
|
959
|
+
rgba: undefined,
|
|
960
|
+
hsl: undefined,
|
|
961
|
+
hsla: undefined,
|
|
962
|
+
hex3: undefined,
|
|
963
|
+
hex4: undefined,
|
|
964
|
+
hex5: undefined,
|
|
965
|
+
hex6: undefined,
|
|
966
|
+
hex8: undefined
|
|
967
|
+
};
|
|
968
|
+
if (cachedMatchers.rgb === undefined) {
|
|
969
|
+
cachedMatchers.rgb = new RegExp("rgb" + call(NUMBER, NUMBER, NUMBER));
|
|
970
|
+
cachedMatchers.rgba = new RegExp("rgba" + call(NUMBER, NUMBER, NUMBER, NUMBER));
|
|
971
|
+
cachedMatchers.hsl = new RegExp("hsl" + call(NUMBER, PERCENTAGE, PERCENTAGE));
|
|
972
|
+
cachedMatchers.hsla = new RegExp("hsla" + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER));
|
|
973
|
+
cachedMatchers.hex3 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
|
|
974
|
+
cachedMatchers.hex4 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
|
|
975
|
+
cachedMatchers.hex6 = /^#([0-9a-fA-F]{6})$/;
|
|
976
|
+
cachedMatchers.hex8 = /^#([0-9a-fA-F]{8})$/;
|
|
977
|
+
}
|
|
978
|
+
return cachedMatchers;
|
|
979
|
+
}
|
|
980
|
+
function hue2rgb(p, q, t) {
|
|
981
|
+
if (t < 0) {
|
|
982
|
+
t += 1;
|
|
983
|
+
}
|
|
984
|
+
if (t > 1) {
|
|
985
|
+
t -= 1;
|
|
986
|
+
}
|
|
987
|
+
if (t < 1 / 6) {
|
|
988
|
+
return p + (q - p) * 6 * t;
|
|
989
|
+
}
|
|
990
|
+
if (t < 1 / 2) {
|
|
991
|
+
return q;
|
|
992
|
+
}
|
|
993
|
+
if (t < 2 / 3) {
|
|
994
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
995
|
+
}
|
|
996
|
+
return p;
|
|
997
|
+
}
|
|
998
|
+
function hslToRgb(h, s, l) {
|
|
999
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
1000
|
+
const p = 2 * l - q;
|
|
1001
|
+
const r = hue2rgb(p, q, h + 1 / 3);
|
|
1002
|
+
const g = hue2rgb(p, q, h);
|
|
1003
|
+
const b = hue2rgb(p, q, h - 1 / 3);
|
|
1004
|
+
return Math.round(r * 255) << 24 | Math.round(g * 255) << 16 | Math.round(b * 255) << 8;
|
|
1005
|
+
}
|
|
1006
|
+
function parse255(str) {
|
|
1007
|
+
const int = Number.parseInt(str, 10);
|
|
1008
|
+
if (int < 0) {
|
|
1009
|
+
return 0;
|
|
1010
|
+
}
|
|
1011
|
+
if (int > 255) {
|
|
1012
|
+
return 255;
|
|
1013
|
+
}
|
|
1014
|
+
return int;
|
|
1015
|
+
}
|
|
1016
|
+
function parse360(str) {
|
|
1017
|
+
const int = Number.parseFloat(str);
|
|
1018
|
+
return (int % 360 + 360) % 360 / 360;
|
|
1019
|
+
}
|
|
1020
|
+
function parse1(str) {
|
|
1021
|
+
const num = Number.parseFloat(str);
|
|
1022
|
+
if (num < 0) {
|
|
1023
|
+
return 0;
|
|
1024
|
+
}
|
|
1025
|
+
if (num > 1) {
|
|
1026
|
+
return 255;
|
|
1027
|
+
}
|
|
1028
|
+
return Math.round(num * 255);
|
|
1029
|
+
}
|
|
1030
|
+
function parsePercentage(str) {
|
|
1031
|
+
const int = Number.parseFloat(str);
|
|
1032
|
+
if (int < 0) {
|
|
1033
|
+
return 0;
|
|
1034
|
+
}
|
|
1035
|
+
if (int > 100) {
|
|
1036
|
+
return 1;
|
|
1037
|
+
}
|
|
1038
|
+
return int / 100;
|
|
1039
|
+
}
|
|
1040
|
+
var colorNames = {
|
|
1041
|
+
transparent: 0,
|
|
1042
|
+
aliceblue: 4042850303,
|
|
1043
|
+
antiquewhite: 4209760255,
|
|
1044
|
+
aqua: 16777215,
|
|
1045
|
+
aquamarine: 2147472639,
|
|
1046
|
+
azure: 4043309055,
|
|
1047
|
+
beige: 4126530815,
|
|
1048
|
+
bisque: 4293182719,
|
|
1049
|
+
black: 255,
|
|
1050
|
+
blanchedalmond: 4293643775,
|
|
1051
|
+
blue: 65535,
|
|
1052
|
+
blueviolet: 2318131967,
|
|
1053
|
+
brown: 2771004159,
|
|
1054
|
+
burlywood: 3736635391,
|
|
1055
|
+
burntsienna: 3934150143,
|
|
1056
|
+
cadetblue: 1604231423,
|
|
1057
|
+
chartreuse: 2147418367,
|
|
1058
|
+
chocolate: 3530104575,
|
|
1059
|
+
coral: 4286533887,
|
|
1060
|
+
cornflowerblue: 1687547391,
|
|
1061
|
+
cornsilk: 4294499583,
|
|
1062
|
+
crimson: 3692313855,
|
|
1063
|
+
cyan: 16777215,
|
|
1064
|
+
darkblue: 35839,
|
|
1065
|
+
darkcyan: 9145343,
|
|
1066
|
+
darkgoldenrod: 3095792639,
|
|
1067
|
+
darkgray: 2846468607,
|
|
1068
|
+
darkgreen: 6553855,
|
|
1069
|
+
darkgrey: 2846468607,
|
|
1070
|
+
darkkhaki: 3182914559,
|
|
1071
|
+
darkmagenta: 2332068863,
|
|
1072
|
+
darkolivegreen: 1433087999,
|
|
1073
|
+
darkorange: 4287365375,
|
|
1074
|
+
darkorchid: 2570243327,
|
|
1075
|
+
darkred: 2332033279,
|
|
1076
|
+
darksalmon: 3918953215,
|
|
1077
|
+
darkseagreen: 2411499519,
|
|
1078
|
+
darkslateblue: 1211993087,
|
|
1079
|
+
darkslategray: 793726975,
|
|
1080
|
+
darkslategrey: 793726975,
|
|
1081
|
+
darkturquoise: 13554175,
|
|
1082
|
+
darkviolet: 2483082239,
|
|
1083
|
+
deeppink: 4279538687,
|
|
1084
|
+
deepskyblue: 12582911,
|
|
1085
|
+
dimgray: 1768516095,
|
|
1086
|
+
dimgrey: 1768516095,
|
|
1087
|
+
dodgerblue: 512819199,
|
|
1088
|
+
firebrick: 2988581631,
|
|
1089
|
+
floralwhite: 4294635775,
|
|
1090
|
+
forestgreen: 579543807,
|
|
1091
|
+
fuchsia: 4278255615,
|
|
1092
|
+
gainsboro: 3705462015,
|
|
1093
|
+
ghostwhite: 4177068031,
|
|
1094
|
+
gold: 4292280575,
|
|
1095
|
+
goldenrod: 3668254975,
|
|
1096
|
+
gray: 2155905279,
|
|
1097
|
+
green: 8388863,
|
|
1098
|
+
greenyellow: 2919182335,
|
|
1099
|
+
grey: 2155905279,
|
|
1100
|
+
honeydew: 4043305215,
|
|
1101
|
+
hotpink: 4285117695,
|
|
1102
|
+
indianred: 3445382399,
|
|
1103
|
+
indigo: 1258324735,
|
|
1104
|
+
ivory: 4294963455,
|
|
1105
|
+
khaki: 4041641215,
|
|
1106
|
+
lavender: 3873897215,
|
|
1107
|
+
lavenderblush: 4293981695,
|
|
1108
|
+
lawngreen: 2096890111,
|
|
1109
|
+
lemonchiffon: 4294626815,
|
|
1110
|
+
lightblue: 2916673279,
|
|
1111
|
+
lightcoral: 4034953471,
|
|
1112
|
+
lightcyan: 3774873599,
|
|
1113
|
+
lightgoldenrodyellow: 4210742015,
|
|
1114
|
+
lightgray: 3553874943,
|
|
1115
|
+
lightgreen: 2431553791,
|
|
1116
|
+
lightgrey: 3553874943,
|
|
1117
|
+
lightpink: 4290167295,
|
|
1118
|
+
lightsalmon: 4288707327,
|
|
1119
|
+
lightseagreen: 548580095,
|
|
1120
|
+
lightskyblue: 2278488831,
|
|
1121
|
+
lightslategray: 2005441023,
|
|
1122
|
+
lightslategrey: 2005441023,
|
|
1123
|
+
lightsteelblue: 2965692159,
|
|
1124
|
+
lightyellow: 4294959359,
|
|
1125
|
+
lime: 16711935,
|
|
1126
|
+
limegreen: 852308735,
|
|
1127
|
+
linen: 4210091775,
|
|
1128
|
+
magenta: 4278255615,
|
|
1129
|
+
maroon: 2147483903,
|
|
1130
|
+
mediumaquamarine: 1724754687,
|
|
1131
|
+
mediumblue: 52735,
|
|
1132
|
+
mediumorchid: 3126187007,
|
|
1133
|
+
mediumpurple: 2473647103,
|
|
1134
|
+
mediumseagreen: 1018393087,
|
|
1135
|
+
mediumslateblue: 2070474495,
|
|
1136
|
+
mediumspringgreen: 16423679,
|
|
1137
|
+
mediumturquoise: 1221709055,
|
|
1138
|
+
mediumvioletred: 3340076543,
|
|
1139
|
+
midnightblue: 421097727,
|
|
1140
|
+
mintcream: 4127193855,
|
|
1141
|
+
mistyrose: 4293190143,
|
|
1142
|
+
moccasin: 4293178879,
|
|
1143
|
+
navajowhite: 4292783615,
|
|
1144
|
+
navy: 33023,
|
|
1145
|
+
oldlace: 4260751103,
|
|
1146
|
+
olive: 2155872511,
|
|
1147
|
+
olivedrab: 1804477439,
|
|
1148
|
+
orange: 4289003775,
|
|
1149
|
+
orangered: 4282712319,
|
|
1150
|
+
orchid: 3664828159,
|
|
1151
|
+
palegoldenrod: 4008225535,
|
|
1152
|
+
palegreen: 2566625535,
|
|
1153
|
+
paleturquoise: 2951671551,
|
|
1154
|
+
palevioletred: 3681588223,
|
|
1155
|
+
papayawhip: 4293907967,
|
|
1156
|
+
peachpuff: 4292524543,
|
|
1157
|
+
peru: 3448061951,
|
|
1158
|
+
pink: 4290825215,
|
|
1159
|
+
plum: 3718307327,
|
|
1160
|
+
powderblue: 2967529215,
|
|
1161
|
+
purple: 2147516671,
|
|
1162
|
+
rebeccapurple: 1714657791,
|
|
1163
|
+
red: 4278190335,
|
|
1164
|
+
rosybrown: 3163525119,
|
|
1165
|
+
royalblue: 1097458175,
|
|
1166
|
+
saddlebrown: 2336560127,
|
|
1167
|
+
salmon: 4202722047,
|
|
1168
|
+
sandybrown: 4104413439,
|
|
1169
|
+
seagreen: 780883967,
|
|
1170
|
+
seashell: 4294307583,
|
|
1171
|
+
sienna: 2689740287,
|
|
1172
|
+
silver: 3233857791,
|
|
1173
|
+
skyblue: 2278484991,
|
|
1174
|
+
slateblue: 1784335871,
|
|
1175
|
+
slategray: 1887473919,
|
|
1176
|
+
slategrey: 1887473919,
|
|
1177
|
+
snow: 4294638335,
|
|
1178
|
+
springgreen: 16744447,
|
|
1179
|
+
steelblue: 1182971135,
|
|
1180
|
+
tan: 3535047935,
|
|
1181
|
+
teal: 8421631,
|
|
1182
|
+
thistle: 3636451583,
|
|
1183
|
+
tomato: 4284696575,
|
|
1184
|
+
turquoise: 1088475391,
|
|
1185
|
+
violet: 4001558271,
|
|
1186
|
+
wheat: 4125012991,
|
|
1187
|
+
white: 4294967295,
|
|
1188
|
+
whitesmoke: 4126537215,
|
|
1189
|
+
yellow: 4294902015,
|
|
1190
|
+
yellowgreen: 2597139199
|
|
1191
|
+
};
|
|
1192
|
+
function normalizeColor(color) {
|
|
1193
|
+
const matchers = getMatchers();
|
|
1194
|
+
let match;
|
|
1195
|
+
if (matchers.hex6) {
|
|
1196
|
+
if (match = matchers.hex6.exec(color)) {
|
|
1197
|
+
return Number.parseInt(match[1] + "ff", 16) >>> 0;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
if (colorNames[color] !== undefined) {
|
|
1201
|
+
return colorNames[color];
|
|
1202
|
+
}
|
|
1203
|
+
if (matchers.rgb) {
|
|
1204
|
+
if (match = matchers.rgb.exec(color)) {
|
|
1205
|
+
return (parse255(match[1]) << 24 | parse255(match[2]) << 16 | parse255(match[3]) << 8 | 255) >>> 0;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
if (matchers.rgba) {
|
|
1209
|
+
if (match = matchers.rgba.exec(color)) {
|
|
1210
|
+
return (parse255(match[1]) << 24 | parse255(match[2]) << 16 | parse255(match[3]) << 8 | parse1(match[4])) >>> 0;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
if (matchers.hex3) {
|
|
1214
|
+
if (match = matchers.hex3.exec(color)) {
|
|
1215
|
+
return Number.parseInt(match[1] + match[1] + match[2] + match[2] + match[3] + match[3] + "ff", 16) >>> 0;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
if (matchers.hex8) {
|
|
1219
|
+
if (match = matchers.hex8.exec(color)) {
|
|
1220
|
+
return Number.parseInt(match[1], 16) >>> 0;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
if (matchers.hex4) {
|
|
1224
|
+
if (match = matchers.hex4.exec(color)) {
|
|
1225
|
+
return Number.parseInt(match[1] + match[1] + match[2] + match[2] + match[3] + match[3] + match[4] + match[4], 16) >>> 0;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
if (matchers.hsl) {
|
|
1229
|
+
if (match = matchers.hsl.exec(color)) {
|
|
1230
|
+
return (hslToRgb(parse360(match[1]), parsePercentage(match[2]), parsePercentage(match[3])) | 255) >>> 0;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if (matchers.hsla) {
|
|
1234
|
+
if (match = matchers.hsla.exec(color)) {
|
|
1235
|
+
return (hslToRgb(parse360(match[1]), parsePercentage(match[2]), parsePercentage(match[3])) | parse1(match[4])) >>> 0;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
throw new Error(\`invalid color string \${color} provided\`);
|
|
1239
|
+
}
|
|
1240
|
+
function processColor(color) {
|
|
1241
|
+
const normalizedColor = normalizeColor(color);
|
|
1242
|
+
return (normalizedColor << 24 | normalizedColor >>> 8) >>> 0;
|
|
1243
|
+
}
|
|
1244
|
+
var proResProfileOptions = [
|
|
1245
|
+
"4444-xq",
|
|
1246
|
+
"4444",
|
|
1247
|
+
"hq",
|
|
1248
|
+
"standard",
|
|
1249
|
+
"light",
|
|
1250
|
+
"proxy"
|
|
1251
|
+
];
|
|
1252
|
+
var ENABLE_V5_BREAKING_CHANGES = false;
|
|
1253
|
+
var validateFrame = ({
|
|
1254
|
+
allowFloats,
|
|
1255
|
+
durationInFrames,
|
|
1256
|
+
frame
|
|
1257
|
+
}) => {
|
|
1258
|
+
if (typeof frame === "undefined") {
|
|
1259
|
+
throw new TypeError(\`Argument missing for parameter "frame"\`);
|
|
1260
|
+
}
|
|
1261
|
+
if (typeof frame !== "number") {
|
|
1262
|
+
throw new TypeError(\`Argument passed for "frame" is not a number: \${frame}\`);
|
|
1263
|
+
}
|
|
1264
|
+
if (!Number.isFinite(frame)) {
|
|
1265
|
+
throw new RangeError(\`Frame \${frame} is not finite\`);
|
|
1266
|
+
}
|
|
1267
|
+
if (frame % 1 !== 0 && !allowFloats) {
|
|
1268
|
+
throw new RangeError(\`Argument for frame must be an integer, but got \${frame}\`);
|
|
1269
|
+
}
|
|
1270
|
+
if (frame < 0 && frame < -durationInFrames) {
|
|
1271
|
+
throw new RangeError(\`Cannot use frame \${frame}: Duration of composition is \${durationInFrames}, therefore the lowest frame that can be rendered is \${-durationInFrames}\`);
|
|
1272
|
+
}
|
|
1273
|
+
if (frame > durationInFrames - 1) {
|
|
1274
|
+
throw new RangeError(\`Cannot use frame \${frame}: Duration of composition is \${durationInFrames}, therefore the highest frame that can be rendered is \${durationInFrames - 1}\`);
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1277
|
+
var validCodecs = [
|
|
1278
|
+
"h264",
|
|
1279
|
+
"h265",
|
|
1280
|
+
"vp8",
|
|
1281
|
+
"vp9",
|
|
1282
|
+
"mp3",
|
|
1283
|
+
"aac",
|
|
1284
|
+
"wav",
|
|
1285
|
+
"prores",
|
|
1286
|
+
"h264-mkv",
|
|
1287
|
+
"h264-ts",
|
|
1288
|
+
"gif"
|
|
1289
|
+
];
|
|
1290
|
+
function validateCodec(defaultCodec, location, name) {
|
|
1291
|
+
if (typeof defaultCodec === "undefined") {
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
if (typeof defaultCodec !== "string") {
|
|
1295
|
+
throw new TypeError(\`The "\${name}" prop \${location} must be a string, but you passed a value of type \${typeof defaultCodec}.\`);
|
|
1296
|
+
}
|
|
1297
|
+
if (!validCodecs.includes(defaultCodec)) {
|
|
1298
|
+
throw new Error(\`The "\${name}" prop \${location} must be one of \${validCodecs.join(", ")}, but you passed \${defaultCodec}.\`);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
var validateDefaultAndInputProps = (defaultProps, name, compositionId) => {
|
|
1302
|
+
if (!defaultProps) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
if (typeof defaultProps !== "object") {
|
|
1306
|
+
throw new Error(\`"\${name}" must be an object, but you passed a value of type \${typeof defaultProps}\`);
|
|
1307
|
+
}
|
|
1308
|
+
if (Array.isArray(defaultProps)) {
|
|
1309
|
+
throw new Error(\`"\${name}" must be an object, an array was passed \${compositionId ? \`for composition "\${compositionId}"\` : ""}\`);
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
function validateDimension(amount, nameOfProp, location) {
|
|
1313
|
+
if (typeof amount !== "number") {
|
|
1314
|
+
throw new Error(\`The "\${nameOfProp}" prop \${location} must be a number, but you passed a value of type \${typeof amount}\`);
|
|
1315
|
+
}
|
|
1316
|
+
if (isNaN(amount)) {
|
|
1317
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must not be NaN, but is NaN.\`);
|
|
1318
|
+
}
|
|
1319
|
+
if (!Number.isFinite(amount)) {
|
|
1320
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must be finite, but is \${amount}.\`);
|
|
1321
|
+
}
|
|
1322
|
+
if (amount % 1 !== 0) {
|
|
1323
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must be an integer, but is \${amount}.\`);
|
|
1324
|
+
}
|
|
1325
|
+
if (amount <= 0) {
|
|
1326
|
+
throw new TypeError(\`The "\${nameOfProp}" prop \${location} must be positive, but got \${amount}.\`);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
function validateDurationInFrames(durationInFrames, options) {
|
|
1330
|
+
const { allowFloats, component } = options;
|
|
1331
|
+
if (typeof durationInFrames === "undefined") {
|
|
1332
|
+
throw new Error(\`The "durationInFrames" prop \${component} is missing.\`);
|
|
1333
|
+
}
|
|
1334
|
+
if (typeof durationInFrames !== "number") {
|
|
1335
|
+
throw new Error(\`The "durationInFrames" prop \${component} must be a number, but you passed a value of type \${typeof durationInFrames}\`);
|
|
1336
|
+
}
|
|
1337
|
+
if (durationInFrames <= 0) {
|
|
1338
|
+
throw new TypeError(\`The "durationInFrames" prop \${component} must be positive, but got \${durationInFrames}.\`);
|
|
1339
|
+
}
|
|
1340
|
+
if (!allowFloats && durationInFrames % 1 !== 0) {
|
|
1341
|
+
throw new TypeError(\`The "durationInFrames" prop \${component} must be an integer, but got \${durationInFrames}.\`);
|
|
1342
|
+
}
|
|
1343
|
+
if (!Number.isFinite(durationInFrames)) {
|
|
1344
|
+
throw new TypeError(\`The "durationInFrames" prop \${component} must be finite, but got \${durationInFrames}.\`);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
function validateFps(fps, location, isGif) {
|
|
1348
|
+
if (typeof fps !== "number") {
|
|
1349
|
+
throw new Error(\`"fps" must be a number, but you passed a value of type \${typeof fps} \${location}\`);
|
|
1350
|
+
}
|
|
1351
|
+
if (!Number.isFinite(fps)) {
|
|
1352
|
+
throw new Error(\`"fps" must be a finite, but you passed \${fps} \${location}\`);
|
|
1353
|
+
}
|
|
1354
|
+
if (isNaN(fps)) {
|
|
1355
|
+
throw new Error(\`"fps" must not be NaN, but got \${fps} \${location}\`);
|
|
1356
|
+
}
|
|
1357
|
+
if (fps <= 0) {
|
|
1358
|
+
throw new TypeError(\`"fps" must be positive, but got \${fps} \${location}\`);
|
|
1359
|
+
}
|
|
1360
|
+
if (isGif && fps > 50) {
|
|
1361
|
+
throw new TypeError(\`The FPS for a GIF cannot be higher than 50. Use the --every-nth-frame option to lower the FPS: https://remotion.dev/docs/render-as-gif\`);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
var getExpectedMediaFrameUncorrected = ({
|
|
1365
|
+
frame,
|
|
1366
|
+
playbackRate,
|
|
1367
|
+
startFrom
|
|
1368
|
+
}) => {
|
|
1369
|
+
return interpolate(frame, [-1, startFrom, startFrom + 1], [-1, startFrom, startFrom + playbackRate]);
|
|
1370
|
+
};
|
|
1371
|
+
var getAbsoluteSrc = (relativeSrc) => {
|
|
1372
|
+
if (typeof window === "undefined") {
|
|
1373
|
+
return relativeSrc;
|
|
1374
|
+
}
|
|
1375
|
+
if (relativeSrc.startsWith("http://") || relativeSrc.startsWith("https://") || relativeSrc.startsWith("file://") || relativeSrc.startsWith("blob:") || relativeSrc.startsWith("data:")) {
|
|
1376
|
+
return relativeSrc;
|
|
1377
|
+
}
|
|
1378
|
+
return new URL(relativeSrc, window.origin).href;
|
|
1379
|
+
};
|
|
1380
|
+
var getOffthreadVideoSource = ({
|
|
1381
|
+
src,
|
|
1382
|
+
transparent,
|
|
1383
|
+
currentTime,
|
|
1384
|
+
toneMapped
|
|
1385
|
+
}) => {
|
|
1386
|
+
return \`http://localhost:\${window.remotion_proxyPort}/proxy?src=\${encodeURIComponent(getAbsoluteSrc(src))}&time=\${encodeURIComponent(Math.max(0, currentTime))}&transparent=\${String(transparent)}&toneMapped=\${String(toneMapped)}\`;
|
|
1387
|
+
};
|
|
1388
|
+
var NoReactInternals = {
|
|
1389
|
+
processColor,
|
|
1390
|
+
truthy,
|
|
1391
|
+
validateFps,
|
|
1392
|
+
validateDimension,
|
|
1393
|
+
validateDurationInFrames,
|
|
1394
|
+
validateDefaultAndInputProps,
|
|
1395
|
+
validateFrame,
|
|
1396
|
+
serializeJSONWithSpecialTypes,
|
|
1397
|
+
bundleName: "bundle.js",
|
|
1398
|
+
bundleMapName: "bundle.js.map",
|
|
1399
|
+
deserializeJSONWithSpecialTypes,
|
|
1400
|
+
DELAY_RENDER_CALLSTACK_TOKEN,
|
|
1401
|
+
DELAY_RENDER_RETRY_TOKEN,
|
|
1402
|
+
DELAY_RENDER_CLEAR_TOKEN,
|
|
1403
|
+
DELAY_RENDER_ATTEMPT_TOKEN: DELAY_RENDER_RETRIES_LEFT,
|
|
1404
|
+
getOffthreadVideoSource,
|
|
1405
|
+
getExpectedMediaFrameUncorrected,
|
|
1406
|
+
ENABLE_V5_BREAKING_CHANGES,
|
|
1407
|
+
MIN_NODE_VERSION: ENABLE_V5_BREAKING_CHANGES ? 18 : 16,
|
|
1408
|
+
MIN_BUN_VERSION: ENABLE_V5_BREAKING_CHANGES ? "1.1.3" : "1.0.3",
|
|
1409
|
+
colorNames,
|
|
1410
|
+
DATE_TOKEN,
|
|
1411
|
+
FILE_TOKEN,
|
|
1412
|
+
validateCodec,
|
|
1413
|
+
proResProfileOptions
|
|
1414
|
+
};
|
|
1415
|
+
|
|
1416
|
+
// src/scripts/render-video.ts
|
|
1417
|
+
var config = JSON.parse(process.argv[2]);
|
|
1418
|
+
var noop = () => {
|
|
1419
|
+
return;
|
|
1420
|
+
};
|
|
1421
|
+
try {
|
|
1422
|
+
const serializedInputProps = NoReactInternals.serializeJSONWithSpecialTypes({
|
|
1423
|
+
data: config.inputProps,
|
|
1424
|
+
indent: undefined,
|
|
1425
|
+
staticBase: null
|
|
1426
|
+
}).serializedString;
|
|
1427
|
+
console.log(JSON.stringify({ stage: "opening-browser", overallProgress: 0 }));
|
|
1428
|
+
const browser = await RenderInternals.internalOpenBrowser({
|
|
1429
|
+
browser: "chrome",
|
|
1430
|
+
browserExecutable: config.browserExecutable,
|
|
1431
|
+
chromiumOptions: config.chromiumOptions,
|
|
1432
|
+
forceDeviceScaleFactor: undefined,
|
|
1433
|
+
viewport: null,
|
|
1434
|
+
indent: false,
|
|
1435
|
+
logLevel: config.logLevel,
|
|
1436
|
+
onBrowserDownload: () => ({
|
|
1437
|
+
version: null,
|
|
1438
|
+
onProgress: noop
|
|
1439
|
+
}),
|
|
1440
|
+
chromeMode: config.chromeMode
|
|
1441
|
+
});
|
|
1442
|
+
console.log(JSON.stringify({ stage: "selecting-composition", overallProgress: 0.02 }));
|
|
1443
|
+
const { metadata: composition } = await RenderInternals.internalSelectComposition({
|
|
1444
|
+
serializedInputPropsWithCustomSchema: serializedInputProps,
|
|
1445
|
+
envVariables: config.envVariables,
|
|
1446
|
+
puppeteerInstance: browser,
|
|
1447
|
+
onBrowserLog: null,
|
|
1448
|
+
browserExecutable: config.browserExecutable,
|
|
1449
|
+
chromiumOptions: config.chromiumOptions,
|
|
1450
|
+
port: null,
|
|
1451
|
+
indent: false,
|
|
1452
|
+
server: undefined,
|
|
1453
|
+
serveUrl: config.serveUrl,
|
|
1454
|
+
id: config.compositionId,
|
|
1455
|
+
onServeUrlVisited: noop,
|
|
1456
|
+
logLevel: config.logLevel,
|
|
1457
|
+
timeoutInMilliseconds: config.timeoutInMilliseconds,
|
|
1458
|
+
binariesDirectory: config.binariesDirectory,
|
|
1459
|
+
onBrowserDownload: () => ({
|
|
1460
|
+
version: null,
|
|
1461
|
+
onProgress: noop
|
|
1462
|
+
}),
|
|
1463
|
+
chromeMode: config.chromeMode,
|
|
1464
|
+
mediaCacheSizeInBytes: config.mediaCacheSizeInBytes,
|
|
1465
|
+
offthreadVideoCacheSizeInBytes: config.offthreadVideoCacheSizeInBytes,
|
|
1466
|
+
offthreadVideoThreads: config.offthreadVideoThreads
|
|
1467
|
+
});
|
|
1468
|
+
const serializedResolvedProps = NoReactInternals.serializeJSONWithSpecialTypes({
|
|
1469
|
+
data: composition.props,
|
|
1470
|
+
indent: undefined,
|
|
1471
|
+
staticBase: null
|
|
1472
|
+
}).serializedString;
|
|
1473
|
+
const { contentType } = await RenderInternals.internalRenderMedia({
|
|
1474
|
+
outputLocation: config.outputLocation,
|
|
1475
|
+
composition,
|
|
1476
|
+
serializedInputPropsWithCustomSchema: serializedInputProps,
|
|
1477
|
+
serializedResolvedPropsWithCustomSchema: serializedResolvedProps,
|
|
1478
|
+
serveUrl: config.serveUrl,
|
|
1479
|
+
codec: config.codec,
|
|
1480
|
+
crf: config.crf,
|
|
1481
|
+
imageFormat: config.imageFormat,
|
|
1482
|
+
pixelFormat: config.pixelFormat,
|
|
1483
|
+
envVariables: config.envVariables,
|
|
1484
|
+
frameRange: config.frameRange,
|
|
1485
|
+
everyNthFrame: config.everyNthFrame,
|
|
1486
|
+
overwrite: true,
|
|
1487
|
+
proResProfile: config.proResProfile ?? undefined,
|
|
1488
|
+
chromiumOptions: config.chromiumOptions,
|
|
1489
|
+
scale: config.scale,
|
|
1490
|
+
browserExecutable: config.browserExecutable,
|
|
1491
|
+
preferLossless: config.preferLossless,
|
|
1492
|
+
enforceAudioTrack: config.enforceAudioTrack,
|
|
1493
|
+
disallowParallelEncoding: config.disallowParallelEncoding,
|
|
1494
|
+
concurrency: config.concurrency,
|
|
1495
|
+
binariesDirectory: config.binariesDirectory,
|
|
1496
|
+
metadata: config.metadata,
|
|
1497
|
+
licenseKey: config.licenseKey,
|
|
1498
|
+
videoBitrate: config.videoBitrate,
|
|
1499
|
+
audioBitrate: config.audioBitrate,
|
|
1500
|
+
encodingMaxRate: config.encodingMaxRate,
|
|
1501
|
+
encodingBufferSize: config.encodingBufferSize,
|
|
1502
|
+
muted: config.muted,
|
|
1503
|
+
numberOfGifLoops: config.numberOfGifLoops,
|
|
1504
|
+
x264Preset: config.x264Preset,
|
|
1505
|
+
colorSpace: config.colorSpace,
|
|
1506
|
+
jpegQuality: config.jpegQuality,
|
|
1507
|
+
audioCodec: config.audioCodec,
|
|
1508
|
+
logLevel: config.logLevel,
|
|
1509
|
+
timeoutInMilliseconds: config.timeoutInMilliseconds,
|
|
1510
|
+
forSeamlessAacConcatenation: config.forSeamlessAacConcatenation,
|
|
1511
|
+
separateAudioTo: config.separateAudioTo,
|
|
1512
|
+
hardwareAcceleration: config.hardwareAcceleration,
|
|
1513
|
+
chromeMode: config.chromeMode,
|
|
1514
|
+
offthreadVideoCacheSizeInBytes: config.offthreadVideoCacheSizeInBytes,
|
|
1515
|
+
mediaCacheSizeInBytes: config.mediaCacheSizeInBytes,
|
|
1516
|
+
offthreadVideoThreads: config.offthreadVideoThreads,
|
|
1517
|
+
repro: config.repro,
|
|
1518
|
+
puppeteerInstance: browser,
|
|
1519
|
+
onProgress: (progress) => {
|
|
1520
|
+
console.log(JSON.stringify({
|
|
1521
|
+
stage: "render-progress",
|
|
1522
|
+
progress: {
|
|
1523
|
+
renderedFrames: progress.renderedFrames,
|
|
1524
|
+
encodedFrames: progress.encodedFrames,
|
|
1525
|
+
encodedDoneIn: progress.encodedDoneIn,
|
|
1526
|
+
renderedDoneIn: progress.renderedDoneIn,
|
|
1527
|
+
renderEstimatedTime: progress.renderEstimatedTime,
|
|
1528
|
+
progress: progress.progress,
|
|
1529
|
+
stitchStage: progress.stitchStage
|
|
1530
|
+
},
|
|
1531
|
+
overallProgress: 0.04 + progress.progress * 0.96
|
|
1532
|
+
}));
|
|
1533
|
+
},
|
|
1534
|
+
onDownload: () => {
|
|
1535
|
+
return;
|
|
1536
|
+
},
|
|
1537
|
+
onBrowserLog: null,
|
|
1538
|
+
onStart: noop,
|
|
1539
|
+
port: null,
|
|
1540
|
+
cancelSignal: undefined,
|
|
1541
|
+
onCtrlCExit: noop,
|
|
1542
|
+
indent: false,
|
|
1543
|
+
server: undefined,
|
|
1544
|
+
ffmpegOverride: undefined,
|
|
1545
|
+
compositionStart: 0,
|
|
1546
|
+
onArtifact: null,
|
|
1547
|
+
onLog: RenderInternals.defaultOnLog,
|
|
1548
|
+
isProduction: true,
|
|
1549
|
+
onBrowserDownload: () => ({
|
|
1550
|
+
version: null,
|
|
1551
|
+
onProgress: noop
|
|
1552
|
+
})
|
|
1553
|
+
});
|
|
1554
|
+
console.log(JSON.stringify({ stage: "render-complete", overallProgress: 1 }));
|
|
1555
|
+
await browser.close({ silent: false });
|
|
1556
|
+
const { size } = statSync(config.outputLocation ?? "/tmp/video.mp4");
|
|
1557
|
+
console.log(JSON.stringify({ stage: "done", size, contentType, overallProgress: 1 }));
|
|
1558
|
+
} catch (err) {
|
|
1559
|
+
console.error(err.message);
|
|
1560
|
+
process.exit(1);
|
|
1561
|
+
}
|
|
1562
|
+
`;
|
|
1563
|
+
|
|
1564
|
+
// script-embed:upload-blob-script
|
|
1565
|
+
var script3 = `// src/scripts/upload-blob.ts
|
|
1566
|
+
import { put } from "@vercel/blob";
|
|
1567
|
+
import { readFileSync, statSync } from "fs";
|
|
1568
|
+
var config = JSON.parse(process.argv[2]);
|
|
1569
|
+
try {
|
|
1570
|
+
const fileBuffer = readFileSync(config.sandboxFilePath);
|
|
1571
|
+
const size = statSync(config.sandboxFilePath).size;
|
|
1572
|
+
const blob = await put(config.blobPath, fileBuffer, {
|
|
1573
|
+
access: config.access,
|
|
1574
|
+
contentType: config.contentType,
|
|
1575
|
+
token: config.blobToken
|
|
1576
|
+
});
|
|
1577
|
+
console.log(JSON.stringify({
|
|
1578
|
+
type: "done",
|
|
1579
|
+
url: blob.downloadUrl,
|
|
1580
|
+
size
|
|
1581
|
+
}));
|
|
1582
|
+
} catch (err) {
|
|
1583
|
+
console.error(err.message);
|
|
1584
|
+
process.exit(1);
|
|
1585
|
+
}
|
|
1586
|
+
`;
|
|
1587
|
+
|
|
1588
|
+
// src/internals/disposable.ts
|
|
1589
|
+
import { Sandbox } from "@vercel/sandbox";
|
|
1590
|
+
var createDisposableSandbox = async (options) => {
|
|
1591
|
+
const sandbox = await Sandbox.create(options);
|
|
1592
|
+
return Object.assign(sandbox, {
|
|
1593
|
+
[Symbol.asyncDispose]: async () => {
|
|
1594
|
+
await sandbox.stop().catch(() => {});
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1599
|
+
// script-embed:ensure-browser-script
|
|
1600
|
+
var script4 = `// src/scripts/ensure-browser.ts
|
|
1601
|
+
import { ensureBrowser } from "@remotion/renderer";
|
|
1602
|
+
await ensureBrowser({
|
|
1603
|
+
onBrowserDownload: () => {
|
|
1604
|
+
return {
|
|
1605
|
+
version: null,
|
|
1606
|
+
onProgress: ({ percent }) => {
|
|
1607
|
+
console.log(JSON.stringify({ type: "browser-progress", percent }));
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1612
|
+
`;
|
|
1613
|
+
|
|
1614
|
+
// src/internals/install-browser.ts
|
|
1615
|
+
async function installBrowser({
|
|
1616
|
+
sandbox,
|
|
1617
|
+
onProgress
|
|
1618
|
+
}) {
|
|
1619
|
+
await sandbox.writeFiles([
|
|
1620
|
+
{
|
|
1621
|
+
path: "ensure-browser.mjs",
|
|
1622
|
+
content: Buffer.from(script4)
|
|
1623
|
+
}
|
|
1624
|
+
]);
|
|
1625
|
+
const ensureBrowserCmd = await sandbox.runCommand({
|
|
1626
|
+
cmd: "node",
|
|
1627
|
+
args: ["ensure-browser.mjs"],
|
|
1628
|
+
detached: true
|
|
1629
|
+
});
|
|
1630
|
+
for await (const log of ensureBrowserCmd.logs()) {
|
|
1631
|
+
if (log.stream === "stdout") {
|
|
1632
|
+
try {
|
|
1633
|
+
const message = JSON.parse(log.data);
|
|
1634
|
+
if (message.type === "browser-progress") {
|
|
1635
|
+
await onProgress(message.percent ?? 0);
|
|
1636
|
+
continue;
|
|
1637
|
+
}
|
|
1638
|
+
} catch {}
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
const ensureBrowserResult = await ensureBrowserCmd.wait();
|
|
1642
|
+
if (ensureBrowserResult.exitCode !== 0) {
|
|
1643
|
+
throw new Error(`ensure-browser failed: ${await ensureBrowserResult.stderr()} ${await ensureBrowserResult.stdout()}`);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// src/internals/install-js-dependencies.ts
|
|
1648
|
+
import { VERSION } from "remotion/version";
|
|
1649
|
+
async function installJsDependencies({
|
|
1650
|
+
sandbox
|
|
1651
|
+
}) {
|
|
1652
|
+
const installCmd = await sandbox.runCommand({
|
|
1653
|
+
cmd: "pnpm",
|
|
1654
|
+
args: [
|
|
1655
|
+
"i",
|
|
1656
|
+
`@remotion/renderer@${VERSION}`,
|
|
1657
|
+
`@remotion/compositor-linux-x64-gnu@${VERSION}`,
|
|
1658
|
+
`@vercel/blob`
|
|
1659
|
+
],
|
|
1660
|
+
detached: true
|
|
1661
|
+
});
|
|
1662
|
+
for await (const _log of installCmd.logs()) {}
|
|
1663
|
+
const installResult = await installCmd.wait();
|
|
1664
|
+
if (installResult.exitCode !== 0) {
|
|
1665
|
+
throw new Error(`pnpm install failed: ${await installResult.stderr()}`);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
// src/internals/install-system-dependencies.ts
|
|
1670
|
+
async function installSystemDependencies({
|
|
1671
|
+
sandbox,
|
|
1672
|
+
onProgress
|
|
1673
|
+
}) {
|
|
1674
|
+
const sysInstallCmd = await sandbox.runCommand({
|
|
1675
|
+
cmd: "sudo",
|
|
1676
|
+
args: [
|
|
1677
|
+
"dnf",
|
|
1678
|
+
"install",
|
|
1679
|
+
"-y",
|
|
1680
|
+
"nss",
|
|
1681
|
+
"atk",
|
|
1682
|
+
"at-spi2-atk",
|
|
1683
|
+
"cups-libs",
|
|
1684
|
+
"libdrm",
|
|
1685
|
+
"libXcomposite",
|
|
1686
|
+
"libXdamage",
|
|
1687
|
+
"libXrandr",
|
|
1688
|
+
"mesa-libgbm",
|
|
1689
|
+
"alsa-lib",
|
|
1690
|
+
"pango",
|
|
1691
|
+
"gtk3",
|
|
1692
|
+
"patchelf",
|
|
1693
|
+
"zstd",
|
|
1694
|
+
"binutils"
|
|
1695
|
+
],
|
|
1696
|
+
detached: true
|
|
1697
|
+
});
|
|
1698
|
+
const EXPECTED_SYS_INSTALL_LINES = 272;
|
|
1699
|
+
let sysInstallLineCount = 0;
|
|
1700
|
+
for await (const _log of sysInstallCmd.logs()) {
|
|
1701
|
+
sysInstallLineCount++;
|
|
1702
|
+
const stageProgress = Math.min(sysInstallLineCount / EXPECTED_SYS_INSTALL_LINES, 1);
|
|
1703
|
+
await onProgress(stageProgress);
|
|
1704
|
+
}
|
|
1705
|
+
const sysInstallResult = await sysInstallCmd.wait();
|
|
1706
|
+
if (sysInstallResult.exitCode !== 0) {
|
|
1707
|
+
throw new Error(`System dependencies install failed: ${await sysInstallResult.stderr()}`);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// src/internals/patch-compositor.ts
|
|
1712
|
+
var GLIBC_DIR = "/tmp/glibc235";
|
|
1713
|
+
var LIBC6_DEB_URL = "https://launchpadlibrarian.net/612471225/libc6_2.35-0ubuntu3.1_amd64.deb";
|
|
1714
|
+
async function patchCompositor({
|
|
1715
|
+
sandbox
|
|
1716
|
+
}) {
|
|
1717
|
+
const script5 = `
|
|
1718
|
+
set -euo pipefail
|
|
1719
|
+
|
|
1720
|
+
echo "[patch-compositor] Listing node_modules/@remotion/:"
|
|
1721
|
+
ls -la node_modules/@remotion/ 2>&1 || echo "(directory does not exist)"
|
|
1722
|
+
|
|
1723
|
+
echo "[patch-compositor] Checking .pnpm store for compositor packages:"
|
|
1724
|
+
ls -la node_modules/.pnpm/@remotion+compositor-linux* 2>&1 || echo "(none found in .pnpm)"
|
|
1725
|
+
|
|
1726
|
+
echo "[patch-compositor] Checking for compositor directories..."
|
|
1727
|
+
for dir in node_modules/@remotion/compositor-linux-x64-gnu; do
|
|
1728
|
+
if [ -e "$dir" ]; then
|
|
1729
|
+
echo "[patch-compositor] Found: $dir ($(stat -c '%F' "$dir" 2>/dev/null || file "$dir"))"
|
|
1730
|
+
if [ -L "$dir" ]; then
|
|
1731
|
+
echo "[patch-compositor] Symlink target: $(readlink -f "$dir")"
|
|
1732
|
+
fi
|
|
1733
|
+
echo "[patch-compositor] Contents:"
|
|
1734
|
+
find -L "$dir" -type f 2>&1 || true
|
|
1735
|
+
else
|
|
1736
|
+
echo "[patch-compositor] Not found: $dir"
|
|
1737
|
+
fi
|
|
1738
|
+
done
|
|
1739
|
+
|
|
1740
|
+
COMPOSITOR_BIN=""
|
|
1741
|
+
# Search with -L to follow pnpm symlinks
|
|
1742
|
+
for dir in node_modules/@remotion/compositor-linux-x64-gnu; do
|
|
1743
|
+
if [ -e "$dir" ]; then
|
|
1744
|
+
COMPOSITOR_BIN="$(find -L "$dir" -name remotion -type f | head -1)"
|
|
1745
|
+
[ -n "$COMPOSITOR_BIN" ] && break
|
|
1746
|
+
fi
|
|
1747
|
+
done
|
|
1748
|
+
|
|
1749
|
+
# Fallback: search the pnpm store directly
|
|
1750
|
+
if [ -z "$COMPOSITOR_BIN" ]; then
|
|
1751
|
+
echo "[patch-compositor] Trying pnpm store fallback..."
|
|
1752
|
+
COMPOSITOR_BIN="$(find -L node_modules/.pnpm -path '*compositor-linux-x64*' -name remotion -type f 2>/dev/null | head -1)"
|
|
1753
|
+
fi
|
|
1754
|
+
|
|
1755
|
+
if [ -z "$COMPOSITOR_BIN" ]; then
|
|
1756
|
+
echo "[patch-compositor] ERROR: Compositor binary not found"
|
|
1757
|
+
exit 1
|
|
1758
|
+
fi
|
|
1759
|
+
|
|
1760
|
+
echo "[patch-compositor] Found compositor binary: $COMPOSITOR_BIN"
|
|
1761
|
+
|
|
1762
|
+
# Download and extract glibc 2.35 from Ubuntu 22.04
|
|
1763
|
+
echo "[patch-compositor] Downloading glibc 2.35..."
|
|
1764
|
+
mkdir -p ${GLIBC_DIR}
|
|
1765
|
+
cd /tmp
|
|
1766
|
+
curl -fsSL -o libc6.deb "${LIBC6_DEB_URL}"
|
|
1767
|
+
ar x libc6.deb
|
|
1768
|
+
zstd -d data.tar.zst -o data.tar
|
|
1769
|
+
tar xf data.tar -C ${GLIBC_DIR} --strip-components=1
|
|
1770
|
+
rm -f libc6.deb data.tar data.tar.zst control.tar.zst debian-binary
|
|
1771
|
+
|
|
1772
|
+
cd -
|
|
1773
|
+
|
|
1774
|
+
# Patch the compositor binary
|
|
1775
|
+
echo "[patch-compositor] Patching binary with patchelf..."
|
|
1776
|
+
patchelf \\
|
|
1777
|
+
--set-interpreter ${GLIBC_DIR}/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 \\
|
|
1778
|
+
--force-rpath \\
|
|
1779
|
+
--set-rpath ${GLIBC_DIR}/lib/x86_64-linux-gnu:\\$ORIGIN \\
|
|
1780
|
+
"$COMPOSITOR_BIN"
|
|
1781
|
+
|
|
1782
|
+
echo "[patch-compositor] Compositor patched successfully"
|
|
1783
|
+
`;
|
|
1784
|
+
const cmd = await sandbox.runCommand({
|
|
1785
|
+
cmd: "bash",
|
|
1786
|
+
args: ["-c", script5],
|
|
1787
|
+
detached: true
|
|
1788
|
+
});
|
|
1789
|
+
for await (const _log of cmd.logs()) {}
|
|
1790
|
+
const result = await cmd.wait();
|
|
1791
|
+
if (result.exitCode !== 0) {
|
|
1792
|
+
throw new Error(`Failed to patch compositor: ${await result.stderr()} ${await result.stdout()}`);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
// src/create-sandbox.ts
|
|
1797
|
+
var SANDBOX_CREATING_TIMEOUT = 5 * 60 * 1000;
|
|
1798
|
+
async function createSandbox({
|
|
1799
|
+
onProgress,
|
|
1800
|
+
resources = { vcpus: 4 }
|
|
1801
|
+
} = {}) {
|
|
1802
|
+
const report = async (progress, message) => {
|
|
1803
|
+
await onProgress?.({ progress, message });
|
|
1804
|
+
};
|
|
1805
|
+
const sandbox = await createDisposableSandbox({
|
|
1806
|
+
runtime: "node24",
|
|
1807
|
+
resources,
|
|
1808
|
+
timeout: SANDBOX_CREATING_TIMEOUT
|
|
1809
|
+
});
|
|
1810
|
+
const WEIGHT_SYS_DEPS = 0.75;
|
|
1811
|
+
const WEIGHT_BROWSER = 0.25;
|
|
1812
|
+
await report(0, "Installing system dependencies...");
|
|
1813
|
+
await installSystemDependencies({
|
|
1814
|
+
sandbox,
|
|
1815
|
+
onProgress: async (stageProgress) => {
|
|
1816
|
+
await report(stageProgress * WEIGHT_SYS_DEPS, "Installing system dependencies...");
|
|
1817
|
+
}
|
|
1818
|
+
});
|
|
1819
|
+
await report(WEIGHT_SYS_DEPS, "Installing JS dependencies...");
|
|
1820
|
+
await installJsDependencies({ sandbox });
|
|
1821
|
+
await patchCompositor({ sandbox });
|
|
1822
|
+
await report(WEIGHT_SYS_DEPS, "Downloading browser...");
|
|
1823
|
+
await installBrowser({
|
|
1824
|
+
sandbox,
|
|
1825
|
+
onProgress: async (browserProgress) => {
|
|
1826
|
+
await report(WEIGHT_SYS_DEPS + browserProgress * WEIGHT_BROWSER, "Downloading browser...");
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
await sandbox.writeFiles([
|
|
1830
|
+
{
|
|
1831
|
+
path: "package.json",
|
|
1832
|
+
content: Buffer.from(JSON.stringify({ type: "module" }))
|
|
1833
|
+
},
|
|
1834
|
+
{
|
|
1835
|
+
path: "render-video.mjs",
|
|
1836
|
+
content: Buffer.from(script2)
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
path: "render-still.mjs",
|
|
1840
|
+
content: Buffer.from(script)
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
path: "upload-blob.mjs",
|
|
1844
|
+
content: Buffer.from(script3)
|
|
1845
|
+
}
|
|
1846
|
+
]);
|
|
1847
|
+
await report(1, "Sandbox ready");
|
|
1848
|
+
return sandbox;
|
|
1849
|
+
}
|
|
1850
|
+
// src/render-media-on-vercel.ts
|
|
1851
|
+
async function renderMediaOnVercel({
|
|
1852
|
+
sandbox,
|
|
1853
|
+
compositionId,
|
|
1854
|
+
inputProps,
|
|
1855
|
+
onProgress,
|
|
1856
|
+
outputFile = "/tmp/video.mp4",
|
|
1857
|
+
codec = "h264",
|
|
1858
|
+
crf,
|
|
1859
|
+
imageFormat,
|
|
1860
|
+
pixelFormat,
|
|
1861
|
+
envVariables = {},
|
|
1862
|
+
frameRange,
|
|
1863
|
+
everyNthFrame = 1,
|
|
1864
|
+
proResProfile,
|
|
1865
|
+
chromiumOptions = {},
|
|
1866
|
+
scale = 1,
|
|
1867
|
+
preferLossless = false,
|
|
1868
|
+
enforceAudioTrack = false,
|
|
1869
|
+
disallowParallelEncoding = false,
|
|
1870
|
+
concurrency,
|
|
1871
|
+
metadata,
|
|
1872
|
+
licenseKey,
|
|
1873
|
+
videoBitrate,
|
|
1874
|
+
audioBitrate,
|
|
1875
|
+
encodingMaxRate,
|
|
1876
|
+
encodingBufferSize,
|
|
1877
|
+
muted = false,
|
|
1878
|
+
numberOfGifLoops,
|
|
1879
|
+
x264Preset,
|
|
1880
|
+
colorSpace = "default",
|
|
1881
|
+
jpegQuality = 80,
|
|
1882
|
+
audioCodec,
|
|
1883
|
+
logLevel = "info",
|
|
1884
|
+
timeoutInMilliseconds = 30000,
|
|
1885
|
+
forSeamlessAacConcatenation = false,
|
|
1886
|
+
separateAudioTo,
|
|
1887
|
+
hardwareAcceleration = "disable",
|
|
1888
|
+
offthreadVideoCacheSizeInBytes,
|
|
1889
|
+
mediaCacheSizeInBytes,
|
|
1890
|
+
offthreadVideoThreads
|
|
1891
|
+
}) {
|
|
1892
|
+
const serveUrl = `/vercel/sandbox/${REMOTION_SANDBOX_BUNDLE_DIR}`;
|
|
1893
|
+
const renderConfig = {
|
|
1894
|
+
serveUrl,
|
|
1895
|
+
compositionId,
|
|
1896
|
+
inputProps,
|
|
1897
|
+
outputLocation: outputFile,
|
|
1898
|
+
codec,
|
|
1899
|
+
crf: crf ?? null,
|
|
1900
|
+
imageFormat: imageFormat ?? null,
|
|
1901
|
+
pixelFormat: pixelFormat ?? null,
|
|
1902
|
+
envVariables,
|
|
1903
|
+
frameRange: frameRange ?? null,
|
|
1904
|
+
everyNthFrame,
|
|
1905
|
+
proResProfile: proResProfile ?? null,
|
|
1906
|
+
chromiumOptions,
|
|
1907
|
+
scale,
|
|
1908
|
+
preferLossless,
|
|
1909
|
+
enforceAudioTrack,
|
|
1910
|
+
disallowParallelEncoding,
|
|
1911
|
+
concurrency: concurrency ?? null,
|
|
1912
|
+
metadata: metadata ?? null,
|
|
1913
|
+
licenseKey: licenseKey ?? null,
|
|
1914
|
+
videoBitrate: videoBitrate ?? null,
|
|
1915
|
+
audioBitrate: audioBitrate ?? null,
|
|
1916
|
+
encodingMaxRate: encodingMaxRate ?? null,
|
|
1917
|
+
encodingBufferSize: encodingBufferSize ?? null,
|
|
1918
|
+
muted,
|
|
1919
|
+
numberOfGifLoops: numberOfGifLoops ?? null,
|
|
1920
|
+
x264Preset: x264Preset ?? null,
|
|
1921
|
+
colorSpace,
|
|
1922
|
+
jpegQuality,
|
|
1923
|
+
audioCodec: audioCodec ?? null,
|
|
1924
|
+
logLevel,
|
|
1925
|
+
timeoutInMilliseconds,
|
|
1926
|
+
forSeamlessAacConcatenation,
|
|
1927
|
+
separateAudioTo: separateAudioTo ?? null,
|
|
1928
|
+
hardwareAcceleration,
|
|
1929
|
+
offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes ?? null,
|
|
1930
|
+
mediaCacheSizeInBytes: mediaCacheSizeInBytes ?? null,
|
|
1931
|
+
offthreadVideoThreads: offthreadVideoThreads ?? null,
|
|
1932
|
+
chromeMode: "headless-shell",
|
|
1933
|
+
browserExecutable: null,
|
|
1934
|
+
binariesDirectory: null,
|
|
1935
|
+
repro: false
|
|
1936
|
+
};
|
|
1937
|
+
const renderCmd = await sandbox.runCommand({
|
|
1938
|
+
cmd: "node",
|
|
1939
|
+
args: ["render-video.mjs", JSON.stringify(renderConfig)],
|
|
1940
|
+
detached: true
|
|
1941
|
+
});
|
|
1942
|
+
let contentType = "application/octet-stream";
|
|
1943
|
+
for await (const log of renderCmd.logs()) {
|
|
1944
|
+
if (log.stream === "stdout") {
|
|
1945
|
+
try {
|
|
1946
|
+
const message = JSON.parse(log.data);
|
|
1947
|
+
if (message.stage === "done") {
|
|
1948
|
+
contentType = message.contentType;
|
|
1949
|
+
} else if (message.stage === "opening-browser" || message.stage === "selecting-composition" || message.stage === "render-progress") {
|
|
1950
|
+
await onProgress?.(message);
|
|
1951
|
+
}
|
|
1952
|
+
} catch {}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
const renderResult = await renderCmd.wait();
|
|
1956
|
+
if (renderResult.exitCode !== 0) {
|
|
1957
|
+
const stderr = await renderResult.stderr();
|
|
1958
|
+
const stdout = await renderResult.stdout();
|
|
1959
|
+
throw new Error(`Render failed: ${stderr} ${stdout}`);
|
|
1960
|
+
}
|
|
1961
|
+
return { sandboxFilePath: outputFile, contentType };
|
|
1962
|
+
}
|
|
1963
|
+
// src/render-still-on-vercel.ts
|
|
1964
|
+
async function renderStillOnVercel({
|
|
1965
|
+
sandbox,
|
|
1966
|
+
compositionId,
|
|
1967
|
+
inputProps,
|
|
1968
|
+
onProgress,
|
|
1969
|
+
outputFile = "/tmp/still.png",
|
|
1970
|
+
frame = 0,
|
|
1971
|
+
imageFormat = "png",
|
|
1972
|
+
jpegQuality = 80,
|
|
1973
|
+
envVariables = {},
|
|
1974
|
+
chromiumOptions = {},
|
|
1975
|
+
scale = 1,
|
|
1976
|
+
logLevel = "info",
|
|
1977
|
+
timeoutInMilliseconds = 30000,
|
|
1978
|
+
offthreadVideoCacheSizeInBytes,
|
|
1979
|
+
mediaCacheSizeInBytes,
|
|
1980
|
+
offthreadVideoThreads,
|
|
1981
|
+
licenseKey
|
|
1982
|
+
}) {
|
|
1983
|
+
const serveUrl = `/vercel/sandbox/${REMOTION_SANDBOX_BUNDLE_DIR}`;
|
|
1984
|
+
const renderConfig = {
|
|
1985
|
+
serveUrl,
|
|
1986
|
+
compositionId,
|
|
1987
|
+
inputProps,
|
|
1988
|
+
output: outputFile,
|
|
1989
|
+
frame,
|
|
1990
|
+
imageFormat,
|
|
1991
|
+
jpegQuality,
|
|
1992
|
+
envVariables,
|
|
1993
|
+
chromiumOptions,
|
|
1994
|
+
scale,
|
|
1995
|
+
logLevel,
|
|
1996
|
+
timeoutInMilliseconds,
|
|
1997
|
+
offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes ?? null,
|
|
1998
|
+
mediaCacheSizeInBytes: mediaCacheSizeInBytes ?? null,
|
|
1999
|
+
offthreadVideoThreads: offthreadVideoThreads ?? null,
|
|
2000
|
+
licenseKey: licenseKey ?? null,
|
|
2001
|
+
chromeMode: "headless-shell",
|
|
2002
|
+
browserExecutable: null,
|
|
2003
|
+
binariesDirectory: null
|
|
2004
|
+
};
|
|
2005
|
+
const renderCmd = await sandbox.runCommand({
|
|
2006
|
+
cmd: "node",
|
|
2007
|
+
args: ["render-still.mjs", JSON.stringify(renderConfig)],
|
|
2008
|
+
detached: true
|
|
2009
|
+
});
|
|
2010
|
+
let contentType = "application/octet-stream";
|
|
2011
|
+
for await (const log of renderCmd.logs()) {
|
|
2012
|
+
if (log.stream === "stdout") {
|
|
2013
|
+
try {
|
|
2014
|
+
const message = JSON.parse(log.data);
|
|
2015
|
+
if (message.type === "opening-browser") {
|
|
2016
|
+
await onProgress?.({
|
|
2017
|
+
stage: "opening-browser",
|
|
2018
|
+
overallProgress: 0
|
|
2019
|
+
});
|
|
2020
|
+
} else if (message.type === "selecting-composition") {
|
|
2021
|
+
await onProgress?.({
|
|
2022
|
+
stage: "selecting-composition",
|
|
2023
|
+
overallProgress: 0.5
|
|
2024
|
+
});
|
|
2025
|
+
} else if (message.type === "done") {
|
|
2026
|
+
contentType = message.contentType;
|
|
2027
|
+
}
|
|
2028
|
+
} catch {}
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
const renderResult = await renderCmd.wait();
|
|
2032
|
+
if (renderResult.exitCode !== 0) {
|
|
2033
|
+
const stderr = await renderResult.stderr();
|
|
2034
|
+
const stdout = await renderResult.stdout();
|
|
2035
|
+
throw new Error(`Render still failed: ${stderr} ${stdout}`);
|
|
2036
|
+
}
|
|
2037
|
+
return { sandboxFilePath: outputFile, contentType };
|
|
2038
|
+
}
|
|
2039
|
+
// src/upload-to-vercel-blob.ts
|
|
2040
|
+
function getExtension(filePath) {
|
|
2041
|
+
const lastDot = filePath.lastIndexOf(".");
|
|
2042
|
+
if (lastDot === -1) {
|
|
2043
|
+
return "";
|
|
2044
|
+
}
|
|
2045
|
+
return filePath.slice(lastDot);
|
|
2046
|
+
}
|
|
2047
|
+
async function uploadToVercelBlob({
|
|
2048
|
+
sandbox,
|
|
2049
|
+
sandboxFilePath,
|
|
2050
|
+
blobPath,
|
|
2051
|
+
contentType,
|
|
2052
|
+
blobToken,
|
|
2053
|
+
access
|
|
2054
|
+
}) {
|
|
2055
|
+
const actualBlobPath = blobPath ?? `renders/${crypto.randomUUID()}${getExtension(sandboxFilePath)}`;
|
|
2056
|
+
const uploadConfig = {
|
|
2057
|
+
sandboxFilePath,
|
|
2058
|
+
blobPath: actualBlobPath,
|
|
2059
|
+
contentType,
|
|
2060
|
+
blobToken,
|
|
2061
|
+
access
|
|
2062
|
+
};
|
|
2063
|
+
const uploadCmd = await sandbox.runCommand({
|
|
2064
|
+
cmd: "node",
|
|
2065
|
+
args: ["upload-blob.mjs", JSON.stringify(uploadConfig)],
|
|
2066
|
+
detached: true
|
|
2067
|
+
});
|
|
2068
|
+
let result = null;
|
|
2069
|
+
for await (const log of uploadCmd.logs()) {
|
|
2070
|
+
if (log.stream === "stdout") {
|
|
2071
|
+
try {
|
|
2072
|
+
const message = JSON.parse(log.data);
|
|
2073
|
+
if (message.type === "done") {
|
|
2074
|
+
result = { url: message.url, size: message.size };
|
|
2075
|
+
}
|
|
2076
|
+
} catch {}
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
const uploadResult = await uploadCmd.wait();
|
|
2080
|
+
if (uploadResult.exitCode !== 0) {
|
|
2081
|
+
const stderr = await uploadResult.stderr();
|
|
2082
|
+
const stdout = await uploadResult.stdout();
|
|
2083
|
+
throw new Error(`Upload failed: ${stderr} ${stdout}`);
|
|
2084
|
+
}
|
|
2085
|
+
if (!result) {
|
|
2086
|
+
throw new Error("Upload script did not return result");
|
|
2087
|
+
}
|
|
2088
|
+
return result;
|
|
2089
|
+
}
|
|
2090
|
+
export {
|
|
2091
|
+
uploadToVercelBlob,
|
|
2092
|
+
renderStillOnVercel,
|
|
2093
|
+
renderMediaOnVercel,
|
|
2094
|
+
createSandbox,
|
|
2095
|
+
addBundleToSandbox
|
|
2096
|
+
};
|