@remotion/studio-server 4.0.502 → 4.0.503

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/detect-outdated-remotion-skills.d.ts +25 -0
  2. package/dist/detect-outdated-remotion-skills.js +73 -0
  3. package/dist/helpers/custom-editor.d.ts +37 -0
  4. package/dist/helpers/custom-editor.js +167 -0
  5. package/dist/helpers/editor-registry.d.ts +18 -0
  6. package/dist/helpers/editor-registry.js +500 -0
  7. package/dist/helpers/open-in-editor.d.ts +3 -4
  8. package/dist/helpers/open-in-editor.js +5 -75
  9. package/dist/helpers/resolve-editor.d.ts +27 -0
  10. package/dist/helpers/resolve-editor.js +90 -0
  11. package/dist/helpers/resolve-file-inside-project.d.ts +2 -0
  12. package/dist/helpers/resolve-file-inside-project.js +5 -2
  13. package/dist/index.d.ts +17 -1
  14. package/dist/index.js +9 -1
  15. package/dist/preview-server/api-routes.js +6 -1
  16. package/dist/preview-server/api-types.d.ts +2 -1
  17. package/dist/preview-server/element-install-state.d.ts +5 -2
  18. package/dist/preview-server/element-install-state.js +6 -3
  19. package/dist/preview-server/handler.d.ts +3 -1
  20. package/dist/preview-server/handler.js +2 -1
  21. package/dist/preview-server/routes/can-update-sequence-props.js +2 -1
  22. package/dist/preview-server/routes/default-editor.d.ts +8 -0
  23. package/dist/preview-server/routes/default-editor.js +131 -0
  24. package/dist/preview-server/routes/delete-effect-keyframe.d.ts +3 -0
  25. package/dist/preview-server/routes/delete-effect-keyframe.js +89 -0
  26. package/dist/preview-server/routes/delete-sequence-keyframe.d.ts +3 -0
  27. package/dist/preview-server/routes/delete-sequence-keyframe.js +82 -0
  28. package/dist/preview-server/routes/element-install-plan.d.ts +32 -0
  29. package/dist/preview-server/routes/element-install-plan.js +122 -0
  30. package/dist/preview-server/routes/insert-element.d.ts +1 -1
  31. package/dist/preview-server/routes/insert-element.js +68 -107
  32. package/dist/preview-server/routes/open-in-editor.d.ts +5 -1
  33. package/dist/preview-server/routes/open-in-editor.js +42 -12
  34. package/dist/preview-server/routes/prepare-element-install.d.ts +3 -0
  35. package/dist/preview-server/routes/prepare-element-install.js +25 -0
  36. package/dist/preview-server/routes/safe-element-install-path.d.ts +9 -0
  37. package/dist/preview-server/routes/safe-element-install-path.js +58 -0
  38. package/dist/preview-server/routes/save-props-mutex.d.ts +1 -0
  39. package/dist/preview-server/routes/save-props-mutex.js +11 -0
  40. package/dist/preview-server/start-server.d.ts +2 -0
  41. package/dist/preview-server/start-server.js +1 -0
  42. package/dist/preview-server/studio-protocol/handle-discovery.js +9 -2
  43. package/dist/preview-server/studio-protocol/handle-install.js +10 -2
  44. package/dist/preview-server/studio-protocol/origin-policy.d.ts +1 -0
  45. package/dist/preview-server/studio-protocol/origin-policy.js +16 -13
  46. package/dist/preview-server/update-available.d.ts +6 -0
  47. package/dist/preview-server/update-available.js +30 -4
  48. package/dist/remotion-skill-names.d.ts +2 -0
  49. package/dist/remotion-skill-names.js +16 -0
  50. package/dist/routes.d.ts +3 -1
  51. package/dist/routes.js +5 -3
  52. package/dist/start-studio.d.ts +3 -1
  53. package/dist/start-studio.js +2 -1
  54. package/package.json +8 -8
