@remotion/studio-server 4.0.496 → 4.0.498

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 (43) hide show
  1. package/dist/better-opn/index.d.ts +6 -0
  2. package/dist/better-opn/index.js +46 -18
  3. package/dist/codemods/update-sequence-props/update-sequence-props.js +47 -0
  4. package/dist/helpers/css-shorthand-properties.d.ts +27 -0
  5. package/dist/helpers/css-shorthand-properties.js +43 -0
  6. package/dist/helpers/package-manager-spawn-options.d.ts +2 -0
  7. package/dist/helpers/package-manager-spawn-options.js +7 -0
  8. package/dist/helpers/parse-background-shorthand.d.ts +11 -0
  9. package/dist/helpers/parse-background-shorthand.js +41 -0
  10. package/dist/helpers/parse-border-shorthand.d.ts +6 -0
  11. package/dist/helpers/parse-border-shorthand.js +135 -0
  12. package/dist/helpers/resolve-composition-component.d.ts +3 -1
  13. package/dist/helpers/resolve-composition-component.js +38 -9
  14. package/dist/index.d.ts +5 -6
  15. package/dist/index.js +2 -0
  16. package/dist/open-browser-shortcut.js +26 -16
  17. package/dist/preview-server/api-routes.js +4 -0
  18. package/dist/preview-server/api-types.d.ts +1 -0
  19. package/dist/preview-server/handler.d.ts +2 -1
  20. package/dist/preview-server/handler.js +2 -1
  21. package/dist/preview-server/routes/batch-update-keyframe-settings.d.ts +7 -0
  22. package/dist/preview-server/routes/batch-update-keyframe-settings.js +187 -0
  23. package/dist/preview-server/routes/can-update-sequence-props.js +54 -3
  24. package/dist/preview-server/routes/download-remote-asset.js +1 -0
  25. package/dist/preview-server/routes/insert-element.js +7 -1
  26. package/dist/preview-server/routes/insert-jsx-element.js +9 -1
  27. package/dist/preview-server/routes/install-dependency.js +5 -1
  28. package/dist/preview-server/routes/save-sequence-props.js +90 -22
  29. package/dist/preview-server/routes/update-public-license.d.ts +7 -0
  30. package/dist/preview-server/routes/update-public-license.js +93 -0
  31. package/dist/preview-server/start-server.d.ts +4 -6
  32. package/dist/preview-server/start-server.js +4 -6
  33. package/dist/routes.d.ts +2 -1
  34. package/dist/routes.js +2 -1
  35. package/dist/start-studio.d.ts +5 -7
  36. package/dist/start-studio.js +4 -6
  37. package/package.json +6 -6
  38. package/dist/preview-server/routes/delete-effect-keyframe.d.ts +0 -3
  39. package/dist/preview-server/routes/delete-effect-keyframe.js +0 -89
  40. package/dist/preview-server/routes/delete-sequence-keyframe.d.ts +0 -3
  41. package/dist/preview-server/routes/delete-sequence-keyframe.js +0 -82
  42. package/dist/preview-server/routes/save-props-mutex.d.ts +0 -1
  43. package/dist/preview-server/routes/save-props-mutex.js +0 -11
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { ApiRoutes, CopyStillToClipboardRequest, getDefaultOutLocation, OpenInFi
2
2
  export type { AggregateRenderProgress, BundlingState, CopyingState, DownloadProgress, HotMiddlewareOptions, JobProgressCallback, ModuleMap, PackageManager, ProjectInfo, RenderingProgressInput, RenderJob, RenderJobWithCleanup, RequiredChromiumOptions, StitchingProgressInput, UiOpenGlOptions, } from '@remotion/studio-shared';
3
3
  import { AnsiDiff } from './ansi-diff';
4
4
  export declare const StudioServerInternals: {
5
- startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, maxTimelineTracks, remotionRoot, keyboardShortcutsEnabled, relativePublicDir, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, bufferStateDelayInMilliseconds, binariesDirectory, forceIPv4, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, askAIEnabled, interactivityEnabled, forceNew, rspack, getStudioRuntimeConfig, }: {
5
+ startStudio: ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, remotionRoot, relativePublicDir, bundlerOverride, rspackOverride, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, binariesDirectory, forceIPv4, getAudioLatencyHint, getPreviewSampleRate, enableCrossSiteIsolation, forceNew, rspack, getStudioRuntimeConfig, configFile, }: {
6
6
  browserArgs: string;
7
7
  browserFlag: string;
8
8
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
@@ -11,11 +11,10 @@ export declare const StudioServerInternals: {
11
11
  getCurrentInputProps: () => object;
12
12
  getEnvVariables: () => Record<string, string>;
13
13
  desiredPort: number | null;
14
- maxTimelineTracks: number | null;
15
- bufferStateDelayInMilliseconds: number | null;
16
14
  remotionRoot: string;
17
- keyboardShortcutsEnabled: boolean;
18
15
  relativePublicDir: string | null;
16
+ bundlerOverride: import("@remotion/bundler").BundlerOverrideFn;
17
+ rspackOverride: import("@remotion/bundler").RspackOverrideFn;
19
18
  webpackOverride: import("@remotion/bundler").WebpackOverrideFn;
20
19
  poll: number | null;
21
20
  getRenderDefaults: () => import("@remotion/studio-shared").RenderDefaults;
@@ -29,11 +28,10 @@ export declare const StudioServerInternals: {
29
28
  gitSource: import("@remotion/studio-shared").GitSource | null;
30
29
  binariesDirectory: string | null;
31
30
  forceIPv4: boolean;
32
- askAIEnabled: boolean;
33
- interactivityEnabled: boolean;
34
31
  forceNew: boolean;
35
32
  rspack: boolean;
36
33
  getStudioRuntimeConfig: () => import("@remotion/studio-shared").StudioRuntimeConfig;
34
+ configFile: string | null;
37
35
  }) => Promise<import("./start-studio").StartStudioResult>;
38
36
  getRemotionVersion: () => any;
39
37
  waitForLiveEventsListener: () => Promise<import("./preview-server/live-events").LiveEventsServer>;
@@ -115,6 +113,7 @@ export declare const StudioServerInternals: {
115
113
  version: string;
116
114
  additionalArgs: string[];
117
115
  }) => string[];
116
+ getPackageManagerSpawnOptions: () => Pick<import("child_process").SpawnOptionsWithoutStdio, "shell">;
118
117
  addCompletedClientRender: ({ render, remotionRoot, }: {
119
118
  render: import("@remotion/studio-shared").CompletedClientRender;
120
119
  remotionRoot: string;
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ const file_watcher_1 = require("./file-watcher");
13
13
  const get_latest_remotion_version_1 = require("./get-latest-remotion-version");
14
14
  const get_installed_dependencies_1 = require("./helpers/get-installed-dependencies");
15
15
  const install_command_1 = require("./helpers/install-command");
16
+ const package_manager_spawn_options_1 = require("./helpers/package-manager-spawn-options");
16
17
  const max_timeline_tracks_1 = require("./max-timeline-tracks");
17
18
  const get_package_manager_1 = require("./preview-server/get-package-manager");
18
19
  const live_events_1 = require("./preview-server/live-events");
@@ -41,6 +42,7 @@ exports.StudioServerInternals = {
41
42
  getInstalledDependencies: get_installed_dependencies_1.getInstalledDependencies,
42
43
  getInstalledDependenciesWithVersions: get_installed_dependencies_1.getInstalledDependenciesWithVersions,
43
44
  getInstallCommand: install_command_1.getInstallCommand,
45
+ getPackageManagerSpawnOptions: package_manager_spawn_options_1.getPackageManagerSpawnOptions,
44
46
  addCompletedClientRender: client_render_queue_1.addCompletedClientRender,
45
47
  getCompletedClientRenders: client_render_queue_1.getCompletedClientRenders,
46
48
  removeCompletedClientRender: client_render_queue_1.removeCompletedClientRender,
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.registerOpenBrowserShortcut = void 0;
37
37
  const readline = __importStar(require("node:readline"));
38
38
  const renderer_1 = require("@remotion/renderer");
39
+ const better_opn_1 = require("./better-opn");
39
40
  const maybe_open_browser_1 = require("./maybe-open-browser");
40
41
  const live_events_1 = require("./preview-server/live-events");
41
42
  const registerOpenBrowserShortcut = ({ browserArgs, browserFlag, url, logLevel, }) => {
@@ -64,30 +65,39 @@ const registerOpenBrowserShortcut = ({ browserArgs, browserFlag, url, logLevel,
64
65
  process.stdin.pause();
65
66
  }
66
67
  };
67
- const openStudio = () => {
68
+ const openStudio = async () => {
68
69
  if (isOpeningBrowser) {
69
70
  return;
70
71
  }
71
72
  isOpeningBrowser = true;
72
73
  (0, live_events_1.clearPrintPortMessageTimeout)();
73
- (0, maybe_open_browser_1.maybeOpenBrowser)({
74
- browserArgs,
75
- browserFlag,
76
- shouldOpenBrowser: true,
77
- url,
78
- logLevel,
79
- })
80
- .then((result) => {
74
+ try {
75
+ const didFocus = await (0, better_opn_1.focusBrowserTabByOrigin)({
76
+ url,
77
+ browserArgs,
78
+ browserFlag,
79
+ });
80
+ if (didFocus) {
81
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Opened ${url} in browser`));
82
+ return;
83
+ }
84
+ const result = await (0, maybe_open_browser_1.maybeOpenBrowser)({
85
+ browserArgs,
86
+ browserFlag,
87
+ shouldOpenBrowser: true,
88
+ url,
89
+ logLevel,
90
+ });
81
91
  if (result.didOpenBrowser) {
82
- renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, `Opened ${url} in browser`);
92
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Opened ${url} in browser`));
83
93
  }
84
- })
85
- .catch((err) => {
94
+ }
95
+ catch (err) {
86
96
  renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, 'Could not open browser:', err);
87
- })
88
- .finally(() => {
97
+ }
98
+ finally {
89
99
  isOpeningBrowser = false;
90
- });
100
+ }
91
101
  };
92
102
  function onKeypress(_str, key) {
93
103
  if ((key === null || key === void 0 ? void 0 : key.ctrl) && key.name === 'c') {
@@ -98,7 +108,7 @@ const registerOpenBrowserShortcut = ({ browserArgs, browserFlag, url, logLevel,
98
108
  if ((key === null || key === void 0 ? void 0 : key.meta) || (key === null || key === void 0 ? void 0 : key.ctrl) || (key === null || key === void 0 ? void 0 : key.name) !== 's') {
99
109
  return;
100
110
  }
101
- openStudio();
111
+ openStudio().catch(() => undefined);
102
112
  }
103
113
  readline.emitKeypressEvents(process.stdin);
104
114
  process.stdin.setRawMode(true);
@@ -8,6 +8,7 @@ const add_render_1 = require("./routes/add-render");
8
8
  const add_sequence_keyframe_1 = require("./routes/add-sequence-keyframe");
9
9
  const apply_codemod_1 = require("./routes/apply-codemod");
10
10
  const apply_visual_control_change_1 = require("./routes/apply-visual-control-change");
11
+ const batch_update_keyframe_settings_1 = require("./routes/batch-update-keyframe-settings");
11
12
  const cancel_render_1 = require("./routes/cancel-render");
12
13
  const composition_component_info_1 = require("./routes/composition-component-info");
13
14
  const convert_figma_clipboard_to_svg_1 = require("./routes/convert-figma-clipboard-to-svg");
@@ -49,6 +50,7 @@ const update_available_1 = require("./routes/update-available");
49
50
  const update_default_props_1 = require("./routes/update-default-props");
50
51
  const update_effect_keyframe_settings_1 = require("./routes/update-effect-keyframe-settings");
51
52
  const update_element_install_target_1 = require("./routes/update-element-install-target");
53
+ const update_public_license_1 = require("./routes/update-public-license");
52
54
  const update_sequence_keyframe_settings_1 = require("./routes/update-sequence-keyframe-settings");
53
55
  exports.allApiRoutes = {
54
56
  '/api/composition-component-info': composition_component_info_1.compositionComponentInfoHandler,
@@ -82,6 +84,7 @@ exports.allApiRoutes = {
82
84
  '/api/add-keyframes': add_keyframes_1.addKeyframesHandler,
83
85
  '/api/update-sequence-keyframe-settings': update_sequence_keyframe_settings_1.updateSequenceKeyframeSettingsHandler,
84
86
  '/api/update-effect-keyframe-settings': update_effect_keyframe_settings_1.updateEffectKeyframeSettingsHandler,
87
+ '/api/batch-update-keyframe-settings': batch_update_keyframe_settings_1.batchUpdateKeyframeSettingsHandler,
85
88
  '/api/delete-effect': delete_effect_1.deleteEffectHandler,
86
89
  '/api/paste-effects': paste_effects_1.pasteEffectsHandler,
87
90
  '/api/delete-jsx-node': delete_jsx_node_1.deleteJsxNodeHandler,
@@ -92,6 +95,7 @@ exports.allApiRoutes = {
92
95
  '/api/delete-static-file': delete_static_file_1.deleteStaticFileHandler,
93
96
  '/api/rename-static-file': rename_static_file_1.renameStaticFileHandler,
94
97
  '/api/restart-studio': restart_studio_1.handleRestartStudio,
98
+ '/api/update-public-license': update_public_license_1.updatePublicLicenseHandler,
95
99
  '/api/install-package': install_dependency_1.handleInstallPackage,
96
100
  '/api/insert-jsx-element': insert_jsx_element_1.insertJsxElementHandler,
97
101
  '/api/insert-element': insert_element_1.insertElementHandler,
@@ -21,4 +21,5 @@ export type ApiHandler<ReqData, ResData> = (params: {
21
21
  methods: QueueMethods;
22
22
  publicDir: string;
23
23
  binariesDirectory: string | null;
24
+ configFile: string | null;
24
25
  }) => Promise<ResData>;
@@ -1,12 +1,13 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
2
  import type { ApiHandler, QueueMethods } from './api-types';
3
- export declare const handleRequest: <Req, Res>({ remotionRoot, request, response, entryPoint, handler, logLevel, methods, binariesDirectory, publicDir, }: {
3
+ export declare const handleRequest: <Req, Res>({ remotionRoot, request, response, entryPoint, handler, logLevel, methods, binariesDirectory, publicDir, configFile, }: {
4
4
  remotionRoot: string;
5
5
  publicDir: string;
6
6
  request: IncomingMessage;
7
7
  response: ServerResponse<IncomingMessage>;
8
8
  entryPoint: string;
9
9
  binariesDirectory: string | null;
10
+ configFile: string | null;
10
11
  handler: ApiHandler<Req, Res>;
11
12
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
12
13
  methods: QueueMethods;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleRequest = void 0;
4
4
  const parse_body_1 = require("./parse-body");
5
5
  const validate_same_origin_1 = require("./validate-same-origin");
6
- const handleRequest = async ({ remotionRoot, request, response, entryPoint, handler, logLevel, methods, binariesDirectory, publicDir, }) => {
6
+ const handleRequest = async ({ remotionRoot, request, response, entryPoint, handler, logLevel, methods, binariesDirectory, publicDir, configFile, }) => {
7
7
  if (request.method === 'OPTIONS') {
8
8
  response.statusCode = 200;
9
9
  response.end();
@@ -24,6 +24,7 @@ const handleRequest = async ({ remotionRoot, request, response, entryPoint, hand
24
24
  methods,
25
25
  binariesDirectory,
26
26
  publicDir,
27
+ configFile,
27
28
  });
28
29
  response.end(JSON.stringify({
29
30
  success: true,
@@ -0,0 +1,7 @@
1
+ import type { BatchUpdateKeyframeSettingsRequest, BatchUpdateKeyframeSettingsResponse } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const batchUpdateKeyframeSettings: ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }: BatchUpdateKeyframeSettingsRequest & {
4
+ remotionRoot: string;
5
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
6
+ }) => Promise<void>;
7
+ export declare const batchUpdateKeyframeSettingsHandler: ApiHandler<BatchUpdateKeyframeSettingsRequest, BatchUpdateKeyframeSettingsResponse>;
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.batchUpdateKeyframeSettingsHandler = exports.batchUpdateKeyframeSettings = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const renderer_1 = require("@remotion/renderer");
6
+ const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
7
+ const file_watcher_1 = require("../../file-watcher");
8
+ const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
9
+ const undo_stack_1 = require("../undo-stack");
10
+ const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
11
+ const log_effect_update_1 = require("./log-updates/log-effect-update");
12
+ const log_update_1 = require("./log-updates/log-update");
13
+ const source_file_write_queue_1 = require("./source-file-write-queue");
14
+ const groupBy = (items, getKey) => {
15
+ var _a;
16
+ const groups = new Map();
17
+ for (const item of items) {
18
+ const key = getKey(item);
19
+ const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : [];
20
+ group.push(item);
21
+ groups.set(key, group);
22
+ }
23
+ return [...groups.values()];
24
+ };
25
+ const toOperation = (settings) => settings.type === 'settings'
26
+ ? {
27
+ type: 'settings',
28
+ clamping: settings.clamping,
29
+ posterize: settings.posterize,
30
+ output: settings.output,
31
+ }
32
+ : {
33
+ type: 'easing',
34
+ segmentIndex: settings.segmentIndex,
35
+ easing: settings.easing,
36
+ };
37
+ const batchUpdateKeyframeSettings = async ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }) => {
38
+ var _a, _b;
39
+ const totalUpdates = sequenceKeyframes.length + effectKeyframes.length;
40
+ if (totalUpdates === 0) {
41
+ throw new Error('No keyframe settings updates were specified');
42
+ }
43
+ const fileGroups = new Map();
44
+ for (const update of sequenceKeyframes) {
45
+ const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
46
+ remotionRoot,
47
+ fileName: update.fileName,
48
+ action: 'modify',
49
+ });
50
+ const group = (_a = fileGroups.get(absolutePath)) !== null && _a !== void 0 ? _a : {
51
+ sequenceKeyframes: [],
52
+ effectKeyframes: [],
53
+ };
54
+ group.sequenceKeyframes.push({ ...update, fileRelativeToRoot });
55
+ fileGroups.set(absolutePath, group);
56
+ }
57
+ for (const update of effectKeyframes) {
58
+ const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
59
+ remotionRoot,
60
+ fileName: update.fileName,
61
+ action: 'modify',
62
+ });
63
+ const group = (_b = fileGroups.get(absolutePath)) !== null && _b !== void 0 ? _b : {
64
+ sequenceKeyframes: [],
65
+ effectKeyframes: [],
66
+ };
67
+ group.effectKeyframes.push({ ...update, fileRelativeToRoot });
68
+ fileGroups.set(absolutePath, group);
69
+ }
70
+ const snapshots = [];
71
+ const sequenceLogs = [];
72
+ const effectLogs = [];
73
+ for (const [absolutePath, group] of fileGroups) {
74
+ const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
75
+ let output = fileContents;
76
+ let firstLogLine = Number.POSITIVE_INFINITY;
77
+ for (const updates of groupBy(group.sequenceKeyframes, (update) => JSON.stringify(update.nodePath.nodePath))) {
78
+ const firstUpdate = updates[0];
79
+ const result = await (0, update_keyframes_1.updateSequenceKeyframes)({
80
+ input: output,
81
+ nodePath: firstUpdate.nodePath.nodePath,
82
+ schema: firstUpdate.schema,
83
+ videoConfigValues: firstUpdate.nodePath.videoConfigValues,
84
+ updates: updates.map((update) => ({
85
+ key: update.key,
86
+ operation: toOperation(update.settings),
87
+ })),
88
+ });
89
+ output = result.output;
90
+ firstLogLine = Math.min(firstLogLine, result.logLine);
91
+ for (const [index, update] of updates.entries()) {
92
+ sequenceLogs.push({
93
+ fileRelativeToRoot: update.fileRelativeToRoot,
94
+ line: result.logLine,
95
+ key: update.key,
96
+ oldValueString: result.oldValueStrings[index],
97
+ newValueString: result.newValueStrings[index],
98
+ formatted: result.formatted,
99
+ });
100
+ }
101
+ }
102
+ for (const updates of groupBy(group.effectKeyframes, (update) => `${JSON.stringify(update.sequenceNodePath.nodePath)}:${update.effectIndex}`)) {
103
+ const firstUpdate = updates[0];
104
+ const result = await (0, update_keyframes_1.updateEffectKeyframes)({
105
+ input: output,
106
+ sequenceNodePath: firstUpdate.sequenceNodePath.nodePath,
107
+ effectIndex: firstUpdate.effectIndex,
108
+ schema: firstUpdate.schema,
109
+ videoConfigValues: firstUpdate.sequenceNodePath.videoConfigValues,
110
+ updates: updates.map((update) => ({
111
+ key: update.key,
112
+ operation: toOperation(update.settings),
113
+ })),
114
+ });
115
+ output = result.output;
116
+ firstLogLine = Math.min(firstLogLine, result.logLine);
117
+ for (const [index, update] of updates.entries()) {
118
+ effectLogs.push({
119
+ fileRelativeToRoot: update.fileRelativeToRoot,
120
+ line: result.logLine,
121
+ effectName: result.effectCallee,
122
+ propKey: update.key,
123
+ oldValueString: result.oldValueStrings[index],
124
+ newValueString: result.newValueStrings[index],
125
+ formatted: result.formatted,
126
+ });
127
+ }
128
+ }
129
+ snapshots.push({
130
+ filePath: absolutePath,
131
+ oldContents: fileContents,
132
+ newContents: output,
133
+ logLine: Number.isFinite(firstLogLine) ? firstLogLine : 1,
134
+ });
135
+ }
136
+ (0, undo_stack_1.pushTransactionToUndoStack)({
137
+ snapshots,
138
+ logLevel,
139
+ remotionRoot,
140
+ description: totalUpdates === 1
141
+ ? {
142
+ undoMessage: '↩️ Keyframe settings reverted',
143
+ redoMessage: '↪️ Keyframe settings updated',
144
+ }
145
+ : {
146
+ undoMessage: `↩️ ${totalUpdates} keyframe settings reverted`,
147
+ redoMessage: `↪️ ${totalUpdates} keyframe settings updated`,
148
+ },
149
+ entryType: sequenceKeyframes.length > 0 ? 'sequence-props' : 'effect-props',
150
+ suppressHmrOnFileRestore: true,
151
+ });
152
+ for (const snapshot of snapshots) {
153
+ (0, undo_stack_1.suppressUndoStackInvalidation)(snapshot.filePath);
154
+ (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
155
+ (0, file_watcher_1.writeFileAndNotifyFileWatchers)(snapshot.filePath, snapshot.newContents, clientId);
156
+ }
157
+ for (const log of sequenceLogs) {
158
+ (0, log_update_1.logUpdate)({
159
+ ...log,
160
+ defaultValueString: null,
161
+ logLevel,
162
+ removedProps: [],
163
+ addedProps: [],
164
+ });
165
+ }
166
+ for (const log of effectLogs) {
167
+ (0, log_effect_update_1.logEffectUpdate)({
168
+ ...log,
169
+ defaultValueString: null,
170
+ logLevel,
171
+ removedProps: [],
172
+ addedProps: [],
173
+ });
174
+ }
175
+ (0, undo_stack_1.printUndoHint)(logLevel);
176
+ };
177
+ exports.batchUpdateKeyframeSettings = batchUpdateKeyframeSettings;
178
+ const batchUpdateKeyframeSettingsHandler = ({ input, remotionRoot, logLevel }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
179
+ renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[batch-update-keyframe-settings] Received ${input.sequenceKeyframes.length + input.effectKeyframes.length} update(s)`);
180
+ await (0, exports.batchUpdateKeyframeSettings)({
181
+ ...input,
182
+ remotionRoot,
183
+ logLevel,
184
+ });
185
+ return { success: true };
186
+ });
187
+ exports.batchUpdateKeyframeSettingsHandler = batchUpdateKeyframeSettingsHandler;
@@ -40,6 +40,7 @@ const studio_shared_1 = require("@remotion/studio-shared");
40
40
  const recast = __importStar(require("recast"));
41
41
  const no_react_1 = require("remotion/no-react");
42
42
  const parse_ast_1 = require("../../codemods/parse-ast");
43
+ const css_shorthand_properties_1 = require("../../helpers/css-shorthand-properties");
43
44
  const get_ast_node_path_1 = require("../../helpers/get-ast-node-path");
44
45
  const import_agnostic_node_path_1 = require("../../helpers/import-agnostic-node-path");
45
46
  const parse_keyframe_easing_expression_1 = require("../../helpers/parse-keyframe-easing-expression");
@@ -669,6 +670,15 @@ const validateStyleValue = (childKey, value) => {
669
670
  }
670
671
  return true;
671
672
  };
673
+ const getObjectPropertyName = (property) => {
674
+ if (property.key.type === 'Identifier') {
675
+ return property.key.name;
676
+ }
677
+ if (property.key.type === 'StringLiteral') {
678
+ return property.key.value;
679
+ }
680
+ return null;
681
+ };
672
682
  const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfigValues, allowSpecialValues, }) => {
673
683
  const attr = jsxElement.attributes.find((a) => a.type !== 'JSXSpreadAttribute' &&
674
684
  a.name.type !== 'JSXNamespacedName' &&
@@ -687,9 +697,50 @@ const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfig
687
697
  return computedStatus();
688
698
  }
689
699
  const objExpr = expression;
690
- const prop = objExpr.properties.find((p) => p.type === 'ObjectProperty' &&
691
- ((p.key.type === 'Identifier' && p.key.name === childKey) ||
692
- (p.key.type === 'StringLiteral' && p.key.value === childKey)));
700
+ const cssShorthand = (0, css_shorthand_properties_1.getCssShorthandForLonghand)({
701
+ parentKey,
702
+ longhand: childKey,
703
+ });
704
+ if (cssShorthand &&
705
+ objExpr.properties.some((property) => {
706
+ if (property.type !== 'ObjectProperty') {
707
+ return false;
708
+ }
709
+ const propertyName = getObjectPropertyName(property);
710
+ return (propertyName !== null &&
711
+ cssShorthand.isUnsupportedProperty(propertyName));
712
+ })) {
713
+ return computedStatus();
714
+ }
715
+ let prop;
716
+ for (let index = objExpr.properties.length - 1; index >= 0; index--) {
717
+ const candidate = objExpr.properties[index];
718
+ if (candidate.type === 'SpreadElement') {
719
+ return computedStatus();
720
+ }
721
+ if (candidate.type === 'ObjectProperty' &&
722
+ (getObjectPropertyName(candidate) === childKey ||
723
+ getObjectPropertyName(candidate) === (cssShorthand === null || cssShorthand === void 0 ? void 0 : cssShorthand.shorthand))) {
724
+ prop = candidate;
725
+ break;
726
+ }
727
+ }
728
+ if (prop &&
729
+ cssShorthand &&
730
+ getObjectPropertyName(prop) === cssShorthand.shorthand) {
731
+ const shorthandValue = prop.value;
732
+ if (!(0, exports.isStaticValue)(shorthandValue, { allowSpecialValues: false })) {
733
+ return computedStatus();
734
+ }
735
+ const staticShorthandValue = (0, exports.extractStaticValue)(shorthandValue, {
736
+ allowSpecialValues: false,
737
+ });
738
+ if (typeof staticShorthandValue !== 'string') {
739
+ return computedStatus();
740
+ }
741
+ const parsed = cssShorthand.parse(staticShorthandValue);
742
+ return parsed ? staticStatus(parsed[childKey], null) : computedStatus();
743
+ }
693
744
  if (!prop) {
694
745
  // Property not set in the object, can be added
695
746
  return staticStatus(undefined, null);
@@ -263,6 +263,7 @@ const downloadRemoteAssetHandler = async ({ input, publicDir, request }) => {
263
263
  src: assetPath,
264
264
  srcType: 'static',
265
265
  dimensions: fileType.dimensions,
266
+ durationInFrames: null,
266
267
  position: null,
267
268
  };
268
269
  return {
@@ -69,10 +69,14 @@ const validateElement = (element) => {
69
69
  }
70
70
  validateDimensions(element.dimensions);
71
71
  };
72
- const insertElementHandler = ({ input: { compositionFile, compositionId, element, position }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
72
+ const insertElementHandler = ({ input: { compositionFile, compositionId, element, from, position }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
73
73
  try {
74
74
  validateElement(element);
75
75
  validatePosition(position);
76
+ if (from !== null &&
77
+ (!Number.isInteger(from) || !Number.isFinite(from) || from < 0)) {
78
+ throw new Error('from must be a non-negative integer');
79
+ }
76
80
  const componentName = (0, studio_shared_1.getElementComponentNameFromSourceCode)(element.sourceCode);
77
81
  if (componentName === null) {
78
82
  throw new Error('Element source must export exactly one named component');
@@ -118,9 +122,11 @@ const insertElementHandler = ({ input: { compositionFile, compositionId, element
118
122
  props: [],
119
123
  position: null,
120
124
  },
125
+ from: null,
121
126
  prettierConfigOverride: null,
122
127
  wrapInSequence: {
123
128
  dimensions: element.dimensions,
129
+ from,
124
130
  name: element.displayName,
125
131
  position,
126
132
  },
@@ -72,6 +72,9 @@ const validateElement = (element, remotionRoot) => {
72
72
  validateDimension('width', element.dimensions.width);
73
73
  validateDimension('height', element.dimensions.height);
74
74
  }
75
+ if (element.durationInFrames !== null) {
76
+ validateDimension('durationInFrames', element.durationInFrames);
77
+ }
75
78
  return;
76
79
  }
77
80
  if (element.type === 'component') {
@@ -145,9 +148,13 @@ const getElementLabel = (element) => {
145
148
  }
146
149
  throw new Error('Unsupported element type');
147
150
  };
148
- const insertJsxElementHandler = ({ input: { compositionFile, compositionId, element }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
151
+ const insertJsxElementHandler = ({ input: { compositionFile, compositionId, element, from }, remotionRoot, logLevel, }) => (0, source_file_write_queue_1.withSourceFileWriteQueue)(async () => {
149
152
  try {
150
153
  validateElement(element, remotionRoot);
154
+ if (from !== null &&
155
+ (!Number.isInteger(from) || !Number.isFinite(from) || from < 0)) {
156
+ throw new Error('from must be a non-negative integer');
157
+ }
151
158
  const elementLabel = getElementLabel(element);
152
159
  renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[insert-jsx-element] Received request for compositionFile="${compositionFile}" compositionId="${compositionId}" element="${element.type}"`);
153
160
  const { fileName, source, oldContents, output, formatted, logLine } = await (0, resolve_composition_component_1.insertJsxElementIntoComposition)({
@@ -155,6 +162,7 @@ const insertJsxElementHandler = ({ input: { compositionFile, compositionId, elem
155
162
  compositionFile,
156
163
  compositionId,
157
164
  element,
165
+ from,
158
166
  prettierConfigOverride: null,
159
167
  });
160
168
  (0, undo_stack_1.pushToUndoStack)({
@@ -6,6 +6,7 @@ const renderer_1 = require("@remotion/renderer");
6
6
  const studio_shared_1 = require("@remotion/studio-shared");
7
7
  const version_1 = require("remotion/version");
8
8
  const install_command_1 = require("../../helpers/install-command");
9
+ const package_manager_spawn_options_1 = require("../../helpers/package-manager-spawn-options");
9
10
  const get_package_manager_1 = require("../get-package-manager");
10
11
  const getExtraPackageVersion = (packageName) => {
11
12
  const pkg = studio_shared_1.extraPackages.find((p) => p.name === packageName);
@@ -52,7 +53,10 @@ const handleInstallPackage = async ({ logLevel, remotionRoot, input: { packageNa
52
53
  const time = Date.now();
53
54
  try {
54
55
  await new Promise((resolve, reject) => {
55
- const cmd = (0, node_child_process_1.spawn)(manager.manager, command, {});
56
+ const cmd = (0, node_child_process_1.spawn)(manager.manager, command, (0, package_manager_spawn_options_1.getPackageManagerSpawnOptions)());
57
+ cmd.on('error', (err) => {
58
+ reject(err);
59
+ });
56
60
  cmd.stdout.on('data', (d) => {
57
61
  const splitted = d.toString().trim().split('\n');
58
62
  splitted.forEach((line) => {