@remotion/studio-server 4.0.518 → 4.0.520

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 (30) hide show
  1. package/dist/codemods/delete-jsx-node.d.ts +1 -4
  2. package/dist/codemods/duplicate-jsx-node.d.ts +11 -0
  3. package/dist/codemods/duplicate-jsx-node.js +11 -1
  4. package/dist/codemods/get-node-path-remappings.d.ts +1 -0
  5. package/dist/codemods/get-node-path-remappings.js +15 -2
  6. package/dist/codemods/split-video-from-audio.d.ts +1 -4
  7. package/dist/helpers/open-in-editor.js +1 -1
  8. package/dist/preview-server/api-routes.js +2 -0
  9. package/dist/preview-server/element-install-state.d.ts +0 -1
  10. package/dist/preview-server/element-install-state.js +1 -2
  11. package/dist/preview-server/routes/delete-jsx-node.js +0 -1
  12. package/dist/preview-server/routes/duplicate-jsx-node.js +71 -39
  13. package/dist/preview-server/routes/element-install-plan.d.ts +5 -11
  14. package/dist/preview-server/routes/element-install-plan.js +22 -9
  15. package/dist/preview-server/routes/insert-element.js +18 -10
  16. package/dist/preview-server/routes/insert-jsx-element.js +0 -1
  17. package/dist/preview-server/routes/prepare-element-install.js +7 -2
  18. package/dist/preview-server/routes/release-notes.d.ts +3 -0
  19. package/dist/preview-server/routes/release-notes.js +127 -0
  20. package/dist/preview-server/routes/reorder-sequence.js +0 -1
  21. package/dist/preview-server/routes/split-jsx-sequence.js +0 -1
  22. package/dist/preview-server/routes/split-video-from-audio.js +0 -1
  23. package/dist/preview-server/sequence-node-path-mutation.d.ts +0 -2
  24. package/dist/preview-server/start-server.js +9 -5
  25. package/dist/preview-server/studio-protocol/handle-discovery.js +2 -3
  26. package/dist/preview-server/studio-protocol/handle-element-library.js +6 -14
  27. package/dist/preview-server/studio-protocol/handle-install.js +16 -25
  28. package/dist/preview-server/studio-protocol/handle-license-key.js +5 -13
  29. package/dist/preview-server/undo-stack.js +4 -13
  30. package/package.json +8 -8
