@remotion/studio-server 4.0.538 → 4.0.540

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,3 +1,4 @@
1
+ import type { SourceFileVersion } from '@remotion/studio-shared';
1
2
  export type FileChangeMetadata = {
2
3
  skipSequencePropsUpdate: boolean;
3
4
  };
@@ -11,6 +12,7 @@ export type FileChangeEvent = {
11
12
  type: 'created';
12
13
  content: string;
13
14
  originatorClientId: string | undefined;
15
+ sourceVersion: SourceFileVersion | null;
14
16
  } | {
15
17
  type: 'deleted';
16
18
  } | {
@@ -18,9 +20,11 @@ export type FileChangeEvent = {
18
20
  content: string;
19
21
  originatorClientId: string | undefined;
20
22
  skipSequencePropsUpdate: boolean;
23
+ sourceVersion: SourceFileVersion | null;
21
24
  };
22
25
  type OnChange = (event: FileChangeEvent) => void;
23
26
  export type FileWatcherRegistry = {
27
+ readonly sourceVersionSessionId: string;
24
28
  installFileWatcher: (options: {
25
29
  file: string;
26
30
  onChange: OnChange;
@@ -35,9 +39,10 @@ export type FileWatcherRegistry = {
35
39
  exists: boolean;
36
40
  unwatch: () => void;
37
41
  };
38
- writeFileAndNotifyFileWatchers: (options: WriteFileAndNotifyFileWatchersOptions) => void;
42
+ writeFileAndNotifyFileWatchers: (options: WriteFileAndNotifyFileWatchersOptions) => SourceFileVersion | null;
39
43
  };
40
44
  export declare const createFileWatcherRegistry: () => FileWatcherRegistry;
45
+ export declare const getSourceVersionSessionId: () => string | null;
41
46
  export declare const setFileWatcherRegistry: (registry: FileWatcherRegistry) => (() => void);
42
47
  export declare const getFileWatcherRegistry: () => FileWatcherRegistry;
43
48
  export declare const installFileWatcher: FileWatcherRegistry['installFileWatcher'];
@@ -33,12 +33,19 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.writeFileAndNotifyFileWatchers = exports.installFileWatcher = exports.getFileWatcherRegistry = exports.setFileWatcherRegistry = exports.createFileWatcherRegistry = void 0;
36
+ exports.writeFileAndNotifyFileWatchers = exports.installFileWatcher = exports.getFileWatcherRegistry = exports.setFileWatcherRegistry = exports.getSourceVersionSessionId = exports.createFileWatcherRegistry = void 0;
37
+ const node_crypto_1 = require("node:crypto");
37
38
  const node_fs_1 = __importStar(require("node:fs"));
38
39
  const watch_ignore_next_change_1 = require("./preview-server/watch-ignore-next-change");
39
40
  const getRegistryKey = (file, existenceOnly) => existenceOnly ? `${file}\0existence-only` : file;
40
41
  const createFileWatcherRegistry = () => {
41
42
  const sharedWatchers = new Map();
43
+ const sessionId = (0, node_crypto_1.randomUUID)();
44
+ let revision = 0;
45
+ const nextSourceVersion = () => ({
46
+ sessionId,
47
+ revision: ++revision,
48
+ });
42
49
  const _installFileWatcher = ({ file, onChange, existenceOnly, }) => {
43
50
  const registryKey = getRegistryKey(file, existenceOnly);
44
51
  const existing = sharedWatchers.get(registryKey);
@@ -74,6 +81,7 @@ const createFileWatcherRegistry = () => {
74
81
  type: 'created',
75
82
  content: '',
76
83
  originatorClientId: undefined,
84
+ sourceVersion: null,
77
85
  };
78
86
  }
79
87
  else if (shared.existedBefore && !existsNow) {
@@ -85,7 +93,12 @@ const createFileWatcherRegistry = () => {
85
93
  const content = (0, node_fs_1.readFileSync)(file, 'utf-8');
86
94
  shared.existedBefore = true;
87
95
  shared.lastKnownContent = content;
88
- event = { type: 'created', content, originatorClientId: undefined };
96
+ event = {
97
+ type: 'created',
98
+ content,
99
+ originatorClientId: undefined,
100
+ sourceVersion: nextSourceVersion(),
101
+ };
89
102
  }
90
103
  else if (shared.existedBefore && !existsNow) {
91
104
  shared.existedBefore = false;
@@ -107,6 +120,7 @@ const createFileWatcherRegistry = () => {
107
120
  content,
108
121
  originatorClientId: undefined,
109
122
  skipSequencePropsUpdate: false,
123
+ sourceVersion: nextSourceVersion(),
110
124
  };
111
125
  }
112
126
  if (!event) {
@@ -133,9 +147,10 @@ const createFileWatcherRegistry = () => {
133
147
  var _a;
134
148
  (0, watch_ignore_next_change_1.prepareBundlerForFileWrite)(file);
135
149
  (0, node_fs_1.writeFileSync)(file, content);
150
+ const sourceVersion = nextSourceVersion();
136
151
  const shared = sharedWatchers.get(getRegistryKey(file, false));
137
152
  if (!shared) {
138
- return;
153
+ return sourceVersion;
139
154
  }
140
155
  shared.lastKnownContent = content;
141
156
  shared.existedBefore = true;
@@ -145,16 +160,21 @@ const createFileWatcherRegistry = () => {
145
160
  content,
146
161
  originatorClientId,
147
162
  skipSequencePropsUpdate: (_a = metadata === null || metadata === void 0 ? void 0 : metadata.skipSequencePropsUpdate) !== null && _a !== void 0 ? _a : false,
163
+ sourceVersion,
148
164
  });
149
165
  }
166
+ return sourceVersion;
150
167
  };
151
168
  return {
169
+ sourceVersionSessionId: sessionId,
152
170
  installFileWatcher: _installFileWatcher,
153
171
  writeFileAndNotifyFileWatchers: _writeFileAndNotifyFileWatchers,
154
172
  };
155
173
  };
156
174
  exports.createFileWatcherRegistry = createFileWatcherRegistry;
157
175
  let currentRegistry = null;
176
+ const getSourceVersionSessionId = () => { var _a; return (_a = currentRegistry === null || currentRegistry === void 0 ? void 0 : currentRegistry.sourceVersionSessionId) !== null && _a !== void 0 ? _a : null; };
177
+ exports.getSourceVersionSessionId = getSourceVersionSessionId;
158
178
  const setFileWatcherRegistry = (registry) => {
159
179
  currentRegistry = registry;
160
180
  return () => {
@@ -181,8 +201,8 @@ const installFileWatcher = (options) => {
181
201
  exports.installFileWatcher = installFileWatcher;
182
202
  const writeFileAndNotifyFileWatchers = (options) => {
183
203
  if (!currentRegistry) {
184
- return;
204
+ return null;
185
205
  }
186
- (0, exports.getFileWatcherRegistry)().writeFileAndNotifyFileWatchers(options);
206
+ return (0, exports.getFileWatcherRegistry)().writeFileAndNotifyFileWatchers(options);
187
207
  };
188
208
  exports.writeFileAndNotifyFileWatchers = writeFileAndNotifyFileWatchers;
package/dist/index.d.ts CHANGED
@@ -48,7 +48,7 @@ export declare const StudioServerInternals: {
48
48
  content: string;
49
49
  originatorClientId: string | undefined;
50
50
  metadata: import("./file-watcher").FileChangeMetadata | null;
51
- }) => void;
51
+ }) => import("@remotion/studio-shared").SourceFileVersion | null;
52
52
  createFileWatcherRegistry: typeof createFileWatcherRegistry;
53
53
  setFileWatcherRegistry: typeof setFileWatcherRegistry;
54
54
  AnsiDiff: typeof AnsiDiff;
@@ -69,6 +69,6 @@ export declare const StudioServerInternals: {
69
69
  removeCompletedClientRender: typeof removeCompletedClientRender;
70
70
  detectOutdatedRemotionSkills: typeof detectOutdatedRemotionSkills;
71
71
  parseRemotionSkillVersion: typeof parseRemotionSkillVersion;
72
- remotionSkillNames: readonly ["remotion-best-practices", "remotion-captions", "remotion-create", "remotion-docs", "remotion-interactivity", "remotion-maps", "remotion-markup", "remotion-multimedia", "remotion-render", "remotion-saas", "remotion-studio", "remotion-upgrade"];
72
+ remotionSkillNames: readonly ["remotion-best-practices", "remotion-captions", "remotion-create", "remotion-docs", "remotion-interactivity", "remotion-license", "remotion-maps", "remotion-markup", "remotion-multimedia", "remotion-render", "remotion-saas", "remotion-studio", "remotion-upgrade"];
73
73
  getEditorName: typeof getEditorName;
74
74
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setLiveEventsListener = exports.getLiveEventsListener = exports.waitForLiveEventsListener = exports.makeLiveEventsRouter = exports.clearPrintPortMessageTimeout = exports.subscribeToConfigChanges = void 0;
4
+ const file_watcher_1 = require("../file-watcher");
4
5
  const server_ready_1 = require("../server-ready");
5
6
  const default_props_watchers_1 = require("./default-props-watchers");
6
7
  const file_existence_watchers_1 = require("./file-existence-watchers");
@@ -41,7 +42,13 @@ const makeLiveEventsRouter = (logLevel, getInitialUndoRedoState) => {
41
42
  }
42
43
  const clientId = String(Math.random());
43
44
  const { undoFile, redoFile } = getInitialUndoRedoState();
44
- response.write(serializeMessage({ type: 'init', clientId, undoFile, redoFile }));
45
+ response.write(serializeMessage({
46
+ type: 'init',
47
+ clientId,
48
+ undoFile,
49
+ redoFile,
50
+ sourceVersionSessionId: (0, file_watcher_1.getSourceVersionSessionId)(),
51
+ }));
45
52
  const newClient = {
46
53
  id: clientId,
47
54
  response,
@@ -58,6 +58,7 @@ const handleAddRender = ({ input, entryPoint, remotionRoot, logLevel, binariesDi
58
58
  chromeMode: input.chromeMode,
59
59
  offthreadVideoThreads: input.offthreadVideoThreads,
60
60
  mediaCacheSizeInBytes: input.mediaCacheSizeInBytes,
61
+ preferredEffectBackend: input.preferredEffectBackend,
61
62
  sampleRate: input.sampleRate,
62
63
  licenseKey: input.licenseKey,
63
64
  },
@@ -98,6 +99,8 @@ const handleAddRender = ({ input, entryPoint, remotionRoot, logLevel, binariesDi
98
99
  chromeMode: input.chromeMode,
99
100
  offthreadVideoThreads: input.offthreadVideoThreads,
100
101
  mediaCacheSizeInBytes: input.mediaCacheSizeInBytes,
102
+ preferredEffectBackend: input.preferredEffectBackend,
103
+ licenseKey: input.licenseKey,
101
104
  },
102
105
  logLevel,
103
106
  });
@@ -132,6 +135,7 @@ const handleAddRender = ({ input, entryPoint, remotionRoot, logLevel, binariesDi
132
135
  chromeMode: input.chromeMode,
133
136
  offthreadVideoThreads: input.offthreadVideoThreads,
134
137
  mediaCacheSizeInBytes: input.mediaCacheSizeInBytes,
138
+ preferredEffectBackend: input.preferredEffectBackend,
135
139
  licenseKey: input.licenseKey,
136
140
  },
137
141
  entryPoint,
@@ -1,5 +1,5 @@
1
1
  import type { LogLevel } from '@remotion/renderer';
2
- import type { DeleteEffectKeyframe, DeleteKeyframesRequest, DeleteKeyframesResponse, DeleteSequenceKeyframe } from '@remotion/studio-shared';
2
+ import type { DeleteEffectKeyframe, DeleteKeyframesRequest, DeleteKeyframesResponse, KeyframeMutationResult, DeleteSequenceKeyframe } from '@remotion/studio-shared';
3
3
  import type { ApiHandler } from '../api-types';
4
4
  export declare const deleteKeyframes: ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }: {
5
5
  sequenceKeyframes: DeleteSequenceKeyframe[];
@@ -7,5 +7,5 @@ export declare const deleteKeyframes: ({ sequenceKeyframes, effectKeyframes, cli
7
7
  clientId: string;
8
8
  remotionRoot: string;
9
9
  logLevel: LogLevel;
10
- }) => Promise<void>;
10
+ }) => Promise<KeyframeMutationResult[]>;
11
11
  export declare const deleteKeyframesHandler: ApiHandler<DeleteKeyframesRequest, DeleteKeyframesResponse>;
@@ -8,6 +8,7 @@ const file_watcher_1 = require("../../file-watcher");
8
8
  const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
9
9
  const undo_stack_1 = require("../undo-stack");
10
10
  const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
11
+ const get_keyframe_mutation_results_1 = require("./get-keyframe-mutation-results");
11
12
  const log_effect_update_1 = require("./log-updates/log-effect-update");
12
13
  const log_update_1 = require("./log-updates/log-update");
13
14
  const source_file_write_queue_1 = require("./source-file-write-queue");
@@ -35,7 +36,7 @@ const getBatchDescription = ({ totalKeyframes, firstKeyframe, }) => {
35
36
  };
36
37
  };
37
38
  const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }) => {
38
- var _a, _b;
39
+ var _a, _b, _c;
39
40
  const totalKeyframes = sequenceKeyframes.length + effectKeyframes.length;
40
41
  if (totalKeyframes === 0) {
41
42
  throw new Error('No keyframes were specified for deletion');
@@ -67,6 +68,8 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
67
68
  group.effectKeyframes.push({ ...keyframe, fileRelativeToRoot });
68
69
  fileGroups.set(absolutePath, group);
69
70
  }
71
+ const results = [];
72
+ const resultsByFile = new Map();
70
73
  const snapshots = [];
71
74
  const sequenceLogs = [];
72
75
  const effectLogs = [];
@@ -74,6 +77,7 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
74
77
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
75
78
  let output = fileContents;
76
79
  let firstLogLine = Number.POSITIVE_INFINITY;
80
+ const targets = [];
77
81
  for (const keyframeGroup of groupBy(group.sequenceKeyframes, (keyframe) => JSON.stringify(keyframe.nodePath.nodePath))) {
78
82
  const [firstSequenceKeyframe] = keyframeGroup;
79
83
  if (!firstSequenceKeyframe) {
@@ -97,6 +101,15 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
97
101
  }),
98
102
  });
