@remotion/studio-server 4.0.490 → 4.0.491

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 +4 -0
  2. package/dist/better-opn/index.js +152 -31
  3. package/dist/codemods/paste-effects.d.ts +2 -1
  4. package/dist/codemods/paste-effects.js +33 -6
  5. package/dist/codemods/update-keyframes/update-keyframes.d.ts +9 -5
  6. package/dist/codemods/update-keyframes/update-keyframes.js +88 -42
  7. package/dist/codemods/update-nested-prop.d.ts +3 -2
  8. package/dist/codemods/update-nested-prop.js +17 -4
  9. package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +6 -3
  10. package/dist/codemods/update-sequence-props/update-sequence-props.js +51 -10
  11. package/dist/helpers/video-config-numeric-expression.d.ts +12 -0
  12. package/dist/helpers/video-config-numeric-expression.js +152 -0
  13. package/dist/helpers/video-config-values.d.ts +7 -0
  14. package/dist/helpers/video-config-values.js +84 -0
  15. package/dist/index.d.ts +1 -2
  16. package/dist/preview-server/element-install-state.d.ts +1 -0
  17. package/dist/preview-server/routes/add-effect-keyframe.js +6 -0
  18. package/dist/preview-server/routes/add-keyframes.js +2 -0
  19. package/dist/preview-server/routes/add-sequence-keyframe.js +2 -0
  20. package/dist/preview-server/routes/apply-codemod.d.ts +1 -0
  21. package/dist/preview-server/routes/apply-codemod.js +62 -13
  22. package/dist/preview-server/routes/can-update-effect-props.d.ts +8 -4
  23. package/dist/preview-server/routes/can-update-effect-props.js +26 -5
  24. package/dist/preview-server/routes/can-update-sequence-props.d.ts +9 -5
  25. package/dist/preview-server/routes/can-update-sequence-props.js +71 -30
  26. package/dist/preview-server/routes/delete-keyframes.js +8 -0
  27. package/dist/preview-server/routes/move-keyframes.js +2 -0
  28. package/dist/preview-server/routes/paste-effects.js +2 -1
  29. package/dist/preview-server/routes/save-effect-props.js +5 -0
  30. package/dist/preview-server/routes/save-sequence-props.js +4 -0
  31. package/dist/preview-server/routes/subscribe-to-sequence-props.js +2 -1
  32. package/dist/preview-server/routes/unsubscribe-from-sequence-props.js +1 -0
  33. package/dist/preview-server/routes/update-effect-keyframe-settings.js +6 -0
  34. package/dist/preview-server/routes/update-element-install-target.js +15 -1
  35. package/dist/preview-server/routes/update-sequence-keyframe-settings.js +2 -0
  36. package/dist/preview-server/sequence-props-watchers.d.ts +5 -3
  37. package/dist/preview-server/sequence-props-watchers.js +14 -5
  38. package/dist/preview-server/start-server.d.ts +0 -1
  39. package/dist/preview-server/start-server.js +0 -1
  40. package/dist/routes.js +2 -0
  41. package/dist/start-studio.d.ts +1 -2
  42. package/dist/start-studio.js +1 -2
  43. package/package.json +6 -6
@@ -1,4 +1,8 @@
1
1
  export declare const getChromiumBrowsersToTry: (processes: string) => ("Arc" | "Brave Browser" | "Chromium" | "Google Chrome" | "Google Chrome Canary" | "Microsoft Edge" | "Vivaldi")[];
