@remotion/studio-server 4.0.463 → 4.0.465

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.
Files changed (29) hide show
  1. package/dist/codemods/apply-codemod-to-file.d.ts +6 -0
  2. package/dist/codemods/apply-codemod-to-file.js +35 -0
  3. package/dist/codemods/delete-effect.d.ts +12 -0
  4. package/dist/codemods/delete-effect.js +54 -0
  5. package/dist/codemods/duplicate-composition.js +1 -1
  6. package/dist/codemods/recast-mods.js +64 -0
  7. package/dist/codemods/update-effect-props/update-effect-props.d.ts +1 -0
  8. package/dist/codemods/update-effect-props/update-effect-props.js +6 -6
  9. package/dist/file-watcher.d.ts +3 -1
  10. package/dist/file-watcher.js +11 -7
  11. package/dist/index.d.ts +15 -1
  12. package/dist/index.js +5 -0
  13. package/dist/preview-server/api-routes.js +2 -0
  14. package/dist/preview-server/dev-middleware/setup-output-filesystem.js +2 -2
  15. package/dist/preview-server/routes/apply-codemod.js +66 -12
  16. package/dist/preview-server/routes/apply-visual-control-change.js +1 -1
  17. package/dist/preview-server/routes/can-update-effect-props.js +3 -4
  18. package/dist/preview-server/routes/can-update-sequence-props.js +2 -1
  19. package/dist/preview-server/routes/delete-effect.d.ts +3 -0
  20. package/dist/preview-server/routes/delete-effect.js +68 -0
  21. package/dist/preview-server/routes/delete-jsx-node.js +1 -1
  22. package/dist/preview-server/routes/duplicate-jsx-node.js +1 -1
  23. package/dist/preview-server/routes/save-effect-props.js +2 -2
  24. package/dist/preview-server/routes/save-sequence-props.js +2 -2
  25. package/dist/preview-server/routes/update-default-props.js +1 -1
  26. package/dist/preview-server/sequence-props-watchers.js +15 -0
  27. package/dist/preview-server/undo-stack.d.ts +9 -1
  28. package/dist/preview-server/undo-stack.js +2 -2
  29. package/package.json +6 -6