@@ -0,0 +1,58 @@
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.getSafeElementInstallPaths = void 0;
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const isInside = ({ child, parent }) => {
10
+ const relative = node_path_1.default.relative(parent, child);
11
+ return (relative === '' ||
12
+ (!relative.startsWith('..') && !node_path_1.default.isAbsolute(relative)));
13
+ };
14
+ const assertInsideProject = ({ fileName, remotionRoot, }) => {
15
+ if (!isInside({ child: fileName, parent: remotionRoot })) {
16
+ throw new Error('Element installation must stay inside the Remotion project');
17
+ }
18
+ };
19
+ const getCanonicalProjectRoot = async (remotionRoot) => {
20
+ return (0, promises_1.realpath)(remotionRoot);
21
+ };
22
+ const getSafeElementInstallPaths = async ({ compositionFileName, elementFileName, remotionRoot, }) => {
23
+ const canonicalRoot = await getCanonicalProjectRoot(remotionRoot);
24
+ const canonicalCompositionFile = await (0, promises_1.realpath)(compositionFileName);
25
+ assertInsideProject({
26
+ fileName: canonicalCompositionFile,
27
+ remotionRoot: canonicalRoot,
28
+ });
29
+ // The Element directory already exists because it is the composition file's
30
+ // directory. Resolving it before appending the file name prevents writes
31
+ // through a directory symlink that leaves the project.
32
+ const canonicalElementDirectory = await (0, promises_1.realpath)(node_path_1.default.dirname(elementFileName));
33
+ assertInsideProject({
34
+ fileName: canonicalElementDirectory,
35
+ remotionRoot: canonicalRoot,
36
+ });
37
+ const canonicalElementFile = node_path_1.default.join(canonicalElementDirectory, node_path_1.default.basename(elementFileName));
38
+ try {
39
+ const elementStats = await (0, promises_1.lstat)(canonicalElementFile);
40
+ if (elementStats.isSymbolicLink()) {
41
+ throw new Error('Element source file must not be a symbolic link');
42
+ }
43
+ if (!elementStats.isFile()) {
44
+ throw new Error('Element source path must be a file');
45
+ }
46
+ }
47
+ catch (error) {
48
+ if (error.code !== 'ENOENT') {
49
+ throw error;
50
+ }
51
+ }
52
+ return {
53
+ compositionFileName: canonicalCompositionFile,
54
+ elementFileName: canonicalElementFile,
55
+ remotionRoot: canonicalRoot,
56
+ };
57
+ };
58
+ exports.getSafeElementInstallPaths = getSafeElementInstallPaths;
@@ -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;
@@ -1,4 +1,5 @@
1
1
  import type { BundlerOverrideFn, RspackOverrideFn, WebpackOverrideFn } from '@remotion/bundler';
2
+ import type { DefaultEditor } from '@remotion/renderer';
2
3
  import type { GitSource, RenderDefaults, RenderJob, StudioRuntimeConfig } from '@remotion/studio-shared';
3
4
  import type { QueueMethods } from './api-types';
4
5
  import type { LiveEventsServer } from './live-events';
@@ -41,5 +42,6 @@ export declare const startServer: (options: {
41
42
  forceNew: boolean;
42
43
  rspack: boolean;
43
44
  getStudioRuntimeConfig: () => StudioRuntimeConfig;
45
+ getDefaultEditor: () => DefaultEditor | null;
44
46
  configFile: string | null;
45
47
  }) => 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
+ getDefaultEditor: options.getDefaultEditor,
105
106
  configFile: options.configFile,
106
107
  });
107
108
  })
@@ -42,7 +42,8 @@ const getProject = ({ gitSource, remotionRoot, }) => (0, studio_shared_1.getProj
42
42
  });
