@remotion/studio-server 4.0.469 → 4.0.471

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 (68) hide show
  1. package/dist/codemods/add-effect.d.ts +15 -0
  2. package/dist/codemods/add-effect.js +231 -0
  3. package/dist/codemods/delete-effect.d.ts +18 -0
  4. package/dist/codemods/delete-effect.js +95 -21
  5. package/dist/codemods/delete-jsx-node.d.ts +10 -0
  6. package/dist/codemods/delete-jsx-node.js +38 -14
  7. package/dist/codemods/reorder-effect.d.ts +13 -0
  8. package/dist/codemods/reorder-effect.js +61 -0
  9. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.d.ts +4 -0
  10. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.js +152 -0
  11. package/dist/codemods/update-keyframes/update-keyframes.d.ts +12 -0
  12. package/dist/codemods/update-keyframes/update-keyframes.js +116 -31
  13. package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +32 -10
  14. package/dist/codemods/update-sequence-props/update-sequence-props.js +39 -7
  15. package/dist/helpers/open-in-editor.d.ts +2 -2
  16. package/dist/helpers/open-in-editor.js +35 -2
  17. package/dist/helpers/resolve-composition-component.d.ts +15 -0
  18. package/dist/helpers/resolve-composition-component.js +269 -31
  19. package/dist/index.d.ts +2 -1
  20. package/dist/preview-server/api-routes.js +20 -0
  21. package/dist/preview-server/routes/add-effect-keyframe.d.ts +3 -0
  22. package/dist/preview-server/routes/add-effect-keyframe.js +91 -0
  23. package/dist/preview-server/routes/add-effect.d.ts +3 -0
  24. package/dist/preview-server/routes/add-effect.js +68 -0
  25. package/dist/preview-server/routes/add-sequence-keyframe.d.ts +3 -0
  26. package/dist/preview-server/routes/add-sequence-keyframe.js +87 -0
  27. package/dist/preview-server/routes/apply-codemod.js +1 -0
  28. package/dist/preview-server/routes/apply-visual-control-change.js +1 -0
  29. package/dist/preview-server/routes/can-update-sequence-props.d.ts +1 -0
  30. package/dist/preview-server/routes/can-update-sequence-props.js +48 -14
  31. package/dist/preview-server/routes/composition-component-info.d.ts +3 -0
  32. package/dist/preview-server/routes/composition-component-info.js +26 -0
  33. package/dist/preview-server/routes/delete-effect-keyframe.d.ts +3 -0
  34. package/dist/preview-server/routes/delete-effect-keyframe.js +89 -0
  35. package/dist/preview-server/routes/delete-effect.js +76 -37
  36. package/dist/preview-server/routes/delete-jsx-node.js +67 -36
  37. package/dist/preview-server/routes/delete-keyframes.d.ts +13 -0
  38. package/dist/preview-server/routes/delete-keyframes.js +263 -0
  39. package/dist/preview-server/routes/delete-sequence-keyframe.d.ts +3 -0
  40. package/dist/preview-server/routes/delete-sequence-keyframe.js +82 -0
  41. package/dist/preview-server/routes/duplicate-jsx-node.js +1 -0
  42. package/dist/preview-server/routes/insert-jsx-element.d.ts +3 -0
  43. package/dist/preview-server/routes/insert-jsx-element.js +79 -0
  44. package/dist/preview-server/routes/open-in-editor.d.ts +4 -0
  45. package/dist/preview-server/routes/open-in-editor.js +40 -0
  46. package/dist/preview-server/routes/register-client-render.d.ts +3 -0
  47. package/dist/preview-server/routes/register-client-render.js +11 -0
  48. package/dist/preview-server/routes/reorder-effect.d.ts +3 -0
  49. package/dist/preview-server/routes/reorder-effect.js +67 -0
  50. package/dist/preview-server/routes/save-effect-props.js +1 -0
  51. package/dist/preview-server/routes/save-sequence-props.js +158 -72
  52. package/dist/preview-server/routes/subscribe-to-sequence-props.js +2 -1
  53. package/dist/preview-server/routes/unregister-client-render.d.ts +4 -0
  54. package/dist/preview-server/routes/unregister-client-render.js +11 -0
  55. package/dist/preview-server/routes/update-default-props.js +1 -0
  56. package/dist/preview-server/sequence-props-watchers.d.ts +2 -1
  57. package/dist/preview-server/sequence-props-watchers.js +22 -2
  58. package/dist/preview-server/start-server.d.ts +1 -0
  59. package/dist/preview-server/start-server.js +1 -0
  60. package/dist/preview-server/undo-stack.d.ts +35 -4
  61. package/dist/preview-server/undo-stack.js +130 -42
  62. package/dist/preview-server/validate-same-origin.d.ts +2 -0
  63. package/dist/preview-server/validate-same-origin.js +13 -0
  64. package/dist/routes.d.ts +2 -1
  65. package/dist/routes.js +9 -136
  66. package/dist/start-studio.d.ts +2 -1
  67. package/dist/start-studio.js +2 -1
  68. package/package.json +6 -6
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pushToUndoStack = pushToUndoStack;
4
+ exports.pushTransactionToUndoStack = pushTransactionToUndoStack;
4
5
  exports.printUndoHint = printUndoHint;