@@ -0,0 +1,6 @@
1
+ import type { RecastCodemod, SymbolicatedStackFrame } from '@remotion/studio-shared';
2
+ export declare const resolveFilePathFromSymbolicatedStack: (remotionRoot: string, stack: SymbolicatedStackFrame) => string;
3
+ export declare const applyCodemodToFile: ({ filePath, codeMod, }: {
4
+ filePath: string;
5
+ codeMod: RecastCodemod;
6
+ }) => Promise<string>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.applyCodemodToFile = exports.resolveFilePathFromSymbolicatedStack = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const can_update_default_props_1 = require("../preview-server/routes/can-update-default-props");
10
+ const duplicate_composition_1 = require("./duplicate-composition");
11
+ const resolveFilePathFromSymbolicatedStack = (remotionRoot, stack) => {
12
+ if (!stack.originalFileName) {
13
+ throw new Error('Could not determine the file where this composition is defined');
14
+ }
15
+ const absolutePath = node_path_1.default.resolve(remotionRoot, stack.originalFileName);
16
+ const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
17
+ if (fileRelativeToRoot.startsWith('..')) {
18
+ throw new Error('Cannot apply codemod to a file outside the project');
19
+ }
20
+ if (!(0, node_fs_1.existsSync)(absolutePath)) {
21
+ throw new Error(`File not found: ${stack.originalFileName}`);
22
+ }
23
+ return absolutePath;
24
+ };
25
+ exports.resolveFilePathFromSymbolicatedStack = resolveFilePathFromSymbolicatedStack;
26
+ const applyCodemodToFile = async ({ filePath, codeMod, }) => {
27
+ (0, can_update_default_props_1.checkIfTypeScriptFile)(filePath);
28
+ const input = (0, node_fs_1.readFileSync)(filePath, 'utf-8');
29
+ const { newContents } = (0, duplicate_composition_1.parseAndApplyCodemod)({
30
+ codeMod,
31
+ input,
32
+ });
33
+ return (0, duplicate_composition_1.formatOutput)(newContents);
34
+ };
35
+ exports.applyCodemodToFile = applyCodemodToFile;
@@ -0,0 +1,12 @@
1
+ import type { SequenceNodePath } from 'remotion';
2
+ export declare const deleteEffect: ({ input, sequenceNodePath, effectIndex, prettierConfigOverride, }: {
3
+ input: string;
4
+ sequenceNodePath: SequenceNodePath;
5
+ effectIndex: number;
6
+ prettierConfigOverride?: Record<string, unknown> | null | undefined;
7
+ }) => Promise<{
8
+ output: string;
9
+ formatted: boolean;
10
+ effectLabel: string;
11
+ logLine: number;
12
+ }>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteEffect = void 0;
4
+ const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
5
+ const format_file_content_1 = require("./format-file-content");
6
+ const parse_ast_1 = require("./parse-ast");
7
+ const update_effect_props_1 = require("./update-effect-props/update-effect-props");
8
+ const getEffectsArray = (attr) => {
9
+ if (!attr.value || attr.value.type !== 'JSXExpressionContainer') {
10
+ throw new Error('Cannot delete effect: effects prop is not an array');
11
+ }
12
+ const expr = attr.value.expression;
13
+ if (expr.type !== 'ArrayExpression') {
14
+ throw new Error('Cannot delete effect: effects prop is not an array');
15
+ }
16
+ return expr;
17
+ };
18
+ const deleteEffect = async ({ input, sequenceNodePath, effectIndex, prettierConfigOverride, }) => {
19
+ var _a, _b;
20
+ var _c, _d, _e;
21
+ const ast = (0, parse_ast_1.parseAst)(input);
22
+ const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, sequenceNodePath);
23
+ if (!jsx) {
24
+ throw new Error('Could not find a JSX element at the specified location to delete effect');
25
+ }
26
+ const attr = (0, update_effect_props_1.findEffectsAttr)((_c = jsx.attributes) !== null && _c !== void 0 ? _c : []);
27
+ if (!attr) {
28
+ throw new Error('Could not find effects on the target JSX element');
29
+ }
30
+ const effectsArray = getEffectsArray(attr);
31
+ const found = (0, update_effect_props_1.findEffectCallExpression)({ attr, effectIndex });
32
+ if (found.kind === 'error') {
33
+ throw new Error(`Cannot delete effect: ${found.reason}`);
34
+ }
35
+ effectsArray.elements.splice(effectIndex, 1);
36
+ if (effectsArray.elements.length === 0) {
37
+ const attrIndex = jsx.attributes.indexOf(attr);
38
+ if (attrIndex !== -1) {
39
+ jsx.attributes.splice(attrIndex, 1);
40
+ }
41
+ }
42
+ const finalFile = (0, parse_ast_1.serializeAst)(ast);
43
+ const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
44
+ input: finalFile,
45
+ prettierConfigOverride,
46
+ });
47
+ return {
48
+ output,
49
+ formatted,
50
+ effectLabel: `${found.callee}()`,
51
+ logLine: (_e = (_d = (_a = found.call.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _d !== void 0 ? _d : (_b = jsx.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _e !== void 0 ? _e : 1,
52
+ };
53
+ };
54
+ exports.deleteEffect = deleteEffect;
@@ -69,7 +69,7 @@ const parseAndApplyCodemod = ({ input, codeMod, }) => {
69
69
  codeMod,
70
70
  });
71
71
  if (changesMade.length === 0) {
72
- throw new Error('Unable to calculate the changes needed for this file. Edit the root file manually.');
72
+ throw new Error('Unable to calculate the changes needed for this file. Edit the file manually.');
73
73
  }
74
74
  const output = (0, parse_ast_1.serializeAst)(newAst);
75
75
  return { changesMade, newContents: output };
@@ -60,11 +60,65 @@ const mapReturnStatement = (statement, transformation, changesMade) => {
60
60
  if (!statement.argument) {
61
61
  return statement;
62
62
  }
63
+ const replacement = transformLoneJsxElement(statement.argument, transformation, changesMade);
64
+ if (replacement !== null) {
65
+ return { ...statement, argument: replacement };
66
+ }
63
67
  return {
64
68
  ...statement,
65
69
  argument: mapAll(statement.argument, transformation, changesMade),
66
70
  };
67
71
  };
72
+ const nullLiteral = () => ({ type: 'NullLiteral' });
73
+ // When a node was originally parenthesized (e.g. the `<JSX/>` inside
74
+ // `return (<JSX/>)`), Babel records `extra.parenthesized` on it. If we move
75
+ // such a node into a JSXFragment without clearing that hint, recast prints
76
+ // stray `(` / `)` characters around it as JSX text. Clear the hint so the
77
+ // node prints cleanly in its new context.
78
+ const stripParenthesizedExtra = (node) => {
79
+ if (!node.extra) {
80
+ return node;
81
+ }
82
+ const { parenthesized: _p, parenStart: _ps, ...rest } = node.extra;
83
+ return { ...node, extra: rest };
84
+ };
85
+ const wrapInJsxFragment = (children) => ({
86
+ type: 'JSXFragment',
87
+ openingFragment: { type: 'JSXOpeningFragment' },
88
+ closingFragment: { type: 'JSXClosingFragment' },
89
+ children: children.map(stripParenthesizedExtra),
90
+ });
91
+ // When a <Composition> JSX element appears in a position where it cannot
92
+ // simply be removed from a parent's children list (e.g. as the sole return
93
+ // value of a wrapper component or as the concise body of an arrow function),
94
+ // we still want delete/rename/duplicate codemods to work. This helper detects
95
+ // that case and produces a structurally-valid replacement expression.
96
+ const transformLoneJsxElement = (expression, transformation, changesMade) => {
97
+ if (expression.type !== 'JSXElement') {
98
+ return null;
99
+ }
100
+ const compId = getCompositionIdFromJSXElement(expression);
101
+ if (compId === null) {
102
+ return null;
103
+ }
104
+ const isMatch = (transformation.type === 'delete-composition' &&
105
+ compId === transformation.idToDelete) ||
106
+ (transformation.type === 'rename-composition' &&
107
+ compId === transformation.idToRename) ||
108
+ (transformation.type === 'duplicate-composition' &&
109
+ compId === transformation.idToDuplicate);
110
+ if (!isMatch) {
111
+ return null;
112
+ }
113
+ const transformed = mapJsxChild(expression, transformation, changesMade);
114
+ if (transformed.length === 0) {
115
+ return nullLiteral();
116
+ }
117
+ if (transformed.length === 1) {
118
+ return transformed[0];
119
+ }
120
+ return wrapInJsxFragment(transformed);
121
+ };
68
122
  const mapJsxElementOrFragment = (jsxFragment, transformation, changesMade) => {
69
123
  return {
70
124
  ...jsxFragment,
@@ -129,6 +183,16 @@ const mapRecognizedType = (expression, transformation, changesMade) => {
129
183
  }
130
184
  if (expression.type === 'ArrowFunctionExpression' ||
131
185
  expression.type === 'FunctionExpression') {
186
+ if (expression.type === 'ArrowFunctionExpression' &&
187
+ expression.body.type === 'JSXElement') {
188
+ const replacement = transformLoneJsxElement(expression.body, transformation, changesMade);
189
+ if (replacement !== null) {
190
+ return {
191
+ ...expression,
192
+ body: replacement,
193
+ };
194
+ }
195
+ }
132
196
  return {
133
197
  ...expression,
134
198
  body: mapAll(expression.body, transformation, changesMade),
@@ -12,6 +12,7 @@ export type UpdateEffectPropsResult = {
12
12
  logLine: number;
13
13
  effectCallee: string;
14
14
  };
15
+ export declare const findEffectsAttr: (attrs: readonly unknown[]) => JSXAttribute | null;
15
16
  export type EffectArrayElement = {
16
17
  kind: 'call';
17
18
  callee: string;
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.updateEffectProps = exports.updateEffectPropsAst = exports.findEffectCallExpression = exports.enumerateEffectArrayElements = void 0;
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
39
  const can_update_sequence_props_1 = require("../../preview-server/routes/can-update-sequence-props");
@@ -50,19 +50,19 @@ const parseValueExpression = (value) => {
50
50
  }
51
51
  return stmt.expression.right;
52
52
  };
53
- const findExperimentalEffectsAttr = (attrs) => {
53
+ const findEffectsAttr = (attrs) => {
54
54
  for (const attr of attrs) {
55
55
  if (attr.type !== 'JSXAttribute') {
56
56
  continue;
57
57
  }
58
58
  const a = attr;
59
- if (a.name.type === 'JSXIdentifier' &&
60
- a.name.name === '_experimentalEffects') {
59
+ if (a.name.type === 'JSXIdentifier' && a.name.name === 'effects') {
61
60
  return a;
62
61
  }
63
62
  }
64
63
  return null;
65
64
  };
65
+ exports.findEffectsAttr = findEffectsAttr;
66
66
  const getCalleeName = (call) => {
67
67
  const { callee } = call;
68
68
  if (callee.type === 'Identifier') {
@@ -140,9 +140,9 @@ const updateEffectPropsAst = ({ input, sequenceNodePath, effectIndex, update, })
140
140
  if (!jsx) {
141
141
  throw new Error('Could not find a JSX element at the specified location to update effects');
142
142
  }
143
- const attr = findExperimentalEffectsAttr((_e = jsx.attributes) !== null && _e !== void 0 ? _e : []);
143
+ const attr = (0, exports.findEffectsAttr)((_e = jsx.attributes) !== null && _e !== void 0 ? _e : []);
144
144
  if (!attr) {
145
- throw new Error('Could not find _experimentalEffects on the target JSX element');
145
+ throw new Error('Could not find effects on the target JSX element');
146
146
  }
147
147
  const found = (0, exports.findEffectCallExpression)({
148
148
  attr,
@@ -1,11 +1,13 @@
1
1
  export type FileChangeEvent = {
2
2
  type: 'created';
3
3
  content: string;
4
+ originatorClientId: string | undefined;
4
5
  } | {
5
6
  type: 'deleted';
6
7
  } | {
7
8
  type: 'changed';
8
9
  content: string;
10
+ originatorClientId: string | undefined;
9
11
  };
10
12
  type OnChange = (event: FileChangeEvent) => void;
11
13
  export type FileWatcherRegistry = {
@@ -23,7 +25,7 @@ export type FileWatcherRegistry = {
23
25
  exists: boolean;
24
26
  unwatch: () => void;
25
27
  };
26
- writeFileAndNotifyFileWatchers: (file: string, content: string) => void;
28
+ writeFileAndNotifyFileWatchers: (file: string, content: string, originatorClientId: string | undefined) => void;
27
29
  };
28
30
  export declare const createFileWatcherRegistry: () => FileWatcherRegistry;
29
31
  export declare const setFileWatcherRegistry: (registry: FileWatcherRegistry) => () => void;
@@ -69,7 +69,11 @@ const createFileWatcherRegistry = () => {
69
69
  if (existenceOnly) {
70
70
  if (!shared.existedBefore && existsNow) {
71
71
  shared.existedBefore = true;
72
- event = { type: 'created', content: '' };
72
+ event = {
73
+ type: 'created',
74
+ content: '',
75
+ originatorClientId: undefined,
76
+ };
73
77
  }
74
78
  else if (shared.existedBefore && !existsNow) {
75
79
  shared.existedBefore = false;
@@ -80,7 +84,7 @@ const createFileWatcherRegistry = () => {
80
84
  const content = (0, node_fs_1.readFileSync)(file, 'utf-8');
81
85
  shared.existedBefore = true;
82
86
  shared.lastKnownContent = content;
83
- event = { type: 'created', content };
87
+ event = { type: 'created', content, originatorClientId: undefined };
84
88
  }
85
89
  else if (shared.existedBefore && !existsNow) {
86
90
  shared.existedBefore = false;
@@ -97,7 +101,7 @@ const createFileWatcherRegistry = () => {
97
101
  return;
98
102
  }
99
103
  shared.lastKnownContent = content;
100
- event = { type: 'changed', content };
104
+ event = { type: 'changed', content, originatorClientId: undefined };
101
105
  }
102
106
  if (!event) {
103
107
  return;
@@ -119,7 +123,7 @@ const createFileWatcherRegistry = () => {
119
123
  },
120
124
  };
121
125
  };
122
- const _writeFileAndNotifyFileWatchers = (file, content) => {
126
+ const _writeFileAndNotifyFileWatchers = (file, content, originatorClientId) => {
123
127
  (0, node_fs_1.writeFileSync)(file, content);
124
128
  const shared = sharedWatchers.get(getRegistryKey(file, false));
125
129
  if (!shared) {
@@ -128,7 +132,7 @@ const createFileWatcherRegistry = () => {
128
132
  shared.lastKnownContent = content;
129
133
  shared.existedBefore = true;
130
134
  for (const subscriber of shared.subscribers) {
131
- subscriber({ type: 'changed', content });
135
+ subscriber({ type: 'changed', content, originatorClientId });
132
136
  }
133
137
  };
134
138
  return {
@@ -162,10 +166,10 @@ const installFileWatcher = (options) => {
162
166
  return (0, exports.getFileWatcherRegistry)().installFileWatcher(options);
163
167
  };
164
168
  exports.installFileWatcher = installFileWatcher;
165
- const writeFileAndNotifyFileWatchers = (file, content) => {
169
+ const writeFileAndNotifyFileWatchers = (file, content, originatorClientId) => {
166
170
  if (!currentRegistry) {
167
171
  return;
168
172
  }
169
- (0, exports.getFileWatcherRegistry)().writeFileAndNotifyFileWatchers(file, content);
173
+ (0, exports.getFileWatcherRegistry)().writeFileAndNotifyFileWatchers(file, content, originatorClientId);
170
174
  };
171
175
  exports.writeFileAndNotifyFileWatchers = writeFileAndNotifyFileWatchers;
package/dist/index.d.ts CHANGED
@@ -63,7 +63,7 @@ export declare const StudioServerInternals: {
63
63
  exists: boolean;
64
64
  unwatch: () => void;
65
65
  };
66
- writeFileAndNotifyFileWatchers: (file: string, content: string) => void;
66
+ writeFileAndNotifyFileWatchers: (file: string, content: string, originatorClientId: string | undefined) => void;
67
67
  createFileWatcherRegistry: () => import("./file-watcher").FileWatcherRegistry;
68
68
  setFileWatcherRegistry: (registry: import("./file-watcher").FileWatcherRegistry) => () => void;
69
69
  AnsiDiff: typeof AnsiDiff;
@@ -80,6 +80,20 @@ export declare const StudioServerInternals: {
80
80
  newContents: string;
81
81
  changesMade: import("./codemods/recast-mods").Change[];
82
82
  };
83
+ applyCodemodToFile: ({ filePath, codeMod, }: {
84
+ filePath: string;
85
+ codeMod: import("@remotion/studio-shared").RecastCodemod;
86
+ }) => Promise<string>;
87
+ formatOutput: (tsContent: string) => Promise<string>;
88
+ updateDefaultProps: ({ input, compositionId, newDefaultProps, enumPaths, }: {
89
+ input: string;
90
+ compositionId: string;
91
+ newDefaultProps: Record<string, unknown>;
92
+ enumPaths: import("@remotion/studio-shared").EnumPath[];
93
+ }) => Promise<{
94
+ output: string;
95
+ formatted: boolean;
96
+ }>;
83
97
  getInstalledDependencies: (remotionRoot: string) => {
84
98
  dependencies: string[];
85
99
  devDependencies: string[];
package/dist/index.js CHANGED
@@ -6,7 +6,9 @@ const studio_shared_2 = require("@remotion/studio-shared");
6
6
  Object.defineProperty(exports, "getDefaultOutLocation", { enumerable: true, get: function () { return studio_shared_2.getDefaultOutLocation; } });
7
7
  const ansi_diff_1 = require("./ansi-diff");
8
8
  const client_render_queue_1 = require("./client-render-queue");
9
+ const apply_codemod_to_file_1 = require("./codemods/apply-codemod-to-file");
9
10
  const duplicate_composition_1 = require("./codemods/duplicate-composition");
11
+ const update_default_props_1 = require("./codemods/update-default-props");
10
12
  const file_watcher_1 = require("./file-watcher");
11
13
  const get_latest_remotion_version_1 = require("./get-latest-remotion-version");
12
14
  const get_installed_dependencies_1 = require("./helpers/get-installed-dependencies");
@@ -32,6 +34,9 @@ exports.StudioServerInternals = {
32
34
  AnsiDiff: ansi_diff_1.AnsiDiff,
33
35
  formatBytes: studio_shared_1.formatBytes,
34
36
  parseAndApplyCodemod: duplicate_composition_1.parseAndApplyCodemod,
37
+ applyCodemodToFile: apply_codemod_to_file_1.applyCodemodToFile,
38
+ formatOutput: duplicate_composition_1.formatOutput,
39
+ updateDefaultProps: update_default_props_1.updateDefaultProps,
35
40
  getInstalledDependencies: get_installed_dependencies_1.getInstalledDependencies,
36
41
  getInstalledDependenciesWithVersions: get_installed_dependencies_1.getInstalledDependenciesWithVersions,
37
42
  getInstallCommand: install_command_1.getInstallCommand,
@@ -5,6 +5,7 @@ const add_render_1 = require("./routes/add-render");
5
5
  const apply_codemod_1 = require("./routes/apply-codemod");
6
6
  const apply_visual_control_change_1 = require("./routes/apply-visual-control-change");
7
7
  const cancel_render_1 = require("./routes/cancel-render");
8
+ const delete_effect_1 = require("./routes/delete-effect");
8
9
  const delete_jsx_node_1 = require("./routes/delete-jsx-node");
9
10
  const delete_static_file_1 = require("./routes/delete-static-file");
10
11
  const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
@@ -41,6 +42,7 @@ exports.allApiRoutes = {
41
42
  '/api/unsubscribe-from-sequence-props': unsubscribe_from_sequence_props_1.unsubscribeFromSequenceProps,
42
43
  '/api/save-sequence-props': save_sequence_props_1.saveSequencePropsHandler,
43
44
  '/api/save-effect-props': save_effect_props_1.saveEffectPropsHandler,
45
+ '/api/delete-effect': delete_effect_1.deleteEffectHandler,
44
46
  '/api/delete-jsx-node': delete_jsx_node_1.deleteJsxNodeHandler,
45
47
  '/api/duplicate-jsx-node': duplicate_jsx_node_1.duplicateJsxNodeHandler,
46
48
  '/api/update-available': update_available_1.handleUpdate,
@@ -7,7 +7,7 @@ exports.setupOutputFileSystem = setupOutputFileSystem;
7
7
  const memfs_1 = __importDefault(require("memfs"));
8
8
  function setupOutputFileSystem(context) {
9
9
  const outputFileSystem = memfs_1.default.createFsFromVolume(new memfs_1.default.Volume());
10
- // @ts-expect-error output file sytem
11
- context.compiler.outputFileSystem = outputFileSystem;
10
+ context.compiler.outputFileSystem =
11
+ outputFileSystem;
12
12
  context.outputFileSystem = outputFileSystem;
13
13
  }
@@ -1,35 +1,89 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.applyCodemodHandler = void 0;
4
7
  const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
5
9
  const renderer_1 = require("@remotion/renderer");
6
- const duplicate_composition_1 = require("../../codemods/duplicate-composition");
10
+ const apply_codemod_to_file_1 = require("../../codemods/apply-codemod-to-file");
7
11
  const simple_diff_1 = require("../../codemods/simple-diff");
8
12
  const file_watcher_1 = require("../../file-watcher");
9
13
  const project_info_1 = require("../project-info");
14
+ const undo_stack_1 = require("../undo-stack");
10
15
  const can_update_default_props_1 = require("./can-update-default-props");
11
- const applyCodemodHandler = async ({ input: { codemod, dryRun }, logLevel, remotionRoot, entryPoint }) => {
16
+ const getCodemodUndoDescription = (codemod) => {
17
+ if (codemod.type === 'delete-composition') {
18
+ return {
19
+ undoMessage: `↩️ Deletion of composition "${codemod.idToDelete}"`,
20
+ redoMessage: `↪️ Deletion of composition "${codemod.idToDelete}"`,
21
+ entryType: codemod.type,
22
+ };
23
+ }
24
+ if (codemod.type === 'rename-composition') {
25
+ const label = `composition "${codemod.idToRename}" to "${codemod.newId}"`;
26
+ return {
27
+ undoMessage: `↩️ Rename of ${label}`,
28
+ redoMessage: `↪️ Rename of ${label}`,
29
+ entryType: codemod.type,
30
+ };
31
+ }
32
+ if (codemod.type === 'duplicate-composition') {
33
+ const label = `composition "${codemod.idToDuplicate}" to "${codemod.newId}"`;
34
+ return {
35
+ undoMessage: `↩️ Duplication of ${label}`,
36
+ redoMessage: `↪️ Duplication of ${label}`,
37
+ entryType: codemod.type,
38
+ };
39
+ }
40
+ return {
41
+ undoMessage: '↩️ Visual control change',
42
+ redoMessage: '↪️ Visual control change',
43
+ entryType: 'visual-control',
44
+ };
45
+ };
46
+ const applyCodemodHandler = async ({ input: { codemod, dryRun, symbolicatedStack }, logLevel, remotionRoot, entryPoint, }) => {
47
+ var _a;
12
48
  try {
13
49
  const time = Date.now();
14
- const projectInfo = await (0, project_info_1.getProjectInfo)(remotionRoot, entryPoint);
15
- if (!projectInfo.rootFile) {
16
- throw new Error('Cannot find root file in project');
50
+ const filePath = symbolicatedStack
51
+ ? (0, apply_codemod_to_file_1.resolveFilePathFromSymbolicatedStack)(remotionRoot, symbolicatedStack)
52
+ : (await (0, project_info_1.getProjectInfo)(remotionRoot, entryPoint)).rootFile;
53
+ if (!filePath) {
54
+ throw new Error('Cannot find file for composition in project');
17
55
  }
18
- (0, can_update_default_props_1.checkIfTypeScriptFile)(projectInfo.rootFile);
19
- const input = (0, node_fs_1.readFileSync)(projectInfo.rootFile, 'utf-8');
20
- const { newContents } = (0, duplicate_composition_1.parseAndApplyCodemod)({
56
+ (0, can_update_default_props_1.checkIfTypeScriptFile)(filePath);
57
+ const input = (0, node_fs_1.readFileSync)(filePath, 'utf-8');
58
+ const formatted = await (0, apply_codemod_to_file_1.applyCodemodToFile)({
59
+ filePath,
21
60
  codeMod: codemod,
22
- input,
23
61
  });
24
- const formatted = await (0, duplicate_composition_1.formatOutput)(newContents);
25
62
  const diff = (0, simple_diff_1.simpleDiff)({
26
63
  oldLines: input.split('\n'),
27
64
  newLines: formatted.split('\n'),
28
65
  });
29
66
  if (!dryRun) {
30
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, formatted);
67
+ const { entryType, undoMessage, redoMessage } = getCodemodUndoDescription(codemod);
68
+ (0, undo_stack_1.pushToUndoStack)({
69
+ filePath,
70
+ oldContents: input,
71
+ logLevel,
72
+ remotionRoot,
73
+ logLine: (_a = symbolicatedStack === null || symbolicatedStack === void 0 ? void 0 : symbolicatedStack.originalLineNumber) !== null && _a !== void 0 ? _a : 1,
74
+ description: {
75
+ undoMessage,
76
+ redoMessage,
77
+ },
78
+ entryType,
79
+ suppressHmrOnFileRestore: false,
80
+ });
81
+ (0, undo_stack_1.suppressUndoStackInvalidation)(filePath);
82
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(filePath, formatted, undefined);
31
83
  const end = Date.now() - time;
32
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Edited root file in ${end}ms`));
84
+ const relativePath = node_path_1.default.relative(remotionRoot, filePath);
85
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Edited ${relativePath} in ${end}ms`));
86
+ (0, undo_stack_1.printUndoHint)(logLevel);
33
87
  }
34
88
  return {
35
89
  success: true,
@@ -126,7 +126,7 @@ const applyVisualControlHandler = async ({ input: { fileName, changes }, remotio
126
126
  });
127
127
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
128
128
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
129
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
129
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
130
130
  (0, live_events_1.waitForLiveEventsListener)().then((listener) => {
131
131
  listener.sendEventToClient({
132
132
  type: 'visual-control-values-changed',
@@ -9,13 +9,12 @@ const node_path_1 = __importDefault(require("node:path"));
9
9
  const parse_ast_1 = require("../../codemods/parse-ast");
10
10
  const update_effect_props_1 = require("../../codemods/update-effect-props/update-effect-props");
11
11
  const can_update_sequence_props_1 = require("./can-update-sequence-props");
12
- const findExperimentalEffectsAttr = (jsx) => {
12
+ const findEffectsAttr = (jsx) => {
13
13
  for (const attr of jsx.attributes) {
14
14
  if (attr.type !== 'JSXAttribute') {
15
15
  continue;
16
16
  }
17
- if (attr.name.type === 'JSXIdentifier' &&
18
- attr.name.name === '_experimentalEffects') {
17
+ if (attr.name.type === 'JSXIdentifier' && attr.name.name === 'effects') {
19
18
  return attr;
20
19
  }
21
20
  }
@@ -55,7 +54,7 @@ const getPropsFromObjectExpression = ({ objExpr, keys, }) => {
55
54
  return out;
56
55
  };
57
56
  const computeEffectPropStatus = ({ jsx, effectIndex, keys, }) => {
58
- const attr = findExperimentalEffectsAttr(jsx);
57
+ const attr = findEffectsAttr(jsx);
59
58
  const elements = getEffectsArrayElements(attr);
60
59
  if (!elements) {
61
60
  return {
@@ -43,6 +43,7 @@ const renderer_1 = require("@remotion/renderer");
43
43
  const recast = __importStar(require("recast"));
44
44
  const parse_ast_1 = require("../../codemods/parse-ast");
45
45
  const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
46
+ const jsx_element_not_found_at_location_error_1 = require("../jsx-element-not-found-at-location-error");
46
47
  const can_update_effect_props_1 = require("./can-update-effect-props");
47
48
  const isStaticValue = (node) => {
48
49
  switch (node.type) {
@@ -295,7 +296,7 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, keys, e
295
296
  const ast = (0, parse_ast_1.parseAst)(fileContents);
296
297
  const jsxElement = (0, exports.findJsxElementAtNodePath)(ast, nodePath);
297
298
  if (!jsxElement) {
298
- throw new Error('Cannot compute sequence props status: Could not find a JSX element at the specified location');
299
+ throw new jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError();
299
300
  }
300
301
  const filteredProps = computeSequenceOnlyPropsRecord({ jsxElement, keys });
301
302
  const effectsStatuses = computeEffectsForJsx({ jsxElement, effects });
@@ -0,0 +1,3 @@
1
+ import type { DeleteEffectRequest, DeleteEffectResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const deleteEffectHandler: ApiHandler<DeleteEffectRequest, DeleteEffectResponse>;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deleteEffectHandler = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const renderer_1 = require("@remotion/renderer");
10
+ const delete_effect_1 = require("../../codemods/delete-effect");
11
+ const file_watcher_1 = require("../../file-watcher");
12
+ const format_log_file_location_1 = require("../format-log-file-location");
13
+ const undo_stack_1 = require("../undo-stack");
14
+ const formatting_1 = require("./log-updates/formatting");
15
+ const log_update_1 = require("./log-updates/log-update");
16
+ const deleteEffectHandler = async ({ input: { fileName, sequenceNodePath, effectIndex }, remotionRoot, logLevel, }) => {
17
+ try {
18
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[delete-effect] Received request for fileName="${fileName}" effectIndex=${effectIndex}`);
19
+ const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
20
+ const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
21
+ if (fileRelativeToRoot.startsWith('..')) {
22
+ throw new Error('Cannot modify a file outside the project');
23
+ }
24
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
25
+ const { output, formatted, effectLabel, logLine } = await (0, delete_effect_1.deleteEffect)({
26
+ input: fileContents,
27
+ sequenceNodePath: sequenceNodePath.nodePath,
28
+ effectIndex,
29
+ });
30
+ (0, undo_stack_1.pushToUndoStack)({
31
+ filePath: absolutePath,
32
+ oldContents: fileContents,
33
+ logLevel,
34
+ remotionRoot,
35
+ logLine,
36
+ description: {
37
+ undoMessage: `↩️ Deletion of ${effectLabel}`,
38
+ redoMessage: `↪️ Deletion of ${effectLabel}`,
39
+ },
40
+ entryType: 'delete-effect',
41
+ suppressHmrOnFileRestore: false,
42
+ });
43
+ (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
44
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
45
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
46
+ remotionRoot,
47
+ absolutePath,
48
+ line: logLine,
49
+ });
50
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${(0, formatting_1.strikeThroughOrRemovedPrefix)(effectLabel)}`);
51
+ if (!formatted) {
52
+ (0, log_update_1.warnAboutPrettierOnce)(logLevel);
53
+ }
54
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[delete-effect] Wrote ${fileRelativeToRoot}${formatted ? ' (formatted)' : ''}`);
55
+ (0, undo_stack_1.printUndoHint)(logLevel);
56
+ return {
57
+ success: true,
58
+ };
59
+ }
60
+ catch (err) {
61
+ return {
62
+ success: false,
63
+ reason: err.message,
64
+ stack: err.stack,
65
+ };
66
+ }
67
+ };
68
+ exports.deleteEffectHandler = deleteEffectHandler;
@@ -39,7 +39,7 @@ const deleteJsxNodeHandler = async ({ input: { fileName, nodePath }, remotionRoo
39
39
  suppressHmrOnFileRestore: false,
40
40
  });
41
41
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
42
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
42
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
43
43
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
44
44
  remotionRoot,
45
45
  absolutePath,
@@ -39,7 +39,7 @@ const duplicateJsxNodeHandler = async ({ input: { fileName, nodePath }, remotion
39
39
  suppressHmrOnFileRestore: false,
40
40
  });
41
41
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
42
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
42
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
43
43
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
44
44
  remotionRoot,
45
45
  absolutePath,
@@ -19,7 +19,7 @@ const format_effect_prop_change_1 = require("./log-updates/format-effect-prop-ch
19
19
  const log_effect_update_1 = require("./log-updates/log-effect-update");
20
20
  const log_update_1 = require("./log-updates/log-update");
21
21
  const save_props_mutex_1 = require("./save-props-mutex");
22
- const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectIndex, key, value, defaultValue, schema, }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
22
+ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectIndex, key, value, defaultValue, schema, clientId, }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
23
23
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-effect-props] Received request for fileName="${fileName}" effectIndex=${effectIndex} key="${key}"`);
24
24
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
25
25
  const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
@@ -75,7 +75,7 @@ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectInd
75
75
  });
76
76
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
77
77
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
78
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
78
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
79
79
  (0, log_effect_update_1.logEffectUpdate)({
80
80
  fileRelativeToRoot,
81
81
  line: logLine,
@@ -17,7 +17,7 @@ const can_update_sequence_props_1 = require("./can-update-sequence-props");
17
17
  const format_prop_change_1 = require("./log-updates/format-prop-change");
18
18
  const log_update_1 = require("./log-updates/log-update");
19
19
  const save_props_mutex_1 = require("./save-props-mutex");
20
- const saveSequencePropsHandler = ({ input: { fileName, nodePath, key, value, defaultValue, schema }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
20
+ const saveSequencePropsHandler = ({ input: { fileName, nodePath, key, value, defaultValue, schema, clientId }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
21
21
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-sequence-props] Received request for fileName="${fileName}" key="${key}"`);
22
22
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
23
23
  const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
@@ -75,7 +75,7 @@ const saveSequencePropsHandler = ({ input: { fileName, nodePath, key, value, def
75
75
  });
76
76
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
77
77
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
78
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
78
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
79
79
  (0, log_update_1.logUpdate)({
80
80
  fileRelativeToRoot,
81
81
  line: logLine,
@@ -45,7 +45,7 @@ const updateDefaultPropsHandler = async ({ input: { compositionId, defaultProps,
45
45
  });
46
46
  (0, undo_stack_1.suppressUndoStackInvalidation)(projectInfo.rootFile);
47
47
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(projectInfo.rootFile);
48
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, output);
48
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, output, undefined);
49
49
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
50
50
  remotionRoot,
51
51
  absolutePath: projectInfo.rootFile,
@@ -8,6 +8,7 @@ const node_path_1 = __importDefault(require("node:path"));
8
8
  const renderer_1 = require("@remotion/renderer");
9
9
  const studio_shared_1 = require("@remotion/studio-shared");
10
10
  const file_watcher_1 = require("../file-watcher");
11
+ const jsx_element_not_found_at_location_error_1 = require("./jsx-element-not-found-at-location-error");
11
12
  const live_events_1 = require("./live-events");
12
13
  const node_path_cache_1 = require("./node-path-cache");
13
14
  const can_update_sequence_props_1 = require("./routes/can-update-sequence-props");
@@ -77,6 +78,9 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, effect
77
78
  if (event.type === 'deleted') {
78
79
  return;
79
80
  }
81
+ if (event.originatorClientId === clientId) {
82
+ return;
83
+ }
80
84
  try {
81
85
  const result = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
82
86
  fileContents: event.content,
@@ -101,6 +105,17 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, effect
101
105
  });
102
106
  }
103
107
  catch (error) {
108
+ if (error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError) {
109
+ (0, live_events_1.waitForLiveEventsListener)().then((listener) => {
110
+ listener.sendEventToClientId(clientId, {
111
+ type: 'lost-node-path',
112
+ fileName,
113
+ line,
114
+ column,
115
+ });
116
+ });
117
+ return;
118
+ }
104
119
  renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, error);
105
120
  }
106
121
  },
@@ -3,7 +3,7 @@ export interface UndoEntryDescription {
3
3
  undoMessage: string;
4
4
  redoMessage: string;
5
5
  }
6
- type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'delete-jsx-node' | 'duplicate-jsx-node';
6
+ type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'delete-effect' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'delete-composition' | 'rename-composition' | 'duplicate-composition';
7
7
  type UndoEntry = {
8
8
  filePath: string;
9
9
  oldContents: string;
@@ -20,10 +20,18 @@ type UndoEntry = {
20
20
  entryType: 'sequence-props';
21
21
  } | {
22
22
  entryType: 'effect-props';
23
+ } | {
24
+ entryType: 'delete-effect';
23
25
  } | {
24
26
  entryType: 'delete-jsx-node';
25
27
  } | {
26
28
  entryType: 'duplicate-jsx-node';
29
+ } | {
30
+ entryType: 'delete-composition';
31
+ } | {
32
+ entryType: 'rename-composition';
33
+ } | {
34
+ entryType: 'duplicate-composition';
27
35
  });
28
36
  export declare function pushToUndoStack({ filePath, oldContents, logLevel, remotionRoot, logLine, description, entryType, suppressHmrOnFileRestore }: {
29
37
  filePath: string;
@@ -195,7 +195,7 @@ function popUndo() {
195
195
  if (entry.suppressHmrOnFileRestore) {
196
196
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(entry.filePath);
197
197
  }
198
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents);
198
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents, undefined);
199
199
  renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: storedLogLevel }, renderer_1.RenderInternals.chalk.gray(`Undo: restored ${entry.filePath} (undo: ${undoStack.length}, redo: ${redoStack.length})`));
200
200
  logFileAction(entry.description.undoMessage, entry.filePath, entry.logLine);
201
201
  if (entry.entryType === 'visual-control') {
@@ -223,7 +223,7 @@ function popRedo() {
223
223
  if (entry.suppressHmrOnFileRestore) {
224
224
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(entry.filePath);
225
225
  }
226
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents);
226
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents, undefined);
227
227
  renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: storedLogLevel }, renderer_1.RenderInternals.chalk.gray(`Redo: restored ${entry.filePath} (undo: ${undoStack.length}, redo: ${redoStack.length})`));
228
228
  logFileAction(entry.description.redoMessage, entry.filePath, entry.logLine);
229
229
  if (entry.entryType === 'visual-control') {
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.463",
6
+ "version": "4.0.465",
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.463",
30
+ "remotion": "4.0.465",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.463",
33
- "@remotion/renderer": "4.0.463",
34
- "@remotion/studio-shared": "4.0.463",
32
+ "@remotion/bundler": "4.0.465",
33
+ "@remotion/renderer": "4.0.465",
34
+ "@remotion/studio-shared": "4.0.465",
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.463",
42
+ "@remotion/eslint-config-internal": "4.0.465",
43
43
  "eslint": "9.19.0",
44
44
  "@types/node": "20.12.14",
45
45
  "@typescript/native-preview": "7.0.0-dev.20260217.1"