@remotion/studio-server 4.0.514 → 4.0.516
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 +2 -1
- package/dist/codemods/delete-jsx-node.js +10 -5
- package/dist/codemods/duplicate-jsx-node.d.ts +3 -3
- package/dist/codemods/duplicate-jsx-node.js +10 -313
- package/dist/helpers/open-file-for-writing-without-symlinks.d.ts +4 -0
- package/dist/helpers/open-file-for-writing-without-symlinks.js +52 -0
- package/dist/helpers/video-config-values.js +25 -6
- package/dist/preview-server/hmr-timing.d.ts +5 -0
- package/dist/preview-server/hmr-timing.js +9 -0
- package/dist/preview-server/hot-middleware/index.js +16 -1
- package/dist/preview-server/routes/can-update-sequence-props.js +49 -3
- 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-jsx-node.js +28 -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/download-remote-asset.d.ts +2 -5
- package/dist/preview-server/routes/download-remote-asset.js +8 -70
- package/dist/preview-server/routes/install-dependency.js +8 -2
- package/dist/preview-server/routes/remotion-skills-info.js +11 -1
- 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/serve-static.d.ts +2 -1
- package/dist/preview-server/serve-static.js +31 -1
- package/dist/routes.js +38 -5
- package/package.json +9 -9
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteEffectKeyframeHandler = 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 parse_ast_1 = require("../../codemods/parse-ast");
|
|
8
|
+
const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
|
|
9
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
10
|
+
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
11
|
+
const undo_stack_1 = require("../undo-stack");
|
|
12
|
+
const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
|
|
13
|
+
const can_update_effect_props_1 = require("./can-update-effect-props");
|
|
14
|
+
const can_update_sequence_props_1 = require("./can-update-sequence-props");
|
|
15
|
+
const log_effect_update_1 = require("./log-updates/log-effect-update");
|
|
16
|
+
const save_props_mutex_1 = require("./save-props-mutex");
|
|
17
|
+
const deleteEffectKeyframeHandler = ({ input: { fileName, sequenceNodePath, effectIndex, key, frame, schema, clientId, }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
|
|
18
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[delete-effect-keyframe] Received request for fileName="${fileName}" effectIndex=${effectIndex} key="${key}" frame=${frame}`);
|
|
19
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
20
|
+
remotionRoot,
|
|
21
|
+
fileName,
|
|
22
|
+
action: 'modify',
|
|
23
|
+
});
|
|
24
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
25
|
+
const { output, oldValueStrings, newValueStrings, formatted, logLine, effectCallee, } = await (0, update_keyframes_1.updateEffectKeyframes)({
|
|
26
|
+
input: fileContents,
|
|
27
|
+
sequenceNodePath: sequenceNodePath.nodePath,
|
|
28
|
+
effectIndex,
|
|
29
|
+
updates: [
|
|
30
|
+
{
|
|
31
|
+
key,
|
|
32
|
+
operation: {
|
|
33
|
+
type: 'remove',
|
|
34
|
+
frame,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
const oldValueString = oldValueStrings[0];
|
|
40
|
+
const newValueString = newValueStrings[0];
|
|
41
|
+
const undoPropChange = `${key} keyframe restored at frame ${frame}`;
|
|
42
|
+
const redoPropChange = `${key} keyframe deleted at frame ${frame}`;
|
|
43
|
+
(0, undo_stack_1.pushToUndoStack)({
|
|
44
|
+
filePath: absolutePath,
|
|
45
|
+
oldContents: fileContents,
|
|
46
|
+
newContents: null,
|
|
47
|
+
logLevel,
|
|
48
|
+
remotionRoot,
|
|
49
|
+
logLine,
|
|
50
|
+
description: {
|
|
51
|
+
undoMessage: `↩️ ${undoPropChange}`,
|
|
52
|
+
redoMessage: `↪️ ${redoPropChange}`,
|
|
53
|
+
},
|
|
54
|
+
entryType: 'effect-props',
|
|
55
|
+
suppressHmrOnFileRestore: true,
|
|
56
|
+
});
|
|
57
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
|
|
58
|
+
(0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
|
|
59
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
|
|
60
|
+
(0, log_effect_update_1.logEffectUpdate)({
|
|
61
|
+
fileRelativeToRoot,
|
|
62
|
+
line: logLine,
|
|
63
|
+
effectName: effectCallee,
|
|
64
|
+
propKey: key,
|
|
65
|
+
oldValueString,
|
|
66
|
+
newValueString,
|
|
67
|
+
defaultValueString: null,
|
|
68
|
+
formatted,
|
|
69
|
+
logLevel,
|
|
70
|
+
removedProps: [],
|
|
71
|
+
addedProps: [],
|
|
72
|
+
});
|
|
73
|
+
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
74
|
+
const ast = (0, parse_ast_1.parseAst)((0, node_fs_1.readFileSync)(absolutePath, 'utf-8'));
|
|
75
|
+
const jsx = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, sequenceNodePath.nodePath);
|
|
76
|
+
if (!jsx) {
|
|
77
|
+
return {
|
|
78
|
+
canUpdate: false,
|
|
79
|
+
effectIndex,
|
|
80
|
+
reason: 'not-found',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return (0, can_update_effect_props_1.computeEffectPropStatus)({
|
|
84
|
+
jsx,
|
|
85
|
+
effectIndex,
|
|
86
|
+
keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
exports.deleteEffectKeyframeHandler = deleteEffectKeyframeHandler;
|
|
@@ -7,6 +7,7 @@ const delete_jsx_node_1 = require("../../codemods/delete-jsx-node");
|
|
|
7
7
|
const file_watcher_1 = require("../../file-watcher");
|
|
8
8
|
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
9
9
|
const format_log_file_location_1 = require("../format-log-file-location");
|
|
10
|
+
const hmr_timing_1 = require("../hmr-timing");
|
|
10
11
|
const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
|
|
11
12
|
const undo_stack_1 = require("../undo-stack");
|
|
12
13
|
const log_update_1 = require("./log-updates/log-update");
|
|
@@ -21,6 +22,11 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
|
|
|
21
22
|
return (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
22
23
|
var _a;
|
|
23
24
|
try {
|
|
25
|
+
(0, hmr_timing_1.logHmrTiming)({
|
|
26
|
+
detail: null,
|
|
27
|
+
logLevel,
|
|
28
|
+
stage: 'delete-jsx-node-request-start',
|
|
29
|
+
});
|
|
24
30
|
if (nodes.length === 0) {
|
|
25
31
|
throw new Error('No JSX nodes were specified for deletion');
|
|
26
32
|
}
|
|
@@ -41,6 +47,13 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
|
|
|
41
47
|
const { output, formatted, nodeLabels, logLines, nodePathRemappings } = await (0, delete_jsx_node_1.deleteJsxNodes)({
|
|
42
48
|
input: fileContents,
|
|
43
49
|
nodePaths: fileItems.map((item) => item.nodePath),
|
|
50
|
+
onFormatFile: (stage) => {
|
|
51
|
+
(0, hmr_timing_1.logHmrTiming)({
|
|
52
|
+
detail: `file=${fileRelativeToRoot}`,
|
|
53
|
+
logLevel,
|
|
54
|
+
stage: `source-file-format-${stage}`,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
44
57
|
});
|
|
45
58
|
return {
|
|
46
59
|
absolutePath,
|
|
@@ -53,6 +66,11 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
|
|
|
53
66
|
logLine: Math.min(...logLines),
|
|
54
67
|
};
|
|
55
68
|
}));
|
|
69
|
+
(0, hmr_timing_1.logHmrTiming)({
|
|
70
|
+
detail: `files=${updates.length}`,
|
|
71
|
+
logLevel,
|
|
72
|
+
stage: 'delete-jsx-node-codemod-complete',
|
|
73
|
+
});
|
|
56
74
|
const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
|
|
57
75
|
absolutePath: update.absolutePath,
|
|
58
76
|
remappings: update.nodePathRemappings,
|
|
@@ -76,12 +94,22 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
|
|
|
76
94
|
nodePathRemappings: update.nodePathRemappings,
|
|
77
95
|
});
|
|
78
96
|
(0, undo_stack_1.suppressUndoStackInvalidation)(update.absolutePath);
|
|
97
|
+
(0, hmr_timing_1.logHmrTiming)({
|
|
98
|
+
detail: `file=${update.fileRelativeToRoot}`,
|
|
99
|
+
logLevel,
|
|
100
|
+
stage: 'source-file-write-start',
|
|
101
|
+
});
|
|
79
102
|
(0, file_watcher_1.writeFileAndNotifyFileWatchers)({
|
|
80
103
|
file: update.absolutePath,
|
|
81
104
|
content: update.output,
|
|
82
105
|
originatorClientId: undefined,
|
|
83
106
|
metadata: { skipSequencePropsUpdate: true },
|
|
84
107
|
});
|
|
108
|
+
(0, hmr_timing_1.logHmrTiming)({
|
|
109
|
+
detail: `file=${update.fileRelativeToRoot}`,
|
|
110
|
+
logLevel,
|
|
111
|
+
stage: 'source-file-write-complete',
|
|
112
|
+
});
|
|
85
113
|
const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
|
|
86
114
|
remotionRoot,
|
|
87
115
|
absolutePath: update.absolutePath,
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DeleteSequenceKeyframeRequest, DeleteSequenceKeyframeResponse } from '@remotion/studio-shared';
|
|
2
|
+
import type { ApiHandler } from '../api-types';
|
|
3
|
+
export declare const deleteSequenceKeyframeHandler: ApiHandler<DeleteSequenceKeyframeRequest, DeleteSequenceKeyframeResponse>;
|
|
@@ -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;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { type DownloadRemoteAssetRequest, type DownloadRemoteAssetResponse
|
|
1
|
+
import { getRemoteAssetFilename, type DownloadRemoteAssetRequest, type DownloadRemoteAssetResponse } from '@remotion/studio-shared';
|
|
2
2
|
import type { ApiHandler } from '../api-types';
|
|
3
|
-
export
|
|
4
|
-
fileType: ImageFileType;
|
|
5
|
-
url: URL;
|
|
6
|
-
}) => string;
|
|
3
|
+
export { getRemoteAssetFilename };
|
|
7
4
|
export declare const downloadRemoteAssetHandler: ApiHandler<DownloadRemoteAssetRequest, DownloadRemoteAssetResponse>;
|
|
@@ -9,58 +9,9 @@ const node_fs_1 = require("node:fs");
|
|
|
9
9
|
const node_net_1 = require("node:net");
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
12
|
+
Object.defineProperty(exports, "getRemoteAssetFilename", { enumerable: true, get: function () { return studio_shared_1.getRemoteAssetFilename; } });
|
|
12
13
|
const validate_same_origin_1 = require("../validate-same-origin");
|
|
13
|
-
const maxRemoteAssetSize = 50 * 1024 * 1024;
|
|
14
|
-
const remoteAssetDownloadTimeout = 15000;
|
|
15
14
|
const maxRemoteAssetRedirects = 5;
|
|
16
|
-
const remoteAssetAcceptHeader = 'image/png,image/apng,image/jpeg,image/webp,image/bmp,image/gif';
|
|
17
|
-
const extensionsForFileType = {
|
|
18
|
-
png: ['png'],
|
|
19
|
-
apng: ['png', 'apng'],
|
|
20
|
-
jpeg: ['jpg', 'jpeg'],
|
|
21
|
-
webp: ['webp'],
|
|
22
|
-
bmp: ['bmp'],
|
|
23
|
-
gif: ['gif'],
|
|
24
|
-
};
|
|
25
|
-
const safeDecodeURIComponent = (value) => {
|
|
26
|
-
try {
|
|
27
|
-
return decodeURIComponent(value);
|
|
28
|
-
}
|
|
29
|
-
catch (_a) {
|
|
30
|
-
return value;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
const sanitizeAssetFilename = (filename) => {
|
|
34
|
-
return Array.from(filename)
|
|
35
|
-
.map((character) => {
|
|
36
|
-
const charCode = character.charCodeAt(0);
|
|
37
|
-
return charCode <= 31 || '<>:"/\\|?*'.includes(character)
|
|
38
|
-
? '-'
|
|
39
|
-
: character;
|
|
40
|
-
})
|
|
41
|
-
.join('')
|
|
42
|
-
.trim()
|
|
43
|
-
.replace(/^[. ]+|[. ]+$/g, '');
|
|
44
|
-
};
|
|
45
|
-
const getRemoteAssetFilename = ({ fileType, url, }) => {
|
|
46
|
-
const basename = safeDecodeURIComponent(node_path_1.default.posix.basename(url.pathname));
|
|
47
|
-
const sanitized = sanitizeAssetFilename(basename);
|
|
48
|
-
const filenameWithoutFallback = sanitized === '' ? 'image' : sanitized;
|
|
49
|
-
const extensions = extensionsForFileType[fileType.type];
|
|
50
|
-
const extension = node_path_1.default
|
|
51
|
-
.extname(filenameWithoutFallback)
|
|
52
|
-
.slice(1)
|
|
53
|
-
.toLowerCase();
|
|
54
|
-
if (extensions.includes(extension)) {
|
|
55
|
-
return filenameWithoutFallback;
|
|
56
|
-
}
|
|
57
|
-
const withoutExtension = extension
|
|
58
|
-
? filenameWithoutFallback.slice(0, -(extension.length + 1))
|
|
59
|
-
: filenameWithoutFallback;
|
|
60
|
-
const safeName = withoutExtension === '' ? 'image' : withoutExtension;
|
|
61
|
-
return `${safeName}.${extensions[0]}`;
|
|
62
|
-
};
|
|
63
|
-
exports.getRemoteAssetFilename = getRemoteAssetFilename;
|
|
64
15
|
const isForbiddenIpv4Address = (address) => {
|
|
65
16
|
const parts = address.split('.').map((part) => Number(part));
|
|
66
17
|
if (parts.length !== 4 ||
|
|
@@ -131,7 +82,7 @@ const fetchRemoteAsset = async ({ signal, url, }) => {
|
|
|
131
82
|
await ensureRemoteUrlIsAllowed(currentUrl);
|
|
132
83
|
const response = await fetch(currentUrl, {
|
|
133
84
|
headers: {
|
|
134
|
-
accept: remoteAssetAcceptHeader,
|
|
85
|
+
accept: studio_shared_1.remoteAssetAcceptHeader,
|
|
135
86
|
},
|
|
136
87
|
redirect: 'manual',
|
|
137
88
|
signal,
|
|
@@ -153,13 +104,13 @@ const fetchRemoteAsset = async ({ signal, url, }) => {
|
|
|
153
104
|
};
|
|
154
105
|
const readRemoteAsset = async ({ response, abort, }) => {
|
|
155
106
|
const contentLength = response.headers.get('content-length');
|
|
156
|
-
if (contentLength !== null && Number(contentLength) > maxRemoteAssetSize) {
|
|
107
|
+
if (contentLength !== null && Number(contentLength) > studio_shared_1.maxRemoteAssetSize) {
|
|
157
108
|
abort();
|
|
158
109
|
throw new Error('Remote asset exceeds the 50MB size limit');
|
|
159
110
|
}
|
|
160
111
|
if (!response.body) {
|
|
161
112
|
const buffer = await response.arrayBuffer();
|
|
162
|
-
if (buffer.byteLength > maxRemoteAssetSize) {
|
|
113
|
+
if (buffer.byteLength > studio_shared_1.maxRemoteAssetSize) {
|
|
163
114
|
throw new Error('Remote asset exceeds the 50MB size limit');
|
|
164
115
|
}
|
|
165
116
|
return new Uint8Array(buffer);
|
|
@@ -176,7 +127,7 @@ const readRemoteAsset = async ({ response, abort, }) => {
|
|
|
176
127
|
continue;
|
|
177
128
|
}
|
|
178
129
|
size += value.byteLength;
|
|
179
|
-
if (size > maxRemoteAssetSize) {
|
|
130
|
+
if (size > studio_shared_1.maxRemoteAssetSize) {
|
|
180
131
|
abort();
|
|
181
132
|
await reader.cancel();
|
|
182
133
|
throw new Error('Remote asset exceeds the 50MB size limit');
|
|
@@ -203,7 +154,7 @@ const downloadRemoteAssetHandler = async ({ input, publicDir, request }) => {
|
|
|
203
154
|
const controller = new AbortController();
|
|
204
155
|
const timeout = setTimeout(() => {
|
|
205
156
|
controller.abort();
|
|
206
|
-
}, remoteAssetDownloadTimeout);
|
|
157
|
+
}, studio_shared_1.remoteAssetDownloadTimeout);
|
|
207
158
|
let contents;
|
|
208
159
|
try {
|
|
209
160
|
const response = await fetchRemoteAsset({
|
|
@@ -231,7 +182,7 @@ const downloadRemoteAssetHandler = async ({ input, publicDir, request }) => {
|
|
|
231
182
|
if (!(0, studio_shared_1.isImageFileType)(fileType)) {
|
|
232
183
|
throw new Error('Remote asset is not a supported image');
|
|
233
184
|
}
|
|
234
|
-
const assetPath = (0,
|
|
185
|
+
const assetPath = (0, studio_shared_1.getRemoteAssetFilename)({ fileType, url });
|
|
235
186
|
const absolutePath = node_path_1.default.join(publicDir, assetPath);
|
|
236
187
|
const relativeToPublicDir = node_path_1.default.relative(publicDir, absolutePath);
|
|
237
188
|
if (relativeToPublicDir.startsWith('..') ||
|
|
@@ -252,20 +203,7 @@ const downloadRemoteAssetHandler = async ({ input, publicDir, request }) => {
|
|
|
252
203
|
(0, node_fs_1.mkdirSync)(node_path_1.default.dirname(absolutePath), { recursive: true });
|
|
253
204
|
(0, node_fs_1.writeFileSync)(absolutePath, contents);
|
|
254
205
|
}
|
|
255
|
-
const element = {
|
|
256
|
-
type: 'asset',
|
|
257
|
-
assetType: fileType.type === 'gif'
|
|
258
|
-
? 'gif'
|
|
259
|
-
: fileType.type === 'apng' ||
|
|
260
|
-
(fileType.type === 'webp' && fileType.animated)
|
|
261
|
-
? 'animated-image'
|
|
262
|
-
: 'image',
|
|
263
|
-
src: assetPath,
|
|
264
|
-
srcType: 'static',
|
|
265
|
-
dimensions: fileType.dimensions,
|
|
266
|
-
durationInFrames: null,
|
|
267
|
-
position: null,
|
|
268
|
-
};
|
|
206
|
+
const element = (0, studio_shared_1.getRemoteAssetElement)({ assetPath, fileType });
|
|
269
207
|
return {
|
|
270
208
|
assetPath,
|
|
271
209
|
sizeInBytes: contents.byteLength,
|
|
@@ -46,13 +46,19 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependenc
|
|
|
46
46
|
manager: manager.manager,
|
|
47
47
|
packages: packagesWithVersions,
|
|
48
48
|
version: '',
|
|
49
|
-
additionalArgs: [],
|
|
49
|
+
additionalArgs: manager.manager === 'yarn' ? [] : ['--ignore-scripts'],
|
|
50
50
|
});
|
|
51
51
|
renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray(`╭─ ${manager.manager} ${command.join(' ')}`));
|
|
52
52
|
const time = Date.now();
|
|
53
53
|
try {
|
|
54
54
|
await new Promise((resolve, reject) => {
|
|
55
|
-
const cmd = (0, node_child_process_1.spawn)(manager.manager, command,
|
|
55
|
+
const cmd = (0, node_child_process_1.spawn)(manager.manager, command, {
|
|
56
|
+
...(0, package_manager_spawn_options_1.getPackageManagerSpawnOptions)(),
|
|
57
|
+
env: {
|
|
58
|
+
...process.env,
|
|
59
|
+
YARN_ENABLE_SCRIPTS: 'false',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
56
62
|
cmd.on('error', reject);
|
|
57
63
|
cmd.stdout.on('data', (d) => d
|
|
58
64
|
.toString()
|
|
@@ -8,15 +8,25 @@ const node_fs_1 = require("node:fs");
|
|
|
8
8
|
const node_os_1 = require("node:os");
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
const detect_outdated_remotion_skills_1 = require("../../detect-outdated-remotion-skills");
|
|
11
|
+
const remotion_skill_names_1 = require("../../remotion-skill-names");
|
|
11
12
|
const getRemotionSkillsInfo = ({ remotionRoot, homeDirectory = (0, node_os_1.homedir)(), }) => {
|
|
12
13
|
const skillsDirectories = (0, detect_outdated_remotion_skills_1.getRemotionSkillsDirectories)({
|
|
13
14
|
cwd: remotionRoot,
|
|
14
15
|
homeDirectory,
|
|
15
16
|
});
|
|
16
|
-
const
|
|
17
|
+
const skills = remotion_skill_names_1.remotionSkillNames.map((name) => ({
|
|
18
|
+
name,
|
|
19
|
+
installedInProject: (0, node_fs_1.existsSync)(node_path_1.default.join(skillsDirectories.project, name, 'SKILL.md')),
|
|
20
|
+
installedGlobally: (0, node_fs_1.existsSync)(node_path_1.default.join(skillsDirectories.global, name, 'SKILL.md')),
|
|
21
|
+
}));
|
|
22
|
+
const isSkillAvailable = (skillName) => {
|
|
23
|
+
const skill = skills.find(({ name }) => name === skillName);
|
|
24
|
+
return Boolean((skill === null || skill === void 0 ? void 0 : skill.installedInProject) || (skill === null || skill === void 0 ? void 0 : skill.installedGlobally));
|
|
25
|
+
};
|
|
17
26
|
return {
|
|
18
27
|
remotionUpgradeSkillAvailable: isSkillAvailable('remotion-upgrade'),
|
|
19
28
|
remotionInteractivitySkillAvailable: isSkillAvailable('remotion-interactivity'),
|
|
29
|
+
skills,
|
|
20
30
|
};
|
|
21
31
|
};
|
|
22
32
|
exports.getRemotionSkillsInfo = getRemotionSkillsInfo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withSavePropsLock: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withSavePropsLock = void 0;
|
|
4
|
+
let chain = Promise.resolve();
|
|
5
|
+
const withSavePropsLock = (fn) => {
|
|
6
|
+
const run = () => fn();
|
|
7
|
+
const next = chain.then(run, run);
|
|
8
|
+
chain = next.then(() => undefined, () => undefined);
|
|
9
|
+
return next;
|
|
10
|
+
};
|
|
11
|
+
exports.withSavePropsLock = withSavePropsLock;
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* MIT Licensed
|
|
7
7
|
*/
|
|
8
8
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
9
|
-
export declare const serveStatic: ({ root, path, req, res, allowOutsidePublicFolder, }: {
|
|
9
|
+
export declare const serveStatic: ({ root, path, req, res, allowOutsidePublicFolder, allowRemotionConvertCors, }: {
|
|
10
10
|
root: string;
|
|
11
11
|
path: string;
|
|
12
12
|
req: IncomingMessage;
|
|
13
13
|
res: ServerResponse<IncomingMessage>;
|
|
14
14
|
allowOutsidePublicFolder: boolean;
|
|
15
|
+
allowRemotionConvertCors: boolean;
|
|
15
16
|
}) => Promise<void>;
|
|
@@ -12,7 +12,36 @@ const node_fs_1 = require("node:fs");
|
|
|
12
12
|
const renderer_1 = require("@remotion/renderer");
|
|
13
13
|
const middleware_1 = require("./dev-middleware/middleware");
|
|
14
14
|
const range_parser_1 = require("./dev-middleware/range-parser");
|
|
15
|
-
const
|
|
15
|
+
const remotionConvertOrigins = [
|
|
16
|
+
'https://remotion.dev',
|
|
17
|
+
'https://www.remotion.dev',
|
|
18
|
+
'https://convert.remotion.dev',
|
|
19
|
+
];
|
|
20
|
+
const applyRemotionConvertCorsHeaders = ({ req, res, }) => {
|
|
21
|
+
const { origin } = req.headers;
|
|
22
|
+
if (!origin || !remotionConvertOrigins.includes(origin)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
26
|
+
res.setHeader('Vary', 'Origin, Access-Control-Request-Headers, Access-Control-Request-Private-Network');
|
|
27
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
|
|
28
|
+
res.setHeader('Access-Control-Allow-Headers', 'Range, Content-Type');
|
|
29
|
+
res.setHeader('Access-Control-Expose-Headers', 'Accept-Ranges, Content-Length, Content-Range');
|
|
30
|
+
res.setHeader('Access-Control-Max-Age', '600');
|
|
31
|
+
if (req.headers['access-control-request-private-network']) {
|
|
32
|
+
res.setHeader('Access-Control-Allow-Private-Network', 'true');
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
};
|
|
36
|
+
const serveStatic = async function ({ root, path, req, res, allowOutsidePublicFolder, allowRemotionConvertCors, }) {
|
|
37
|
+
const remotionConvertCorsAllowed = allowRemotionConvertCors
|
|
38
|
+
? applyRemotionConvertCorsHeaders({ req, res })
|
|
39
|
+
: false;
|
|
40
|
+
if (req.method === 'OPTIONS' && remotionConvertCorsAllowed) {
|
|
41
|
+
res.statusCode = 204;
|
|
42
|
+
res.end();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
16
45
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
17
46
|
// method not allowed
|
|
18
47
|
res.statusCode = 405;
|
|
@@ -43,6 +72,7 @@ const serveStatic = async function ({ root, path, req, res, allowOutsidePublicFo
|
|
|
43
72
|
req,
|
|
44
73
|
res,
|
|
45
74
|
allowOutsidePublicFolder: true,
|
|
75
|
+
allowRemotionConvertCors,
|
|
46
76
|
});
|
|
47
77
|
}
|
|
48
78
|
const isDirectory = lstat.isDirectory();
|
package/dist/routes.js
CHANGED
|
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.handleRoutes = void 0;
|
|
37
|
-
const fs_1 = __importStar(require("fs"));
|
|
38
37
|
const node_fs_1 = require("node:fs");
|
|
39
38
|
const node_path_1 = __importStar(require("node:path"));
|
|
40
39
|
const node_url_1 = require("node:url");
|
|
@@ -45,6 +44,7 @@ const better_opn_1 = require("./better-opn");
|
|
|
45
44
|
const client_render_queue_1 = require("./client-render-queue");
|
|
46
45
|
const get_file_source_1 = require("./helpers/get-file-source");
|
|
47
46
|
const get_installed_installable_packages_1 = require("./helpers/get-installed-installable-packages");
|
|
47
|
+
const open_file_for_writing_without_symlinks_1 = require("./helpers/open-file-for-writing-without-symlinks");
|
|
48
48
|
const resolve_output_path_1 = require("./helpers/resolve-output-path");
|
|
49
49
|
const api_routes_1 = require("./preview-server/api-routes");
|
|
50
50
|
const get_package_manager_1 = require("./preview-server/get-package-manager");
|
|
@@ -61,6 +61,21 @@ const origin_policy_1 = require("./preview-server/studio-protocol/origin-policy"
|
|
|
61
61
|
const validate_same_origin_1 = require("./preview-server/validate-same-origin");
|
|
62
62
|
const watch_ignore_next_change_1 = require("./preview-server/watch-ignore-next-change");
|
|
63
63
|
const loggedStaticFileHints = new Set();
|
|
64
|
+
const clientRenderOutputExtensions = new Set([
|
|
65
|
+
'aac',
|
|
66
|
+
'flac',
|
|
67
|
+
'jpeg',
|
|
68
|
+
'jpg',
|
|
69
|
+
'mkv',
|
|
70
|
+
'mov',
|
|
71
|
+
'mp3',
|
|
72
|
+
'mp4',
|
|
73
|
+
'ogg',
|
|
74
|
+
'png',
|
|
75
|
+
'wav',
|
|
76
|
+
'webm',
|
|
77
|
+
'webp',
|
|
78
|
+
]);
|
|
64
79
|
const static404 = (response) => {
|
|
65
80
|
response.writeHead(404);
|
|
66
81
|
response.end('The static/ prefix has been changed, this URL is no longer valid.');
|
|
@@ -188,8 +203,14 @@ const handleAddAsset = ({ req, res, search, publicDir, }) => {
|
|
|
188
203
|
if (relativeToPublicDir.startsWith('..')) {
|
|
189
204
|
throw new Error(`Not allowed to write to ${relativeToPublicDir}`);
|
|
190
205
|
}
|
|
191
|
-
|
|
192
|
-
|
|
206
|
+
const fileDescriptor = (0, open_file_for_writing_without_symlinks_1.openFileForWritingWithoutSymlinks)({
|
|
207
|
+
rootDirectory: publicDir,
|
|
208
|
+
absolutePath,
|
|
209
|
+
});
|
|
210
|
+
const writeStream = (0, node_fs_1.createWriteStream)(absolutePath, {
|
|
211
|
+
fd: fileDescriptor,
|
|
212
|
+
autoClose: true,
|
|
213
|
+
});
|
|
193
214
|
writeStream.on('close', () => {
|
|
194
215
|
res.end(JSON.stringify({ success: true }));
|
|
195
216
|
});
|
|
@@ -210,8 +231,18 @@ const handleUploadOutput = ({ req, res, search, remotionRoot, }) => {
|
|
|
210
231
|
throw new Error('No `filePath` provided');
|
|
211
232
|
}
|
|
212
233
|
const absolutePath = (0, resolve_output_path_1.resolveOutputPath)(remotionRoot, filePath);
|
|
213
|
-
|
|
214
|
-
|
|
234
|
+
const extension = node_path_1.default.extname(absolutePath).slice(1).toLowerCase();
|
|
235
|
+
if (!clientRenderOutputExtensions.has(extension)) {
|
|
236
|
+
throw new Error(`Not allowed to upload a .${extension || 'unknown'} file`);
|
|
237
|
+
}
|
|
238
|
+
const fileDescriptor = (0, open_file_for_writing_without_symlinks_1.openFileForWritingWithoutSymlinks)({
|
|
239
|
+
rootDirectory: remotionRoot,
|
|
240
|
+
absolutePath,
|
|
241
|
+
});
|
|
242
|
+
const writeStream = (0, node_fs_1.createWriteStream)(absolutePath, {
|
|
243
|
+
fd: fileDescriptor,
|
|
244
|
+
autoClose: true,
|
|
245
|
+
});
|
|
215
246
|
writeStream.on('close', () => {
|
|
216
247
|
res.end(JSON.stringify({ success: true }));
|
|
217
248
|
});
|
|
@@ -365,6 +396,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
|
|
|
365
396
|
req: request,
|
|
366
397
|
res: response,
|
|
367
398
|
allowOutsidePublicFolder: false,
|
|
399
|
+
allowRemotionConvertCors: true,
|
|
368
400
|
});
|
|
369
401
|
}
|
|
370
402
|
if (url.pathname.startsWith(staticHashPrefix)) {
|
|
@@ -379,6 +411,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
|
|
|
379
411
|
req: request,
|
|
380
412
|
res: response,
|
|
381
413
|
allowOutsidePublicFolder: false,
|
|
414
|
+
allowRemotionConvertCors: false,
|
|
382
415
|
});
|
|
383
416
|
}
|
|
384
417
|
if (url.pathname.startsWith(outputHashPrefix)) {
|
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.516",
|
|
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.516",
|
|
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.
|
|
36
|
-
"recast": "0.23.
|
|
37
|
-
"@remotion/bundler": "4.0.
|
|
38
|
-
"@remotion/renderer": "4.0.
|
|
39
|
-
"@remotion/studio-codemods": "4.0.
|
|
40
|
-
"@remotion/studio-shared": "4.0.
|
|
35
|
+
"remotion": "4.0.516",
|
|
36
|
+
"recast": "0.23.21",
|
|
37
|
+
"@remotion/bundler": "4.0.516",
|
|
38
|
+
"@remotion/renderer": "4.0.516",
|
|
39
|
+
"@remotion/studio-codemods": "4.0.516",
|
|
40
|
+
"@remotion/studio-shared": "4.0.516",
|
|
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.516",
|
|
49
49
|
"eslint": "9.19.0",
|
|
50
50
|
"@types/node": "20.12.14",
|
|
51
51
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|