5
6
  exports.pushToRedoStack = pushToRedoStack;
6
7
  exports.suppressUndoStackInvalidation = suppressUndoStackInvalidation;
@@ -8,6 +9,7 @@ exports.popUndo = popUndo;
8
9
  exports.popRedo = popRedo;
9
10
  exports.getUndoStack = getUndoStack;
10
11
  exports.getRedoStack = getRedoStack;
12
+ exports.clearUndoStackForTests = clearUndoStackForTests;
11
13
  const node_fs_1 = require("node:fs");
12
14
  const renderer_1 = require("@remotion/renderer");
13
15
  const parse_ast_1 = require("../codemods/parse-ast");
@@ -35,23 +37,60 @@ function broadcastState() {
35
37
  });
36
38
  });
37
39
  }
38
- function pushToUndoStack({ filePath, oldContents, logLevel, remotionRoot, logLine, description, entryType, suppressHmrOnFileRestore, }) {
40
+ const entryTouchesFile = (entry, filePath) => {
41
+ return entry.snapshots.some((snapshot) => snapshot.filePath === filePath);
42
+ };
43
+ const getEntryFilePaths = (entry) => {
44
+ return entry.snapshots.map((snapshot) => snapshot.filePath);
45
+ };
46
+ const makeUndoEntry = ({ snapshots, description, entryType, suppressHmrOnFileRestore, }) => {
47
+ if (snapshots.length === 0) {
48
+ throw new Error('Cannot create an undo entry without snapshots');
49
+ }
50
+ return {
51
+ filePath: snapshots[0].filePath,
52
+ logLine: snapshots[0].logLine,
53
+ snapshots,
54
+ description,
55
+ entryType,
56
+ suppressHmrOnFileRestore,
57
+ };
58
+ };
59
+ function pushToUndoStack({ filePath, oldContents, newContents, logLevel, remotionRoot, logLine, description, entryType, suppressHmrOnFileRestore, }) {
60
+ pushTransactionToUndoStack({
61
+ snapshots: [
62
+ {
63
+ filePath,
64
+ oldContents,
65
+ newContents,
66
+ logLine,
67
+ },
68
+ ],
69
+ logLevel,
70
+ remotionRoot,
71
+ description,
72
+ entryType,
73
+ suppressHmrOnFileRestore,
74
+ });
75
+ }
76
+ function pushTransactionToUndoStack({ snapshots, logLevel, remotionRoot, description, entryType, suppressHmrOnFileRestore, }) {
39
77
  storedLogLevel = logLevel;
40
78
  storedRemotionRoot = remotionRoot;
41
- undoStack.push({
42
- filePath,
43
- oldContents,
44
- logLine,
79
+ const entry = makeUndoEntry({
80
+ snapshots,
45
81
  description,
46
82
  entryType,
47
83
  suppressHmrOnFileRestore,
48
84
  });
85
+ undoStack.push(entry);
49
86
  if (undoStack.length > MAX_ENTRIES) {
50
87
  undoStack.shift();
51
88
  }
52
89
  redoStack.length = 0;
53
- renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray(`Undo stack: added entry for ${filePath} (${undoStack.length} items)`));
54
- ensureWatching(filePath);
90
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray(`Undo stack: added entry for ${entry.filePath} (${undoStack.length} items)`));
91
+ for (const filePath of getEntryFilePaths(entry)) {
92
+ ensureWatching(filePath);
93
+ }
55
94
  broadcastState();
56
95
  }
57
96
  function printUndoHint(logLevel) {
@@ -61,20 +100,28 @@ function printUndoHint(logLevel) {
61
100
  renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray(`Tip: ${shortcut} in Studio to undo`));
62
101
  }
63
102
  }
