@remotion/studio-server 4.0.502 → 4.0.504
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/detect-outdated-remotion-skills.d.ts +25 -0
- package/dist/detect-outdated-remotion-skills.js +73 -0
- package/dist/helpers/custom-editor.d.ts +37 -0
- package/dist/helpers/custom-editor.js +167 -0
- package/dist/helpers/editor-registry.d.ts +18 -0
- package/dist/helpers/editor-registry.js +500 -0
- package/dist/helpers/open-in-editor.d.ts +4 -4
- package/dist/helpers/open-in-editor.js +23 -87
- package/dist/helpers/resolve-editor.d.ts +27 -0
- package/dist/helpers/resolve-editor.js +90 -0
- package/dist/helpers/resolve-file-inside-project.d.ts +2 -0
- package/dist/helpers/resolve-file-inside-project.js +5 -2
- package/dist/index.d.ts +17 -1
- package/dist/index.js +9 -1
- package/dist/preview-server/api-routes.js +6 -1
- package/dist/preview-server/api-types.d.ts +2 -1
- package/dist/preview-server/element-install-state.d.ts +9 -2
- package/dist/preview-server/element-install-state.js +15 -5
- package/dist/preview-server/handler.d.ts +3 -1
- package/dist/preview-server/handler.js +2 -1
- package/dist/preview-server/routes/can-update-sequence-props.js +2 -1
- package/dist/preview-server/routes/default-editor.d.ts +8 -0
- package/dist/preview-server/routes/default-editor.js +131 -0
- package/dist/preview-server/routes/delete-effect-keyframe.d.ts +3 -0
- package/dist/preview-server/routes/delete-effect-keyframe.js +89 -0
- package/dist/preview-server/routes/delete-sequence-keyframe.d.ts +3 -0
- package/dist/preview-server/routes/delete-sequence-keyframe.js +82 -0
- package/dist/preview-server/routes/element-install-plan.d.ts +33 -0
- package/dist/preview-server/routes/element-install-plan.js +122 -0
- package/dist/preview-server/routes/insert-element.d.ts +1 -1
- package/dist/preview-server/routes/insert-element.js +70 -107
- package/dist/preview-server/routes/install-dependency.d.ts +2 -1
- package/dist/preview-server/routes/install-dependency.js +33 -44
- package/dist/preview-server/routes/open-in-editor.d.ts +5 -1
- package/dist/preview-server/routes/open-in-editor.js +42 -12
- package/dist/preview-server/routes/prepare-element-install.d.ts +3 -0
- package/dist/preview-server/routes/prepare-element-install.js +25 -0
- package/dist/preview-server/routes/safe-element-install-path.d.ts +9 -0
- package/dist/preview-server/routes/safe-element-install-path.js +58 -0
- package/dist/preview-server/routes/save-props-mutex.d.ts +1 -0
- package/dist/preview-server/routes/save-props-mutex.js +11 -0
- package/dist/preview-server/routes/update-public-license.d.ts +4 -0
- package/dist/preview-server/routes/update-public-license.js +9 -5
- package/dist/preview-server/start-server.d.ts +2 -0
- package/dist/preview-server/start-server.js +1 -0
- package/dist/preview-server/studio-protocol/handle-discovery.js +57 -26
- package/dist/preview-server/studio-protocol/handle-install.js +13 -3
- package/dist/preview-server/studio-protocol/handle-license-key.d.ts +6 -0
- package/dist/preview-server/studio-protocol/handle-license-key.js +129 -0
- package/dist/preview-server/studio-protocol/origin-policy.d.ts +6 -3
- package/dist/preview-server/studio-protocol/origin-policy.js +43 -17
- package/dist/preview-server/update-available.d.ts +6 -0
- package/dist/preview-server/update-available.js +30 -4
- package/dist/remotion-skill-names.d.ts +2 -0
- package/dist/remotion-skill-names.js +16 -0
- package/dist/routes.d.ts +3 -1
- package/dist/routes.js +16 -5
- package/dist/start-studio.d.ts +3 -1
- package/dist/start-studio.js +2 -1
- package/package.json +8 -8
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteSequenceKeyframeHandler = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const renderer_1 = require("@remotion/renderer");
|
|
6
|
+
const studio_shared_1 = require("@remotion/studio-shared");
|
|
7
|
+
const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
|
|
8
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
9
|
+
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
10
|
+
const undo_stack_1 = require("../undo-stack");
|
|
11
|
+
const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
|
|
12
|
+
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
13
|
+
const log_update_1 = require("./log-updates/log-update");
|
|
14
|
+
const save_props_mutex_1 = require("./save-props-mutex");
|
|
15
|
+
const deleteSequenceKeyframeHandler = ({ input: { fileName, nodePath, key, frame, schema, clientId }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
|
|
16
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[delete-sequence-keyframe] Received request for fileName="${fileName}" key="${key}" frame=${frame}`);
|
|
17
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
18
|
+
remotionRoot,
|
|
19
|
+
fileName,
|
|
20
|
+
action: 'modify',
|
|
21
|
+
});
|
|
22
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
23
|
+
const { output, oldValueStrings, newValueStrings, formatted, logLine } = await (0, update_keyframes_1.updateSequenceKeyframes)({
|
|
24
|
+
input: fileContents,
|
|
25
|
+
nodePath: nodePath.nodePath,
|
|
26
|
+
updates: [
|
|
27
|
+
{
|
|
28
|
+
key,
|
|
29
|
+
operation: {
|
|
30
|
+
type: 'remove',
|
|
31
|
+
frame,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
const oldValueString = oldValueStrings[0];
|
|
37
|
+
const newValueString = newValueStrings[0];
|
|
38
|
+
const undoPropChange = `${key} keyframe restored at frame ${frame}`;
|
|
39
|
+
const redoPropChange = `${key} keyframe deleted at frame ${frame}`;
|
|
40
|
+
(0, undo_stack_1.pushToUndoStack)({
|
|
41
|
+
filePath: absolutePath,
|
|
42
|
+
oldContents: fileContents,
|
|
43
|
+
newContents: null,
|
|
44
|
+
logLevel,
|
|
45
|
+
remotionRoot,
|
|
46
|
+
logLine,
|
|
47
|
+
description: {
|
|
48
|
+
undoMessage: `↩️ ${undoPropChange}`,
|
|
49
|
+
redoMessage: `↪️ ${redoPropChange}`,
|
|
50
|
+
},
|
|
51
|
+
entryType: 'sequence-props',
|
|
52
|
+
suppressHmrOnFileRestore: true,
|
|
53
|
+
});
|
|
54
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
|
|
55
|
+
(0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
|
|
56
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
|
|
57
|
+
(0, log_update_1.logUpdate)({
|
|
58
|
+
fileRelativeToRoot,
|
|
59
|
+
line: logLine,
|
|
60
|
+
key,
|
|
61
|
+
oldValueString,
|
|
62
|
+
newValueString,
|
|
63
|
+
defaultValueString: null,
|
|
64
|
+
formatted,
|
|
65
|
+
logLevel,
|
|
66
|
+
removedProps: [],
|
|
67
|
+
addedProps: [],
|
|
68
|
+
});
|
|
69
|
+
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
70
|
+
const status = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
|
|
71
|
+
fileContents: output,
|
|
72
|
+
keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
|
|
73
|
+
nodePath: nodePath.nodePath,
|
|
74
|
+
effects: [],
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
canUpdate: true,
|
|
78
|
+
props: status.props,
|
|
79
|
+
results: [{ fileName, nodePath, props: status.props }],
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
exports.deleteSequenceKeyframeHandler = deleteSequenceKeyframeHandler;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ElementInstallExpectedFileState, PrepareElementInstallRequest } from '@remotion/studio-shared';
|
|
2
|
+
export declare const normalizeElementSourceForComparison: (source: string) => string;
|
|
3
|
+
export declare const getElementSourceHash: (source: string) => string;
|
|
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
|
+
slug: string;
|
|
9
|
+
displayName: string;
|
|
10
|
+
sourceCode: string;
|
|
11
|
+
dimensions: import("@remotion/studio-protocol").ComponentDimensions | null;
|
|
12
|
+
}) => void;
|
|
13
|
+
export declare const makeRelativeElementImportPath: ({ fromFile, toFile, }: {
|
|
14
|
+
fromFile: string;
|
|
15
|
+
toFile: string;
|
|
16
|
+
}) => string;
|
|
17
|
+
export declare const getElementInstallPlan: ({ compositionFile, compositionId, element, remotionRoot, }: PrepareElementInstallRequest & {
|
|
18
|
+
remotionRoot: string;
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
componentName: string;
|
|
21
|
+
elementFileExists: boolean;
|
|
22
|
+
elementFileName: string;
|
|
23
|
+
existingElementSource: string | null;
|
|
24
|
+
expectedFileState: ElementInstallExpectedFileState;
|
|
25
|
+
filePath: string;
|
|
26
|
+
importPath: string;
|
|
27
|
+
location: import("../../helpers/resolve-composition-component").ResolvedCompositionComponentWithFile;
|
|
28
|
+
safePaths: {
|
|
29
|
+
compositionFileName: string;
|
|
30
|
+
elementFileName: string;
|
|
31
|
+
remotionRoot: string;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
@@ -0,0 +1,122 @@
|
|
|
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.getElementInstallPlan = exports.makeRelativeElementImportPath = exports.validateElementForInstallation = exports.validateElementInstallPosition = exports.getElementSourceHash = exports.normalizeElementSourceForComparison = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const studio_protocol_1 = require("@remotion/studio-protocol");
|
|
11
|
+
const resolve_composition_component_1 = require("../../helpers/resolve-composition-component");
|
|
12
|
+
const safe_element_install_path_1 = require("./safe-element-install-path");
|
|
13
|
+
const normalizeElementSourceForComparison = (source) => {
|
|
14
|
+
return source.replace(/\r\n/g, '\n').trim();
|
|
15
|
+
};
|
|
16
|
+
exports.normalizeElementSourceForComparison = normalizeElementSourceForComparison;
|
|
17
|
+
const getElementSourceHash = (source) => {
|
|
18
|
+
return (0, node_crypto_1.createHash)('sha256').update(source).digest('hex');
|
|
19
|
+
};
|
|
20
|
+
exports.getElementSourceHash = getElementSourceHash;
|
|
21
|
+
const validateElementInstallPosition = (position) => {
|
|
22
|
+
if (position === null) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!Number.isFinite(position.x) || !Number.isFinite(position.y)) {
|
|
26
|
+
throw new Error('Position must be finite');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
exports.validateElementInstallPosition = validateElementInstallPosition;
|
|
30
|
+
const validateDimensions = (dimensions) => {
|
|
31
|
+
if (dimensions === null) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!Number.isFinite(dimensions.width) ||
|
|
35
|
+
!Number.isFinite(dimensions.height) ||
|
|
36
|
+
dimensions.width <= 0 ||
|
|
37
|
+
dimensions.height <= 0) {
|
|
38
|
+
throw new Error('Element dimensions must be positive finite numbers');
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const validateElementForInstallation = (element) => {
|
|
42
|
+
if (studio_protocol_1.StudioProtocolInternals.makeElementFileNameFromSlug(element.slug) === null) {
|
|
43
|
+
throw new Error('Element slug must produce a safe lowercase .tsx file name');
|
|
44
|
+
}
|
|
45
|
+
if (typeof element.sourceCode !== 'string' ||
|
|
46
|
+
element.sourceCode.trim().length === 0 ||
|
|
47
|
+
element.sourceCode.length > 200000) {
|
|
48
|
+
throw new Error('Unsupported Element source code');
|
|
49
|
+
}
|
|
50
|
+
if (studio_protocol_1.StudioProtocolInternals.getElementComponentNameFromSourceCode(element.sourceCode) === null) {
|
|
51
|
+
throw new Error('Element source must export exactly one named component');
|
|
52
|
+
}
|
|
53
|
+
validateDimensions(element.dimensions);
|
|
54
|
+
};
|
|
55
|
+
exports.validateElementForInstallation = validateElementForInstallation;
|
|
56
|
+
const makeRelativeElementImportPath = ({ fromFile, toFile, }) => {
|
|
57
|
+
const withoutExtension = toFile.replace(/\.tsx$/, '');
|
|
58
|
+
let relative = node_path_1.default
|
|
59
|
+
.relative(node_path_1.default.dirname(fromFile), withoutExtension)
|
|
60
|
+
.split(node_path_1.default.sep)
|
|
61
|
+
.join('/');
|
|
62
|
+
if (!relative.startsWith('.')) {
|
|
63
|
+
relative = `./${relative}`;
|
|
64
|
+
}
|
|
65
|
+
return relative;
|
|
66
|
+
};
|
|
67
|
+
exports.makeRelativeElementImportPath = makeRelativeElementImportPath;
|
|
68
|
+
const getExpectedFileState = (existingSource) => {
|
|
69
|
+
if (existingSource === null) {
|
|
70
|
+
return { exists: false };
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
exists: true,
|
|
74
|
+
sourceHash: (0, exports.getElementSourceHash)(existingSource),
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const getElementInstallPlan = async ({ compositionFile, compositionId, element, remotionRoot, }) => {
|
|
78
|
+
(0, exports.validateElementForInstallation)(element);
|
|
79
|
+
const componentName = studio_protocol_1.StudioProtocolInternals.getElementComponentNameFromSourceCode(element.sourceCode);
|
|
80
|
+
if (componentName === null) {
|
|
81
|
+
throw new Error('Element source must export exactly one named component');
|
|
82
|
+
}
|
|
83
|
+
const location = await (0, resolve_composition_component_1.resolveCompositionComponentWithFile)({
|
|
84
|
+
remotionRoot,
|
|
85
|
+
compositionFile,
|
|
86
|
+
compositionId,
|
|
87
|
+
});
|
|
88
|
+
if (!location.canAddSequence) {
|
|
89
|
+
throw new Error('Cannot insert Element into this composition component');
|
|
90
|
+
}
|
|
91
|
+
const derivedElementFileName = studio_protocol_1.StudioProtocolInternals.makeElementFileNameFromSlug(element.slug);
|
|
92
|
+
if (derivedElementFileName === null) {
|
|
93
|
+
throw new Error('Element slug must produce a safe lowercase .tsx file name');
|
|
94
|
+
}
|
|
95
|
+
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),
|
|
98
|
+
remotionRoot,
|
|
99
|
+
});
|
|
100
|
+
const elementFileExists = (0, node_fs_1.existsSync)(safePaths.elementFileName);
|
|
101
|
+
const existingElementSource = elementFileExists
|
|
102
|
+
? (0, node_fs_1.readFileSync)(safePaths.elementFileName, 'utf-8')
|
|
103
|
+
: null;
|
|
104
|
+
return {
|
|
105
|
+
componentName,
|
|
106
|
+
elementFileExists,
|
|
107
|
+
elementFileName: safePaths.elementFileName,
|
|
108
|
+
existingElementSource,
|
|
109
|
+
expectedFileState: getExpectedFileState(existingElementSource),
|
|
110
|
+
filePath: node_path_1.default
|
|
111
|
+
.relative(safePaths.remotionRoot, safePaths.elementFileName)
|
|
112
|
+
.split(node_path_1.default.sep)
|
|
113
|
+
.join('/'),
|
|
114
|
+
importPath: (0, exports.makeRelativeElementImportPath)({
|
|
115
|
+
fromFile: safePaths.compositionFileName,
|
|
116
|
+
toFile: safePaths.elementFileName,
|
|
117
|
+
}),
|
|
118
|
+
location,
|
|
119
|
+
safePaths,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
exports.getElementInstallPlan = getElementInstallPlan;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { InsertElementRequest, InsertElementResponse } from '@remotion/studio-shared';
|
|
2
2
|
import type { ApiHandler } from '../api-types';
|
|
3
3
|
export declare const insertElementHandler: ApiHandler<InsertElementRequest, InsertElementResponse>;
|
|
@@ -1,138 +1,86 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.insertElementHandler = void 0;
|
|
7
|
-
const node_fs_1 = require("node:fs");
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
4
|
const renderer_1 = require("@remotion/renderer");
|
|
10
|
-
const studio_protocol_1 = require("@remotion/studio-protocol");
|
|
11
5
|
const file_watcher_1 = require("../../file-watcher");
|
|
12
6
|
const resolve_composition_component_1 = require("../../helpers/resolve-composition-component");
|
|
13
7
|
const format_log_file_location_1 = require("../format-log-file-location");
|
|
14
8
|
const undo_stack_1 = require("../undo-stack");
|
|
9
|
+
const element_install_plan_1 = require("./element-install-plan");
|
|
15
10
|
const log_update_1 = require("./log-updates/log-update");
|
|
16
11
|
const source_file_write_queue_1 = require("./source-file-write-queue");
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
return;
|
|
12
|
+
const hasExpectedFileState = ({ expected, actual, }) => {
|
|
13
|
+
if (expected.exists !== actual.exists) {
|
|
14
|
+
return false;
|
|
20
15
|
}
|
|
21
|
-
if (!
|
|
22
|
-
|
|
16
|
+
if (!expected.exists) {
|
|
17
|
+
return true;
|
|
23
18
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const relative = node_path_1.default.relative(parent, child);
|
|
27
|
-
return (relative === '' ||
|
|
28
|
-
(!relative.startsWith('..') && !node_path_1.default.isAbsolute(relative)));
|
|
29
|
-
};
|
|
30
|
-
const withoutTsxExtension = (fileName) => {
|
|
31
|
-
return fileName.replace(/\.tsx$/, '');
|
|
32
|
-
};
|
|
33
|
-
const normalizeSourceForComparison = (source) => {
|
|
34
|
-
return source.replace(/\r\n/g, '\n').trim();
|
|
35
|
-
};
|
|
36
|
-
const makeRelativeImportPath = ({ fromFile, toFile, }) => {
|
|
37
|
-
const withoutExtension = withoutTsxExtension(toFile);
|
|
38
|
-
let relative = node_path_1.default
|
|
39
|
-
.relative(node_path_1.default.dirname(fromFile), withoutExtension)
|
|
40
|
-
.split(node_path_1.default.sep)
|
|
41
|
-
.join('/');
|
|
42
|
-
if (!relative.startsWith('.')) {
|
|
43
|
-
relative = `./${relative}`;
|
|
19
|
+
if (!actual.exists) {
|
|
20
|
+
return false;
|
|
44
21
|
}
|
|
45
|
-
return
|
|
22
|
+
return actual.sourceHash === expected.sourceHash;
|
|
46
23
|
};
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (!Number.isFinite(dimensions.width) ||
|
|
52
|
-
!Number.isFinite(dimensions.height) ||
|
|
53
|
-
dimensions.width <= 0 ||
|
|
54
|
-
dimensions.height <= 0) {
|
|
55
|
-
throw new Error('Element dimensions must be positive finite numbers');
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
const validateElement = (element) => {
|
|
59
|
-
if (studio_protocol_1.StudioProtocolInternals.makeElementFileNameFromSlug(element.slug) === null) {
|
|
60
|
-
throw new Error('Element slug must produce a safe lowercase .tsx file name');
|
|
61
|
-
}
|
|
62
|
-
if (typeof element.sourceCode !== 'string' ||
|
|
63
|
-
element.sourceCode.trim().length === 0 ||
|
|
64
|
-
element.sourceCode.length > 200000) {
|
|
65
|
-
throw new Error('Unsupported Element source code');
|
|
66
|
-
}
|
|
67
|
-
if (studio_protocol_1.StudioProtocolInternals.getElementComponentNameFromSourceCode(element.sourceCode) === null) {
|
|
68
|
-
throw new Error('Element source must export exactly one named component');
|
|
69
|
-
}
|
|
70
|
-
validateDimensions(element.dimensions);
|
|
71
|
-
};
|
|
72
|
-
const insertElementHandler = ({ input: { compositionFile, compositionId, element, from, position, overwriteExisting, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
24
|
+
const insertElementHandler = ({ input: { compositionFile, compositionId, element, expectedFileState, from, position, overwriteExisting, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
25
|
+
var _a;
|
|
73
26
|
try {
|
|
74
|
-
|
|
75
|
-
validatePosition(position);
|
|
27
|
+
(0, element_install_plan_1.validateElementInstallPosition)(position);
|
|
76
28
|
if (from !== null &&
|
|
77
29
|
(!Number.isInteger(from) || !Number.isFinite(from) || from < 0)) {
|
|
78
30
|
throw new Error('from must be a non-negative integer');
|
|
79
31
|
}
|
|
80
|
-
const componentName = studio_protocol_1.StudioProtocolInternals.getElementComponentNameFromSourceCode(element.sourceCode);
|
|
81
|
-
if (componentName === null) {
|
|
82
|
-
throw new Error('Element source must export exactly one named component');
|
|
83
|
-
}
|
|
84
32
|
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[insert-element] Received request for compositionFile="${compositionFile}" compositionId="${compositionId}" element="${element.slug}"`);
|
|
85
|
-
const
|
|
86
|
-
remotionRoot,
|
|
33
|
+
const plan = await (0, element_install_plan_1.getElementInstallPlan)({
|
|
87
34
|
compositionFile,
|
|
88
35
|
compositionId,
|
|
36
|
+
element,
|
|
37
|
+
remotionRoot,
|
|
89
38
|
});
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
39
|
+
if (expectedFileState !== null &&
|
|
40
|
+
!hasExpectedFileState({
|
|
41
|
+
actual: plan.expectedFileState,
|
|
42
|
+
expected: expectedFileState,
|
|
43
|
+
})) {
|
|
44
|
+
const { existingElementSource } = plan;
|
|
45
|
+
if (existingElementSource !== null) {
|
|
46
|
+
return {
|
|
47
|
+
success: false,
|
|
48
|
+
type: 'file-conflict',
|
|
49
|
+
conflict: {
|
|
50
|
+
filePath: plan.filePath,
|
|
51
|
+
existingSource: existingElementSource,
|
|
52
|
+
incomingSource: element.sourceCode,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
throw new Error('Element source changed during installation');
|
|
100
57
|
}
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
normalizeSourceForComparison(element.sourceCode);
|
|
108
|
-
if (elementSourcesDiffer && !overwriteExisting) {
|
|
58
|
+
const elementSourcesDiffer = plan.existingElementSource !== null &&
|
|
59
|
+
(0, element_install_plan_1.normalizeElementSourceForComparison)(plan.existingElementSource) !==
|
|
60
|
+
(0, element_install_plan_1.normalizeElementSourceForComparison)(element.sourceCode);
|
|
61
|
+
if (elementSourcesDiffer &&
|
|
62
|
+
!overwriteExisting &&
|
|
63
|
+
plan.existingElementSource !== null) {
|
|
109
64
|
return {
|
|
110
65
|
success: false,
|
|
111
66
|
type: 'file-conflict',
|
|
112
67
|
conflict: {
|
|
113
|
-
filePath:
|
|
114
|
-
|
|
115
|
-
.split(node_path_1.default.sep)
|
|
116
|
-
.join('/'),
|
|
117
|
-
existingSource: existingElementSource,
|
|
68
|
+
filePath: plan.filePath,
|
|
69
|
+
existingSource: plan.existingElementSource,
|
|
118
70
|
incomingSource: element.sourceCode,
|
|
119
71
|
},
|
|
120
72
|
};
|
|
121
73
|
}
|
|
122
|
-
const shouldWriteElementFile = !elementFileExists || elementSourcesDiffer;
|
|
123
|
-
const importPath = makeRelativeImportPath({
|
|
124
|
-
fromFile: location.fileName,
|
|
125
|
-
toFile: elementFileName,
|
|
126
|
-
});
|
|
74
|
+
const shouldWriteElementFile = !plan.elementFileExists || elementSourcesDiffer;
|
|
127
75
|
const inserted = await (0, resolve_composition_component_1.insertJsxElementIntoComposition)({
|
|
128
76
|
remotionRoot,
|
|
129
77
|
compositionFile,
|
|
130
78
|
compositionId,
|
|
131
79
|
element: {
|
|
132
80
|
type: 'component',
|
|
133
|
-
componentName,
|
|
134
|
-
importName: componentName,
|
|
135
|
-
importPath,
|
|
81
|
+
componentName: plan.componentName,
|
|
82
|
+
importName: plan.componentName,
|
|
83
|
+
importPath: plan.importPath,
|
|
136
84
|
props: [],
|
|
137
85
|
position: null,
|
|
138
86
|
},
|
|
@@ -140,18 +88,35 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
140
88
|
prettierConfigOverride: null,
|
|
141
89
|
wrapInSequence: {
|
|
142
90
|
dimensions: element.dimensions,
|
|
91
|
+
durationInFrames: (_a = element.durationInFrames) !== null && _a !== void 0 ? _a : null,
|
|
143
92
|
from,
|
|
144
93
|
name: element.displayName,
|
|
145
94
|
position,
|
|
146
95
|
},
|
|
147
96
|
});
|
|
97
|
+
const finalPlan = await (0, element_install_plan_1.getElementInstallPlan)({
|
|
98
|
+
compositionFile,
|
|
99
|
+
compositionId,
|
|
100
|
+
element,
|
|
101
|
+
remotionRoot,
|
|
102
|
+
});
|
|
103
|
+
if (finalPlan.safePaths.compositionFileName !==
|
|
104
|
+
plan.safePaths.compositionFileName) {
|
|
105
|
+
throw new Error('Composition source changed during Element installation');
|
|
106
|
+
}
|
|
107
|
+
if (!hasExpectedFileState({
|
|
108
|
+
actual: finalPlan.expectedFileState,
|
|
109
|
+
expected: plan.expectedFileState,
|
|
110
|
+
})) {
|
|
111
|
+
throw new Error('Element source changed during installation');
|
|
112
|
+
}
|
|
148
113
|
(0, undo_stack_1.pushTransactionToUndoStack)({
|
|
149
114
|
snapshots: [
|
|
150
115
|
...(shouldWriteElementFile
|
|
151
116
|
? [
|
|
152
117
|
{
|
|
153
|
-
filePath: elementFileName,
|
|
154
|
-
oldContents: existingElementSource,
|
|
118
|
+
filePath: plan.elementFileName,
|
|
119
|
+
oldContents: plan.existingElementSource,
|
|
155
120
|
newContents: element.sourceCode,
|
|
156
121
|
logLine: 1,
|
|
157
122
|
},
|
|
@@ -174,11 +139,11 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
174
139
|
suppressHmrOnFileRestore: false,
|
|
175
140
|
});
|
|
176
141
|
if (shouldWriteElementFile) {
|
|
177
|
-
(0, undo_stack_1.suppressUndoStackInvalidation)(elementFileName);
|
|
142
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(plan.elementFileName);
|
|
178
143
|
}
|
|
179
144
|
(0, undo_stack_1.suppressUndoStackInvalidation)(inserted.fileName);
|
|
180
145
|
if (shouldWriteElementFile) {
|
|
181
|
-
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(elementFileName, element.sourceCode, undefined);
|
|
146
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(plan.elementFileName, element.sourceCode, undefined);
|
|
182
147
|
}
|
|
183
148
|
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(inserted.fileName, inserted.output, undefined);
|
|
184
149
|
const compositionLocationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
|
|
@@ -188,23 +153,21 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
188
153
|
});
|
|
189
154
|
const elementLocationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
|
|
190
155
|
remotionRoot,
|
|
191
|
-
absolutePath: elementFileName,
|
|
156
|
+
absolutePath: plan.elementFileName,
|
|
192
157
|
line: 1,
|
|
193
158
|
});
|
|
194
159
|
const elementFileAction = elementSourcesDiffer
|
|
195
160
|
? 'Overwrote existing Element source'
|
|
196
|
-
: elementFileExists
|
|
161
|
+
: plan.elementFileExists
|
|
197
162
|
? 'Reused existing Element source'
|
|
198
163
|
: 'Created Element source';
|
|
199
164
|
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(elementLocationLabel)} ${elementFileAction}`);
|
|
200
|
-
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(compositionLocationLabel)} Added <${componentName}>`);
|
|
165
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(compositionLocationLabel)} Added <${plan.componentName}>`);
|
|
201
166
|
if (!inserted.formatted) {
|
|
202
167
|
(0, log_update_1.warnAboutPrettierOnce)(logLevel);
|
|
203
168
|
}
|
|
204
169
|
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
205
|
-
return {
|
|
206
|
-
success: true,
|
|
207
|
-
};
|
|
170
|
+
return { success: true };
|
|
208
171
|
}
|
|
209
172
|
catch (err) {
|
|
210
173
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import type { ElementDependency } from '@remotion/studio-protocol';
|
|
1
2
|
import { type InstallPackageRequest, type InstallPackageResponse } from '@remotion/studio-shared';
|
|
2
3
|
import type { ApiHandler } from '../api-types';
|
|
3
|
-
export declare const getPackageInstallSpec: (
|
|
4
|
+
export declare const getPackageInstallSpec: (dependency: string | ElementDependency) => string;
|
|
4
5
|
export declare const handleInstallPackage: ApiHandler<InstallPackageRequest, InstallPackageResponse>;
|
|
@@ -12,21 +12,26 @@ const getExtraPackageVersion = (packageName) => {
|
|
|
12
12
|
const pkg = studio_shared_1.extraPackages.find((p) => p.name === packageName);
|
|
13
13
|
return pkg ? pkg.version : null;
|
|
14
14
|
};
|
|
15
|
-
const getPackageInstallSpec = (
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
return `${
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
const getPackageInstallSpec = (dependency) => {
|
|
16
|
+
const { name, version } = typeof dependency === 'string'
|
|
17
|
+
? { name: dependency, version: null }
|
|
18
|
+
: dependency;
|
|
19
|
+
const extraVersion = getExtraPackageVersion(name);
|
|
20
|
+
if (extraVersion)
|
|
21
|
+
return `${name}@${extraVersion}`;
|
|
22
|
+
if (name === 'remotion' || name.startsWith('@remotion/'))
|
|
23
|
+
return `${name}@${version_1.VERSION}`;
|
|
24
|
+
return version === null ? name : `${name}@${version}`;
|
|
24
25
|
};
|
|
25
26
|
exports.getPackageInstallSpec = getPackageInstallSpec;
|
|
26
|
-
const handleInstallPackage = async ({ logLevel, remotionRoot, input: {
|
|
27
|
-
for (const
|
|
28
|
-
if (!(0, studio_shared_1.isValidPackageName)(
|
|
29
|
-
return Promise.reject(new Error(`Package name ${JSON.stringify(
|
|
27
|
+
const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependencies } }) => {
|
|
28
|
+
for (const dependency of dependencies) {
|
|
29
|
+
if (!(0, studio_shared_1.isValidPackageName)(dependency.name)) {
|
|
30
|
+
return Promise.reject(new Error(`Package name ${JSON.stringify(dependency.name)} is invalid.`));
|
|
31
|
+
}
|
|
32
|
+
if (dependency.version !== null &&
|
|
33
|
+
!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(dependency.version)) {
|
|
34
|
+
return Promise.reject(new Error(`Package version ${JSON.stringify(dependency.version)} is invalid.`));
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
const manager = (0, get_package_manager_1.getPackageManager)({
|
|
@@ -36,13 +41,9 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { packageNa
|
|
|
36
41
|
logLevel,
|
|
37
42
|
});
|
|
38
43
|
if (manager === 'unknown') {
|
|
39
|
-
throw new Error(`No lockfile was found in your project (one of ${get_package_manager_1.lockFilePaths
|
|
40
|
-
.map((p) => p.path)
|
|
41
|
-
.join(', ')}). Install dependencies using your favorite manager!`);
|
|
44
|
+
throw new Error(`No lockfile was found in your project (one of ${get_package_manager_1.lockFilePaths.map((p) => p.path).join(', ')}). Install dependencies using your favorite manager!`);
|
|
42
45
|
}
|
|
43
|
-
|
|
44
|
-
// packages use their supported version. Other packages resolve normally.
|
|
45
|
-
const packagesWithVersions = packageNames.map(exports.getPackageInstallSpec);
|
|
46
|
+
const packagesWithVersions = dependencies.map(exports.getPackageInstallSpec);
|
|
46
47
|
const command = (0, install_command_1.getInstallCommand)({
|
|
47
48
|
manager: manager.manager,
|
|
48
49
|
packages: packagesWithVersions,
|
|
@@ -54,34 +55,22 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { packageNa
|
|
|
54
55
|
try {
|
|
55
56
|
await new Promise((resolve, reject) => {
|
|
56
57
|
const cmd = (0, node_child_process_1.spawn)(manager.manager, command, (0, package_manager_spawn_options_1.getPackageManagerSpawnOptions)());
|
|
57
|
-
cmd.on('error',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
resolve();
|
|
68
|
-
});
|
|
69
|
-
cmd.on('close', (code, signal) => {
|
|
70
|
-
if (code === 0) {
|
|
71
|
-
resolve();
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
reject(new Error(`Command exited with code ${code} and signal ${signal}`));
|
|
75
|
-
}
|
|
76
|
-
});
|
|
58
|
+
cmd.on('error', reject);
|
|
59
|
+
cmd.stdout.on('data', (d) => d
|
|
60
|
+
.toString()
|
|
61
|
+
.trim()
|
|
62
|
+
.split('\n')
|
|
63
|
+
.forEach((line) => renderer_1.RenderInternals.Log.info({ indent: true, logLevel }, line)));
|
|
64
|
+
cmd.stdout.on('end', resolve);
|
|
65
|
+
cmd.on('close', (code, signal) => code === 0
|
|
66
|
+
? resolve()
|
|
67
|
+
: reject(new Error(`Command exited with code ${code} and signal ${signal}`)));
|
|
77
68
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return Promise.resolve({});
|
|
69
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray('╰─ '), `Done in ${Date.now() - time}ms`);
|
|
70
|
+
return {};
|
|
81
71
|
}
|
|
82
72
|
catch (err) {
|
|
83
|
-
|
|
84
|
-
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray('╰─ '), renderer_1.RenderInternals.chalk.red(`Errored in ${timeEnd - time}ms`));
|
|
73
|
+
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray('╰─ '), renderer_1.RenderInternals.chalk.red(`Errored in ${Date.now() - time}ms`));
|
|
85
74
|
return Promise.reject(err);
|
|
86
75
|
}
|
|
87
76
|
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { type DefaultEditor } from '@remotion/renderer';
|
|
1
2
|
import type { OpenInEditorRequest, OpenInEditorResponse } from '@remotion/studio-shared';
|
|
2
3
|
import type { ApiHandler } from '../api-types';
|
|
3
|
-
export declare const getEditorName: (
|
|
4
|
+
export declare const getEditorName: ({ getDefaultEditor, logLevel, }: {
|
|
5
|
+
getDefaultEditor: () => DefaultEditor | null;
|
|
6
|
+
logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
7
|
+
}) => Promise<string | null>;
|
|
4
8
|
export declare const openInEditorHandler: ApiHandler<OpenInEditorRequest, OpenInEditorResponse>;
|