99
103
  output = result.output;
104
+ targets.push({
105
+ nodePath: {
106
+ ...firstSequenceKeyframe.nodePath,
107
+ absolutePath,
108
+ nodePath: result.updatedNode.nodePath,
109
+ },
110
+ effectIndex: null,
111
+ keys: [...new Set(keyframeGroup.map((keyframe) => keyframe.key))],
112
+ });
100
113
  firstLogLine = Math.min(firstLogLine, result.logLine);
101
114
  for (const [keyframeIndex, keyframe] of keyframeGroup.entries()) {
102
115
  sequenceLogs.push({
@@ -133,6 +146,15 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
133
146
  }),
134
147
  });
135
148
  output = result.output;
149
+ targets.push({
150
+ nodePath: {
151
+ ...firstEffectKeyframe.sequenceNodePath,
152
+ absolutePath,
153
+ nodePath: result.updatedEffect.nodePath,
154
+ },
155
+ effectIndex: firstEffectKeyframe.effectIndex,
156
+ keys: [...new Set(keyframeGroup.map((keyframe) => keyframe.key))],
157
+ });
136
158
  firstLogLine = Math.min(firstLogLine, result.logLine);
137
159
  for (const [keyframeIndex, keyframe] of keyframeGroup.entries()) {
138
160
  effectLogs.push({
@@ -146,6 +168,12 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
146
168
  });
147
169
  }
