@remotion/studio-server 4.0.513 → 4.0.515

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 (67) hide show
  1. package/dist/codemods/delete-jsx-node.d.ts +2 -5
  2. package/dist/codemods/delete-jsx-node.js +23 -341
  3. package/dist/codemods/duplicate-composition.d.ts +1 -9
  4. package/dist/codemods/duplicate-composition.js +3 -49
  5. package/dist/codemods/format-inline-content.d.ts +0 -4
  6. package/dist/codemods/format-inline-content.js +7 -46
  7. package/dist/codemods/recast-mods.js +0 -18
  8. package/dist/codemods/reorder-sequence.d.ts +2 -2
  9. package/dist/codemods/reorder-sequence.js +12 -112
  10. package/dist/codemods/split-jsx-sequence.d.ts +1 -2
  11. package/dist/codemods/split-jsx-sequence.js +11 -298
  12. package/dist/codemods/split-video-from-audio.d.ts +15 -0
  13. package/dist/codemods/split-video-from-audio.js +15 -0
  14. package/dist/codemods/update-default-props.d.ts +2 -6
  15. package/dist/codemods/update-default-props.js +12 -220
  16. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.d.ts +1 -4
  17. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.js +5 -102
  18. package/dist/codemods/update-keyframes/update-keyframes.d.ts +8 -93
  19. package/dist/codemods/update-keyframes/update-keyframes.js +11 -1302
  20. package/dist/detect-outdated-remotion-skills.d.ts +7 -0
  21. package/dist/detect-outdated-remotion-skills.js +11 -5
  22. package/dist/helpers/open-file-for-writing-without-symlinks.d.ts +4 -0
  23. package/dist/helpers/open-file-for-writing-without-symlinks.js +52 -0
  24. package/dist/helpers/resolve-composition-component.d.ts +3 -11
  25. package/dist/helpers/resolve-composition-component.js +38 -1495
  26. package/dist/helpers/video-config-values.js +25 -6
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.js +1 -0
  29. package/dist/max-timeline-tracks.d.ts +2 -1
  30. package/dist/max-timeline-tracks.js +10 -4
  31. package/dist/preview-server/api-routes.js +4 -0
  32. package/dist/preview-server/routes/add-effect.js +1 -1
  33. package/dist/preview-server/routes/apply-codemod.js +3 -3
  34. package/dist/preview-server/routes/apply-visual-control-change.js +3 -3
  35. package/dist/preview-server/routes/can-update-sequence-props.js +107 -24
  36. package/dist/preview-server/routes/delete-effect-keyframe.d.ts +3 -0
  37. package/dist/preview-server/routes/delete-effect-keyframe.js +89 -0
  38. package/dist/preview-server/routes/delete-effect.js +1 -1
  39. package/dist/preview-server/routes/delete-jsx-node.js +1 -1
  40. package/dist/preview-server/routes/delete-sequence-keyframe.d.ts +3 -0
  41. package/dist/preview-server/routes/delete-sequence-keyframe.js +82 -0
  42. package/dist/preview-server/routes/duplicate-effect.js +1 -1
  43. package/dist/preview-server/routes/duplicate-jsx-node.js +1 -1
  44. package/dist/preview-server/routes/element-install-plan.d.ts +1 -1
  45. package/dist/preview-server/routes/insert-element.js +2 -2
  46. package/dist/preview-server/routes/insert-jsx-element.js +1 -1
  47. package/dist/preview-server/routes/install-dependency.js +8 -2
  48. package/dist/preview-server/routes/log-updates/log-effect-update.js +2 -1
  49. package/dist/preview-server/routes/log-updates/log-update.js +2 -1
  50. package/dist/preview-server/routes/paste-effects.js +1 -1
  51. package/dist/preview-server/routes/remotion-skills-info.d.ts +7 -0
  52. package/dist/preview-server/routes/remotion-skills-info.js +24 -0
  53. package/dist/preview-server/routes/reorder-effect.js +1 -1
  54. package/dist/preview-server/routes/reorder-sequence.js +1 -1
  55. package/dist/preview-server/routes/save-props-mutex.d.ts +1 -0
  56. package/dist/preview-server/routes/save-props-mutex.js +11 -0
  57. package/dist/preview-server/routes/source-file-write-queue.d.ts +1 -0
  58. package/dist/preview-server/routes/source-file-write-queue.js +11 -2
  59. package/dist/preview-server/routes/split-jsx-sequence.js +1 -1
  60. package/dist/preview-server/routes/split-video-from-audio.d.ts +3 -0
  61. package/dist/preview-server/routes/split-video-from-audio.js +80 -0
  62. package/dist/preview-server/routes/update-default-props.js +1 -1
  63. package/dist/preview-server/start-server.js +188 -140
  64. package/dist/preview-server/undo-stack.d.ts +3 -52
  65. package/dist/preview-server/update-available.js +4 -4
  66. package/dist/routes.js +36 -5
  67. package/package.json +8 -8
