@remotion/studio-server 4.0.522 → 4.0.523

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.
@@ -1,6 +1,6 @@
1
1
  import type { ApiRoutes } from '@remotion/studio-shared';
2
2
  import type { ApiHandler } from './api-types';
3
- type StandardApiRoute = Exclude<keyof ApiRoutes, '/api/update-config'>;
3
+ type StandardApiRoute = Exclude<keyof ApiRoutes, '/api/install-package' | '/api/update-config'>;
4
4
  export declare const allApiRoutes: {
5
5
  [key in StandardApiRoute]: ApiHandler<ApiRoutes[key]['Request'], ApiRoutes[key]['Response']>;
6
6
  };
@@ -25,7 +25,6 @@ const duplicate_jsx_node_1 = require("./routes/duplicate-jsx-node");
25
25
  const find_in_file_1 = require("./routes/find-in-file");
26
26
  const insert_element_1 = require("./routes/insert-element");
27
27
  const insert_jsx_element_1 = require("./routes/insert-jsx-element");
28
- const install_dependency_1 = require("./routes/install-dependency");
29
28
  const log_studio_error_1 = require("./routes/log-studio-error");
30
29
  const move_keyframes_1 = require("./routes/move-keyframes");
31
30
  const open_in_editor_1 = require("./routes/open-in-editor");
@@ -120,7 +119,6 @@ exports.allApiRoutes = {
120
119
  '/api/restart-studio': restart_studio_1.handleRestartStudio,
121
120
  '/api/default-coding-agent-info': default_coding_agent_1.getDefaultCodingAgentInfoHandler,
122
121
  '/api/default-editor-info': default_editor_1.getDefaultEditorInfoHandler,
123
- '/api/install-package': install_dependency_1.handleInstallPackage,
124
122
  '/api/insert-jsx-element': insert_jsx_element_1.insertJsxElementHandler,
125
123
  '/api/insert-element': insert_element_1.insertElementHandler,
126
124
  '/api/prepare-element-install': prepare_element_install_1.prepareElementInstallHandler,
@@ -65,7 +65,7 @@ const deleteJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) => {
65
65
  const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
66
66
  absolutePath: update.absolutePath,
67
67
  remappings: update.nodePathRemappings,
68
- })));
68
+ })), null);
69
69
  for (const update of updates) {
70
70
  const deletedNodeDescription = getDeletedNodeDescription(update.nodeLabels);
71
71
  (0, undo_stack_1.pushToUndoStack)({
@@ -50,7 +50,7 @@ const duplicateJsxNodeHandler = ({ input: { nodes }, remotionRoot, logLevel }) =
50
50
  const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
51
51
  absolutePath: update.absolutePath,
52
52
  remappings: update.nodePathRemappings,
53
- })));
53
+ })), null);
54
54
  const duplicatedNodeDescription = nodes.length === 1
55
55
  ? updates[0].nodeLabels[0]
56
56
  : `${nodes.length} JSX nodes`;
@@ -1,5 +1,4 @@
1
1
  import type { ElementInstallExpectedFileState, PrepareElementInstallRequest } from '@remotion/studio-shared';
2
- export declare const normalizeElementSourceForComparison: (source: string) => string;
3
2
  export declare const getElementSourceHash: (source: string) => string;
4
3
  export declare const validateElementInstallPosition: (position: import("@remotion/studio-shared").InsertableCompositionElementPosition | null) => void;
5
4
  export declare const validateElementForInstallation: (element: import("@remotion/studio-shared").InstallableElement) => void;
@@ -7,7 +6,7 @@ export declare const makeRelativeElementImportPath: ({ fromFile, toFile, }: {
7
6
  fromFile: string;
8
7
  toFile: string;
9
8
  }) => string;
