@revideo/vite-plugin 0.4.7-alpha.1027 → 0.4.7-five.1022

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.
@@ -1,10 +1,12 @@
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 });
1
+ 'use strict';
2
+ var __importDefault =
3
+ (this && this.__importDefault) ||
4
+ function (mod) {
5
+ return mod && mod.__esModule ? mod : {default: mod};
6
+ };
7
+ Object.defineProperty(exports, '__esModule', {value: true});
6
8
  exports.corsProxyPlugin = void 0;
7
- const follow_redirects_1 = __importDefault(require("follow-redirects"));
9
+ const follow_redirects_1 = __importDefault(require('follow-redirects'));
8
10
  /**
9
11
  * This module provides the proxy located at
10
12
  * /cors-proxy/...
@@ -22,69 +24,78 @@ const follow_redirects_1 = __importDefault(require("follow-redirects"));
22
24
  * same host as the main app.
23
25
  */
24
26
  function corsProxyPlugin(config) {
25
- setupEnvVarsForProxy(config);
26
- return {
27
- name: 'revideo:cors-proxy',
28
- configureServer(server) {
29
- if (config !== false && config !== undefined) {
30
- motionCanvasCorsProxy(server.middlewares, config === true ? {} : config);
31
- }
32
- },
33
- };
27
+ setupEnvVarsForProxy(config);
28
+ return {
29
+ name: 'revideo:cors-proxy',
30
+ configureServer(server) {
31
+ if (config !== false && config !== undefined) {
32
+ motionCanvasCorsProxy(
33
+ server.middlewares,
34
+ config === true ? {} : config,
35
+ );
36
+ }
37
+ },
38
+ };
34
39
  }
35
40
  exports.corsProxyPlugin = corsProxyPlugin;
36
41
  function setupEnvVarsForProxy(config) {
37
- // Define Keys for Env Var
38
- const prefix = 'VITE_MC_PROXY_';
39
- const isEnabledKey = prefix + 'ENABLED';
40
- const allowList = prefix + 'ALLOW_LIST';
41
- if (config === true) {
42
- config = {}; // Use Default values
43
- }
44
- process.env[isEnabledKey] = String(!!config); // 'true' or 'false'
45
- if (config) {
46
- // These values are only configured if the Proxy is enabled
47
- // You cannot access them via import.meta.env if the Proxy
48
- // is set to false
49
- process.env[allowList] = JSON.stringify(config.allowListHosts ?? []);
50
- }
42
+ // Define Keys for Env Var
43
+ const prefix = 'VITE_MC_PROXY_';
44
+ const isEnabledKey = prefix + 'ENABLED';
45
+ const allowList = prefix + 'ALLOW_LIST';
46
+ if (config === true) {
47
+ config = {}; // Use Default values
48
+ }
49
+ process.env[isEnabledKey] = String(!!config); // 'true' or 'false'
50
+ if (config) {
51
+ // These values are only configured if the Proxy is enabled
52
+ // You cannot access them via import.meta.env if the Proxy
53
+ // is set to false
54
+ process.env[allowList] = JSON.stringify(config.allowListHosts ?? []);
55
+ }
51
56
  }
