@remotion/studio 4.0.472 → 4.0.473

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 (133) hide show
  1. package/dist/api/rename-static-file.d.ts +6 -0
  2. package/dist/api/rename-static-file.js +18 -0
  3. package/dist/components/AssetSelector.js +45 -4
  4. package/dist/components/AssetSelectorItem.js +153 -27
  5. package/dist/components/Canvas.js +60 -11
  6. package/dist/components/ConfirmationDialog-types.d.ts +8 -0
  7. package/dist/components/ConfirmationDialog-types.js +2 -0
  8. package/dist/components/ConfirmationDialog.d.ts +7 -0
  9. package/dist/components/ConfirmationDialog.js +103 -0
  10. package/dist/components/ContextMenu.d.ts +9 -1
  11. package/dist/components/ContextMenu.js +49 -5
  12. package/dist/components/CurrentAsset.d.ts +1 -0
  13. package/dist/components/CurrentAsset.js +13 -2
  14. package/dist/components/EditorContent.js +15 -2
  15. package/dist/components/EditorContexts.js +2 -1
  16. package/dist/components/EditorRuler/Ruler.js +2 -0
  17. package/dist/components/ExplorerPanel.d.ts +0 -4
  18. package/dist/components/ExplorerPanel.js +8 -4
  19. package/dist/components/ExplorerPanelRef.d.ts +4 -0
  20. package/dist/components/ExplorerPanelRef.js +5 -0
  21. package/dist/components/FilePreview.d.ts +1 -1
  22. package/dist/components/InitialCompositionLoader.d.ts +0 -1
  23. package/dist/components/InitialCompositionLoader.js +5 -27
  24. package/dist/components/Menu/MenuItem.js +7 -1
  25. package/dist/components/Menu/SubMenu.js +5 -1
  26. package/dist/components/Menu/portals.js +17 -8
  27. package/dist/components/MenuToolbar.js +5 -1
  28. package/dist/components/ModalContainer.js +6 -1
  29. package/dist/components/Modals.js +6 -2
  30. package/dist/components/NewComposition/ComboBox.js +8 -2
  31. package/dist/components/NewComposition/DeleteStaticFile.d.ts +4 -0
  32. package/dist/components/NewComposition/DeleteStaticFile.js +44 -0
  33. package/dist/components/NewComposition/RenameStaticFile.d.ts +4 -0
  34. package/dist/components/NewComposition/RenameStaticFile.js +118 -0
  35. package/dist/components/OptionsPanel.js +5 -1
  36. package/dist/components/OutlineToggle.d.ts +2 -0
  37. package/dist/components/OutlineToggle.js +20 -0
  38. package/dist/components/Preview.d.ts +0 -2
  39. package/dist/components/Preview.js +23 -33
  40. package/dist/components/PreviewToolbar.js +19 -6
  41. package/dist/components/RenderButton.js +8 -2
  42. package/dist/components/RenderPreview.js +2 -2
  43. package/dist/components/SelectedOutlineOverlay.d.ts +24 -0
  44. package/dist/components/SelectedOutlineOverlay.js +190 -22
  45. package/dist/components/ShowOutlinesProvider.d.ts +4 -0
  46. package/dist/components/ShowOutlinesProvider.js +24 -0
  47. package/dist/components/SizeSelector.js +3 -3
  48. package/dist/components/Splitter/SplitterHandle.js +2 -0
  49. package/dist/components/StaticFilePreview.js +2 -2
  50. package/dist/components/Timeline/KeyframeSettingsModal.d.ts +15 -0
  51. package/dist/components/Timeline/KeyframeSettingsModal.js +150 -0
  52. package/dist/components/Timeline/Timeline.js +3 -13
  53. package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +25 -2
  54. package/dist/components/Timeline/TimelineClipboardKeybindings.js +234 -20
  55. package/dist/components/Timeline/TimelineDeleteKeybindings.js +12 -2
  56. package/dist/components/Timeline/TimelineEffectItem.js +1 -0
  57. package/dist/components/Timeline/TimelineEffectPropItem.js +52 -2
  58. package/dist/components/Timeline/TimelineKeyframeControls.js +5 -15
  59. package/dist/components/Timeline/TimelineKeyframeDiamond.js +24 -21
  60. package/dist/components/Timeline/TimelineKeyframeDiamondIcon.d.ts +6 -0
  61. package/dist/components/Timeline/TimelineKeyframeDiamondIcon.js +14 -0
  62. package/dist/components/Timeline/TimelineKeyframeDragState.d.ts +17 -0
  63. package/dist/components/Timeline/TimelineKeyframeDragState.js +39 -0
  64. package/dist/components/Timeline/TimelineList.js +2 -2
  65. package/dist/components/Timeline/TimelineMediaInfo.d.ts +0 -13
  66. package/dist/components/Timeline/TimelineMediaInfo.js +8 -73
  67. package/dist/components/Timeline/TimelineScaleField.js +1 -1
  68. package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
  69. package/dist/components/Timeline/TimelineSequenceItem.js +276 -22
  70. package/dist/components/Timeline/TimelineSequencePropItem.js +81 -16
  71. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +25 -28
  72. package/dist/components/Timeline/apply-effect-response-to-code-values.d.ts +5 -0
  73. package/dist/components/Timeline/apply-effect-response-to-code-values.js +19 -0
  74. package/dist/components/Timeline/call-add-keyframe.js +2 -0
  75. package/dist/components/Timeline/call-move-keyframe.d.ts +19 -0
  76. package/dist/components/Timeline/call-move-keyframe.js +71 -0
  77. package/dist/components/Timeline/call-update-keyframe-settings.d.ts +22 -0
  78. package/dist/components/Timeline/call-update-keyframe-settings.js +52 -0
  79. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +7 -4
  80. package/dist/components/Timeline/delete-selected-timeline-item.js +33 -21
  81. package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +4 -2
  82. package/dist/components/Timeline/duplicate-selected-timeline-item.js +39 -34
  83. package/dist/components/Timeline/get-bounded-keyframe-drag-delta.d.ts +8 -0
  84. package/dist/components/Timeline/get-bounded-keyframe-drag-delta.js +12 -0
  85. package/dist/components/Timeline/get-keyframe-navigation.d.ts +2 -2
  86. package/dist/components/Timeline/get-keyframe-navigation.js +14 -6
  87. package/dist/components/Timeline/reset-selected-timeline-props.js +3 -2
  88. package/dist/components/Timeline/save-effect-prop.d.ts +14 -3
  89. package/dist/components/Timeline/save-effect-prop.js +36 -18
  90. package/dist/components/Timeline/save-prop-queue.d.ts +2 -1
  91. package/dist/components/Timeline/save-prop-queue.js +5 -2
  92. package/dist/components/Timeline/save-sequence-prop.d.ts +2 -7
  93. package/dist/components/Timeline/save-sequence-prop.js +33 -30
  94. package/dist/components/Timeline/should-clear-selection-on-pointer-down.d.ts +3 -0
  95. package/dist/components/Timeline/should-clear-selection-on-pointer-down.js +7 -0
  96. package/dist/components/Timeline/timeline-asset-link.d.ts +13 -0
  97. package/dist/components/Timeline/timeline-asset-link.js +37 -0
  98. package/dist/components/Timeline/timeline-translate-utils.js +4 -1
  99. package/dist/components/Timeline/use-timeline-keyframe-drag.d.ts +10 -0
  100. package/dist/components/Timeline/use-timeline-keyframe-drag.js +378 -0
  101. package/dist/components/import-assets.d.ts +16 -0
  102. package/dist/components/import-assets.js +155 -18
  103. package/dist/components/load-canvas-content-from-url.d.ts +1 -0
  104. package/dist/components/load-canvas-content-from-url.js +9 -3
  105. package/dist/components/use-select-asset.d.ts +1 -0
  106. package/dist/components/use-select-asset.js +30 -0
  107. package/dist/error-overlay/error-origin.d.ts +3 -0
  108. package/dist/error-overlay/error-origin.js +42 -0
  109. package/dist/error-overlay/react-overlay/listen-to-runtime-errors.js +6 -2
  110. package/dist/error-overlay/remotion-overlay/ErrorLoader.js +38 -0
  111. package/dist/error-overlay/remotion-overlay/ShortcutHint.js +1 -1
  112. package/dist/error-overlay/remotion-overlay/log-studio-error.d.ts +3 -0
  113. package/dist/error-overlay/remotion-overlay/log-studio-error.js +27 -0
  114. package/dist/esm/{chunk-48grt472.js → chunk-q0jkt0zq.js} +21961 -19299
  115. package/dist/esm/internals.mjs +21961 -19299
  116. package/dist/esm/previewEntry.mjs +20600 -17914
  117. package/dist/esm/renderEntry.mjs +1 -1
  118. package/dist/helpers/get-asset-metadata.js +2 -2
  119. package/dist/helpers/get-preview-file-type.d.ts +2 -0
  120. package/dist/helpers/get-preview-file-type.js +33 -0
  121. package/dist/helpers/install-required-package.d.ts +1 -0
  122. package/dist/helpers/install-required-package.js +39 -0
  123. package/dist/helpers/remote-asset-drag.d.ts +4 -0
  124. package/dist/helpers/remote-asset-drag.js +73 -0
  125. package/dist/helpers/use-asset-drag-events.d.ts +5 -2
  126. package/dist/helpers/use-asset-drag-events.js +13 -2
  127. package/dist/hot-middleware-client/client.js +6 -0
  128. package/dist/state/editor-outlines.d.ts +8 -0
  129. package/dist/state/editor-outlines.js +18 -0
  130. package/dist/state/modals.d.ts +19 -2
  131. package/package.json +10 -10
  132. package/dist/helpers/detect-file-type.d.ts +0 -69
  133. package/dist/helpers/detect-file-type.js +0 -278
