@remotion/studio-server 4.0.464 → 4.0.466

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ 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");
10
11
  const update_default_props_1 = require("./codemods/update-default-props");
11
12
  const file_watcher_1 = require("./file-watcher");
@@ -33,6 +34,7 @@ exports.StudioServerInternals = {
33
34
  AnsiDiff: ansi_diff_1.AnsiDiff,
34
35
  formatBytes: studio_shared_1.formatBytes,
35
36
  parseAndApplyCodemod: duplicate_composition_1.parseAndApplyCodemod,
37
+ applyCodemodToFile: apply_codemod_to_file_1.applyCodemodToFile,
36
38
  formatOutput: duplicate_composition_1.formatOutput,
37
39
  updateDefaultProps: update_default_props_1.updateDefaultProps,
38
40
  getInstalledDependencies: get_installed_dependencies_1.getInstalledDependencies,
@@ -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
  }
@@ -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,
@@ -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, undefined);
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,
@@ -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
  }
@@ -44,7 +43,7 @@ const getPropsFromObjectExpression = ({ objExpr, keys, }) => {
44
43
  }
45
44
  const valueExpr = prop.value;
46
45
  if (!(0, can_update_sequence_props_1.isStaticValue)(valueExpr)) {
47
- out[key] = { canUpdate: false, reason: 'computed' };
46
+ out[key] = (0, can_update_sequence_props_1.getComputedStatus)(valueExpr);
48
47
  continue;
49
48
  }
50
49
  out[key] = {
@@ -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 {
@@ -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)) {
@@ -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;
@@ -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;
@@ -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;
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.464",
6
+ "version": "4.0.466",
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.464",
30
+ "remotion": "4.0.466",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.464",
33
- "@remotion/renderer": "4.0.464",
34
- "@remotion/studio-shared": "4.0.464",
32
+ "@remotion/bundler": "4.0.466",
33
+ "@remotion/renderer": "4.0.466",
34
+ "@remotion/studio-shared": "4.0.466",
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.464",
42
+ "@remotion/eslint-config-internal": "4.0.466",
43
43
  "eslint": "9.19.0",
44
44
  "@types/node": "20.12.14",
45
45
  "@typescript/native-preview": "7.0.0-dev.20260217.1"