@remotion/studio-server 4.0.518 → 4.0.519
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/codemods/delete-jsx-node.d.ts +1 -4
- package/dist/codemods/duplicate-jsx-node.d.ts +11 -0
- package/dist/codemods/duplicate-jsx-node.js +11 -1
- package/dist/codemods/get-node-path-remappings.d.ts +1 -0
- package/dist/codemods/get-node-path-remappings.js +15 -2
- package/dist/codemods/split-video-from-audio.d.ts +1 -4
- package/dist/helpers/open-in-editor.js +1 -1
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/element-install-state.d.ts +0 -1
- package/dist/preview-server/element-install-state.js +1 -2
- package/dist/preview-server/routes/delete-jsx-node.js +0 -1
- package/dist/preview-server/routes/duplicate-jsx-node.js +71 -39
- package/dist/preview-server/routes/element-install-plan.d.ts +4 -2
- package/dist/preview-server/routes/element-install-plan.js +22 -9
- package/dist/preview-server/routes/insert-element.js +13 -6
- package/dist/preview-server/routes/insert-jsx-element.js +0 -1
- package/dist/preview-server/routes/prepare-element-install.js +7 -2
- package/dist/preview-server/routes/release-notes.d.ts +3 -0
- package/dist/preview-server/routes/release-notes.js +127 -0
- package/dist/preview-server/routes/reorder-sequence.js +0 -1
- package/dist/preview-server/routes/split-jsx-sequence.js +0 -1
- package/dist/preview-server/routes/split-video-from-audio.js +0 -1
- package/dist/preview-server/sequence-node-path-mutation.d.ts +0 -2
- package/dist/preview-server/start-server.js +9 -5
- package/dist/preview-server/studio-protocol/handle-discovery.js +2 -3
- package/dist/preview-server/undo-stack.js +4 -13
- 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
|
|
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,
|
|
@@ -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 (
|
|
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: {
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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 ${
|
|
41
|
-
redoMessage: `↪️ Duplication of ${
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
(0,
|
|
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,
|
|
@@ -15,17 +15,19 @@ export declare const makeRelativeElementImportPath: ({ fromFile, toFile, }: {
|
|
|
15
15
|
fromFile: string;
|
|
16
16
|
toFile: string;
|
|
17
17
|
}) => string;
|
|
18
|
-
export declare const getElementInstallPlan: ({
|
|
18
|
+
export declare const getElementInstallPlan: ({ destination, element, entryPoint, remotionRoot, }: PrepareElementInstallRequest & {
|
|
19
|
+
entryPoint: string;
|
|
19
20
|
remotionRoot: string;
|
|
20
21
|
}) => Promise<{
|
|
21
22
|
componentName: string;
|
|
23
|
+
destinationCompositionFileName: string;
|
|
22
24
|
elementFileExists: boolean;
|
|
23
25
|
elementFileName: string;
|
|
24
26
|
existingElementSource: string | null;
|
|
25
27
|
expectedFileState: ElementInstallExpectedFileState;
|
|
26
28
|
filePath: string;
|
|
27
29
|
importPath: string;
|
|
28
|
-
location: import("@remotion/studio-codemods").ResolvedCompositionComponentWithFile;
|
|
30
|
+
location: import("@remotion/studio-codemods").ResolvedCompositionComponentWithFile | null;
|
|
29
31
|
safePaths: {
|
|
30
32
|
compositionFileName: string;
|
|
31
33
|
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 ({
|
|
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 =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
97
|
-
elementFileName: node_path_1.default.resolve(node_path_1.default.dirname(
|
|
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,7 +22,7 @@ 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 () => {
|
|
25
|
+
const insertElementHandler = ({ input: { compositionFile, compositionId, element, expectedFileState, from, position, overwriteExisting, }, entryPoint, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
26
26
|
var _a, _b;
|
|
27
27
|
try {
|
|
28
28
|
(0, element_install_plan_1.validateElementInstallPosition)(position);
|
|
@@ -34,9 +34,13 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
34
34
|
const componentOwnsSequence = installationMode === 'component-owned-sequence';
|
|
35
35
|
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[insert-element] Received request for compositionFile="${compositionFile}" compositionId="${compositionId}" element="${element.slug}"`);
|
|
36
36
|
const plan = await (0, element_install_plan_1.getElementInstallPlan)({
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
destination: {
|
|
38
|
+
type: 'current-composition',
|
|
39
|
+
compositionFile,
|
|
40
|
+
compositionId,
|
|
41
|
+
},
|
|
39
42
|
element,
|
|
43
|
+
entryPoint,
|
|
40
44
|
remotionRoot,
|
|
41
45
|
});
|
|
42
46
|
if (expectedFileState !== null &&
|
|
@@ -112,9 +116,13 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
112
116
|
},
|
|
113
117
|
});
|
|
114
118
|
const finalPlan = await (0, element_install_plan_1.getElementInstallPlan)({
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
destination: {
|
|
120
|
+
type: 'current-composition',
|
|
121
|
+
compositionFile,
|
|
122
|
+
compositionId,
|
|
123
|
+
},
|
|
117
124
|
element,
|
|
125
|
+
entryPoint,
|
|
118
126
|
remotionRoot,
|
|
119
127
|
});
|
|
120
128
|
if (finalPlan.safePaths.compositionFileName !==
|
|
@@ -131,7 +139,6 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
131
139
|
{
|
|
132
140
|
absolutePath: inserted.fileName,
|
|
133
141
|
remappings: inserted.nodePathRemappings,
|
|
134
|
-
restoredNodePaths: [],
|
|
135
142
|
},
|
|
136
143
|
]);
|
|
137
144
|
(0, undo_stack_1.pushTransactionToUndoStack)({
|
|
@@ -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)({
|
|
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,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;
|
|
@@ -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 =
|
|
23
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
70
|
+
const installTarget = isElementRequestTarget(target) ? target : null;
|
|
72
71
|
const issuedInstallTarget = installTarget === null
|
|
73
72
|
? null
|
|
74
73
|
: (0, element_install_state_1.issueStudioProtocolTarget)({
|
|
@@ -257,18 +257,10 @@ function popUndo() {
|
|
|
257
257
|
return [
|
|
258
258
|
{
|
|
259
259
|
absolutePath: snapshot.filePath,
|
|
260
|
-
remappings: snapshot.nodePathRemappings.
|
|
261
|
-
|
|
262
|
-
|
|
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.
|
|
6
|
+
"version": "4.0.519",
|
|
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.
|
|
26
|
+
"@remotion/studio-protocol": "4.0.519",
|
|
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.
|
|
35
|
+
"remotion": "4.0.519",
|
|
36
36
|
"recast": "0.23.21",
|
|
37
|
-
"@remotion/bundler": "4.0.
|
|
38
|
-
"@remotion/renderer": "4.0.
|
|
39
|
-
"@remotion/studio-codemods": "4.0.
|
|
40
|
-
"@remotion/studio-shared": "4.0.
|
|
37
|
+
"@remotion/bundler": "4.0.519",
|
|
38
|
+
"@remotion/renderer": "4.0.519",
|
|
39
|
+
"@remotion/studio-codemods": "4.0.519",
|
|
40
|
+
"@remotion/studio-shared": "4.0.519",
|
|
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.
|
|
48
|
+
"@remotion/eslint-config-internal": "4.0.519",
|
|
49
49
|
"eslint": "9.19.0",
|
|
50
50
|
"@types/node": "20.12.14",
|
|
51
51
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|