64
- function pushToRedoStack({ filePath, oldContents, logLine, description, entryType, suppressHmrOnFileRestore, }) {
65
- redoStack.push({
66
- filePath,
67
- oldContents,
68
- logLine,
103
+ function pushToRedoStack({ filePath, oldContents, newContents, logLine, description, entryType, suppressHmrOnFileRestore, }) {
104
+ const entry = makeUndoEntry({
105
+ snapshots: [
106
+ {
107
+ filePath,
108
+ oldContents,
109
+ newContents,
110
+ logLine,
111
+ },
112
+ ],
69
113
  description,
70
114
  entryType,
71
115
  suppressHmrOnFileRestore,
72
116
  });
117
+ redoStack.push(entry);
73
118
  if (redoStack.length > MAX_ENTRIES) {
74
119
  redoStack.shift();
75
120
  }
76
- renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: storedLogLevel }, renderer_1.RenderInternals.chalk.gray(`Redo stack: added entry for ${filePath} (${redoStack.length} items)`));
77
- ensureWatching(filePath);
121
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: storedLogLevel }, renderer_1.RenderInternals.chalk.gray(`Redo stack: added entry for ${entry.filePath} (${redoStack.length} items)`));
122
+ for (const watchedFilePath of getEntryFilePaths(entry)) {
123
+ ensureWatching(watchedFilePath);
124
+ }
78
125
  broadcastState();
79
126
  }
