@remotion/studio-server 4.0.533 → 4.0.535

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 (68) hide show
  1. package/dist/detect-outdated-remotion-skills.d.ts +4 -0
  2. package/dist/detect-outdated-remotion-skills.js +3 -2
  3. package/dist/file-watcher.js +2 -0
  4. package/dist/helpers/app-discovery.d.ts +9 -0
  5. package/dist/helpers/app-discovery.js +61 -0
  6. package/dist/helpers/coding-agent-registry.d.ts +1 -0
  7. package/dist/helpers/coding-agent-registry.js +22 -1
  8. package/dist/helpers/editor-registry.d.ts +1 -0
  9. package/dist/helpers/editor-registry.js +24 -1
  10. package/dist/helpers/open-in-app.d.ts +13 -0
  11. package/dist/helpers/open-in-app.js +72 -0
  12. package/dist/helpers/open-in-editor.d.ts +1 -1
  13. package/dist/helpers/open-in-editor.js +67 -84
  14. package/dist/helpers/recently-used-apps.d.ts +9 -0
  15. package/dist/helpers/recently-used-apps.js +63 -0
  16. package/dist/helpers/running-processes.d.ts +12 -0
  17. package/dist/helpers/running-processes.js +88 -0
  18. package/dist/helpers/video-config-numeric-expression.js +29 -20
  19. package/dist/helpers/video-config-values.d.ts +6 -3
  20. package/dist/helpers/video-config-values.js +42 -26
  21. package/dist/preview-server/api-routes.js +8 -5
  22. package/dist/preview-server/live-events.d.ts +1 -0
  23. package/dist/preview-server/live-events.js +12 -1
  24. package/dist/preview-server/routes/add-sequence-keyframe.js +0 -1
  25. package/dist/preview-server/routes/app-info.d.ts +3 -0
  26. package/dist/preview-server/routes/app-info.js +16 -0
  27. package/dist/preview-server/routes/can-update-effect-props.d.ts +4 -6
  28. package/dist/preview-server/routes/can-update-effect-props.js +5 -28
  29. package/dist/preview-server/routes/can-update-sequence-props.d.ts +6 -8
  30. package/dist/preview-server/routes/can-update-sequence-props.js +11 -12
  31. package/dist/preview-server/routes/default-coding-agent.d.ts +1 -2
  32. package/dist/preview-server/routes/default-coding-agent.js +11 -19
  33. package/dist/preview-server/routes/default-editor.js +9 -29
  34. package/dist/preview-server/routes/delete-keyframes.d.ts +2 -2
  35. package/dist/preview-server/routes/delete-keyframes.js +0 -1
  36. package/dist/preview-server/routes/element-install-plan.js +5 -0
  37. package/dist/preview-server/routes/insert-basic-captions.js +1 -0
  38. package/dist/preview-server/routes/insert-element.js +63 -20
  39. package/dist/preview-server/routes/install-remotion-skill.d.ts +2 -1
  40. package/dist/preview-server/routes/install-remotion-skill.js +87 -56
  41. package/dist/preview-server/routes/open-in-editor.d.ts +1 -1
  42. package/dist/preview-server/routes/open-in-editor.js +2 -56
  43. package/dist/preview-server/routes/redo.js +2 -1
  44. package/dist/preview-server/routes/remotion-skills-info.d.ts +2 -1
  45. package/dist/preview-server/routes/remotion-skills-info.js +57 -3
  46. package/dist/preview-server/routes/save-sequence-props.js +0 -1
  47. package/dist/preview-server/routes/shared-memory-capture-support.d.ts +3 -0
  48. package/dist/preview-server/routes/shared-memory-capture-support.js +13 -0
  49. package/dist/preview-server/routes/source-file-write-queue.d.ts +1 -1
  50. package/dist/preview-server/routes/subscribe-to-sequence-props.js +1 -2
  51. package/dist/preview-server/routes/undo.js +2 -1
  52. package/dist/preview-server/routes/unsubscribe-from-sequence-props.js +0 -1
  53. package/dist/preview-server/routes/update-config.js +12 -5
  54. package/dist/preview-server/routes/update-sequence-keyframe-settings.js +0 -1
  55. package/dist/preview-server/routes/wrap-node.js +13 -4
  56. package/dist/preview-server/sequence-props-watchers.d.ts +3 -5
  57. package/dist/preview-server/sequence-props-watchers.js +9 -17
  58. package/dist/preview-server/studio-protocol/handle-element-library.js +14 -0
  59. package/dist/preview-server/studio-protocol/handle-install.js +2 -1
  60. package/dist/preview-server/undo-stack.js +1 -0
  61. package/dist/preview-server/update-available.js +17 -0
  62. package/dist/preview-server/watch-ignore-next-change.d.ts +1 -0
  63. package/dist/preview-server/watch-ignore-next-change.js +15 -2
  64. package/dist/routes.js +3 -1
  65. package/dist/start-studio.js +13 -6
  66. package/dist/studio-shortcuts.d.ts +13 -0
  67. package/dist/studio-shortcuts.js +257 -0
  68. package/package.json +8 -8