@@ -1,6 +1,22 @@
1
+ import { type FileType, type InsertableCompositionElement } from '@remotion/studio-shared';
2
+ export declare const getAssetElement: ({ fileType, src, }: {
3
+ fileType: FileType;
4
+ src: string;
5
+ }) => InsertableCompositionElement | null;
6
+ export declare const getAssetElementFromPath: (assetPath: string) => InsertableCompositionElement | null;
1
7
  export declare const pickFilesToImport: () => Promise<File[]>;
2
8
  export declare const importAssets: ({ compositionFile, compositionId, files, }: {
3
9
  compositionFile: string;
4
10
  compositionId: string;
5
11
  files: File[];
6
12
  }) => Promise<void>;
13
+ export declare const importRemoteAsset: ({ compositionFile, compositionId, url, }: {
14
+ compositionFile: string;
15
+ compositionId: string;
16
+ url: string;
17
+ }) => Promise<void>;
18
+ export declare const insertExistingAssets: ({ assetPaths, compositionFile, compositionId, }: {
19
+ assetPaths: string[];
20
+ compositionFile: string;
21
+ compositionId: string;
22
+ }) => Promise<void>;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.importAssets = exports.pickFilesToImport = void 0;
3
+ exports.insertExistingAssets = exports.importRemoteAsset = exports.importAssets = exports.pickFilesToImport = exports.getAssetElementFromPath = exports.getAssetElement = void 0;
4
+ const studio_shared_1 = require("@remotion/studio-shared");
4
5
  const get_static_files_1 = require("../api/get-static-files");
