@remotion/studio-server 4.0.501 → 4.0.502

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 (27) hide show
  1. package/dist/codemods/update-inline-caption-patches.d.ts +1 -11
  2. package/dist/codemods/update-inline-caption-patches.js +2 -183
  3. package/dist/codemods/update-sequence-props/update-sequence-props.d.ts +2 -35
  4. package/dist/codemods/update-sequence-props/update-sequence-props.js +7 -720
  5. package/dist/helpers/resolve-composition-component.js +18 -6
  6. package/dist/preview-server/element-install-state.d.ts +16 -0
  7. package/dist/preview-server/element-install-state.js +43 -1
  8. package/dist/preview-server/handler.js +1 -1
  9. package/dist/preview-server/parse-body.d.ts +6 -1
  10. package/dist/preview-server/parse-body.js +60 -9
  11. package/dist/preview-server/routes/can-update-default-props.d.ts +1 -1
  12. package/dist/preview-server/routes/can-update-default-props.js +5 -132
  13. package/dist/preview-server/routes/can-update-sequence-props.d.ts +3 -2
  14. package/dist/preview-server/routes/can-update-sequence-props.js +51 -9
  15. package/dist/preview-server/routes/insert-element.js +5 -5
  16. package/dist/preview-server/routes/insert-jsx-element.js +5 -5
  17. package/dist/preview-server/sequence-props-watchers.js +2 -1
  18. package/dist/preview-server/studio-protocol/handle-discovery.d.ts +11 -0
  19. package/dist/preview-server/studio-protocol/handle-discovery.js +99 -0
  20. package/dist/preview-server/studio-protocol/handle-install.d.ts +10 -0
  21. package/dist/preview-server/studio-protocol/handle-install.js +139 -0
  22. package/dist/preview-server/studio-protocol/origin-policy.d.ts +10 -0
  23. package/dist/preview-server/studio-protocol/origin-policy.js +40 -0
  24. package/dist/preview-server/studio-protocol/protocol-response.d.ts +7 -0
  25. package/dist/preview-server/studio-protocol/protocol-response.js +13 -0
  26. package/dist/routes.js +14 -154
  27. package/package.json +9 -8
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.handleStudioProtocolDiscovery = exports.ELEMENT_INSTALL_TARGET_RESPONSE_WAIT = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const studio_shared_1 = require("@remotion/studio-shared");
9
+ const version_1 = require("remotion/version");
10
+ const element_install_state_1 = require("../element-install-state");
11
+ const origin_policy_1 = require("./origin-policy");
12
+ const protocol_response_1 = require("./protocol-response");
13
+ const ELEMENT_INSTALL_FOCUS_MAX_AGE = 5 * 60 * 1000;
14
+ exports.ELEMENT_INSTALL_TARGET_RESPONSE_WAIT = 250;
15
+ const requestInstallTarget = ({ liveEventsServer, }) => {
16
+ const requestId = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
17
+ liveEventsServer.sendEventToClient({
18
+ type: 'request-element-install-target',
19
+ requestId,
20
+ });
21
+ return requestId;
22
+ };
23
+ const getLiveInstallableTarget = (requestId) => {
24
+ const target = (0, element_install_state_1.getElementInstallTarget)(requestId);
25
+ const now = Date.now();
26
+ if (target === null ||
27
+ now - target.updatedAt >= element_install_state_1.ELEMENT_INSTALL_TARGET_MAX_AGE ||
28
+ target.lastFocusedAt === null ||
29
+ now - target.lastFocusedAt >= ELEMENT_INSTALL_FOCUS_MAX_AGE ||
30
+ !target.canInstall ||
31
+ target.readOnly ||
32
+ target.compositionFile === null ||
33
+ target.compositionId === null) {
34
+ return null;
35
+ }
36
+ return target;
37
+ };
38
+ const getProject = ({ gitSource, remotionRoot, }) => (0, studio_shared_1.getProjectName)({
39
+ basename: node_path_1.default.basename,
40
+ gitSource,
41
+ resolvedRemotionRoot: remotionRoot,
42
+ });
43
+ const handleStudioProtocolDiscovery = ({ gitSource, liveEventsServer, remotionRoot, request, response, }) => {
44
+ (0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
45
+ if (!(0, origin_policy_1.isAllowedStudioProtocolOrigin)(request.headers.origin)) {
46
+ (0, protocol_response_1.writeStudioProtocolError)({
47
+ code: 'unsupported-origin',
48
+ message: 'Origin not allowed',
49
+ response,
50
+ status: 403,
51
+ });
52
+ return Promise.resolve();
53
+ }
54
+ if (request.method !== 'GET') {
55
+ (0, protocol_response_1.writeStudioProtocolError)({
56
+ code: 'method-not-allowed',
57
+ message: 'Use GET for Studio Protocol discovery.',
58
+ response,
59
+ status: 405,
60
+ });
61
+ return Promise.resolve();
62
+ }
63
+ const requestId = requestInstallTarget({ liveEventsServer });
64
+ return new Promise((resolve) => {
65
+ setTimeout(() => {
66
+ const now = Date.now();
67
+ const target = getLiveInstallableTarget(requestId);
68
+ const issued = target === null ? null : (0, element_install_state_1.issueStudioProtocolTarget)({ now, target });
69
+ response.writeHead(200, {
70
+ 'Cache-Control': 'no-store',
71
+ 'Content-Type': 'application/json',
72
+ });
73
+ response.end(JSON.stringify({
74
+ protocol: 'remotion-studio-protocol',
75
+ protocolVersion: 1,
76
+ studioVersion: version_1.VERSION,
77
+ capabilities: {
78
+ install: [
79
+ {
80
+ payloadType: 'remotion-element',
81
+ payloadVersions: [1],
82
+ },
83
+ ],
84
+ },
85
+ projectName: getProject({ gitSource, remotionRoot }),
86
+ installTarget: issued === null || target === null
87
+ ? null
88
+ : {
89
+ id: issued.id,
90
+ expiresAt: issued.expiresAt,
91
+ compositionId: target.compositionId,
92
+ lastFocusedAt: target.lastFocusedAt,
93
+ },
94
+ }));
95
+ resolve();
96
+ }, exports.ELEMENT_INSTALL_TARGET_RESPONSE_WAIT);
97
+ });
98
+ };
99
+ exports.handleStudioProtocolDiscovery = handleStudioProtocolDiscovery;
@@ -0,0 +1,10 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { LiveEventsServer } from '../live-events';
3
+ type FocusStudioTab = (studioUrl: string) => void;
4
+ export declare const handleStudioProtocolInstall: ({ focusStudioTab, liveEventsServer, request, response, }: {
5
+ readonly focusStudioTab: FocusStudioTab;
6
+ readonly liveEventsServer: LiveEventsServer;
7
+ readonly request: IncomingMessage;
8
+ readonly response: ServerResponse<IncomingMessage>;
9
+ }) => Promise<void>;
10
+ export {};
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleStudioProtocolInstall = void 0;
4
+ const studio_protocol_1 = require("@remotion/studio-protocol");
5
+ const zod_1 = require("zod");
6
+ const element_install_state_1 = require("../element-install-state");
7
+ const parse_body_1 = require("../parse-body");
8
+ const origin_policy_1 = require("./origin-policy");
9
+ const protocol_response_1 = require("./protocol-response");
10
+ const studioProtocolInstallRequestSchema = zod_1.z.object({
11
+ protocol: zod_1.z.literal('remotion-studio-protocol'),
12
+ protocolVersion: zod_1.z.literal(1),
13
+ targetId: zod_1.z.string(),
14
+ payload: zod_1.z.unknown(),
15
+ });
16
+ // A valid payload may contain 250,000 JSON characters. Allow room for its
17
+ // UTF-8 representation and the protocol envelope while keeping memory bounded.
18
+ const MAX_STUDIO_PROTOCOL_INSTALL_BODY_SIZE = 1000000;
19
+ const deliverElementInstall = ({ element, focusStudioTab, liveEventsServer, target, }) => {
20
+ if (target.compositionFile === null || target.compositionId === null) {
21
+ return false;
22
+ }
23
+ const installRequest = {
24
+ id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
25
+ clientId: target.clientId,
26
+ createdAt: Date.now(),
27
+ compositionFile: target.compositionFile,
28
+ compositionId: target.compositionId,
29
+ element,
30
+ position: null,
31
+ };
32
+ const delivered = liveEventsServer.sendEventToClientId(target.clientId, {
33
+ type: 'element-install-request',
34
+ request: installRequest,
35
+ });
36
+ if (delivered) {
37
+ focusStudioTab(target.studioUrl);
38
+ }
39
+ return delivered;
40
+ };
41
+ const handleStudioProtocolInstall = async ({ focusStudioTab, liveEventsServer, request, response, }) => {
42
+ (0, origin_policy_1.setStudioProtocolCorsHeaders)({ request, response });
43
+ if (!(0, origin_policy_1.isAllowedStudioProtocolOrigin)(request.headers.origin)) {
44
+ (0, protocol_response_1.writeStudioProtocolError)({
45
+ code: 'unsupported-origin',
46
+ message: 'Origin not allowed',
47
+ response,
48
+ status: 403,
49
+ });
50
+ return;
51
+ }
52
+ if (request.method !== 'POST') {
53
+ (0, protocol_response_1.writeStudioProtocolError)({
54
+ code: 'method-not-allowed',
55
+ message: 'Use POST to request an Element installation.',
56
+ response,
57
+ status: 405,
58
+ });
59
+ return;
60
+ }
61
+ let body;
62
+ try {
63
+ body = await (0, parse_body_1.parseRequestBody)(request, {
64
+ maxBytes: MAX_STUDIO_PROTOCOL_INSTALL_BODY_SIZE,
65
+ });
66
+ }
67
+ catch (error) {
68
+ if (error instanceof parse_body_1.RequestBodyTooLargeError) {
69
+ (0, protocol_response_1.writeStudioProtocolError)({
70
+ code: 'request-too-large',
71
+ message: 'The request body is too large.',
72
+ response,
73
+ status: 413,
74
+ });
75
+ return;
76
+ }
77
+ (0, protocol_response_1.writeStudioProtocolError)({
78
+ code: 'invalid-request',
79
+ message: 'The request body is not valid JSON.',
80
+ response,
81
+ status: 400,
82
+ });
83
+ return;
84
+ }
85
+ const parsedRequest = studioProtocolInstallRequestSchema.safeParse(body);
86
+ if (!parsedRequest.success) {
87
+ (0, protocol_response_1.writeStudioProtocolError)({
88
+ code: 'unsupported-protocol',
89
+ message: 'Invalid Remotion Studio Protocol request.',
90
+ response,
91
+ status: 400,
92
+ });
93
+ return;
94
+ }
95
+ const payload = studio_protocol_1.StudioProtocolInternals.parseStudioElementPayload(parsedRequest.data.payload);
96
+ if (payload === null) {
97
+ (0, protocol_response_1.writeStudioProtocolError)({
98
+ code: 'invalid-payload',
99
+ message: 'Invalid Element payload.',
100
+ response,
101
+ status: 400,
102
+ });
103
+ return;
104
+ }
105
+ const target = (0, element_install_state_1.consumeStudioProtocolTarget)({
106
+ now: Date.now(),
107
+ targetId: parsedRequest.data.targetId,
108
+ });
109
+ if (target === null) {
110
+ (0, protocol_response_1.writeStudioProtocolError)({
111
+ code: 'target-expired',
112
+ message: 'The selected Studio target is no longer available.',
113
+ response,
114
+ status: 409,
115
+ });
116
+ return;
117
+ }
118
+ if (!deliverElementInstall({
119
+ element: payload.element,
120
+ focusStudioTab,
121
+ liveEventsServer,
122
+ target,
123
+ })) {
124
+ (0, protocol_response_1.writeStudioProtocolError)({
125
+ code: 'target-expired',
126
+ message: 'The selected Remotion Studio tab is no longer connected.',
127
+ response,
128
+ status: 409,
129
+ });
130
+ return;
131
+ }
132
+ response.writeHead(200, { 'Content-Type': 'application/json' });
133
+ response.end(JSON.stringify({
134
+ protocol: 'remotion-studio-protocol',
135
+ protocolVersion: 1,
136
+ status: 'awaiting-confirmation',
137
+ }));
138
+ };
139
+ exports.handleStudioProtocolInstall = handleStudioProtocolInstall;
@@ -0,0 +1,10 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ export declare const isAllowedStudioProtocolOrigin: (origin: string | undefined) => boolean;
3
+ export declare const setStudioProtocolCorsHeaders: ({ request, response, }: {
4
+ readonly request: IncomingMessage;
5
+ readonly response: ServerResponse<IncomingMessage>;
6
+ }) => void;
7
+ export declare const handleStudioProtocolOptions: ({ request, response, }: {
8
+ readonly request: IncomingMessage;
9
+ readonly response: ServerResponse<IncomingMessage>;
10
+ }) => Promise<void>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleStudioProtocolOptions = exports.setStudioProtocolCorsHeaders = exports.isAllowedStudioProtocolOrigin = void 0;
4
+ const isAllowedStudioProtocolOrigin = (origin) => {
5
+ if (!origin) {
6
+ return false;
7
+ }
8
+ try {
9
+ const url = new URL(origin);
10
+ return ((url.protocol === 'https:' &&
11
+ (url.hostname === 'remotion.dev' ||
12
+ url.hostname === 'www.remotion.dev')) ||
13
+ (url.protocol === 'http:' &&
14
+ (url.hostname === 'localhost' || url.hostname === '127.0.0.1')));
15
+ }
16
+ catch (_a) {
17
+ return false;
18
+ }
19
+ };
20
+ exports.isAllowedStudioProtocolOrigin = isAllowedStudioProtocolOrigin;
21
+ const setStudioProtocolCorsHeaders = ({ request, response, }) => {
22
+ const { origin } = request.headers;
23
+ if (typeof origin !== 'string' || !(0, exports.isAllowedStudioProtocolOrigin)(origin)) {
24
+ return;
25
+ }
26
+ response.setHeader('Access-Control-Allow-Origin', origin);
27
+ response.setHeader('Vary', 'Origin');
28
+ response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
29
+ response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
30
+ response.setHeader('Access-Control-Max-Age', '600');
31
+ response.setHeader('Access-Control-Allow-Private-Network', 'true');
32
+ };
33
+ exports.setStudioProtocolCorsHeaders = setStudioProtocolCorsHeaders;
34
+ const handleStudioProtocolOptions = ({ request, response, }) => {
35
+ (0, exports.setStudioProtocolCorsHeaders)({ request, response });
36
+ response.writeHead((0, exports.isAllowedStudioProtocolOrigin)(request.headers.origin) ? 204 : 403);
37
+ response.end();
38
+ return Promise.resolve();
39
+ };
40
+ exports.handleStudioProtocolOptions = handleStudioProtocolOptions;
@@ -0,0 +1,7 @@
1
+ import type { ServerResponse } from 'node:http';
2
+ export declare const writeStudioProtocolError: ({ code, message, response, status, }: {
3
+ readonly code: string;
4
+ readonly message: string;
5
+ readonly response: ServerResponse<import("http").IncomingMessage>;
6
+ readonly status: number;
7
+ }) => void;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeStudioProtocolError = void 0;
4
+ const writeStudioProtocolError = ({ code, message, response, status, }) => {
5
+ response.writeHead(status, { 'Content-Type': 'application/json' });
6
+ response.end(JSON.stringify({
7
+ protocol: 'remotion-studio-protocol',
8
+ protocolVersion: 1,
9
+ status: 'error',
10
+ error: { code, message },
11
+ }));
12
+ };
13
+ exports.writeStudioProtocolError = writeStudioProtocolError;
package/dist/routes.js CHANGED
@@ -39,7 +39,6 @@ const node_fs_1 = require("node:fs");
39
39
  const node_path_1 = __importStar(require("node:path"));
40
40
  const node_url_1 = require("node:url");
41
41
  const bundler_1 = require("@remotion/bundler");
42
- const drag_and_drop_1 = require("@remotion/drag-and-drop");
43
42
  const renderer_1 = require("@remotion/renderer");
44
43
  const studio_shared_1 = require("@remotion/studio-shared");
45
44
  const better_opn_1 = require("./better-opn");
@@ -48,19 +47,18 @@ const get_file_source_1 = require("./helpers/get-file-source");
48
47
  const get_installed_installable_packages_1 = require("./helpers/get-installed-installable-packages");
49
48
  const resolve_output_path_1 = require("./helpers/resolve-output-path");
50
49
  const api_routes_1 = require("./preview-server/api-routes");
51
- const element_install_state_1 = require("./preview-server/element-install-state");
52
50
  const get_package_manager_1 = require("./preview-server/get-package-manager");
53
51
  const get_static_file_fallback_hint_1 = require("./preview-server/get-static-file-fallback-hint");
54
52
  const handler_1 = require("./preview-server/handler");
55
- const parse_body_1 = require("./preview-server/parse-body");
56
53
  const public_folder_1 = require("./preview-server/public-folder");
57
54
  const open_in_editor_1 = require("./preview-server/routes/open-in-editor");
58
55
  const serve_static_1 = require("./preview-server/serve-static");
56
+ const handle_discovery_1 = require("./preview-server/studio-protocol/handle-discovery");
57
+ const handle_install_1 = require("./preview-server/studio-protocol/handle-install");
58
+ const origin_policy_1 = require("./preview-server/studio-protocol/origin-policy");
59
59
  const validate_same_origin_1 = require("./preview-server/validate-same-origin");
60
60
  const watch_ignore_next_change_1 = require("./preview-server/watch-ignore-next-change");
61
61
  const loggedStaticFileHints = new Set();
62
- const ELEMENT_INSTALL_FOCUS_MAX_AGE = 5 * 60 * 1000;
63
- const ELEMENT_INSTALL_TARGET_RESPONSE_WAIT = 250;
64
62
  const static404 = (response) => {
65
63
  response.writeHead(404);
66
64
  response.end('The static/ prefix has been changed, this URL is no longer valid.');
@@ -84,147 +82,6 @@ const handleRemotionConfig = (response, remotionRoot) => {
84
82
  response.end(JSON.stringify(body));
85
83
  return Promise.resolve();
86
84
  };
87
- const isAllowedElementInstallOrigin = (origin) => {
88
- if (!origin) {
89
- return false;
90
- }
91
- try {
92
- const url = new URL(origin);
93
- return ((url.protocol === 'https:' &&
94
- (url.hostname === 'remotion.dev' ||
95
- url.hostname === 'www.remotion.dev')) ||
96
- (url.protocol === 'http:' &&
97
- (url.hostname === 'localhost' || url.hostname === '127.0.0.1')));
98
- }
99
- catch (_a) {
100
- return false;
101
- }
102
- };
103
- const setElementInstallCorsHeaders = ({ request, response, }) => {
104
- const { origin } = request.headers;
105
- if (isAllowedElementInstallOrigin(origin)) {
106
- response.setHeader('Access-Control-Allow-Origin', origin);
107
- response.setHeader('Vary', 'Origin');
108
- response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
109
- response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
110
- response.setHeader('Access-Control-Max-Age', '600');
111
- response.setHeader('Access-Control-Allow-Private-Network', 'true');
112
- }
113
- };
114
- const handleElementInstallOptions = ({ request, response, }) => {
115
- setElementInstallCorsHeaders({ request, response });
116
- response.writeHead(isAllowedElementInstallOrigin(request.headers.origin) ? 204 : 403);
117
- response.end();
118
- return Promise.resolve();
119
- };
120
- const handleElementInstallTarget = ({ liveEventsServer, request, response, remotionRoot, gitSource, }) => {
121
- if (!isAllowedElementInstallOrigin(request.headers.origin)) {
122
- response.writeHead(403);
123
- response.end(JSON.stringify({ success: false, reason: 'Origin not allowed' }));
124
- return Promise.resolve();
125
- }
126
- const requestId = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
127
- liveEventsServer.sendEventToClient({
128
- type: 'request-element-install-target',
129
- requestId,
130
- });
131
- return new Promise((resolve) => {
132
- setTimeout(() => {
133
- var _a, _b, _c, _d, _e;
134
- const target = (0, element_install_state_1.getElementInstallTarget)(requestId);
135
- const now = Date.now();
136
- const targetIsLive = target !== null &&
137
- now - target.updatedAt < element_install_state_1.ELEMENT_INSTALL_TARGET_MAX_AGE;
138
- const host = (_a = request.headers.host) !== null && _a !== void 0 ? _a : null;
139
- const port = (_b = host === null || host === void 0 ? void 0 : host.split(':').at(-1)) !== null && _b !== void 0 ? _b : null;
140
- setElementInstallCorsHeaders({ request, response });
141
- response.writeHead(200, { 'Content-Type': 'application/json' });
142
- response.end(JSON.stringify({
143
- type: 'remotion-studio',
144
- projectName: (0, studio_shared_1.getProjectName)({
145
- basename: node_path_1.default.basename,
146
- gitSource,
147
- resolvedRemotionRoot: remotionRoot,
148
- }),
149
- port: port === null ? null : Number(port),
150
- lastFocusedAt: (_c = target === null || target === void 0 ? void 0 : target.lastFocusedAt) !== null && _c !== void 0 ? _c : null,
151
- canInstall: target !== null && target.canInstall && targetIsLive,
152
- activeCompositionId: (_d = target === null || target === void 0 ? void 0 : target.compositionId) !== null && _d !== void 0 ? _d : null,
153
- readOnly: (_e = target === null || target === void 0 ? void 0 : target.readOnly) !== null && _e !== void 0 ? _e : false,
154
- }));
155
- resolve();
156
- }, ELEMENT_INSTALL_TARGET_RESPONSE_WAIT);
157
- });
158
- };
159
- const handleRequestElementInstall = async ({ liveEventsServer, request, response, }) => {
160
- if (!isAllowedElementInstallOrigin(request.headers.origin)) {
161
- response.writeHead(403);
162
- response.end(JSON.stringify({ success: false, reason: 'Origin not allowed' }));
163
- return;
164
- }
165
- setElementInstallCorsHeaders({ request, response });
166
- response.setHeader('Content-Type', 'application/json');
167
- try {
168
- const body = await (0, parse_body_1.parseRequestBody)(request);
169
- const { mimeType, payload } = body;
170
- const parsed = typeof mimeType === 'string' && typeof payload === 'string'
171
- ? drag_and_drop_1.DragAndDropInternals.parseDragData({ mimeType, payload })
172
- : null;
173
- if ((parsed === null || parsed === void 0 ? void 0 : parsed.type) !== 'element') {
174
- response.writeHead(400);
175
- response.end(JSON.stringify({ success: false, reason: 'Invalid Element payload' }));
176
- return;
177
- }
178
- const target = (0, element_install_state_1.getElementInstallTarget)(null);
179
- const now = Date.now();
180
- const targetIsLive = target !== null &&
181
- now - target.updatedAt < element_install_state_1.ELEMENT_INSTALL_TARGET_MAX_AGE;
182
- const targetWasRecentlyFocused = target !== null &&
183
- target.lastFocusedAt !== null &&
184
- now - target.lastFocusedAt < ELEMENT_INSTALL_FOCUS_MAX_AGE;
185
- if (target === null ||
186
- !target.canInstall ||
187
- target.compositionFile === null ||
188
- target.compositionId === null ||
189
- !targetIsLive ||
190
- !targetWasRecentlyFocused) {
191
- response.writeHead(409);
192
- response.end(JSON.stringify({
193
- success: false,
194
- reason: 'No focused writable Remotion Studio composition',
195
- }));
196
- return;
197
- }
198
- const installRequest = {
199
- id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
200
- clientId: target.clientId,
201
- createdAt: Date.now(),
202
- compositionFile: target.compositionFile,
203
- compositionId: target.compositionId,
204
- element: parsed.data.element,
205
- position: null,
206
- };
207
- const delivered = liveEventsServer.sendEventToClientId(target.clientId, {
208
- type: 'element-install-request',
209
- request: installRequest,
210
- });
211
- if (delivered === false) {
212
- response.writeHead(409);
213
- response.end(JSON.stringify({
214
- success: false,
215
- reason: 'The selected Remotion Studio tab is no longer connected',
216
- }));
217
- return;
218
- }
219
- (0, better_opn_1.focusBrowserTab)({ url: target.studioUrl }).catch(() => undefined);
220
- response.writeHead(200);
221
- response.end(JSON.stringify({ success: true, status: 'sent' }));
222
- }
223
- catch (err) {
224
- response.writeHead(500);
225
- response.end(JSON.stringify({ success: false, reason: err.message }));
226
- }
227
- };
228
85
  const handleFallback = async ({ remotionRoot, hash, response, request, getCurrentInputProps, getEnvVariables, publicDir, getRenderQueue, getRenderDefaults, getNumberOfAudioTags, getAudioLatencyHint, getPreviewSampleRate, gitSource, logLevel, enableCrossSiteIsolation, getStudioRuntimeConfig, }) => {
229
86
  var _a, _b;
230
87
  const acceptsHtml = ((_a = request.headers.accept) !== null && _a !== void 0 ? _a : '').includes('text/html');
@@ -421,21 +278,24 @@ const handleRoutes = ({ staticHash, staticHashPrefix, outputHash, outputHashPref
421
278
  remotionRoot,
422
279
  });
423
280
  }
424
- if (url.pathname === '/api/element-install-target' ||
425
- url.pathname === '/api/request-element-install') {
281
+ if (url.pathname === '/api/studio-protocol' ||
282
+ url.pathname === '/api/studio-protocol/install') {
426
283
  if (request.method === 'OPTIONS') {
427
- return handleElementInstallOptions({ request, response });
284
+ return (0, origin_policy_1.handleStudioProtocolOptions)({ request, response });
428
285
  }
429
- if (url.pathname === '/api/element-install-target') {
430
- return handleElementInstallTarget({
286
+ if (url.pathname === '/api/studio-protocol') {
287
+ return (0, handle_discovery_1.handleStudioProtocolDiscovery)({
288
+ gitSource,
431
289
  liveEventsServer,
290
+ remotionRoot,
432
291
  request,
433
292
  response,
434
- remotionRoot,
435
- gitSource,
436
293
  });
437
294
  }
438
- return handleRequestElementInstall({
295
+ return (0, handle_install_1.handleStudioProtocolInstall)({
296
+ focusStudioTab: (studioUrl) => {
297
+ (0, better_opn_1.focusBrowserTab)({ url: studioUrl }).catch(() => undefined);
298
+ },
439
299
  liveEventsServer,
440
300
  request,
441
301
  response,
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.501",
6
+ "version": "4.0.502",
7
7
  "description": "Run a Remotion Studio with a server backend",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -23,20 +23,21 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@remotion/drag-and-drop": "4.0.501",
26
+ "@remotion/studio-protocol": "4.0.502",
27
27
  "@babel/types": "7.24.0",
28
28
  "@babel/parser": "7.24.1",
29
29
  "@svgr/core": "8.1.0",
30
30
  "@svgr/plugin-jsx": "8.1.0",
31
31
  "kiwi-schema": "0.5.0",
32
32
  "semver": "7.5.3",
33
+ "zod": "4.4.3",
33
34
  "prettier": "3.8.1",
34
- "remotion": "4.0.501",
35
+ "remotion": "4.0.502",
35
36
  "recast": "0.23.11",
36
- "@remotion/bundler": "4.0.501",
37
- "@remotion/renderer": "4.0.501",
38
- "@remotion/studio-codemods": "4.0.501",
39
- "@remotion/studio-shared": "4.0.501",
37
+ "@remotion/bundler": "4.0.502",
38
+ "@remotion/renderer": "4.0.502",
39
+ "@remotion/studio-codemods": "4.0.502",
40
+ "@remotion/studio-shared": "4.0.502",
40
41
  "memfs": "3.4.3",
41
42
  "open": "8.4.2"
42
43
  },
@@ -44,7 +45,7 @@
44
45
  "ast-types": "0.16.1",
45
46
  "react": "19.2.3",
46
47
  "@types/semver": "7.5.3",
47
- "@remotion/eslint-config-internal": "4.0.501",
48
+ "@remotion/eslint-config-internal": "4.0.502",
48
49
  "eslint": "9.19.0",
49
50
  "@types/node": "20.12.14",
50
51
  "@typescript/native-preview": "7.0.0-dev.20260217.1"