43
43
  const handleStudioProtocolDiscovery = ({ gitSource, liveEventsServer, remotionRoot, request, response, }) => {
44
44
  (0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
45
- if (!(0, origin_policy_1.isAllowedStudioProtocolOrigin)(request.headers.origin)) {
45
+ const requestOrigin = (0, origin_policy_1.getAllowedStudioProtocolOrigin)(request.headers.origin);
46
+ if (requestOrigin === null) {
46
47
  (0, protocol_response_1.writeStudioProtocolError)({
47
48
  code: 'unsupported-origin',
48
49
  message: 'Origin not allowed',
@@ -65,7 +66,13 @@ const handleStudioProtocolDiscovery = ({ gitSource, liveEventsServer, remotionRo
65
66
  setTimeout(() => {
66
67
  const now = Date.now();
67
68
  const target = getLiveInstallableTarget(requestId);
68
- const issued = target === null ? null : (0, element_install_state_1.issueStudioProtocolTarget)({ now, target });
69
+ const issued = target === null
70
+ ? null
71
+ : (0, element_install_state_1.issueStudioProtocolTarget)({
72
+ now,
73
+ origin: requestOrigin,
74
+ target,
75
+ });
69
76
  response.writeHead(200, {
70
77
  'Cache-Control': 'no-store',
71
78
  'Content-Type': 'application/json',
@@ -16,7 +16,7 @@ const studioProtocolInstallRequestSchema = zod_1.z.object({
16
16
  // A valid payload may contain 250,000 JSON characters. Allow room for its
17
17
  // UTF-8 representation and the protocol envelope while keeping memory bounded.
18
18
  const MAX_STUDIO_PROTOCOL_INSTALL_BODY_SIZE = 1000000;
19
- const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, target, }) => {
19
+ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, origin, target, }) => {
20
20
  if (target.compositionFile === null || target.compositionId === null) {
21
21
  return false;
22
22
  }
@@ -27,7 +27,12 @@ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, targ
27
27
  compositionFile: target.compositionFile,
28
28
  compositionId: target.compositionId,
29
29
  element,
30
+ from: null,
30
31
  position: null,
32
+ source: {
33
+ type: 'studio-protocol',
34
+ origin,
35
+ },
31
36
  };
32
37
  const delivered = liveEventsServer.sendEventToClientId(target.clientId, {
33
38
  type: 'element-install-request',
@@ -40,7 +45,8 @@ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, targ
40
45
  };
41
46
  const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, request, response, }) => {
42
47
  (0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
43
- if (!(0, origin_policy_1.isAllowedStudioProtocolOrigin)(request.headers.origin)) {
48
+ const requestOrigin = (0, origin_policy_1.getAllowedStudioProtocolOrigin)(request.headers.origin);
49
+ if (requestOrigin === null) {
44
50
  (0, protocol_response_1.writeStudioProtocolError)({
45
51
  code: 'unsupported-origin',
46
52
  message: 'Origin not allowed',
@@ -104,6 +110,7 @@ const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, r
104
110
  }
105
111
  const target = (0, element_install_state_1.consumeStudioProtocolTarget)({
106
112
  now: Date.now(),
113
+ origin: requestOrigin,
107
114
  targetId: parsedRequest.data.targetId,
108
115
  });
109
116
  if (target === null) {
@@ -119,6 +126,7 @@ const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, r
119
126
  element: payload.element,
120
127
  focusStudioTab,
121
128
  liveEventsServer,
129
+ origin: requestOrigin,
122
130
  target,
123
131
  })) {
124
132
  (0, protocol_response_1.writeStudioProtocolError)({
@@ -1,4 +1,5 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ export declare const getAllowedStudioProtocolOrigin: (origin: string | undefined) => string | null;
2
3
  export declare const isAllowedStudioProtocolOrigin: (origin: string | undefined) => boolean;
3
4
  export declare const setStudioProtocolCorsHeaders: ({ request, response, }: {
4
5
  readonly request: IncomingMessage;
@@ -1,30 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleStudioProtocolOptions = exports.setStudioProtocolCorsHeaders = exports.isAllowedStudioProtocolOrigin = void 0;
4
- const isAllowedStudioProtocolOrigin = (origin) => {
3
+ exports.handleStudioProtocolOptions = exports.setStudioProtocolCorsHeaders = exports.isAllowedStudioProtocolOrigin = exports.getAllowedStudioProtocolOrigin = void 0;
4
+ const getAllowedStudioProtocolOrigin = (origin) => {
5
5
  if (!origin) {
6
- return false;
6
+ return null;
7
7
  }
8
8
  try {
9
9
  const url = new URL(origin);
10
- return ((url.protocol === 'https:' &&
11
- (url.hostname === 'remotion.dev' ||
12
- url.hostname === 'www.remotion.dev')) ||
13
- (url.protocol === 'http:' &&
14
- (url.hostname === 'localhost' || url.hostname === '127.0.0.1')));
10
+ const isLoopbackHttp = url.protocol === 'http:' &&
11
+ (url.hostname === 'localhost' || url.hostname === '127.0.0.1');
12
+ if (url.protocol !== 'https:' && !isLoopbackHttp) {
13
+ return null;
14
+ }
15
+ return url.origin;
15
16
  }
16
17
  catch (_a) {
17
- return false;
18
+ return null;
18
19
  }
19
20
  };
21
+ exports.getAllowedStudioProtocolOrigin = getAllowedStudioProtocolOrigin;
22
+ const isAllowedStudioProtocolOrigin = (origin) => (0, exports.getAllowedStudioProtocolOrigin)(origin) !== null;
20
23
  exports.isAllowedStudioProtocolOrigin = isAllowedStudioProtocolOrigin;
21
24
  const setStudioProtocolCorsHeaders = ({ request, response, }) => {
22
- const { origin } = request.headers;
23
- if (typeof origin !== 'string' || !(0, exports.isAllowedStudioProtocolOrigin)(origin)) {
25
+ const origin = (0, exports.getAllowedStudioProtocolOrigin)(request.headers.origin);
26
+ if (origin === null) {
24
27
  return;
25
28
  }
26
29
  response.setHeader('Access-Control-Allow-Origin', origin);
27
- response.setHeader('Vary', 'Origin');
30
+ response.setHeader('Vary', 'Origin, Access-Control-Request-Headers, Access-Control-Request-Private-Network');
28
31
  response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
29
32
  response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
30
33
  response.setHeader('Access-Control-Max-Age', '600');
@@ -33,7 +36,7 @@ const setStudioProtocolCorsHeaders = ({ request, response, }) => {
33
36
  exports.setStudioProtocolCorsHeaders = setStudioProtocolCorsHeaders;
34
37
  const handleStudioProtocolOptions = ({ request, response, }) => {
35
38
  (0, exports.setStudioProtocolCorsHeaders)({ request, response });
36
- response.writeHead((0, exports.isAllowedStudioProtocolOrigin)(request.headers.origin) ? 204 : 403);
39
+ response.writeHead((0, exports.getAllowedStudioProtocolOrigin)(request.headers.origin) === null ? 403 : 204);
37
40
  response.end();
38
41
  return Promise.resolve();
39
42
  };
@@ -1,3 +1,9 @@
1
1
  import type { UpdateAvailableResponse } from '@remotion/studio-shared';
2
+ export declare const isUpdateAvailable: ({ remotionRoot, currentVersion, logLevel, getLatestVersion, }: {
3
+ remotionRoot: string;
4
+ currentVersion: string;
5
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
6
+ getLatestVersion: (() => Promise<string>) | null;
7
+ }) => Promise<UpdateAvailableResponse>;
2
8
  export declare const getRemotionVersion: () => any;
3
9
  export declare const isUpdateAvailableWithTimeout: (remotionRoot: string, logLevel: "error" | "info" | "trace" | "verbose" | "warn") => Promise<UpdateAvailableResponse>;
@@ -3,12 +3,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isUpdateAvailableWithTimeout = exports.getRemotionVersion = void 0;
6
+ exports.isUpdateAvailableWithTimeout = exports.getRemotionVersion = exports.isUpdateAvailable = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
7
9
  const semver_1 = __importDefault(require("semver"));
10
+ const detect_outdated_remotion_skills_1 = require("../detect-outdated-remotion-skills");
8
11
  const get_latest_remotion_version_1 = require("../get-latest-remotion-version");
9
12
  const get_package_manager_1 = require("./get-package-manager");
10
- const isUpdateAvailable = async ({ remotionRoot, currentVersion, logLevel, }) => {
11
- const latest = await (0, get_latest_remotion_version_1.getLatestRemotionVersion)();
13
+ const getSkillsUpdateInfo = ({ remotionRoot, currentVersion, }) => {
14
+ const projectSkills = (0, detect_outdated_remotion_skills_1.detectOutdatedRemotionSkills)({
15
+ cwd: remotionRoot,
16
+ currentVersion,
17
+ }).project;
18
+ return {
19
+ skillsUpdateAvailable: projectSkills.type === 'outdated',
20
+ remotionUpgradeSkillAvailable: (0, node_fs_1.existsSync)(node_path_1.default.join(remotionRoot, '.agents', 'skills', 'remotion-upgrade', 'SKILL.md')),
21
+ };
22
+ };
23
+ const isUpdateAvailable = async ({ remotionRoot, currentVersion, logLevel, getLatestVersion, }) => {
24
+ const latest = await (getLatestVersion !== null && getLatestVersion !== void 0 ? getLatestVersion : get_latest_remotion_version_1.getLatestRemotionVersion)();
25
+ const skillsUpdateInfo = getSkillsUpdateInfo({ remotionRoot, currentVersion });
12
26
  const pkgManager = (0, get_package_manager_1.getPackageManager)({
13
27
  remotionRoot,
14
28
  packageManager: undefined,
@@ -17,12 +31,14 @@ const isUpdateAvailable = async ({ remotionRoot, currentVersion, logLevel, }) =>
17
31
  });
18
32
  return {
19
33
  updateAvailable: semver_1.default.lt(currentVersion, latest),
34
+ ...skillsUpdateInfo,
20
35
  currentVersion,
21
36
  latestVersion: latest,
22
37
  timedOut: false,
23
38
  packageManager: pkgManager === 'unknown' ? 'unknown' : pkgManager.manager,
24
39
  };
25
40
  };
41
+ exports.isUpdateAvailable = isUpdateAvailable;
26
42
  const getRemotionVersion = () => {
27
43
  // careful when refactoring this file, path must be adjusted
28
44
  const packageJson = require('../../package.json');
@@ -32,6 +48,10 @@ const getRemotionVersion = () => {
32
48
  exports.getRemotionVersion = getRemotionVersion;
33
49
  const isUpdateAvailableWithTimeout = (remotionRoot, logLevel) => {
34
50
  const version = (0, exports.getRemotionVersion)();
51
+ const skillsUpdateInfo = getSkillsUpdateInfo({
52
+ remotionRoot,
53
+ currentVersion: version,
54
+ });
35
55
  const threeSecTimeout = new Promise((resolve) => {
36
56
  const pkgManager = (0, get_package_manager_1.getPackageManager)({
37
57
  remotionRoot,
@@ -44,6 +64,7 @@ const isUpdateAvailableWithTimeout = (remotionRoot, logLevel) => {
44
64
  currentVersion: version,
45
65
  latestVersion: version,
46
66
  updateAvailable: false,
67
+ ...skillsUpdateInfo,
47
68
  timedOut: true,
48
69
  packageManager: pkgManager === 'unknown' ? 'unknown' : pkgManager.manager,
49
70
  });
@@ -51,7 +72,12 @@ const isUpdateAvailableWithTimeout = (remotionRoot, logLevel) => {
51
72
  });
52
73
  return Promise.race([
53
74
  threeSecTimeout,
54
- isUpdateAvailable({ remotionRoot, currentVersion: version, logLevel }),
75
+ (0, exports.isUpdateAvailable)({
76
+ remotionRoot,
77
+ currentVersion: version,
78
+ logLevel,
79
+ getLatestVersion: null,
80
+ }),
55
81
  ]);
56
82
  };
57
83
  exports.isUpdateAvailableWithTimeout = isUpdateAvailableWithTimeout;
@@ -0,0 +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"];
2
+ export type RemotionSkillName = (typeof remotionSkillNames)[number];
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.remotionSkillNames = void 0;
4
+ exports.remotionSkillNames = [
5
+ 'remotion-best-practices',
6
+ 'remotion-captions',
7
+ 'remotion-create',
8
+ 'remotion-docs',
9
+ 'remotion-interactivity',
10
+ 'remotion-maps',
11
+ 'remotion-markup',
12
+ 'remotion-multimedia',
13
+ 'remotion-render',
14
+ 'remotion-saas',
15
+ 'remotion-upgrade',
16
+ ];
package/dist/routes.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { DefaultEditor } from '@remotion/renderer';
2
3
  import type { GitSource, RenderDefaults, RenderJob, StudioRuntimeConfig } from '@remotion/studio-shared';
3
4
  import type { QueueMethods } from './preview-server/api-types';
4
5
  import type { LiveEventsServer } from './preview-server/live-events';
5
- export declare const handleRoutes: ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, configFile, }: {
6
+ export declare const handleRoutes: ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultEditor, configFile, }: {
6
7
  staticHash: string;
7
8
  staticHashPrefix: string;
8
9
  outputHash: string;
@@ -26,5 +27,6 @@ export declare const handleRoutes: ({ staticHash, staticHashPrefix, outputHash,
26
27
  getPreviewSampleRate: () => number | null;
27
28
  enableCrossSiteIsolation: boolean;
28
29
  getStudioRuntimeConfig: () => StudioRuntimeConfig;
30
+ getDefaultEditor: () => DefaultEditor | null;
29
31
  configFile: string | null;
30
32
  }) => Promise<void>;
package/dist/routes.js CHANGED
@@ -82,7 +82,7 @@ const handleRemotionConfig = (response, remotionRoot) => {
82
82
  response.end(JSON.stringify(body));
83
83
  return Promise.resolve();
84
84
  };
85
- const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, getAudioLatencyHint, getPreviewSampleRate, gitSource, logLevel, enableCrossSiteIsolation, getStudioRuntimeConfig, }) => {
85
+ const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, getAudioLatencyHint, getPreviewSampleRate, gitSource, logLevel, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultEditor, }) => {
86
86
  var _a, _b;
87
87
  const acceptsHtml = ((_a = request.headers.accept) !== null && _a !== void 0 ? _a : '').includes('text/html');
88
88
  if (request.method === 'GET' && acceptsHtml) {
@@ -105,7 +105,7 @@ const handleFallback = async ({ remotionRoot, hash, response, request, getCurren
105
105
  `Change \`"${pathname}"\` to \`staticFile("${pathname}")\` to fix the error.`,
106
106
  ].join('\n'));
107
107
  }
108
- const displayName = await (0, open_in_editor_1.getEditorName)();
108
+ const displayName = await (0, open_in_editor_1.getEditorName)({ getDefaultEditor, logLevel });
109
109
  response.setHeader('content-type', 'text/html');
110
110
  if (enableCrossSiteIsolation) {
111
111
  response.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
@@ -251,7 +251,7 @@ const handleBeep = (_, response) => {
251
251
  readStream.pipe(response);
252
252
  return Promise.resolve();
253
253
  };
254
- const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, configFile, }) => {
254
+ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultEditor, configFile, }) => {
255
255
  const url = new URL(request.url, 'http://localhost');
256
256
  if (url.pathname === '/api/file-source') {
257
257
  return handleFileSource({
@@ -314,6 +314,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
314
314
  binariesDirectory,
315
315
  publicDir,
316
316
  configFile,
317
+ getDefaultEditor,
317
318
  });
318
319
  }
319
320
  }
@@ -374,6 +375,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
374
375
  getPreviewSampleRate,
375
376
  enableCrossSiteIsolation,
376
377
  getStudioRuntimeConfig,
378
+ getDefaultEditor,
377
379
  });
378
380
  };
379
381
  exports.handleRoutes = handleRoutes;
@@ -1,4 +1,5 @@
1
1
  import type { BundlerOverrideFn, RspackOverrideFn, WebpackOverrideFn } from '@remotion/bundler';
2
+ import type { DefaultEditor } from '@remotion/renderer';
2
3
  import type { GitSource, RenderDefaults, RenderJob, StudioRuntimeConfig } from '@remotion/studio-shared';
3
4
  import type { QueueMethods } from './preview-server/api-types';
4
5
  export type StartStudioResult = {
@@ -6,7 +7,7 @@ export type StartStudioResult = {
6
7
  } | {
7
8
  type: 'already-running';
8
9
  };
9
- export declare const startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, remotionRoot, relativePublicDir, bundlerOverride, rspackOverride, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, binariesDirectory, forceIPv4, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, forceNew, rspack, getStudioRuntimeConfig, configFile, }: {
10
+ export declare const startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, remotionRoot, relativePublicDir, bundlerOverride, rspackOverride, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, binariesDirectory, forceIPv4, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, forceNew, rspack, getStudioRuntimeConfig, getDefaultEditor, configFile, }: {
10
11
  browserArgs: string;
11
12
  browserFlag: string;
12
13
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
@@ -35,5 +36,6 @@ export declare const startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser
35
36
  forceNew: boolean;
36
37
  rspack: boolean;
37
38
  getStudioRuntimeConfig: () => StudioRuntimeConfig;
39
+ getDefaultEditor: () => DefaultEditor | null;
38
40
  configFile: string | null;
39
41
  }) => Promise<StartStudioResult>;
@@ -19,7 +19,7 @@ const public_folder_1 = require("./preview-server/public-folder");
19
19
  const start_server_1 = require("./preview-server/start-server");
20
20
  const server_ready_1 = require("./server-ready");
21
21
  const watch_root_file_1 = require("./watch-root-file");
22
- const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, remotionRoot, relativePublicDir, bundlerOverride, rspackOverride, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, binariesDirectory, forceIPv4, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, forceNew, rspack, getStudioRuntimeConfig, configFile, }) => {
22
+ const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, remotionRoot, relativePublicDir, bundlerOverride, rspackOverride, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, binariesDirectory, forceIPv4, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, forceNew, rspack, getStudioRuntimeConfig, getDefaultEditor, configFile, }) => {
23
23
  try {
24
24
  if (typeof Bun === 'undefined') {
25
25
  process.title = 'node (npx remotion studio)';
@@ -93,6 +93,7 @@ const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEn
93
93
  forceNew,
94
94
  rspack,
95
95
  getStudioRuntimeConfig,
96
+ getDefaultEditor,
96
97
  configFile,
97
98
  });
98
99
  if (result.type === 'already-running') {
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.502",
6
+ "version": "4.0.503",
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.502",
26
+ "@remotion/studio-protocol": "4.0.503",
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.502",
35
+ "remotion": "4.0.503",
36
36
  "recast": "0.23.11",
37
- "@remotion/bundler": "4.0.502",
38
- "@remotion/renderer": "4.0.502",
39
- "@remotion/studio-codemods": "4.0.502",
40
- "@remotion/studio-shared": "4.0.502",
37
+ "@remotion/bundler": "4.0.503",
38
+ "@remotion/renderer": "4.0.503",
39
+ "@remotion/studio-codemods": "4.0.503",
40
+ "@remotion/studio-shared": "4.0.503",
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.502",
48
+ "@remotion/eslint-config-internal": "4.0.503",
49
49
  "eslint": "9.19.0",
50
50
  "@types/node": "20.12.14",
51
51
  "@typescript/native-preview": "7.0.0-dev.20260217.1"