148
170
  }
171
+ const fileResults = (0, get_keyframe_mutation_results_1.getKeyframeMutationResults)({
172
+ fileContents: output,
173
+ targets,
174
+ });
175
+ results.push(...fileResults);
176
+ resultsByFile.set(absolutePath, fileResults);
149
177
  snapshots.push({
150
178
  filePath: absolutePath,
151
179
  oldContents: fileContents,
@@ -176,12 +204,15 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
176
204
  for (const snapshot of snapshots) {
177
205
  (0, undo_stack_1.suppressUndoStackInvalidation)(snapshot.filePath);
178
206
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
179
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
207
+ const sourceVersion = (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
180
208
  file: snapshot.filePath,
181
209
  content: snapshot.newContents,
182
210
  originatorClientId: clientId,
183
211
  metadata: null,
184
212
  });
213
+ for (const result of (_c = resultsByFile.get(snapshot.filePath)) !== null && _c !== void 0 ? _c : []) {
214
+ result.sourceVersion = sourceVersion;
215
+ }
185
216
  }
186
217
  for (const log of sequenceLogs) {
187
218
  (0, log_update_1.logUpdate)({
@@ -213,17 +244,18 @@ const deleteKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, r
213
244
  });
214
245
  }
215
246
  (0, undo_stack_1.printUndoHint)(logLevel);
247
+ return results;
216
248
  };