@@ -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
- });
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,7 +1,8 @@
1
- import type { GetRemotionSkillsInfoRequest, GetRemotionSkillsInfoResponse } from '@remotion/studio-shared';
1
+ import type { GetRemotionSkillsInfoRequest, GetRemotionSkillsInfoResponse, OpenRemotionSkillRequest } from '@remotion/studio-shared';
2
2
  import type { ApiHandler } from '../api-types';
3
3
  export declare const getRemotionSkillsInfo: ({ remotionRoot, homeDirectory, }: {
4
4
  remotionRoot: string;
5
5
  homeDirectory?: string | undefined;
6
6
  }) => GetRemotionSkillsInfoResponse;
7
7
  export declare const remotionSkillsInfoHandler: ApiHandler<GetRemotionSkillsInfoRequest, GetRemotionSkillsInfoResponse>;
8
+ export declare const openRemotionSkillHandler: ApiHandler<OpenRemotionSkillRequest, void>;
@@ -3,32 +3,86 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.remotionSkillsInfoHandler = exports.getRemotionSkillsInfo = void 0;
6
+ exports.openRemotionSkillHandler = exports.remotionSkillsInfoHandler = exports.getRemotionSkillsInfo = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_os_1 = require("node:os");
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
+ const version_1 = require("remotion/version");
11
+ const semver_1 = __importDefault(require("semver"));
10
12
  const detect_outdated_remotion_skills_1 = require("../../detect-outdated-remotion-skills");
13
+ const open_directory_in_finder_1 = require("../../open-directory-in-finder");
11
14
  const remotion_skill_names_1 = require("../../remotion-skill-names");
12
15
  const getRemotionSkillsInfo = ({ remotionRoot, homeDirectory = (0, node_os_1.homedir)(), }) => {
16
+ var _a;
13
17
  const skillsDirectories = (0, detect_outdated_remotion_skills_1.getRemotionSkillsDirectories)({
14
18
  cwd: remotionRoot,
15
19
  homeDirectory,
16
20
  });
21
+ const installations = remotion_skill_names_1.remotionSkillNames.flatMap((name) => {
22
+ return ['project', 'global'].flatMap((scope) => {
23
+ const { installed, version } = (0, detect_outdated_remotion_skills_1.readRemotionSkill)(node_path_1.default.join(skillsDirectories[scope], name, 'SKILL.md'));
24
+ if (!installed) {
25
+ return [];
26
+ }
27
+ return [
28
+ {
29
+ name,
30
+ scope,
31
+ version,
32
+ outdated: version === null ||
33
+ semver_1.default.valid(version) === null ||
34
+ semver_1.default.lt(version, version_1.VERSION),
35
+ },
36
+ ];
37
+ });
38
+ });
17
39
  const skills = remotion_skill_names_1.remotionSkillNames.map((name) => ({
18
40
  name,
19
- installedInProject: (0, node_fs_1.existsSync)(node_path_1.default.join(skillsDirectories.project, name, 'SKILL.md')),
20
- installedGlobally: (0, node_fs_1.existsSync)(node_path_1.default.join(skillsDirectories.global, name, 'SKILL.md')),
41
+ installedInProject: installations.some((installation) => installation.name === name && installation.scope === 'project'),
42
+ installedGlobally: installations.some((installation) => installation.name === name && installation.scope === 'global'),
21
43
  }));
22
44
  const isSkillAvailable = (skillName) => {
23
45
  const skill = skills.find(({ name }) => name === skillName);
24
46
  return Boolean((skill === null || skill === void 0 ? void 0 : skill.installedInProject) || (skill === null || skill === void 0 ? void 0 : skill.installedGlobally));
25
47
  };
48
+ const restartSkillDirectories = [skillsDirectories.global];
49
+ let directory = node_path_1.default.resolve(remotionRoot);
50
+ while (true) {
51
+ restartSkillDirectories.push(node_path_1.default.join(directory, '.agents', 'skills'));
52
+ const parent = node_path_1.default.dirname(directory);
53
+ if (parent === directory || (0, node_fs_1.existsSync)(node_path_1.default.join(directory, '.git'))) {
54
+ break;
55
+ }
56
+ directory = parent;
57
+ }
58
+ const studioRestartSkill = (_a = ['remotion-studio', 'remotion-best-practices'].find((name) => restartSkillDirectories.some((skillsDirectory) => (0, node_fs_1.existsSync)(node_path_1.default.join(skillsDirectory, name, 'SKILL.md'))))) !== null && _a !== void 0 ? _a : null;
26
59
  return {
60
+ studioServerStartedByAgent: Boolean(process.env.CURSOR_AGENT || process.env.CLAUDECODE === '1'),
61
+ studioRestartSkill,
27
62
  remotionUpgradeSkillAvailable: isSkillAvailable('remotion-upgrade'),
28
63
  remotionInteractivitySkillAvailable: isSkillAvailable('remotion-interactivity'),
64
+ installations,
29
65
  skills,
30
66
  };
31
67
  };