@@ -9,10 +9,7 @@ export declare const deleteJsxNodes: ({ input, nodePaths, }: {
9
9
  formatted: boolean;
10
10
  nodeLabels: string[];
11
11
  logLines: number[];
12
- nodePathRemappings: {
13
- oldNodePath: SequenceNodePath;
14
- newNodePath: SequenceNodePath | null;
15
- }[];
12
+ nodePathRemappings: import("@remotion/studio-shared").SequenceNodePathRemapping[];
16
13
  }>;
17
14
  export declare const deleteJsxNode: ({ input, nodePath, }: {
18
15
  input: string;
@@ -12,3 +12,14 @@ export declare const duplicateJsxNode: ({ input, nodePath, prettierConfigOverrid
12
12
  logLine: number;
13
13
  nodePathRemappings: import("@remotion/studio-shared").SequenceNodePathRemapping[];
14
14
  }>;
15
+ export declare const duplicateJsxNodes: ({ input, nodePaths, prettierConfigOverride, }: {
16
+ input: string;
17
+ nodePaths: SequenceNodePath[];
18
+ prettierConfigOverride?: Record<string, unknown> | null | undefined;
19
+ }) => Promise<{
20
+ output: string;
21
+ formatted: boolean;
22
+ nodeLabels: string[];
23
+ logLines: number[];
24
+ nodePathRemappings: import("@remotion/studio-shared").SequenceNodePathRemapping[];
25
+ }>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.duplicateJsxNode = exports.duplicateJsxElementAtPath = void 0;
3
+ exports.duplicateJsxNodes = exports.duplicateJsxNode = exports.duplicateJsxElementAtPath = void 0;
4
4
  const studio_codemods_1 = require("@remotion/studio-codemods");
5
5
  Object.defineProperty(exports, "duplicateJsxElementAtPath", { enumerable: true, get: function () { return studio_codemods_1.duplicateJsxElementAtPath; } });
6
6
  const format_file_content_1 = require("./format-file-content");
@@ -14,3 +14,13 @@ const duplicateJsxNode = ({ input, nodePath, prettierConfigOverride, }) => (0, s
14
14
  prettierConfigOverride,
15
15
  });
16
16
  exports.duplicateJsxNode = duplicateJsxNode;
17
+ const duplicateJsxNodes = ({ input, nodePaths, prettierConfigOverride, }) => (0, studio_codemods_1.duplicateJsxNodes)({
18
+ input,
19
+ nodePaths,
20
+ formatFile: ({ contents, prettierConfigOverride: override }) => (0, format_file_content_1.formatFileContent)({
21
+ input: contents,
22
+ prettierConfigOverride: override,
23
+ }),
24
+ prettierConfigOverride,
25
+ });
26
+ exports.duplicateJsxNodes = duplicateJsxNodes;
@@ -4,6 +4,7 @@ import type { SequenceNodePath } from 'remotion';
4
4
  export type CapturedJsxNodePath = {
5
5
  node: JSXOpeningElement;
6
6
  nodePath: SequenceNodePath;
7
+ signature: string;
7
8
  };
8
9
  export declare const captureJsxNodePaths: (ast: File) => CapturedJsxNodePath[];
9
10
  export declare const getNodePathRemappings: ({ ast, captured, output, }: {
@@ -44,6 +44,7 @@ const captureJsxNodePaths = (ast) => {
44
44
  captured.push({
45
45
  node: path.node,
46
46
  nodePath: (0, can_update_sequence_props_1.getNodePathForRecastPath)(path, ast),
47
+ signature: recast.prettyPrint(path.node).code,
47
48
  });
48
49
  return this.traverse(path);
49
50
  },
@@ -74,15 +75,27 @@ const getNodePathRemappings = ({ ast, captured, output, }) => {
74
75
  for (let i = 0; i < nodesAfterMutation.length; i++) {
75
76
  finalNodePathByNode.set(nodesAfterMutation[i], finalNodePaths[i]);
76
77
  }
77
- const nodePathRemappings = captured.flatMap(({ node, nodePath }) => {
78
+ const capturedNodes = new Set(captured.map(({ node }) => node));
79
+ const nodePathRemappings = captured.flatMap(({ node, nodePath, signature }) => {
78
80
  var _a;
79
81
  const newNodePath = (_a = finalNodePathByNode.get(node)) !== null && _a !== void 0 ? _a : null;
80
82
  if (newNodePath !== null &&
81
- JSON.stringify(nodePath) === JSON.stringify(newNodePath)) {
83
+ JSON.stringify(nodePath) === JSON.stringify(newNodePath) &&
84
+ recast.prettyPrint(node).code === signature) {
82
85
  return [];
83
86
  }
84
87
  return [{ oldNodePath: nodePath, newNodePath }];
85
88
  });
89
+ for (const node of nodesAfterMutation) {
90
+ if (capturedNodes.has(node)) {
91
+ continue;
92
+ }
93
+ const newNodePath = finalNodePathByNode.get(node);
94
+ if (!newNodePath) {
95
+ throw new Error('Could not map inserted JSX node path');
96
+ }
97
+ nodePathRemappings.push({ oldNodePath: null, newNodePath });
98
+ }
86
99
  return { finalNodePathByNode, nodePathRemappings };
87
100
  };
88
101
  exports.getNodePathRemappings = getNodePathRemappings;
@@ -8,8 +8,5 @@ export declare const splitVideoFromAudio: ({ input, nodePath, prettierConfigOver
8
8
  formatted: boolean;
9
9
  nodeLabel: string;
10
10
  logLine: number;
11
- nodePathRemappings: {
12
- oldNodePath: SequenceNodePath;
13
- newNodePath: SequenceNodePath | null;
14
- }[];
11
+ nodePathRemappings: import("@remotion/studio-shared").SequenceNodePathRemapping[];
15
12
  }>;
@@ -255,7 +255,7 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, colNumber) {
255
255
  editor.endsWith('/Zed Preview.app/Contents/MacOS/cli');
256
256
  const isFolder = node_fs_1.default.existsSync(fileName) && node_fs_1.default.lstatSync(fileName).isDirectory();
257
257
  if (isZedEditor) {
258
- return [fileName + ':' + lineNumber + ':' + colNumber];
258
+ return ['--existing', fileName + ':' + lineNumber + ':' + colNumber];
259
259
  }
260
260
  switch (editorBasename) {
261
261
  case 'atom':
@@ -37,6 +37,7 @@ const prepare_element_install_1 = require("./routes/prepare-element-install");
37
37
  const project_info_1 = require("./routes/project-info");
38
38
  const redo_1 = require("./routes/redo");
39
39
  const register_client_render_1 = require("./routes/register-client-render");
40
+ const release_notes_1 = require("./routes/release-notes");
40
41
  const remotion_skills_info_1 = require("./routes/remotion-skills-info");
41
42
  const remove_render_1 = require("./routes/remove-render");
42
43
  const rename_static_file_1 = require("./routes/rename-static-file");
@@ -107,6 +108,7 @@ exports.allApiRoutes = {
107
108
  '/api/split-jsx-sequence': split_jsx_sequence_1.splitJsxSequenceHandler,
108
109
  '/api/split-video-from-audio': split_video_from_audio_1.splitVideoFromAudioHandler,
109
110
  '/api/update-available': update_available_1.handleUpdate,
111
+ '/api/release-notes': release_notes_1.getReleaseNotesHandler,
110
112
  '/api/remotion-skills-info': remotion_skills_info_1.remotionSkillsInfoHandler,
111
113
  '/api/project-info': project_info_1.projectInfoHandler,
112
114
  '/api/delete-static-file': delete_static_file_1.deleteStaticFileHandler,
@@ -5,7 +5,6 @@ export type ElementInstallTarget = {
5
5
  clientId: string;
6
6
  compositionFile: string | null;
7
7
  compositionId: string | null;
8
- canInstall: boolean;
9
8
  lastFocusedAt: number | null;
10
9
  readOnly: boolean;
11
10
  studioUrl: string;
@@ -80,8 +80,7 @@ const consumeStudioProtocolTarget = ({ now, origin, purpose, targetId, }) => {
80
80
  if (purpose !== 'install-element') {
81
81
  return issued.target;
82
82
  }
83
- if (!current.canInstall ||
84
- current.compositionFile !== issued.target.compositionFile ||
83
+ if (current.compositionFile !== issued.target.compositionFile ||
85
84
  current.compositionId !== issued.target.compositionId) {
86
85
  return null;
87
86
  }
@@ -65,7 +65,6 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
65
65
  const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
66
66
  absolutePath: update.absolutePath,
67
67
  remappings: update.nodePathRemappings,
68
- restoredNodePaths: [],
69
68
  })));
70
69
  for (const update of updates) {
71
70
  const deletedNodeDescription = getDeletedNodeDescription(update.nodeLabels);
@@ -11,56 +11,88 @@ const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
11
11
  const undo_stack_1 = require("../undo-stack");
12
12
  const log_update_1 = require("./log-updates/log-update");
13
13
  const source_file_write_queue_1 = require("./source-file-write-queue");
14
- const duplicateJsxNodeHandler = ({ input: { fileName, nodePath }, remotionRoot, logLevel }) => {
14
+ const duplicateJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
15
15
  return (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
16
+ var _a;
16
17
  try {
17
- renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[duplicate-jsx-node] Received request for fileName="${fileName}"`);
18
- const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
19
- remotionRoot,
20
- fileName,
21
- action: 'modify',
22
- });
23
- const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
24
- const { output, formatted, nodeLabel, logLine, nodePathRemappings } = await (0, duplicate_jsx_node_1.duplicateJsxNode)({ input: fileContents, nodePath });
25
- const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)([
26
- {
18
+ if (nodes.length === 0) {
19
+ throw new Error('No JSX nodes were specified for duplication');
20
+ }
21
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[duplicate-jsx-node] Received request to duplicate ${nodes.length} JSX node${nodes.length === 1 ? '' : 's'}`);
22
+ const itemsByFileName = new Map();
23
+ for (const item of nodes) {
24
+ const fileItems = (_a = itemsByFileName.get(item.fileName)) !== null && _a !== void 0 ? _a : [];
25
+ fileItems.push(item);
26
+ itemsByFileName.set(item.fileName, fileItems);
27
+ }
28
+ const updates = await Promise.all([...itemsByFileName.entries()].map(async ([fileName, fileItems]) => {
29
+ const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
30
+ remotionRoot,
31
+ fileName,
32
+ action: 'modify',
33
+ });
34
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
35
+ const { output, formatted, nodeLabels, logLines, nodePathRemappings } = await (0, duplicate_jsx_node_1.duplicateJsxNodes)({
36
+ input: fileContents,
37
+ nodePaths: fileItems.map((item) => item.nodePath),
38
+ });
39
+ return {
27
40
  absolutePath,
28
- remappings: nodePathRemappings,
29
- restoredNodePaths: [],
30
- },
31
- ]);
32
- (0, undo_stack_1.pushToUndoStack)({
33
- filePath: absolutePath,
34
- oldContents: fileContents,
35
- newContents: null,
41
+ fileRelativeToRoot,
42
+ fileContents,
43
+ formatted,
44
+ logLine: Math.min(...logLines),
45
+ nodeLabels,
46
+ nodePathRemappings,
47
+ output,
48
+ };
49
+ }));
50
+ const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
51
+ absolutePath: update.absolutePath,
52
+ remappings: update.nodePathRemappings,
53
+ })));
54
+ const duplicatedNodeDescription = nodes.length === 1
55
+ ? updates[0].nodeLabels[0]
56
+ : `${nodes.length} JSX nodes`;
57
+ (0, undo_stack_1.pushTransactionToUndoStack)({
58
+ snapshots: updates.map((update) => ({
59
+ filePath: update.absolutePath,
60
+ oldContents: update.fileContents,
61
+ newContents: null,
62
+ logLine: update.logLine,
63
+ nodePathRemappings: update.nodePathRemappings,
64
+ })),
36
65
  logLevel,
37
66
  remotionRoot,
38
- logLine,
39
67
  description: {
40
- undoMessage: `↩️ Duplication of ${nodeLabel}`,
41
- redoMessage: `↪️ Duplication of ${nodeLabel}`,
68
+ undoMessage: `↩️ Duplication of ${duplicatedNodeDescription}`,
69
+ redoMessage: `↪️ Duplication of ${duplicatedNodeDescription}`,
42
70
  },
43
71
  entryType: 'duplicate-jsx-node',
44
72
  suppressHmrOnFileRestore: false,
45
- nodePathRemappings,
46
- });
47
- (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
48
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
49
- file: absolutePath,
50
- content: output,
51
- originatorClientId: undefined,
52
- metadata: { skipSequencePropsUpdate: true },
53
- });
54
- const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
55
- remotionRoot,
56
- absolutePath,
57
- line: logLine,
58
73
  });
59
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${nodeLabel}`);
60
- if (!formatted) {
61
- (0, log_update_1.warnAboutPrettierOnce)(logLevel);
74
+ for (const update of updates) {
75
+ (0, undo_stack_1.suppressUndoStackInvalidation)(update.absolutePath);
76
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
77
+ file: update.absolutePath,
78
+ content: update.output,
79
+ originatorClientId: undefined,
80
+ metadata: { skipSequencePropsUpdate: true },
81
+ });
82
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
83
+ remotionRoot,
84
+ absolutePath: update.absolutePath,
85
+ line: update.logLine,
86
+ });
87
+ const fileDescription = update.nodeLabels.length === 1
88
+ ? update.nodeLabels[0]
89
+ : `${update.nodeLabels.length} JSX nodes`;
90
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Duplicated ${fileDescription}`);
91
+ if (!update.formatted) {
92
+ (0, log_update_1.warnAboutPrettierOnce)(logLevel);
93
+ }
94
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[duplicate-jsx-node] Wrote ${update.fileRelativeToRoot}${update.formatted ? ' (formatted)' : ''}`);
62
95
  }
63
- renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[duplicate-jsx-node] Wrote ${fileRelativeToRoot}${formatted ? ' (formatted)' : ''}`);
64
96
  (0, undo_stack_1.printUndoHint)(logLevel);
