@remotion/studio-server 4.0.491 → 4.0.493

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.
@@ -434,6 +434,8 @@ const transformLoneJsxElement = (expression, transformation, changesMade, parent
434
434
  compId === transformation.idToDelete) ||
435
435
  (transformation.type === 'rename-composition' &&
436
436
  compId === transformation.idToRename) ||
437
+ (transformation.type === 'update-composition-metadata' &&
438
+ compId === transformation.idToUpdate) ||
437
439
  (transformation.type === 'duplicate-composition' &&
438
440
  compId === transformation.idToDuplicate) ||
439
441
  (transformation.type === 'delete-folder' &&
@@ -512,6 +514,21 @@ const mapJsxChild = (c, transformation, changesMade, parentFolderName) => {
512
514
  }),
513
515
  ];
514
516
  }
517
+ if (transformation.type === 'update-composition-metadata' &&
518
+ compId === transformation.idToUpdate) {
519
+ return [
520
+ changeComposition({
521
+ jsxElement: c,
522
+ newCompositionId: null,
523
+ newCompositionFps: transformation.newFps,
524
+ newCompositionDurationInFrames: transformation.newDurationInFrames,
525
+ newCompositionHeight: transformation.newHeight,
526
+ newCompositionWidth: transformation.newWidth,
527
+ changesMade,
528
+ newTagToUse: null,
529
+ }),
530
+ ];
531
+ }
515
532
  if (transformation.type === 'delete-composition' &&
516
533
  compId === transformation.idToDelete) {
517
534
  changesMade.push({
@@ -783,7 +800,8 @@ const changeComposition = ({ jsxElement, newCompositionId, newCompositionFps, ne
783
800
  // id="one"
784
801
  if (attribute.name.name === 'id' &&
785
802
  attribute.value &&
786
- attribute.value.type === 'StringLiteral') {
803
+ attribute.value.type === 'StringLiteral' &&
804
+ newCompositionId !== null) {
787
805
  changesMade.push({
788
806
  description: 'Replaced composition id',
789
807
  });
@@ -796,7 +814,8 @@ const changeComposition = ({ jsxElement, newCompositionId, newCompositionFps, ne
796
814
  if (attribute.name.name === 'id' &&
797
815
  attribute.value &&
798
816
  attribute.value.type === 'JSXExpressionContainer' &&
799
- attribute.value.expression.type === 'StringLiteral') {
817
+ attribute.value.expression.type === 'StringLiteral' &&
818
+ newCompositionId !== null) {
800
819
  changesMade.push({
801
820
  description: 'Replaced composition id',
802
821
  });
@@ -811,85 +830,74 @@ const changeComposition = ({ jsxElement, newCompositionId, newCompositionFps, ne
811
830
  },
812
831
  };
813
832
  }
814
- if (attribute.name.name === 'fps' &&
815
- attribute.value &&
816
- attribute.value.type === 'JSXExpressionContainer' &&
817
- attribute.value.expression.type === 'NumericLiteral' &&
818
- newCompositionFps !== null) {
833
+ if (attribute.name.name === 'fps' && newCompositionFps !== null) {
819
834
  changesMade.push({
820
835
  description: 'Replaced FPS',
821
836
  });
822
837
  return {
823
838
  ...attribute,
824
- value: {
825
- ...attribute.value,
826
- expression: {
827
- ...attribute.value.expression,
828
- value: newCompositionFps,
829
- },
830
- },
839
+ value: b.jsxExpressionContainer(b.numericLiteral(newCompositionFps)),
831
840
  };
832
841
  }
833
842
  if (attribute.name.name === 'durationInFrames' &&
834
- attribute.value &&
835
- attribute.value.type === 'JSXExpressionContainer' &&
836
- attribute.value.expression.type === 'NumericLiteral' &&
837
843
  newCompositionDurationInFrames !== null) {
838
844
  changesMade.push({
839
845
  description: 'Replaced durationInFrames',
840
846
  });
841
847
  return {
842
848
  ...attribute,
843
- value: {
844
- ...attribute.value,
845
- expression: {
846
- ...attribute.value.expression,
847
- value: newCompositionDurationInFrames,
848
- },
849
- },
849
+ value: b.jsxExpressionContainer(b.numericLiteral(newCompositionDurationInFrames)),
850
850
  };
851
851
  }
852
- if (attribute.name.name === 'width' &&
853
- attribute.value &&
854
- attribute.value.type === 'JSXExpressionContainer' &&
855
- attribute.value.expression.type === 'NumericLiteral' &&
856
- newCompositionWidth !== null) {
852
+ if (attribute.name.name === 'width' && newCompositionWidth !== null) {
857
853
  changesMade.push({
858
854
  description: 'Replaced width',
859
855
  });
860
856
  return {
861
857
  ...attribute,
862
- value: {
863
- ...attribute.value,
864
- expression: {
865
- ...attribute.value.expression,
866
- value: newCompositionWidth,
867
- },
868
- },
858
+ value: b.jsxExpressionContainer(b.numericLiteral(newCompositionWidth)),
869
859
  };
870
860
  }
871
- if (attribute.name.name === 'height' &&
872
- attribute.value &&
873
- attribute.value.type === 'JSXExpressionContainer' &&
874
- attribute.value.expression.type === 'NumericLiteral' &&
875
- newCompositionHeight !== null) {
861
+ if (attribute.name.name === 'height' && newCompositionHeight !== null) {
876
862
  changesMade.push({
877
863
  description: 'Replaced height',
878
864
  });
879
865
  return {
880
866
  ...attribute,
881
- value: {
882
- ...attribute.value,
883
- expression: {
884
- ...attribute.value.expression,
885
- value: newCompositionHeight,
886
- },
887
- },
867
+ value: b.jsxExpressionContainer(b.numericLiteral(newCompositionHeight)),
888
868
  };
889
869
  }
890
870
  return attribute;
891
871
  })
892
872
  .filter(Boolean);
873
+ if (newCompositionFps !== null &&
874
+ !attributes.some((attribute) => attribute.type === 'JSXAttribute' &&
875
+ attribute.name.type === 'JSXIdentifier' &&
876
+ attribute.name.name === 'fps')) {
877
+ changesMade.push({ description: 'Added FPS' });
878
+ attributes.push(jsxAttributeWithExpression('fps', b.numericLiteral(newCompositionFps)));
879
+ }
880
+ if (newCompositionDurationInFrames !== null &&
881
+ !attributes.some((attribute) => attribute.type === 'JSXAttribute' &&
882
+ attribute.name.type === 'JSXIdentifier' &&
883
+ attribute.name.name === 'durationInFrames')) {
884
+ changesMade.push({ description: 'Added durationInFrames' });
885
+ attributes.push(jsxAttributeWithExpression('durationInFrames', b.numericLiteral(newCompositionDurationInFrames)));
886
+ }
887
+ if (newCompositionWidth !== null &&
888
+ !attributes.some((attribute) => attribute.type === 'JSXAttribute' &&
889
+ attribute.name.type === 'JSXIdentifier' &&
890
+ attribute.name.name === 'width')) {
891
+ changesMade.push({ description: 'Added width' });
892
+ attributes.push(jsxAttributeWithExpression('width', b.numericLiteral(newCompositionWidth)));
893
+ }
894
+ if (newCompositionHeight !== null &&
895
+ !attributes.some((attribute) => attribute.type === 'JSXAttribute' &&
896
+ attribute.name.type === 'JSXIdentifier' &&
897
+ attribute.name.name === 'height')) {
898
+ changesMade.push({ description: 'Added height' });
899
+ attributes.push(jsxAttributeWithExpression('height', b.numericLiteral(newCompositionHeight)));
900
+ }
893
901
  const newName = newTagToUse !== null && newTagToUse !== void 0 ? newTagToUse : name.name;
894
902
  if (newName !== name.name) {
895
903
  changesMade.push({
@@ -74,6 +74,11 @@ const getStaticNumber = (attribute) => {
74
74
  if (expression.type === 'NumericLiteral') {
75
75
  return expression.value;
76
76
  }
77
+ if (expression.type === 'UnaryExpression' &&
78
+ expression.operator === '-' &&
79
+ expression.argument.type === 'NumericLiteral') {
80
+ return -expression.argument.value;
81
+ }
77
82
  if (expression.type === 'Identifier' && expression.name === 'Infinity') {
78
83
  return Infinity;
79
84
  }
@@ -508,6 +508,9 @@ const getComponentRootNode = (declaration) => {
508
508
  const createSequenceElement = () => {
509
509
  return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier('Sequence'), []), recast.types.builders.jsxClosingElement(recast.types.builders.jsxIdentifier('Sequence')), []);
510
510
  };
511
+ const createSequenceWithChild = ({ child, sequenceLocalName, }) => {
512
+ return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(sequenceLocalName), []), recast.types.builders.jsxClosingElement(recast.types.builders.jsxIdentifier(sequenceLocalName)), [child]);
513
+ };
511
514
  const createNumberAttribute = (name, value) => {
512
515
  return recast.types.builders.jsxAttribute(recast.types.builders.jsxIdentifier(name), recast.types.builders.jsxExpressionContainer(recast.types.builders.numericLiteral(value)));
513
516
  };
@@ -1019,8 +1022,8 @@ const createCompositionComponentElement = ({ localName, props, }) => {
1019
1022
  return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), attributes, true), null, []);
1020
1023
  };
1021
1024
  const addElementToComponentRoot = ({ ast, exportName, element, }) => {
1022
- var _a;
1023
- var _b;
1025
+ var _a, _b;
1026
+ var _c, _d;
1024
1027
  const declaration = getDeclarationByExportName({ ast, exportName });
1025
1028
  if (!declaration) {
1026
1029
  throw new Error('Could not find composition component declaration');
@@ -1033,9 +1036,6 @@ const addElementToComponentRoot = ({ ast, exportName, element, }) => {
1033
1036
  }
1034
1037
  throw new Error('Composition component does not return JSX');
1035
1038
  }
1036
- if (rootNode.type === 'JSXElement' && rootNode.openingElement.selfClosing) {
1037
- throw new Error('Cannot insert into a self-closing root JSX element');
1038
- }
1039
1039
  const CANVAS_ROOT_ELEMENTS = [
1040
1040
  'ThreeCanvas',
1041
1041
  'RiveCanvas',
@@ -1047,11 +1047,35 @@ const addElementToComponentRoot = ({ ast, exportName, element, }) => {
1047
1047
  CANVAS_ROOT_ELEMENTS.includes(rootNode.openingElement.name.name)) {
1048
1048
  throw new Error(`Cannot insert a JSX element into a composition whose root element is <${rootNode.openingElement.name.name}>`);
1049
1049
  }
1050
+ if (rootNode.type === 'JSXElement' && rootNode.openingElement.selfClosing) {
1051
+ const fragment = recast.types.builders.jsxFragment(recast.types.builders.jsxOpeningFragment(), recast.types.builders.jsxClosingFragment(), [
1052
+ createSequenceWithChild({
1053
+ child: rootNode,
1054
+ sequenceLocalName: ensureSequenceImport(ast),
1055
+ }),
1056
+ element,
1057
+ ]);
1058
+ let replaced = false;
1059
+ recast.types.visit(ast, {
1060
+ visitJSXElement(astPath) {
1061
+ if (astPath.node === rootNode) {
1062
+ astPath.replace(fragment);
1063
+ replaced = true;
1064
+ return false;
1065
+ }
1066
+ this.traverse(astPath);
1067
+ },
1068
+ });
1069
+ if (!replaced) {
1070
+ throw new Error('Could not replace composition component root');
1071
+ }
1072
+ return (_c = (_a = rootNode.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _c !== void 0 ? _c : 1;
1073
+ }
1050
1074
  if (!rootNode.children) {
1051
1075
  throw new Error('Composition component root does not accept children');
1052
1076
  }
1053
1077
  rootNode.children.push(element);
1054
- return (_b = (_a = rootNode.loc) === null || _a === void 0 ? void 0 : _a.start.line) !== null && _b !== void 0 ? _b : 1;
1078
+ return (_d = (_b = rootNode.loc) === null || _b === void 0 ? void 0 : _b.start.line) !== null && _d !== void 0 ? _d : 1;
1055
1079
  };
1056
1080
  const getDefaultExportDeclaration = (ast) => {
1057
1081
  let declaration = null;
@@ -40,6 +40,9 @@ const getCodemodLogMessage = (codemod) => {
40
40
  if (codemod.type === 'rename-composition') {
41
41
  return `Renamed composition "${codemod.idToRename}" to "${codemod.newId}"`;
42
42
  }
43
+ if (codemod.type === 'update-composition-metadata') {
44
+ return `Updated metadata of composition "${codemod.idToUpdate}"`;
45
+ }
43
46
  if (codemod.type === 'delete-composition') {
44
47
  return `Deleted composition "${codemod.idToDelete}"`;
45
48
  }
@@ -84,6 +87,14 @@ const getCodemodUndoDescription = (codemod) => {
84
87
  entryType: codemod.type,
85
88
  };
86
89
  }
90
+ if (codemod.type === 'update-composition-metadata') {
91
+ const label = `metadata of composition "${codemod.idToUpdate}"`;
92
+ return {
93
+ undoMessage: `↩️ Update of ${label}`,
94
+ redoMessage: `↪️ Update of ${label}`,
95
+ entryType: codemod.type,
96
+ };
97
+ }
87
98
  if (codemod.type === 'duplicate-composition') {
88
99
  const label = `composition "${codemod.idToDuplicate}" to "${codemod.newId}"`;
89
100
  return {
@@ -23,28 +23,31 @@ export declare const hasJsxChildrenAttribute: (jsxElement: JSXOpeningElement) =>
23
23
  export declare const getStaticJsxTextContent: (jsxElement: JSXElement) => StaticJsxTextContent | null;
24
24
  export declare const findNodePathForJsxElement: (ast: File, target: JSXOpeningElement) => SequenceNodePath | null;
25
25
  export declare const lineColumnToNodePath: (ast: File, targetLine: number) => SequenceNodePath | null;
26
- export declare const computeSequencePropsStatusFromContent: ({ fileContents, nodePath, componentIdentity, keys, effects, videoConfigValues, }: {
26
+ export declare const computeSequencePropsStatusFromContent: ({ fileContents, nodePath, componentIdentity, keys, assetKeys, effects, videoConfigValues, }: {
27
27
  fileContents: string;
28
28
  nodePath: SequenceNodePath;
29
29
  componentIdentity: string | null;
30
30
  keys: string[];
31
+ assetKeys?: string[] | undefined;
31
32
  effects: string[][];
32
33
  videoConfigValues: VideoConfigValues | null;
33
34
  }) => CanUpdateSequencePropsResponseTrue;
34
- export declare const computeSequencePropsStatus: ({ fileName, nodePath, componentIdentity, keys, effects, remotionRoot, videoConfigValues, }: {
35
+ export declare const computeSequencePropsStatus: ({ fileName, nodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, videoConfigValues, }: {
35
36
  fileName: string;
36
37
  nodePath: SequenceNodePath;
37
38
  componentIdentity: string | null;
38
39
  keys: string[];
40
+ assetKeys?: string[] | undefined;
39
41
  effects: string[][];
40
42
  remotionRoot: string;
41
43
  videoConfigValues: VideoConfigValues | null;
42
44
  }) => CanUpdateSequencePropsResponseTrue;
43
- export declare const computeSequencePropsStatusFromFilenameByLine: ({ fileName, line, componentIdentity, keys, effects, remotionRoot, logLevel, videoConfigValues, }: {
45
+ export declare const computeSequencePropsStatusFromFilenameByLine: ({ fileName, line, componentIdentity, keys, assetKeys, effects, remotionRoot, logLevel, videoConfigValues, }: {
44
46
  fileName: string;
45
47
  line: number;
46
48
  componentIdentity: string | null;
47
49
  keys: string[];
50
+ assetKeys?: string[] | undefined;
48
51
  effects: string[][];
49
52
  remotionRoot: string;
50
53
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
@@ -480,7 +480,7 @@ const getComputedStatus = (node, ast, videoConfigValues) => {
480
480
  };
481
481
  };
482
482
  exports.getComputedStatus = getComputedStatus;
483
- const getPropsStatus = (jsxElement, ast, videoConfigValues) => {
483
+ const getPropsStatus = (jsxElement, ast, videoConfigValues, assetKeys) => {
484
484
  const props = {};
485
485
  for (const attr of jsxElement.attributes) {
486
486
  if (attr.type === 'JSXSpreadAttribute') {
@@ -504,11 +504,14 @@ const getPropsStatus = (jsxElement, ast, videoConfigValues) => {
504
504
  }
505
505
  if (value.type === 'JSXExpressionContainer') {
506
506
  const { expression } = value;
507
+ const staticValueOptions = {
508
+ allowSpecialValues: assetKeys.includes(name),
509
+ };
507
510
  if (expression.type === 'JSXEmptyExpression') {
508
511
  props[name] = computedStatus();
509
512
  continue;
510
513
  }
511
- if (!(0, exports.isStaticValue)(expression)) {
514
+ if (!(0, exports.isStaticValue)(expression, staticValueOptions)) {
512
515
  const numericExpression = (0, video_config_numeric_expression_1.parseVideoConfigNumericExpression)({
513
516
  node: expression,
514
517
  videoConfigValues,
@@ -518,7 +521,7 @@ const getPropsStatus = (jsxElement, ast, videoConfigValues) => {
518
521
  : (0, exports.getComputedStatus)(expression, ast, videoConfigValues);
519
522
  continue;
520
523
  }
521
- props[name] = staticStatus((0, exports.extractStaticValue)(expression), null);
524
+ props[name] = staticStatus((0, exports.extractStaticValue)(expression, staticValueOptions), null);
522
525
  continue;
523
526
  }
524
527
  props[name] = computedStatus();
@@ -666,7 +669,7 @@ const validateStyleValue = (childKey, value) => {
666
669
  }
667
670
  return true;
668
671
  };
669
- const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfigValues, }) => {
672
+ const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfigValues, allowSpecialValues, }) => {
670
673
  const attr = jsxElement.attributes.find((a) => a.type !== 'JSXSpreadAttribute' &&
671
674
  a.name.type !== 'JSXNamespacedName' &&
672
675
  a.name.name === parentKey);
@@ -692,7 +695,8 @@ const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfig
692
695
  return staticStatus(undefined, null);
693
696
  }
694
697
  const propValue = prop.value;
695
- if (!(0, exports.isStaticValue)(propValue)) {
698
+ const staticValueOptions = { allowSpecialValues };
699
+ if (!(0, exports.isStaticValue)(propValue, staticValueOptions)) {
696
700
  const numericExpression = (0, video_config_numeric_expression_1.parseVideoConfigNumericExpression)({
697
701
  node: propValue,
698
702
  videoConfigValues,
@@ -701,7 +705,7 @@ const getNestedPropStatus = ({ jsxElement, ast, parentKey, childKey, videoConfig
701
705
  ? staticStatus(numericExpression.value, numericExpression)
702
706
  : (0, exports.getComputedStatus)(propValue, ast, videoConfigValues);
703
707
  }
704
- const propStatus = (0, exports.extractStaticValue)(propValue);
708
+ const propStatus = (0, exports.extractStaticValue)(propValue, staticValueOptions);
705
709
  if (!validateStyleValue(childKey, propStatus)) {
706
710
  return computedStatus();
707
711
  }
@@ -716,8 +720,8 @@ const computeEffectsForJsx = ({ ast, jsxElement, effects, videoConfigValues, })
716
720
  videoConfigValues,
717
721
  }));
718
722
  };
719
- const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys, videoConfigValues, }) => {
720
- const allProps = getPropsStatus(jsxElement, ast, videoConfigValues);
723
+ const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys, assetKeys, videoConfigValues, }) => {
724
+ const allProps = getPropsStatus(jsxElement, ast, videoConfigValues, assetKeys);
721
725
  const filteredProps = {};
722
726
  for (const key of keys) {
723
727
  if (key === 'children') {
@@ -744,6 +748,7 @@ const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys,
744
748
  parentKey: key.slice(0, dotIndex),
745
749
  childKey: key.slice(dotIndex + 1),
746
750
  videoConfigValues,
751
+ allowSpecialValues: assetKeys.includes(key),
747
752
  });
748
753
  }
749
754
  else if (key in allProps) {
@@ -755,7 +760,7 @@ const computeSequenceOnlyPropsRecord = ({ jsxElement, jsxElementNode, ast, keys,
755
760
  }
756
761
  return filteredProps;
757
762
  };
758
- const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, effects, videoConfigValues, }) => {
763
+ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, componentIdentity, keys, assetKeys = [], effects, videoConfigValues, }) => {
759
764
  var _a;
760
765
  const ast = (0, parse_ast_1.parseAst)(fileContents);
761
766
  const videoConfigIdentifierValues = (0, video_config_values_1.getVideoConfigIdentifierValues)({
@@ -778,6 +783,7 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, compone
778
783
  jsxElementNode,
779
784
  ast,
780
785
  keys,
786
+ assetKeys,
781
787
  videoConfigValues: videoConfigIdentifierValues,
782
788
  });
783
789
  const effectsStatuses = computeEffectsForJsx({
@@ -793,7 +799,7 @@ const computeSequencePropsStatusFromContent = ({ fileContents, nodePath, compone
793
799
  };
794
800
  };
795
801
  exports.computeSequencePropsStatusFromContent = computeSequencePropsStatusFromContent;
796
- const computeSequencePropsStatus = ({ fileName, nodePath, componentIdentity, keys, effects, remotionRoot, videoConfigValues, }) => {
802
+ const computeSequencePropsStatus = ({ fileName, nodePath, componentIdentity, keys, assetKeys = [], effects, remotionRoot, videoConfigValues, }) => {
797
803
  const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
798
804
  remotionRoot,
799
805
  fileName,
@@ -805,12 +811,13 @@ const computeSequencePropsStatus = ({ fileName, nodePath, componentIdentity, key
805
811
  nodePath,
806
812
  componentIdentity,
807
813
  keys,
814
+ assetKeys,
808
815
  effects,
809
816
  videoConfigValues,
810
817
  });
811
818
  };
812
819
  exports.computeSequencePropsStatus = computeSequencePropsStatus;
813
- const computeSequencePropsStatusFromFilenameByLine = ({ fileName, line, componentIdentity, keys, effects, remotionRoot, logLevel, videoConfigValues, }) => {
820
+ const computeSequencePropsStatusFromFilenameByLine = ({ fileName, line, componentIdentity, keys, assetKeys = [], effects, remotionRoot, logLevel, videoConfigValues, }) => {
814
821
  try {
815
822
  const { absolutePath } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
816
823
  remotionRoot,
@@ -835,6 +842,7 @@ const computeSequencePropsStatusFromFilenameByLine = ({ fileName, line, componen
835
842
  nodePath: resolvedNodePath,
836
843
  componentIdentity,
837
844
  keys,
845
+ assetKeys,
838
846
  effects,
839
847
  remotionRoot,
840
848
  videoConfigValues,
@@ -331,6 +331,7 @@ const saveSequencePropsHandler = ({ input: { edits, movedKeyframes = { sequenceK
331
331
  const newStatus = (0, can_update_sequence_props_1.computeSequencePropsStatusFromContent)({
332
332
  fileContents: output,
333
333
  keys: (0, studio_shared_1.getAllSchemaKeys)(edit.schema),
334
+ assetKeys: (0, studio_shared_1.getAssetSchemaKeys)(edit.schema),
334
335
  nodePath: edit.nodePath.nodePath,
335
336
  componentIdentity: null,
336
337
  effects: [],
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.subscribeToSequenceProps = void 0;
4
4
  const sequence_props_watchers_1 = require("../sequence-props-watchers");
5
- const subscribeToSequenceProps = ({ input: { fileName, line, column, nodePath, componentIdentity, keys, effects, clientId, videoConfigValues, }, remotionRoot, logLevel, }) => {
5
+ const subscribeToSequenceProps = ({ input: { fileName, line, column, nodePath, componentIdentity, keys, assetKeys = [], effects, clientId, videoConfigValues, }, remotionRoot, logLevel, }) => {
6
6
  const result = (0, sequence_props_watchers_1.subscribeToSequencePropsWatchers)({
7
7
  fileName,
8
8
  line,
@@ -10,6 +10,7 @@ const subscribeToSequenceProps = ({ input: { fileName, line, column, nodePath, c
10
10
  nodePath,
11
11
  componentIdentity,
12
12
  keys,
13
+ assetKeys,
13
14
  effects,
14
15
  remotionRoot,
15
16
  clientId,
@@ -2,13 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.unsubscribeFromSequenceProps = void 0;
4
4
  const sequence_props_watchers_1 = require("../sequence-props-watchers");
5
- const unsubscribeFromSequenceProps = ({ input: { fileName, nodePath, clientId, sequenceKeys, effectKeys }, remotionRoot, }) => {
5
+ const unsubscribeFromSequenceProps = ({ input: { fileName, nodePath, clientId, sequenceKeys, assetKeys = [], effectKeys, }, remotionRoot, }) => {
6
6
  (0, sequence_props_watchers_1.unsubscribeFromSequencePropsWatchers)({
7
7
  fileName,
8
8
  nodePath: nodePath.nodePath,
9
9
  remotionRoot,
10
10
  clientId,
11
11
  sequenceKeys,
12
+ assetKeys,
12
13
  effectKeys,
13
14
  videoConfigValues: nodePath.videoConfigValues,
14
15
  });
@@ -1,24 +1,26 @@
1
1
  import { type SubscribeToSequencePropsResponse } from '@remotion/studio-shared';
2
2
  import type { SequenceNodePath, VideoConfigValues } from 'remotion';
3
- export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }: {
3
+ export declare const subscribeToSequencePropsWatchers: ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }: {
4
4
  fileName: string;
5
5
  line: number;
6
6
  column: number;
7
7
  nodePath: SequenceNodePath | null;
8
8
  componentIdentity: string | null;
9
9
  keys: string[];
10
+ assetKeys: string[];
10
11
  effects: string[][];
11
12
  remotionRoot: string;
12
13
  clientId: string;
13
14
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
14
15
  videoConfigValues: VideoConfigValues;
15
16
  }) => SubscribeToSequencePropsResponse;
16
- export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, effectKeys, videoConfigValues, }: {
17
+ export declare const unsubscribeFromSequencePropsWatchers: ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, assetKeys, effectKeys, videoConfigValues, }: {
17
18
  fileName: string;
18
19
  nodePath: SequenceNodePath;
19
20
  remotionRoot: string;
20
21
  clientId: string;
21
22
  sequenceKeys: string[];
23
+ assetKeys: string[];
22
24
  effectKeys: string[][];
23
25
  videoConfigValues: VideoConfigValues | null;
24
26
  }) => 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) => `${(0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath)}:${JSON.stringify(nodePath.videoConfigValues)}`;
18
- const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, componentIdentity, keys, effects, remotionRoot, logLevel, videoConfigValues, }) => {
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, componentIdentity, keys, assetKeys, effects, remotionRoot, logLevel, videoConfigValues, }) => {
19
19
  if (preferredNodePath) {
20
20
  try {
21
21
  const fromNodePath = (0, can_update_sequence_props_1.computeSequencePropsStatus)({
@@ -23,6 +23,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, com
23
23
  nodePath: preferredNodePath,
24
24
  componentIdentity,
25
25
  keys,
26
+ assetKeys,
26
27
  effects,
27
28
  remotionRoot,
28
29
  videoConfigValues,
@@ -56,6 +57,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, com
56
57
  nodePath: cachedNodePath,
57
58
  componentIdentity,
58
59
  keys,
60
+ assetKeys,
59
61
  effects,
60
62
  remotionRoot,
61
63
  videoConfigValues,
@@ -88,6 +90,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, com
88
90
  line,
89
91
  componentIdentity,
90
92
  keys,
93
+ assetKeys,
91
94
  effects,
92
95
  remotionRoot,
93
96
  logLevel,
@@ -95,7 +98,7 @@ const getSequencePropsStatus = ({ fileName, line, column, preferredNodePath, com
95
98
  });
96
99
  return status;
97
100
  };
98
- const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }) => {
101
+ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: preferredNodePath, componentIdentity, keys, assetKeys, effects, remotionRoot, clientId, logLevel, videoConfigValues, }) => {
99
102
  var _a;
100
103
  const initialResult = getSequencePropsStatus({
101
104
  fileName,
@@ -104,6 +107,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
104
107
  preferredNodePath,
105
108
  componentIdentity,
106
109
  keys,
110
+ assetKeys,
107
111
  effects,
108
112
  remotionRoot,
109
113
  logLevel,
@@ -116,7 +120,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
116
120
  // Cache the resolved nodePath for future lookups with stale source maps
117
121
  (0, node_path_cache_1.setCachedNodePath)(fileName, line, column, initialResult.nodePath.nodePath);
118
122
  const { nodePath } = initialResult;
119
- const watcherKey = getWatcherKey(nodePath);
123
+ const watcherKey = getWatcherKey(nodePath, assetKeys);
120
124
  // If a watcher already exists for this key, just bump the ref count
121
125
  if ((_a = sequencePropsWatchers[clientId]) === null || _a === void 0 ? void 0 : _a[watcherKey]) {
122
126
  sequencePropsWatchers[clientId][watcherKey].refCount++;
@@ -138,6 +142,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
138
142
  nodePath: nodePath.nodePath,
139
143
  componentIdentity,
140
144
  keys,
145
+ assetKeys,
141
146
  effects,
142
147
  videoConfigValues,
143
148
  });
@@ -181,7 +186,7 @@ const subscribeToSequencePropsWatchers = ({ fileName, line, column, nodePath: pr
181
186
  return initialResult;
182
187
  };
183
188
  exports.subscribeToSequencePropsWatchers = subscribeToSequencePropsWatchers;
184
- const unsubscribeFromSequencePropsWatchers = ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, effectKeys, videoConfigValues, }) => {
189
+ const unsubscribeFromSequencePropsWatchers = ({ fileName, nodePath, remotionRoot, clientId, sequenceKeys, assetKeys, effectKeys, videoConfigValues, }) => {
185
190
  const absolutePath = node_path_1.default.resolve(remotionRoot, fileName);
186
191
  const watcherKey = getWatcherKey({
187
192
  absolutePath,
@@ -189,7 +194,7 @@ const unsubscribeFromSequencePropsWatchers = ({ fileName, nodePath, remotionRoot
189
194
  sequenceKeys,
190
195
  effectKeys,
191
196
  videoConfigValues,
192
- });
197
+ }, assetKeys);
193
198
  if (!sequencePropsWatchers[clientId] ||
194
199
  !sequencePropsWatchers[clientId][watcherKey]) {
195
200
  return;
@@ -3,7 +3,7 @@ export interface UndoEntryDescription {
3
3
  undoMessage: string;
4
4
  redoMessage: string;
5
5
  }
6
- type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'keyframe-add' | 'keyframe-delete' | 'add-effect' | 'delete-effect' | 'duplicate-effect' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'split-jsx-sequence' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'new-composition' | 'duplicate-composition' | 'move-composition-to-folder' | 'new-folder' | 'delete-folder' | 'rename-folder';
6
+ type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'keyframe-add' | 'keyframe-delete' | 'add-effect' | 'delete-effect' | 'duplicate-effect' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'split-jsx-sequence' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'update-composition-metadata' | 'new-composition' | 'duplicate-composition' | 'move-composition-to-folder' | 'new-folder' | 'delete-folder' | 'rename-folder';
7
7
  type UndoEntrySnapshot = {
8
8
  filePath: string;
9
9
  oldContents: string | null;
@@ -55,6 +55,8 @@ type UndoEntry = {
55
55
  entryType: 'delete-composition';
56
56
  } | {
57
57
  entryType: 'rename-composition';
58
+ } | {
59
+ entryType: 'update-composition-metadata';
58
60
  } | {
59
61
  entryType: 'new-composition';
60
62
  } | {
package/dist/routes.js CHANGED
@@ -278,6 +278,7 @@ const handleFallback = async ({ remotionRoot, hash, response, request, getCurren
278
278
  title: 'Remotion Studio',
279
279
  renderDefaults: getRenderDefaults(),
280
280
  publicFolderExists: (0, node_fs_1.existsSync)(publicDir) ? publicDir : null,
281
+ fileSystemPlatform: process.platform,
281
282
  gitSource,
282
283
  projectName: (0, studio_shared_1.getProjectName)({
283
284
  basename: node_path_1.default.basename,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio-server"
4
4
  },
5
5
  "name": "@remotion/studio-server",
6
- "version": "4.0.491",
6
+ "version": "4.0.493",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -27,11 +27,11 @@
27
27
  "@babel/parser": "7.24.1",
28
28
  "semver": "7.5.3",
29
29
  "prettier": "3.8.1",
30
- "remotion": "4.0.491",
30
+ "remotion": "4.0.493",
31
31
  "recast": "0.23.11",
32
- "@remotion/bundler": "4.0.491",
33
- "@remotion/renderer": "4.0.491",
34
- "@remotion/studio-shared": "4.0.491",
32
+ "@remotion/bundler": "4.0.493",
33
+ "@remotion/renderer": "4.0.493",
34
+ "@remotion/studio-shared": "4.0.493",
35
35
  "memfs": "3.4.3",
36
36
  "open": "8.4.2"
37
37
  },
@@ -39,7 +39,7 @@
39
39
  "ast-types": "0.16.1",
40
40
  "react": "19.2.3",
41
41
  "@types/semver": "7.5.3",
42
- "@remotion/eslint-config-internal": "4.0.491",
42
+ "@remotion/eslint-config-internal": "4.0.493",
43
43
  "eslint": "9.19.0",
44
44
  "@types/node": "20.12.14",
45
45
  "@typescript/native-preview": "7.0.0-dev.20260217.1"