32
68
  exports.getRemotionSkillsInfo = getRemotionSkillsInfo;
33
69
  const remotionSkillsInfoHandler = ({ remotionRoot }) => Promise.resolve((0, exports.getRemotionSkillsInfo)({ remotionRoot }));
34
70
  exports.remotionSkillsInfoHandler = remotionSkillsInfoHandler;
71
+ const openRemotionSkillHandler = ({ remotionRoot, input: { skill, scope } }) => {
72
+ if (!remotion_skill_names_1.remotionSkillNames.some((name) => name === skill)) {
73
+ throw new Error(`Unknown Remotion skill: ${JSON.stringify(skill)}`);
74
+ }
75
+ if (scope !== 'project' && scope !== 'global') {
76
+ throw new Error(`Unknown skill scope: ${JSON.stringify(scope)}`);
77
+ }
78
+ const directories = (0, detect_outdated_remotion_skills_1.getRemotionSkillsDirectories)({
79
+ cwd: remotionRoot,
80
+ homeDirectory: (0, node_os_1.homedir)(),
81
+ });
82
+ const skillDirectory = node_path_1.default.join(directories[scope], skill);
83
+ if (!(0, node_fs_1.existsSync)(node_path_1.default.join(skillDirectory, 'SKILL.md'))) {
84
+ throw new Error(`${skill} is not installed ${scope === 'global' ? 'globally' : 'in the project'}.`);
85
+ }
86
+ return (0, open_directory_in_finder_1.openDirectoryInFinder)(skillDirectory, directories[scope]);
87
+ };
88
+ exports.openRemotionSkillHandler = openRemotionSkillHandler;
@@ -492,7 +492,6 @@ const saveSequencePropsHandler = ({ input: { edits, addedKeyframes, movedKeyfram
492
492
  nodePath: (_a = updatedNodePaths.get(`${absolutePath}:${JSON.stringify(target.nodePath.nodePath)}`)) !== null && _a !== void 0 ? _a : target.nodePath.nodePath,
493
493
  componentIdentity: null,
494
494
  effects: [],
495
- videoConfigValues: target.nodePath.videoConfigValues,
496
495
  };
497
496
  const newStatus = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
498
497
  ...statusInput,
@@ -0,0 +1,3 @@
1
+ import type { ApiRoutes } from '@remotion/studio-shared';
2
+ import type { ApiHandler } from '../api-types';
3
+ export declare const sharedMemoryCaptureSupportHandler: ApiHandler<ApiRoutes['/api/shared-memory-capture-support']['Request'], ApiRoutes['/api/shared-memory-capture-support']['Response']>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sharedMemoryCaptureSupportHandler = void 0;
4
+ const renderer_1 = require("@remotion/renderer");
5
+ const sharedMemoryCaptureSupportHandler = async ({ input, binariesDirectory, logLevel }) => {
6
+ const supported = await renderer_1.RenderInternals.probeSharedMemoryCapture({
7
+ ...input,
8
+ binariesDirectory,
9
+ logLevel,
10
+ });
11
+ return { supported };
12
+ };
13
+ exports.sharedMemoryCaptureSupportHandler = sharedMemoryCaptureSupportHandler;
@@ -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>;
@@ -32,7 +32,7 @@ const subscribeToSequenceProps = ({ input, remotionRoot, logLevel }) => {
32
32
  // Let each subscription produce its usual not-found response.
33
33
  }
34
34
  }
35
- const results = input.requests.map(({ fileName, line, column, nodePath, componentIdentity, keys, assetKeys, effects, clientId, videoConfigValues, }, index) => (0, sequence_props_watchers_1.subscribeToSequencePropsWatchers)({
35
+ const results = input.requests.map(({ fileName, line, column, nodePath, componentIdentity, keys, assetKeys, effects, clientId, }, index) => (0, sequence_props_watchers_1.subscribeToSequencePropsWatchers)({
36
36
  fileName,
37
37
  line,
38
38
  column,
@@ -44,7 +44,6 @@ const subscribeToSequenceProps = ({ input, remotionRoot, logLevel }) => {
44
44
  effects,
45
45
  remotionRoot,
46
46
  clientId,
47
- videoConfigValues,
48
47
  logLevel,
49
48
  }));
50
49
  return Promise.resolve({ results });
@@ -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;
@@ -11,7 +11,6 @@ const unsubscribeFromSequenceProps = ({ input: { fileName, nodePath, clientId, s
11
11
  sequenceKeys,
12
12
  assetKeys,
13
13
  effectKeys,
14
- videoConfigValues: nodePath.videoConfigValues,
15
14
  });
16
15
  return Promise.resolve(undefined);
17
16
  };
@@ -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)
@@ -87,7 +87,6 @@ const updateSequenceKeyframeSettingsHandler = ({ input: { fileName, nodePath, ke
87
87
  nodePath: updatedNodePath,
88
88
  componentIdentity: null,
89
89
  effects: [],
90
- videoConfigValues: nodePath.videoConfigValues,
91
90
  });
92
91
  const updatedSubscriptionKey = { ...nodePath, nodePath: updatedNodePath };
93
92
  return {
@@ -10,9 +10,10 @@ const format_log_file_location_1 = require("../format-log-file-location");
10
10
  const sequence_node_path_mutation_1 = require("../sequence-node-path-mutation");
11
11
  const undo_stack_1 = require("../undo-stack");
12
12
  const source_file_write_queue_1 = require("./source-file-write-queue");
13
- const wrapNodeHandler = ({ input: { fileName, nodePath, wrapper, width, height, timing }, remotionRoot, logLevel, }) => {
13
+ const wrapNodeHandler = ({ input: { fileName, compositionId, nodePath, wrapper, width, height, timing }, remotionRoot, logLevel, }) => {
14
14
  return (0, source_file_write_queue_1.withSourceFileWriteQueue)(() => {
15
15
  var _a;
16
+ var _b, _c;
16
17
  try {
17
18
  const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
18
19
  remotionRoot,
@@ -56,8 +57,16 @@ const wrapNodeHandler = ({ input: { fileName, nodePath, wrapper, width, height,
56
57
  throw new Error('Could not wrap JSX node');
57
58
  }
58
59
  const output = change.nextContents;
59
- const remappings = result.nodePathRemappings.map(({ oldNodePath, newNodePath }) => ({ oldNodePath, newNodePath }));
60
- const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)([{ absolutePath, remappings }], null);
60
+ const remappings = result.nodePathRemappings.map(({ oldNodePath, newNodePath, oldJsxName, newJsxName }) => ({
61
+ oldNodePath,
62
+ newNodePath,
63
+ oldJsxName,
64
+ newJsxName,
65
+ }));
66
+ const insertedNodePath = (_b = (_a = remappings.find((remapping) => remapping.oldNodePath === null)) === null || _a === void 0 ? void 0 : _a.newNodePath) !== null && _b !== void 0 ? _b : null;
67
+ const nodePathMutation = (0, sequence_node_path_mutation_1.broadcastSequenceNodePathMutation)([{ absolutePath, remappings }], insertedNodePath !== null
68
+ ? { compositionId, absolutePath, nodePath: insertedNodePath }
69
+ : null);
61
70
  const line = result.logLine;
62
71
  (0, undo_stack_1.pushTransactionToUndoStack)({
63
72
  snapshots: [
@@ -100,7 +109,7 @@ const wrapNodeHandler = ({ input: { fileName, nodePath, wrapper, width, height,
100
109
  return Promise.resolve({
101
110
  success: false,
102
111
  reason: err.message,
103
- stack: (_a = err.stack) !== null && _a !== void 0 ? _a : '',
112
+ stack: (_c = err.stack) !== null && _c !== void 0 ? _c : '',
104
113
  });
105
114
  }
106
115
  });
@@ -1,6 +1,6 @@
1
1
  import { type SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
2
- import type { SequenceNodePath, VideoConfigValues } from 'remotion';
3
- export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, resolvedNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }: {
2
+ import type { SequenceNodePath } from 'remotion';
3
+ export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, resolvedNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, }: {
4
4
  fileName: string;
5
5
  line: number;
6
6
  column: number;
@@ -13,9 +13,8 @@ export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column
13
13
  remotionRoot: string;
14
14
  clientId: string;
15
15
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
16
- videoConfigValues: VideoConfigValues;
17
16
  }) => SubscribeToSequencePropsResponse;
18
- export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, assetKeys, effectKeys, videoConfigValues, }: {
17
+ export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, assetKeys, effectKeys, }: {
19
18
  fileName: string;
20
19
  nodePath: SequenceNodePath;
21
20
  remotionRoot: string;
@@ -23,6 +22,5 @@ export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, nodePath
23
22
  sequenceKeys: string[];
24
23
  assetKeys: string[];
25
24
  effectKeys: string[][];
26
- videoConfigValues: VideoConfigValues | null;
27
25
  }) => void;
28
26
  export declare const unsubscribeClientSequencePropsWatchers: (clientId: string) => void;
@@ -14,8 +14,8 @@ const live_events_1 = require("./live-events");
14
14
  const node_path_cache_1 = require("./node-path-cache");
15
15
  const can_update_sequence_props_1 = require("./routes/can-update-sequence-props");
16
16
  const sequencePropsWatchers = {};
17
- const getWatcherKey = (nodePath, assetKeys) => `${(0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath)}:${assetKeys.join('\0')}:${JSON.stringify(nodePath.videoConfigValues)}`;
18
- const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, resolvedNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, logLevel, videoConfigValues, }) => {
17
+ const getWatcherKey = (nodePath, assetKeys) => `${(0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath)}:${assetKeys.join('\0')}`;
18
+ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, resolvedNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, logLevel, }) => {
19
19
  if (preferredNodePath) {
20
20
  try {
21
21
  const fromNodePath = (0, can_update_sequence_props_1.computeSequencePropsStatus)({
@@ -26,7 +26,6 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, res
26
26
  assetKeys,
27
27
  effects,
28
28
  remotionRoot,
29
- videoConfigValues,
30
29
  });
31
30
  return {
32
31
  status: fromNodePath,
@@ -35,7 +34,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, res
35
34
  nodePath: preferredNodePath,
36
35
  sequenceKeys: keys,
37
36
  effectKeys: effects,
38
- videoConfigValues,
37
+ videoConfigValues: null,
39
38
  },
40
39
  success: true,
41
40
  };
@@ -60,7 +59,6 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, res
60
59
  assetKeys,
61
60
  effects,
62
61
  remotionRoot,
63
- videoConfigValues,
64
62
  });
65
63
  }
66
64
  catch (error) {
@@ -79,7 +77,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, res
79
77
  nodePath: cachedNodePath,
80
78
  sequenceKeys: keys,
81
79
  effectKeys: effects,
82
- videoConfigValues,
80
+ videoConfigValues: null,
83
81
  },
84
82
  success: true,
85
83
  };
@@ -96,14 +94,13 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, res
96
94
  assetKeys,
97
95
  effects,
98
96
  remotionRoot,
99
- videoConfigValues,
100
97
  }),
101
98
  nodePath: {
102
99
  absolutePath: node_path_1.default.resolve(remotionRoot, fileName),
103
100
  nodePath: resolvedNodePath,
104
101
  sequenceKeys: keys,
105
102
  effectKeys: effects,
106
- videoConfigValues,
103
+ videoConfigValues: null,
107
104
  },
108
105
  success: true,
109
106
  };
@@ -125,11 +122,10 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, res
125
122
  effects,
126
123
  remotionRoot,
127
124
  logLevel,
128
- videoConfigValues,
129
125
  });
130
126
  return status;
131
127
  };
132
- const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, resolvedNodePath = null, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }) => {
128
+ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, resolvedNodePath = null, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, }) => {
133
129
  var _a;
134
130
  const initialResult = getSequencePropsStatus({
135
131
  fileName,
@@ -143,7 +139,6 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
143
139
  effects,
144
140
  remotionRoot,
145
141
  logLevel,
146
- videoConfigValues,
147
142
  });
148
143
  if (!initialResult.success) {
149
144
  return initialResult;
@@ -170,9 +165,8 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
170
165
  if (event.type === 'deleted') {
171
166
  return;
172
167
  }
173
- if (event.originatorClientId === clientId) {
174
- return;
175
- }
168
+ // Even the editing client needs the saved expression: its optimistic
169
+ // numeric value only describes the instance that initiated the edit.
176
170
  if (event.type === 'changed' && event.skipSequencePropsUpdate) {
177
171
  return;
178
172
  }
@@ -184,7 +178,6 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
184
178
  keys,
185
179
  assetKeys,
186
180
  effects,
187
- videoConfigValues,
188
181
  });