65
97
  return {
66
98
  success: true,
@@ -2,30 +2,24 @@ import type { ElementInstallExpectedFileState, PrepareElementInstallRequest } fr
2
2
  export declare const normalizeElementSourceForComparison: (source: string) => string;
3
3
  export declare const getElementSourceHash: (source: string) => string;
4
4
  export declare const validateElementInstallPosition: (position: import("@remotion/studio-shared").InsertableCompositionElementPosition | null) => void;
5
- export declare const validateElementForInstallation: (element: {
6
- dependencies: import("@remotion/studio-protocol").ElementDependency[];
7
- durationInFrames?: number | undefined;
8
- installationMode?: import("@remotion/studio-protocol").ElementInstallationMode | undefined;
9
- slug: string;
10
- displayName: string;
11
- sourceCode: string;
12
- dimensions: import("@remotion/studio-protocol").ComponentDimensions | null;
13
- }) => void;
5
+ export declare const validateElementForInstallation: (element: import("@remotion/studio-shared").InstallableElement) => void;
14
6
  export declare const makeRelativeElementImportPath: ({ fromFile, toFile, }: {
15
7
  fromFile: string;
16
8
  toFile: string;
17
9
  }) => string;
18
- export declare const getElementInstallPlan: ({ compositionFile, compositionId, element, remotionRoot, }: PrepareElementInstallRequest & {
10
+ export declare const getElementInstallPlan: ({ destination, element, entryPoint, remotionRoot, }: PrepareElementInstallRequest & {
11
+ entryPoint: string;
19
12
  remotionRoot: string;
20
13
  }) => Promise<{
21
14
  componentName: string;
15
+ destinationCompositionFileName: string;
22
16
  elementFileExists: boolean;
23
17
  elementFileName: string;
24
18
  existingElementSource: string | null;
25
19
  expectedFileState: ElementInstallExpectedFileState;
26
20
  filePath: string;
27
21
  importPath: string;
28
- location: import("@remotion/studio-codemods").ResolvedCompositionComponentWithFile;
22
+ location: import("@remotion/studio-codemods").ResolvedCompositionComponentWithFile | null;
29
23
  safePaths: {
30
24
  compositionFileName: string;
31
25
  elementFileName: string;
@@ -9,6 +9,7 @@ const node_fs_1 = require("node:fs");
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const studio_protocol_1 = require("@remotion/studio-protocol");
11
11
  const resolve_composition_component_1 = require("../../helpers/resolve-composition-component");
12
+ const project_info_1 = require("../project-info");
12
13
  const safe_element_install_path_1 = require("./safe-element-install-path");
13
14
  const normalizeElementSourceForComparison = (source) => {
14
15
  return source.replace(/\r\n/g, '\n').trim();
@@ -74,27 +75,38 @@ const getExpectedFileState = (existingSource) => {
74
75
  sourceHash: (0, exports.getElementSourceHash)(existingSource),
75
76
  };
76
77
  };
77
- const getElementInstallPlan = async ({ compositionFile, compositionId, element, remotionRoot, }) => {
78
+ const getElementInstallPlan = async ({ destination, element, entryPoint, remotionRoot, }) => {
79
+ var _a;
78
80
  (0, exports.validateElementForInstallation)(element);
79
81
  const componentName = studio_protocol_1.StudioProtocolInternals.getElementComponentNameFromSourceCode(element.sourceCode);
80
82
  if (componentName === null) {
81
83
  throw new Error('Element source must export exactly one named component');
82
84
  }
83
- const location = await (0, resolve_composition_component_1.resolveCompositionComponentWithFile)({
84
- remotionRoot,
85
- compositionFile,
86
- compositionId,
87
- });
88
- if (!location.canAddSequence) {
85
+ const location = destination.type === 'current-composition'
86
+ ? await (0, resolve_composition_component_1.resolveCompositionComponentWithFile)({
87
+ remotionRoot,
88
+ compositionFile: destination.compositionFile,
89
+ compositionId: destination.compositionId,
90
+ })
91
+ : null;
92
+ if (location !== null && !location.canAddSequence) {
89
93
  throw new Error('Cannot insert Element into this composition component');
90
94
  }
91
95
  const derivedElementFileName = studio_protocol_1.StudioProtocolInternals.makeElementFileNameFromSlug(element.slug);
92
96
  if (derivedElementFileName === null) {
93
97
  throw new Error('Element slug must produce a safe lowercase .tsx file name');
94
98
  }
99
+ const destinationCompositionFile = destination.compositionFile;
100
+ const destinationCompositionFileName = destinationCompositionFile === null
101
+ ? (await (0, project_info_1.getProjectInfo)(remotionRoot, entryPoint)).rootFile
102
+ : node_path_1.default.resolve(remotionRoot, destinationCompositionFile);
103
+ if (destinationCompositionFileName === null) {
104
+ throw new Error('Could not find the root file of the project');
105
+ }
106
+ const compositionFileName = (_a = location === null || location === void 0 ? void 0 : location.fileName) !== null && _a !== void 0 ? _a : destinationCompositionFileName;
95
107
  const safePaths = await (0, safe_element_install_path_1.getSafeElementInstallPaths)({
96
- compositionFileName: location.fileName,
97
- elementFileName: node_path_1.default.resolve(node_path_1.default.dirname(location.fileName), derivedElementFileName),
108
+ compositionFileName,
109
+ elementFileName: node_path_1.default.resolve(node_path_1.default.dirname(compositionFileName), derivedElementFileName),
98
110
  remotionRoot,
99
111
  });
100
112
  const elementFileExists = (0, node_fs_1.existsSync)(safePaths.elementFileName);
@@ -103,6 +115,7 @@ const getElementInstallPlan = async ({ compositionFile, compositionId, element,
103
115
  : null;
104
116
  return {
105
117
  componentName,
118
+ destinationCompositionFileName,
106
119
  elementFileExists,
107
120
  elementFileName: safePaths.elementFileName,
108
121
  existingElementSource,
@@ -22,21 +22,26 @@ const hasExpectedFileState = ({ expected, actual, }) => {
22
22
  }
23
23
  return actual.sourceHash === expected.sourceHash;
24
24
  };
25
- const insertElementHandler = ({ input: { compositionFile, compositionId, element, expectedFileState, from, position, overwriteExisting, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
26
- var _a, _b;
25
+ const insertElementHandler = ({ input: { compositionFile, compositionId, element, expectedFileState, from, position, overwriteExisting, }, entryPoint, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
27
26
  try {
28
27
  (0, element_install_plan_1.validateElementInstallPosition)(position);
29
28
  if (from !== null &&
30
29
  (!Number.isInteger(from) || !Number.isFinite(from) || from < 0)) {
31
30
  throw new Error('from must be a non-negative integer');
32
31
  }
33
- const installationMode = (_a = element.installationMode) !== null && _a !== void 0 ? _a : 'wrapped';
32
+ const installationMode = element.installationMode === null
33
+ ? 'wrapped'
34
+ : element.installationMode;
34
35
  const componentOwnsSequence = installationMode === 'component-owned-sequence';
35
36
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[insert-element] Received request for compositionFile="${compositionFile}" compositionId="${compositionId}" element="${element.slug}"`);
36
37
  const plan = await (0, element_install_plan_1.getElementInstallPlan)({
37
- compositionFile,
38
- compositionId,
38
+ destination: {
39
+ type: 'current-composition',
40
+ compositionFile,
41
+ compositionId,
42
+ },
39
43
  element,
44
+ entryPoint,
40
45
  remotionRoot,
41
46
  });
42
47
  if (expectedFileState !== null &&
@@ -86,7 +91,7 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
86
91
  importPath: plan.importPath,
87
92
  props: componentOwnsSequence
88
93
  ? [
89
- ...(element.durationInFrames === undefined
94
+ ...(element.durationInFrames === null
90
95
  ? []
91
96
  : [
92
97
  {
@@ -105,16 +110,20 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
105
110
  ? null
106
111
  : {
107
112
  dimensions: element.dimensions,
108
- durationInFrames: (_b = element.durationInFrames) !== null && _b !== void 0 ? _b : null,
113
+ durationInFrames: element.durationInFrames,
109
114
  from,
110
115
  name: element.displayName,
111
116
  position,
112
117
  },
113
118
  });
114
119
  const finalPlan = await (0, element_install_plan_1.getElementInstallPlan)({
115
- compositionFile,
116
- compositionId,
120
+ destination: {
121
+ type: 'current-composition',
122
+ compositionFile,
123
+ compositionId,
124
+ },
117
125
  element,
126
+ entryPoint,
118
127
  remotionRoot,
119
128
  });
120
129
  if (finalPlan.safePaths.compositionFileName !==
@@ -131,7 +140,6 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
131
140
  {
132
141
  absolutePath: inserted.fileName,
133
142
  remappings: inserted.nodePathRemappings,
134
- restoredNodePaths: [],
135
143
  },
136
144
  ]);
137
145
  (0, undo_stack_1.pushTransactionToUndoStack)({
@@ -171,7 +171,6 @@ const insertJsxElementHandler = ({ input: { compositionFile, compositionId, elem
171
171
  {
172
172
  absolutePath: fileName,
173
173
  remappings: nodePathRemappings,
174
- restoredNodePaths: [],
175
174
  },
176
175
  ]);
177
176
  if (insertedNodePath === null) {
@@ -3,12 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prepareElementInstallHandler = void 0;
4
4
  const element_install_plan_1 = require("./element-install-plan");
5
5
  const source_file_write_queue_1 = require("./source-file-write-queue");
6
- const prepareElementInstallHandler = ({ input, remotionRoot }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
6
+ const prepareElementInstallHandler = ({ entryPoint, input, remotionRoot }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
7
7
  try {
8
- const plan = await (0, element_install_plan_1.getElementInstallPlan)({ ...input, remotionRoot });
8
+ const plan = await (0, element_install_plan_1.getElementInstallPlan)({
9
+ ...input,
10
+ entryPoint,
11
+ remotionRoot,
12
+ });
9
13
  return {
10
14
  success: true,
11
15
  plan: {
16
+ compositionFile: plan.destinationCompositionFileName,
12
17
  expectedFileState: plan.expectedFileState,
13
18
  filePath: plan.filePath,
14
19
  },
@@ -0,0 +1,3 @@
1
+ import type { GetReleaseNotesRequest, GetReleaseNotesResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const getReleaseNotesHandler: ApiHandler<GetReleaseNotesRequest, GetReleaseNotesResponse>;
@@ -0,0 +1,127 @@
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.getReleaseNotesHandler = void 0;
7
+ const semver_1 = __importDefault(require("semver"));
8
+ const githubApiVersion = '2022-11-28';
9
+ const releaseNotesTimeout = 5000;
10
+ const releaseNotesCacheDuration = 5 * 60 * 1000;
11
+ const maximumReleaseNotes = 5;
12
+ const releaseNotesCache = new Map();
13
+ const getReleaseNotesHandler = async ({ input }) => {
14
+ const currentVersion = semver_1.default.valid(input.currentVersion);
15
+ const latestVersion = semver_1.default.valid(input.latestVersion);
16
+ if (currentVersion === null || latestVersion === null) {
17
+ throw new Error(`Invalid Remotion version range: ${input.currentVersion} to ${input.latestVersion}`);
18
+ }
19
+ const cacheKey = `${currentVersion}:${latestVersion}`;
20
+ const cachedReleaseNotes = releaseNotesCache.get(cacheKey);
21
+ if (cachedReleaseNotes && cachedReleaseNotes.expiresAt > Date.now()) {
22
+ return cachedReleaseNotes.response;
23
+ }
24
+ const controller = new AbortController();
25
+ const timeout = setTimeout(() => controller.abort(), releaseNotesTimeout);
26
+ try {
27
+ const releaseResponse = await fetch('https://api.github.com/repos/remotion-dev/remotion/releases?per_page=100', {
28
+ headers: {
29
+ accept: 'application/vnd.github+json',
30
+ 'user-agent': 'Remotion Studio',
31
+ 'x-github-api-version': githubApiVersion,
32
+ },
33
+ signal: controller.signal,
34
+ });
35
+ if (!releaseResponse.ok) {
36
+ return { hasMore: false, releases: [] };
37
+ }
38
+ const githubReleases = (await releaseResponse.json());
39
+ if (!Array.isArray(githubReleases)) {
40
+ return { hasMore: false, releases: [] };
41
+ }
42
+ const matchingReleases = githubReleases
43
+ .flatMap((release) => {
44
+ if (typeof release !== 'object' || release === null) {
45
+ return [];
46
+ }
47
+ const { body, published_at: publishedAt, tag_name: tagName, } = release;
48
+ if (typeof tagName !== 'string') {
49
+ return [];
50
+ }
51
+ const version = semver_1.default.valid(tagName.startsWith('v') ? tagName.slice(1) : tagName);
52
+ if (version === null ||
53
+ !semver_1.default.gt(version, currentVersion) ||
54
+ !semver_1.default.lte(version, latestVersion)) {
55
+ return [];
56
+ }
57
+ return [
58
+ {
59
+ body: typeof body === 'string' ? body : null,
60
+ publishedAt: typeof publishedAt === 'string' ? publishedAt : null,
61
+ version,
62
+ },
63
+ ];
64
+ })
65
+ .sort((a, b) => semver_1.default.rcompare(a.version, b.version));
66
+ const hasMore = matchingReleases.length > maximumReleaseNotes;
67
+ const releases = await Promise.all(matchingReleases.slice(0, maximumReleaseNotes).map(async (release) => {
68
+ if (release.body === null || release.body.trim() === '') {
69
+ return {
70
+ publishedAt: release.publishedAt,
71
+ releaseNotesHtml: null,
72
+ version: release.version,
73
+ };
74
+ }
75
+ try {
76
+ const markdownResponse = await fetch('https://api.github.com/markdown', {
77
+ body: JSON.stringify({
78
+ context: 'remotion-dev/remotion',
79
+ mode: 'gfm',
80
+ text: release.body,
81
+ }),
82
+ headers: {
83
+ accept: 'text/html',
84
+ 'content-type': 'application/json',
85
+ 'user-agent': 'Remotion Studio',
86
+ 'x-github-api-version': githubApiVersion,
87
+ },
88
+ method: 'POST',
89
+ signal: controller.signal,
90
+ });
91
+ if (!markdownResponse.ok) {
92
+ return {
93
+ publishedAt: release.publishedAt,
94
+ releaseNotesHtml: null,
95
+ version: release.version,
96
+ };
97
+ }
98
+ const releaseNotesHtml = await markdownResponse.text();
99
+ return {
100
+ publishedAt: release.publishedAt,
101
+ releaseNotesHtml: releaseNotesHtml || null,
102
+ version: release.version,
103
+ };
104
+ }
105
+ catch (_a) {
106
+ return {
107
+ publishedAt: release.publishedAt,
108
+ releaseNotesHtml: null,
109
+ version: release.version,
110
+ };
111
+ }
112
+ }));
113
+ const response = { hasMore, releases };
114
+ releaseNotesCache.set(cacheKey, {
115
+ expiresAt: Date.now() + releaseNotesCacheDuration,
116
+ response,
117
+ });
118
+ return response;
119
+ }
120
+ catch (_a) {
121
+ return { hasMore: false, releases: [] };
122
+ }
123
+ finally {
124
+ clearTimeout(timeout);
125
+ }
126
+ };
127
+ exports.getReleaseNotesHandler = getReleaseNotesHandler;
@@ -32,7 +32,6 @@ const reorderSequenceHandler = ({ input: { fileName, sourceNodePath, targetNodeP
32
32
  {
33
33
  absolutePath,
34
34
  remappings: nodePathRemappings,
35
- restoredNodePaths: [],
36
35
  },
37
36
  ]);
38
37
  (0, undo_stack_1.pushToUndoStack)({
@@ -30,7 +30,6 @@ const splitJsxSequenceHandler = ({ input: { fileName, nodePath, sequenceKeys, sp
30
30
  {
31
31
  absolutePath,
32
32
  remappings: nodePathRemappings,
33
- restoredNodePaths: [],
34
33
  },
35
34
  ]);
36
35
  (0, undo_stack_1.pushToUndoStack)({
@@ -28,7 +28,6 @@ const splitVideoFromAudioHandler = ({ input: { fileName, nodePath }, remotionRoo
28
28
  {
29
29
  absolutePath,
30
30
  remappings: nodePathRemappings,
31
- restoredNodePaths: [],
32
31
  },
33
32
  ]);
34
33
  (0, undo_stack_1.pushToUndoStack)({
@@ -1,7 +1,5 @@
1
1
  import type { SequenceNodePathMutation, SequenceNodePathRemapping } from '@remotion/studio-shared';
2
- import type { SequenceNodePath } from 'remotion';
3
2
  export declare const broadcastSequenceNodePathMutation: (files: {
4
3
  absolutePath: string;
5
4
  remappings: SequenceNodePathRemapping[];
6
- restoredNodePaths: SequenceNodePath[];
7
5
  }[]) => SequenceNodePathMutation;
@@ -19,16 +19,20 @@ const startServer = async (options) => {
19
19
  var _a, _b;
20
20
  const desiredPort = (_b = (_a = options === null || options === void 0 ? void 0 : options.port) !== null && _a !== void 0 ? _a : (process.env.PORT ? Number(process.env.PORT) : undefined)) !== null && _b !== void 0 ? _b : undefined;
21
21
  const portConfig = renderer_1.RenderInternals.getPortConfig(options.forceIPv4);
22
- const onPortUnavailable = options.forceNew
23
- ? undefined
24
- : async (port) => {
22
+ const onPortUnavailable = async (port) => {
23
+ if (!options.forceNew) {
25
24
  const detection = await (0, detect_remotion_server_1.detectRemotionServer)({
26
25
  port,
27
26
  cwd: options.remotionRoot,
28
27
  hostname: portConfig.hostsToTry[0],
29
28
  });
30
- return detection.type === 'match' ? 'stop' : 'continue';
31
- };
29
+ if (detection.type === 'match') {
30
+ return 'stop';
31
+ }
32
+ }
33
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel: options.logLevel }, renderer_1.RenderInternals.chalk.gray(`Port ${port} is busy, trying another.`));
34
+ return 'continue';
35
+ };
32
36
  let portSelection = await renderer_1.RenderInternals.getDesiredPort({
33
37
  desiredPort,
34
38
  from: 3000,
@@ -32,8 +32,7 @@ const getLiveStudioTarget = (requestId) => {
32
32
  }
33
33
  return target;
34
34
  };
35
- const isInstallableTarget = (target) => target !== null &&
36
- target.canInstall &&
35
+ const isElementRequestTarget = (target) => target !== null &&
37
36
  target.compositionFile !== null &&
38
37
  target.compositionId !== null &&
39
38
  target.lastFocusedAt !== null;
@@ -68,7 +67,7 @@ const handleStudioProtocolDiscovery = ({ gitSource, liveEventsServer, remotionRo
68
67
  setTimeout(() => {
69
68
  const now = Date.now();
70
69
  const target = getLiveStudioTarget(requestId);
71
- const installTarget = isInstallableTarget(target) ? target : null;
70
+ const installTarget = isElementRequestTarget(target) ? target : null;
72
71
  const issuedInstallTarget = installTarget === null
73
72
  ? null
74
73
  : (0, element_install_state_1.issueStudioProtocolTarget)({
@@ -1,19 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleStudioProtocolElementLibrary = void 0;
4
- const zod_1 = require("zod");
4
+ const studio_protocol_1 = require("@remotion/studio-protocol");
5
5
  const element_install_state_1 = require("../element-install-state");
6
6
  const parse_body_1 = require("../parse-body");
7
7
  const origin_policy_1 = require("./origin-policy");
8
8
  const protocol_response_1 = require("./protocol-response");
9
- const studioProtocolElementLibraryRequestSchema = zod_1.z.object({
10
- operation: zod_1.z.literal('add-element-library'),
11
- protocol: zod_1.z.literal('remotion-studio-protocol'),
12
- protocolVersion: zod_1.z.literal(1),
13
- targetId: zod_1.z.string().min(1),
14
- url: zod_1.z.string(),
15
- displayName: zod_1.z.string().nullable(),
16
- });
17
9
  const MAX_STUDIO_PROTOCOL_ELEMENT_LIBRARY_BODY_SIZE = 16 * 1024;
18
10
  const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab, liveEventsServer, request, response, }) => {
19
11
  var _a;
@@ -62,8 +54,8 @@ const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab,
62
54
  });
63
55
  return;
64
56
  }
65
- const parsedRequest = studioProtocolElementLibraryRequestSchema.safeParse(body);
66
- if (!parsedRequest.success) {
57
+ const parsedRequest = studio_protocol_1.StudioProtocolInternals.parseStudioProtocolAddElementLibraryRequest(body);
58
+ if (parsedRequest === null) {
67
59
  (0, protocol_response_1.writeStudioProtocolError)({
68
60
  code: 'unsupported-protocol',
69
61
  message: 'Invalid Remotion Studio Protocol request.',
@@ -74,7 +66,7 @@ const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab,
74
66
  }
75
67
  let normalizedUrl;
76
68
  try {
77
- const parsedUrl = new URL(parsedRequest.data.url);
69
+ const parsedUrl = new URL(parsedRequest.url);
78
70
  if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
79
71
  throw new Error('Unsupported protocol');
80
72
  }
@@ -89,7 +81,7 @@ const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab,
89
81
  });
90
82
  return;
91
83
  }
92
- const displayName = (_b = (_a = parsedRequest.data.displayName) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
84
+ const displayName = (_b = (_a = parsedRequest.displayName) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
93
85
  if (displayName === '') {
94
86
  (0, protocol_response_1.writeStudioProtocolError)({
95
87
  code: 'invalid-display-name',
@@ -103,7 +95,7 @@ const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab,
103
95
  now: Date.now(),
104
96
  origin: requestOrigin,
105
97
  purpose: 'add-element-library',
106
- targetId: parsedRequest.data.targetId,
98
+ targetId: parsedRequest.targetId,
107
99
  });
108
100
  if (target === null) {
109
101
  (0, protocol_response_1.writeStudioProtocolError)({
@@ -2,22 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleStudioProtocolInstall = void 0;
4
4
  const studio_protocol_1 = require("@remotion/studio-protocol");
5
- const zod_1 = require("zod");
6
5
  const element_install_state_1 = require("../element-install-state");
7
6
  const parse_body_1 = require("../parse-body");
8
7
  const origin_policy_1 = require("./origin-policy");
9
8
  const protocol_response_1 = require("./protocol-response");
10
- const studioProtocolInstallRequestSchema = zod_1.z.object({
11
- operation: zod_1.z.literal('install-element'),
12
- protocol: zod_1.z.literal('remotion-studio-protocol'),
13
- protocolVersion: zod_1.z.literal(1),
14
- targetId: zod_1.z.string(),
15
- payload: zod_1.z.unknown(),
16
- });
17
9
  // A valid payload may contain 250,000 JSON characters. Allow room for its
18
10
  // UTF-8 representation and the protocol envelope while keeping memory bounded.
19
11
  const MAX_STUDIO_PROTOCOL_INSTALL_BODY_SIZE = 1000000;
20
12
  const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, origin, target, }) => {
13
+ var _a, _b;
21
14
  if (target.compositionFile === null || target.compositionId === null) {
22
15
  return false;
23
16
  }
@@ -27,7 +20,11 @@ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, orig
27
20
  createdAt: Date.now(),
28
21
  compositionFile: target.compositionFile,
29
22
  compositionId: target.compositionId,
30
- element,
23
+ element: {
24
+ ...element,
25
+ durationInFrames: (_a = element.durationInFrames) !== null && _a !== void 0 ? _a : null,
26
+ installationMode: (_b = element.installationMode) !== null && _b !== void 0 ? _b : null,
27
+ },
31
28
  from: null,
32
29
  position: null,
33
30
  source: {
@@ -89,21 +86,15 @@ const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, r
89
86
  });
90
87
  return;
91
88
  }
92
- const parsedRequest = studioProtocolInstallRequestSchema.safeParse(body);
93
- if (!parsedRequest.success) {
94
- (0, protocol_response_1.writeStudioProtocolError)({
95
- code: 'unsupported-protocol',
96
- message: 'Invalid Remotion Studio Protocol request.',
97
- response,
98
- status: 400,
99
- });
100
- return;
101
- }
102
- const payload = studio_protocol_1.StudioProtocolInternals.parseStudioElementPayload(parsedRequest.data.payload);
103
- if (payload === null) {
89
+ const parsedRequest = studio_protocol_1.StudioProtocolInternals.parseStudioProtocolInstallRequest(body);
90
+ if (parsedRequest.status !== 'valid') {
104
91
  (0, protocol_response_1.writeStudioProtocolError)({
105
- code: 'invalid-payload',
106
- message: 'Invalid Element payload.',
92
+ code: parsedRequest.status === 'invalid-payload'
93
+ ? 'invalid-payload'
94
+ : 'unsupported-protocol',
95
+ message: parsedRequest.status === 'invalid-payload'
96
+ ? 'Invalid Element payload.'
97
+ : 'Invalid Remotion Studio Protocol request.',
107
98
  response,
108
99
  status: 400,
109
100
  });
@@ -113,7 +104,7 @@ const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, r
113
104
  now: Date.now(),
114
105
  origin: requestOrigin,
115
106
  purpose: 'install-element',
116
- targetId: parsedRequest.data.targetId,
107
+ targetId: parsedRequest.request.targetId,
117
108
  });
118
109
  if (target === null) {
119
110
  (0, protocol_response_1.writeStudioProtocolError)({
@@ -125,7 +116,7 @@ const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, r
125
116
  return;
126
117
  }
127
118
  if (!deliverElementInstall({
128
- element: payload.element,
119
+ element: parsedRequest.request.payload.element,
129
120
  focusStudioTab,
130
121
  liveEventsServer,
131
122
  origin: requestOrigin,
@@ -2,18 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleStudioProtocolLicenseKey = void 0;
4
4
  const studio_protocol_1 = require("@remotion/studio-protocol");
5
- const zod_1 = require("zod");
6
5
  const element_install_state_1 = require("../element-install-state");
7
6
  const parse_body_1 = require("../parse-body");
8
7
  const origin_policy_1 = require("./origin-policy");
9
8
  const protocol_response_1 = require("./protocol-response");
10
- const studioProtocolLicenseKeyRequestSchema = zod_1.z.object({
11
- operation: zod_1.z.literal('set-license-key'),
12
- protocol: zod_1.z.literal('remotion-studio-protocol'),
13
- protocolVersion: zod_1.z.literal(1),
14
- targetId: zod_1.z.string().min(1),
15
- licenseKey: zod_1.z.string(),
16
- });
17
9
  const MAX_STUDIO_PROTOCOL_LICENSE_KEY_BODY_SIZE = 4096;
18
10
  const handleStudioProtocolLicenseKey = async ({ configFile, focusStudioTab, liveEventsServer, request, response, }) => {
19
11
  (0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
@@ -60,8 +52,8 @@ const handleStudioProtocolLicenseKey = async ({ configFile, focusStudioTab, live
60
52
  });
61
53
  return;
62
54
  }
63
- const parsedRequest = studioProtocolLicenseKeyRequestSchema.safeParse(body);
64
- if (!parsedRequest.success) {
55
+ const parsedRequest = studio_protocol_1.StudioProtocolInternals.parseStudioProtocolSetLicenseKeyRequest(body);
56
+ if (parsedRequest === null) {
65
57
  (0, protocol_response_1.writeStudioProtocolError)({
66
58
  code: 'unsupported-protocol',
67
59
  message: 'Invalid Remotion Studio Protocol request.',
@@ -70,7 +62,7 @@ const handleStudioProtocolLicenseKey = async ({ configFile, focusStudioTab, live
70
62
  });
71
63
  return;
72
64
  }
73
- if (!studio_protocol_1.StudioProtocolInternals.isValidPublicLicenseKey(parsedRequest.data.licenseKey)) {
65
+ if (!studio_protocol_1.StudioProtocolInternals.isValidPublicLicenseKey(parsedRequest.licenseKey)) {
74
66
  (0, protocol_response_1.writeStudioProtocolError)({
75
67
  code: 'invalid-license-key',
76
68
  message: 'The license key is not a valid public Remotion license key.',
@@ -83,7 +75,7 @@ const handleStudioProtocolLicenseKey = async ({ configFile, focusStudioTab, live
83
75
  now: Date.now(),
84
76
  origin: requestOrigin,
85
77
  purpose: 'set-license-key',
86
- targetId: parsedRequest.data.targetId,
78
+ targetId: parsedRequest.targetId,
87
79
  });
88
80
  if (target === null) {
89
81
  (0, protocol_response_1.writeStudioProtocolError)({
@@ -105,7 +97,7 @@ const handleStudioProtocolLicenseKey = async ({ configFile, focusStudioTab, live
105
97
  }
106
98
  const delivered = liveEventsServer.sendEventToClientId(target.clientId, {
107
99
  type: 'license-key-install-request',
108
- licenseKey: parsedRequest.data.licenseKey,
100
+ licenseKey: parsedRequest.licenseKey,
109
101
  });
110
102
  if (!delivered) {
111
103
  (0, protocol_response_1.writeStudioProtocolError)({
@@ -257,18 +257,10 @@ function popUndo() {
257
257
  return [
258
258
  {
259
259
  absolutePath: snapshot.filePath,
260
- remappings: snapshot.nodePathRemappings.flatMap((remapping) => {
261
- if (remapping.newNodePath === null) {
262
- return [];
263
- }
264
- return [
265
- {
266
- oldNodePath: remapping.newNodePath,
267
- newNodePath: remapping.oldNodePath,
268
- },
269
- ];
270
- }),
271
- restoredNodePaths: snapshot.nodePathRemappings.flatMap((remapping) => remapping.newNodePath === null ? [remapping.oldNodePath] : []),
260
+ remappings: snapshot.nodePathRemappings.map((remapping) => ({
261
+ oldNodePath: remapping.newNodePath,
262
+ newNodePath: remapping.oldNodePath,
263
+ })),
272
264
  },
273
265
  ];
274
266
  });
@@ -339,7 +331,6 @@ function popRedo() {
339
331
  {
340
332
  absolutePath: snapshot.filePath,
341
333
  remappings: snapshot.nodePathRemappings,
342
- restoredNodePaths: [],
343
334
  },
344
335
  ];
345
336
  });
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.518",
6
+ "version": "4.0.520",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -23,7 +23,7 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@remotion/studio-protocol": "4.0.518",
26
+ "@remotion/studio-protocol": "4.0.520",
27
27
  "@babel/types": "7.24.0",
28
28
  "@babel/parser": "7.24.1",
29
29
  "@svgr/core": "8.1.0",
@@ -32,12 +32,12 @@
32
32
  "semver": "7.5.3",
33
33
  "zod": "4.4.3",
34
34
  "prettier": "3.8.1",
35
- "remotion": "4.0.518",
35
+ "remotion": "4.0.520",
36
36
  "recast": "0.23.21",
37
- "@remotion/bundler": "4.0.518",
38
- "@remotion/renderer": "4.0.518",
39
- "@remotion/studio-codemods": "4.0.518",
40
- "@remotion/studio-shared": "4.0.518",
37
+ "@remotion/bundler": "4.0.520",
38
+ "@remotion/renderer": "4.0.520",
39
+ "@remotion/studio-codemods": "4.0.520",
40
+ "@remotion/studio-shared": "4.0.520",
41
41
  "memfs": "3.4.3",
42
42
  "open": "8.4.2"
43
43
  },
@@ -45,7 +45,7 @@
45
45
  "ast-types": "0.16.1",
46
46
  "react": "19.2.3",
47
47
  "@types/semver": "7.5.3",
48
- "@remotion/eslint-config-internal": "4.0.518",
48
+ "@remotion/eslint-config-internal": "4.0.520",
49
49
  "eslint": "9.19.0",
50
50
  "@types/node": "20.12.14",
51
51
  "@typescript/native-preview": "7.0.0-dev.20260217.1"