80
127
  function suppressUndoStackInvalidation(filePath) {
@@ -109,7 +156,7 @@ function invalidateForFile(filePath) {
109
156
  let changed = false;
110
157
  let lastUndoIndex = -1;
111
158
  for (let i = undoStack.length - 1; i >= 0; i--) {
112
- if (undoStack[i].filePath === filePath) {
159
+ if (entryTouchesFile(undoStack[i], filePath)) {
113
160
  lastUndoIndex = i;
114
161
  break;
115
162
  }
@@ -122,7 +169,7 @@ function invalidateForFile(filePath) {
122
169
  }
123
170
  let lastRedoIndex = -1;
124
171
  for (let i = redoStack.length - 1; i >= 0; i--) {
125
- if (redoStack[i].filePath === filePath) {
172
+ if (entryTouchesFile(redoStack[i], filePath)) {
126
173
  lastRedoIndex = i;
127
174
  break;
128
175
  }
@@ -140,8 +187,8 @@ function invalidateForFile(filePath) {
140
187
  }
141
188
  function cleanupWatchers() {
142
189
  const filesInStacks = new Set([
143
- ...undoStack.map((e) => e.filePath),
144
- ...redoStack.map((e) => e.filePath),
190
+ ...undoStack.flatMap(getEntryFilePaths),
191
+ ...redoStack.flatMap(getEntryFilePaths),
145
192
  ]);
146
193
  for (const [filePath, watcher] of watchers) {
147
194
  if (!filesInStacks.has(filePath)) {
@@ -182,26 +229,39 @@ function popUndo() {
182
229
  if (!entry) {
183
230
  return { success: false, reason: 'Nothing to undo' };
184
231
  }
185
- const currentContents = (0, node_fs_1.readFileSync)(entry.filePath, 'utf-8');
186
- redoStack.push({
187
- filePath: entry.filePath,
188
- oldContents: currentContents,
189
- logLine: entry.logLine,
232
+ const redoSnapshots = entry.snapshots.map((snapshot) => {
233
+ var _a;
234
+ return {
235
+ ...snapshot,
236
+ newContents: (_a = snapshot.newContents) !== null && _a !== void 0 ? _a : (0, node_fs_1.readFileSync)(snapshot.filePath, 'utf-8'),
237
+ };
238
+ });
239
+ redoStack.push(makeUndoEntry({
240
+ snapshots: redoSnapshots,
190
241
  description: entry.description,
191
242
  entryType: entry.entryType,
192
243
  suppressHmrOnFileRestore: entry.suppressHmrOnFileRestore,
193
- });
194
- suppressUndoStackInvalidation(entry.filePath);
195
- if (entry.suppressHmrOnFileRestore) {
196
- (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(entry.filePath);
244
+ }));
245
+ if (redoStack.length > MAX_ENTRIES) {
246
+ redoStack.shift();
247
+ }
248
+ for (const snapshot of entry.snapshots) {
249
+ suppressUndoStackInvalidation(snapshot.filePath);
250
+ if (entry.suppressHmrOnFileRestore) {
251
+ (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
252
+ }
253
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(snapshot.filePath, snapshot.oldContents, undefined);
197
254
  }
198
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents, undefined);
199
255
  renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: storedLogLevel }, renderer_1.RenderInternals.chalk.gray(`Undo: restored ${entry.filePath} (undo: ${undoStack.length}, redo: ${redoStack.length})`));
200
256
  logFileAction(entry.description.undoMessage, entry.filePath, entry.logLine);
201
257
  if (entry.entryType === 'visual-control') {
202
- emitVisualControlChanges(entry.oldContents);
258
+ for (const snapshot of entry.snapshots) {
259
+ emitVisualControlChanges(snapshot.oldContents);
260
+ }
261
+ }
262
+ for (const filePath of getEntryFilePaths(entry)) {
263
+ ensureWatching(filePath);
203
264
  }
204
- ensureWatching(entry.filePath);
205
265
  broadcastState();
206
266
  return { success: true };
207
267
  }
@@ -210,32 +270,60 @@ function popRedo() {
210
270
  if (!entry) {
211
271
  return { success: false, reason: 'Nothing to redo' };
212
272
  }
213
- const currentContents = (0, node_fs_1.readFileSync)(entry.filePath, 'utf-8');
214
- undoStack.push({
215
- filePath: entry.filePath,
216
- oldContents: currentContents,
217
- logLine: entry.logLine,
273
+ const snapshotsWithNewContents = [];
274
+ for (const snapshot of entry.snapshots) {
275
+ if (snapshot.newContents === null) {
276
+ return { success: false, reason: 'Redo entry is incomplete' };
277
+ }
278
+ snapshotsWithNewContents.push({
279
+ ...snapshot,
280
+ newContents: snapshot.newContents,
281
+ });
282
+ }
283
+ undoStack.push(makeUndoEntry({
284
+ snapshots: snapshotsWithNewContents,
218
285
  description: entry.description,
219
286
  entryType: entry.entryType,
220
287
  suppressHmrOnFileRestore: entry.suppressHmrOnFileRestore,
221
- });
222
- suppressUndoStackInvalidation(entry.filePath);
223
- if (entry.suppressHmrOnFileRestore) {
224
- (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(entry.filePath);
288
+ }));
289
+ if (undoStack.length > MAX_ENTRIES) {
290
+ undoStack.shift();
291
+ }
292
+ for (const snapshot of snapshotsWithNewContents) {
293
+ suppressUndoStackInvalidation(snapshot.filePath);
294
+ if (entry.suppressHmrOnFileRestore) {
295
+ (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
296
+ }
297
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(snapshot.filePath, snapshot.newContents, undefined);
225
298
  }
226
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents, undefined);
227
299
  renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: storedLogLevel }, renderer_1.RenderInternals.chalk.gray(`Redo: restored ${entry.filePath} (undo: ${undoStack.length}, redo: ${redoStack.length})`));
228
300
  logFileAction(entry.description.redoMessage, entry.filePath, entry.logLine);
229
301
  if (entry.entryType === 'visual-control') {
230
- emitVisualControlChanges(entry.oldContents);
302
+ for (const snapshot of entry.snapshots) {
303
+ if (snapshot.newContents !== null) {
304
+ emitVisualControlChanges(snapshot.newContents);
305
+ }
306
+ }
307
+ }
308
+ for (const filePath of getEntryFilePaths(entry)) {
309
+ ensureWatching(filePath);
231
310
  }
232
- ensureWatching(entry.filePath);
233
311
  broadcastState();
234
312
  return { success: true };
235
313
  }
314
+ /*
315
+ * Keep stack accessors typed as readonly arrays so callers can only inspect
316
+ * whether undo/redo is available and which file represents the top entry.
317
+ */
236
318
  function getUndoStack() {
237
319
  return undoStack;
238
320
  }
239
321
  function getRedoStack() {
240
322
  return redoStack;
241
323
  }
324
+ function clearUndoStackForTests() {
325
+ undoStack.length = 0;
326
+ redoStack.length = 0;
327
+ suppressedWrites.clear();
328
+ cleanupWatchers();
329
+ }
@@ -0,0 +1,2 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ export declare const validateSameOrigin: (req: IncomingMessage) => void;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateSameOrigin = void 0;
4
+ const validateSameOrigin = (req) => {
5
+ const { origin, host } = req.headers;
6
+ if (origin) {
7
+ const originUrl = new URL(origin);
8
+ if (originUrl.host !== host) {
9
+ throw new Error('Request from different origin not allowed');
10
+ }
11
+ }
12
+ };
13
+ exports.validateSameOrigin = validateSameOrigin;
package/dist/routes.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
2
2
  import type { GitSource, RenderDefaults, RenderJob } from '@remotion/studio-shared';
3
3
  import type { QueueMethods } from './preview-server/api-types';
4
4
  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, numberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, audioLatencyHint, enableCrossSiteIsolation, }: {
5
+ export declare const handleRoutes: ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, numberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, audioLatencyHint, previewSampleRate, enableCrossSiteIsolation, }: {
6
6
  staticHash: string;
7
7
  staticHashPrefix: string;
8
8
  outputHash: string;
@@ -23,5 +23,6 @@ export declare const handleRoutes: ({ staticHash, staticHashPrefix, outputHash,
23
23
  gitSource: GitSource | null;
24
24
  binariesDirectory: string | null;
25
25
  audioLatencyHint: AudioContextLatencyCategory | null;
26
+ previewSampleRate: number | null;
26
27
  enableCrossSiteIsolation: boolean;
27
28
  }) => Promise<void>;
package/dist/routes.js CHANGED
@@ -44,18 +44,16 @@ const studio_shared_1 = require("@remotion/studio-shared");
44
44
  const client_render_queue_1 = require("./client-render-queue");
45
45
  const get_file_source_1 = require("./helpers/get-file-source");
46
46
  const get_installed_installable_packages_1 = require("./helpers/get-installed-installable-packages");
47
- const open_in_editor_1 = require("./helpers/open-in-editor");
48
- const resolve_composition_component_1 = require("./helpers/resolve-composition-component");
49
47
  const resolve_output_path_1 = require("./helpers/resolve-output-path");
50
48
  const api_routes_1 = require("./preview-server/api-routes");
51
49
  const get_package_manager_1 = require("./preview-server/get-package-manager");
52
50
  const get_static_file_fallback_hint_1 = require("./preview-server/get-static-file-fallback-hint");
53
51
  const handler_1 = require("./preview-server/handler");
54
- const parse_body_1 = require("./preview-server/parse-body");
55
52
  const public_folder_1 = require("./preview-server/public-folder");
53
+ const open_in_editor_1 = require("./preview-server/routes/open-in-editor");
56
54
  const serve_static_1 = require("./preview-server/serve-static");
55
+ const validate_same_origin_1 = require("./preview-server/validate-same-origin");
57
56
  const watch_ignore_next_change_1 = require("./preview-server/watch-ignore-next-change");
58
- const editorGuess = (0, open_in_editor_1.guessEditor)();
59
57
  const loggedStaticFileHints = new Set();
60
58
  const static404 = (response) => {
61
59
  response.writeHead(404);
@@ -80,7 +78,7 @@ const handleRemotionConfig = (response, remotionRoot) => {
80
78
  response.end(JSON.stringify(body));
81
79
  return Promise.resolve();
82
80
  };
83
- const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, numberOfAudioTags, audioLatencyHint, gitSource, logLevel, enableCrossSiteIsolation, }) => {
81
+ const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, numberOfAudioTags, audioLatencyHint, previewSampleRate, gitSource, logLevel, enableCrossSiteIsolation, }) => {
84
82
  var _a;
85
83
  const acceptsHtml = ((_a = request.headers.accept) !== null && _a !== void 0 ? _a : '').includes('text/html');
86
84
  if (request.method === 'GET' && acceptsHtml) {
@@ -103,8 +101,7 @@ const handleFallback = async ({ remotionRoot, hash, response, request, getCurren
103
101
  `Change \`"${pathname}"\` to \`staticFile("${pathname}")\` to fix the error.`,
104
102
  ].join('\n'));
105
103
  }
106
- const [edit] = await editorGuess;
107
- const displayName = (0, open_in_editor_1.getDisplayNameForEditor)(edit ? edit.command : null);
104
+ const displayName = await (0, open_in_editor_1.getEditorName)();
108
105
  response.setHeader('content-type', 'text/html');
109
106
  if (enableCrossSiteIsolation) {
110
107
  response.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
@@ -145,6 +142,7 @@ const handleFallback = async ({ remotionRoot, hash, response, request, getCurren
145
142
  logLevel,
146
143
  mode: 'dev',
147
144
  audioLatencyHint: audioLatencyHint !== null && audioLatencyHint !== void 0 ? audioLatencyHint : 'playback',
145
+ sampleRate: previewSampleRate,
148
146
  }));
149
147
  };
150
148
  const handleFileSource = async ({ method, remotionRoot, search, response, }) => {
@@ -167,88 +165,9 @@ const handleFileSource = async ({ method, remotionRoot, search, response, }) =>
167
165
  response.end();
168
166
  return Promise.resolve();
169
167
  };
170
- const handleOpenInEditor = async (remotionRoot, req, res, logLevel) => {
171
- if (req.method === 'OPTIONS') {
172
- res.statusCode = 200;
173
- res.end();
174
- return;
175
- }
176
- try {
177
- const body = (await (0, parse_body_1.parseRequestBody)(req));
178
- if (!('stack' in body)) {
179
- throw new TypeError('Need to pass stack');
180
- }
181
- const stack = body.stack;
182
- const guess = await editorGuess;
183
- const didOpen = await (0, open_in_editor_1.launchEditor)({
184
- colNumber: stack.originalColumnNumber,
185
- editor: guess[0],
186
- fileName: node_path_1.default.resolve(remotionRoot, stack.originalFileName),
187
- lineNumber: stack.originalLineNumber,
188
- vsCodeNewWindow: false,
189
- logLevel,
190
- });
191
- res.setHeader('content-type', 'application/json');
192
- res.writeHead(200);
193
- res.end(JSON.stringify({
194
- success: didOpen,
195
- }));
196
- }
197
- catch (_a) {
198
- res.setHeader('content-type', 'application/json');
199
- res.writeHead(200);
200
- res.end(JSON.stringify({
201
- success: false,
202
- }));
203
- }
204
- };
205
- const handleGetCompositionComponentInfo = async (remotionRoot, req, res) => {
206
- if (req.method === 'OPTIONS') {
207
- res.statusCode = 200;
208
- res.end();
209
- return;
210
- }
211
- res.setHeader('content-type', 'application/json');
212
- try {
213
- const body = (await (0, parse_body_1.parseRequestBody)(req));
214
- if (typeof body.compositionFile !== 'string') {
215
- throw new TypeError('Need to pass compositionFile');
216
- }
217
- if (typeof body.compositionId !== 'string') {
218
- throw new TypeError('Need to pass compositionId');
219
- }
220
- const location = await (0, resolve_composition_component_1.resolveCompositionComponent)({
221
- remotionRoot,
222
- compositionFile: body.compositionFile,
223
- compositionId: body.compositionId,
224
- });
225
- res.writeHead(200);
226
- res.end(JSON.stringify({
227
- success: true,
228
- location,
229
- canAddSequence: location.canAddSequence,
230
- }));
231
- }
232
- catch (err) {
233
- res.writeHead(200);
234
- res.end(JSON.stringify({
235
- success: false,
236
- error: err.message,
237
- }));
238
- }
239
- };
240
- const validateSameOrigin = (req) => {
241
- const { origin, host } = req.headers;
242
- if (origin) {
243
- const originUrl = new URL(origin);
244
- if (originUrl.host !== host) {
245
- throw new Error('Request from different origin not allowed');
246
- }
247
- }
248
- };
249
168
  const handleAddAsset = ({ req, res, search, publicDir, }) => {
250
169
  try {
251
- validateSameOrigin(req);
170
+ (0, validate_same_origin_1.validateSameOrigin)(req);
252
171
  const query = new node_url_1.URLSearchParams(search);
253
172
  const filePath = query.get('filePath');
254
173
  if (typeof filePath !== 'string') {
@@ -274,7 +193,7 @@ const handleAddAsset = ({ req, res, search, publicDir, }) => {
274
193
  };
275
194
  const handleUploadOutput = ({ req, res, search, remotionRoot, }) => {
276
195
  try {
277
- validateSameOrigin(req);
196
+ (0, validate_same_origin_1.validateSameOrigin)(req);
278
197
  const query = new node_url_1.URLSearchParams(search);
279
198
  const filePath = query.get('filePath');
280
199
  if (typeof filePath !== 'string') {
@@ -303,34 +222,6 @@ const handleUploadOutput = ({ req, res, search, remotionRoot, }) => {
303
222
  }
304
223
  return Promise.resolve();
305
224
  };
306
- const handleRegisterClientRender = async ({ req, res, remotionRoot, }) => {
307
- try {
308
- validateSameOrigin(req);
309
- const body = (await (0, parse_body_1.parseRequestBody)(req));
310
- (0, client_render_queue_1.addCompletedClientRender)({ render: body, remotionRoot });
311
- res.setHeader('content-type', 'application/json');
312
- res.writeHead(200);
313
- res.end(JSON.stringify({ success: true }));
314
- }
315
- catch (err) {
316
- res.statusCode = 500;
317
- res.end(JSON.stringify({ error: err.message }));
318
- }
319
- };
320
- const handleUnregisterClientRender = async ({ req, res, }) => {
321
- try {
322
- validateSameOrigin(req);
323
- const body = (await (0, parse_body_1.parseRequestBody)(req));
324
- (0, client_render_queue_1.removeCompletedClientRender)(body.id);
325
- res.setHeader('content-type', 'application/json');
326
- res.writeHead(200);
327
- res.end(JSON.stringify({ success: true }));
328
- }
329
- catch (err) {
330
- res.statusCode = 500;
331
- res.end(JSON.stringify({ error: err.message }));
332
- }
333
- };
334
225
  const handleFavicon = (_, response) => {
335
226
  const filePath = node_path_1.default.join(__dirname, '..', 'web', 'favicon.png');
336
227
  const stat = (0, node_fs_1.statSync)(filePath);
@@ -353,7 +244,7 @@ const handleBeep = (_, response) => {
353
244
  readStream.pipe(response);
354
245
  return Promise.resolve();
355
246
  };
356
- const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, numberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, audioLatencyHint, enableCrossSiteIsolation, }) => {
247
+ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPrefix, request, response, liveEventsServer, getCurrentInputProps, getEnvVariables, remotionRoot, entryPoint, publicDir, logLevel, getRenderQueue, getRenderDefaults, numberOfAudioTags, queueMethods: methods, gitSource, binariesDirectory, audioLatencyHint, previewSampleRate, enableCrossSiteIsolation, }) => {
357
248
  const url = new URL(request.url, 'http://localhost');
358
249
  if (url.pathname === '/api/file-source') {
359
250
  return handleFileSource({
@@ -363,12 +254,6 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
363
254
  response,
364
255
  });
365
256
  }
366
- if (url.pathname === '/api/open-in-editor') {
367
- return handleOpenInEditor(remotionRoot, request, response, logLevel);
368
- }
369
- if (url.pathname === '/api/composition-component-info') {
370
- return handleGetCompositionComponentInfo(remotionRoot, request, response);
371
- }
372
257
  if (url.pathname === `${staticHash}/api/add-asset`) {
373
258
  return handleAddAsset({
374
259
  req: request,
@@ -385,19 +270,6 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
385
270
  remotionRoot,
386
271
  });
387
272
  }
388
- if (url.pathname === '/api/register-client-render') {
389
- return handleRegisterClientRender({
390
- req: request,
391
- res: response,
392
- remotionRoot,
393
- });
394
- }
395
- if (url.pathname === '/api/unregister-client-render') {
396
- return handleUnregisterClientRender({
397
- req: request,
398
- res: response,
399
- });
400
- }
401
273
  for (const [key, value] of Object.entries(api_routes_1.allApiRoutes)) {
402
274
  if (url.pathname === key) {
403
275
  return (0, handler_1.handleRequest)({
@@ -467,6 +339,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
467
339
  gitSource,
468
340
  logLevel,
469
341
  audioLatencyHint,
342
+ previewSampleRate,
470
343
  enableCrossSiteIsolation,
471
344
  });
472
345
  };
@@ -6,7 +6,7 @@ export type StartStudioResult = {
6
6
  } | {
7
7
  type: 'already-running';
8
8
  };
9
- export declare const startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, maxTimelineTracks, remotionRoot, keyboardShortcutsEnabled, experimentalClientSideRenderingEnabled, relativePublicDir, webpackOverride, poll, getRenderDefaults, getRenderQueue, numberOfAudioTags, queueMethods, previewEntry, gitSource, bufferStateDelayInMilliseconds, binariesDirectory, forceIPv4, audioLatencyHint, enableCrossSiteIsolation, askAIEnabled, forceNew, rspack, }: {
9
+ export declare const startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, maxTimelineTracks, remotionRoot, keyboardShortcutsEnabled, experimentalClientSideRenderingEnabled, relativePublicDir, webpackOverride, poll, getRenderDefaults, getRenderQueue, numberOfAudioTags, queueMethods, previewEntry, gitSource, bufferStateDelayInMilliseconds, binariesDirectory, forceIPv4, audioLatencyHint, previewSampleRate, enableCrossSiteIsolation, askAIEnabled, forceNew, rspack, }: {
10
10
  browserArgs: string;
11
11
  browserFlag: string;
12
12
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
@@ -27,6 +27,7 @@ export declare const startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser
27
27
  getRenderQueue: () => RenderJob[];
28
28
  numberOfAudioTags: number;
29
29
  audioLatencyHint: AudioContextLatencyCategory | null;
30
+ previewSampleRate: number | null;
30
31
  enableCrossSiteIsolation: boolean;
31
32
  queueMethods: QueueMethods;
32
33
  previewEntry: string;
@@ -18,7 +18,7 @@ const public_folder_1 = require("./preview-server/public-folder");
18
18
  const start_server_1 = require("./preview-server/start-server");
19
19
  const server_ready_1 = require("./server-ready");
20
20
  const watch_root_file_1 = require("./watch-root-file");
21
- const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, maxTimelineTracks, remotionRoot, keyboardShortcutsEnabled, experimentalClientSideRenderingEnabled, relativePublicDir, webpackOverride, poll, getRenderDefaults, getRenderQueue, numberOfAudioTags, queueMethods, previewEntry, gitSource, bufferStateDelayInMilliseconds, binariesDirectory, forceIPv4, audioLatencyHint, enableCrossSiteIsolation, askAIEnabled, forceNew, rspack, }) => {
21
+ const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, maxTimelineTracks, remotionRoot, keyboardShortcutsEnabled, experimentalClientSideRenderingEnabled, relativePublicDir, webpackOverride, poll, getRenderDefaults, getRenderQueue, numberOfAudioTags, queueMethods, previewEntry, gitSource, bufferStateDelayInMilliseconds, binariesDirectory, forceIPv4, audioLatencyHint, previewSampleRate, enableCrossSiteIsolation, askAIEnabled, forceNew, rspack, }) => {
22
22
  try {
23
23
  if (typeof Bun === 'undefined') {
24
24
  process.title = 'node (npx remotion studio)';
@@ -89,6 +89,7 @@ const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEn
89
89
  binariesDirectory,
90
90
  forceIPv4,
91
91
  audioLatencyHint,
92
+ previewSampleRate,
92
93
  enableCrossSiteIsolation,
93
94
  askAIEnabled,
94
95
  forceNew,
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.469",
6
+ "version": "4.0.471",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -27,11 +27,11 @@
27
27
  "@babel/parser": "7.24.1",
28
28
  "semver": "7.5.3",
29
29
  "prettier": "3.8.1",
30
- "remotion": "4.0.469",
30
+ "remotion": "4.0.471",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.469",
33
- "@remotion/renderer": "4.0.469",
34
- "@remotion/studio-shared": "4.0.469",
32
+ "@remotion/bundler": "4.0.471",
33
+ "@remotion/renderer": "4.0.471",
34
+ "@remotion/studio-shared": "4.0.471",
35
35
  "memfs": "3.4.3",
36
36
  "open": "8.4.2"
37
37
  },
@@ -39,7 +39,7 @@
39
39
  "ast-types": "0.16.1",
40
40
  "react": "19.2.3",
41
41
  "@types/semver": "7.5.3",
42
- "@remotion/eslint-config-internal": "4.0.469",
42
+ "@remotion/eslint-config-internal": "4.0.471",
43
43
  "eslint": "9.19.0",
44
44
  "@types/node": "20.12.14",
45
45
  "@typescript/native-preview": "7.0.0-dev.20260217.1"