@remotion/studio-server 4.0.465 → 4.0.467

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.
@@ -1,5 +1,5 @@
1
1
  import type { ArrayExpression, CallExpression, JSXAttribute } from '@babel/types';
2
- import type { SequenceNodePath } from 'remotion';
2
+ import type { SequenceNodePath, SequenceSchema } from 'remotion';
3
3
  export type EffectPropUpdate = {
4
4
  key: string;
5
5
  value: unknown;
@@ -11,6 +11,11 @@ export type UpdateEffectPropsResult = {
11
11
  oldValueString: string;
12
12
  logLine: number;
13
13
  effectCallee: string;
14
+ removedProps: PropDelta[];
15
+ };
16
+ export type PropDelta = {
17
+ key: string;
18
+ valueString: string;
14
19
  };
15
20
  export declare const findEffectsAttr: (attrs: readonly unknown[]) => JSXAttribute | null;
16
21
  export type EffectArrayElement = {
@@ -33,21 +38,24 @@ export declare const findEffectCallExpression: ({ attr, effectIndex, }: {
33
38
  kind: "error";
34
39
  reason: "not-call-expression" | "not-found";
35
40
  };
36
- export declare const updateEffectPropsAst: ({ input, sequenceNodePath, effectIndex, update, }: {
41
+ export declare const updateEffectPropsAst: ({ input, sequenceNodePath, effectIndex, update, schema, }: {
37
42
  input: string;
38
43
  sequenceNodePath: SequenceNodePath;
39
44
  effectIndex: number;
40
45
  update: EffectPropUpdate;
46
+ schema: SequenceSchema;
41
47
  }) => {
42
48
  serialized: string;
43
49
  oldValueString: string;
44
50
  logLine: number;
45
51
  effectCallee: string;
52
+ removedProps: PropDelta[];
46
53
  };
47
- export declare const updateEffectProps: ({ input, sequenceNodePath, effectIndex, update, prettierConfigOverride, }: {
54
+ export declare const updateEffectProps: ({ input, sequenceNodePath, effectIndex, update, schema, prettierConfigOverride, }: {
48
55
  input: string;
49
56
  sequenceNodePath: SequenceNodePath;
50
57
  effectIndex: number;
51
58
  update: EffectPropUpdate;
59
+ schema: SequenceSchema;
52
60
  prettierConfigOverride?: Record<string, unknown> | null | undefined;
53
61
  }) => Promise<UpdateEffectPropsResult>;
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.updateEffectProps = exports.updateEffectPropsAst = exports.findEffectCallExpression = exports.enumerateEffectArrayElements = exports.findEffectsAttr = void 0;
37
37
  const studio_shared_1 = require("@remotion/studio-shared");
38
38
  const recast = __importStar(require("recast"));
39
+ const no_react_1 = require("remotion/no-react");
39
40
  const can_update_sequence_props_1 = require("../../preview-server/routes/can-update-sequence-props");
40
41
  const format_file_content_1 = require("../format-file-content");
41
42
  const parse_ast_1 = require("../parse-ast");
@@ -132,7 +133,24 @@ const findObjectProperty = (objExpr, propertyName) => {
132
133
  : undefined,
133
134
  };
134
135
  };
135
- const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, }) => {
136
+ const printObjectPropertyValue = (prop) => recast
137
+ .print(prop.value)
138
+ .code.replace(/[\n\r\t]+/g, ' ')
139
+ .replace(/,(\s*[}\]])/g, '$1')
140
+ .trim();
141
+ const removeObjectProperty = ({ objExpr, propertyName, }) => {
142
+ const { propIndex, prop } = findObjectProperty(objExpr, propertyName);
143
+ if (!prop || propIndex === -1) {
144
+ return null;
145
+ }
146
+ const valueString = printObjectPropertyValue(prop);
147
+ objExpr.properties.splice(propIndex, 1);
148
+ return {
149
+ key: propertyName,
150
+ valueString,
151
+ };
152
+ };
153
+ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, schema, }) => {
136
154
  var _a, _b, _c, _d;
137
155
  var _e, _f, _g, _h, _j;
138
156
  const ast = (0, parse_ast_1.parseAst)(input);
@@ -162,6 +180,7 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
162
180
  oldValueString: '',
163
181
  logLine: (_g = (_f = (_a = call.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _f !== void 0 ? _f : (_b = jsx.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _g !== void 0 ? _g : 1,
164
182
  effectCallee,
183
+ removedProps: [],
165
184
  };
166
185
  }
167
186
  objExpr = b.objectExpression([]);
@@ -174,6 +193,7 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
174
193
  objExpr = call.arguments[0];
175
194
  }
176
195
  const { prop } = findObjectProperty(objExpr, update.key);
196
+ const removedProps = [];
177
197
  let oldValueString = '';
178
198
  if (prop) {
179
199
  oldValueString = recast.print(prop.value).code;
@@ -198,21 +218,40 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
198
218
  objExpr.properties.push(b.objectProperty(b.identifier(update.key), newValueExpr));
199
219
  }
200
220
  }
221
+ const fieldSchema = schema[update.key];
222
+ if (fieldSchema && fieldSchema.type === 'enum') {
223
+ const propsToDelete = no_react_1.NoReactInternals.findPropsToDelete({
224
+ schema,
225
+ key: update.key,
226
+ value: update.value,
227
+ });
228
+ for (const propToDelete of propsToDelete) {
229
+ const removed = removeObjectProperty({
230
+ objExpr,
231
+ propertyName: propToDelete,
232
+ });
233
+ if (removed) {
234
+ removedProps.push(removed);
235
+ }
236
+ }
237
+ }
201
238
  const logLine = (_j = (_h = (_c = call.loc) === null || _c === void 0 ? void 0 : _c.start.line) !== null && _h !== void 0 ? _h : (_d = jsx.loc) === null || _d === void 0 ? void 0 : _d.start.line) !== null && _j !== void 0 ? _j : 1;
202
239
  return {
203
240
  serialized: (0, parse_ast_1.serializeAst)(ast),
204
241
  oldValueString,
205
242
  logLine,
206
243
  effectCallee,
244
+ removedProps,
207
245
  };
208
246
  };
209
247
  exports.updateEffectPropsAst = updateEffectPropsAst;
210
- const updateEffectProps = async ({ input, sequenceNodePath, effectIndex, update, prettierConfigOverride, }) => {
211
- const { serialized, oldValueString, logLine, effectCallee } = (0, exports.updateEffectPropsAst)({
248
+ const updateEffectProps = async ({ input, sequenceNodePath, effectIndex, update, schema, prettierConfigOverride, }) => {
249
+ const { serialized, oldValueString, logLine, effectCallee, removedProps } = (0, exports.updateEffectPropsAst)({
212
250
  input,
213
251
  sequenceNodePath,
214
252
  effectIndex,
215
253
  update,
254
+ schema,
216
255
  });
217
256
  const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
218
257
  input: serialized,
@@ -224,6 +263,7 @@ const updateEffectProps = async ({ input, sequenceNodePath, effectIndex, update,
224
263
  formatted,
225
264
  logLine,
226
265
  effectCallee,
266
+ removedProps,
227
267
  };
228
268
  };
229
269
  exports.updateEffectProps = updateEffectProps;
@@ -0,0 +1,11 @@
1
+ export type ResolvedCompositionComponent = {
2
+ source: string;
3
+ line: number;
4
+ column: number;
5
+ canAddSequence: boolean;
6
+ };
7
+ export declare const resolveCompositionComponent: ({ remotionRoot, compositionFile, compositionId, }: {
8
+ remotionRoot: string;
9
+ compositionFile: string;
10
+ compositionId: string;
11
+ }) => Promise<ResolvedCompositionComponent>;
@@ -0,0 +1,691 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.resolveCompositionComponent = void 0;
40
+ const node_fs_1 = __importDefault(require("node:fs"));
41
+ const node_path_1 = __importDefault(require("node:path"));
42
+ const recast = __importStar(require("recast"));
43
+ const parse_ast_1 = require("../codemods/parse-ast");
44
+ const allowedFileExtensions = new Set(['.tsx', '.ts', '.jsx', '.js']);
45
+ const extensionsToProbe = ['.tsx', '.ts', '.jsx', '.js'];
46
+ const isInRemotionRoot = ({ remotionRoot, fileName, }) => {
47
+ const relativePath = node_path_1.default.relative(remotionRoot, fileName);
48
+ return !relativePath.startsWith('..') && !node_path_1.default.isAbsolute(relativePath);
49
+ };
50
+ const readSourceFile = ({ remotionRoot, fileName, }) => {
51
+ const resolved = node_path_1.default.resolve(remotionRoot, fileName);
52
+ if (!isInRemotionRoot({ remotionRoot, fileName: resolved })) {
53
+ throw new Error(`Not allowed to open ${fileName}`);
54
+ }
55
+ if (!allowedFileExtensions.has(node_path_1.default.extname(resolved))) {
56
+ throw new Error(`Not allowed to open ${fileName}`);
57
+ }
58
+ return node_fs_1.default.promises.readFile(resolved, 'utf-8');
59
+ };
60
+ const getAttributeName = (attribute) => {
61
+ if (attribute.name.type !== 'JSXIdentifier') {
62
+ return null;
63
+ }
64
+ return attribute.name.name;
65
+ };
66
+ const findAttribute = (element, name) => {
67
+ return element.openingElement.attributes.find((attribute) => {
68
+ if (attribute.type !== 'JSXAttribute') {
69
+ return false;
70
+ }
71
+ return getAttributeName(attribute) === name;
72
+ });
73
+ };
74
+ const getStringAttributeValue = (element, name) => {
75
+ const attribute = findAttribute(element, name);
76
+ if (!(attribute === null || attribute === void 0 ? void 0 : attribute.value)) {
77
+ return null;
78
+ }
79
+ if (attribute.value.type === 'StringLiteral') {
80
+ return attribute.value.value;
81
+ }
82
+ if (attribute.value.type === 'JSXExpressionContainer' &&
83
+ attribute.value.expression.type === 'StringLiteral') {
84
+ return attribute.value.expression.value;
85
+ }
86
+ return null;
87
+ };
88
+ const findCompositionElement = ({ ast, compositionId, }) => {
89
+ let found = null;
90
+ recast.types.visit(ast, {
91
+ visitJSXElement(astPath) {
92
+ if (found) {
93
+ return false;
94
+ }
95
+ const node = astPath.node;
96
+ const openingName = node.openingElement.name;
97
+ if (openingName.type === 'JSXIdentifier' &&
98
+ (openingName.name === 'Composition' || openingName.name === 'Still') &&
99
+ getStringAttributeValue(node, 'id') === compositionId) {
100
+ found = node;
101
+ return false;
102
+ }
103
+ this.traverse(astPath);
104
+ return undefined;
105
+ },
106
+ });
107
+ return found;
108
+ };
109
+ const getComponentIdentifier = (element) => {
110
+ const attribute = findAttribute(element, 'component');
111
+ if (!(attribute === null || attribute === void 0 ? void 0 : attribute.value) ||
112
+ attribute.value.type !== 'JSXExpressionContainer' ||
113
+ attribute.value.expression.type !== 'Identifier') {
114
+ return null;
115
+ }
116
+ return attribute.value.expression.name;
117
+ };
118
+ const isRecord = (value) => {
119
+ return typeof value === 'object' && value !== null;
120
+ };
121
+ const findDynamicImportPath = (value) => {
122
+ if (!isRecord(value)) {
123
+ return null;
124
+ }
125
+ if (value.type === 'CallExpression' &&
126
+ isRecord(value.callee) &&
127
+ value.callee.type === 'Import' &&
128
+ Array.isArray(value.arguments) &&
129
+ isRecord(value.arguments[0]) &&
130
+ value.arguments[0].type === 'StringLiteral' &&
131
+ typeof value.arguments[0].value === 'string') {
132
+ return value.arguments[0].value;
133
+ }
134
+ for (const [key, child] of Object.entries(value)) {
135
+ if (key === 'loc' ||
136
+ key === 'start' ||
137
+ key === 'end' ||
138
+ key === 'comments' ||
139
+ key === 'leadingComments' ||
140
+ key === 'trailingComments' ||
141
+ key === 'innerComments' ||
142
+ key === 'extra' ||
143
+ key === 'original') {
144
+ continue;
145
+ }
146
+ if (Array.isArray(child)) {
147
+ for (const item of child) {
148
+ const nestedResult = findDynamicImportPath(item);
149
+ if (nestedResult) {
150
+ return nestedResult;
151
+ }
152
+ }
153
+ continue;
154
+ }
155
+ const childResult = findDynamicImportPath(child);
156
+ if (childResult) {
157
+ return childResult;
158
+ }
159
+ }
160
+ return null;
161
+ };
162
+ const getLazyImportPath = (element) => {
163
+ const attribute = findAttribute(element, 'lazyComponent');
164
+ if (!(attribute === null || attribute === void 0 ? void 0 : attribute.value) || attribute.value.type !== 'JSXExpressionContainer') {
165
+ return null;
166
+ }
167
+ return findDynamicImportPath(attribute.value.expression);
168
+ };
169
+ const findImportTarget = ({ ast, componentName, }) => {
170
+ let found = null;
171
+ recast.types.visit(ast, {
172
+ visitImportDeclaration(astPath) {
173
+ var _a;
174
+ if (found) {
175
+ return false;
176
+ }
177
+ const node = astPath.node;
178
+ if (typeof node.source.value !== 'string') {
179
+ return false;
180
+ }
181
+ const matchingSpecifier = (_a = node.specifiers) === null || _a === void 0 ? void 0 : _a.find((specifier) => {
182
+ var _a;
183
+ return ((_a = specifier.local) === null || _a === void 0 ? void 0 : _a.name) === componentName;
184
+ });
185
+ if (!matchingSpecifier) {
186
+ return false;
187
+ }
188
+ if (matchingSpecifier.type === 'ImportDefaultSpecifier') {
189
+ found = {
190
+ importPath: node.source.value,
191
+ exportName: 'default',
192
+ };
193
+ return false;
194
+ }
195
+ if (matchingSpecifier.type === 'ImportSpecifier' &&
196
+ matchingSpecifier.imported.type === 'Identifier') {
197
+ found = {
198
+ importPath: node.source.value,
199
+ exportName: matchingSpecifier.imported.name,
200
+ };
201
+ return false;
202
+ }
203
+ if (matchingSpecifier.type === 'ImportSpecifier' &&
204
+ matchingSpecifier.imported.type === 'StringLiteral') {
205
+ found = {
206
+ importPath: node.source.value,
207
+ exportName: matchingSpecifier.imported.value,
208
+ };
209
+ return false;
210
+ }
211
+ return false;
212
+ },
213
+ });
214
+ return found;
215
+ };
216
+ const getExportedName = (exported) => {
217
+ if (!exported) {
218
+ return null;
219
+ }
220
+ if (!isRecord(exported)) {
221
+ return null;
222
+ }
223
+ if (exported.type === 'Identifier' && typeof exported.name === 'string') {
224
+ return exported.name;
225
+ }
226
+ if (exported.type === 'StringLiteral' && typeof exported.value === 'string') {
227
+ return exported.value;
228
+ }
229
+ return null;
230
+ };
231
+ const getSpecifierLocalName = (specifier) => {
232
+ if (specifier.local.type === 'Identifier') {
233
+ return specifier.local.name;
234
+ }
235
+ return null;
236
+ };
237
+ const findReExportTargets = ({ ast, exportName, }) => {
238
+ const targets = [];
239
+ recast.types.visit(ast, {
240
+ visitExportNamedDeclaration(astPath) {
241
+ var _a;
242
+ const node = astPath.node;
243
+ if (typeof ((_a = node.source) === null || _a === void 0 ? void 0 : _a.value) !== 'string') {
244
+ return false;
245
+ }
246
+ for (const specifier of node.specifiers) {
247
+ if (specifier.type !== 'ExportSpecifier') {
248
+ continue;
249
+ }
250
+ const exportedName = getExportedName(specifier.exported);
251
+ if (exportedName !== exportName) {
252
+ continue;
253
+ }
254
+ const localName = getSpecifierLocalName(specifier);
255
+ if (!localName) {
256
+ continue;
257
+ }
258
+ targets.push({
259
+ importPath: node.source.value,
260
+ exportName: localName === 'default' ? 'default' : localName,
261
+ });
262
+ }
263
+ return false;
264
+ },
265
+ visitExportAllDeclaration(astPath) {
266
+ const node = astPath.node;
267
+ if (typeof node.source.value !== 'string') {
268
+ return false;
269
+ }
270
+ targets.push({
271
+ importPath: node.source.value,
272
+ exportName,
273
+ });
274
+ return false;
275
+ },
276
+ });
277
+ return targets;
278
+ };
279
+ const resolveImportPath = ({ importPath, fromFile, }) => {
280
+ if (!importPath.startsWith('.')) {
281
+ throw new Error(`Cannot resolve non-relative import ${importPath}`);
282
+ }
283
+ const basePath = node_path_1.default.resolve(node_path_1.default.dirname(fromFile), importPath);
284
+ const candidates = node_path_1.default.extname(basePath)
285
+ ? [basePath]
286
+ : [
287
+ ...extensionsToProbe.map((extension) => `${basePath}${extension}`),
288
+ ...extensionsToProbe.map((extension) => node_path_1.default.join(basePath, `index${extension}`)),
289
+ ];
290
+ const existingFile = candidates.find((candidate) => {
291
+ return node_fs_1.default.existsSync(candidate) && node_fs_1.default.statSync(candidate).isFile();
292
+ });
293
+ if (!existingFile) {
294
+ throw new Error(`Could not find imported component file ${importPath}`);
295
+ }
296
+ return existingFile;
297
+ };
298
+ const locationFromNode = (node) => {
299
+ if (!node.loc) {
300
+ return null;
301
+ }
302
+ return {
303
+ line: node.loc.start.line,
304
+ column: node.loc.start.column,
305
+ };
306
+ };
307
+ const findLocalSymbolLocation = ({ ast, name, }) => {
308
+ let location = null;
309
+ recast.types.visit(ast, {
310
+ visitVariableDeclarator(astPath) {
311
+ if (location) {
312
+ return false;
313
+ }
314
+ const { node } = astPath;
315
+ if (node.id.type === 'Identifier' && node.id.name === name) {
316
+ location = locationFromNode(node);
317
+ return false;
318
+ }
319
+ this.traverse(astPath);
320
+ return undefined;
321
+ },
322
+ visitFunctionDeclaration(astPath) {
323
+ var _a;
324
+ if (location) {
325
+ return false;
326
+ }
327
+ const { node } = astPath;
328
+ if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
329
+ location = locationFromNode(node);
330
+ return false;
331
+ }
332
+ this.traverse(astPath);
333
+ return undefined;
334
+ },
335
+ visitClassDeclaration(astPath) {
336
+ var _a;
337
+ if (location) {
338
+ return false;
339
+ }
340
+ const { node } = astPath;
341
+ if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
342
+ location = locationFromNode(node);
343
+ return false;
344
+ }
345
+ this.traverse(astPath);
346
+ return undefined;
347
+ },
348
+ });
349
+ return location;
350
+ };
351
+ const findDefaultExportLocation = (ast) => {
352
+ let location = null;
353
+ let exportedIdentifier = null;
354
+ recast.types.visit(ast, {
355
+ visitExportDefaultDeclaration(astPath) {
356
+ var _a;
357
+ if (location || exportedIdentifier) {
358
+ return false;
359
+ }
360
+ const { node } = astPath;
361
+ if (node.declaration.type === 'Identifier') {
362
+ exportedIdentifier = node.declaration.name;
363
+ return false;
364
+ }
365
+ location = (_a = locationFromNode(node.declaration)) !== null && _a !== void 0 ? _a : locationFromNode(node);
366
+ return false;
367
+ },
368
+ });
369
+ if (exportedIdentifier) {
370
+ return findLocalSymbolLocation({ ast, name: exportedIdentifier });
371
+ }
372
+ return location;
373
+ };
374
+ const findLocalComponentDeclaration = ({ ast, name, }) => {
375
+ let declaration = null;
376
+ recast.types.visit(ast, {
377
+ visitVariableDeclarator(astPath) {
378
+ if (declaration) {
379
+ return false;
380
+ }
381
+ const { node } = astPath;
382
+ if (node.id.type === 'Identifier' && node.id.name === name) {
383
+ declaration = node;
384
+ return false;
385
+ }
386
+ this.traverse(astPath);
387
+ return undefined;
388
+ },
389
+ visitFunctionDeclaration(astPath) {
390
+ var _a;
391
+ if (declaration) {
392
+ return false;
393
+ }
394
+ const { node } = astPath;
395
+ if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
396
+ declaration = node;
397
+ return false;
398
+ }
399
+ this.traverse(astPath);
400
+ return undefined;
401
+ },
402
+ visitClassDeclaration(astPath) {
403
+ var _a;
404
+ if (declaration) {
405
+ return false;
406
+ }
407
+ const { node } = astPath;
408
+ if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.name) === name) {
409
+ declaration = node;
410
+ return false;
411
+ }
412
+ this.traverse(astPath);
413
+ return undefined;
414
+ },
415
+ });
416
+ return declaration;
417
+ };
418
+ const getTopLevelReturnStatement = (statements) => {
419
+ const returnStatements = [];
420
+ for (const statement of statements) {
421
+ if (recast.types.namedTypes.ReturnStatement.check(statement)) {
422
+ returnStatements.push(statement);
423
+ }
424
+ }
425
+ if (returnStatements.length !== 1) {
426
+ return null;
427
+ }
428
+ const singleReturn = returnStatements[0];
429
+ const finalStatement = statements.at(-1);
430
+ if (singleReturn !== finalStatement) {
431
+ return null;
432
+ }
433
+ return singleReturn;
434
+ };
435
+ const getReturnedJsxFromFunction = (fn) => {
436
+ if (fn.type === 'ArrowFunctionExpression') {
437
+ if (fn.body.type === 'JSXElement' || fn.body.type === 'JSXFragment') {
438
+ return fn.body;
439
+ }
440
+ if (fn.body.type !== 'BlockStatement') {
441
+ return null;
442
+ }
443
+ const arrowReturnStatement = getTopLevelReturnStatement(fn.body.body);
444
+ if (!(arrowReturnStatement === null || arrowReturnStatement === void 0 ? void 0 : arrowReturnStatement.argument)) {
445
+ return null;
446
+ }
447
+ return arrowReturnStatement.argument.type === 'JSXElement' ||
448
+ arrowReturnStatement.argument.type === 'JSXFragment'
449
+ ? arrowReturnStatement.argument
450
+ : null;
451
+ }
452
+ if (fn.body.type !== 'BlockStatement') {
453
+ return null;
454
+ }
455
+ const returnStatement = getTopLevelReturnStatement(fn.body.body);
456
+ if (!(returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.argument)) {
457
+ return null;
458
+ }
459
+ return returnStatement.argument.type === 'JSXElement' ||
460
+ returnStatement.argument.type === 'JSXFragment'
461
+ ? returnStatement.argument
462
+ : null;
463
+ };
464
+ const findRenderMethod = (declaration) => {
465
+ const renderMethod = declaration.body.body.find((member) => {
466
+ return (member.type === 'ClassMethod' &&
467
+ member.kind === 'method' &&
468
+ member.key.type === 'Identifier' &&
469
+ member.key.name === 'render');
470
+ });
471
+ return (renderMethod === null || renderMethod === void 0 ? void 0 : renderMethod.type) === 'ClassMethod' ? renderMethod : null;
472
+ };
473
+ const getComponentRootNode = (declaration) => {
474
+ if (declaration.type === 'VariableDeclarator') {
475
+ if (!declaration.init ||
476
+ (declaration.init.type !== 'ArrowFunctionExpression' &&
477
+ declaration.init.type !== 'FunctionExpression')) {
478
+ return null;
479
+ }
480
+ return getReturnedJsxFromFunction(declaration.init);
481
+ }
482
+ if (declaration.type === 'ArrowFunctionExpression' ||
483
+ declaration.type === 'FunctionExpression' ||
484
+ declaration.type === 'FunctionDeclaration') {
485
+ return getReturnedJsxFromFunction(declaration);
486
+ }
487
+ if (declaration.type !== 'ClassDeclaration') {
488
+ return null;
489
+ }
490
+ const renderMethod = findRenderMethod(declaration);
491
+ if (!renderMethod) {
492
+ return null;
493
+ }
494
+ const returnStatement = getTopLevelReturnStatement(renderMethod.body.body);
495
+ if (!(returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.argument)) {
496
+ return null;
497
+ }
498
+ return returnStatement.argument.type === 'JSXElement' ||
499
+ returnStatement.argument.type === 'JSXFragment'
500
+ ? returnStatement.argument
501
+ : null;
502
+ };
503
+ const createSequenceElement = () => {
504
+ return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier('Sequence'), []), recast.types.builders.jsxClosingElement(recast.types.builders.jsxIdentifier('Sequence')), []);
505
+ };
506
+ const getDefaultExportDeclaration = (ast) => {
507
+ let declaration = null;
508
+ let identifierName = null;
509
+ recast.types.visit(ast, {
510
+ visitExportDefaultDeclaration(astPath) {
511
+ if (declaration || identifierName) {
512
+ return false;
513
+ }
514
+ const { node } = astPath;
515
+ if (node.declaration.type === 'Identifier') {
516
+ identifierName = node.declaration.name;
517
+ return false;
518
+ }
519
+ declaration = node.declaration;
520
+ return false;
521
+ },
522
+ });
523
+ if (identifierName) {
524
+ return findLocalComponentDeclaration({ ast, name: identifierName });
525
+ }
526
+ return declaration;
527
+ };
528
+ const getDeclarationByExportName = ({ ast, exportName, }) => {
529
+ if (exportName === 'default') {
530
+ return getDefaultExportDeclaration(ast);
531
+ }
532
+ return findLocalComponentDeclaration({ ast, name: exportName });
533
+ };
534
+ const canAddSequenceToComponent = ({ ast, exportName, }) => {
535
+ const declaration = getDeclarationByExportName({ ast, exportName });
536
+ if (!declaration) {
537
+ return false;
538
+ }
539
+ const rootNode = getComponentRootNode(declaration);
540
+ if (!rootNode) {
541
+ return false;
542
+ }
543
+ if (rootNode.type === 'JSXElement') {
544
+ if (rootNode.openingElement.selfClosing) {
545
+ return false;
546
+ }
547
+ if (!rootNode.children) {
548
+ return false;
549
+ }
550
+ rootNode.children.push(createSequenceElement());
551
+ try {
552
+ recast.print(ast);
553
+ return true;
554
+ }
555
+ catch (_a) {
556
+ return false;
557
+ }
558
+ }
559
+ if (!rootNode.children) {
560
+ return false;
561
+ }
562
+ rootNode.children.push(createSequenceElement());
563
+ try {
564
+ recast.print(ast);
565
+ return true;
566
+ }
567
+ catch (_b) {
568
+ return false;
569
+ }
570
+ };
571
+ const getComponentLocationInFile = async ({ remotionRoot, fileName, exportName, }) => {
572
+ var _a, _b;
573
+ const input = await readSourceFile({ remotionRoot, fileName });
574
+ const ast = (0, parse_ast_1.parseAst)(input);
575
+ const astForSequenceSimulation = (0, parse_ast_1.parseAst)(input);
576
+ const location = exportName === 'default'
577
+ ? findDefaultExportLocation(ast)
578
+ : findLocalSymbolLocation({ ast, name: exportName });
579
+ const canAddSequence = canAddSequenceToComponent({
580
+ ast: astForSequenceSimulation,
581
+ exportName,
582
+ });
583
+ return {
584
+ source: node_path_1.default.relative(remotionRoot, fileName),
585
+ line: (_a = location === null || location === void 0 ? void 0 : location.line) !== null && _a !== void 0 ? _a : 1,
586
+ column: (_b = location === null || location === void 0 ? void 0 : location.column) !== null && _b !== void 0 ? _b : 0,
587
+ canAddSequence,
588
+ };
589
+ };
590
+ const getComponentLocationRecursively = async ({ remotionRoot, fileName, exportName, visited, }) => {
591
+ const key = `${fileName}:${exportName}`;
592
+ if (visited.has(key)) {
593
+ throw new Error(`Could not resolve component export "${exportName}" in ${node_path_1.default.relative(remotionRoot, fileName)}`);
594
+ }
595
+ visited.add(key);
596
+ try {
597
+ const input = await readSourceFile({ remotionRoot, fileName });
598
+ const ast = (0, parse_ast_1.parseAst)(input);
599
+ const localDeclaration = getDeclarationByExportName({
600
+ ast,
601
+ exportName,
602
+ });
603
+ if (localDeclaration) {
604
+ return await getComponentLocationInFile({
605
+ remotionRoot,
606
+ fileName,
607
+ exportName,
608
+ });
609
+ }
610
+ const reExportTargets = findReExportTargets({
611
+ ast,
612
+ exportName,
613
+ });
614
+ for (const target of reExportTargets) {
615
+ try {
616
+ const resolvedImportPath = resolveImportPath({
617
+ importPath: target.importPath,
618
+ fromFile: fileName,
619
+ });
620
+ return await getComponentLocationRecursively({
621
+ remotionRoot,
622
+ fileName: resolvedImportPath,
623
+ exportName: target.exportName,
624
+ visited,
625
+ });
626
+ }
627
+ catch (_a) {
628
+ continue;
629
+ }
630
+ }
631
+ if (reExportTargets.length > 0) {
632
+ throw new Error(`Could not resolve component export "${exportName}" in ${node_path_1.default.relative(remotionRoot, fileName)}`);
633
+ }
634
+ return await getComponentLocationInFile({
635
+ remotionRoot,
636
+ fileName,
637
+ exportName,
638
+ });
639
+ }
640
+ finally {
641
+ visited.delete(key);
642
+ }
643
+ };
644
+ const resolveCompositionComponent = async ({ remotionRoot, compositionFile, compositionId, }) => {
645
+ const compositionFileName = node_path_1.default.resolve(remotionRoot, compositionFile);
646
+ const input = await readSourceFile({
647
+ remotionRoot,
648
+ fileName: compositionFileName,
649
+ });
650
+ const ast = (0, parse_ast_1.parseAst)(input);
651
+ const compositionElement = findCompositionElement({ ast, compositionId });
652
+ if (!compositionElement) {
653
+ throw new Error(`Could not find composition "${compositionId}"`);
654
+ }
655
+ const lazyImportPath = getLazyImportPath(compositionElement);
656
+ if (lazyImportPath) {
657
+ const lazyComponentFile = resolveImportPath({
658
+ importPath: lazyImportPath,
659
+ fromFile: compositionFileName,
660
+ });
661
+ return getComponentLocationRecursively({
662
+ remotionRoot,
663
+ fileName: lazyComponentFile,
664
+ exportName: 'default',
665
+ visited: new Set(),
666
+ });
667
+ }
668
+ const componentName = getComponentIdentifier(compositionElement);
669
+ if (!componentName) {
670
+ throw new Error(`Could not find a component prop for composition "${compositionId}"`);
671
+ }
672
+ const importTarget = findImportTarget({ ast, componentName });
673
+ if (!importTarget) {
674
+ return getComponentLocationInFile({
675
+ remotionRoot,
676
+ fileName: compositionFileName,
677
+ exportName: componentName,
678
+ });
679
+ }
680
+ const importedComponentFile = resolveImportPath({
681
+ importPath: importTarget.importPath,
682
+ fromFile: compositionFileName,
683
+ });
684
+ return getComponentLocationRecursively({
685
+ remotionRoot,
686
+ fileName: importedComponentFile,
687
+ exportName: importTarget.exportName,
688
+ visited: new Set(),
689
+ });
690
+ };
691
+ exports.resolveCompositionComponent = resolveCompositionComponent;
@@ -26,6 +26,7 @@ const handleAddRender = ({ input, entryPoint, remotionRoot, logLevel, binariesDi
26
26
  cancelToken: (0, renderer_1.makeCancelSignal)(),
27
27
  concurrency: input.concurrency,
28
28
  crf: input.crf,
29
+ gopSize: input.gopSize,
29
30
  endFrame: input.endFrame,
30
31
  startFrame: input.startFrame,
31
32
  muted: input.muted,
@@ -43,7 +43,7 @@ const getPropsFromObjectExpression = ({ objExpr, keys, }) => {
43
43
  }
44
44
  const valueExpr = prop.value;
45
45
  if (!(0, can_update_sequence_props_1.isStaticValue)(valueExpr)) {
46
- out[key] = { canUpdate: false, reason: 'computed' };
46
+ out[key] = (0, can_update_sequence_props_1.getComputedStatus)(valueExpr);
47
47
  continue;
48
48
  }
49
49
  out[key] = {
@@ -1,10 +1,9 @@
1
1
  import type { Expression, File, JSXOpeningElement } from '@babel/types';
2
2
  import type { SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
3
- import type { CanUpdateSequencePropsResponseTrue } from 'remotion';
4
- import type { SequenceNodePath } from 'remotion';
5
- import type { CanUpdateSequencePropStatus } from 'remotion';
3
+ import type { CanUpdateSequencePropsResponseTrue, CanUpdateSequencePropStatus, SequenceNodePath } from 'remotion';
6
4
  export declare const isStaticValue: (node: Expression) => boolean;
7
5
  export declare const extractStaticValue: (node: Expression) => unknown;
6
+ export declare const getComputedStatus: (node: Expression) => CanUpdateSequencePropStatus;
8
7
  export declare const findJsxElementAtNodePath: (ast: File, nodePath: SequenceNodePath) => JSXOpeningElement | null;
9
8
  export declare const lineColumnToNodePath: (ast: File, targetLine: number) => SequenceNodePath | null;
10
9
  export declare const computeSequencePropsOnlyStatus: ({ fileName, nodePath, keys, remotionRoot, }: {
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.computeSequencePropsStatusFromFilenameByLine = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.computeSequencePropsOnlyStatus = exports.lineColumnToNodePath = exports.findJsxElementAtNodePath = exports.extractStaticValue = exports.isStaticValue = void 0;
39
+ exports.computeSequencePropsStatusFromFilenameByLine = exports.computeSequencePropsStatus = exports.computeSequencePropsStatusFromContent = exports.computeSequencePropsOnlyStatus = exports.lineColumnToNodePath = exports.findJsxElementAtNodePath = exports.getComputedStatus = exports.extractStaticValue = exports.isStaticValue = void 0;
40
40
  const node_fs_1 = require("node:fs");
41
41
  const node_path_1 = __importDefault(require("node:path"));
42
42
  const renderer_1 = require("@remotion/renderer");
@@ -117,6 +117,76 @@ const extractStaticValue = (node) => {
117
117
  }
118
118
  };
119
119
  exports.extractStaticValue = extractStaticValue;
120
+ const getNumericValue = (node) => {
121
+ if (node.type === 'NumericLiteral') {
122
+ return node.value;
123
+ }
124
+ if (node.type === 'UnaryExpression' &&
125
+ (node.operator === '-' || node.operator === '+') &&
126
+ node.argument.type === 'NumericLiteral') {
127
+ return node.operator === '-' ? -node.argument.value : node.argument.value;
128
+ }
129
+ if (node.type === 'TSAsExpression') {
130
+ return getNumericValue(node.expression);
131
+ }
132
+ return null;
133
+ };
134
+ const getInterpolateKeyframes = (node) => {
135
+ if (node.type === 'TSAsExpression') {
136
+ return getInterpolateKeyframes(node.expression);
137
+ }
138
+ if (node.type !== 'CallExpression') {
139
+ return undefined;
140
+ }
141
+ const callExpression = node;
142
+ if (callExpression.callee.type !== 'Identifier' ||
143
+ callExpression.callee.name !== 'interpolate') {
144
+ return undefined;
145
+ }
146
+ const inputArg = callExpression.arguments[1];
147
+ const outputArg = callExpression.arguments[2];
148
+ if (!inputArg ||
149
+ !outputArg ||
150
+ inputArg.type !== 'ArrayExpression' ||
151
+ outputArg.type !== 'ArrayExpression') {
152
+ return undefined;
153
+ }
154
+ if (inputArg.elements.length !== outputArg.elements.length) {
155
+ return undefined;
156
+ }
157
+ const keyframes = [];
158
+ for (let i = 0; i < inputArg.elements.length; i++) {
159
+ const inputElement = inputArg.elements[i];
160
+ const outputElement = outputArg.elements[i];
161
+ if (!inputElement ||
162
+ !outputElement ||
163
+ inputElement.type === 'SpreadElement' ||
164
+ outputElement.type === 'SpreadElement') {
165
+ return undefined;
166
+ }
167
+ const frame = getNumericValue(inputElement);
168
+ if (frame === null || !(0, exports.isStaticValue)(outputElement)) {
169
+ return undefined;
170
+ }
171
+ keyframes.push({
172
+ frame,
173
+ value: (0, exports.extractStaticValue)(outputElement),
174
+ });
175
+ }
176
+ return keyframes.length > 0 ? keyframes : undefined;
177
+ };
178
+ const getComputedStatus = (node) => {
179
+ const keyframes = getInterpolateKeyframes(node);
180
+ if (!keyframes) {
181
+ return { canUpdate: false, reason: 'computed' };
182
+ }
183
+ return {
184
+ canUpdate: false,
185
+ reason: 'computed',
186
+ keyframes,
187
+ };
188
+ };
189
+ exports.getComputedStatus = getComputedStatus;
120
190
  const getPropsStatus = (jsxElement) => {
121
191
  const props = {};
122
192
  for (const attr of jsxElement.attributes) {
@@ -144,11 +214,14 @@ const getPropsStatus = (jsxElement) => {
144
214
  }
145
215
  if (value.type === 'JSXExpressionContainer') {
146
216
  const { expression } = value;
147
- if (expression.type === 'JSXEmptyExpression' ||
148
- !(0, exports.isStaticValue)(expression)) {
217
+ if (expression.type === 'JSXEmptyExpression') {
149
218
  props[name] = { canUpdate: false, reason: 'computed' };
150
219
  continue;
151
220
  }
221
+ if (!(0, exports.isStaticValue)(expression)) {
222
+ props[name] = (0, exports.getComputedStatus)(expression);
223
+ continue;
224
+ }
152
225
  props[name] = {
153
226
  canUpdate: true,
154
227
  codeValue: (0, exports.extractStaticValue)(expression),
@@ -242,7 +315,7 @@ const getNestedPropStatus = (jsxElement, parentKey, childKey) => {
242
315
  }
243
316
  const propValue = prop.value;
244
317
  if (!(0, exports.isStaticValue)(propValue)) {
245
- return { canUpdate: false, reason: 'computed' };
318
+ return (0, exports.getComputedStatus)(propValue);
246
319
  }
247
320
  const codeValue = (0, exports.extractStaticValue)(propValue);
248
321
  if (!validateStyleValue(childKey, codeValue)) {
@@ -27,7 +27,9 @@ const attrName = (str) => (0, exports.fg)(166, 226, 46, str);
27
27
  exports.attrName = attrName;
28
28
  const equals = (str) => (0, exports.fg)(249, 38, 114, str);
29
29
  exports.equals = equals;
30
- const punctuation = (str) => (0, exports.fg)(248, 248, 242, str);
30
+ // Use the terminal's default foreground color so punctuation is visible in both
31
+ // light and dark terminal themes.
32
+ const punctuation = (str) => str;
31
33
  exports.punctuation = punctuation;
32
34
  const stringValue = (str) => (0, exports.fg)(230, 219, 116, str);
33
35
  exports.stringValue = stringValue;
@@ -28,7 +28,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
28
28
  }
29
29
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
30
30
  const parsedDefault = defaultValue !== null ? JSON.parse(defaultValue) : null;
31
- const { output, oldValueString, formatted, logLine, effectCallee } = await (0, update_effect_props_1.updateEffectProps)({
31
+ const { output, oldValueString, formatted, logLine, effectCallee, removedProps, } = await (0, update_effect_props_1.updateEffectProps)({
32
32
  input: fileContents,
33
33
  sequenceNodePath: sequenceNodePath.nodePath,
34
34
  effectIndex,
@@ -37,11 +37,16 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
37
37
  value: JSON.parse(value),
38
38
  defaultValue: parsedDefault,
39
39
  },
40
+ schema,
40
41
  });
41
42
  const defaultValueString = parsedDefault !== null ? JSON.stringify(parsedDefault) : null;
42
43
  const normalizedOld = (0, log_update_1.normalizeQuotes)(oldValueString);
43
44
  const normalizedNew = (0, log_update_1.normalizeQuotes)(value);
44
45
  const normalizedDefault = defaultValueString !== null ? (0, log_update_1.normalizeQuotes)(defaultValueString) : null;
46
+ const normalizedRemovedProps = removedProps.map((prop) => ({
47
+ ...prop,
48
+ valueString: (0, log_update_1.normalizeQuotes)(prop.valueString),
49
+ }));
45
50
  const undoPropChange = (0, format_effect_prop_change_1.formatEffectPropChange)({
46
51
  effectName: effectCallee,
47
52
  key,
@@ -49,7 +54,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
49
54
  newValueString: normalizedOld,
50
55
  defaultValueString: normalizedDefault,
51
56
  removedProps: [],
52
- addedProps: [],
57
+ addedProps: normalizedRemovedProps,
53
58
  });
54
59
  const redoPropChange = (0, format_effect_prop_change_1.formatEffectPropChange)({
55
60
  effectName: effectCallee,
@@ -57,7 +62,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
57
62
  oldValueString: normalizedOld,
58
63
  newValueString: normalizedNew,
59
64
  defaultValueString: normalizedDefault,
60
- removedProps: [],
65
+ removedProps: normalizedRemovedProps,
61
66
  addedProps: [],
62
67
  });
63
68
  (0, undo_stack_1.pushToUndoStack)({
@@ -86,7 +91,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
86
91
  defaultValueString,
87
92
  formatted,
88
93
  logLevel,
89
- removedProps: [],
94
+ removedProps,
90
95
  addedProps: [],
91
96
  });
92
97
  (0, undo_stack_1.printUndoHint)(logLevel);
package/dist/routes.js CHANGED
@@ -45,6 +45,7 @@ const client_render_queue_1 = require("./client-render-queue");
45
45
  const get_file_source_1 = require("./helpers/get-file-source");
46
46
  const get_installed_installable_packages_1 = require("./helpers/get-installed-installable-packages");
47
47
  const open_in_editor_1 = require("./helpers/open-in-editor");
48
+ const resolve_composition_component_1 = require("./helpers/resolve-composition-component");
48
49
  const resolve_output_path_1 = require("./helpers/resolve-output-path");
49
50
  const api_routes_1 = require("./preview-server/api-routes");
50
51
  const get_package_manager_1 = require("./preview-server/get-package-manager");
@@ -201,6 +202,41 @@ const handleOpenInEditor = async (remotionRoot, req, res, logLevel) => {
201
202
  }));
202
203
  }
203
204
  };
205
+ const handleGetCompositionComponentInfo = async (remotionRoot, req, res) => {
206
+ if (req.method === 'OPTIONS') {
207
+ res.statusCode = 200;
208
+ res.end();
209
+ return;
210
+ }
211
+ res.setHeader('content-type', 'application/json');
212
+ try {
213
+ const body = (await (0, parse_body_1.parseRequestBody)(req));
214
+ if (typeof body.compositionFile !== 'string') {
215
+ throw new TypeError('Need to pass compositionFile');
216
+ }
217
+ if (typeof body.compositionId !== 'string') {
218
+ throw new TypeError('Need to pass compositionId');
219
+ }
220
+ const location = await (0, resolve_composition_component_1.resolveCompositionComponent)({
221
+ remotionRoot,
222
+ compositionFile: body.compositionFile,
223
+ compositionId: body.compositionId,
224
+ });
225
+ res.writeHead(200);
226
+ res.end(JSON.stringify({
227
+ success: true,
228
+ location,
229
+ canAddSequence: location.canAddSequence,
230
+ }));
231
+ }
232
+ catch (err) {
233
+ res.writeHead(200);
234
+ res.end(JSON.stringify({
235
+ success: false,
236
+ error: err.message,
237
+ }));
238
+ }
239
+ };
204
240
  const validateSameOrigin = (req) => {
205
241
  const { origin, host } = req.headers;
206
242
  if (origin) {
@@ -330,6 +366,9 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
330
366
  if (url.pathname === '/api/open-in-editor') {
331
367
  return handleOpenInEditor(remotionRoot, request, response, logLevel);
332
368
  }
369
+ if (url.pathname === '/api/composition-component-info') {
370
+ return handleGetCompositionComponentInfo(remotionRoot, request, response);
371
+ }
333
372
  if (url.pathname === `${staticHash}/api/add-asset`) {
334
373
  return handleAddAsset({
335
374
  req: request,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio-server"
4
4
  },
5
5
  "name": "@remotion/studio-server",
6
- "version": "4.0.465",
6
+ "version": "4.0.467",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -27,11 +27,11 @@
27
27
  "@babel/parser": "7.24.1",
28
28
  "semver": "7.5.3",
29
29
  "prettier": "3.8.1",
30
- "remotion": "4.0.465",
30
+ "remotion": "4.0.467",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.465",
33
- "@remotion/renderer": "4.0.465",
34
- "@remotion/studio-shared": "4.0.465",
32
+ "@remotion/bundler": "4.0.467",
33
+ "@remotion/renderer": "4.0.467",
34
+ "@remotion/studio-shared": "4.0.467",
35
35
  "memfs": "3.4.3",
36
36
  "open": "8.4.2"
37
37
  },
@@ -39,7 +39,7 @@
39
39
  "ast-types": "0.16.1",
40
40
  "react": "19.2.3",
41
41
  "@types/semver": "7.5.3",
42
- "@remotion/eslint-config-internal": "4.0.465",
42
+ "@remotion/eslint-config-internal": "4.0.467",
43
43
  "eslint": "9.19.0",
44
44
  "@types/node": "20.12.14",
45
45
  "@typescript/native-preview": "7.0.0-dev.20260217.1"