@remotion/studio-server 4.0.534 → 4.0.536

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 (103) hide show
  1. package/dist/file-watcher.js +2 -0
  2. package/dist/helpers/app-discovery.d.ts +9 -0
  3. package/dist/helpers/app-discovery.js +61 -0
  4. package/dist/helpers/open-in-app.d.ts +13 -0
  5. package/dist/helpers/open-in-app.js +72 -0
  6. package/dist/helpers/open-in-editor.js +7 -6
  7. package/dist/helpers/recently-used-apps.d.ts +9 -0
  8. package/dist/helpers/recently-used-apps.js +63 -0
  9. package/dist/helpers/resolve-composition-component.d.ts +1 -2
  10. package/dist/helpers/resolve-composition-component.js +1 -3
  11. package/dist/preview-server/api-routes.js +4 -5
  12. package/dist/preview-server/live-events.d.ts +1 -0
  13. package/dist/preview-server/live-events.js +12 -1
  14. package/dist/preview-server/routes/app-info.d.ts +3 -0
  15. package/dist/preview-server/routes/app-info.js +16 -0
  16. package/dist/preview-server/routes/default-coding-agent.d.ts +1 -2
  17. package/dist/preview-server/routes/default-coding-agent.js +10 -20
  18. package/dist/preview-server/routes/default-editor.js +9 -33
  19. package/dist/preview-server/routes/element-install-plan.js +5 -0
  20. package/dist/preview-server/routes/insert-basic-captions.js +2 -2
  21. package/dist/preview-server/routes/insert-composition-element.js +14 -6
  22. package/dist/preview-server/routes/insert-element.js +46 -14
  23. package/dist/preview-server/routes/open-in-editor.d.ts +1 -1
  24. package/dist/preview-server/routes/open-in-editor.js +2 -56
  25. package/dist/preview-server/routes/redo.js +2 -1
  26. package/dist/preview-server/routes/source-file-write-queue.d.ts +1 -1
  27. package/dist/preview-server/routes/undo.js +2 -1
  28. package/dist/preview-server/routes/update-config.js +12 -5
  29. package/dist/preview-server/studio-protocol/handle-element-library.js +14 -0
  30. package/dist/preview-server/studio-protocol/handle-install.js +2 -1
  31. package/dist/preview-server/undo-stack.js +1 -0
  32. package/dist/preview-server/watch-ignore-next-change.d.ts +1 -0
  33. package/dist/preview-server/watch-ignore-next-change.js +15 -2
  34. package/dist/start-studio.js +6 -3
  35. package/dist/studio-shortcuts.d.ts +13 -0
  36. package/dist/studio-shortcuts.js +257 -0
  37. package/package.json +8 -8
  38. package/dist/canvas-capture/generate-canvas-capture-composition.d.ts +0 -14
  39. package/dist/canvas-capture/generate-canvas-capture-composition.js +0 -239
  40. package/dist/codemods/add-effect.d.ts +0 -1
  41. package/dist/codemods/add-effect.js +0 -8
  42. package/dist/codemods/apply-codemod-to-file.d.ts +0 -7
  43. package/dist/codemods/apply-codemod-to-file.js +0 -171
  44. package/dist/codemods/apply-visual-control.d.ts +0 -8
  45. package/dist/codemods/apply-visual-control.js +0 -89
  46. package/dist/codemods/delete-effect.d.ts +0 -1
  47. package/dist/codemods/delete-effect.js +0 -6
  48. package/dist/codemods/delete-jsx-node.d.ts +0 -22
  49. package/dist/codemods/delete-jsx-node.js +0 -17
  50. package/dist/codemods/delete-jsx-nodes.d.ts +0 -13
  51. package/dist/codemods/delete-jsx-nodes.js +0 -10
  52. package/dist/codemods/duplicate-composition.d.ts +0 -2
  53. package/dist/codemods/duplicate-composition.js +0 -64
  54. package/dist/codemods/duplicate-effect.d.ts +0 -1
  55. package/dist/codemods/duplicate-effect.js +0 -6
  56. package/dist/codemods/duplicate-jsx-node.d.ts +0 -25
  57. package/dist/codemods/duplicate-jsx-node.js +0 -26
  58. package/dist/codemods/format-file-content.d.ts +0 -7
  59. package/dist/codemods/format-file-content.js +0 -80
  60. package/dist/codemods/format-inline-content.d.ts +0 -18
  61. package/dist/codemods/format-inline-content.js +0 -78
  62. package/dist/codemods/insert-video-layers.d.ts +0 -11
  63. package/dist/codemods/insert-video-layers.js +0 -5
  64. package/dist/codemods/recast-mods.d.ts +0 -13
  65. package/dist/codemods/recast-mods.js +0 -902
  66. package/dist/codemods/reorder-effect.d.ts +0 -1
  67. package/dist/codemods/reorder-effect.js +0 -5
  68. package/dist/codemods/reorder-sequence.d.ts +0 -1
  69. package/dist/codemods/reorder-sequence.js +0 -5
  70. package/dist/codemods/simple-diff.d.ts +0 -5
  71. package/dist/codemods/simple-diff.js +0 -39
  72. package/dist/codemods/split-jsx-sequence.d.ts +0 -27
  73. package/dist/codemods/split-jsx-sequence.js +0 -19
  74. package/dist/codemods/split-video-from-audio.d.ts +0 -1
  75. package/dist/codemods/split-video-from-audio.js +0 -5
  76. package/dist/codemods/update-default-props.d.ts +0 -1
  77. package/dist/codemods/update-default-props.js +0 -6
  78. package/dist/codemods/update-inline-caption-patches.d.ts +0 -1
  79. package/dist/codemods/update-inline-caption-patches.js +0 -5
  80. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.d.ts +0 -1
  81. package/dist/codemods/update-keyframes/ensure-imports-and-frame-hook.js +0 -7
  82. package/dist/open-browser-shortcut.d.ts +0 -9
  83. package/dist/open-browser-shortcut.js +0 -121
  84. package/dist/preview-server/hot-middleware/types.d.ts +0 -2
  85. package/dist/preview-server/hot-middleware/types.js +0 -2
  86. package/dist/preview-server/routes/apply-codemod.d.ts +0 -4
  87. package/dist/preview-server/routes/apply-codemod.js +0 -272
  88. package/dist/preview-server/routes/delete-jsx-node.d.ts +0 -3
  89. package/dist/preview-server/routes/delete-jsx-node.js +0 -126
  90. package/dist/preview-server/routes/delete-jsx-nodes.d.ts +0 -3
  91. package/dist/preview-server/routes/delete-jsx-nodes.js +0 -137
  92. package/dist/preview-server/routes/duplicate-jsx-node.d.ts +0 -3
  93. package/dist/preview-server/routes/duplicate-jsx-node.js +0 -118
  94. package/dist/preview-server/routes/insert-jsx-element.d.ts +0 -3
  95. package/dist/preview-server/routes/insert-jsx-element.js +0 -231
  96. package/dist/preview-server/routes/insert-video-layers.d.ts +0 -3
  97. package/dist/preview-server/routes/insert-video-layers.js +0 -68
  98. package/dist/preview-server/routes/split-jsx-sequence.d.ts +0 -3
  99. package/dist/preview-server/routes/split-jsx-sequence.js +0 -117
  100. package/dist/preview-server/routes/update-public-license.d.ts +0 -11
  101. package/dist/preview-server/routes/update-public-license.js +0 -97
  102. package/dist/preview-server/routes/wrap-jsx-node.d.ts +0 -3
  103. package/dist/preview-server/routes/wrap-jsx-node.js +0 -97
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.insertElementHandler = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const codemods_1 = require("@remotion/codemods");
9
10
  const renderer_1 = require("@remotion/renderer");
