@remotion/studio-server 4.0.462 → 4.0.464

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 (30) hide show
  1. package/dist/file-watcher.d.ts +3 -1
  2. package/dist/file-watcher.js +11 -7
  3. package/dist/index.d.ts +11 -1
  4. package/dist/index.js +3 -0
  5. package/dist/preview-server/jsx-element-not-found-at-location-error.d.ts +3 -0
  6. package/dist/preview-server/jsx-element-not-found-at-location-error.js +10 -0
  7. package/dist/preview-server/project-info.js +27 -0
  8. package/dist/preview-server/routes/apply-codemod.js +1 -1
  9. package/dist/preview-server/routes/apply-visual-control-change.js +1 -1
  10. package/dist/preview-server/routes/can-update-sequence-props.js +2 -1
  11. package/dist/preview-server/routes/delete-jsx-node.js +1 -1
  12. package/dist/preview-server/routes/duplicate-jsx-node.js +1 -1
  13. package/dist/preview-server/routes/save-effect-props.js +4 -3
  14. package/dist/preview-server/routes/save-props-mutex.d.ts +1 -0
  15. package/dist/preview-server/routes/save-props-mutex.js +11 -0
  16. package/dist/preview-server/routes/save-sequence-props.js +4 -3
  17. package/dist/preview-server/routes/update-default-props.js +1 -1
  18. package/dist/preview-server/sequence-props-watchers.js +15 -0
  19. package/dist/preview-server/undo-stack.js +2 -2
  20. package/package.json +6 -6
  21. package/dist/codemods/get-all-schema-keys.d.ts +0 -2
  22. package/dist/codemods/get-all-schema-keys.js +0 -8
  23. package/dist/codemods/update-sequence-props/find-props-to-delete.d.ts +0 -6
  24. package/dist/codemods/update-sequence-props/find-props-to-delete.js +0 -37
  25. package/dist/codemods/update-sequence-props.d.ts +0 -35
  26. package/dist/codemods/update-sequence-props.js +0 -237
  27. package/dist/preview-server/routes/log-update.d.ts +0 -29
  28. package/dist/preview-server/routes/log-update.js +0 -126
  29. package/dist/preview-server/routes/log-updates/format-side-prop.d.ts +0 -0
  30. package/dist/preview-server/routes/log-updates/format-side-prop.js +0 -1
@@ -1,11 +1,13 @@
1
1
  export type FileChangeEvent = {
2
2
  type: 'created';
3
3
  content: string;
4
+ originatorClientId: string | undefined;
4
5
  } | {
5
6
  type: 'deleted';
6
7
  } | {
7
8
  type: 'changed';
8
9
  content: string;
10
+ originatorClientId: string | undefined;
9
11
  };
10
12
  type OnChange = (event: FileChangeEvent) => void;
11
13
  export type FileWatcherRegistry = {
@@ -23,7 +25,7 @@ export type FileWatcherRegistry = {
23
25
  exists: boolean;
24
26
  unwatch: () => void;
25
27
  };
26
- writeFileAndNotifyFileWatchers: (file: string, content: string) => void;
28
+ writeFileAndNotifyFileWatchers: (file: string, content: string, originatorClientId: string | undefined) => void;
27
29
  };
28
30
  export declare const createFileWatcherRegistry: () => FileWatcherRegistry;
29
31
  export declare const setFileWatcherRegistry: (registry: FileWatcherRegistry) => () => void;
