@editframe/vite-plugin 0.6.0-beta.9 → 0.7.0-beta.4
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.
- package/dist/packages/vite-plugin/forbidRelativePaths.cjs +8 -0
- package/dist/packages/vite-plugin/forbidRelativePaths.js +8 -0
- package/dist/packages/vite-plugin/index.cjs +65 -0
- package/dist/packages/vite-plugin/index.js +65 -0
- package/dist/packages/vite-plugin/packages/vite-plugin/src/forbidRelativePaths.d.ts +3 -0
- package/dist/packages/vite-plugin/packages/vite-plugin/src/index.d.ts +9 -0
- package/dist/packages/vite-plugin/packages/vite-plugin/src/sendTaskResult.d.ts +5 -0
- package/dist/packages/vite-plugin/sendTaskResult.cjs +56 -0
- package/dist/packages/vite-plugin/sendTaskResult.js +56 -0
- package/package.json +11 -6
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const forbidRelativePaths = (req) => {
|
|
4
|
+
if (req.url?.includes("..")) {
|
|
5
|
+
throw new Error("Relative paths are forbidden");
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
exports.forbidRelativePaths = forbidRelativePaths;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
const debug = require("debug");
|
|
5
|
+
const assets = require("@editframe/assets");
|
|
6
|
+
const forbidRelativePaths = require("./forbidRelativePaths.cjs");
|
|
7
|
+
const sendTaskResult = require("./sendTaskResult.cjs");
|
|
8
|
+
const vitePluginEditframe = (options) => {
|
|
9
|
+
return {
|
|
10
|
+
name: "vite-plugin-editframe",
|
|
11
|
+
configureServer(server) {
|
|
12
|
+
server.middlewares.use(async (req, res, next) => {
|
|
13
|
+
const log = debug("ef:vite-plugin");
|
|
14
|
+
if (req.url?.startsWith("/@ef")) {
|
|
15
|
+
forbidRelativePaths.forbidRelativePaths(req);
|
|
16
|
+
} else {
|
|
17
|
+
return next();
|
|
18
|
+
}
|
|
19
|
+
log(`Handling ${req.url}`);
|
|
20
|
+
const requestPath = req.url.replace(/^\/@ef-[^\/]+\//, "");
|
|
21
|
+
const assetPath = requestPath.replace(/\?.*$/, "");
|
|
22
|
+
const absolutePath = path.join(options.root, assetPath).replace("dist/", "src/");
|
|
23
|
+
options.cacheRoot = options.cacheRoot.replace("dist/", "src/");
|
|
24
|
+
const efPrefix = req.url.split("/")[1];
|
|
25
|
+
switch (efPrefix) {
|
|
26
|
+
case "@ef-asset": {
|
|
27
|
+
if (req.method !== "HEAD") {
|
|
28
|
+
res.writeHead(405, { Allow: "HEAD" });
|
|
29
|
+
res.end();
|
|
30
|
+
}
|
|
31
|
+
assets.md5FilePath(absolutePath).then((md5) => {
|
|
32
|
+
res.writeHead(200, {
|
|
33
|
+
etag: md5
|
|
34
|
+
});
|
|
35
|
+
res.end();
|
|
36
|
+
}).catch(next);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case "@ef-track-fragment-index": {
|
|
40
|
+
log(`Serving track fragment index for ${absolutePath}`);
|
|
41
|
+
assets.generateTrackFragmentIndex(options.cacheRoot, absolutePath).then((taskResult) => sendTaskResult.sendTaskResult(req, res, taskResult)).catch(next);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "@ef-track": {
|
|
45
|
+
log(`Serving track for ${absolutePath}`);
|
|
46
|
+
assets.generateTrack(options.cacheRoot, absolutePath, req.url).then((taskResult) => sendTaskResult.sendTaskResult(req, res, taskResult)).catch(next);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case "@ef-captions":
|
|
50
|
+
log(`Serving captions for ${absolutePath}`);
|
|
51
|
+
assets.findOrCreateCaptions(options.cacheRoot, absolutePath).then((taskResult) => sendTaskResult.sendTaskResult(req, res, taskResult)).catch(next);
|
|
52
|
+
break;
|
|
53
|
+
case "@ef-image":
|
|
54
|
+
log(`Serving image file ${absolutePath}`);
|
|
55
|
+
assets.cacheImage(options.cacheRoot, absolutePath).then((taskResult) => sendTaskResult.sendTaskResult(req, res, taskResult)).catch(next);
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
log(`Unknown asset type ${efPrefix}`);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
exports.vitePluginEditframe = vitePluginEditframe;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import debug from "debug";
|
|
3
|
+
import { cacheImage, findOrCreateCaptions, generateTrack, generateTrackFragmentIndex, md5FilePath } from "@editframe/assets";
|
|
4
|
+
import { forbidRelativePaths } from "./forbidRelativePaths.js";
|
|
5
|
+
import { sendTaskResult } from "./sendTaskResult.js";
|
|
6
|
+
const vitePluginEditframe = (options) => {
|
|
7
|
+
return {
|
|
8
|
+
name: "vite-plugin-editframe",
|
|
9
|
+
configureServer(server) {
|
|
10
|
+
server.middlewares.use(async (req, res, next) => {
|
|
11
|
+
const log = debug("ef:vite-plugin");
|
|
12
|
+
if (req.url?.startsWith("/@ef")) {
|
|
13
|
+
forbidRelativePaths(req);
|
|
14
|
+
} else {
|
|
15
|
+
return next();
|
|
16
|
+
}
|
|
17
|
+
log(`Handling ${req.url}`);
|
|
18
|
+
const requestPath = req.url.replace(/^\/@ef-[^\/]+\//, "");
|
|
19
|
+
const assetPath = requestPath.replace(/\?.*$/, "");
|
|
20
|
+
const absolutePath = path.join(options.root, assetPath).replace("dist/", "src/");
|
|
21
|
+
options.cacheRoot = options.cacheRoot.replace("dist/", "src/");
|
|
22
|
+
const efPrefix = req.url.split("/")[1];
|
|
23
|
+
switch (efPrefix) {
|
|
24
|
+
case "@ef-asset": {
|
|
25
|
+
if (req.method !== "HEAD") {
|
|
26
|
+
res.writeHead(405, { Allow: "HEAD" });
|
|
27
|
+
res.end();
|
|
28
|
+
}
|
|
29
|
+
md5FilePath(absolutePath).then((md5) => {
|
|
30
|
+
res.writeHead(200, {
|
|
31
|
+
etag: md5
|
|
32
|
+
});
|
|
33
|
+
res.end();
|
|
34
|
+
}).catch(next);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case "@ef-track-fragment-index": {
|
|
38
|
+
log(`Serving track fragment index for ${absolutePath}`);
|
|
39
|
+
generateTrackFragmentIndex(options.cacheRoot, absolutePath).then((taskResult) => sendTaskResult(req, res, taskResult)).catch(next);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "@ef-track": {
|
|
43
|
+
log(`Serving track for ${absolutePath}`);
|
|
44
|
+
generateTrack(options.cacheRoot, absolutePath, req.url).then((taskResult) => sendTaskResult(req, res, taskResult)).catch(next);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case "@ef-captions":
|
|
48
|
+
log(`Serving captions for ${absolutePath}`);
|
|
49
|
+
findOrCreateCaptions(options.cacheRoot, absolutePath).then((taskResult) => sendTaskResult(req, res, taskResult)).catch(next);
|
|
50
|
+
break;
|
|
51
|
+
case "@ef-image":
|
|
52
|
+
log(`Serving image file ${absolutePath}`);
|
|
53
|
+
cacheImage(options.cacheRoot, absolutePath).then((taskResult) => sendTaskResult(req, res, taskResult)).catch(next);
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
log(`Unknown asset type ${efPrefix}`);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
export {
|
|
64
|
+
vitePluginEditframe
|
|
65
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface VitePluginEditframeOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
cacheRoot: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const vitePluginEditframe: (options: VitePluginEditframeOptions) => {
|
|
6
|
+
name: string;
|
|
7
|
+
configureServer(this: void, server: import('vite').ViteDevServer): void;
|
|
8
|
+
};
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ServerResponse } from 'node:http';
|
|
2
|
+
import { IncomingMessage } from 'connect';
|
|
3
|
+
import { TaskResult } from '../../assets/src';
|
|
4
|
+
|
|
5
|
+
export declare const sendTaskResult: (req: IncomingMessage, res: ServerResponse<IncomingMessage>, taskResult: TaskResult) => ServerResponse<IncomingMessage> | undefined;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const node_fs = require("node:fs");
|
|
4
|
+
const mime = require("mime");
|
|
5
|
+
const debug = require("debug");
|
|
6
|
+
const sendTaskResult = (req, res, taskResult) => {
|
|
7
|
+
const { cachePath, md5Sum } = taskResult;
|
|
8
|
+
const filePath = cachePath;
|
|
9
|
+
const headers = {
|
|
10
|
+
etag: md5Sum
|
|
11
|
+
};
|
|
12
|
+
const log = debug("ef:sendfile");
|
|
13
|
+
try {
|
|
14
|
+
log(`Sending file ${filePath}`);
|
|
15
|
+
const stats = node_fs.statSync(filePath);
|
|
16
|
+
if (req.headers.range) {
|
|
17
|
+
const [x, y] = req.headers.range.replace("bytes=", "").split("-");
|
|
18
|
+
let end = Number.parseInt(y ?? "0", 10) || stats.size - 1;
|
|
19
|
+
const start = Number.parseInt(x ?? "0", 10) || 0;
|
|
20
|
+
if (end >= stats.size) {
|
|
21
|
+
end = stats.size - 1;
|
|
22
|
+
}
|
|
23
|
+
if (start >= stats.size) {
|
|
24
|
+
log("Range start is greater than file size");
|
|
25
|
+
res.setHeader("Content-Range", `bytes */${stats.size}`);
|
|
26
|
+
res.statusCode = 416;
|
|
27
|
+
return res.end();
|
|
28
|
+
}
|
|
29
|
+
res.writeHead(206, {
|
|
30
|
+
...headers,
|
|
31
|
+
"Content-Type": mime.getType(filePath) || "text/plain",
|
|
32
|
+
"Cache-Control": "max-age=3600",
|
|
33
|
+
"Content-Range": `bytes ${start}-${end}/${stats.size}`,
|
|
34
|
+
"Content-Length": end - start + 1,
|
|
35
|
+
"Accept-Ranges": "bytes"
|
|
36
|
+
});
|
|
37
|
+
log(`Sending ${filePath} range ${start}-${end}/${stats.size}`);
|
|
38
|
+
const readStream = node_fs.createReadStream(filePath, { start, end });
|
|
39
|
+
readStream.pipe(res);
|
|
40
|
+
} else {
|
|
41
|
+
res.writeHead(200, {
|
|
42
|
+
...headers,
|
|
43
|
+
"Content-Type": mime.getType(filePath) || "text/plain",
|
|
44
|
+
"Cache-Control": "max-age=3600",
|
|
45
|
+
"Contetn-Length": stats.size
|
|
46
|
+
});
|
|
47
|
+
log(`Sending ${filePath}`);
|
|
48
|
+
const readStream = node_fs.createReadStream(filePath);
|
|
49
|
+
readStream.pipe(res);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
log("Error sending file", error);
|
|
53
|
+
console.error(error);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
exports.sendTaskResult = sendTaskResult;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { statSync, createReadStream } from "node:fs";
|
|
2
|
+
import mime from "mime";
|
|
3
|
+
import debug from "debug";
|
|
4
|
+
const sendTaskResult = (req, res, taskResult) => {
|
|
5
|
+
const { cachePath, md5Sum } = taskResult;
|
|
6
|
+
const filePath = cachePath;
|
|
7
|
+
const headers = {
|
|
8
|
+
etag: md5Sum
|
|
9
|
+
};
|
|
10
|
+
const log = debug("ef:sendfile");
|
|
11
|
+
try {
|
|
12
|
+
log(`Sending file ${filePath}`);
|
|
13
|
+
const stats = statSync(filePath);
|
|
14
|
+
if (req.headers.range) {
|
|
15
|
+
const [x, y] = req.headers.range.replace("bytes=", "").split("-");
|
|
16
|
+
let end = Number.parseInt(y ?? "0", 10) || stats.size - 1;
|
|
17
|
+
const start = Number.parseInt(x ?? "0", 10) || 0;
|
|
18
|
+
if (end >= stats.size) {
|
|
19
|
+
end = stats.size - 1;
|
|
20
|
+
}
|
|
21
|
+
if (start >= stats.size) {
|
|
22
|
+
log("Range start is greater than file size");
|
|
23
|
+
res.setHeader("Content-Range", `bytes */${stats.size}`);
|
|
24
|
+
res.statusCode = 416;
|
|
25
|
+
return res.end();
|
|
26
|
+
}
|
|
27
|
+
res.writeHead(206, {
|
|
28
|
+
...headers,
|
|
29
|
+
"Content-Type": mime.getType(filePath) || "text/plain",
|
|
30
|
+
"Cache-Control": "max-age=3600",
|
|
31
|
+
"Content-Range": `bytes ${start}-${end}/${stats.size}`,
|
|
32
|
+
"Content-Length": end - start + 1,
|
|
33
|
+
"Accept-Ranges": "bytes"
|
|
34
|
+
});
|
|
35
|
+
log(`Sending ${filePath} range ${start}-${end}/${stats.size}`);
|
|
36
|
+
const readStream = createReadStream(filePath, { start, end });
|
|
37
|
+
readStream.pipe(res);
|
|
38
|
+
} else {
|
|
39
|
+
res.writeHead(200, {
|
|
40
|
+
...headers,
|
|
41
|
+
"Content-Type": mime.getType(filePath) || "text/plain",
|
|
42
|
+
"Cache-Control": "max-age=3600",
|
|
43
|
+
"Contetn-Length": stats.size
|
|
44
|
+
});
|
|
45
|
+
log(`Sending ${filePath}`);
|
|
46
|
+
const readStream = createReadStream(filePath);
|
|
47
|
+
readStream.pipe(res);
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
log("Error sending file", error);
|
|
51
|
+
console.error(error);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
sendTaskResult
|
|
56
|
+
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/vite-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-beta.4",
|
|
4
4
|
"description": "Editframe vite plugin",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
-
"import":
|
|
8
|
-
|
|
7
|
+
"import": {
|
|
8
|
+
"default": "./dist/packages/vite-plugin/index.js",
|
|
9
|
+
"types": "./dist/packages/vite-plugin/index.d.ts"
|
|
10
|
+
},
|
|
11
|
+
"require": {
|
|
12
|
+
"default": "./dist/packages/vite-plugin/index.cjs",
|
|
13
|
+
"types": "./dist/packages/vite-plugin/index.d.ts"
|
|
14
|
+
}
|
|
9
15
|
}
|
|
10
16
|
},
|
|
11
|
-
"types": "./dist/packages/vite-plugin/index.d.ts",
|
|
12
17
|
"scripts": {
|
|
13
18
|
"typecheck": "tsc --noEmit --emitDeclarationOnly false",
|
|
14
19
|
"build": "vite build",
|
|
@@ -18,8 +23,8 @@
|
|
|
18
23
|
"author": "",
|
|
19
24
|
"license": "UNLICENSED",
|
|
20
25
|
"dependencies": {
|
|
21
|
-
"@editframe/assets": "0.
|
|
22
|
-
"debug": "^4.3.
|
|
26
|
+
"@editframe/assets": "0.7.0-beta.4",
|
|
27
|
+
"debug": "^4.3.5",
|
|
23
28
|
"mime": "^4.0.3",
|
|
24
29
|
"node-html-parser": "^6.1.13",
|
|
25
30
|
"vite": "^5.2.11"
|