5
6
  const write_static_file_1 = require("../api/write-static-file");
6
- const detect_file_type_1 = require("../helpers/detect-file-type");
7
+ const install_required_package_1 = require("../helpers/install-required-package");
7
8
  const call_api_1 = require("./call-api");
8
9
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
9
10
  const getAssetElement = ({ fileType, src, }) => {
@@ -37,8 +38,64 @@ const getAssetElement = ({ fileType, src, }) => {
37
38
  dimensions: null,
38
39
  };
39
40
  }
41
+ if (fileType.type === 'wav' ||
42
+ fileType.type === 'mp3' ||
43
+ fileType.type === 'aac' ||
44
+ fileType.type === 'flac') {
45
+ return {
46
+ type: 'asset',
47
+ assetType: 'audio',
48
+ src,
49
+ dimensions: null,
50
+ };
51
+ }
40
52
  return null;
41
53
  };
54
+ exports.getAssetElement = getAssetElement;
55
+ const getAssetElementFromPath = (assetPath) => {
56
+ var _a;
57
+ if (!assetPath || assetPath.includes('\\')) {
58
+ return null;
59
+ }
60
+ const extension = (_a = assetPath.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
61
+ if (!extension || extension === assetPath.toLowerCase()) {
62
+ return null;
63
+ }
64
+ if (['png', 'jpg', 'jpeg', 'webp', 'bmp'].includes(extension)) {
65
+ return {
66
+ type: 'asset',
67
+ assetType: 'image',
68
+ src: assetPath,
69
+ dimensions: null,
70
+ };
71
+ }
72
+ if (extension === 'gif') {
73
+ return {
74
+ type: 'asset',
75
+ assetType: 'gif',
76
+ src: assetPath,
77
+ dimensions: null,
78
+ };
79
+ }
80
+ if (['mp4', 'm4v', 'mov', 'avi', 'webm', 'ts', 'm2ts'].includes(extension)) {
81
+ return {
82
+ type: 'asset',
83
+ assetType: 'video',
84
+ src: assetPath,
85
+ dimensions: null,
86
+ };
87
+ }
88
+ if (['wav', 'mp3', 'aac', 'flac'].includes(extension)) {
89
+ return {
90
+ type: 'asset',
91
+ assetType: 'audio',
92
+ src: assetPath,
93
+ dimensions: null,
94
+ };
95
+ }
96
+ return null;
97
+ };
98
+ exports.getAssetElementFromPath = getAssetElementFromPath;
42
99
  const getAssetLabel = (element) => {
43
100
  if (element.type !== 'asset') {
44
101
  throw new Error('Expected asset element');
@@ -49,7 +106,13 @@ const getAssetLabel = (element) => {
49
106
  if (element.assetType === 'video') {
50
107
  return '<Video>';
51
108
  }
52
- return '<Gif>';
109
+ if (element.assetType === 'gif') {
110
+ return '<Gif>';
111
+ }
112
+ if (element.assetType === 'audio') {
113
+ return '<Audio>';
114
+ }
115
+ throw new Error('Unsupported asset type');
53
116
  };
54
117
  const pickFilesToImport = () => {
55
118
  return new Promise((resolve) => {
@@ -80,6 +143,39 @@ const pickFilesToImport = () => {
80
143
  });
81
144
  };
82
145
  exports.pickFilesToImport = pickFilesToImport;
146
+ const notifyInsertedAssets = (insertedLabels) => {
147
+ if (insertedLabels.length === 1) {
148
+ (0, NotificationCenter_1.showNotification)(`Added ${insertedLabels[0]} to source file`, 2000);
149
+ }
150
+ else if (insertedLabels.length > 1) {
151
+ (0, NotificationCenter_1.showNotification)(`Added ${insertedLabels.length} assets to source file`, 2000);
152
+ }
153
+ };
154
+ const notifyUnsupportedFiles = (unsupportedFiles) => {
155
+ if (unsupportedFiles.length === 1) {
156
+ (0, NotificationCenter_1.showNotification)(`Cannot add ${unsupportedFiles[0]}: Unsupported file type`, 3000);
157
+ }
158
+ else if (unsupportedFiles.length > 1) {
159
+ (0, NotificationCenter_1.showNotification)(`Skipped ${unsupportedFiles.length} unsupported files`, 3000);
160
+ }
161
+ };
162
+ const insertAssetElement = async ({ compositionFile, compositionId, element, }) => {
163
+ const requiredPackage = (0, studio_shared_1.getRequiredPackageForInsertableElement)(element);
164
+ await (0, install_required_package_1.installRequiredPackages)(requiredPackage ? [requiredPackage] : []);
165
+ const result = await (0, call_api_1.callApi)('/api/insert-jsx-element', {
166
+ compositionFile,
167
+ compositionId,
168
+ element,
169
+ });
170
+ if (!result.success) {
171
+ (0, NotificationCenter_1.showNotification)(result.reason, 4000);
172
+ return false;
173
+ }
174
+ return true;
175
+ };
176
+ const downloadRemoteAsset = async (url) => {
177
+ return (0, call_api_1.callApi)('/api/download-remote-asset', { url });
178
+ };
83
179
  const importAssets = async ({ compositionFile, compositionId, files, }) => {
84
180
  if (files.length === 0) {
85
181
  return;
@@ -107,8 +203,8 @@ const importAssets = async ({ compositionFile, compositionId, files, }) => {
107
203
  try {
108
204
  for (const file of files) {
109
205
  const contents = await file.arrayBuffer();
110
- const fileType = (0, detect_file_type_1.detectFileType)(new Uint8Array(contents));
111
- const element = getAssetElement({
206
+ const fileType = (0, studio_shared_1.detectFileType)(new Uint8Array(contents));
207
+ const element = (0, exports.getAssetElement)({
112
208
  fileType,
113
209
  src: file.name,
114
210
  });
@@ -124,34 +220,75 @@ const importAssets = async ({ compositionFile, compositionId, files, }) => {
124
220
  });
125
221
  addedStaticFiles.push(file.name);
126
222
  }
127
- const result = await (0, call_api_1.callApi)('/api/insert-jsx-element', {
223
+ const inserted = await insertAssetElement({
128
224
  compositionFile,
129
225
  compositionId,
130
226
  element,
131
227
  });
132
- if (!result.success) {
228
+ if (!inserted) {
133
229
  notifyAddedStaticFiles();
134
- (0, NotificationCenter_1.showNotification)(result.reason, 4000);
135
230
  return;
136
231
  }
137
232
  insertedLabels.push(getAssetLabel(element));
138
233
  }
139
234
  notifyAddedStaticFiles();
140
- if (insertedLabels.length === 1) {
141
- (0, NotificationCenter_1.showNotification)(`Added ${insertedLabels[0]} to source file`, 2000);
142
- }
143
- else if (insertedLabels.length > 1) {
144
- (0, NotificationCenter_1.showNotification)(`Added ${insertedLabels.length} assets to source file`, 2000);
235
+ notifyInsertedAssets(insertedLabels);
236
+ notifyUnsupportedFiles(unsupportedFiles);
237
+ }
238
+ catch (error) {
239
+ (0, NotificationCenter_1.showNotification)(`Could not add asset: ${error instanceof Error ? error.message : String(error)}`, 4000);
240
+ }
241
+ };
242
+ exports.importAssets = importAssets;
243
+ const importRemoteAsset = async ({ compositionFile, compositionId, url, }) => {
244
+ try {
245
+ const { assetPath, created, element } = await downloadRemoteAsset(url);
246
+ if (created) {
247
+ (0, NotificationCenter_1.showNotification)(`Created ${assetPath} in public folder`, 3000);
145
248
  }
146
- if (unsupportedFiles.length === 1) {
147
- (0, NotificationCenter_1.showNotification)(`Cannot add ${unsupportedFiles[0]}: Unsupported file type`, 3000);
249
+ const inserted = await insertAssetElement({
250
+ compositionFile,
251
+ compositionId,
252
+ element,
253
+ });
254
+ if (!inserted) {
255
+ return;
148
256
  }
149
- else if (unsupportedFiles.length > 1) {
150
- (0, NotificationCenter_1.showNotification)(`Skipped ${unsupportedFiles.length} unsupported files`, 3000);
257
+ notifyInsertedAssets([getAssetLabel(element)]);
258
+ }
259
+ catch (error) {
260
+ (0, NotificationCenter_1.showNotification)(`Could not add remote asset: ${error instanceof Error ? error.message : String(error)}`, 4000);
261
+ }
262
+ };
263
+ exports.importRemoteAsset = importRemoteAsset;
264
+ const insertExistingAssets = async ({ assetPaths, compositionFile, compositionId, }) => {
265
+ if (assetPaths.length === 0) {
266
+ return;
267
+ }
268
+ const insertedLabels = [];
269
+ const unsupportedFiles = [];
270
+ try {
271
+ for (const assetPath of assetPaths) {
272
+ const element = (0, exports.getAssetElementFromPath)(assetPath);
273
+ if (element === null) {
274
+ unsupportedFiles.push(assetPath);
275
+ continue;
276
+ }
277
+ const inserted = await insertAssetElement({
278
+ compositionFile,
279
+ compositionId,
280
+ element,
281
+ });
282
+ if (!inserted) {
283
+ return;
284
+ }
285
+ insertedLabels.push(getAssetLabel(element));
151
286
  }
287
+ notifyInsertedAssets(insertedLabels);
288
+ notifyUnsupportedFiles(unsupportedFiles);
152
289
  }
153
290
  catch (error) {
154
291
  (0, NotificationCenter_1.showNotification)(`Could not add asset: ${error instanceof Error ? error.message : String(error)}`, 4000);
155
292
  }
156
293
  };
157
- exports.importAssets = importAssets;
294
+ exports.insertExistingAssets = insertExistingAssets;
@@ -1,2 +1,3 @@
1
1
  import type { CanvasContent } from 'remotion';
2
+ export declare const deriveCanvasContentFromRoute: (route: string) => CanvasContent | null;
2
3
  export declare const deriveCanvasContentFromUrl: () => CanvasContent | null;
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deriveCanvasContentFromUrl = void 0;
3
+ exports.deriveCanvasContentFromUrl = exports.deriveCanvasContentFromRoute = void 0;
4
4
  const url_state_1 = require("../helpers/url-state");
5
- const deriveCanvasContentFromUrl = () => {
6
- const route = (0, url_state_1.getRoute)();
5
+ const deriveCanvasContentFromRoute = (route) => {
7
6
  const substrings = route.split('/').filter(Boolean);
8
7
  // CJK-named composition IDs are not automatically reselected after page refresh
9
8
  const lastPart = substrings[substrings.length - 1];
10
9
  if (substrings[0] === 'assets') {
10
+ if (!lastPart || substrings.length === 1) {
11
+ return null;
12
+ }
11
13
  return {
12
14
  type: 'asset',
13
15
  asset: decodeURIComponent(route.substring('/assets/'.length)),
@@ -27,4 +29,8 @@ const deriveCanvasContentFromUrl = () => {
27
29
  }
28
30
  return null;
29
31
  };
32
+ exports.deriveCanvasContentFromRoute = deriveCanvasContentFromRoute;
33
+ const deriveCanvasContentFromUrl = () => {
34
+ return (0, exports.deriveCanvasContentFromRoute)((0, url_state_1.getRoute)());
35
+ };
30
36
  exports.deriveCanvasContentFromUrl = deriveCanvasContentFromUrl;
@@ -0,0 +1 @@
1
+ export declare const useSelectAsset: () => (asset: string) => void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSelectAsset = void 0;
4
+ const react_1 = require("react");
5
+ const remotion_1 = require("remotion");
6
+ const folders_1 = require("../state/folders");
7
+ const ExplorerPanelRef_1 = require("./ExplorerPanelRef");
8
+ const useSelectAsset = () => {
9
+ const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
10
+ const { setAssetFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
11
+ return (0, react_1.useCallback)((asset) => {
12
+ var _a;
13
+ setCanvasContent({ type: 'asset', asset });
14
+ (_a = ExplorerPanelRef_1.explorerSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectAssetsPanel();
15
+ setAssetFoldersExpanded((ex) => {
16
+ const split = asset.split('/');
17
+ const keysToExpand = split.map((_, i) => {
18
+ return split.slice(0, i).join('/');
19
+ });
20
+ const newState = {
21
+ ...ex,
22
+ };
23
+ for (const key of keysToExpand) {
24
+ newState[key] = true;
25
+ }
26
+ return newState;
27
+ });
28
+ }, [setAssetFoldersExpanded, setCanvasContent]);
29
+ };
30
+ exports.useSelectAsset = useSelectAsset;
@@ -0,0 +1,3 @@
1
+ export declare const markErrorAsLoggedByServer: (error: object) => void;
2
+ export declare const markErrorMessageAsLoggedByServer: (message: string) => void;
3
+ export declare const wasErrorLoggedByServer: (error: Error) => boolean;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wasErrorLoggedByServer = exports.markErrorMessageAsLoggedByServer = exports.markErrorAsLoggedByServer = void 0;
4
+ const errorsLoggedByServer = new WeakSet();
5
+ const errorMessagesLoggedByServer = new Set();
6
+ const maxLoggedErrorMessages = 100;
7
+ const rememberServerLoggedMessage = (message) => {
8
+ if (errorMessagesLoggedByServer.size >= maxLoggedErrorMessages) {
9
+ errorMessagesLoggedByServer.clear();
10
+ }
11
+ errorMessagesLoggedByServer.add(message);
12
+ };
13
+ const markErrorAsLoggedByServer = (error) => {
14
+ errorsLoggedByServer.add(error);
15
+ };
16
+ exports.markErrorAsLoggedByServer = markErrorAsLoggedByServer;
17
+ const markErrorMessageAsLoggedByServer = (message) => {
18
+ if (message.trim() === '') {
19
+ return;
20
+ }
21
+ rememberServerLoggedMessage(message);
22
+ };
23
+ exports.markErrorMessageAsLoggedByServer = markErrorMessageAsLoggedByServer;
24
+ const wasErrorLoggedByServer = (error) => {
25
+ if (errorsLoggedByServer.has(error)) {
26
+ return true;
27
+ }
28
+ const message = typeof error.message === 'string' ? error.message : null;
29
+ const stack = typeof error.stack === 'string' ? error.stack : null;
30
+ if (message && errorMessagesLoggedByServer.has(message)) {
31
+ return true;
32
+ }
33
+ if (stack) {
34
+ for (const serverLoggedMessage of errorMessagesLoggedByServer) {
35
+ if (stack.includes(serverLoggedMessage)) {
36
+ return true;
37
+ }
38
+ }
39
+ }
40
+ return false;
41
+ };
42
+ exports.wasErrorLoggedByServer = wasErrorLoggedByServer;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getErrorRecord = void 0;
4
4
  exports.listenToRuntimeErrors = listenToRuntimeErrors;
5
5
  const url_state_1 = require("../../helpers/url-state");
6
+ const error_origin_1 = require("../error-origin");
6
7
  const Overlay_1 = require("../remotion-overlay/Overlay");
7
8
  const format_warning_1 = require("./effects/format-warning");
8
9
  const proxy_console_1 = require("./effects/proxy-console");
@@ -60,13 +61,16 @@ function listenToRuntimeErrors(crash) {
60
61
  if (d.type === 'webpack-error') {
61
62
  const { message, frames } = d;
62
63
  const data = (0, format_warning_1.massageWarning)(message, frames);
63
- crashWithFramesRunTime({
64
+ const error = {
64
65
  message: data.message,
65
66
  stack: data.stack,
66
67
  name: '',
67
- });
68
+ };
69
+ (0, error_origin_1.markErrorAsLoggedByServer)(error);
70
+ crashWithFramesRunTime(error);
68
71
  }
69
72
  if (d.type === 'build-error') {
73
+ (0, error_origin_1.markErrorAsLoggedByServer)(d.error);
70
74
  crashWithFramesRunTime(d.error);
71
75
  }
72
76
  });
@@ -2,10 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ErrorLoader = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const studio_shared_1 = require("@remotion/studio-shared");
5
6
  const react_1 = require("react");
7
+ const error_origin_1 = require("../error-origin");
6
8
  const listen_to_runtime_errors_1 = require("../react-overlay/listen-to-runtime-errors");
7
9
  const ErrorDisplay_1 = require("./ErrorDisplay");
8
10
  const ErrorTitle_1 = require("./ErrorTitle");
11
+ const log_studio_error_1 = require("./log-studio-error");
9
12
  const container = {
10
13
  width: '100%',
11
14
  maxWidth: 1000,
@@ -21,6 +24,32 @@ const errorWhileErrorStyle = {
21
24
  lineHeight: 1.5,
22
25
  whiteSpace: 'pre',
23
26
  };
27
+ const shouldLogError = (error) => {
28
+ return (!(0, error_origin_1.wasErrorLoggedByServer)(error) && (0, studio_shared_1.getLocationFromBuildError)(error) === null);
29
+ };
30
+ const shouldIncludeFrameInServerLog = (frame) => {
31
+ var _a, _b, _c, _d;
32
+ return !(((_a = frame.originalFileName) === null || _a === void 0 ? void 0 : _a.includes('node_modules')) ||
33
+ ((_b = frame.originalFileName) === null || _b === void 0 ? void 0 : _b.startsWith('webpack/')) ||
34
+ ((_c = frame.originalFileName) === null || _c === void 0 ? void 0 : _c.includes('/bundler/dist/fast-refresh/')) ||
35
+ ((_d = frame.originalFileName) === null || _d === void 0 ? void 0 : _d.includes('bundler/dist/fast-refresh/')));
36
+ };
37
+ const logSymbolicatedStudioError = (record) => {
38
+ const name = typeof record.error.name === 'string' ? record.error.name : null;
39
+ const message = typeof record.error.message === 'string' ? record.error.message : '';
40
+ const filteredStackFrames = record.stackFrames.filter(shouldIncludeFrameInServerLog);
41
+ const stackFrames = filteredStackFrames.length > 0
42
+ ? filteredStackFrames
43
+ : record.stackFrames[0]
44
+ ? [record.stackFrames[0]]
45
+ : [];
46
+ (0, log_studio_error_1.logStudioErrorData)({
47
+ name,
48
+ message,
49
+ stack: typeof record.error.stack === 'string' ? record.error.stack : null,
50
+ symbolicatedStackFrames: stackFrames.length > 0 ? stackFrames : null,
51
+ });
52
+ };
24
53
  const ErrorLoader = ({ error, keyboardShortcuts, onRetry, canHaveDismissButton, calculateMetadata, }) => {
25
54
  const [state, setState] = (0, react_1.useState)({
26
55
  type: 'loading',
@@ -29,18 +58,27 @@ const ErrorLoader = ({ error, keyboardShortcuts, onRetry, canHaveDismissButton,
29
58
  (0, listen_to_runtime_errors_1.getErrorRecord)(error)
30
59
  .then((record) => {
31
60
  if (record) {
61
+ if (shouldLogError(error)) {
62
+ logSymbolicatedStudioError(record);
63
+ }
32
64
  setState({
33
65
  type: 'symbolicated',
34
66
  record,
35
67
  });
36
68
  }
37
69
  else {
70
+ if (shouldLogError(error)) {
71
+ (0, log_studio_error_1.logStudioError)(error);
72
+ }
38
73
  setState({
39
74
  type: 'no-record',
40
75
  });
41
76
  }
42
77
  })
43
78
  .catch((err) => {
79
+ if (shouldLogError(error)) {
80
+ (0, log_studio_error_1.logStudioError)(error);
81
+ }
44
82
  setState({
45
83
  err,
46
84
  type: 'error',
@@ -4,7 +4,7 @@ exports.ShortcutHint = exports.cmdOrCtrlCharacter = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const use_keybinding_1 = require("../../helpers/use-keybinding");
7
- exports.cmdOrCtrlCharacter = window.navigator.platform.startsWith('Mac')
7
+ exports.cmdOrCtrlCharacter = typeof window !== 'undefined' && window.navigator.platform.startsWith('Mac')
8
8
  ? '⌘'
9
9
  : 'Ctrl';
10
10
  const container = {
@@ -0,0 +1,3 @@
1
+ import type { LogStudioErrorRequest } from '@remotion/studio-shared';
2
+ export declare const logStudioErrorData: (data: LogStudioErrorRequest) => void;
3
+ export declare const logStudioError: (error: Error) => void;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logStudioError = exports.logStudioErrorData = void 0;
4
+ const call_api_1 = require("../../components/call-api");
5
+ const loggedErrors = new Set();
6
+ const maxLoggedErrors = 100;
7
+ const logStudioErrorData = (data) => {
8
+ const key = JSON.stringify([data.name, data.message, data.stack]);
9
+ if (loggedErrors.has(key)) {
10
+ return;
11
+ }
12
+ if (loggedErrors.size >= maxLoggedErrors) {
13
+ loggedErrors.clear();
14
+ }
15
+ loggedErrors.add(key);
16
+ (0, call_api_1.callApi)('/api/log-studio-error', data).catch(() => undefined);
17
+ };
18
+ exports.logStudioErrorData = logStudioErrorData;
19
+ const logStudioError = (error) => {
20
+ (0, exports.logStudioErrorData)({
21
+ name: typeof error.name === 'string' ? error.name : null,
22
+ message: typeof error.message === 'string' ? error.message : '',
23
+ stack: typeof error.stack === 'string' ? error.stack : null,
24
+ symbolicatedStackFrames: null,
25
+ });
26
+ };
27
+ exports.logStudioError = logStudioError;