52
57
  function motionCanvasCorsProxy(middleware, config) {
53
- // Set the default config if no config was provided
54
- config.allowedMimeTypes ??= ['image/*', 'video/*'];
55
- config.allowListHosts ??= [];
56
- // Check the Mime Types to have a correct structure (left/right)
57
- // not having them in the correct format would crash the Middleware
58
- // further down below
59
- if ((config.allowedMimeTypes ?? []).some(e => e.split('/').length !== 2)) {
60
- throw new Error("Invalid config for Proxy:\nAll Entries must have the following format:\n 'left/right' where left may be '*'");
58
+ // Set the default config if no config was provided
59
+ config.allowedMimeTypes ??= ['image/*', 'video/*'];
60
+ config.allowListHosts ??= [];
61
+ // Check the Mime Types to have a correct structure (left/right)
62
+ // not having them in the correct format would crash the Middleware
63
+ // further down below
64
+ if ((config.allowedMimeTypes ?? []).some(e => e.split('/').length !== 2)) {
65
+ throw new Error(
66
+ "Invalid config for Proxy:\nAll Entries must have the following format:\n 'left/right' where left may be '*'",
67
+ );
68
+ }
69
+ middleware.use((req, res, next) => {
70
+ if (!req.url || !req.url.startsWith('/cors-proxy/')) {
71
+ // url does not start with /cors-proxy/, so this
72
+ // middleware does not care about it
73
+ return next();
61
74
  }
62
- middleware.use((req, res, next) => {
63
- if (!req.url || !req.url.startsWith('/cors-proxy/')) {
64
- // url does not start with /cors-proxy/, so this
65
- // middleware does not care about it
66
- return next();
67
- }
68
- // For now, only allow GET Requests
69
- if (req.method !== 'GET') {
70
- return writeError('Only GET Requests are allowed', res, 405);
71
- }
72
- let sourceUrl;
73
- try {
74
- sourceUrl = extractDestination(req.url);
75
- }
76
- catch (err) {
77
- return writeError(err, res);
78
- }
79
- if (!isReceivedUrlInAllowedHosts(sourceUrl.hostname, config.allowListHosts)) {
80
- return writeError(`Blocked by Proxy: ${sourceUrl.hostname} is not on Hosts Allowlist`, res);
81
- }
82
- // Get the resource, do some checks. Throws an Error
83
- // if the checks fail. The catch then writes an Error
84
- return tryGetResource(res, sourceUrl, config).catch(error => {
85
- writeError(error, res);
86
- });
75
+ // For now, only allow GET Requests
76
+ if (req.method !== 'GET') {
77
+ return writeError('Only GET Requests are allowed', res, 405);
78
+ }
79
+ let sourceUrl;
80
+ try {
81
+ sourceUrl = extractDestination(req.url);
82
+ } catch (err) {
83
+ return writeError(err, res);
84
+ }
85
+ if (
86
+ !isReceivedUrlInAllowedHosts(sourceUrl.hostname, config.allowListHosts)
87
+ ) {
88
+ return writeError(
89
+ `Blocked by Proxy: ${sourceUrl.hostname} is not on Hosts Allowlist`,
90
+ res,
91
+ );
92
+ }
93
+ // Get the resource, do some checks. Throws an Error
94
+ // if the checks fail. The catch then writes an Error
95
+ return tryGetResource(res, sourceUrl, config).catch(error => {
96
+ writeError(error, res);
87
97
  });
98
+ });
88
99
  }
89
100
  /**
90
101
  * Unwrap the destination from the URL.
@@ -98,32 +109,34 @@ function motionCanvasCorsProxy(middleware, config) {
98
109
  * @returns The URL that needs to be called.
99
110
  */
100
111
  function extractDestination(url) {
101
- const withoutPrefix = url.replace('/cors-proxy/', '');
102
- const asUrl = new URL(decodeURIComponent(withoutPrefix));
103
- if (asUrl.protocol !== 'http:' && asUrl.protocol !== 'https:') {
104
- throw new Error('Only supported protocols are http and https');
105
- }
106
- return asUrl;
112
+ const withoutPrefix = url.replace('/cors-proxy/', '');
113
+ const asUrl = new URL(decodeURIComponent(withoutPrefix));
114
+ if (asUrl.protocol !== 'http:' && asUrl.protocol !== 'https:') {
115
+ throw new Error('Only supported protocols are http and https');
116
+ }
117
+ return asUrl;
107
118
  }
108
119
  /**
109
120
  * A simple Error Helper that will write an Error and close the response.
110
121
  */
111
122
  function writeError(message, res, statusCode = 400) {
112
- res.writeHead(statusCode, message);
113
- res.end();
123
+ res.writeHead(statusCode, message);
124
+ res.end();
114
125
  }
115
126
  /**
116
127
  * Check if the Proxy is allowed to get the requested resource based on the
117
128
  * host.
118
129
  */
119
130
  function isReceivedUrlInAllowedHosts(hostname, allowListHosts) {
120
- if (!allowListHosts || allowListHosts.length === 0) {
121
- // if the allowListHosts is just the predefinedAllowlist, the user has not
122
- // set any additional hosts. In this case, allow any hostname
123
- return true;
124
- }
125
- // Check if the hostname is any of the values set in allowListHosts
126
- return allowListHosts.some(e => e.toLowerCase().trim() === hostname.toLowerCase().trim());
131
+ if (!allowListHosts || allowListHosts.length === 0) {
132
+ // if the allowListHosts is just the predefinedAllowlist, the user has not
133
+ // set any additional hosts. In this case, allow any hostname
134
+ return true;
135
+ }
136
+ // Check if the hostname is any of the values set in allowListHosts
137
+ return allowListHosts.some(
138
+ e => e.toLowerCase().trim() === hostname.toLowerCase().trim(),
139
+ );
127
140
  }
128
141
  /**
129
142
  * Check if the Proxy is allowed to get the requested resource based on the
@@ -133,87 +146,98 @@ function isReceivedUrlInAllowedHosts(hostname, allowListHosts) {
133
146
  * Also handles catch-All Declarations like `image/*`.
134
147
  */
135
148
  function isResultOfAllowedResourceType(foundMimeType, allowedMimeTypes) {
136
- if (!allowedMimeTypes || allowedMimeTypes.length === 0) {
137
- return true; // no filters set
138
- }
139
- if (foundMimeType.split('/').length !== 2) {
140
- return false; // invalid mime structure
141
- }
142
- const [leftSegment, rightSegment] = foundMimeType
143
- .split('/')
144
- .map(e => e.trim().toLowerCase());
145
- // Get all Segments where the left Part is identical between foundMimeType and
146
- // allowedMimeType.
147
- const leftSegmentMatches = allowedMimeTypes.filter(e => e.trim().toLowerCase().split('/')[0] === leftSegment);
148
- if (leftSegmentMatches.length === 0) {
149
- // No matches at all, not even catchall - resource is rejected.
150
- return false;
151
- }
152
- // This just gets the right part of the MIME Types from the
153
- // configured allowList, e.g. "image/png" -> png
154
- const rightSegmentOfLeftSegmentMatches = leftSegmentMatches.map(e => e.split('/')[1]);
155
- // if an exact match or a catchall is found, the resource is allowed to be
156
- // proxied.
157
- return rightSegmentOfLeftSegmentMatches.some(e => e === '*' || e === rightSegment);
149
+ if (!allowedMimeTypes || allowedMimeTypes.length === 0) {
150
+ return true; // no filters set
151
+ }
152
+ if (foundMimeType.split('/').length !== 2) {
153
+ return false; // invalid mime structure
154
+ }
155
+ const [leftSegment, rightSegment] = foundMimeType
156
+ .split('/')
157
+ .map(e => e.trim().toLowerCase());
158
+ // Get all Segments where the left Part is identical between foundMimeType and
159
+ // allowedMimeType.
160
+ const leftSegmentMatches = allowedMimeTypes.filter(
161
+ e => e.trim().toLowerCase().split('/')[0] === leftSegment,
162
+ );
163
+ if (leftSegmentMatches.length === 0) {
164
+ // No matches at all, not even catchall - resource is rejected.
165
+ return false;
166
+ }
167
+ // This just gets the right part of the MIME Types from the
168
+ // configured allowList, e.g. "image/png" -> png
169
+ const rightSegmentOfLeftSegmentMatches = leftSegmentMatches.map(
170
+ e => e.split('/')[1],
171
+ );
172
+ // if an exact match or a catchall is found, the resource is allowed to be
173
+ // proxied.
174
+ return rightSegmentOfLeftSegmentMatches.some(
175
+ e => e === '*' || e === rightSegment,
176
+ );
158
177
  }
159
178
  /**
160
179
  * Requests a remote resource with the help of axios
161
180
  * May throw a string in case of a bad mime-type or missing headers
162
181
  */
163
182
  async function tryGetResource(res, sourceUrl, config) {
164
- // Turn this callback into a Promise to avoid additional nesting
165
- const result = await new Promise((res, rej) => {
166
- try {
167
- // We check what protocol was used and decide if we use http or https
168
- const request = (sourceUrl.protocol.startsWith('https')
169
- ? follow_redirects_1.default.https
170
- : follow_redirects_1.default.http).get(sourceUrl, data => {
171
- res(data);
172
- });
173
- request.on('error', (err) => {
174
- if (err.code && err.code === 'ENOTFOUND') {
175
- // This is a bit hacky, but this basically returns as a
176
- // 404 instead of crashing the Node Server with ENOTFOUND
177
- res({ statusCode: 404 });
178
- }
179
- else {
180
- rej(err);
181
- }
182
- });
183
- }
184
- catch (err) {
185
- rej(err);
183
+ // Turn this callback into a Promise to avoid additional nesting
184
+ const result = await new Promise((res, rej) => {
185
+ try {
186
+ // We check what protocol was used and decide if we use http or https
187
+ const request = (
188
+ sourceUrl.protocol.startsWith('https')
189
+ ? follow_redirects_1.default.https
190
+ : follow_redirects_1.default.http
191
+ ).get(sourceUrl, data => {
192
+ res(data);
193
+ });
194
+ request.on('error', err => {
195
+ if (err.code && err.code === 'ENOTFOUND') {
196
+ // This is a bit hacky, but this basically returns as a
197
+ // 404 instead of crashing the Node Server with ENOTFOUND
198
+ res({statusCode: 404});
199
+ } else {
200
+ rej(err);
186
201
  }
187
- });
188
- if (!result.statusCode || result.statusCode >= 300) {
189
- throw 'Unexpected Status: ' + result.statusCode ?? 'NO_STATUS';
202
+ });
203
+ } catch (err) {
204
+ rej(err);
190
205
  }
191
- const contentType = result.headers['content-type'];
192
- const contentLength = result.headers['content-length'];
193
- if (!contentType) {
194
- throw 'Proxied Response does not contain a Content Type';
206
+ });
207
+ if (!result.statusCode || result.statusCode >= 300) {
208
+ throw 'Unexpected Status: ' + result.statusCode ?? 'NO_STATUS';
209
+ }
210
+ const contentType = result.headers['content-type'];
211
+ const contentLength = result.headers['content-length'];
212
+ if (!contentType) {
213
+ throw 'Proxied Response does not contain a Content Type';
214
+ }
215
+ if (!contentLength) {
216
+ throw 'Proxied Response does not contain a Content Length';
217
+ }
218
+ if (
219
+ !isResultOfAllowedResourceType(
220
+ contentType.toString(),
221
+ config.allowedMimeTypes ?? [],
222
+ )
223
+ ) {
224
+ throw 'Proxied response has blocked content-type: ' + contentType;
225
+ }
226
+ // Prepare Response
227
+ for (const key in result.headers) {
228
+ const header = result.headers[key];
229
+ if (header === undefined) {
230
+ console.warn('Proxy: Received Header is empty. Skipping…');
231
+ continue;
195
232
  }
196
- if (!contentLength) {
197
- throw 'Proxied Response does not contain a Content Length';
198
- }
199
- if (!isResultOfAllowedResourceType(contentType.toString(), config.allowedMimeTypes ?? [])) {
200
- throw 'Proxied response has blocked content-type: ' + contentType;
201
- }
202
- // Prepare Response
203
- for (const key in result.headers) {
204
- const header = result.headers[key];
205
- if (header === undefined) {
206
- console.warn('Proxy: Received Header is empty. Skipping…');
207
- continue;
208
- }
209
- res.setHeader(key, header);
210
- }
211
- res.addListener('error', () => {
212
- console.log('Proxy: Connection Reset');
213
- });
214
- res.setHeader('x-proxy-destination', sourceUrl.toString());
215
- // Don't store on the server, just immediately pass on the
216
- // received chunks
217
- result.pipe(res);
233
+ res.setHeader(key, header);
234
+ }
235
+ res.addListener('error', () => {
236
+ console.log('Proxy: Connection Reset');
237
+ });
238
+ res.setHeader('x-proxy-destination', sourceUrl.toString());
239
+ // Don't store on the server, just immediately pass on the
240
+ // received chunks
241
+ result.pipe(res);
218
242
  }
219
- //# sourceMappingURL=corsProxy.js.map
243
+ //# sourceMappingURL=corsProxy.js.map
@@ -1,8 +1,11 @@
1
- import { Plugin } from 'vite';
2
- import { Projects } from '../utils';
1
+ import {Plugin} from 'vite';
2
+ import {Projects} from '../utils';
3
3
  interface EditorPluginConfig {
4
- editor: string;
5
- projects: Projects;
4
+ editor: string;
5
+ projects: Projects;
6
6
  }
7
- export declare function editorPlugin({ editor, projects }: EditorPluginConfig): Plugin;
7
+ export declare function editorPlugin({
8
+ editor,
9
+ projects,
10
+ }: EditorPluginConfig): Plugin;
8
11
  export {};
@@ -1,72 +1,79 @@
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 });
1
+ 'use strict';
2
+ var __importDefault =
3
+ (this && this.__importDefault) ||
4
+ function (mod) {
5
+ return mod && mod.__esModule ? mod : {default: mod};
6
+ };
7
+ Object.defineProperty(exports, '__esModule', {value: true});
6
8
  exports.editorPlugin = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function editorPlugin({ editor, projects }) {
10
- const editorPath = path_1.default.dirname(require.resolve(editor));
11
- const editorFile = fs_1.default.readFileSync(path_1.default.resolve(editorPath, 'editor.html'));
12
- const htmlParts = editorFile
13
- .toString()
14
- .replace('{{style}}', `/@fs/${path_1.default.resolve(editorPath, 'style.css')}`)
15
- .split('{{source}}');
16
- const createHtml = (src) => htmlParts[0] + src + htmlParts[1];
17
- const resolvedEditorId = '\0virtual:editor';
18
- return {
19
- name: 'revideo:editor',
20
- async load(id) {
21
- const [, query] = id.split('?');
22
- if (id.startsWith(resolvedEditorId)) {
23
- if (projects.list.length === 1) {
24
- /* language=typescript */
25
- return `\
9
+ const fs_1 = __importDefault(require('fs'));
10
+ const path_1 = __importDefault(require('path'));
11
+ function editorPlugin({editor, projects}) {
12
+ const editorPath = path_1.default.dirname(require.resolve(editor));
13
+ const editorFile = fs_1.default.readFileSync(
14
+ path_1.default.resolve(editorPath, 'editor.html'),
15
+ );
16
+ const htmlParts = editorFile
17
+ .toString()
18
+ .replace(
19
+ '{{style}}',
20
+ `/@fs/${path_1.default.resolve(editorPath, 'style.css')}`,
21
+ )
22
+ .split('{{source}}');
23
+ const createHtml = src => htmlParts[0] + src + htmlParts[1];
24
+ const resolvedEditorId = '\0virtual:editor';
25
+ return {
26
+ name: 'revideo:editor',
27
+ async load(id) {
28
+ const [, query] = id.split('?');
29
+ if (id.startsWith(resolvedEditorId)) {
30
+ if (projects.list.length === 1) {
31
+ /* language=typescript */
32
+ return `\
26
33
  import {editor} from '${editor}';
27
34
  import project from '${projects.list[0].url}?project';
28
35
  editor(project);
29
36
  `;
30
- }
31
- if (query) {
32
- const params = new URLSearchParams(query);
33
- const name = params.get('project');
34
- if (name && projects.lookup.has(name)) {
35
- /* language=typescript */
36
- return `\
37
+ }
38
+ if (query) {
39
+ const params = new URLSearchParams(query);
40
+ const name = params.get('project');
41
+ if (name && projects.lookup.has(name)) {
42
+ /* language=typescript */
43
+ return `\
37
44
  import {editor} from '${editor}';
38
45
  import project from '${projects.lookup.get(name).url}?project';
39
46
  editor(project);
40
47
  `;
41
- }
42
- }
43
- /* language=typescript */
44
- return `\
48
+ }
49
+ }
50
+ /* language=typescript */
51
+ return `\
45
52
  import {index} from '${editor}';
46
53
  index(${JSON.stringify(projects.list)});
47
54
  `;
48
- }
49
- },
50
- configureServer(server) {
51
- server.middlewares.use((req, res, next) => {
52
- if (req.url) {
53
- const url = new URL(req.url, `http://${req.headers.host}`);
54
- if (url.pathname === '/') {
55
- res.setHeader('Content-Type', 'text/html');
56
- res.end(createHtml('/@id/__x00__virtual:editor'));
57
- return;
58
- }
59
- const name = url.pathname.slice(1);
60
- if (name && projects.lookup.has(name)) {
61
- res.setHeader('Content-Type', 'text/html');
62
- res.end(createHtml(`/@id/__x00__virtual:editor?project=${name}`));
63
- return;
64
- }
65
- }
66
- next();
67
- });
68
- },
69
- };
55
+ }
56
+ },
57
+ configureServer(server) {
58
+ server.middlewares.use((req, res, next) => {
59
+ if (req.url) {
60
+ const url = new URL(req.url, `http://${req.headers.host}`);
61
+ if (url.pathname === '/') {
62
+ res.setHeader('Content-Type', 'text/html');
63
+ res.end(createHtml('/@id/__x00__virtual:editor'));
64
+ return;
65
+ }
66
+ const name = url.pathname.slice(1);
67
+ if (name && projects.lookup.has(name)) {
68
+ res.setHeader('Content-Type', 'text/html');
69
+ res.end(createHtml(`/@id/__x00__virtual:editor?project=${name}`));
70
+ return;
71
+ }
72
+ }
73
+ next();
74
+ });
75
+ },
76
+ };
70
77
  }
71
78
  exports.editorPlugin = editorPlugin;
72
- //# sourceMappingURL=editor.js.map
79
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1,25 @@
1
+ import type { Plugin, WebSocketServer } from 'vite';
2
+ interface ExporterPluginConfig {
3
+ output: string;
4
+ }
5
+ export declare function ffmpegExporterPlugin({ output }: ExporterPluginConfig): Plugin;
6
+ /**
7
+ * A simple bridge between the FFmpegExporterServer and FFmpegExporterClient.
8
+ *
9
+ * @remarks
10
+ * This class lets the client exporter invoke methods on the server and receive
11
+ * responses using a simple Promise-based API.
12
+ */
13
+ export declare class FFmpegBridge {
14
+ private readonly ws;
15
+ private readonly config;
16
+ private process;
17
+ constructor(ws: WebSocketServer, config: ExporterPluginConfig);
18
+ private handleMessage;
19
+ private respondSuccess;
20
+ private respondError;
21
+ private videoFrameExtractors;
22
+ private handleVideoFrameMessage;
23
+ private handleRenderFinished;
24
+ }
25
+ export {};