217
249
  exports.deleteKeyframes = deleteKeyframes;
218
250
  const deleteKeyframesHandler = ({ input: { sequenceKeyframes, effectKeyframes, clientId }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
219
251
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[delete-keyframes] Received request to delete ${sequenceKeyframes.length + effectKeyframes.length} keyframe(s)`);
220
- await (0, exports.deleteKeyframes)({
252
+ const results = await (0, exports.deleteKeyframes)({
221
253
  sequenceKeyframes,
222
254
  effectKeyframes,
223
255
  clientId,
224
256
  remotionRoot,
225
257
  logLevel,
226
258
  });
227
- return { success: true };
259
+ return { success: true, results };
228
260
  });
229
261
  exports.deleteKeyframesHandler = deleteKeyframesHandler;
@@ -58,6 +58,7 @@ const duplicateNodesHandler = ({ input: { nodes }, remotionRoot, logLevel }) =>
58
58
  logLine: Math.min(...logLines),
59
59
  nodeLabels,
60
60
  nodePathRemappings,
61
+ duplicatedNodes: result.duplicatedNodes.map(({ filePath, nodePath }) => ({ absolutePath: filePath, nodePath })),
61
62
  output,
62
63
  };
63
64
  }));
@@ -109,6 +110,7 @@ const duplicateNodesHandler = ({ input: { nodes }, remotionRoot, logLevel }) =>
109
110
  return {
110
111
  success: true,
111
112
  nodePathMutation,
113
+ duplicatedNodes: updates.flatMap((update) => update.duplicatedNodes),
112
114
  };
113
115
  }
114
116
  catch (err) {
@@ -0,0 +1,7 @@
1
+ import type { KeyframeMutationResult } from '@remotion/studio-shared';
2
+ export declare const getKeyframeMutationResults: ({ fileContents, targets, }: {
3
+ fileContents: string;
4
+ targets: readonly (Pick<KeyframeMutationResult, 'nodePath' | 'effectIndex'> & {
5
+ keys: string[];
6
+ })[];
7
+ }) => KeyframeMutationResult[];
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getKeyframeMutationResults = void 0;
4
+ const codemods_1 = require("@remotion/codemods");
5
+ const getKeyframeMutationResults = ({ fileContents, targets, }) => {
6
+ return targets.map(({ nodePath, effectIndex, keys }) => {
7
+ const status = (0, codemods_1.getNodeProps)({
8
+ project: { rootDir: '/', files: { 'source.tsx': fileContents } },
9
+ node: { filePath: 'source.tsx', nodePath: nodePath.nodePath },
10
+ componentIdentity: null,
11
+ keys: effectIndex === null ? keys : [],
12
+ effectKeys: effectIndex === null
13
+ ? []
14
+ : Array.from({ length: effectIndex + 1 }, (_, index) => index === effectIndex ? keys : []),
15
+ });
16
+ if (effectIndex === null)
17
+ return { nodePath, effectIndex, props: status.props, sourceVersion: null };
18
+ const effect = status.effects[effectIndex];
19
+ if (!(effect === null || effect === void 0 ? void 0 : effect.canUpdate))
20
+ throw new Error('Could not read the updated effect keyframes');
21
+ return { nodePath, effectIndex, props: effect.props, sourceVersion: null };
22
+ });
23
+ };
24
+ exports.getKeyframeMutationResults = getKeyframeMutationResults;
@@ -1,8 +1,8 @@
1
1
  import type { LogLevel } from '@remotion/renderer';
2
- import type { MoveKeyframesRequest, MoveKeyframesResponse } from '@remotion/studio-shared';
2
+ import type { MoveKeyframesRequest, MoveKeyframesResponse, KeyframeMutationResult } from '@remotion/studio-shared';
3
3
  import type { ApiHandler } from '../api-types';
4
4
  export declare const moveKeyframes: ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }: MoveKeyframesRequest & {
5
5
  remotionRoot: string;
6
6
  logLevel: LogLevel;
7
- }) => Promise<void>;
7
+ }) => Promise<KeyframeMutationResult[]>;
8
8
  export declare const moveKeyframesHandler: ApiHandler<MoveKeyframesRequest, MoveKeyframesResponse>;
@@ -8,6 +8,7 @@ const file_watcher_1 = require("../../file-watcher");
8
8
  const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
9
9
  const undo_stack_1 = require("../undo-stack");
10
10
  const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
11
+ const get_keyframe_mutation_results_1 = require("./get-keyframe-mutation-results");
11
12
  const log_effect_update_1 = require("./log-updates/log-effect-update");
12
13
  const log_update_1 = require("./log-updates/log-update");
13
14
  const source_file_write_queue_1 = require("./source-file-write-queue");
@@ -35,7 +36,7 @@ const getBatchDescription = ({ totalKeyframes, firstKeyframe, }) => {
35
36
  };
36
37
  };
37
38
  const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }) => {
38
- var _a, _b;
39
+ var _a, _b, _c;
39
40
  const totalKeyframes = sequenceKeyframes.length + effectKeyframes.length;
40
41
  if (totalKeyframes === 0) {
41
42
  throw new Error('No keyframes were specified for moving');
@@ -79,6 +80,8 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
79
80
  });
80
81
  fileGroups.set(absolutePath, group);
81
82
  }
83
+ const results = [];
84
+ const resultsByFile = new Map();
82
85
  const snapshots = [];
83
86
  const sequenceLogs = [];
84
87
  const effectLogs = [];
@@ -86,6 +89,7 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
86
89
  const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
87
90
  let output = fileContents;
88
91
  let firstLogLine = Number.POSITIVE_INFINITY;
92
+ const targets = [];
89
93
  for (const keyframeGroup of groupBy(group.sequenceKeyframes, (keyframe) => JSON.stringify(keyframe.nodePath.nodePath))) {
90
94
  const [firstSequenceKeyframe] = keyframeGroup;
91
95
  if (!firstSequenceKeyframe) {
@@ -115,6 +119,15 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
115
119
  updates,
116
120
  });
117
121
  output = result.output;
122
+ targets.push({
123
+ nodePath: {
124
+ ...firstSequenceKeyframe.nodePath,
125
+ absolutePath,
126
+ nodePath: result.updatedNode.nodePath,
127
+ },
128
+ effectIndex: null,
129
+ keys: [...new Set(keyframeGroup.map((keyframe) => keyframe.key))],
130
+ });
118
131
  firstLogLine = Math.min(firstLogLine, result.logLine);
119
132
  for (const [updateIndex, update] of updates.entries()) {
120
133
  sequenceLogs.push({
@@ -157,6 +170,15 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
157
170
  updates,
158
171
  });
159
172
  output = result.output;
173
+ targets.push({
174
+ nodePath: {
175
+ ...firstEffectKeyframe.sequenceNodePath,
176
+ absolutePath,
177
+ nodePath: result.updatedEffect.nodePath,
178
+ },
179
+ effectIndex: firstEffectKeyframe.effectIndex,
180
+ keys: [...new Set(keyframeGroup.map((keyframe) => keyframe.key))],
181
+ });
160
182
  firstLogLine = Math.min(firstLogLine, result.logLine);
161
183
  for (const [updateIndex, update] of updates.entries()) {
162
184
  effectLogs.push({
@@ -170,6 +192,12 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
170
192
  });
171
193
  }
172
194
  }
195
+ const fileResults = (0, get_keyframe_mutation_results_1.getKeyframeMutationResults)({
196
+ fileContents: output,
197
+ targets,
198
+ });
199
+ results.push(...fileResults);
200
+ resultsByFile.set(absolutePath, fileResults);
173
201
  snapshots.push({
174
202
  filePath: absolutePath,
175
203
  oldContents: fileContents,
@@ -200,12 +228,15 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
200
228
  for (const snapshot of snapshots) {
201
229
  (0, undo_stack_1.suppressUndoStackInvalidation)(snapshot.filePath);
202
230
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
203
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
231
+ const sourceVersion = (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
204
232
  file: snapshot.filePath,
205
233
  content: snapshot.newContents,
206
234
  originatorClientId: clientId,
207
235
  metadata: null,
208
236
  });
237
+ for (const result of (_c = resultsByFile.get(snapshot.filePath)) !== null && _c !== void 0 ? _c : []) {
238
+ result.sourceVersion = sourceVersion;
239
+ }
209
240
  }
210
241
  for (const log of sequenceLogs) {
211
242
  (0, log_update_1.logUpdate)({
@@ -237,17 +268,18 @@ const moveKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, rem
237
268
  });
238
269
  }
239
270
  (0, undo_stack_1.printUndoHint)(logLevel);
271
+ return results;
240
272
  };
241
273
  exports.moveKeyframes = moveKeyframes;
242
274
  const moveKeyframesHandler = ({ input: { sequenceKeyframes, effectKeyframes, clientId }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
243
275
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[move-keyframes] Received request to move ${sequenceKeyframes.length + effectKeyframes.length} keyframe(s)`);
244
- await (0, exports.moveKeyframes)({
276
+ const results = await (0, exports.moveKeyframes)({
245
277
  sequenceKeyframes,
246
278
  effectKeyframes,
247
279
  clientId,
248
280
  remotionRoot,
249
281
  logLevel,
250
282
  });
251
- return { success: true };
283
+ return { success: true, results };
252
284
  });
253
285
  exports.moveKeyframesHandler = moveKeyframesHandler;
@@ -10,7 +10,7 @@ const format_log_file_location_1 = require("../format-log-file-location");
10
10
  const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
11
11
  const undo_stack_1 = require("../undo-stack");
12
12
  const source_file_write_queue_1 = require("./source-file-write-queue");
13
- const precomposeJsxNodesHandler = ({ input: { nodes, dryRun, compositionFile, compositionId, metadata, existingCompositionIds, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(() => {
13
+ const precomposeJsxNodesHandler = ({ input: { nodes, dryRun, compositionFile, compositionId, metadata, existingCompositionIds, name, }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(() => {
14
14
  var _a;
15
15
  const attemptedWrites = [];
16
16
  let undoEntryPushed = false;
@@ -54,16 +54,8 @@ const precomposeJsxNodesHandler = ({ input: { nodes, dryRun, compositionFile, co
54
54
  compositionId,
55
55
  metadata,
56
56
  existingCompositionIds,
57
+ name,
57
58
  };
58
- if (dryRun) {
59
- const eligibility = (0, codemods_1.canPrecomposeJsxNodes)(codemodInput);
60
- return Promise.resolve({
61
- success: true,
62
- ...eligibility,
63
- nodePathMutation: null,
64
- newCompositionId: null,
65
- });
66
- }
67
59
  let result;
68
60
  try {
69
61
  result = (0, codemods_1.precomposeJsxNodes)(codemodInput);
@@ -73,10 +65,21 @@ const precomposeJsxNodesHandler = ({ input: { nodes, dryRun, compositionFile, co
73
65
  success: true,
74
66
  canPrecompose: false,
75
67
  reason: error instanceof Error ? error.message : String(error),
68
+ invalidName: error instanceof Error && error.name === 'PrecomposeNameError',
76
69
  nodePathMutation: null,
77
70
  newCompositionId: null,
78
71
  });
79
72
  }
73
+ if (dryRun) {
74
+ return Promise.resolve({
75
+ success: true,
76
+ canPrecompose: true,
77
+ reason: null,
78
+ invalidName: false,
79
+ nodePathMutation: null,
80
+ newCompositionId: result.newCompositionId,
81
+ });
82
+ }
80
83
  const changes = [...result.changes].sort((a, b) => Number(b.filePath === absolutePath) -
81
84
  Number(a.filePath === absolutePath));
82
85
  if (!changes.some(({ filePath }) => filePath === absolutePath) ||
@@ -172,6 +175,7 @@ const precomposeJsxNodesHandler = ({ input: { nodes, dryRun, compositionFile, co
172
175
  success: true,
173
176
  canPrecompose: true,
174
177
  reason: null,
178
+ invalidName: false,
175
179
  nodePathMutation,
176
180
  newCompositionId: result.newCompositionId,
177
181
  });
@@ -60,6 +60,10 @@ const splitSequencesHandler = ({ input: { sequences }, remotionRoot, logLevel })
60
60
  nodeLabels,
61
61
  nodePathRemappings,
62
62
  output,
63
+ splitNodes: result.insertedNodes.map(({ filePath, nodePath }) => ({
64
+ absolutePath: filePath,
65
+ nodePath,
66
+ })),
63
67
  };
64
68
  }));
65
69
  const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)(updates.map((update) => ({
@@ -87,14 +91,16 @@ const splitSequencesHandler = ({ input: { sequences }, remotionRoot, logLevel })
87
91
  suppressHmrOnFileRestore: false,
88
92
  undoRedoNavigation: null,
89
93
  });
94
+ const sourceVersions = [];
90
95
  for (const update of updates) {
91
96
  (0, undo_stack_1.suppressUndoStackInvalidation)(update.absolutePath);
92
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
97
+ const sourceVersion = (0, file_watcher_1.writeFileAndNotifyFileWatchers)({
93
98
  file: update.absolutePath,
94
99
  content: update.output,
95
100
  originatorClientId: undefined,
96
101
  metadata: { skipSequencePropsUpdate: true },
97
102
  });
103
+ sourceVersions.push({ absolutePath: update.absolutePath, sourceVersion });
98
104
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
99
105
  remotionRoot,
100
106
  absolutePath: update.absolutePath,
@@ -110,6 +116,8 @@ const splitSequencesHandler = ({ input: { sequences }, remotionRoot, logLevel })
110
116
  return {
111
117
  success: true,
112
118
  nodePathMutation,
119
+ splitNodes: updates.flatMap((update) => update.splitNodes),
120
+ sourceVersions,
113
121
  };
114
122
  }
115
123
  catch (err) {
@@ -181,9 +181,10 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
181
181
  return;
182
182
  }
183
183
  try {
184
+ const sourceNodePath = watcherInfo.currentNodePath;
184
185
  const result = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
185
186
  fileContents: event.content,
186
- nodePath: watcherInfo.currentNodePath.nodePath,
187
+ nodePath: sourceNodePath.nodePath,
187
188
  componentIdentity,
188
189
  keys,
189
190
  assetKeys,
@@ -200,7 +201,8 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
200
201
  listener.sendEventToClientId(clientId, {
201
202
  type: 'sequence-props-updated',
202
203
  fileName,
203
- nodePath: watcherInfo.currentNodePath,
204
+ nodePath: sourceNodePath,
205
+ sourceVersion: event.sourceVersion,
204
206
  result,
205
207
  });
206
208
  });
@@ -214,6 +216,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
214
216
  fileName,
215
217
  line,
216
218
  column,
219
+ sourceVersion: event.sourceVersion,
217
220
  });
218
221
  });
219
222
  return;
@@ -19,7 +19,8 @@ const validateSameOrigin = (req) => {
19
19
  catch (_a) {
20
20
  throw new Error('Request from different origin not allowed');
21
21
  }
22
- if (originUrl.origin !== `http://${host}`) {
22
+ if (originUrl.origin !== `http://${host}` &&
23
+ originUrl.origin !== `https://${host}`) {
23
24
  throw new Error('Request from different origin not allowed');
24
25
  }
25
26
  };
@@ -1,2 +1,2 @@
1
- export declare const remotionSkillNames: readonly ['remotion-best-practices', 'remotion-captions', 'remotion-create', 'remotion-docs', 'remotion-interactivity', 'remotion-maps', 'remotion-markup', 'remotion-multimedia', 'remotion-render', 'remotion-saas', 'remotion-studio', 'remotion-upgrade'];
1
+ export declare const remotionSkillNames: readonly ['remotion-best-practices', 'remotion-captions', 'remotion-create', 'remotion-docs', 'remotion-interactivity', 'remotion-license', 'remotion-maps', 'remotion-markup', 'remotion-multimedia', 'remotion-render', 'remotion-saas', 'remotion-studio', 'remotion-upgrade'];
2
2
  export type RemotionSkillName = (typeof remotionSkillNames)[number];
@@ -7,6 +7,7 @@ exports.remotionSkillNames = [
7
7
  'remotion-create',
8
8
  'remotion-docs',
9
9
  'remotion-interactivity',
10
+ 'remotion-license',
10
11
  'remotion-maps',
11
12
  'remotion-markup',
12
13
  'remotion-multimedia',
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.538",
6
+ "version": "4.0.540",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -23,28 +23,28 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@remotion/studio-protocol": "4.0.538",
26
+ "@remotion/studio-protocol": "4.0.540",
27
27
  "@babel/types": "7.24.0",
28
28
  "@babel/parser": "7.24.1",
29
29
  "@svgr/core": "8.1.0",
30
30
  "@svgr/plugin-jsx": "8.1.0",
31
31
  "kiwi-schema": "0.5.0",
32
32
  "semver": "7.5.3",
33
- "zod": "4.5.4",
34
- "remotion": "4.0.538",
33
+ "zod": "4.6.7",
34
+ "remotion": "4.0.540",
35
35
  "recast": "0.23.21",
36
- "@remotion/bundler": "4.0.538",
37
- "@remotion/renderer": "4.0.538",
38
- "@remotion/codemods": "4.0.538",
39
- "@remotion/studio-shared": "4.0.538",
36
+ "@remotion/bundler": "4.0.540",
37
+ "@remotion/renderer": "4.0.540",
38
+ "@remotion/codemods": "4.0.540",
39
+ "@remotion/studio-shared": "4.0.540",
40
40
  "memfs": "3.4.3",
41
41
  "open": "8.4.2"
42
42
  },
43
43
  "devDependencies": {
44
44
  "ast-types": "0.16.1",
45
- "react": "19.2.3",
45
+ "react": "19.3.1",
46
46
  "@types/semver": "7.5.3",
47
- "@remotion/eslint-config-internal": "4.0.538",
47
+ "@remotion/eslint-config-internal": "4.0.540",
48
48
  "eslint": "9.19.0",
49
49
  "prettier": "3.8.1",
50
50
  "@types/node": "20.12.14",