189
182
  const previousEffectChain = result.effects.map((effect) => effect.canUpdate && effect.callee);
190
183
  const newEffectChain = initialResult.success &&
@@ -227,14 +220,13 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
227
220
  return initialResult;
228
221
  };
229
222
  exports.subscribeToSequencePropsWatchers = subscribeToSequencePropsWatchers;
230
- const unsubscribeFromSequencePropsWatchers = ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, assetKeys, effectKeys, videoConfigValues, }) => {
223
+ const unsubscribeFromSequencePropsWatchers = ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, assetKeys, effectKeys, }) => {
231
224
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
232
225
  const watcherKey = getWatcherKey({
233
226
  absolutePath,
234
227
  nodePath,
235
228
  sequenceKeys,
236
229
  effectKeys,
237
- videoConfigValues,
238
230
  }, assetKeys);
239
231
  if (!sequencePropsWatchers[clientId] ||
240
232
  !sequencePropsWatchers[clientId][watcherKey]) {
@@ -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 {
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isUpdateAvailableWithTimeout = exports.getRemotionVersion = exports.isUpdateAvailable = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
7
8
  const semver_1 = __importDefault(require("semver"));
8
9
  const detect_outdated_remotion_skills_1 = require("../detect-outdated-remotion-skills");
9
10
  const get_latest_remotion_version_1 = require("../get-latest-remotion-version");
@@ -15,6 +16,22 @@ const getSkillsUpdateInfo = ({ remotionRoot, currentVersion, }) => {
15
16
  }).project;
16
17
  return {
17
18
  skillsUpdateAvailable: projectSkills.type === 'outdated',
19
+ skillsUpdateDetails: projectSkills.type === 'outdated'
20
+ ? {
21
+ outdatedSkills: projectSkills.outdatedSkillNames.map((name) => {
22
+ const { version } = (0, detect_outdated_remotion_skills_1.readRemotionSkill)(node_path_1.default.join(projectSkills.skillsDirectory, name, 'SKILL.md'));
23
+ return {
24
+ name,
25
+ installedVersion: version,
26
+ reason: version === null
27
+ ? 'missing-version'
28
+ : semver_1.default.valid(version) === null
29
+ ? 'invalid-version'
30
+ : 'older-version',
31
+ };
32
+ }),
33
+ }
34
+ : null,
18
35
  };
19
36
  };
20
37
  const isUpdateAvailable = async ({ remotionRoot, currentVersion, logLevel, getLatestVersion, }) => {
@@ -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;
package/dist/routes.js CHANGED
@@ -102,7 +102,7 @@ const handleRemotionConfig = (response, remotionRoot) => {
102
102
  response.end(JSON.stringify(body));
103
103
  return Promise.resolve();
104
104
  };
105
- const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, getAudioLatencyHint, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, gitSource, logLevel, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultEditor, }) => {
105
+ const handleFallback = async ({ remotionRoot, hash, outputHash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, getAudioLatencyHint, getExperimentalKeepAudioContextAlive, getPreviewSampleRate, gitSource, logLevel, enableCrossSiteIsolation, getStudioRuntimeConfig, getDefaultEditor, }) => {
106
106
  var _a, _b;
107
107
  const acceptsHtml = ((_a = request.headers.accept) !== null && _a !== void 0 ? _a : '').includes('text/html');
108
108
  if (request.method === 'GET' && acceptsHtml) {
@@ -142,6 +142,7 @@ const handleFallback = async ({ remotionRoot, hash, response, request, getCurren
142
142
  response.end(bundler_1.BundlerInternals.indexHtml({
143
143
  importMap: null,
144
144
  staticHash: hash,
145
+ outputHash,
145
146
  publicPath: '/',
146
147
  editorName: displayName,
147
148
  envVariables: getEnvVariables(),
@@ -470,6 +471,7 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
470
471
  return handleFallback({
471
472
  remotionRoot,
472
473
  hash: staticHash,
474
+ outputHash,
473
475
  response,
474
476
  request,
475
477
  getCurrentInputProps,