10
11
  const studio_protocol_1 = require("@remotion/studio-protocol");
11
12
  const add_composition_to_file_1 = require("../../codemods/add-composition-to-file");
@@ -33,10 +34,18 @@ const hasExpectedFileState = ({ expected, actual, }) => {
33
34
  }
34
35
  return actual.sourceHash === expected.sourceHash;
35
36
  };
36
- const insertElementHandler = async ({ input: { compositionFile, compositionId, element, installationName, expectedFileState, from, premountFor, position, overwriteExisting, undoRedoNavigation, newComposition, }, entryPoint, remotionRoot, logLevel, publicDir, }) => {
37
+ const insertElementHandler = async ({ input: { compositionFile, compositionId, captionTarget, element, installationName, expectedFileState, from, position, overwriteExisting, undoRedoNavigation, newComposition, }, entryPoint, remotionRoot, logLevel, publicDir, }) => {
37
38
  var _a;
38
39
  let resolvedAssets;
39
40
  try {
41
+ if (captionTarget !== null &&
42
+ (element.isCaptionStyle !== true ||
43
+ element.installationMode !== 'component-owned-sequence' ||
44
+ newComposition !== null ||
45
+ compositionFile !== null ||
46
+ compositionId !== null)) {
47
+ throw new Error('Invalid caption style installation target');
48
+ }
40
49
  studio_protocol_1.StudioProtocolInternals.assertElementAssets(element.assets);
41
50
  studio_protocol_1.StudioProtocolInternals.assertElementAssetReferences(element);
42
51
  resolvedAssets = await studio_protocol_1.StudioProtocolInternals.resolveElementAssets({
@@ -132,16 +141,21 @@ const insertElementHandler = async ({ input: { compositionFile, compositionId, e
132
141
  [componentFilePath, componentFileContents],
133
142
  ]);
134
143
  }
135
- const installDestination = newComposition === null
144
+ const installDestination = captionTarget !== null
136
145
  ? {
137
- type: 'current-composition',
138
- compositionFile,
139
- compositionId,
146
+ type: 'selected-media',
147
+ compositionFile: captionTarget.fileName,
140
148
  }
141
- : {
142
- type: 'new-composition',
143
- compositionFile,
144
- };
149
+ : newComposition === null
150
+ ? {
151
+ type: 'current-composition',
152
+ compositionFile,
153
+ compositionId,
154
+ }
155
+ : {
156
+ type: 'new-composition',
157
+ compositionFile,
158
+ };
145
159
  const plan = await (0, element_install_plan_1.getElementInstallPlan)({
146
160
  installationName,
147
161
  destination: installDestination,
@@ -223,7 +237,6 @@ const insertElementHandler = async ({ input: { compositionFile, compositionId, e
223
237
  position: componentOwnsSequence ? position : null,
224
238
  },
225
239
  from: componentOwnsSequence ? from : null,
226
- premountFor,
227
240
  prettierConfigOverride: null,
228
241
  wrapInSequence: componentOwnsSequence
229
242
  ? null
@@ -235,10 +248,29 @@ const insertElementHandler = async ({ input: { compositionFile, compositionId, e
235
248
  position,
236
249
  },
237
250
  };
238
- const inserted = await (0, resolve_composition_component_1.insertJsxElementIntoComposition)({
239
- ...insertionInput,
240
- sourceFileOverrides,
241
- });
251
+ let inserted;
252
+ if (captionTarget === null) {
253
+ inserted = await (0, resolve_composition_component_1.insertJsxElementIntoComposition)({
254
+ ...insertionInput,
255
+ compositionFile,
256
+ compositionId,
257
+ sourceFileOverrides,
258
+ });
259
+ }
260
+ else {
261
+ const fileName = plan.safePaths.compositionFileName;
262
+ const oldContents = (0, node_fs_1.readFileSync)(fileName, 'utf-8');
263
+ inserted = {
264
+ ...codemods_1.CodemodsInternals.insertBasicCaptions({
265
+ ...captionTarget,
266
+ input: oldContents,
267
+ importPath: plan.importPath,
268
+ element: { componentName: plan.componentName, initialProps },
269
+ }),
270
+ fileName,
271
+ oldContents,
272
+ };
273
+ }
242
274
  if (compositionCreation !== null &&
243
275
  inserted.fileName !== compositionCreation.componentFilePath) {
244
276
  throw new Error('New composition component does not match installation target');
@@ -1,4 +1,4 @@
1
- import { type DefaultEditor } from '@remotion/renderer';
1
+ import type { DefaultEditor } from '@remotion/renderer';
2
2
  import type { OpenInEditorRequest, OpenInEditorResponse } from '@remotion/studio-shared';
3
3
  import type { ApiHandler } from '../api-types';
4
4
  export declare const getEditorName: ({ getDefaultEditor, logLevel, }: {
@@ -1,13 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.openInEditorHandler = exports.getEditorName = void 0;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const renderer_1 = require("@remotion/renderer");
9
- const custom_editor_1 = require("../../helpers/custom-editor");
10
- const open_in_editor_1 = require("../../helpers/open-in-editor");
4
+ const open_in_app_1 = require("../../helpers/open-in-app");
11
5
  const resolve_editor_1 = require("../../helpers/resolve-editor");
12
6
  const getEditorName = async ({ getDefaultEditor, logLevel, }) => {
13
7
  var _a;
@@ -19,52 +13,4 @@ const getEditorName = async ({ getDefaultEditor, logLevel, }) => {
19
13
  return (_a = editor === null || editor === void 0 ? void 0 : editor.nameWithType) !== null && _a !== void 0 ? _a : null;
20
14
  };
21
15
  exports.getEditorName = getEditorName;
22
- const openInEditorHandler = async ({ input, remotionRoot, logLevel, getDefaultEditor }) => {
23
- try {
24
- if (!('stack' in input)) {
25
- throw new TypeError('Need to pass stack');
26
- }
27
- const { stack } = input;
28
- if (input.editorId !== null &&
29
- input.editorId !== 'custom' &&
30
- !renderer_1.defaultEditorIds.includes(input.editorId)) {
31
- return { success: false };
32
- }
33
- const editor = await (0, resolve_editor_1.resolveEditor)({
34
- defaultEditor: getDefaultEditor(),
35
- logLevel,
36
- preferredEditor: input.editorId,
37
- });
38
- if (!editor) {
39
- return { success: false };
40
- }
41
- const fileName = node_path_1.default.resolve(remotionRoot, stack.originalFileName);
42
- const didOpen = editor.type === 'custom'
43
- ? await (0, custom_editor_1.launchCustomEditor)({
44
- editor: editor.editor,
45
- resolvedExecutable: editor,
46
- targetPath: fileName,
47
- lineNumber: stack.originalLineNumber,
48
- columnNumber: stack.originalColumnNumber,
49
- logLevel,
50
- spawnProcess: null,
51
- })
52
- : await (0, open_in_editor_1.launchEditor)({
53
- colNumber: stack.originalColumnNumber,
54
- editor,
55
- fileName,
56
- lineNumber: stack.originalLineNumber,
57
- vsCodeNewWindow: false,
58
- logLevel,
59
- }, remotionRoot);
60
- return {
61
- success: didOpen,
62
- };
63
- }
64
- catch (_a) {
65
- return {
66
- success: false,
67
- };
68
- }
69
- };
70
- exports.openInEditorHandler = openInEditorHandler;
16
+ exports.openInEditorHandler = open_in_app_1.openInEditor;
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.redoHandler = void 0;
4
4
  const undo_stack_1 = require("../undo-stack");
5
+ const source_file_write_queue_1 = require("./source-file-write-queue");
5
6
  const redoHandler = () => {
6
- return Promise.resolve((0, undo_stack_1.popRedo)());
7
+ return (0, source_file_write_queue_1.withSourceFileWriteQueue)(() => (0, undo_stack_1.popRedo)());
7
8
  };
8
9
  exports.redoHandler = redoHandler;
@@ -1,2 +1,2 @@
1
1
  export declare const getCodemodTimingPrefix: (logLevel: "error" | "info" | "trace" | "verbose" | "warn") => string;
2
- export declare const withSourceFileWriteQueue: <T>(fn: () => Promise<T>) => Promise<T>;
2
+ export declare const withSourceFileWriteQueue: <T>(fn: () => T | Promise<T>) => Promise<T>;
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.undoHandler = void 0;
4
4
  const undo_stack_1 = require("../undo-stack");
5
+ const source_file_write_queue_1 = require("./source-file-write-queue");
5
6
  const undoHandler = () => {
6
- return Promise.resolve((0, undo_stack_1.popUndo)());
7
+ return (0, source_file_write_queue_1.withSourceFileWriteQueue)(() => (0, undo_stack_1.popUndo)());
7
8
  };
8
9
  exports.undoHandler = undoHandler;
@@ -120,6 +120,10 @@ const validateUpdates = (updates) => {
120
120
  catch (_b) {
121
121
  return 'Config.addElementLibrary() expects an HTTP or HTTPS URL.';
122
122
  }
123
+ if (elementLibrary.captionStylesUrl !== undefined &&
124
+ (0, studio_shared_1.normalizeHttpUrl)(elementLibrary.captionStylesUrl) === null) {
125
+ return 'Config.addElementLibrary() expects "captionStylesUrl" to be an absolute HTTP or HTTPS URL.';
126
+ }
123
127
  if (displayName !== undefined &&
124
128
  (typeof displayName !== 'string' || displayName.trim() === '')) {
125
129
  return 'Config.addElementLibrary() expects a non-empty display name.';
@@ -223,16 +227,19 @@ const updateConfigFile = ({ configContents, existingElementLibraryUrls, updates,
223
227
  let value = initialValue;
224
228
  if (setter === 'addElementLibrary') {
225
229
  const elementLibrary = initialValue;
226
- const { displayName: rawDisplayName, url } = elementLibrary;
230
+ const { displayName: rawDisplayName, url, captionStylesUrl, } = elementLibrary;
227
231
  const normalizedUrl = new URL(url).href;
228
232
  if (elementLibraryUrls.has(normalizedUrl)) {
229
233
  continue;
230
234
  }
231
235
  const displayName = typeof rawDisplayName === 'string' ? rawDisplayName.trim() : null;
232
- value =
233
- displayName === null
234
- ? { url: normalizedUrl }
235
- : { url: normalizedUrl, displayName };
236
+ value = {
237
+ url: normalizedUrl,
238
+ ...(displayName === null ? {} : { displayName }),
239
+ ...(captionStylesUrl === undefined
240
+ ? {}
241
+ : { captionStylesUrl: new URL(captionStylesUrl).href }),
242
+ };
236
243
  elementLibraryUrls.add(normalizedUrl);
237
244
  }
238
245
  const serializedValue = JSON.stringify(value)
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleStudioProtocolElementLibrary = void 0;
4
4
  const studio_protocol_1 = require("@remotion/studio-protocol");
5
+ const studio_shared_1 = require("@remotion/studio-shared");
5
6
  const element_install_state_1 = require("../element-install-state");
6
7
  const parse_body_1 = require("../parse-body");
7
8
  const origin_policy_1 = require("./origin-policy");
@@ -81,6 +82,18 @@ const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab,
81
82
  });
82
83
  return;
83
84
  }
85
+ const captionStylesUrl = parsedRequest.captionStylesUrl === null
86
+ ? null
87
+ : (0, studio_shared_1.normalizeHttpUrl)(parsedRequest.captionStylesUrl);
88
+ if (parsedRequest.captionStylesUrl !== null && captionStylesUrl === null) {
89
+ (0, protocol_response_1.writeStudioProtocolError)({
90
+ code: 'invalid-url',
91
+ message: 'The caption styles URL must be an absolute HTTP or HTTPS URL.',
92
+ response,
93
+ status: 400,
94
+ });
95
+ return;
96
+ }
84
97
  const displayName = (_b = (_a = parsedRequest.displayName) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
85
98
  if (displayName === '') {
86
99
  (0, protocol_response_1.writeStudioProtocolError)({
@@ -117,6 +130,7 @@ const handleStudioProtocolElementLibrary = async ({ configFile, focusStudioTab,
117
130
  }
118
131
  const delivered = liveEventsServer.sendEventToClientId(target.clientId, {
119
132
  type: 'element-library-add-request',
133
+ captionStylesUrl,
120
134
  url: normalizedUrl,
121
135
  displayName,
122
136
  origin: requestOrigin,
@@ -10,7 +10,7 @@ const protocol_response_1 = require("./protocol-response");
10
10
  // UTF-8 representation and the protocol envelope while keeping memory bounded.
11
11
  const MAX_STUDIO_PROTOCOL_INSTALL_BODY_SIZE = 1000000;
12
12
  const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, origin, target, }) => {
13
- var _a, _b, _c;
13
+ var _a, _b, _c, _d;
14
14
  const installRequest = {
15
15
  id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
16
16
  clientId: target.clientId,
@@ -22,6 +22,7 @@ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, orig
22
22
  durationInFrames: (_a = element.durationInFrames) !== null && _a !== void 0 ? _a : null,
23
23
  initialProps: (_b = element.initialProps) !== null && _b !== void 0 ? _b : null,
24
24
  installationMode: (_c = element.installationMode) !== null && _c !== void 0 ? _c : null,
25
+ isCaptionStyle: (_d = element.isCaptionStyle) !== null && _d !== void 0 ? _d : false,
25
26
  },
26
27
  from: null,
27
28
  position: null,
@@ -285,6 +285,7 @@ function popUndo() {
285
285
  (0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
286
286
  }
287
287
  if (snapshot.oldContents === null) {
288
+ (0, watch_ignore_next_change_1.prepareBundlerForFileWrite)(snapshot.filePath);
288
289
  (0, node_fs_1.rmSync)(snapshot.filePath, { force: true });
289
290
  }
290
291
  else {
@@ -1,5 +1,6 @@
1
1
  import type { WatchIgnoreNextChangePlugin } from '@remotion/bundler';
2
2
  export declare const setWatchIgnoreNextChangePlugin: (plugin: WatchIgnoreNextChangePlugin) => void;
3
3
  export declare const suppressBundlerUpdateForFile: (absolutePath: string) => void;
4
+ export declare const prepareBundlerForFileWrite: (absolutePath: string) => void;
4
5
  export declare const invalidatePreviouslySuppressedFiles: () => Promise<boolean>;
5
6
  export declare const reloadPreviouslySuppressedFiles: () => Promise<void>;
@@ -1,16 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.reloadPreviouslySuppressedFiles = exports.invalidatePreviouslySuppressedFiles = exports.suppressBundlerUpdateForFile = exports.setWatchIgnoreNextChangePlugin = void 0;
3
+ exports.reloadPreviouslySuppressedFiles = exports.invalidatePreviouslySuppressedFiles = exports.prepareBundlerForFileWrite = exports.suppressBundlerUpdateForFile = exports.setWatchIgnoreNextChangePlugin = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
+ const pendingSuppressedWrites = new Set();
5
6
  let currentPlugin = null;
6
7
  const setWatchIgnoreNextChangePlugin = (plugin) => {
7
8
  currentPlugin = plugin;
9
+ pendingSuppressedWrites.clear();
8
10
  };
9
11
  exports.setWatchIgnoreNextChangePlugin = setWatchIgnoreNextChangePlugin;
10
12
  const suppressBundlerUpdateForFile = (absolutePath) => {
11
- currentPlugin === null || currentPlugin === void 0 ? void 0 : currentPlugin.ignoreNextChange(absolutePath);
13
+ pendingSuppressedWrites.add(absolutePath);
12
14
  };
13
15
  exports.suppressBundlerUpdateForFile = suppressBundlerUpdateForFile;
16
+ // Consume the intent for this write, rather than letting an earlier suppressed
17
+ // write swallow a subsequent structural change in the watcher's aggregated event.
18
+ const prepareBundlerForFileWrite = (absolutePath) => {
19
+ if (pendingSuppressedWrites.delete(absolutePath)) {
20
+ currentPlugin === null || currentPlugin === void 0 ? void 0 : currentPlugin.ignoreNextChange(absolutePath);
21
+ }
22
+ else {
23
+ currentPlugin === null || currentPlugin === void 0 ? void 0 : currentPlugin.requireRebuild(absolutePath);
24
+ }
25
+ };
26
+ exports.prepareBundlerForFileWrite = prepareBundlerForFileWrite;
14
27
  const invalidatePreviouslySuppressedFiles = async () => {
15
28
  if (!currentPlugin) {
16
29
  return false;
@@ -11,13 +11,13 @@ const renderer_1 = require("@remotion/renderer");
11
11
  const file_watcher_1 = require("./file-watcher");
12
12
  const get_network_address_1 = require("./get-network-address");
13
13
  const maybe_open_browser_1 = require("./maybe-open-browser");
14
- const open_browser_shortcut_1 = require("./open-browser-shortcut");
15
14
  const close_and_restart_1 = require("./preview-server/close-and-restart");
16
15
  const get_absolute_public_dir_1 = require("./preview-server/get-absolute-public-dir");
17
16
  const live_events_1 = require("./preview-server/live-events");
18
17
  const public_folder_1 = require("./preview-server/public-folder");
19
18
  const start_server_1 = require("./preview-server/start-server");
20
19
  const server_ready_1 = require("./server-ready");
20
+ const studio_shortcuts_1 = require("./studio-shortcuts");
21
21
  const watch_root_file_1 = require("./watch-root-file");
22
22
  const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEntryPath, logLevel, getCurrentInputProps, getEnvVariables, desiredPort, remotionRoot, relativePublicDir, bundlerOverride, rspackOverride, webpackOverride, poll, getRenderDefaults, getRenderQueue, getNumberOfAudioTags, queueMethods, previewEntry, gitSource, binariesDirectory, forceIPv4, getAudioLatencyHint, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, enableCrossSiteIsolation, forceNew, rspack, getStudioRuntimeConfig, getDefaultCodingAgent, getDefaultEditor, configFile, }) => {
23
23
  try {
@@ -128,11 +128,14 @@ const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEn
128
128
  (0, server_ready_1.printServerReadyComment)('Server ready', logLevel);
129
129
  renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, 'Building...');
130
130
  const studioUrl = `http://localhost:${port}`;
131
- const openBrowserShortcut = (0, open_browser_shortcut_1.registerOpenBrowserShortcut)({
131
+ const studioShortcuts = (0, studio_shortcuts_1.registerStudioShortcuts)({
132
132
  browserArgs,
133
133
  browserFlag,
134
134
  url: studioUrl,
135
135
  logLevel,
136
+ remotionRoot,
137
+ getDefaultEditor,
138
+ getDefaultCodingAgent,
136
139
  });
137
140
  let action;
138
141
  try {
@@ -146,7 +149,7 @@ const startStudio = async ({ browserArgs, browserFlag, shouldOpenBrowser, fullEn
146
149
  action = await (0, close_and_restart_1.noOpUntilRestart)();
147
150
  }
148
151
  finally {
149
- openBrowserShortcut.cleanup();
152
+ studioShortcuts.cleanup();
150
153
  }
151
154
  renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, action === 'shutdown'
152
155
  ? 'Shutting down Studio...'
@@ -0,0 +1,13 @@
1
+ import type { DefaultEditor } from '@remotion/renderer';
2
+ export declare const registerStudioShortcuts: ({ browserArgs, browserFlag, url, logLevel, remotionRoot, getDefaultEditor, getDefaultCodingAgent, }: {
3
+ browserArgs: string;
4
+ browserFlag: string;
5
+ url: string;
6
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
7
+ remotionRoot: string;
8
+ getDefaultEditor: () => DefaultEditor | null;
9
+ getDefaultCodingAgent: () => "claude-code" | "codex" | "copilot" | "cursor" | null;
10
+ }) => {
11
+ registered: boolean;
12
+ cleanup: () => void;
13
+ };
@@ -0,0 +1,257 @@
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.registerStudioShortcuts = void 0;
37
+ const readline = __importStar(require("node:readline"));
38
+ const renderer_1 = require("@remotion/renderer");
39
+ const studio_shared_1 = require("@remotion/studio-shared");
40
+ const better_opn_1 = require("./better-opn");
41
+ const app_discovery_1 = require("./helpers/app-discovery");
42
+ const open_in_app_1 = require("./helpers/open-in-app");
43
+ const recently_used_apps_1 = require("./helpers/recently-used-apps");
44
+ const maybe_open_browser_1 = require("./maybe-open-browser");
45
+ const live_events_1 = require("./preview-server/live-events");
46
+ const registerStudioShortcuts = ({ browserArgs, browserFlag, url, logLevel, remotionRoot, getDefaultEditor, getDefaultCodingAgent, }) => {
47
+ if (!process.stdin.isTTY) {
48
+ return { registered: false, cleanup: () => undefined };
49
+ }
50
+ if (typeof process.stdin.setRawMode !== 'function') {
51
+ return { registered: false, cleanup: () => undefined };
52
+ }
53
+ const wasRaw = process.stdin.isRaw;
54
+ const shouldPauseAfterCleanup = process.stdin.isPaused();
55
+ let cleanedUp = false;
56
+ let isOpeningBrowser = false;
57
+ let editor = null;
58
+ let codingAgent = null;
59
+ const openingApps = new Set();
60
+ let refreshRevision = 0;
61
+ let lastPrintedAssignment = null;
62
+ const refreshShortcuts = async () => {
63
+ var _a;
64
+ const revision = ++refreshRevision;
65
+ const configuredEditor = getDefaultEditor();
66
+ const configuredCodingAgent = getDefaultCodingAgent();
67
+ const [discovery, editorInfo, recentEditors, recentCodingAgents] = await Promise.all([
68
+ (0, app_discovery_1.getAppDiscovery)(),
69
+ (0, app_discovery_1.getEditorInfo)(configuredEditor),
70
+ (0, recently_used_apps_1.getRecentlyUsedApps)({
71
+ remotionRoot,
72
+ type: 'editor',
73
+ recentlyUsedIds: null,
74
+ }),
75
+ (0, recently_used_apps_1.getRecentlyUsedApps)({
76
+ remotionRoot,
77
+ type: 'coding-agent',
78
+ recentlyUsedIds: null,
79
+ }),
80
+ ]);
81
+ if (cleanedUp || revision !== refreshRevision) {
82
+ return;
83
+ }
84
+ editor = (0, studio_shared_1.getPreferredApp)({
85
+ installedApps: editorInfo.installedEditors,
86
+ configuredId: editorInfo.defaultEditor,
87
+ runningIds: (_a = editorInfo.runningEditors) !== null && _a !== void 0 ? _a : [],
88
+ recentlyUsedIds: recentEditors,
89
+ fallbackIds: studio_shared_1.preferredFallbackEditorIds,
90
+ });
91
+ codingAgent = (0, studio_shared_1.getPreferredApp)({
92
+ installedApps: discovery.installedCodingAgents,
93
+ configuredId: configuredCodingAgent,
94
+ runningIds: discovery.runningCodingAgents,
95
+ recentlyUsedIds: recentCodingAgents,
96
+ fallbackIds: discovery.installedCodingAgents.map(({ id }) => id),
97
+ });
98
+ printShortcuts();
99
+ };
100
+ const printShortcuts = () => {
101
+ var _a, _b;
102
+ if (cleanedUp) {
103
+ return;
104
+ }
105
+ const shortcuts = [
106
+ '[s] Open Studio',
107
+ ...(codingAgent ? [`[a] Open agent (${codingAgent.name})`] : []),
108
+ ...(editor
109
+ ? [
110
+ `[e] Open editor (${editor.name === 'Code' ? 'VS Code' : editor.name})`,
111
+ ]
112
+ : []),
113
+ ];
114
+ const assignment = JSON.stringify([
115
+ (_a = editor === null || editor === void 0 ? void 0 : editor.id) !== null && _a !== void 0 ? _a : null,
116
+ (_b = codingAgent === null || codingAgent === void 0 ? void 0 : codingAgent.id) !== null && _b !== void 0 ? _b : null,
117
+ shortcuts,
118
+ (editor === null || editor === void 0 ? void 0 : editor.id) === 'custom' ? getDefaultEditor() : null,
119
+ ]);
120
+ if (assignment === lastPrintedAssignment) {
121
+ return;
122
+ }
123
+ lastPrintedAssignment = assignment;
124
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.gray(shortcuts.join(' ')));
125
+ };
126
+ const onPreferencesChange = () => {
127
+ if (cleanedUp) {
128
+ return;
129
+ }
130
+ refreshShortcuts().catch((err) => {
131
+ renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Could not refresh Studio shortcuts:', err);
132
+ printShortcuts();
133
+ });
134
+ };
135
+ const unsubscribeHistory = (0, recently_used_apps_1.subscribeToRecentlyUsedApps)({
136
+ remotionRoot,
137
+ onChange: onPreferencesChange,
138
+ });
139
+ const unsubscribeConfig = (0, live_events_1.subscribeToConfigChanges)(onPreferencesChange);
140
+ const openApp = async (key) => {
141
+ if (openingApps.has(key) || cleanedUp) {
142
+ return;
143
+ }
144
+ openingApps.add(key);
145
+ try {
146
+ const response = key === 'a' && codingAgent
147
+ ? await (0, open_in_app_1.openInCodingAgent)({
148
+ input: { codingAgentId: codingAgent.id, prompt: null },
149
+ remotionRoot,
150
+ logLevel,
151
+ })
152
+ : key === 'e' && editor
153
+ ? await (0, open_in_app_1.openInEditor)({
154
+ input: {
155
+ editorId: editor.id,
156
+ stack: {
157
+ originalFileName: remotionRoot,
158
+ originalLineNumber: 1,
159
+ originalColumnNumber: 1,
160
+ originalFunctionName: null,
161
+ originalScriptCode: null,
162
+ },
163
+ },
164
+ remotionRoot,
165
+ logLevel,
166
+ getDefaultEditor,
167
+ })
168
+ : null;
169
+ if (response && !response.success) {
170
+ renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, `Could not open ${key === 'a' ? codingAgent === null || codingAgent === void 0 ? void 0 : codingAgent.name : editor === null || editor === void 0 ? void 0 : editor.name}`);
171
+ }
172
+ }
173
+ catch (err) {
174
+ renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, key === 'a' ? 'Could not open coding agent:' : 'Could not open editor:', err);
175
+ }
176
+ finally {
177
+ openingApps.delete(key);
178
+ }
179
+ };
180
+ const cleanup = () => {
181
+ if (cleanedUp) {
182
+ return;
183
+ }
184
+ cleanedUp = true;
185
+ unsubscribeHistory();
186
+ unsubscribeConfig();
187
+ process.stdin.removeListener('keypress', onKeypress);
188
+ process.removeListener('SIGINT', cleanup);
189
+ process.removeListener('exit', cleanup);
190
+ if (!wasRaw && process.stdin.isTTY) {
191
+ process.stdin.setRawMode(false);
192
+ }
193
+ if (shouldPauseAfterCleanup) {
194
+ process.stdin.pause();
195
+ }
196
+ };
197
+ const openStudio = async () => {
198
+ if (isOpeningBrowser) {
199
+ return;
200
+ }
201
+ isOpeningBrowser = true;
202
+ (0, live_events_1.clearPrintPortMessageTimeout)();
203
+ try {
204
+ const didFocus = await (0, better_opn_1.focusBrowserTabByOrigin)({
205
+ url,
206
+ browserArgs,
207
+ browserFlag,
208
+ });
209
+ if (didFocus) {
210
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Opened ${url} in browser`));
211
+ return;
212
+ }
213
+ const result = await (0, maybe_open_browser_1.maybeOpenBrowser)({
214
+ browserArgs,
215
+ browserFlag,
216
+ shouldOpenBrowser: true,
217
+ url,
218
+ logLevel,
219
+ });
220
+ if (result.didOpenBrowser) {
221
+ renderer_1.RenderInternals.Log.info({ indent: false, logLevel }, renderer_1.RenderInternals.chalk.blue(`Opened ${url} in browser`));
222
+ }
223
+ }
224
+ catch (err) {
225
+ renderer_1.RenderInternals.Log.error({ indent: false, logLevel }, 'Could not open browser:', err);
226
+ }
227
+ finally {
228
+ isOpeningBrowser = false;
229
+ }
230
+ };
231
+ function onKeypress(_str, key) {
232
+ if ((key === null || key === void 0 ? void 0 : key.ctrl) && key.name === 'c') {
233
+ cleanup();
234
+ process.kill(process.pid, 'SIGINT');
235
+ return;
236
+ }
237
+ if ((key === null || key === void 0 ? void 0 : key.meta) || (key === null || key === void 0 ? void 0 : key.ctrl)) {
238
+ return;
239
+ }
240
+ if ((key === null || key === void 0 ? void 0 : key.name) === 's') {
241
+ openStudio().catch(() => undefined);
242
+ }
243
+ else if ((key === null || key === void 0 ? void 0 : key.name) === 'a' || (key === null || key === void 0 ? void 0 : key.name) === 'e') {
244
+ openApp(key.name).catch(() => undefined);
245
+ }
246
+ }
247
+ readline.emitKeypressEvents(process.stdin);
248
+ process.stdin.setRawMode(true);
249
+ process.stdin.resume();
250
+ process.stdin.on('keypress', onKeypress);
251
+ process.once('SIGINT', cleanup);
252
+ process.once('exit', cleanup);
253
+ // Discovery may finish after other startup logs; never await it here.
254
+ onPreferencesChange();
255
+ return { registered: true, cleanup };
256
+ };
257
+ exports.registerStudioShortcuts = registerStudioShortcuts;