@@ -197,8 +197,8 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
197
197
  : plan.elementFileExists
198
198
  ? 'Reused existing Element source'
199
199
  : 'Created Element source';
200
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(elementLocationLabel)} ${elementFileAction}`);
201
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(compositionLocationLabel)} Added <${plan.componentName}>`);
200
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(elementLocationLabel)} ${elementFileAction}`);
201
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(compositionLocationLabel)} Added <${plan.componentName}>`);
202
202
  if (!inserted.formatted) {
203
203
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
204
204
  }
@@ -204,7 +204,7 @@ const insertJsxElementHandler = ({ input: { compositionFile, compositionId, elem
204
204
  absolutePath: fileName,
205
205
  line: logLine,
206
206
  });
207
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Added ${elementLabel}`);
207
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Added ${elementLabel}`);
208
208
  if (!formatted) {
209
209
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
210
210
  }
@@ -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, (0, package_manager_spawn_options_1.getPackageManagerSpawnOptions)());
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()
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logEffectUpdate = void 0;
4
4
  const renderer_1 = require("@remotion/renderer");
5
+ const source_file_write_queue_1 = require("../source-file-write-queue");
5
6
  const format_effect_prop_change_1 = require("./format-effect-prop-change");
6
7
  const log_update_1 = require("./log-update");