2
+ export declare const getFocusBrowserTabAppleScript: (chromiumBrowser: "Arc" | "Brave Browser" | "Chromium" | "Google Chrome" | "Google Chrome Canary" | "Microsoft Edge" | "Vivaldi") => string;
3
+ export declare const focusBrowserTab: ({ url }: {
4
+ url: string;
5
+ }) => Promise<boolean>;
2
6
  export declare const openBrowser: ({ url, browserFlag, browserArgs, }: {
3
7
  url: string;
4
8
  browserFlag: string | undefined;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // Copied from https://github.com/michaellzc/better-opn#readme
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.openBrowser = exports.getChromiumBrowsersToTry = void 0;
4
+ exports.openBrowser = exports.focusBrowserTab = exports.getFocusBrowserTabAppleScript = exports.getChromiumBrowsersToTry = void 0;
5
5
  const node_child_process_1 = require("node:child_process");
6
6
  const open = require("open");
7
7
  const supportedChromiumBrowsers = [
@@ -21,6 +21,69 @@ const getChromiumBrowsersToTry = (processes) => {
21
21
  return supportedChromiumBrowsers.filter((browser) => processNames.has(browser));
22
22
  };
23
23
  exports.getChromiumBrowsersToTry = getChromiumBrowsersToTry;
24
+ const CHILD_PROCESS_TIMEOUT_IN_MILLISECONDS = 10000;
25
+ const getRunningChromiumBrowsers = async () => {
26
+ const processes = await new Promise((resolve, reject) => {
27
+ (0, node_child_process_1.exec)('ps -cax -o comm=', { timeout: CHILD_PROCESS_TIMEOUT_IN_MILLISECONDS }, (err, stdout) => {
28
+ if (err) {
29
+ reject(err);
30
+ }
31
+ else {
32
+ resolve(stdout);
33
+ }
34
+ });
35
+ });
36
+ return (0, exports.getChromiumBrowsersToTry)(processes);
37
+ };
38
+ const runAppleScript = ({ appleScript, args, }) => {
39
+ return new Promise((resolve, reject) => {
40
+ const proc = (0, node_child_process_1.spawn)('osascript', ['-', ...args]);
41
+ const stdoutChunks = [];
42
+ const stderrChunks = [];
43
+ let settled = false;
44
+ const timeout = setTimeout(() => {
45
+ if (settled) {
46
+ return;
47
+ }
48
+ settled = true;
49
+ proc.kill();
50
+ reject(new Error('osascript timed out'));
51
+ }, CHILD_PROCESS_TIMEOUT_IN_MILLISECONDS);
52
+ const rejectOnce = (error) => {
53
+ if (settled) {
54
+ return;
55
+ }
56
+ settled = true;
57
+ clearTimeout(timeout);
58
+ proc.kill();
59
+ reject(error);
60
+ };
61
+ proc.stdout.on('data', (chunk) => stdoutChunks.push(chunk));
62
+ proc.stderr.on('data', (chunk) => stderrChunks.push(chunk));
63
+ proc.stdin.on('error', rejectOnce);
64
+ proc.on('error', rejectOnce);
65
+ proc.on('close', (code) => {
66
+ if (settled) {
67
+ return;
68
+ }
69
+ settled = true;
70
+ clearTimeout(timeout);
71
+ const stdout = Buffer.concat(stdoutChunks).toString('utf8');
72
+ if (code === 0) {
73
+ resolve(stdout);
74
+ return;
75
+ }
76
+ const stderr = Buffer.concat(stderrChunks).toString('utf8').trim();
77
+ reject(new Error(stderr || `osascript exited with code ${code}`));
78
+ });
79
+ proc.stdin.end(appleScript);
80
+ });
81
+ };
82
+ const isAppleScriptPermissionError = (error) => {
83
+ const message = error.message.toLowerCase();
84
+ return (message.includes('not authorised to send apple events') ||
85
+ message.includes('not authorized to send apple events'));
86
+ };
24
87
  const normalizeURLToMatch = (target) => {
25
88
  // We may encounter URL parse error but want to fallback to default behavior
26
89
  try {
@@ -33,6 +96,87 @@ const normalizeURLToMatch = (target) => {
33
96
  return target;
34
97
  }
35
98
  };
99
+ const getFocusBrowserTabAppleScript = (chromiumBrowser) => {
100
+ return `
101
+ property targetTabIndex: -1
102
+ property targetWindow: null
103
+ property theProgram: "${chromiumBrowser}"
104
+
105
+ on run argv
106
+ set targetURL to item 1 of argv
107
+
108
+ using terms from application "Google Chrome"
109
+ tell application theProgram
110
+ set found to my lookupTabWithUrl(targetURL)
111
+ if not found then
112
+ return false
113
+ end if
114
+
115
+ set targetWindow's active tab index to targetTabIndex
116
+ set index of targetWindow to 1
117
+ activate
118
+ return true
119
+ end tell
120
+ end using terms from
121
+ end run
122
+
123
+ on lookupTabWithUrl(lookupUrl)
124
+ using terms from application "Google Chrome"
125
+ tell application theProgram
126
+ set found to false
127
+ repeat with theWindow in every window
128
+ set theTabIndex to 0
129
+ repeat with theTab in every tab of theWindow
130
+ set theTabIndex to theTabIndex + 1
131
+ if (theTab's URL as string) is lookupUrl then
132
+ set targetTabIndex to theTabIndex
133
+ set targetWindow to theWindow
134
+ set found to true
135
+ exit repeat
136
+ end if
137
+ end repeat
138
+
139
+ if found then
140
+ exit repeat
141
+ end if
142
+ end repeat
143
+ end tell
144
+ end using terms from
145
+ return found
146
+ end lookupTabWithUrl
147
+ `.trim();
148
+ };
149
+ exports.getFocusBrowserTabAppleScript = getFocusBrowserTabAppleScript;
150
+ const focusBrowserTab = async ({ url }) => {
151
+ if (process.platform !== 'darwin') {
152
+ return false;
153
+ }
154
+ let browsersToTry;
155
+ try {
156
+ browsersToTry = await getRunningChromiumBrowsers();
157
+ }
158
+ catch (_a) {
159
+ return false;
160
+ }
161
+ for (const chromiumBrowser of browsersToTry) {
162
+ try {
163
+ const result = await runAppleScript({
164
+ appleScript: (0, exports.getFocusBrowserTabAppleScript)(chromiumBrowser),
165
+ args: [url],
166
+ });
167
+ if (result.trim() === 'true') {
168
+ return true;
169
+ }
170
+ }
171
+ catch (error) {
172
+ if (isAppleScriptPermissionError(error)) {
173
+ return false;
174
+ }
175
+ }
176
+ }
177
+ return false;
178
+ };
179
+ exports.focusBrowserTab = focusBrowserTab;
36
180
  // Copy from
37
181
  // https://github.com/facebook/create-react-app/blob/master/packages/react-dev-utils/openBrowser.js#L64
38
182
  const startBrowserProcess = async ({ browser, url, args, }) => {
@@ -43,17 +187,7 @@ const startBrowserProcess = async ({ browser, url, args, }) => {
43
187
  if (shouldTryOpenChromiumWithAppleScript) {
44
188
  let appleScriptDenied = false;
45
189
  // Will use the first open browser found from list
46
- const processes = await new Promise((resolve, reject) => {
47
- (0, node_child_process_1.exec)('ps -cax -o comm=', (err, stdout) => {
48
- if (err) {
49
- reject(err);
50
- }
51
- else {
52
- resolve(stdout);
53
- }
54
- });
55
- });
56
- const browsersToTry = (0, exports.getChromiumBrowsersToTry)(processes);
190
+ const browsersToTry = await getRunningChromiumBrowsers();
57
191
  for (const chromiumBrowser of browsersToTry) {
58
192
  if (appleScriptDenied) {
59
193
  continue;
@@ -74,8 +208,8 @@ const startBrowserProcess = async ({ browser, url, args, }) => {
74
208
  property theProgram: "${chromiumBrowser}"
75
209
 
76
210
  on run argv
77
- set theURL to "${encodeURI(url)}"
78
- set matchURL to "${encodeURI(normalizeURLToMatch(url))}"
211
+ set theURL to item 1 of argv
212
+ set matchURL to item 2 of argv
79
213
 
80
214
  using terms from application "Google Chrome"
81
215
  tell application theProgram
@@ -151,27 +285,14 @@ const startBrowserProcess = async ({ browser, url, args, }) => {
151
285
  return found
152
286
  end lookupTabWithUrl
153
287
  `.trim();
154
- await new Promise((resolve, reject) => {
155
- const proc = (0, node_child_process_1.exec)(`osascript -`, (error) => {
156
- if (error) {
157
- reject(error);
158
- }
159
- else {
160
- // Ignore errors.
161
- // It it breaks, it will fallback to `opn` anyway
162
- resolve();
163
- }
164
- });
165
- proc.stdin.write(appleScript);
166
- proc.stdin.end();
288
+ await runAppleScript({
289
+ appleScript,
290
+ args: [encodeURI(url), encodeURI(normalizeURLToMatch(url))],
167
291
  });
168
292
  return Promise.resolve(true);
169
293
  }
170
294
  catch (error) {
171
- const appleScriptError = error.message;
172
- if (appleScriptError
173
- .toLowerCase()
174
- .includes('not authorised to send apple events')) {
295
+ if (isAppleScriptPermissionError(error)) {
175
296
  appleScriptDenied = true;
176
297
  }
177
298
  // Ignore errors.
@@ -1,11 +1,12 @@
1
1
  import type { EffectClipboardPasteType, EffectClipboardSnapshot } from '@remotion/studio-shared';
2
2
  import type { SequenceNodePath } from 'remotion';
3
- export declare const pasteEffects: ({ input, targetSequenceNodePath, type, effects, prettierConfigOverride, }: {
3
+ export declare const pasteEffects: ({ input, targetSequenceNodePath, type, effects, insertAtIndices, prettierConfigOverride, }: {
4
4
  readonly input: string;
5
5
  readonly targetFileName: string;
6
6
  readonly targetSequenceNodePath: SequenceNodePath;
7
7
  readonly type: EffectClipboardPasteType;
8
8
  readonly effects: EffectClipboardSnapshot[];
9
+ readonly insertAtIndices: number[] | null;
9
10
  readonly prettierConfigOverride?: Record<string, unknown> | null | undefined;
10
11
  }) => Promise<{
11
12
  readonly output: string;
@@ -92,7 +92,7 @@ const removeEffectsAttr = (attributes, attr) => {
92
92
  attributes.splice(index, 1);
93
93
  }
94
94
  };
95
- const pasteEffects = async ({ input, targetSequenceNodePath, type, effects, prettierConfigOverride, }) => {
95
+ const pasteEffects = async ({ input, targetSequenceNodePath, type, effects, insertAtIndices, prettierConfigOverride, }) => {
96
96
  var _a;
97
97
  var _b, _c, _d;
98
98
  const ast = (0, parse_ast_1.parseAst)(input);
@@ -115,6 +115,14 @@ const pasteEffects = async ({ input, targetSequenceNodePath, type, effects, pret
115
115
  const effectCalls = effects.map((effect) => makeEffectCall({ ast, effect, remotionLocalNames }));
116
116
  const effectLabels = effects.map((effect) => `${effect.callee}()`);
117
117
  const existingAttr = (0, update_effect_props_1.findEffectsAttr)((_c = targetJsx.attributes) !== null && _c !== void 0 ? _c : []);
118
+ if (insertAtIndices !== null) {
119
+ if (type !== 'effects-additive' ||
120
+ insertAtIndices.length !== effectCalls.length ||
121
+ new Set(insertAtIndices).size !== insertAtIndices.length ||
122
+ insertAtIndices.some((index) => !Number.isInteger(index) || index < 0)) {
123
+ throw new Error('Cannot paste effects: invalid insertion indices');
124
+ }
125
+ }
118
126
  if (type === 'effects-replacing') {
119
127
  if (existingAttr) {
120
128
  removeEffectsAttr(targetJsx.attributes, existingAttr);
@@ -123,14 +131,33 @@ const pasteEffects = async ({ input, targetSequenceNodePath, type, effects, pret
123
131
  targetJsx.attributes.push(makeEffectsAttr(makeEffectsArray(effectCalls)));
124
132
  }
125
133
  }
126
- else if (existingAttr) {
127
- getEffectsArray(existingAttr).elements.push(...effectCalls);
134
+ else if (effectCalls.length === 0) {
135
+ throw new Error('Cannot paste effects: no effects were copied');
128
136
  }
129
- else if (effectCalls.length > 0) {
130
- targetJsx.attributes.push(makeEffectsAttr(makeEffectsArray(effectCalls)));
137
+ else if (insertAtIndices === null) {
138
+ if (existingAttr) {
139
+ getEffectsArray(existingAttr).elements.push(...effectCalls);
140
+ }
141
+ else {
142
+ targetJsx.attributes.push(makeEffectsAttr(makeEffectsArray(effectCalls)));
143
+ }
131
144
  }
132
145
  else {
133
- throw new Error('Cannot paste effects: no effects were copied');
146
+ const elements = existingAttr
147
+ ? getEffectsArray(existingAttr).elements
148
+ : [];
149
+ const indexedCalls = effectCalls
150
+ .map((effect, index) => ({
151
+ effect,
152
+ index: insertAtIndices[index],
153
+ }))
154
+ .sort((left, right) => left.index - right.index);
155
+ for (const indexedCall of indexedCalls) {
156
+ elements.splice(Math.min(indexedCall.index, elements.length), 0, indexedCall.effect);
157
+ }
158
+ if (!existingAttr) {
159
+ targetJsx.attributes.push(makeEffectsAttr(b.arrayExpression(elements)));
160
+ }
134
161
  }
135
162
  const finalFile = (0, parse_ast_1.serializeAst)(ast);
136
163
  const { output, formatted } = await (0, format_file_content_1.formatFileContent)({
@@ -1,5 +1,5 @@
1
1
  import { type KeyframeInterpolationFunction } from '@remotion/studio-shared';
2
- import type { CanUpdateSequencePropStatus, ExtrapolateType, InteractivitySchema, InterpolateOutputOption, SequenceNodePath } from 'remotion';
2
+ import type { CanUpdateSequencePropStatus, ExtrapolateType, InteractivitySchema, InterpolateOutputOption, SequenceNodePath, VideoConfigValues } from 'remotion';
3
3
  type KeyframeEasing = Extract<CanUpdateSequencePropStatus, {
4
4
  status: 'keyframed';
5
5
  }>['easing'][number];
@@ -42,11 +42,12 @@ export type IntroducedKeyframeIdentifiers = {
42
42
  needsFrameHook: boolean;
43
43
  needsEasingImport: boolean;
44
44
  };
45
- export declare const updateSequenceKeyframesAst: ({ input, nodePath, updates, schema, }: {
45
+ export declare const updateSequenceKeyframesAst: ({ input, nodePath, updates, schema, videoConfigValues, }: {
46
46
  input: string;
47
47
  nodePath: SequenceNodePath;
48
48
  updates: SequenceKeyframeUpdate[];
49
49
  schema?: InteractivitySchema | undefined;
50
+ videoConfigValues: VideoConfigValues | null;
50
51
  }) => {
51
52
  serialized: string;
52
53
  oldValueStrings: string[];
@@ -54,12 +55,13 @@ export declare const updateSequenceKeyframesAst: ({ input, nodePath, updates, sc
54
55
  logLine: number;
55
56
  updatedNodePath: SequenceNodePath;
56
57
  };
57
- export declare const updateSequenceKeyframes: ({ input, nodePath, updates, schema, prettierConfigOverride, }: {
58
+ export declare const updateSequenceKeyframes: ({ input, nodePath, updates, schema, prettierConfigOverride, videoConfigValues, }: {
58
59
  input: string;
59
60
  nodePath: SequenceNodePath;
60
61
  updates: SequenceKeyframeUpdate[];
61
62
  schema?: InteractivitySchema | undefined;
62
63
  prettierConfigOverride?: Record<string, unknown> | null | undefined;
64
+ videoConfigValues: VideoConfigValues | null;
63
65
  }) => Promise<{
64
66
  output: string;
65
67
  formatted: boolean;
@@ -68,12 +70,13 @@ export declare const updateSequenceKeyframes: ({ input, nodePath, updates, schem
68
70
  logLine: number;
69
71
  updatedNodePath: SequenceNodePath;
70
72
  }>;
71
- export declare const updateEffectKeyframesAst: ({ input, sequenceNodePath, effectIndex, updates, schema, }: {
73
+ export declare const updateEffectKeyframesAst: ({ input, sequenceNodePath, effectIndex, updates, schema, videoConfigValues, }: {
72
74
  input: string;
73
75
  sequenceNodePath: SequenceNodePath;
74
76
  effectIndex: number;
75
77
  updates: EffectKeyframeUpdate[];
76
78
  schema?: InteractivitySchema | undefined;
79
+ videoConfigValues: VideoConfigValues | null;
77
80
  }) => {
78
81
  serialized: string;
79
82
  oldValueStrings: string[];
@@ -82,13 +85,14 @@ export declare const updateEffectKeyframesAst: ({ input, sequenceNodePath, effec
82
85
  effectCallee: string;
83
86
  updatedSequenceNodePath: SequenceNodePath;
84
87
  };
85
- export declare const updateEffectKeyframes: ({ input, sequenceNodePath, effectIndex, updates, schema, prettierConfigOverride, }: {
88
+ export declare const updateEffectKeyframes: ({ input, sequenceNodePath, effectIndex, updates, schema, prettierConfigOverride, videoConfigValues, }: {
86
89
  input: string;
87
90
  sequenceNodePath: SequenceNodePath;
88
91
  effectIndex: number;
89
92
  updates: EffectKeyframeUpdate[];
90
93
  schema?: InteractivitySchema | undefined;
91
94
  prettierConfigOverride?: Record<string, unknown> | null | undefined;
95
+ videoConfigValues: VideoConfigValues | null;
92
96
  }) => Promise<{
93
97
  output: string;
94
98
  formatted: boolean;