@remotion/studio-server 4.0.505 → 4.0.507
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/effect-param-expression.js +2 -0
- package/dist/codemods/update-keyframes/update-keyframes.js +2 -0
- package/dist/helpers/coding-agent-registry.d.ts +49 -0
- package/dist/helpers/coding-agent-registry.js +515 -0
- package/dist/helpers/editor-registry.d.ts +1 -0
- package/dist/helpers/editor-registry.js +31 -3
- package/dist/helpers/open-in-editor.js +5 -5
- package/dist/helpers/parse-keyframe-easing-expression.js +3 -0
- package/dist/helpers/resolve-editor.d.ts +2 -0
- package/dist/helpers/resolve-editor.js +4 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +2 -0
- package/dist/preview-server/api-routes.js +7 -3
- package/dist/preview-server/api-types.d.ts +2 -1
- package/dist/preview-server/handler.d.ts +2 -1
- package/dist/preview-server/handler.js +2 -1
- package/dist/preview-server/routes/add-render.js +2 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +28 -5
- package/dist/preview-server/routes/copy-render-output-to-asset.d.ts +3 -0
- package/dist/preview-server/routes/copy-render-output-to-asset.js +58 -0
- package/dist/preview-server/routes/default-coding-agent.d.ts +4 -0
- package/dist/preview-server/routes/default-coding-agent.js +32 -0
- package/dist/preview-server/routes/default-editor.d.ts +1 -6
- package/dist/preview-server/routes/default-editor.js +13 -113
- package/dist/preview-server/routes/element-install-plan.d.ts +1 -0
- package/dist/preview-server/routes/insert-element.js +27 -11
- package/dist/preview-server/routes/install-dependency.d.ts +2 -3
- package/dist/preview-server/routes/install-dependency.js +5 -7
- package/dist/preview-server/routes/open-in-editor.js +1 -1
- package/dist/preview-server/routes/update-config.d.ts +7 -0
- package/dist/preview-server/routes/update-config.js +188 -0
- package/dist/preview-server/start-server.d.ts +1 -0
- package/dist/preview-server/start-server.js +1 -0
- package/dist/preview-server/studio-protocol/handle-discovery.js +3 -4
- package/dist/preview-server/studio-protocol/handle-install.js +1 -1
- package/dist/preview-server/studio-protocol/handle-license-key.d.ts +6 -1
- package/dist/preview-server/studio-protocol/handle-license-key.js +13 -15
- package/dist/preview-server/studio-protocol/origin-policy.d.ts +2 -5
- package/dist/preview-server/studio-protocol/origin-policy.js +6 -30
- package/dist/remotion-skill-names.d.ts +1 -1
- package/dist/remotion-skill-names.js +1 -0
- package/dist/routes.d.ts +2 -1
- package/dist/routes.js +11 -3
- package/dist/start-studio.d.ts +2 -1
- package/dist/start-studio.js +2 -1
- package/package.json +8 -8
- package/web/coding-agent-icons/claude-code.png +0 -0
- package/web/coding-agent-icons/codex.png +0 -0
- package/web/coding-agent-icons/copilot.png +0 -0
- package/web/coding-agent-icons/cursor.png +0 -0
- package/dist/preview-server/routes/delete-effect-keyframe.d.ts +0 -3
- package/dist/preview-server/routes/delete-effect-keyframe.js +0 -89
- package/dist/preview-server/routes/delete-sequence-keyframe.d.ts +0 -3
- package/dist/preview-server/routes/delete-sequence-keyframe.js +0 -82
- package/dist/preview-server/routes/save-props-mutex.d.ts +0 -1
- package/dist/preview-server/routes/save-props-mutex.js +0 -11
|
@@ -1,73 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
const node_fs_1 = require("node:fs");
|
|
38
|
-
const renderer_1 = require("@remotion/renderer");
|
|
39
|
-
const recast = __importStar(require("recast"));
|
|
40
|
-
const parse_ast_1 = require("../../codemods/parse-ast");
|
|
41
|
-
const file_watcher_1 = require("../../file-watcher");
|
|
3
|
+
exports.getDefaultEditorInfoHandler = void 0;
|
|
42
4
|
const editor_registry_1 = require("../../helpers/editor-registry");
|
|
43
|
-
const updateDefaultEditorInConfig = ({ configContents, defaultEditor, }) => {
|
|
44
|
-
const ast = (0, parse_ast_1.parseAst)(configContents);
|
|
45
|
-
recast.types.visit(ast.program, {
|
|
46
|
-
visitExpressionStatement(path) {
|
|
47
|
-
const { expression } = path.node;
|
|
48
|
-
if (expression.type === 'CallExpression' &&
|
|
49
|
-
expression.callee.type === 'MemberExpression' &&
|
|
50
|
-
!expression.callee.computed &&
|
|
51
|
-
expression.callee.object.type === 'Identifier' &&
|
|
52
|
-
expression.callee.object.name === 'Config' &&
|
|
53
|
-
expression.callee.property.type === 'Identifier' &&
|
|
54
|
-
expression.callee.property.name === 'setDefaultEditor') {
|
|
55
|
-
path.prune();
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
this.traverse(path);
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
const configWithoutExistingCalls = recast.print(ast, {
|
|
62
|
-
lineTerminator: '\n',
|
|
63
|
-
}).code;
|
|
64
|
-
if (defaultEditor === null) {
|
|
65
|
-
return configWithoutExistingCalls;
|
|
66
|
-
}
|
|
67
|
-
const separator = configWithoutExistingCalls.endsWith('\n') ? '' : '\n';
|
|
68
|
-
return `${configWithoutExistingCalls}${separator}Config.setDefaultEditor('${defaultEditor}');\n`;
|
|
69
|
-
};
|
|
70
|
-
exports.updateDefaultEditorInConfig = updateDefaultEditorInConfig;
|
|
71
5
|
const getDefaultEditorInfoHandler = async ({ getDefaultEditor }) => {
|
|
72
6
|
const installedEditors = await (0, editor_registry_1.getAvailableEditors)();
|
|
73
7
|
const configuredEditor = getDefaultEditor();
|
|
@@ -77,55 +11,21 @@ const getDefaultEditorInfoHandler = async ({ getDefaultEditor }) => {
|
|
|
77
11
|
return {
|
|
78
12
|
defaultEditor: typeof configuredEditor === 'object' ? 'custom' : configuredEditor,
|
|
79
13
|
installedEditors: [
|
|
80
|
-
...installedEditors.map(({ id, name }) => ({
|
|
14
|
+
...installedEditors.map(({ id, name, nameWithType }) => ({
|
|
15
|
+
id,
|
|
16
|
+
name,
|
|
17
|
+
nameWithType,
|
|
18
|
+
})),
|
|
81
19
|
...(customEditor
|
|
82
|
-
? [
|
|
20
|
+
? [
|
|
21
|
+
{
|
|
22
|
+
id: 'custom',
|
|
23
|
+
name: customEditor.name,
|
|
24
|
+
nameWithType: customEditor.name,
|
|
25
|
+
},
|
|
26
|
+
]
|
|
83
27
|
: []),
|
|
84
28
|
],
|
|
85
29
|
};
|
|
86
30
|
};
|
|
87
31
|
exports.getDefaultEditorInfoHandler = getDefaultEditorInfoHandler;
|
|
88
|
-
const updateDefaultEditorHandler = async ({ input, configFile, getDefaultEditor }) => {
|
|
89
|
-
if (configFile === null || configFile === undefined) {
|
|
90
|
-
return {
|
|
91
|
-
success: false,
|
|
92
|
-
reason: 'No Remotion config file was loaded.',
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
if (input.defaultEditor === 'custom') {
|
|
96
|
-
const configuredEditor = getDefaultEditor();
|
|
97
|
-
if (!configuredEditor || typeof configuredEditor !== 'object') {
|
|
98
|
-
return {
|
|
99
|
-
success: false,
|
|
100
|
-
reason: 'No custom editor is configured.',
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
// The browser only knows the opaque "custom" ID. Keeping the existing
|
|
104
|
-
// config call untouched avoids exposing or rewriting its executable and
|
|
105
|
-
// arguments, which may have come from environment variables.
|
|
106
|
-
return { success: true };
|
|
107
|
-
}
|
|
108
|
-
if (input.defaultEditor !== null &&
|
|
109
|
-
!renderer_1.defaultEditorIds.includes(input.defaultEditor)) {
|
|
110
|
-
return {
|
|
111
|
-
success: false,
|
|
112
|
-
reason: `Unknown editor: ${input.defaultEditor}`,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (input.defaultEditor !== null) {
|
|
116
|
-
const installedEditors = await (0, editor_registry_1.getAvailableEditors)();
|
|
117
|
-
if (!installedEditors.some(({ id }) => id === input.defaultEditor)) {
|
|
118
|
-
return {
|
|
119
|
-
success: false,
|
|
120
|
-
reason: 'The selected editor is not installed.',
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const configContents = (0, node_fs_1.readFileSync)(configFile, 'utf8');
|
|
125
|
-
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(configFile, (0, exports.updateDefaultEditorInConfig)({
|
|
126
|
-
configContents,
|
|
127
|
-
defaultEditor: input.defaultEditor,
|
|
128
|
-
}), undefined);
|
|
129
|
-
return { success: true };
|
|
130
|
-
};
|
|
131
|
-
exports.updateDefaultEditorHandler = updateDefaultEditorHandler;
|
|
@@ -5,6 +5,7 @@ export declare const validateElementInstallPosition: (position: import("@remotio
|
|
|
5
5
|
export declare const validateElementForInstallation: (element: {
|
|
6
6
|
dependencies: import("@remotion/studio-protocol").ElementDependency[];
|
|
7
7
|
durationInFrames?: number | undefined;
|
|
8
|
+
installationMode?: import("@remotion/studio-protocol").ElementInstallationMode | undefined;
|
|
8
9
|
slug: string;
|
|
9
10
|
displayName: string;
|
|
10
11
|
sourceCode: string;
|
|
@@ -22,13 +22,15 @@ const hasExpectedFileState = ({ expected, actual, }) => {
|
|
|
22
22
|
return actual.sourceHash === expected.sourceHash;
|
|
23
23
|
};
|
|
24
24
|
const insertElementHandler = ({ input: { compositionFile, compositionId, element, expectedFileState, from, position, overwriteExisting, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
|
|
25
|
-
var _a;
|
|
25
|
+
var _a, _b;
|
|
26
26
|
try {
|
|
27
27
|
(0, element_install_plan_1.validateElementInstallPosition)(position);
|
|
28
28
|
if (from !== null &&
|
|
29
29
|
(!Number.isInteger(from) || !Number.isFinite(from) || from < 0)) {
|
|
30
30
|
throw new Error('from must be a non-negative integer');
|
|
31
31
|
}
|
|
32
|
+
const installationMode = (_a = element.installationMode) !== null && _a !== void 0 ? _a : 'wrapped';
|
|
33
|
+
const componentOwnsSequence = installationMode === 'component-owned-sequence';
|
|
32
34
|
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[insert-element] Received request for compositionFile="${compositionFile}" compositionId="${compositionId}" element="${element.slug}"`);
|
|
33
35
|
const plan = await (0, element_install_plan_1.getElementInstallPlan)({
|
|
34
36
|
compositionFile,
|
|
@@ -81,18 +83,32 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
|
|
|
81
83
|
componentName: plan.componentName,
|
|
82
84
|
importName: plan.componentName,
|
|
83
85
|
importPath: plan.importPath,
|
|
84
|
-
props:
|
|
85
|
-
|
|
86
|
+
props: componentOwnsSequence
|
|
87
|
+
? [
|
|
88
|
+
...(element.durationInFrames === undefined
|
|
89
|
+
? []
|
|
90
|
+
: [
|
|
91
|
+
{
|
|
92
|
+
name: 'durationInFrames',
|
|
93
|
+
value: element.durationInFrames,
|
|
94
|
+
},
|
|
95
|
+
]),
|
|
96
|
+
{ name: 'name', value: element.displayName },
|
|
97
|
+
]
|
|
98
|
+
: [],
|
|
99
|
+
position: componentOwnsSequence ? position : null,
|
|
86
100
|
},
|
|
87
|
-
from: null,
|
|
101
|
+
from: componentOwnsSequence ? from : null,
|
|
88
102
|
prettierConfigOverride: null,
|
|
89
|
-
wrapInSequence:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
wrapInSequence: componentOwnsSequence
|
|
104
|
+
? null
|
|
105
|
+
: {
|
|
106
|
+
dimensions: element.dimensions,
|
|
107
|
+
durationInFrames: (_b = element.durationInFrames) !== null && _b !== void 0 ? _b : null,
|
|
108
|
+
from,
|
|
109
|
+
name: element.displayName,
|
|
110
|
+
position,
|
|
111
|
+
},
|
|
96
112
|
});
|
|
97
113
|
const finalPlan = await (0, element_install_plan_1.getElementInstallPlan)({
|
|
98
114
|
compositionFile,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { type InstallPackageRequest, type InstallPackageResponse } from '@remotion/studio-shared';
|
|
1
|
+
import { type InstallPackageRequest, type InstallPackageResponse, type PackageInstallSpec } from '@remotion/studio-shared';
|
|
3
2
|
import type { ApiHandler } from '../api-types';
|
|
4
|
-
export declare const getPackageInstallSpec: (dependency:
|
|
3
|
+
export declare const getPackageInstallSpec: (dependency: PackageInstallSpec) => string;
|
|
5
4
|
export declare const handleInstallPackage: ApiHandler<InstallPackageRequest, InstallPackageResponse>;
|
|
@@ -13,15 +13,13 @@ const getExtraPackageVersion = (packageName) => {
|
|
|
13
13
|
return pkg ? pkg.version : null;
|
|
14
14
|
};
|
|
15
15
|
const getPackageInstallSpec = (dependency) => {
|
|
16
|
-
const { name, version } =
|
|
17
|
-
? { name: dependency, version: null }
|
|
18
|
-
: dependency;
|
|
19
|
-
const extraVersion = getExtraPackageVersion(name);
|
|
20
|
-
if (extraVersion)
|
|
21
|
-
return `${name}@${extraVersion}`;
|
|
16
|
+
const { name, version } = dependency;
|
|
22
17
|
if (name === 'remotion' || name.startsWith('@remotion/'))
|
|
23
18
|
return `${name}@${version_1.VERSION}`;
|
|
24
|
-
|
|
19
|
+
if (version !== null)
|
|
20
|
+
return `${name}@${version}`;
|
|
21
|
+
const extraVersion = getExtraPackageVersion(name);
|
|
22
|
+
return extraVersion === null ? name : `${name}@${extraVersion}`;
|
|
25
23
|
};
|
|
26
24
|
exports.getPackageInstallSpec = getPackageInstallSpec;
|
|
27
25
|
const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependencies } }) => {
|
|
@@ -16,7 +16,7 @@ const getEditorName = async ({ getDefaultEditor, logLevel, }) => {
|
|
|
16
16
|
logLevel,
|
|
17
17
|
preferredEditor: null,
|
|
18
18
|
});
|
|
19
|
-
return (_a = editor === null || editor === void 0 ? void 0 : editor.
|
|
19
|
+
return (_a = editor === null || editor === void 0 ? void 0 : editor.nameWithType) !== null && _a !== void 0 ? _a : null;
|
|
20
20
|
};
|
|
21
21
|
exports.getEditorName = getEditorName;
|
|
22
22
|
const openInEditorHandler = async ({ input, remotionRoot, logLevel, getDefaultEditor }) => {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ConfigUpdate, type UpdateConfigRequest, type UpdateConfigResponse } from '@remotion/studio-shared';
|
|
2
|
+
import type { ApiHandler } from '../api-types';
|
|
3
|
+
export declare const updateConfigFile: ({ configContents, updates, }: {
|
|
4
|
+
readonly configContents: string;
|
|
5
|
+
readonly updates: ConfigUpdate[];
|
|
6
|
+
}) => string;
|
|
7
|
+
export declare const updateConfigHandler: ApiHandler<UpdateConfigRequest, UpdateConfigResponse>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.updateConfigHandler = exports.updateConfigFile = void 0;
|
|
37
|
+
const node_fs_1 = require("node:fs");
|
|
38
|
+
const renderer_1 = require("@remotion/renderer");
|
|
39
|
+
const studio_shared_1 = require("@remotion/studio-shared");
|
|
40
|
+
const recast = __importStar(require("recast"));
|
|
41
|
+
const parse_ast_1 = require("../../codemods/parse-ast");
|
|
42
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
43
|
+
const editor_registry_1 = require("../../helpers/editor-registry");
|
|
44
|
+
const validSetterName = /^set[A-Z][A-Za-z0-9]*$/;
|
|
45
|
+
const isConfigValue = (value) => {
|
|
46
|
+
if (value === null ||
|
|
47
|
+
typeof value === 'string' ||
|
|
48
|
+
typeof value === 'boolean') {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === 'number') {
|
|
52
|
+
return Number.isFinite(value);
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(value)) {
|
|
55
|
+
return value.every(isConfigValue);
|
|
56
|
+
}
|
|
57
|
+
if (typeof value === 'object') {
|
|
58
|
+
if (Object.getPrototypeOf(value) !== Object.prototype &&
|
|
59
|
+
Object.getPrototypeOf(value) !== null) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return Object.values(value).every(isConfigValue);
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
};
|
|
66
|
+
const validateUpdates = (updates) => {
|
|
67
|
+
if (!Array.isArray(updates) || updates.length === 0) {
|
|
68
|
+
return 'At least one config update is required.';
|
|
69
|
+
}
|
|
70
|
+
const setters = new Set();
|
|
71
|
+
for (const update of updates) {
|
|
72
|
+
if (typeof update !== 'object' || update === null) {
|
|
73
|
+
return 'Each config update must be an object.';
|
|
74
|
+
}
|
|
75
|
+
const { setter, type } = update;
|
|
76
|
+
if (typeof setter !== 'string' ||
|
|
77
|
+
!validSetterName.test(setter) ||
|
|
78
|
+
!(setter in studio_shared_1.configMethodLifecycles)) {
|
|
79
|
+
return `Invalid config setter: ${JSON.stringify(setter)}.`;
|
|
80
|
+
}
|
|
81
|
+
if (setters.has(setter)) {
|
|
82
|
+
return `The config setter ${setter} was specified more than once.`;
|
|
83
|
+
}
|
|
84
|
+
setters.add(setter);
|
|
85
|
+
if (type === 'delete') {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (type !== 'set' ||
|
|
89
|
+
!('value' in update) ||
|
|
90
|
+
!isConfigValue(update.value)) {
|
|
91
|
+
return `Invalid value for Config.${setter}().`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
};
|
|
96
|
+
const updateConfigFile = ({ configContents, updates, }) => {
|
|
97
|
+
const setters = new Set(updates.map(({ setter }) => setter));
|
|
98
|
+
const ast = (0, parse_ast_1.parseAst)(configContents);
|
|
99
|
+
recast.types.visit(ast.program, {
|
|
100
|
+
visitExpressionStatement(path) {
|
|
101
|
+
const { expression } = path.node;
|
|
102
|
+
if (expression.type === 'CallExpression' &&
|
|
103
|
+
expression.callee.type === 'MemberExpression' &&
|
|
104
|
+
!expression.callee.computed &&
|
|
105
|
+
expression.callee.object.type === 'Identifier' &&
|
|
106
|
+
expression.callee.object.name === 'Config' &&
|
|
107
|
+
expression.callee.property.type === 'Identifier' &&
|
|
108
|
+
setters.has(expression.callee.property.name)) {
|
|
109
|
+
path.prune();
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
this.traverse(path);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
let updatedConfig = recast.print(ast, { lineTerminator: '\n' }).code;
|
|
116
|
+
for (const update of updates) {
|
|
117
|
+
if (update.type === 'delete') {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const serializedValue = JSON.stringify(update.value)
|
|
121
|
+
.replaceAll('\u2028', '\\u2028')
|
|
122
|
+
.replaceAll('\u2029', '\\u2029');
|
|
123
|
+
const statement = (0, parse_ast_1.parseAst)(`Config.${update.setter}(${serializedValue});`)
|
|
124
|
+
.program.body[0];
|
|
125
|
+
const separator = updatedConfig.endsWith('\n') ? '' : '\n';
|
|
126
|
+
updatedConfig += `${separator}${recast.prettyPrint(statement, {
|
|
127
|
+
lineTerminator: '\n',
|
|
128
|
+
quote: 'single',
|
|
129
|
+
useTabs: true,
|
|
130
|
+
}).code}\n`;
|
|
131
|
+
}
|
|
132
|
+
return updatedConfig;
|
|
133
|
+
};
|
|
134
|
+
exports.updateConfigFile = updateConfigFile;
|
|
135
|
+
const updateConfigHandler = async ({ input, configFile }) => {
|
|
136
|
+
if (configFile === null || configFile === undefined) {
|
|
137
|
+
return {
|
|
138
|
+
success: false,
|
|
139
|
+
reason: 'No Remotion config file was loaded.',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const validationError = validateUpdates(input.updates);
|
|
143
|
+
if (validationError !== null) {
|
|
144
|
+
return { success: false, reason: validationError };
|
|
145
|
+
}
|
|
146
|
+
for (const update of input.updates) {
|
|
147
|
+
if (update.type === 'delete') {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (update.setter === 'setDefaultCodingAgent' &&
|
|
151
|
+
(typeof update.value !== 'string' ||
|
|
152
|
+
!renderer_1.defaultCodingAgentIds.includes(update.value))) {
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
reason: `Unknown coding agent: ${JSON.stringify(update.value)}`,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (update.setter === 'setDefaultEditor') {
|
|
159
|
+
if (typeof update.value !== 'string' ||
|
|
160
|
+
!renderer_1.defaultEditorIds.includes(update.value)) {
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
reason: `Unknown editor: ${JSON.stringify(update.value)}`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const installedEditors = await (0, editor_registry_1.getAvailableEditors)();
|
|
167
|
+
if (!installedEditors.some(({ id }) => id === update.value)) {
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
reason: 'The selected editor is not installed.',
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (update.setter === 'setPublicLicenseKey' &&
|
|
175
|
+
(typeof update.value !== 'string' ||
|
|
176
|
+
(update.value !== 'free-license' &&
|
|
177
|
+
!update.value.startsWith('rm_pub_')))) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
reason: 'The public license key must start with "rm_pub_" or be "free-license".',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const configContents = (0, node_fs_1.readFileSync)(configFile, 'utf8');
|
|
185
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(configFile, (0, exports.updateConfigFile)({ configContents, updates: input.updates }), input.clientId);
|
|
186
|
+
return { success: true };
|
|
187
|
+
};
|
|
188
|
+
exports.updateConfigHandler = updateConfigHandler;
|
|
@@ -42,6 +42,7 @@ export declare const startServer: (options: {
|
|
|
42
42
|
forceNew: boolean;
|
|
43
43
|
rspack: boolean;
|
|
44
44
|
getStudioRuntimeConfig: () => StudioRuntimeConfig;
|
|
45
|
+
getDefaultCodingAgent: () => "claude-code" | "codex" | "copilot" | "cursor" | null;
|
|
45
46
|
getDefaultEditor: () => DefaultEditor | null;
|
|
46
47
|
configFile: string | null;
|
|
47
48
|
}) => Promise<StartServerResult>;
|
|
@@ -102,6 +102,7 @@ const startServer = async (options) => {
|
|
|
102
102
|
getPreviewSampleRate: options.getPreviewSampleRate,
|
|
103
103
|
enableCrossSiteIsolation: options.enableCrossSiteIsolation,
|
|
104
104
|
getStudioRuntimeConfig: options.getStudioRuntimeConfig,
|
|
105
|
+
getDefaultCodingAgent: options.getDefaultCodingAgent,
|
|
105
106
|
getDefaultEditor: options.getDefaultEditor,
|
|
106
107
|
configFile: options.configFile,
|
|
107
108
|
});
|
|
@@ -43,7 +43,7 @@ const getProject = ({ gitSource, remotionRoot, }) => (0, studio_shared_1.getProj
|
|
|
43
43
|
resolvedRemotionRoot: remotionRoot,
|
|
44
44
|
});
|
|
45
45
|
const handleStudioProtocolDiscovery = ({ gitSource, liveEventsServer, remotionRoot, request, response, }) => {
|
|
46
|
-
(0, origin_policy_1.setStudioProtocolCorsHeaders)({
|
|
46
|
+
(0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
|
|
47
47
|
const requestOrigin = (0, origin_policy_1.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
48
48
|
if (requestOrigin === null) {
|
|
49
49
|
(0, protocol_response_1.writeStudioProtocolError)({
|
|
@@ -77,12 +77,11 @@ const handleStudioProtocolDiscovery = ({ gitSource, liveEventsServer, remotionRo
|
|
|
77
77
|
purpose: 'install-element',
|
|
78
78
|
target: installTarget,
|
|
79
79
|
});
|
|
80
|
-
const
|
|
81
|
-
const issuedLicenseKeyTarget = target === null || licenseKeyOrigin === null
|
|
80
|
+
const issuedLicenseKeyTarget = target === null
|
|
82
81
|
? null
|
|
83
82
|
: (0, element_install_state_1.issueStudioProtocolTarget)({
|
|
84
83
|
now,
|
|
85
|
-
origin:
|
|
84
|
+
origin: requestOrigin,
|
|
86
85
|
purpose: 'set-license-key',
|
|
87
86
|
target,
|
|
88
87
|
});
|
|
@@ -45,7 +45,7 @@ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, orig
|
|
|
45
45
|
return delivered;
|
|
46
46
|
};
|
|
47
47
|
const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, request, response, }) => {
|
|
48
|
-
(0, origin_policy_1.setStudioProtocolCorsHeaders)({
|
|
48
|
+
(0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
|
|
49
49
|
const requestOrigin = (0, origin_policy_1.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
50
50
|
if (requestOrigin === null) {
|
|
51
51
|
(0, protocol_response_1.writeStudioProtocolError)({
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
|
|
2
|
+
import type { LiveEventsServer } from '../live-events';
|
|
3
|
+
type FocusStudioTab = (studioUrl: string) => void;
|
|
4
|
+
export declare const handleStudioProtocolLicenseKey: ({ configFile, focusStudioTab, liveEventsServer, request, response, }: {
|
|
3
5
|
readonly configFile: string | null;
|
|
6
|
+
readonly focusStudioTab: FocusStudioTab;
|
|
7
|
+
readonly liveEventsServer: LiveEventsServer;
|
|
4
8
|
readonly request: IncomingMessage;
|
|
5
9
|
readonly response: ServerResponse<IncomingMessage>;
|
|
6
10
|
}) => Promise<void>;
|
|
11
|
+
export {};
|
|
@@ -5,7 +5,6 @@ const studio_protocol_1 = require("@remotion/studio-protocol");
|
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
6
|
const element_install_state_1 = require("../element-install-state");
|
|
7
7
|
const parse_body_1 = require("../parse-body");
|
|
8
|
-
const update_public_license_1 = require("../routes/update-public-license");
|
|
9
8
|
const origin_policy_1 = require("./origin-policy");
|
|
10
9
|
const protocol_response_1 = require("./protocol-response");
|
|
11
10
|
const studioProtocolLicenseKeyRequestSchema = zod_1.z.object({
|
|
@@ -16,9 +15,9 @@ const studioProtocolLicenseKeyRequestSchema = zod_1.z.object({
|
|
|
16
15
|
licenseKey: zod_1.z.string(),
|
|
17
16
|
});
|
|
18
17
|
const MAX_STUDIO_PROTOCOL_LICENSE_KEY_BODY_SIZE = 4096;
|
|
19
|
-
const handleStudioProtocolLicenseKey = async ({ configFile, request, response, }) => {
|
|
20
|
-
(0, origin_policy_1.setStudioProtocolCorsHeaders)({
|
|
21
|
-
const requestOrigin = (0, origin_policy_1.
|
|
18
|
+
const handleStudioProtocolLicenseKey = async ({ configFile, focusStudioTab, liveEventsServer, request, response, }) => {
|
|
19
|
+
(0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
|
|
20
|
+
const requestOrigin = (0, origin_policy_1.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
22
21
|
if (requestOrigin === null) {
|
|
23
22
|
(0, protocol_response_1.writeStudioProtocolError)({
|
|
24
23
|
code: 'unsupported-origin',
|
|
@@ -104,26 +103,25 @@ const handleStudioProtocolLicenseKey = async ({ configFile, request, response, }
|
|
|
104
103
|
});
|
|
105
104
|
return;
|
|
106
105
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
catch (_a) {
|
|
106
|
+
const delivered = liveEventsServer.sendEventToClientId(target.clientId, {
|
|
107
|
+
type: 'license-key-install-request',
|
|
108
|
+
licenseKey: parsedRequest.data.licenseKey,
|
|
109
|
+
});
|
|
110
|
+
if (!delivered) {
|
|
114
111
|
(0, protocol_response_1.writeStudioProtocolError)({
|
|
115
|
-
code: '
|
|
116
|
-
message: '
|
|
112
|
+
code: 'target-expired',
|
|
113
|
+
message: 'The selected Remotion Studio tab is no longer connected.',
|
|
117
114
|
response,
|
|
118
|
-
status:
|
|
115
|
+
status: 409,
|
|
119
116
|
});
|
|
120
117
|
return;
|
|
121
118
|
}
|
|
119
|
+
focusStudioTab(target.studioUrl);
|
|
122
120
|
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
123
121
|
response.end(JSON.stringify({
|
|
124
122
|
protocol: 'remotion-studio-protocol',
|
|
125
123
|
protocolVersion: 1,
|
|
126
|
-
status: '
|
|
124
|
+
status: 'awaiting-confirmation',
|
|
127
125
|
}));
|
|
128
126
|
};
|
|
129
127
|
exports.handleStudioProtocolLicenseKey = handleStudioProtocolLicenseKey;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
export declare const getAllowedStudioProtocolOrigin: (origin: string | undefined) => string | null;
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const setStudioProtocolCorsHeaders: ({ licenseKey, request, response, }: {
|
|
5
|
-
readonly licenseKey: boolean;
|
|
3
|
+
export declare const setStudioProtocolCorsHeaders: ({ request, response, }: {
|
|
6
4
|
readonly request: IncomingMessage;
|
|
7
5
|
readonly response: ServerResponse<IncomingMessage>;
|
|
8
6
|
}) => void;
|
|
9
|
-
export declare const handleStudioProtocolOptions: ({
|
|
10
|
-
readonly licenseKey: boolean;
|
|
7
|
+
export declare const handleStudioProtocolOptions: ({ request, response, }: {
|
|
11
8
|
readonly request: IncomingMessage;
|
|
12
9
|
readonly response: ServerResponse<IncomingMessage>;
|
|
13
10
|
}) => Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleStudioProtocolOptions = exports.setStudioProtocolCorsHeaders = exports.
|
|
3
|
+
exports.handleStudioProtocolOptions = exports.setStudioProtocolCorsHeaders = exports.getAllowedStudioProtocolOrigin = void 0;
|
|
4
4
|
const isLoopbackHttp = (url) => url.protocol === 'http:' &&
|
|
5
5
|
(url.hostname === 'localhost' || url.hostname === '127.0.0.1');
|
|
6
6
|
const getAllowedStudioProtocolOrigin = (origin) => {
|
|
@@ -19,30 +19,8 @@ const getAllowedStudioProtocolOrigin = (origin) => {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
exports.getAllowedStudioProtocolOrigin = getAllowedStudioProtocolOrigin;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
const url = new URL(origin);
|
|
28
|
-
if (isLoopbackHttp(url)) {
|
|
29
|
-
return url.origin;
|
|
30
|
-
}
|
|
31
|
-
if (url.origin === 'https://remotion.pro' ||
|
|
32
|
-
url.origin === 'https://www.remotion.pro') {
|
|
33
|
-
return url.origin;
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
catch (_a) {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
exports.getAllowedLicenseKeyOrigin = getAllowedLicenseKeyOrigin;
|
|
42
|
-
const setStudioProtocolCorsHeaders = ({ licenseKey, request, response, }) => {
|
|
43
|
-
const origin = licenseKey
|
|
44
|
-
? (0, exports.getAllowedLicenseKeyOrigin)(request.headers.origin)
|
|
45
|
-
: (0, exports.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
22
|
+
const setStudioProtocolCorsHeaders = ({ request, response, }) => {
|
|
23
|
+
const origin = (0, exports.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
46
24
|
if (origin === null) {
|
|
47
25
|
return;
|
|
48
26
|
}
|
|
@@ -54,11 +32,9 @@ const setStudioProtocolCorsHeaders = ({ licenseKey, request, response, }) => {
|
|
|
54
32
|
response.setHeader('Access-Control-Allow-Private-Network', 'true');
|
|
55
33
|
};
|
|
56
34
|
exports.setStudioProtocolCorsHeaders = setStudioProtocolCorsHeaders;
|
|
57
|
-
const handleStudioProtocolOptions = ({
|
|
58
|
-
(0, exports.setStudioProtocolCorsHeaders)({
|
|
59
|
-
const origin =
|
|
60
|
-
? (0, exports.getAllowedLicenseKeyOrigin)(request.headers.origin)
|
|
61
|
-
: (0, exports.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
35
|
+
const handleStudioProtocolOptions = ({ request, response, }) => {
|
|
36
|
+
(0, exports.setStudioProtocolCorsHeaders)({ request, response });
|
|
37
|
+
const origin = (0, exports.getAllowedStudioProtocolOrigin)(request.headers.origin);
|
|
62
38
|
response.writeHead(origin === null ? 403 : 204);
|
|
63
39
|
response.end();
|
|
64
40
|
return Promise.resolve();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const remotionSkillNames: readonly ["remotion-best-practices", "remotion-captions", "remotion-create", "remotion-docs", "remotion-interactivity", "remotion-maps", "remotion-markup", "remotion-multimedia", "remotion-render", "remotion-saas", "remotion-upgrade"];
|
|
1
|
+
export declare const remotionSkillNames: readonly ["remotion-best-practices", "remotion-captions", "remotion-create", "remotion-docs", "remotion-interactivity", "remotion-maps", "remotion-markup", "remotion-multimedia", "remotion-render", "remotion-saas", "remotion-studio", "remotion-upgrade"];
|
|
2
2
|
export type RemotionSkillName = (typeof remotionSkillNames)[number];
|