7
8
  const logEffectUpdate = ({ fileRelativeToRoot, line, effectName, propKey, oldValueString, newValueString, defaultValueString, formatted, logLevel, removedProps, addedProps, }) => {
@@ -15,7 +16,7 @@ const logEffectUpdate = ({ fileRelativeToRoot, line, effectName, propKey, oldVal
15
16
  removedProps,
16
17
  addedProps,
17
18
  });
18
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${propChange}`);
19
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${propChange}`);
19
20
  if (!formatted) {
20
21
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
21
22
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logUpdate = exports.normalizeQuotes = exports.warnAboutPrettierOnce = void 0;
4
4
  const renderer_1 = require("@remotion/renderer");
5
+ const source_file_write_queue_1 = require("../source-file-write-queue");
5
6
  const format_prop_change_1 = require("./format-prop-change");
6
7
  let warnedAboutPrettier = false;
7
8
  const warnAboutPrettierOnce = (logLevel) => {
@@ -31,7 +32,7 @@ const logUpdate = ({ fileRelativeToRoot, line, key, oldValueString, newValueStri
31
32
  removedProps,
32
33
  addedProps,
33
34
  });
34
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${propChange}`);
35
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} ${propChange}`);
35
36
  if (!formatted) {
36
37
  (0, exports.warnAboutPrettierOnce)(logLevel);
37
38
  }
@@ -66,7 +66,7 @@ const pasteEffectsHandler = ({ input: { targetFileName, targetSequenceNodePath,
66
66
  absolutePath,
67
67
  line: logLine,
68
68
  });
69
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Pasted ${(0, formatting_1.attrName)(effectDescription)}`);
69
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Pasted ${(0, formatting_1.attrName)(effectDescription)}`);
70
70
  if (!formatted) {
71
71
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
72
72
  }
@@ -0,0 +1,7 @@
1
+ import type { GetRemotionSkillsInfoRequest, GetRemotionSkillsInfoResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const getRemotionSkillsInfo: ({ remotionRoot, homeDirectory, }: {
4
+ remotionRoot: string;
5
+ homeDirectory?: string | undefined;
6
+ }) => GetRemotionSkillsInfoResponse;
7
+ export declare const remotionSkillsInfoHandler: ApiHandler<GetRemotionSkillsInfoRequest, GetRemotionSkillsInfoResponse>;
@@ -0,0 +1,24 @@
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.remotionSkillsInfoHandler = exports.getRemotionSkillsInfo = void 0;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_os_1 = require("node:os");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const detect_outdated_remotion_skills_1 = require("../../detect-outdated-remotion-skills");
11
+ const getRemotionSkillsInfo = ({ remotionRoot, homeDirectory = (0, node_os_1.homedir)(), }) => {
12
+ const skillsDirectories = (0, detect_outdated_remotion_skills_1.getRemotionSkillsDirectories)({
13
+ cwd: remotionRoot,
14
+ homeDirectory,
15
+ });
16
+ const isSkillAvailable = (skillName) => Object.values(skillsDirectories).some((skillsDirectory) => (0, node_fs_1.existsSync)(node_path_1.default.join(skillsDirectory, skillName, 'SKILL.md')));
17
+ return {
18
+ remotionUpgradeSkillAvailable: isSkillAvailable('remotion-upgrade'),
19
+ remotionInteractivitySkillAvailable: isSkillAvailable('remotion-interactivity'),
20
+ };
21
+ };
22
+ exports.getRemotionSkillsInfo = getRemotionSkillsInfo;
23
+ const remotionSkillsInfoHandler = ({ remotionRoot }) => Promise.resolve((0, exports.getRemotionSkillsInfo)({ remotionRoot }));
24
+ exports.remotionSkillsInfoHandler = remotionSkillsInfoHandler;
@@ -54,7 +54,7 @@ const reorderEffectHandler = ({ input: { fileName, sequenceNodePath, fromIndex,
54
54
  absolutePath,
55
55
  line: logLine,
56
56
  });
57
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Reordered ${(0, formatting_1.attrName)(effectLabel)}`);
57
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Reordered ${(0, formatting_1.attrName)(effectLabel)}`);
58
58
  if (!formatted) {
59
59
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
60
60
  }
@@ -62,7 +62,7 @@ const reorderSequenceHandler = ({ input: { fileName, sourceNodePath, targetNodeP
62
62
  absolutePath,
63
63
  line: logLine,
64
64
  });
65
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Reordered ${(0, formatting_1.attrName)(sequenceLabel)}`);
65
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Reordered ${(0, formatting_1.attrName)(sequenceLabel)}`);
66
66
  if (!formatted) {
67
67
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
68
68
  }
@@ -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 +1,2 @@
1
+ export declare const getCodemodTimingPrefix: (logLevel: "error" | "info" | "trace" | "verbose" | "warn") => string;
1
2
  export declare const withSourceFileWriteQueue: <T>(fn: () => Promise<T>) => Promise<T>;
@@ -1,9 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withSourceFileWriteQueue = void 0;
3
+ exports.withSourceFileWriteQueue = exports.getCodemodTimingPrefix = void 0;
4
+ const node_async_hooks_1 = require("node:async_hooks");
4
5
  let chain = Promise.resolve();
6
+ const codemodStartTime = new node_async_hooks_1.AsyncLocalStorage();
7
+ const getCodemodTimingPrefix = (logLevel) => {
8
+ const startTime = codemodStartTime.getStore();
9
+ return logLevel === 'trace' && startTime !== undefined
10
+ ? `[${Date.now() - startTime}ms] `
11
+ : '';
12
+ };
13
+ exports.getCodemodTimingPrefix = getCodemodTimingPrefix;
5
14
  const withSourceFileWriteQueue = (fn) => {
6
- const run = () => fn();
15
+ const run = () => codemodStartTime.run(Date.now(), fn);
7
16
  const next = chain.then(run, run);
8
17
  chain = next.then(() => undefined, () => undefined);
9
18
  return next;
@@ -60,7 +60,7 @@ const splitJsxSequenceHandler = ({ input: { fileName, nodePath, sequenceKeys, sp
60
60
  absolutePath,
61
61
  line: logLine,
62
62
  });
63
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Split ${nodeLabel}`);
63
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Split ${nodeLabel}`);
64
64
  if (!formatted) {
65
65
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
66
66
  }
@@ -0,0 +1,3 @@
1
+ import type { SplitVideoFromAudioRequest, SplitVideoFromAudioResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const splitVideoFromAudioHandler: ApiHandler<SplitVideoFromAudioRequest, SplitVideoFromAudioResponse>;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.splitVideoFromAudioHandler = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const renderer_1 = require("@remotion/renderer");
6
+ const split_video_from_audio_1 = require("../../codemods/split-video-from-audio");
7
+ const file_watcher_1 = require("../../file-watcher");
8
+ const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
9
+ const format_log_file_location_1 = require("../format-log-file-location");
10
+ const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
11
+ const undo_stack_1 = require("../undo-stack");
12
+ const log_update_1 = require("./log-updates/log-update");
13
+ const source_file_write_queue_1 = require("./source-file-write-queue");
14
+ const splitVideoFromAudioHandler = ({ input: { fileName, nodePath }, remotionRoot, logLevel }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
15
+ try {
16
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[split-video-from-audio] Received request for fileName="${fileName}"`);
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, formatted, nodeLabel, logLine, nodePathRemappings } = await (0, split_video_from_audio_1.splitVideoFromAudio)({
24
+ input: fileContents,
25
+ nodePath,
26
+ });
27
+ const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)([
28
+ {
29
+ absolutePath,
30
+ remappings: nodePathRemappings,
31
+ restoredNodePaths: [],
32
+ },
33
+ ]);
34
+ (0, undo_stack_1.pushToUndoStack)({
35
+ filePath: absolutePath,
36
+ oldContents: fileContents,
37
+ newContents: null,
38
+ logLevel,
39
+ remotionRoot,
40
+ logLine,
41
+ description: {
42
+ undoMessage: `↩️ Split of audio from ${nodeLabel}`,
43
+ redoMessage: `↪️ Split of audio from ${nodeLabel}`,
44
+ },
45
+ entryType: 'split-video-from-audio',
46
+ suppressHmrOnFileRestore: false,
47
+ nodePathRemappings,
48
+ });
49
+ (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
50
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
51
+ file: absolutePath,
52
+ content: output,
53
+ originatorClientId: undefined,
54
+ metadata: { skipSequencePropsUpdate: true },
55
+ });
56
+ const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
57
+ remotionRoot,
58
+ absolutePath,
59
+ line: logLine,
60
+ });
61
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Split audio from ${nodeLabel}`);
62
+ if (!formatted) {
63
+ (0, log_update_1.warnAboutPrettierOnce)(logLevel);
64
+ }
65
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `[split-video-from-audio] Wrote ${fileRelativeToRoot}${formatted ? ' (formatted)' : ''}`);
66
+ (0, undo_stack_1.printUndoHint)(logLevel);
67
+ return {
68
+ success: true,
69
+ nodePathMutation,
70
+ };
71
+ }
72
+ catch (err) {
73
+ return {
74
+ success: false,
75
+ reason: err.message,
76
+ stack: err.stack,
77
+ };
78
+ }
79
+ });
80
+ exports.splitVideoFromAudioHandler = splitVideoFromAudioHandler;
@@ -60,7 +60,7 @@ const updateDefaultPropsHandler = ({ input: { compositionId, defaultProps, enumP
60
60
  absolutePath: projectInfo.rootFile,
61
61
  line: logLine,
62
62
  });
63
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Updated default props for "${compositionId}"`);
63
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${(0, source_file_write_queue_1.getCodemodTimingPrefix)(logLevel)}${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}`)} Updated default props for "${compositionId}"`);
64
64
  if (!formatted) {
65
65
  (0, log_update_1.warnAboutPrettierOnce)(logLevel);
66
66
  }
@@ -29,171 +29,219 @@ const startServer = async (options) => {
29
29
  });
30
30
  return detection.type === 'match' ? 'stop' : 'continue';
31
31
  };
32
- const watchIgnorePlugin = new bundler_1.WatchIgnoreNextChangePlugin((...args) => {
33
- renderer_1.RenderInternals.Log.trace({ indent: false, logLevel: options.logLevel }, ...args);
32
+ let portSelection = await renderer_1.RenderInternals.getDesiredPort({
33
+ desiredPort,
34
+ from: 3000,
35
+ to: 3100,
36
+ hostsToTry: portConfig.hostsToTry,
37
+ onPortUnavailable,
34
38
  });
35
- const configArgs = {
36
- entry: options.entry,
37
- userDefinedComponent: options.userDefinedComponent,
38
- outDir: null,
39
- environment: 'development',
40
- bundlerOverride: options.bundlerOverride,
41
- rspackOverride: options.rspackOverride,
42
- webpackOverride: options === null || options === void 0 ? void 0 : options.webpackOverride,
43
- remotionRoot: options.remotionRoot,
44
- poll: options.poll,
45
- extraPlugins: [watchIgnorePlugin],
46
- };
47
- let compiler;
48
- if (options.rspack) {
49
- const [, rspackConf] = await bundler_1.BundlerInternals.rspackConfig(configArgs);
50
- compiler = bundler_1.BundlerInternals.createRspackCompiler(rspackConf);
51
- }
52
- else {
53
- const [, webpackConf] = await bundler_1.BundlerInternals.webpackConfig(configArgs);
54
- compiler = (0, bundler_1.webpack)(webpackConf);
55
- }
56
- (0, watch_ignore_next_change_1.setWatchIgnoreNextChangePlugin)(watchIgnorePlugin);
57
- const wdmMiddleware = (0, dev_middleware_1.wdm)(compiler, options.logLevel);
58
- const liveEventsServer = (0, live_events_1.makeLiveEventsRouter)(options.logLevel, () => {
59
- const undoStack = (0, undo_stack_1.getUndoStack)();
60
- const redoStack = (0, undo_stack_1.getRedoStack)();
39
+ if (portSelection.didUsePort) {
40
+ portSelection.unlockPort();
61
41
  return {
62
- undoFile: undoStack.length > 0 ? undoStack[undoStack.length - 1].filePath : null,
63
- redoFile: redoStack.length > 0 ? redoStack[redoStack.length - 1].filePath : null,
42
+ type: 'already-running',
43
+ port: portSelection.port,
64
44
  };
65
- });
66
- (0, hot_middleware_1.setupWebpackHmr)(compiler, options.logLevel, liveEventsServer);
67
- compiler.hooks.done.tap('remotion-node-path-cache', () => {
68
- (0, node_path_cache_1.clearNodePathCache)();
69
- });
70
- const server = node_http_1.default.createServer((request, response) => {
71
- if (options.enableCrossSiteIsolation) {
72
- response.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
73
- response.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
74
- }
75
- new Promise((resolve) => {
76
- wdmMiddleware(request, response, () => {
77
- resolve();
78
- });
79
- })
80
- .then(() => {
81
- return (0, routes_1.handleRoutes)({
82
- staticHash: options.staticHash,
83
- staticHashPrefix: options.staticHashPrefix,
84
- outputHash: options.outputHash,
85
- outputHashPrefix: options.outputHashPrefix,
86
- request: request,
87
- response,
88
- liveEventsServer,
89
- getCurrentInputProps: options.getCurrentInputProps,
90
- getEnvVariables: options.getEnvVariables,
91
- remotionRoot: options.remotionRoot,
92
- entryPoint: options.userDefinedComponent,
93
- publicDir: options.publicDir,
94
- logLevel: options.logLevel,
95
- getRenderQueue: options.getRenderQueue,
96
- getRenderDefaults: options.getRenderDefaults,
97
- getNumberOfAudioTags: options.getNumberOfAudioTags,
98
- queueMethods: options.queueMethods,
99
- gitSource: options.gitSource,
100
- binariesDirectory: options.binariesDirectory,
101
- getAudioLatencyHint: options.getAudioLatencyHint,
102
- getExperimentalKeepAudioContextAlive: options.getExperimentalKeepAudioContextAlive,
103
- getPreviewSampleRate: options.getPreviewSampleRate,
104
- enableCrossSiteIsolation: options.enableCrossSiteIsolation,
105
- getStudioRuntimeConfig: options.getStudioRuntimeConfig,
106
- getDefaultCodingAgent: options.getDefaultCodingAgent,
107
- getDefaultEditor: options.getDefaultEditor,
108
- configFile: options.configFile,
109
- });
110
- })
111
- .catch((err) => {
112
- renderer_1.RenderInternals.Log.error({ indent: false, logLevel: options.logLevel }, `Error while calling ${request.url}`, err);
113
- if (!response.headersSent) {
114
- response.setHeader('content-type', 'application/json');
115
- response.writeHead(500);
116
- }
117
- if (!response.writableEnded) {
118
- response.end(JSON.stringify({
119
- err: err.message,
120
- }));
121
- }
122
- });
123
- });
45
+ }
46
+ const handleRequestBeforeReady = (_request, response) => {
47
+ response.writeHead(503);
48
+ response.end('Studio is starting...');
49
+ };
50
+ const server = node_http_1.default.createServer(handleRequestBeforeReady);
124
51
  const maxTries = 5;
52
+ let selectedPort = null;
125
53
  for (let i = 0; i < maxTries; i++) {
126
54
  try {
127
- const { port, unlockPort, didUsePort } = await renderer_1.RenderInternals.getDesiredPort({
128
- desiredPort,
129
- from: 3000,
130
- to: 3100,
131
- hostsToTry: portConfig.hostsToTry,
132
- onPortUnavailable,
133
- });
134
- if (didUsePort) {
135
- unlockPort();
136
- await Promise.all([
137
- new Promise((resolve) => {
138
- server.close(() => resolve());
139
- }),
140
- new Promise((resolve) => {
141
- compiler.close(() => resolve());
142
- }),
143
- ]);
144
- return {
145
- type: 'already-running',
146
- port,
147
- };
148
- }
149
- const selectedPort = await new Promise((resolve, reject) => {
55
+ const { port, unlockPort } = portSelection;
56
+ selectedPort = await new Promise((resolve, reject) => {
150
57
  renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: options.logLevel }, `Binding server to host ${portConfig.host}, port ${port}`);
58
+ const onListening = () => {
59
+ server.off('error', onError);
60
+ unlockPort();
61
+ resolve(port);
62
+ };
63
+ const onError = (error) => {
64
+ server.off('listening', onListening);
65
+ reject(error);
66
+ };
67
+ server.once('listening', onListening);
68
+ server.once('error', onError);
151
69
  server.listen({
152
70
  port,
153
71
  host: portConfig.host,
154
72
  });
155
- server.on('listening', () => {
156
- resolve(port);
157
- return unlockPort();
158
- });
159
- server.on('error', (err) => {
160
- reject(err);
161
- });
162
73
  });
163
- return {
164
- type: 'started',
165
- port: selectedPort,
166
- liveEventsServer,
167
- close: async () => {
168
- server.closeAllConnections();
169
- await Promise.all([
170
- new Promise((resolve) => {
171
- server.close(() => {
172
- resolve();
173
- });
174
- }),
175
- new Promise((resolve) => {
176
- compiler.close(() => {
177
- resolve();
178
- });
179
- }),
180
- ]);
181
- },
182
- };
74
+ break;
183
75
  }
184
76
  catch (err) {
185
77
  if (!(err instanceof Error)) {
78
+ portSelection.unlockPort();
186
79
  throw err;
187
80
  }
188
81
  const codedError = err;
189
82
  if (codedError.code === 'EADDRINUSE') {
83
+ portSelection.unlockPort();
190
84
  renderer_1.RenderInternals.Log.error({ indent: false, logLevel: options.logLevel }, `Port ${codedError.port} is already in use. Trying another port...`);
85
+ if (i === maxTries - 1) {
86
+ break;
87
+ }
88
+ portSelection = await renderer_1.RenderInternals.getDesiredPort({
89
+ desiredPort,
90
+ from: 3000,
91
+ to: 3100,
92
+ hostsToTry: portConfig.hostsToTry,
93
+ onPortUnavailable,
94
+ });
95
+ if (portSelection.didUsePort) {
96
+ portSelection.unlockPort();
97
+ return {
98
+ type: 'already-running',
99
+ port: portSelection.port,
100
+ };
101
+ }
191
102
  }
192
103
  else {
104
+ portSelection.unlockPort();
193
105
  throw err;
194
106
  }
195
107
  }
196
108
  }
197
- throw new Error(`Tried ${maxTries} times to find a free port. Giving up.`);
109
+ if (selectedPort === null) {
110
+ throw new Error(`Tried ${maxTries} times to find a free port. Giving up.`);
111
+ }
112
+ let compiler = null;
113
+ try {
114
+ const watchIgnorePlugin = new bundler_1.WatchIgnoreNextChangePlugin((...args) => {
115
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel: options.logLevel }, ...args);
116
+ });
117
+ const configArgs = {
118
+ entry: options.entry,
119
+ userDefinedComponent: options.userDefinedComponent,
120
+ outDir: null,
121
+ environment: 'development',
122
+ bundlerOverride: options.bundlerOverride,
123
+ rspackOverride: options.rspackOverride,
124
+ webpackOverride: options === null || options === void 0 ? void 0 : options.webpackOverride,
125
+ remotionRoot: options.remotionRoot,
126
+ poll: options.poll,
127
+ extraPlugins: [watchIgnorePlugin],
128
+ };
129
+ if (options.rspack) {
130
+ const [, rspackConf] = await bundler_1.BundlerInternals.rspackConfig(configArgs);
131
+ compiler = bundler_1.BundlerInternals.createRspackCompiler(rspackConf);
132
+ }
133
+ else {
134
+ const [, webpackConf] = await bundler_1.BundlerInternals.webpackConfig(configArgs);
135
+ compiler = (0, bundler_1.webpack)(webpackConf);
136
+ }
137
+ (0, watch_ignore_next_change_1.setWatchIgnoreNextChangePlugin)(watchIgnorePlugin);
138
+ const wdmMiddleware = (0, dev_middleware_1.wdm)(compiler, options.logLevel);
139
+ const liveEventsServer = (0, live_events_1.makeLiveEventsRouter)(options.logLevel, () => {
140
+ const undoStack = (0, undo_stack_1.getUndoStack)();
141
+ const redoStack = (0, undo_stack_1.getRedoStack)();
142
+ return {
143
+ undoFile: undoStack.length > 0
144
+ ? undoStack[undoStack.length - 1].filePath
145
+ : null,
146
+ redoFile: redoStack.length > 0
147
+ ? redoStack[redoStack.length - 1].filePath
148
+ : null,
149
+ };
150
+ });
151
+ (0, hot_middleware_1.setupWebpackHmr)(compiler, options.logLevel, liveEventsServer);
152
+ compiler.hooks.done.tap('remotion-node-path-cache', () => {
153
+ (0, node_path_cache_1.clearNodePathCache)();
154
+ });
155
+ server.off('request', handleRequestBeforeReady);
156
+ server.on('request', (request, response) => {
157
+ if (options.enableCrossSiteIsolation) {
158
+ response.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
159
+ response.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
160
+ }
161
+ new Promise((resolve) => {
162
+ wdmMiddleware(request, response, () => {
163
+ resolve();
164
+ });
165
+ })
166
+ .then(() => {
167
+ return (0, routes_1.handleRoutes)({
168
+ staticHash: options.staticHash,
169
+ staticHashPrefix: options.staticHashPrefix,
170
+ outputHash: options.outputHash,
171
+ outputHashPrefix: options.outputHashPrefix,
172
+ request: request,
173
+ response,
174
+ liveEventsServer,
175
+ getCurrentInputProps: options.getCurrentInputProps,
176
+ getEnvVariables: options.getEnvVariables,
177
+ remotionRoot: options.remotionRoot,
178
+ entryPoint: options.userDefinedComponent,
179
+ publicDir: options.publicDir,
180
+ logLevel: options.logLevel,
181
+ getRenderQueue: options.getRenderQueue,
182
+ getRenderDefaults: options.getRenderDefaults,
183
+ getNumberOfAudioTags: options.getNumberOfAudioTags,
184
+ queueMethods: options.queueMethods,
185
+ gitSource: options.gitSource,
186
+ binariesDirectory: options.binariesDirectory,
187
+ getAudioLatencyHint: options.getAudioLatencyHint,
188
+ getExperimentalKeepAudioContextAlive: options.getExperimentalKeepAudioContextAlive,
189
+ getPreviewSampleRate: options.getPreviewSampleRate,
190
+ enableCrossSiteIsolation: options.enableCrossSiteIsolation,
191
+ getStudioRuntimeConfig: options.getStudioRuntimeConfig,
192
+ getDefaultCodingAgent: options.getDefaultCodingAgent,
193
+ getDefaultEditor: options.getDefaultEditor,
194
+ configFile: options.configFile,
195
+ });
196
+ })
197
+ .catch((err) => {
198
+ renderer_1.RenderInternals.Log.error({ indent: false, logLevel: options.logLevel }, `Error while calling ${request.url}`, err);
199
+ if (!response.headersSent) {
200
+ response.setHeader('content-type', 'application/json');
201
+ response.writeHead(500);
202
+ }
203
+ if (!response.writableEnded) {
204
+ response.end(JSON.stringify({
205
+ err: err.message,
206
+ }));
207
+ }
208
+ });
209
+ });
210
+ const initializedCompiler = compiler;
211
+ return {
212
+ type: 'started',
213
+ port: selectedPort,
214
+ liveEventsServer,
215
+ close: async () => {
216
+ server.closeAllConnections();
217
+ await Promise.all([
218
+ new Promise((resolve) => {
219
+ server.close(() => {
220
+ resolve();
221
+ });
222
+ }),
223
+ new Promise((resolve) => {
224
+ initializedCompiler.close(() => {
225
+ resolve();
226
+ });
227
+ }),
228
+ ]);
229
+ },
230
+ };
231
+ }
232
+ catch (error) {
233
+ server.closeAllConnections();
234
+ await Promise.all([
235
+ new Promise((resolve) => {
236
+ server.close(() => resolve());
237
+ }),
238
+ compiler
239
+ ? new Promise((resolve) => {
240
+ compiler === null || compiler === void 0 ? void 0 : compiler.close(() => resolve());
241
+ })
242
+ : Promise.resolve(),
243
+ ]);
244
+ throw error;
245
+ }
198
246
  };
199
247
  exports.startServer = startServer;