@@ -69,7 +69,11 @@ const createFileWatcherRegistry = () => {
69
69
  if (existenceOnly) {
70
70
  if (!shared.existedBefore && existsNow) {
71
71
  shared.existedBefore = true;
72
- event = { type: 'created', content: '' };
72
+ event = {
73
+ type: 'created',
74
+ content: '',
75
+ originatorClientId: undefined,
76
+ };
73
77
  }
74
78
  else if (shared.existedBefore && !existsNow) {
75
79
  shared.existedBefore = false;
@@ -80,7 +84,7 @@ const createFileWatcherRegistry = () => {
80
84
  const content = (0, node_fs_1.readFileSync)(file, 'utf-8');
81
85
  shared.existedBefore = true;
82
86
  shared.lastKnownContent = content;
83
- event = { type: 'created', content };
87
+ event = { type: 'created', content, originatorClientId: undefined };
84
88
  }
85
89
  else if (shared.existedBefore && !existsNow) {
86
90
  shared.existedBefore = false;
@@ -97,7 +101,7 @@ const createFileWatcherRegistry = () => {
97
101
  return;
98
102
  }
99
103
  shared.lastKnownContent = content;
100
- event = { type: 'changed', content };
104
+ event = { type: 'changed', content, originatorClientId: undefined };
101
105
  }
102
106
  if (!event) {
103
107
  return;
@@ -119,7 +123,7 @@ const createFileWatcherRegistry = () => {
119
123
  },
120
124
  };
121
125
  };
122
- const _writeFileAndNotifyFileWatchers = (file, content) => {
126
+ const _writeFileAndNotifyFileWatchers = (file, content, originatorClientId) => {
123
127
  (0, node_fs_1.writeFileSync)(file, content);
124
128
  const shared = sharedWatchers.get(getRegistryKey(file, false));
125
129
  if (!shared) {
@@ -128,7 +132,7 @@ const createFileWatcherRegistry = () => {
128
132
  shared.lastKnownContent = content;
129
133
  shared.existedBefore = true;
130
134
  for (const subscriber of shared.subscribers) {
131
- subscriber({ type: 'changed', content });
135
+ subscriber({ type: 'changed', content, originatorClientId });
132
136
  }
133
137
  };
134
138
  return {
@@ -162,10 +166,10 @@ const installFileWatcher = (options) => {
162
166
  return (0, exports.getFileWatcherRegistry)().installFileWatcher(options);
163
167
  };
164
168
  exports.installFileWatcher = installFileWatcher;
165
- const writeFileAndNotifyFileWatchers = (file, content) => {
169
+ const writeFileAndNotifyFileWatchers = (file, content, originatorClientId) => {
166
170
  if (!currentRegistry) {
167
171
  return;
168
172
  }
169
- (0, exports.getFileWatcherRegistry)().writeFileAndNotifyFileWatchers(file, content);
173
+ (0, exports.getFileWatcherRegistry)().writeFileAndNotifyFileWatchers(file, content, originatorClientId);
170
174
  };
171
175
  exports.writeFileAndNotifyFileWatchers = writeFileAndNotifyFileWatchers;
package/dist/index.d.ts CHANGED
@@ -63,7 +63,7 @@ export declare const StudioServerInternals: {
63
63
  exists: boolean;
64
64
  unwatch: () => void;
65
65
  };
66
- writeFileAndNotifyFileWatchers: (file: string, content: string) => void;
66
+ writeFileAndNotifyFileWatchers: (file: string, content: string, originatorClientId: string | undefined) => void;
67
67
  createFileWatcherRegistry: () => import("./file-watcher").FileWatcherRegistry;
68
68
  setFileWatcherRegistry: (registry: import("./file-watcher").FileWatcherRegistry) => () => void;
69
69
  AnsiDiff: typeof AnsiDiff;
@@ -80,6 +80,16 @@ export declare const StudioServerInternals: {
80
80
  newContents: string;
81
81
  changesMade: import("./codemods/recast-mods").Change[];
82
82
  };
83
+ formatOutput: (tsContent: string) => Promise<string>;
84
+ updateDefaultProps: ({ input, compositionId, newDefaultProps, enumPaths, }: {
85
+ input: string;
86
+ compositionId: string;
87
+ newDefaultProps: Record<string, unknown>;
88
+ enumPaths: import("@remotion/studio-shared").EnumPath[];
89
+ }) => Promise<{
90
+ output: string;
91
+ formatted: boolean;
92
+ }>;
83
93
  getInstalledDependencies: (remotionRoot: string) => {
84
94
  dependencies: string[];
85
95
  devDependencies: string[];
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "getDefaultOutLocation", { enumerable: true, get:
7
7
  const ansi_diff_1 = require("./ansi-diff");
8
8
  const client_render_queue_1 = require("./client-render-queue");
9
9
  const duplicate_composition_1 = require("./codemods/duplicate-composition");
10
+ const update_default_props_1 = require("./codemods/update-default-props");
10
11
  const file_watcher_1 = require("./file-watcher");
11
12
  const get_latest_remotion_version_1 = require("./get-latest-remotion-version");
12
13
  const get_installed_dependencies_1 = require("./helpers/get-installed-dependencies");
@@ -32,6 +33,8 @@ exports.StudioServerInternals = {
32
33
  AnsiDiff: ansi_diff_1.AnsiDiff,
33
34
  formatBytes: studio_shared_1.formatBytes,
34
35
  parseAndApplyCodemod: duplicate_composition_1.parseAndApplyCodemod,
36
+ formatOutput: duplicate_composition_1.formatOutput,
37
+ updateDefaultProps: update_default_props_1.updateDefaultProps,
35
38
  getInstalledDependencies: get_installed_dependencies_1.getInstalledDependencies,
36
39
  getInstalledDependenciesWithVersions: get_installed_dependencies_1.getInstalledDependenciesWithVersions,
37
40
  getInstallCommand: install_command_1.getInstallCommand,
@@ -0,0 +1,3 @@
1
+ export declare class JsxElementNotFoundAtLocationError extends Error {
2
+ constructor();
3
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsxElementNotFoundAtLocationError = void 0;
4
+ class JsxElementNotFoundAtLocationError extends Error {
5
+ constructor() {
6
+ super('Cannot compute sequence props status: Could not find a JSX element at the specified location');
7
+ this.name = 'JsxElementNotFoundAtLocationError';
8
+ }
9
+ }
10
+ exports.JsxElementNotFoundAtLocationError = JsxElementNotFoundAtLocationError;
@@ -6,8 +6,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getProjectInfo = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const getRootFileFromEntryPoint = (entryPoint) => {
10
+ const entryBase = node_path_1.default.basename(entryPoint, node_path_1.default.extname(entryPoint));
11
+ if (!entryBase.endsWith('-entry')) {
12
+ return null;
13
+ }
14
+ const stem = entryBase.slice(0, -'-entry'.length);
15
+ const pascalCase = stem
16
+ .split('-')
17
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
18
+ .join('');
19
+ const rootName = `${pascalCase}Root`;
20
+ const entryDir = node_path_1.default.dirname(entryPoint);
21
+ for (const ext of ['.tsx', '.ts', '.jsx', '.js']) {
22
+ const candidate = node_path_1.default.join(entryDir, rootName + ext);
23
+ if ((0, node_fs_1.existsSync)(candidate)) {
24
+ return candidate;
25
+ }
26
+ }
27
+ return null;
28
+ };
9
29
  const getProjectInfo = (remotionRoot, entryPoint) => {
10
30
  var _a;
31
+ const rootFileFromEntryPoint = getRootFileFromEntryPoint(entryPoint);
32
+ if (rootFileFromEntryPoint) {
33
+ return Promise.resolve({
34
+ rootFile: rootFileFromEntryPoint,
35
+ relativeRootFile: node_path_1.default.relative(remotionRoot, rootFileFromEntryPoint),
36
+ });
37
+ }
11
38
  const knownPaths = [
12
39
  'src/Root.tsx',
13
40
  'src/Root.jsx',
@@ -27,7 +27,7 @@ const applyCodemodHandler = async ({ input: { codemod, dryRun }, logLevel, remot
27
27
  newLines: formatted.split('\n'),
28
28
  });
29
29
  if (!dryRun) {
30
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, formatted);
30
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, formatted, undefined);
31
31
  const end = Date.now() - time;
32
32
  renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Edited root file in ${end}ms`));
33
33
  }
@@ -126,7 +126,7 @@ const applyVisualControlHandler = async ({ input: { fileName, changes }, remotio
126
126
  });
127
127
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
128
128
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
129
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
129
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
130
130
  (0, live_events_1.waitForLiveEventsListener)().then((listener) => {
131
131
  listener.sendEventToClient({
132
132
  type: 'visual-control-values-changed',
@@ -43,6 +43,7 @@ const renderer_1 = require("@remotion/renderer");
43
43
  const recast = __importStar(require("recast"));
44
44
  const parse_ast_1 = require("../../codemods/parse-ast");
45
45
  const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
46
+ const jsx_element_not_found_at_location_error_1 = require("../jsx-element-not-found-at-location-error");
46
47
  const can_update_effect_props_1 = require("./can-update-effect-props");
47
48
  const isStaticValue = (node) => {
48
49
  switch (node.type) {
@@ -295,7 +296,7 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, keys, e
295
296
  const ast = (0, parse_ast_1.parseAst)(fileContents);
296
297
  const jsxElement = (0, exports.findJsxElementAtNodePath)(ast, nodePath);
297
298
  if (!jsxElement) {
298
- throw new Error('Cannot compute sequence props status: Could not find a JSX element at the specified location');
299
+ throw new jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError();
299
300
  }
300
301
  const filteredProps = computeSequenceOnlyPropsRecord({ jsxElement, keys });
301
302
  const effectsStatuses = computeEffectsForJsx({ jsxElement, effects });
@@ -39,7 +39,7 @@ const deleteJsxNodeHandler = async ({ input: { fileName, nodePath }, remotionRoo
39
39
  suppressHmrOnFileRestore: false,
40
40
  });
41
41
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
42
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
42
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
43
43
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
44
44
  remotionRoot,
45
45
  absolutePath,
@@ -39,7 +39,7 @@ const duplicateJsxNodeHandler = async ({ input: { fileName, nodePath }, remotion
39
39
  suppressHmrOnFileRestore: false,
40
40
  });
41
41
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
42
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
42
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, undefined);
43
43
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
44
44
  remotionRoot,
45
45
  absolutePath,
@@ -18,7 +18,8 @@ const can_update_sequence_props_1 = require("./can-update-sequence-props");
18
18
  const format_effect_prop_change_1 = require("./log-updates/format-effect-prop-change");
19
19
  const log_effect_update_1 = require("./log-updates/log-effect-update");
20
20
  const log_update_1 = require("./log-updates/log-update");
21
- const saveEffectPropsHandler = async ({ input: { fileName, sequenceNodePath, effectIndex, key, value, defaultValue, schema, }, remotionRoot, logLevel, }) => {
21
+ const save_props_mutex_1 = require("./save-props-mutex");
22
+ const saveEffectPropsHandler = ({ input: { fileName, sequenceNodePath, effectIndex, key, value, defaultValue, schema, clientId, }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
22
23
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-effect-props] Received request for fileName="${fileName}" effectIndex=${effectIndex} key="${key}"`);
23
24
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
24
25
  const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
@@ -74,7 +75,7 @@ const saveEffectPropsHandler = async ({ input: { fileName, sequenceNodePath, eff
74
75
  });
75
76
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
76
77
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
77
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
78
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
78
79
  (0, log_effect_update_1.logEffectUpdate)({
79
80
  fileRelativeToRoot,
80
81
  line: logLine,
@@ -103,5 +104,5 @@ const saveEffectPropsHandler = async ({ input: { fileName, sequenceNodePath, eff
103
104
  effectIndex,
104
105
  keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
105
106
  });
106
- };
107
+ });
107
108
  exports.saveEffectPropsHandler = saveEffectPropsHandler;
@@ -0,0 +1 @@
1
+ export declare const withSavePropsLock: <T>(fn: () => Promise<T>) => Promise<T>;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withSavePropsLock = void 0;
4
+ let chain = Promise.resolve();
5
+ const withSavePropsLock = (fn) => {
6
+ const run = () => fn();
7
+ const next = chain.then(run, run);
8
+ chain = next.then(() => undefined, () => undefined);
9
+ return next;
10
+ };
11
+ exports.withSavePropsLock = withSavePropsLock;
@@ -16,7 +16,8 @@ const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
16
16
  const can_update_sequence_props_1 = require("./can-update-sequence-props");
17
17
  const format_prop_change_1 = require("./log-updates/format-prop-change");
18
18
  const log_update_1 = require("./log-updates/log-update");
19
- const saveSequencePropsHandler = async ({ input: { fileName, nodePath, key, value, defaultValue, schema }, remotionRoot, logLevel, }) => {
19
+ const save_props_mutex_1 = require("./save-props-mutex");
20
+ const saveSequencePropsHandler = ({ input: { fileName, nodePath, key, value, defaultValue, schema, clientId }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
20
21
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[save-sequence-props] Received request for fileName="${fileName}" key="${key}"`);
21
22
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
22
23
  const fileRelativeToRoot = node_path_1.default.relative(remotionRoot, absolutePath);
@@ -74,7 +75,7 @@ const saveSequencePropsHandler = async ({ input: { fileName, nodePath, key, valu
74
75
  });
75
76
  (0, undo_stack_1.suppressUndoStackInvalidation)(absolutePath);
76
77
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(absolutePath);
77
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output);
78
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(absolutePath, output, clientId);
78
79
  (0, log_update_1.logUpdate)({
79
80
  fileRelativeToRoot,
80
81
  line: logLine,
@@ -95,5 +96,5 @@ const saveSequencePropsHandler = async ({ input: { fileName, nodePath, key, valu
95
96
  remotionRoot,
96
97
  });
97
98
  return newStatus;
98
- };
99
+ });
99
100
  exports.saveSequencePropsHandler = saveSequencePropsHandler;
@@ -45,7 +45,7 @@ const updateDefaultPropsHandler = async ({ input: { compositionId, defaultProps,
45
45
  });
46
46
  (0, undo_stack_1.suppressUndoStackInvalidation)(projectInfo.rootFile);
47
47
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(projectInfo.rootFile);
48
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, output);
48
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(projectInfo.rootFile, output, undefined);
49
49
  const locationLabel = (0, format_log_file_location_1.formatLogFileLocation)({
50
50
  remotionRoot,
51
51
  absolutePath: projectInfo.rootFile,
@@ -8,6 +8,7 @@ const node_path_1 = __importDefault(require("node:path"));
8
8
  const renderer_1 = require("@remotion/renderer");
9
9
  const studio_shared_1 = require("@remotion/studio-shared");
10
10
  const file_watcher_1 = require("../file-watcher");
11
+ const jsx_element_not_found_at_location_error_1 = require("./jsx-element-not-found-at-location-error");
11
12
  const live_events_1 = require("./live-events");
12
13
  const node_path_cache_1 = require("./node-path-cache");
13
14
  const can_update_sequence_props_1 = require("./routes/can-update-sequence-props");
@@ -77,6 +78,9 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, effect
77
78
  if (event.type === 'deleted') {
78
79
  return;
79
80
  }
81
+ if (event.originatorClientId === clientId) {
82
+ return;
83
+ }
80
84
  try {
81
85
  const result = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
82
86
  fileContents: event.content,
@@ -101,6 +105,17 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, keys, effect
101
105
  });
102
106
  }
103
107
  catch (error) {
108
+ if (error instanceof jsx_element_not_found_at_location_error_1.JsxElementNotFoundAtLocationError) {
109
+ (0, live_events_1.waitForLiveEventsListener)().then((listener) => {
110
+ listener.sendEventToClientId(clientId, {
111
+ type: 'lost-node-path',
112
+ fileName,
113
+ line,
114
+ column,
115
+ });
116
+ });
117
+ return;
118
+ }
104
119
  renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, error);
105
120
  }
106
121
  },
@@ -195,7 +195,7 @@ function popUndo() {
195
195
  if (entry.suppressHmrOnFileRestore) {
196
196
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(entry.filePath);
197
197
  }
198
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents);
198
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents, undefined);
199
199
  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
200
  logFileAction(entry.description.undoMessage, entry.filePath, entry.logLine);
201
201
  if (entry.entryType === 'visual-control') {
@@ -223,7 +223,7 @@ function popRedo() {
223
223
  if (entry.suppressHmrOnFileRestore) {
224
224
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(entry.filePath);
225
225
  }
226
- (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents);
226
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(entry.filePath, entry.oldContents, undefined);
227
227
  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
228
  logFileAction(entry.description.redoMessage, entry.filePath, entry.logLine);
229
229
  if (entry.entryType === 'visual-control') {
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.462",
6
+ "version": "4.0.464",
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.462",
30
+ "remotion": "4.0.464",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.462",
33
- "@remotion/renderer": "4.0.462",
34
- "@remotion/studio-shared": "4.0.462",
32
+ "@remotion/bundler": "4.0.464",
33
+ "@remotion/renderer": "4.0.464",
34
+ "@remotion/studio-shared": "4.0.464",
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.462",
42
+ "@remotion/eslint-config-internal": "4.0.464",
43
43
  "eslint": "9.19.0",
44
44
  "@types/node": "20.12.14",
45
45
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
@@ -1,2 +0,0 @@
1
- import type { SequenceSchema } from 'remotion';
2
- export declare const getAllSchemaKeys: (schema: SequenceSchema) => string[];
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAllSchemaKeys = void 0;
4
- const remotion_1 = require("remotion");
5
- const getAllSchemaKeys = (schema) => {
6
- return Object.keys(remotion_1.Internals.getFlatSchemaWithAllKeys(schema));
7
- };
8
- exports.getAllSchemaKeys = getAllSchemaKeys;
@@ -1,6 +0,0 @@
1
- import type { SequenceSchema } from 'remotion';
2
- export declare const findPropsToDelete: ({ schema, key, value, }: {
3
- schema: SequenceSchema;
4
- key: string;
5
- value: unknown;
6
- }) => string[];
@@ -1,37 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findPropsToDelete = void 0;
4
- const findPropsToDelete = ({ schema, key, value, }) => {
5
- const fieldSchema = schema[key];
6
- if (!fieldSchema) {
7
- throw new Error('Key ' + JSON.stringify(key) + ' not found in schema');
8
- }
9
- if (typeof value !== 'string') {
10
- throw new Error('Value must be a string, but is ' + JSON.stringify(value));
11
- }
12
- if (fieldSchema.type !== 'enum') {
13
- throw new Error('Key ' + JSON.stringify(key) + ' is not an enum');
14
- }
15
- const currentVariant = fieldSchema.variants[value];
16
- if (!currentVariant) {
17
- throw new Error('Value for ' +
18
- JSON.stringify(key) +
19
- ' must be one of ' +
20
- Object.keys(fieldSchema.variants)
21
- .map((v) => JSON.stringify(v))
22
- .join(', ') +
23
- ', got ' +
24
- JSON.stringify(value));
25
- }
26
- const otherVariants = Object.keys(fieldSchema.variants).filter((v) => v !== value);
27
- const otherKeys = new Set();
28
- for (const variant of otherVariants) {
29
- const otherVariant = fieldSchema.variants[variant];
30
- const keys = Object.keys(otherVariant);
31
- for (const k of keys) {
32
- otherKeys.add(k);
33
- }
34
- }
35
- return [...otherKeys];
36
- };
37
- exports.findPropsToDelete = findPropsToDelete;
@@ -1,35 +0,0 @@
1
- import type { SequenceNodePath } from 'remotion';
2
- import type { SequenceSchema } from 'remotion';
3
- export type SequencePropUpdate = {
4
- key: string;
5
- value: unknown;
6
- defaultValue: unknown | null;
7
- };
8
- export type RemovedProp = {
9
- key: string;
10
- valueString: string;
11
- };
12
- export declare const updateSequencePropsAst: ({ input, nodePath, updates, schema, }: {
13
- input: string;
14
- nodePath: SequenceNodePath;
15
- updates: SequencePropUpdate[];
16
- schema: SequenceSchema;
17
- }) => {
18
- serialized: string;
19
- oldValueStrings: string[];
20
- logLine: number;
21
- removedProps: RemovedProp[];
22
- };
23
- export declare const updateSequenceProps: ({ input, nodePath, updates, schema, prettierConfigOverride, }: {
24
- input: string;
25
- nodePath: SequenceNodePath;
26
- updates: SequencePropUpdate[];
27
- schema: SequenceSchema;
28
- prettierConfigOverride?: Record<string, unknown> | null | undefined;
29
- }) => Promise<{
30
- output: string;
31
- oldValueStrings: string[];
32
- formatted: boolean;
33
- logLine: number;
34
- removedProps: RemovedProp[];
35
- }>;
@@ -1,237 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.updateSequenceProps = exports.updateSequencePropsAst = void 0;
37
- const recast = __importStar(require("recast"));
38
- const can_update_sequence_props_1 = require("../preview-server/routes/can-update-sequence-props");
39
- const format_file_content_1 = require("./format-file-content");
40
- const parse_ast_1 = require("./parse-ast");
41
- const update_nested_prop_1 = require("./update-nested-prop");
42
- const b = recast.types.builders;
43
- const removeVariantKey = ({ node, variantKey, }) => {
44
- var _a;
45
- const dotIndex = variantKey.indexOf('.');
46
- if (dotIndex === -1) {
47
- const idx = (_a = node.attributes) === null || _a === void 0 ? void 0 : _a.findIndex((a) => a.type === 'JSXAttribute' &&
48
- a.name.type === 'JSXIdentifier' &&
49
- a.name.name === variantKey);
50
- if (idx !== undefined && idx !== -1 && node.attributes) {
51
- node.attributes.splice(idx, 1);
52
- }
53
- return;
54
- }
55
- (0, update_nested_prop_1.updateNestedProp)({
56
- node,
57
- parentKey: variantKey.slice(0, dotIndex),
58
- childKey: variantKey.slice(dotIndex + 1),
59
- value: undefined,
60
- defaultValue: null,
61
- isDefault: true,
62
- });
63
- };
64
- const snapshotTopLevelAttrs = (node) => {
65
- var _a;
66
- const result = new Map();
67
- for (const a of (_a = node.attributes) !== null && _a !== void 0 ? _a : []) {
68
- if (a.type === 'JSXAttribute' && a.name.type === 'JSXIdentifier') {
69
- const name = a.name.name;
70
- const printed = recast
71
- .print(a)
72
- .code.replace(/\s+/g, ' ')
73
- .replace(/,(\s*[}\]])/g, '$1')
74
- .trim();
75
- const prefix = `${name}=`;
76
- let valueOnly = printed.startsWith(prefix)
77
- ? printed.slice(prefix.length)
78
- : printed;
79
- if (valueOnly.startsWith('{') && valueOnly.endsWith('}')) {
80
- valueOnly = valueOnly.slice(1, -1).trim();
81
- }
82
- result.set(name, valueOnly);
83
- }
84
- }
85
- return result;
86
- };
87
- const updateSequencePropsAst = ({ input, nodePath, updates, schema, }) => {
88
- var _a, _b, _c;
89
- var _d, _e;
90
- const ast = (0, parse_ast_1.parseAst)(input);
91
- const node = (0, can_update_sequence_props_1.findJsxElementAtNodePath)(ast, nodePath);
92
- if (!node) {
93
- throw new Error('Could not find a JSX element at the specified line to update');
94
- }
95
- const logLine = (_d = (_a = node.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _d !== void 0 ? _d : 1;
96
- const oldValueStrings = [];
97
- const initialAttrs = snapshotTopLevelAttrs(node);
98
- const updatedTopLevelKeys = new Set(updates.map(({ key }) => {
99
- const dot = key.indexOf('.');
100
- return dot === -1 ? key : key.slice(0, dot);
101
- }));
102
- for (const { key, value, defaultValue } of updates) {
103
- let oldValueString = '';
104
- const isDefault = defaultValue !== null &&
105
- JSON.stringify(value) === JSON.stringify(defaultValue);
106
- const dotIndex = key.indexOf('.');
107
- const isNested = dotIndex !== -1;
108
- const parentKey = isNested ? key.slice(0, dotIndex) : key;
109
- const childKey = isNested ? key.slice(dotIndex + 1) : '';
110
- if (isNested) {
111
- oldValueString = (0, update_nested_prop_1.updateNestedProp)({
112
- node,
113
- parentKey,
114
- childKey,
115
- value,
116
- defaultValue,
117
- isDefault,
118
- });
119
- }
120
- else {
121
- const attrIndex = (_b = node.attributes) === null || _b === void 0 ? void 0 : _b.findIndex((a) => {
122
- if (a.type === 'JSXSpreadAttribute') {
123
- return false;
124
- }
125
- if (a.name.type === 'JSXNamespacedName') {
126
- return false;
127
- }
128
- return a.name.name === key;
129
- });
130
- const attr = attrIndex !== undefined && attrIndex !== -1
131
- ? (_c = node.attributes) === null || _c === void 0 ? void 0 : _c[attrIndex]
132
- : undefined;
133
- if (attr && attr.type !== 'JSXSpreadAttribute' && attr.value) {
134
- const printed = recast.print(attr.value).code;
135
- // Strip JSX expression container braces, e.g. "{30}" -> "30"
136
- oldValueString =
137
- printed.startsWith('{') && printed.endsWith('}')
138
- ? printed.slice(1, -1)
139
- : printed;
140
- }
141
- else if (attr && attr.type !== 'JSXSpreadAttribute' && !attr.value) {
142
- // JSX shorthand like `loop` (no value) is implicitly `true`
143
- oldValueString = 'true';
144
- }
145
- else if (!attr && defaultValue !== null) {
146
- oldValueString = JSON.stringify(defaultValue);
147
- }
148
- if (isDefault) {
149
- if (attr && attr.type !== 'JSXSpreadAttribute' && node.attributes) {
150
- node.attributes.splice(attrIndex, 1);
151
- }
152
- }
153
- else {
154
- const parsed = (0, update_nested_prop_1.parseValueExpression)(value);
155
- const newValue = value === true ? null : b.jsxExpressionContainer(parsed);
156
- if (!attr || attr.type === 'JSXSpreadAttribute') {
157
- const newAttr = b.jsxAttribute(b.jsxIdentifier(key), newValue);
158
- if (!node.attributes) {
159
- node.attributes = [];
160
- }
161
- node.attributes.push(newAttr);
162
- }
163
- else {
164
- attr.value = newValue;
165
- }
166
- }
167
- }
168
- oldValueStrings.push(oldValueString);
169
- if (schema && !isNested) {
170
- const fieldSchema = schema[key];
171
- if (fieldSchema && fieldSchema.type === 'enum') {
172
- let oldRawValue;
173
- try {
174
- oldRawValue = JSON.parse(oldValueString);
175
- }
176
- catch (_f) {
177
- oldRawValue = oldValueString;
178
- }
179
- if (oldRawValue !== value) {
180
- const oldVariant = typeof oldRawValue === 'string'
181
- ? fieldSchema.variants[oldRawValue]
182
- : undefined;
183
- const newVariant = typeof value === 'string' ? fieldSchema.variants[value] : undefined;
184
- if (oldVariant) {
185
- const newKeys = new Set(newVariant ? Object.keys(newVariant) : []);
186
- for (const variantKey of Object.keys(oldVariant)) {
187
- if (newKeys.has(variantKey)) {
188
- continue;
189
- }
190
- removeVariantKey({ node, variantKey });
191
- }
192
- }
193
- }
194
- }
195
- }
196
- }
197
- const finalAttrNames = new Set();
198
- for (const a of (_e = node.attributes) !== null && _e !== void 0 ? _e : []) {
199
- if (a.type === 'JSXAttribute' && a.name.type === 'JSXIdentifier') {
200
- finalAttrNames.add(a.name.name);
201
- }
202
- }
203
- const removedProps = [];
204
- for (const [name, valueString] of initialAttrs) {
205
- if (finalAttrNames.has(name) || updatedTopLevelKeys.has(name)) {
206
- continue;
207
- }
208
- removedProps.push({ key: name, valueString });
209
- }
210
- return {
211
- serialized: (0, parse_ast_1.serializeAst)(ast),
212
- oldValueStrings,
213
- logLine,
214
- removedProps,
215
- };
216
- };
217
- exports.updateSequencePropsAst = updateSequencePropsAst;
218
- const updateSequenceProps = async ({ input, nodePath, updates, schema, prettierConfigOverride, }) => {
219
- const { serialized, oldValueStrings, logLine, removedProps } = (0, exports.updateSequencePropsAst)({
220
- input,
221
- nodePath,
222
- updates,
223
- schema,
224
- });
225
- const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
226
- input: serialized,
227
- prettierConfigOverride,
228
- });
229
- return {
230
- output,
231
- oldValueStrings,
232
- formatted,
233
- logLine,
234
- removedProps,
235
- };
236
- };
237
- exports.updateSequenceProps = updateSequenceProps;
@@ -1,29 +0,0 @@
1
- export declare const warnAboutPrettierOnce: (logLevel: "error" | "info" | "trace" | "verbose" | "warn") => void;
2
- export declare const normalizeQuotes: (str: string) => string;
3
- export declare const fg: (r: number, g: number, b: number, str: string) => string;
4
- export declare const bg: (r: number, g: number, b: number, str: string) => string;
5
- export declare const strikeThrough: (str: string) => string;
6
- export type PropDelta = {
7
- key: string;
8
- valueString: string;
9
- };
10
- export declare const formatPropChange: ({ key, oldValueString, newValueString, defaultValueString, removedProps, addedProps, }: {
11
- key: string;
12
- oldValueString: string;
13
- newValueString: string;
14
- defaultValueString: string | null;
15
- removedProps: PropDelta[];
16
- addedProps: PropDelta[];
17
- }) => string;
18
- export declare const logUpdate: ({ fileRelativeToRoot, line, key, oldValueString, newValueString, defaultValueString, formatted, logLevel, removedProps, addedProps, }: {
19
- fileRelativeToRoot: string;
20
- line: number;
21
- key: string;
22
- oldValueString: string;
23
- newValueString: string;
24
- defaultValueString: string | null;
25
- formatted: boolean;
26
- logLevel: "error" | "info" | "trace" | "verbose" | "warn";
27
- removedProps: PropDelta[];
28
- addedProps: PropDelta[];
29
- }) => void;
@@ -1,126 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logUpdate = exports.formatPropChange = exports.strikeThrough = exports.bg = exports.fg = exports.normalizeQuotes = exports.warnAboutPrettierOnce = void 0;
4
- const renderer_1 = require("@remotion/renderer");
5
- let warnedAboutPrettier = false;
6
- const warnAboutPrettierOnce = (logLevel) => {
7
- if (warnedAboutPrettier) {
8
- return;
9
- }
10
- warnedAboutPrettier = true;
11
- renderer_1.RenderInternals.Log.warn({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.yellow('Could not format with Prettier. File will need to be formatted manually.'));
12
- };
13
- exports.warnAboutPrettierOnce = warnAboutPrettierOnce;
14
- const normalizeQuotes = (str) => {
15
- if (str.length >= 2 &&
16
- ((str.startsWith("'") && str.endsWith("'")) ||
17
- (str.startsWith('"') && str.endsWith('"')))) {
18
- return `'${str.slice(1, -1)}'`;
19
- }
20
- return str;
21
- };
22
- exports.normalizeQuotes = normalizeQuotes;
23
- // 24-bit ANSI helpers
24
- const fg = (r, g, b, str) => `\u001b[38;2;${r};${g};${b}m${str}\u001b[39m`;
25
- exports.fg = fg;
26
- const bg = (r, g, b, str) => `\u001b[48;2;${r};${g};${b}m${str}\u001b[49m`;
27
- exports.bg = bg;
28
- // eslint-disable-next-line no-control-regex
29
- const stripAnsi = (str) => str.replace(/\u001b\[[0-9;]*m/g, '');
30
- const strikeThrough = (str) => `\u001b[9m\u001b[38;2;255;85;85m${stripAnsi(str)}\u001b[39m\u001b[29m`;
31
- exports.strikeThrough = strikeThrough;
32
- // Monokai-inspired syntax colors
33
- const attrName = (str) => (0, exports.fg)(166, 226, 46, str);
34
- const equals = (str) => (0, exports.fg)(249, 38, 114, str);
35
- const punctuation = (str) => (0, exports.fg)(248, 248, 242, str);
36
- const stringValue = (str) => (0, exports.fg)(230, 219, 116, str);
37
- const numberValue = (str) => (0, exports.fg)(174, 129, 255, str);
38
- const colorValue = (str) => {
39
- if ((str.startsWith("'") && str.endsWith("'")) ||
40
- (str.startsWith('"') && str.endsWith('"'))) {
41
- return stringValue(str);
42
- }
43
- if (/^-?\d+(\.\d+)?$/.test(str)) {
44
- return numberValue(str);
45
- }
46
- return punctuation(str);
47
- };
48
- const colorEnabled = () => renderer_1.RenderInternals.chalk.enabled();
49
- // Format key={value} with Monokai syntax highlighting
50
- const formatSimpleProp = (key, value) => {
51
- return `${attrName(key)}${equals('=')}${punctuation('{')}${colorValue(value)}${punctuation('}')}`;
52
- };
53
- // Format parentKey={{childKey: value}} with Monokai syntax highlighting
54
- const formatNestedProp = (parentKey, childKey, value) => {
55
- return `${attrName(parentKey)}${equals('=')}${punctuation('{{')}${punctuation(childKey)}${punctuation(':')} ${colorValue(value)}${punctuation('}}')}`;
56
- };
57
- const formatPropDelta = ({ key, valueString }) => {
58
- if (!colorEnabled()) {
59
- const dotIdx = key.indexOf('.');
60
- if (dotIdx === -1) {
61
- return `${key}={${valueString}}`;
62
- }
63
- const parent = key.slice(0, dotIdx);
64
- const child = key.slice(dotIdx + 1);
65
- return `${parent}={{${child}: ${valueString}}}`;
66
- }
67
- const dotIdx = key.indexOf('.');
68
- if (dotIdx === -1) {
69
- return formatSimpleProp(key, valueString);
70
- }
71
- return formatNestedProp(key.slice(0, dotIdx), key.slice(dotIdx + 1), valueString);
72
- };
73
- const formatSideProps = ({ removedProps, addedProps, }) => {
74
- const parts = [];
75
- for (const prop of removedProps) {
76
- const formatted = formatPropDelta(prop);
77
- parts.push(colorEnabled() ? (0, exports.strikeThrough)(formatted) : formatted);
78
- }
79
- for (const prop of addedProps) {
80
- parts.push(formatPropDelta(prop));
81
- }
82
- if (parts.length === 0) {
83
- return '';
84
- }
85
- return `, ${parts.join(', ')}`;
86
- };
87
- const formatPropChange = ({ key, oldValueString, newValueString, defaultValueString, removedProps, addedProps, }) => {
88
- const suffix = formatSideProps({ removedProps, addedProps });
89
- if (!colorEnabled()) {
90
- const dotIdx = key.indexOf('.');
91
- if (dotIdx === -1) {
92
- return `${key}={${oldValueString}} \u2192 ${key}={${newValueString}}${suffix}`;
93
- }
94
- const parent = key.slice(0, dotIdx);
95
- const child = key.slice(dotIdx + 1);
96
- return `${parent}={{${child}: ${oldValueString}}} \u2192 ${parent}={{${child}: ${newValueString}}}${suffix}`;
97
- }
98
- const dotIndex = key.indexOf('.');
99
- const formatProp = (value) => dotIndex === -1
100
- ? formatSimpleProp(key, value)
101
- : formatNestedProp(key.slice(0, dotIndex), key.slice(dotIndex + 1), value);
102
- if (defaultValueString !== null && newValueString === defaultValueString) {
103
- return `${(0, exports.strikeThrough)(formatProp(oldValueString))}${suffix}`;
104
- }
105
- if (defaultValueString !== null && oldValueString === defaultValueString) {
106
- return `${formatProp(newValueString)}${suffix}`;
107
- }
108
- return `${formatProp(oldValueString)} \u2192 ${formatProp(newValueString)}${suffix}`;
109
- };
110
- exports.formatPropChange = formatPropChange;
111
- const logUpdate = ({ fileRelativeToRoot, line, key, oldValueString, newValueString, defaultValueString, formatted, logLevel, removedProps, addedProps, }) => {
112
- const locationLabel = `${fileRelativeToRoot}:${line}`;
113
- const propChange = (0, exports.formatPropChange)({
114
- key,
115
- oldValueString: (0, exports.normalizeQuotes)(oldValueString),
116
- newValueString: (0, exports.normalizeQuotes)(newValueString),
117
- defaultValueString: defaultValueString !== null ? (0, exports.normalizeQuotes)(defaultValueString) : null,
118
- removedProps,
119
- addedProps,
120
- });
121
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `${renderer_1.RenderInternals.chalk.blueBright(`${locationLabel}:`)} ${propChange}`);
122
- if (!formatted) {
123
- (0, exports.warnAboutPrettierOnce)(logLevel);
124
- }
125
- };
126
- exports.logUpdate = logUpdate;
@@ -1 +0,0 @@
1
- "use strict";