10
- export declare const getElementInstallPlan: ({ destination, element, entryPoint, remotionRoot, }: PrepareElementInstallRequest & {
9
+ export declare const getElementInstallPlan: ({ destination, element, installationName, entryPoint, remotionRoot, }: PrepareElementInstallRequest & {
11
10
  entryPoint: string;
12
11
  remotionRoot: string;
13
12
  }) => Promise<{
@@ -3,7 +3,7 @@ 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.getElementInstallPlan = exports.makeRelativeElementImportPath = exports.validateElementForInstallation = exports.validateElementInstallPosition = exports.getElementSourceHash = exports.normalizeElementSourceForComparison = void 0;
6
+ exports.getElementInstallPlan = exports.makeRelativeElementImportPath = exports.validateElementForInstallation = exports.validateElementInstallPosition = exports.getElementSourceHash = void 0;
7
7
  const node_crypto_1 = require("node:crypto");
8
8
  const node_fs_1 = require("node:fs");
9
9
  const node_path_1 = __importDefault(require("node:path"));
@@ -11,10 +11,6 @@ const studio_protocol_1 = require("@remotion/studio-protocol");
11
11
  const resolve_composition_component_1 = require("../../helpers/resolve-composition-component");
12
12
  const project_info_1 = require("../project-info");
13
13
  const safe_element_install_path_1 = require("./safe-element-install-path");
14
- const normalizeElementSourceForComparison = (source) => {
15
- return source.replace(/\r\n/g, '\n').trim();
16
- };
17
- exports.normalizeElementSourceForComparison = normalizeElementSourceForComparison;
18
14
  const getElementSourceHash = (source) => {
19
15
  return (0, node_crypto_1.createHash)('sha256').update(source).digest('hex');
20
16
  };
@@ -75,7 +71,7 @@ const getExpectedFileState = (existingSource) => {
75
71
  sourceHash: (0, exports.getElementSourceHash)(existingSource),
76
72
  };
77
73
  };
78
- const getElementInstallPlan = async ({ destination, element, entryPoint, remotionRoot, }) => {
74
+ const getElementInstallPlan = async ({ destination, element, installationName, entryPoint, remotionRoot, }) => {
79
75
  var _a;
80
76
  (0, exports.validateElementForInstallation)(element);
81
77
  const componentName = studio_protocol_1.StudioProtocolInternals.getElementComponentNameFromSourceCode(element.sourceCode);
@@ -92,9 +88,11 @@ const getElementInstallPlan = async ({ destination, element, entryPoint, remotio
92
88
  if (location !== null && !location.canAddSequence) {
93
89
  throw new Error('Cannot insert Element into this composition component');
94
90
  }
95
- const derivedElementFileName = studio_protocol_1.StudioProtocolInternals.makeElementFileNameFromSlug(element.slug);
96
- if (derivedElementFileName === null) {
97
- throw new Error('Element slug must produce a safe lowercase .tsx file name');
91
+ const derivedElementFileName = studio_protocol_1.StudioProtocolInternals.makeElementFileNameFromSlug(installationName !== null && installationName !== void 0 ? installationName : element.slug);
92
+ if (derivedElementFileName === null ||
93
+ (typeof installationName === 'string' &&
94
+ derivedElementFileName !== `${installationName}.element.tsx`)) {
95
+ throw new Error('Use a lowercase installation name with letters, numbers and hyphens, without a file extension.');
98
96
  }
99
97
  const destinationCompositionFile = destination.compositionFile;
100
98
  const destinationCompositionFileName = destinationCompositionFile === null
@@ -21,7 +21,7 @@ const hasExpectedFileState = ({ expected, actual, }) => {
21
21
  }
22
22
  return actual.sourceHash === expected.sourceHash;
23
23
  };
24
- const insertElementHandler = ({ input: { compositionFile, compositionId, element, expectedFileState, from, position, overwriteExisting, }, entryPoint, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
24
+ const insertElementHandler = ({ input: { compositionFile, compositionId, element, installationName, expectedFileState, from, position, overwriteExisting, }, entryPoint, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
25
25
  try {
26
26
  (0, element_install_plan_1.validateElementInstallPosition)(position);
27
27
  if (from !== null &&
@@ -34,6 +34,7 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
34
34
  const componentOwnsSequence = installationMode === 'component-owned-sequence';
35
35
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[insert-element] Received request for compositionFile="${compositionFile}" compositionId="${compositionId}" element="${element.slug}"`);
36
36
  const plan = await (0, element_install_plan_1.getElementInstallPlan)({
37
+ installationName,
37
38
  destination: {
38
39
  type: 'current-composition',
39
40
  compositionFile,
@@ -63,11 +64,8 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
63
64
  throw new Error('Element source changed during installation');
64
65
  }
65
66
  const elementSourcesDiffer = plan.existingElementSource !== null &&
66
- (0, element_install_plan_1.normalizeElementSourceForComparison)(plan.existingElementSource) !==
67
- (0, element_install_plan_1.normalizeElementSourceForComparison)(element.sourceCode);
68
- if (elementSourcesDiffer &&
69
- !overwriteExisting &&
70
- plan.existingElementSource !== null) {
67
+ plan.existingElementSource !== element.sourceCode;
68
+ if (!overwriteExisting && plan.existingElementSource !== null) {
71
69
  return {
72
70
  success: false,
73
71
  type: 'file-conflict',
@@ -116,6 +114,7 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
116
114
  },
117
115
  });
118
116
  const finalPlan = await (0, element_install_plan_1.getElementInstallPlan)({
117
+ installationName,
119
118
  destination: {
120
119
  type: 'current-composition',
121
120
  compositionFile,
@@ -140,7 +139,7 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
140
139
  absolutePath: inserted.fileName,
141
140
  remappings: inserted.nodePathRemappings,
142
141
  },
143
- ]);
142
+ ], null);
144
143
  (0, undo_stack_1.pushTransactionToUndoStack)({
145
144
  snapshots: [
146
145
  ...(shouldWriteElementFile
@@ -171,7 +171,13 @@ const insertJsxElementHandler = ({ input: { compositionFile, compositionId, elem
171
171
  absolutePath: fileName,
172
172
  remappings: nodePathRemappings,
173
173
  },
174
- ]);
174
+ ], insertedNodePath === null
175
+ ? null
176
+ : {
177
+ absolutePath: fileName,
178
+ compositionId,
179
+ nodePath: insertedNodePath,
180
+ });
175
181
  if (insertedNodePath === null) {
176
182
  renderer_1.RenderInternals.Log.warn({ indent: false, logLevel }, 'Could not determine the inserted JSX element node path. Skipping automatic selection.');
177
183
  }
@@ -1,4 +1,18 @@
1
1
  import { type InstallPackageRequest, type InstallPackageResponse, type PackageInstallSpec } from '@remotion/studio-shared';
2
- import type { ApiHandler } from '../api-types';
3
2
  export declare const getPackageInstallSpec: (dependency: PackageInstallSpec) => string;
4
- export declare const handleInstallPackage: ApiHandler<InstallPackageRequest, InstallPackageResponse>;
3
+ export declare const handleInstallPackage: ({ logLevel, remotionRoot, input: { dependencies }, invalidateBundle, }: {
4
+ input: InstallPackageRequest;
5
+ entryPoint: string;
6
+ remotionRoot: string;
7
+ request: import("http").IncomingMessage;
8
+ response: import("http").ServerResponse<import("http").IncomingMessage>;
9
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
10
+ methods: import("../api-types").QueueMethods;
11
+ publicDir: string;
12
+ binariesDirectory: string | null;
13
+ configFile: string | null;
14
+ getDefaultCodingAgent: () => "claude-code" | "codex" | "copilot" | "cursor" | null;
15
+ getDefaultEditor: () => import("@remotion/renderer").DefaultEditor | null;
16
+ } & {
17
+ readonly invalidateBundle: () => Promise<void>;
18
+ }) => Promise<InstallPackageResponse>;
@@ -22,7 +22,7 @@ const getPackageInstallSpec = (dependency) => {
22
22
  return extraVersion === null ? name : `${name}@${extraVersion}`;
23
23
  };
24
24
  exports.getPackageInstallSpec = getPackageInstallSpec;
25
- const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependencies } }) => {
25
+ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependencies }, invalidateBundle, }) => {
26
26
  for (const dependency of dependencies) {
27
27
  if (!(0, studio_shared_1.isValidPackageName)(dependency.name)) {
28
28
  return Promise.reject(new Error(`Package name ${JSON.stringify(dependency.name)} is invalid.`));
@@ -41,12 +41,24 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependenc
41
41
  if (manager === 'unknown') {
42
42
  throw new Error(`No lockfile was found in your project (one of ${get_package_manager_1.lockFilePaths.map((p) => p.path).join(', ')}). Install dependencies using your favorite manager!`);
43
43
  }
44
+ const additionalArgs = ['--ignore-scripts'];
45
+ if (manager.manager === 'yarn') {
46
+ const version = (0, node_child_process_1.execFileSync)('yarn', ['--version'], {
47
+ ...(0, package_manager_spawn_options_1.getPackageManagerSpawnOptions)(),
48
+ cwd: remotionRoot,
49
+ encoding: 'utf8',
50
+ timeout: 10000,
51
+ }).trim();
52
+ if (!/^1\./.test(version)) {
53
+ additionalArgs[0] = '--mode=skip-build';
54
+ }
55
+ }
44
56
  const packagesWithVersions = dependencies.map(exports.getPackageInstallSpec);
45
57
  const command = (0, install_command_1.getInstallCommand)({
46
58
  manager: manager.manager,
47
59
  packages: packagesWithVersions,
48
60
  version: '',
49
- additionalArgs: manager.manager === 'yarn' ? [] : ['--ignore-scripts'],
61
+ additionalArgs,
50
62
  });
51
63
  renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray(`╭─ ${manager.manager} ${command.join(' ')}`));
52
64
  const time = Date.now();
@@ -54,6 +66,7 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependenc
54
66
  await new Promise((resolve, reject) => {
55
67
  const cmd = (0, node_child_process_1.spawn)(manager.manager, command, {
56
68
  ...(0, package_manager_spawn_options_1.getPackageManagerSpawnOptions)(),
69
+ cwd: remotionRoot,
57
70
  env: {
58
71
  ...process.env,
59
72
  YARN_ENABLE_SCRIPTS: 'false',
@@ -70,6 +83,7 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { dependenc
70
83
  ? resolve()
71
84
  : reject(new Error(`Command exited with code ${code} and signal ${signal}`)));
72
85
  });
86
+ await invalidateBundle();
73
87
  renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray('╰─ '), `Done in ${Date.now() - time}ms`);
74
88
  return {};
75
89
  }
@@ -33,7 +33,7 @@ const reorderSequenceHandler = ({ input: { fileName, sourceNodePath, targetNodeP
33
33
  absolutePath,
34
34
  remappings: nodePathRemappings,
35
35
  },
36
- ]);
36
+ ], null);
37
37
  (0, undo_stack_1.pushToUndoStack)({
38
38
  filePath: absolutePath,
39
39
  oldContents: fileContents,
@@ -30,7 +30,7 @@ const splitJsxSequenceHandler = ({ input: { fileName, nodePath, sequenceKeys, sp
30
30
  absolutePath,
31
31
  remappings: nodePathRemappings,
32
32
  },
33
- ]);
33
+ ], null);
34
34
  (0, undo_stack_1.pushToUndoStack)({
35
35
  filePath: absolutePath,
36
36
  oldContents: fileContents,
@@ -29,7 +29,7 @@ const splitVideoFromAudioHandler = ({ input: { fileName, nodePath }, remotionRoo
29
29
  absolutePath,
30
30
  remappings: nodePathRemappings,
31
31
  },
32
- ]);
32
+ ], null);
33
33
  (0, undo_stack_1.pushToUndoStack)({
34
34
  filePath: absolutePath,
35
35
  oldContents: fileContents,
@@ -238,6 +238,12 @@ const updateConfigHandler = async ({ input, configFile, getStudioRuntimeConfig,
238
238
  if (update.type === 'delete') {
239
239
  continue;
240
240
  }
241
+ if (update.setter === 'setKeyboardShortcuts') {
242
+ const keyboardShortcutsError = (0, studio_shared_1.validateStudioKeyboardShortcuts)(update.value);
243
+ if (keyboardShortcutsError !== null) {
244
+ return { success: false, reason: keyboardShortcutsError };
245
+ }
246
+ }
241
247
  if (update.setter === 'setDefaultCodingAgent' &&
242
248
  (typeof update.value !== 'string' ||
243
249
  !renderer_1.defaultCodingAgentIds.includes(update.value))) {
@@ -2,4 +2,8 @@ import type { SequenceNodePathMutation, SequenceNodePathRemapping } from '@remot
2
2
  export declare const broadcastSequenceNodePathMutation: (files: {
3
3
  absolutePath: string;
4
4
  remappings: SequenceNodePathRemapping[];
5
- }[]) => SequenceNodePathMutation;
5
+ }[], timelineSelection: {
6
+ compositionId: string;
7
+ absolutePath: string;
8
+ nodePath: import("remotion").SequenceNodePath;
9
+ } | null) => SequenceNodePathMutation;
@@ -5,11 +5,12 @@ const node_crypto_1 = require("node:crypto");
5
5
  const live_events_1 = require("./live-events");
6
6
  const mutationSessionId = (0, node_crypto_1.randomUUID)();
7
7
  let mutationCounter = 0;
8
- const broadcastSequenceNodePathMutation = (files) => {
8
+ const broadcastSequenceNodePathMutation = (files, timelineSelection) => {
9
9
  var _a;
10
10
  mutationCounter++;
11
11
  const mutation = {
12
12
  mutationId: `${mutationSessionId}:${mutationCounter}`,
13
+ timelineSelection,
13
14
  files,
14
15
  };
15
16
  (_a = (0, live_events_1.getLiveEventsListener)()) === null || _a === void 0 ? void 0 : _a.sendEventToClient({
@@ -140,6 +140,22 @@ const startServer = async (options) => {
140
140
  }
141
141
  (0, watch_ignore_next_change_1.setWatchIgnoreNextChangePlugin)(watchIgnorePlugin);
142
142
  const wdmMiddleware = (0, dev_middleware_1.wdm)(compiler, options.logLevel);
143
+ const invalidateBundle = () => {
144
+ return new Promise((resolve, reject) => {
145
+ const watching = compiler === null || compiler === void 0 ? void 0 : compiler.watching;
146
+ if (!watching) {
147
+ reject(new Error('The Studio bundle is not being watched.'));
148
+ return;
149
+ }
150
+ watching.invalidate((error) => {
151
+ if (error) {
152
+ reject(error);
153
+ return;
154
+ }
155
+ resolve();
156
+ });
157
+ });
158
+ };
143
159
  const liveEventsServer = (0, live_events_1.makeLiveEventsRouter)(options.logLevel, () => {
144
160
  const undoStack = (0, undo_stack_1.getUndoStack)();
145
161
  const redoStack = (0, undo_stack_1.getRedoStack)();
@@ -196,6 +212,7 @@ const startServer = async (options) => {
196
212
  getDefaultCodingAgent: options.getDefaultCodingAgent,
197
213
  getDefaultEditor: options.getDefaultEditor,
198
214
  configFile: options.configFile,
215
+ invalidateBundle,
199
216
  });
200
217
  })
201
218
  .catch((err) => {
@@ -264,7 +264,7 @@ function popUndo() {
264
264
  },
265
265
  ];
266
266
  });
267
- const nodePathMutation = files.length === 0 ? null : (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(files);
267
+ const nodePathMutation = files.length === 0 ? null : (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(files, null);
268
268
  for (const snapshot of entry.snapshots) {
269
269
  suppressUndoStackInvalidation(snapshot.filePath);
270
270
  if (entry.suppressHmrOnFileRestore) {
@@ -334,7 +334,7 @@ function popRedo() {
334
334
  },
335
335
  ];
336
336
  });
337
- const nodePathMutation = files.length === 0 ? null : (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(files);
337
+ const nodePathMutation = files.length === 0 ? null : (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(files, null);
338
338
  for (const snapshot of snapshotsWithNewContents) {
339
339
  suppressUndoStackInvalidation(snapshot.filePath);
340
340
  if (entry.suppressHmrOnFileRestore) {
package/dist/routes.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { DefaultEditor } from '@remotion/renderer';
3
3
  import type { GitSource, RenderDefaults, RenderJob, StudioRuntimeConfig } from '@remotion/studio-shared';
4
4
  import type { QueueMethods } from './preview-server/api-types';
5
5
  import type { LiveEventsServer } from './preview-server/live-events';
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, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultCodingAgent, getDefaultEditor, 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, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultCodingAgent, getDefaultEditor, configFile, invalidateBundle, }: {
7
7
  staticHash: string;
8
8
  staticHashPrefix: string;
9
9
  outputHash: string;
@@ -31,4 +31,5 @@ export declare const handleRoutes: ({ staticHash, staticHashPrefix, outputHash,
31
31
  getDefaultCodingAgent: () => "claude-code" | "codex" | "copilot" | "cursor" | null;
32
32
  getDefaultEditor: () => DefaultEditor | null;
33
33
  configFile: string | null;
34
+ invalidateBundle: () => Promise<void>;
34
35
  }) => Promise<void>;
package/dist/routes.js CHANGED
@@ -52,6 +52,7 @@ const get_static_file_fallback_hint_1 = require("./preview-server/get-static-fil
52
52
  const handler_1 = require("./preview-server/handler");
53
53
  const public_folder_1 = require("./preview-server/public-folder");
54
54
  const app_icon_1 = require("./preview-server/routes/app-icon");
55
+ const install_dependency_1 = require("./preview-server/routes/install-dependency");
55
56
  const open_in_editor_1 = require("./preview-server/routes/open-in-editor");
56
57
  const update_config_1 = require("./preview-server/routes/update-config");
57
58
  const serve_static_1 = require("./preview-server/serve-static");
@@ -139,6 +140,7 @@ const handleFallback = async ({ remotionRoot, hash, response, request, getCurren
139
140
  (0, public_folder_1.fetchFolder)({ publicDir, staticHash: hash });
140
141
  const installedDependencies = (0, get_installed_installable_packages_1.getInstalledInstallablePackages)(remotionRoot);
141
142
  response.end(bundler_1.BundlerInternals.indexHtml({
143
+ importMap: null,
142
144
  staticHash: hash,
143
145
  publicPath: '/',
144
146
  editorName: displayName,
@@ -287,7 +289,7 @@ const handleBeep = (_, response) => {
287
289
  readStream.pipe(response);
288
290
  return Promise.resolve();
289
291
  };
290
- const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, getAudioLatencyHint, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultCodingAgent, getDefaultEditor, configFile, }) => {
292
+ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, getAudioLatencyHint, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultCodingAgent, getDefaultEditor, configFile, invalidateBundle, }) => {
291
293
  const url = new URL(request.url, 'http://localhost');
292
294
  if (url.pathname === '/api/file-source') {
293
295
  return handleFileSource({
@@ -387,6 +389,22 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
387
389
  getDefaultEditor,
388
390
  });
389
391
  }
392
+ if (url.pathname === '/api/install-package') {
393
+ return (0, handler_1.handleRequest)({
394
+ remotionRoot,
395
+ entryPoint,
396
+ handler: (params) => (0, install_dependency_1.handleInstallPackage)({ ...params, invalidateBundle }),
397
+ request,
398
+ response,
399
+ logLevel,
400
+ methods,
401
+ binariesDirectory,
402
+ publicDir,
403
+ configFile,
404
+ getDefaultCodingAgent,
405
+ getDefaultEditor,
406
+ });
407
+ }
390
408
  for (const [key, value] of Object.entries(api_routes_1.allApiRoutes)) {
391
409
  if (url.pathname === key) {
392
410
  return (0, handler_1.handleRequest)({
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.522",
6
+ "version": "4.0.523",
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.522",
26
+ "@remotion/studio-protocol": "4.0.523",
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.5.4",
34
34
  "prettier": "3.8.1",
35
- "remotion": "4.0.522",
35
+ "remotion": "4.0.523",
36
36
  "recast": "0.23.21",
37
- "@remotion/bundler": "4.0.522",
38
- "@remotion/renderer": "4.0.522",
39
- "@remotion/studio-codemods": "4.0.522",
40
- "@remotion/studio-shared": "4.0.522",
37
+ "@remotion/bundler": "4.0.523",
38
+ "@remotion/renderer": "4.0.523",
39
+ "@remotion/studio-codemods": "4.0.523",
40
+ "@remotion/studio-shared": "4.0.523",
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.522",
48
+ "@remotion/eslint-config-internal": "4.0.523",
49
49
  "eslint": "9.19.0",
50
50
  "@types/node": "20.12.14",
51
51
  "@typescript/native-preview": "7.0.0-dev.20260217.1"