@blocklet/uploader-server 0.1.90 → 0.1.91
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.
|
@@ -6,6 +6,5 @@ type initStaticResourceMiddlewareOptions = {
|
|
|
6
6
|
skipRunningCheck?: boolean;
|
|
7
7
|
};
|
|
8
8
|
export declare const initStaticResourceMiddleware: ({ options, resourceTypes: _resourceTypes, express, skipRunningCheck: _skipRunningCheck, }?: initStaticResourceMiddlewareOptions) => (req: any, res: any, next: Function) => void;
|
|
9
|
-
export declare const getCanUseResources: () => any;
|
|
10
9
|
export declare const initProxyToMediaKitUploadsMiddleware: ({ options, express }?: any) => (req: any, res: any, next: Function) => Promise<any>;
|
|
11
10
|
export {};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { existsSync } from "fs";
|
|
1
|
+
import { existsSync, readdirSync, statSync, createReadStream } from "fs";
|
|
2
2
|
import { join, basename } from "path";
|
|
3
3
|
import config from "@blocklet/sdk/lib/config";
|
|
4
4
|
import { getResources } from "@blocklet/sdk/lib/component";
|
|
5
5
|
import joinUrl from "url-join";
|
|
6
6
|
import component from "@blocklet/sdk/lib/component";
|
|
7
|
+
import mime from "mime-types";
|
|
7
8
|
import { setPDFDownloadHeader, logger } from "../utils.js";
|
|
8
9
|
import { ImageBinDid } from "../constants.js";
|
|
10
|
+
import ms from "ms";
|
|
9
11
|
const ImgResourceType = "imgpack";
|
|
10
12
|
let skipRunningCheck = false;
|
|
11
13
|
let resourceTypes = [
|
|
@@ -16,13 +18,14 @@ let resourceTypes = [
|
|
|
16
18
|
// can be string or string[]
|
|
17
19
|
}
|
|
18
20
|
];
|
|
19
|
-
let
|
|
21
|
+
let resourcesMap = /* @__PURE__ */ new Map();
|
|
20
22
|
export const mappingResource = async () => {
|
|
21
23
|
try {
|
|
22
24
|
const resources = getResources({
|
|
23
25
|
types: resourceTypes,
|
|
24
26
|
skipRunningCheck
|
|
25
27
|
});
|
|
28
|
+
let canUseResources = [];
|
|
26
29
|
canUseResources = resources.map((resource) => {
|
|
27
30
|
const originDir = resource.path;
|
|
28
31
|
const resourceType = resourceTypes.find(({ type }) => originDir.endsWith(type));
|
|
@@ -38,11 +41,46 @@ export const mappingResource = async () => {
|
|
|
38
41
|
blacklist: resourceType.blacklist
|
|
39
42
|
}));
|
|
40
43
|
}).filter(Boolean).flat();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
resourcesMap.clear();
|
|
45
|
+
for (const resource of canUseResources) {
|
|
46
|
+
const { dir, whitelist, blacklist, originDir, blockletInfo } = resource;
|
|
47
|
+
if (existsSync(dir)) {
|
|
48
|
+
try {
|
|
49
|
+
const files = readdirSync(dir);
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
const filePath = join(dir, file);
|
|
52
|
+
let stat;
|
|
53
|
+
try {
|
|
54
|
+
stat = statSync(filePath);
|
|
55
|
+
if (stat.isDirectory()) continue;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (whitelist?.length && !whitelist.some((ext) => file.endsWith(ext))) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (blacklist?.length && blacklist.some((ext) => file.endsWith(ext))) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const contentType = mime.lookup(filePath) || "application/octet-stream";
|
|
66
|
+
resourcesMap.set(file, {
|
|
67
|
+
filePath,
|
|
68
|
+
dir,
|
|
69
|
+
originDir,
|
|
70
|
+
blockletInfo,
|
|
71
|
+
whitelist,
|
|
72
|
+
blacklist,
|
|
73
|
+
mtime: stat.mtime,
|
|
74
|
+
size: stat.size,
|
|
75
|
+
contentType
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
logger.error(`Error scanning directory ${dir}:`, err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
logger.info("Mapping resources: files count:", resourcesMap.size, "directories count:", canUseResources.length);
|
|
46
84
|
return canUseResources;
|
|
47
85
|
} catch (error) {
|
|
48
86
|
logger.error(error);
|
|
@@ -56,12 +94,26 @@ events.on(Events.componentStarted, () => mappingResource());
|
|
|
56
94
|
events.on(Events.componentStopped, () => mappingResource());
|
|
57
95
|
events.on(Events.componentUpdated, () => mappingResource());
|
|
58
96
|
export const initStaticResourceMiddleware = ({
|
|
59
|
-
options,
|
|
97
|
+
options = {},
|
|
60
98
|
resourceTypes: _resourceTypes = resourceTypes,
|
|
61
99
|
express,
|
|
62
100
|
skipRunningCheck: _skipRunningCheck
|
|
63
101
|
} = {}) => {
|
|
64
102
|
skipRunningCheck = !!_skipRunningCheck;
|
|
103
|
+
let maxAgeInSeconds = 31536e3;
|
|
104
|
+
const maxAge = options.maxAge || "365d";
|
|
105
|
+
if (typeof maxAge === "string") {
|
|
106
|
+
try {
|
|
107
|
+
const milliseconds = ms(maxAge);
|
|
108
|
+
maxAgeInSeconds = typeof milliseconds === "number" ? milliseconds / 1e3 : 31536e3;
|
|
109
|
+
} catch (e) {
|
|
110
|
+
logger.warn(`Invalid maxAge format: ${maxAge}, using default 1 year (31536000 seconds)`);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
maxAgeInSeconds = maxAge;
|
|
114
|
+
}
|
|
115
|
+
const cacheControl = `public, max-age=${maxAgeInSeconds}`;
|
|
116
|
+
const cacheControlImmutable = `${cacheControl}, immutable`;
|
|
65
117
|
if (_resourceTypes?.length > 0) {
|
|
66
118
|
resourceTypes = _resourceTypes.map((item) => {
|
|
67
119
|
if (typeof item === "string") {
|
|
@@ -80,39 +132,40 @@ export const initStaticResourceMiddleware = ({
|
|
|
80
132
|
return (req, res, next) => {
|
|
81
133
|
const fileName = basename(req.path || req.url?.split("?")[0]);
|
|
82
134
|
try {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (whitelist?.length && !whitelist.some((ext) => fileName?.endsWith(ext))) {
|
|
93
|
-
return false;
|
|
135
|
+
const resource = resourcesMap.get(fileName);
|
|
136
|
+
if (resource) {
|
|
137
|
+
res.setHeader("Content-Type", resource.contentType);
|
|
138
|
+
res.setHeader("Content-Length", resource.size);
|
|
139
|
+
res.setHeader("Last-Modified", resource.mtime.toUTCString());
|
|
140
|
+
res.setHeader("Cache-Control", options.immutable === false ? cacheControl : cacheControlImmutable);
|
|
141
|
+
if (options.setHeaders && typeof options.setHeaders === "function") {
|
|
142
|
+
const statObj = { mtime: resource.mtime, size: resource.size };
|
|
143
|
+
options.setHeaders(res, resource.filePath, statObj);
|
|
94
144
|
}
|
|
95
|
-
|
|
96
|
-
|
|
145
|
+
const ifModifiedSince = req.headers["if-modified-since"];
|
|
146
|
+
if (ifModifiedSince) {
|
|
147
|
+
const ifModifiedSinceDate = new Date(ifModifiedSince);
|
|
148
|
+
if (resource.mtime <= ifModifiedSinceDate) {
|
|
149
|
+
res.statusCode = 304;
|
|
150
|
+
res.end();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
97
153
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
index: false,
|
|
105
|
-
...options
|
|
106
|
-
})(req, res, next);
|
|
154
|
+
const fileStream = createReadStream(resource.filePath);
|
|
155
|
+
fileStream.on("error", (error) => {
|
|
156
|
+
logger.error(`Error streaming file ${resource.filePath}:`, error);
|
|
157
|
+
next(error);
|
|
158
|
+
});
|
|
159
|
+
fileStream.pipe(res);
|
|
107
160
|
} else {
|
|
108
161
|
next();
|
|
109
162
|
}
|
|
110
163
|
} catch (error) {
|
|
164
|
+
logger.error("Error serving static file:", error);
|
|
111
165
|
next();
|
|
112
166
|
}
|
|
113
167
|
};
|
|
114
168
|
};
|
|
115
|
-
export const getCanUseResources = () => canUseResources;
|
|
116
169
|
export const initProxyToMediaKitUploadsMiddleware = ({ options, express } = {}) => {
|
|
117
170
|
return async (req, res, next) => {
|
|
118
171
|
if (!component.getComponentWebEndpoint(ImageBinDid)) {
|
|
@@ -6,6 +6,5 @@ type initStaticResourceMiddlewareOptions = {
|
|
|
6
6
|
skipRunningCheck?: boolean;
|
|
7
7
|
};
|
|
8
8
|
export declare const initStaticResourceMiddleware: ({ options, resourceTypes: _resourceTypes, express, skipRunningCheck: _skipRunningCheck, }?: initStaticResourceMiddlewareOptions) => (req: any, res: any, next: Function) => void;
|
|
9
|
-
export declare const getCanUseResources: () => any;
|
|
10
9
|
export declare const initProxyToMediaKitUploadsMiddleware: ({ options, express }?: any) => (req: any, res: any, next: Function) => Promise<any>;
|
|
11
10
|
export {};
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.mappingResource = exports.initStaticResourceMiddleware = exports.initProxyToMediaKitUploadsMiddleware =
|
|
6
|
+
exports.mappingResource = exports.initStaticResourceMiddleware = exports.initProxyToMediaKitUploadsMiddleware = void 0;
|
|
7
7
|
var _fs = require("fs");
|
|
8
8
|
var _path = require("path");
|
|
9
9
|
var _config = _interopRequireDefault(require("@blocklet/sdk/lib/config"));
|
|
10
10
|
var _component = _interopRequireWildcard(require("@blocklet/sdk/lib/component"));
|
|
11
11
|
var _urlJoin = _interopRequireDefault(require("url-join"));
|
|
12
|
+
var _mimeTypes = _interopRequireDefault(require("mime-types"));
|
|
12
13
|
var _utils = require("../utils");
|
|
13
14
|
var _constants = require("../constants");
|
|
15
|
+
var _ms = _interopRequireDefault(require("ms"));
|
|
14
16
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
15
17
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
16
18
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -22,13 +24,14 @@ let resourceTypes = [{
|
|
|
22
24
|
folder: ""
|
|
23
25
|
// can be string or string[]
|
|
24
26
|
}];
|
|
25
|
-
let
|
|
27
|
+
let resourcesMap = /* @__PURE__ */new Map();
|
|
26
28
|
const mappingResource = async () => {
|
|
27
29
|
try {
|
|
28
30
|
const resources = (0, _component.getResources)({
|
|
29
31
|
types: resourceTypes,
|
|
30
32
|
skipRunningCheck
|
|
31
33
|
});
|
|
34
|
+
let canUseResources = [];
|
|
32
35
|
canUseResources = resources.map(resource => {
|
|
33
36
|
const originDir = resource.path;
|
|
34
37
|
const resourceType = resourceTypes.find(({
|
|
@@ -46,9 +49,52 @@ const mappingResource = async () => {
|
|
|
46
49
|
blacklist: resourceType.blacklist
|
|
47
50
|
}));
|
|
48
51
|
}).filter(Boolean).flat();
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
resourcesMap.clear();
|
|
53
|
+
for (const resource of canUseResources) {
|
|
54
|
+
const {
|
|
55
|
+
dir,
|
|
56
|
+
whitelist,
|
|
57
|
+
blacklist,
|
|
58
|
+
originDir,
|
|
59
|
+
blockletInfo
|
|
60
|
+
} = resource;
|
|
61
|
+
if ((0, _fs.existsSync)(dir)) {
|
|
62
|
+
try {
|
|
63
|
+
const files = (0, _fs.readdirSync)(dir);
|
|
64
|
+
for (const file of files) {
|
|
65
|
+
const filePath = (0, _path.join)(dir, file);
|
|
66
|
+
let stat;
|
|
67
|
+
try {
|
|
68
|
+
stat = (0, _fs.statSync)(filePath);
|
|
69
|
+
if (stat.isDirectory()) continue;
|
|
70
|
+
} catch (e) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (whitelist?.length && !whitelist.some(ext => file.endsWith(ext))) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (blacklist?.length && blacklist.some(ext => file.endsWith(ext))) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const contentType = _mimeTypes.default.lookup(filePath) || "application/octet-stream";
|
|
80
|
+
resourcesMap.set(file, {
|
|
81
|
+
filePath,
|
|
82
|
+
dir,
|
|
83
|
+
originDir,
|
|
84
|
+
blockletInfo,
|
|
85
|
+
whitelist,
|
|
86
|
+
blacklist,
|
|
87
|
+
mtime: stat.mtime,
|
|
88
|
+
size: stat.size,
|
|
89
|
+
contentType
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
_utils.logger.error(`Error scanning directory ${dir}:`, err);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
_utils.logger.info("Mapping resources: files count:", resourcesMap.size, "directories count:", canUseResources.length);
|
|
52
98
|
return canUseResources;
|
|
53
99
|
} catch (error) {
|
|
54
100
|
_utils.logger.error(error);
|
|
@@ -66,12 +112,26 @@ events.on(Events.componentStarted, () => mappingResource());
|
|
|
66
112
|
events.on(Events.componentStopped, () => mappingResource());
|
|
67
113
|
events.on(Events.componentUpdated, () => mappingResource());
|
|
68
114
|
const initStaticResourceMiddleware = ({
|
|
69
|
-
options,
|
|
115
|
+
options = {},
|
|
70
116
|
resourceTypes: _resourceTypes = resourceTypes,
|
|
71
117
|
express,
|
|
72
118
|
skipRunningCheck: _skipRunningCheck
|
|
73
119
|
} = {}) => {
|
|
74
120
|
skipRunningCheck = !!_skipRunningCheck;
|
|
121
|
+
let maxAgeInSeconds = 31536e3;
|
|
122
|
+
const maxAge = options.maxAge || "365d";
|
|
123
|
+
if (typeof maxAge === "string") {
|
|
124
|
+
try {
|
|
125
|
+
const milliseconds = (0, _ms.default)(maxAge);
|
|
126
|
+
maxAgeInSeconds = typeof milliseconds === "number" ? milliseconds / 1e3 : 31536e3;
|
|
127
|
+
} catch (e) {
|
|
128
|
+
_utils.logger.warn(`Invalid maxAge format: ${maxAge}, using default 1 year (31536000 seconds)`);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
maxAgeInSeconds = maxAge;
|
|
132
|
+
}
|
|
133
|
+
const cacheControl = `public, max-age=${maxAgeInSeconds}`;
|
|
134
|
+
const cacheControlImmutable = `${cacheControl}, immutable`;
|
|
75
135
|
if (_resourceTypes?.length > 0) {
|
|
76
136
|
resourceTypes = _resourceTypes.map(item => {
|
|
77
137
|
if (typeof item === "string") {
|
|
@@ -90,44 +150,44 @@ const initStaticResourceMiddleware = ({
|
|
|
90
150
|
return (req, res, next) => {
|
|
91
151
|
const fileName = (0, _path.basename)(req.path || req.url?.split("?")[0]);
|
|
92
152
|
try {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
153
|
+
const resource = resourcesMap.get(fileName);
|
|
154
|
+
if (resource) {
|
|
155
|
+
res.setHeader("Content-Type", resource.contentType);
|
|
156
|
+
res.setHeader("Content-Length", resource.size);
|
|
157
|
+
res.setHeader("Last-Modified", resource.mtime.toUTCString());
|
|
158
|
+
res.setHeader("Cache-Control", options.immutable === false ? cacheControl : cacheControlImmutable);
|
|
159
|
+
if (options.setHeaders && typeof options.setHeaders === "function") {
|
|
160
|
+
const statObj = {
|
|
161
|
+
mtime: resource.mtime,
|
|
162
|
+
size: resource.size
|
|
163
|
+
};
|
|
164
|
+
options.setHeaders(res, resource.filePath, statObj);
|
|
100
165
|
}
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
166
|
+
const ifModifiedSince = req.headers["if-modified-since"];
|
|
167
|
+
if (ifModifiedSince) {
|
|
168
|
+
const ifModifiedSinceDate = new Date(ifModifiedSince);
|
|
169
|
+
if (resource.mtime <= ifModifiedSinceDate) {
|
|
170
|
+
res.statusCode = 304;
|
|
171
|
+
res.end();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
107
174
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
express.static(matchCanUseResourceItem.dir, {
|
|
115
|
-
maxAge: "365d",
|
|
116
|
-
immutable: true,
|
|
117
|
-
index: false,
|
|
118
|
-
...options
|
|
119
|
-
})(req, res, next);
|
|
175
|
+
const fileStream = (0, _fs.createReadStream)(resource.filePath);
|
|
176
|
+
fileStream.on("error", error => {
|
|
177
|
+
_utils.logger.error(`Error streaming file ${resource.filePath}:`, error);
|
|
178
|
+
next(error);
|
|
179
|
+
});
|
|
180
|
+
fileStream.pipe(res);
|
|
120
181
|
} else {
|
|
121
182
|
next();
|
|
122
183
|
}
|
|
123
184
|
} catch (error) {
|
|
185
|
+
_utils.logger.error("Error serving static file:", error);
|
|
124
186
|
next();
|
|
125
187
|
}
|
|
126
188
|
};
|
|
127
189
|
};
|
|
128
190
|
exports.initStaticResourceMiddleware = initStaticResourceMiddleware;
|
|
129
|
-
const getCanUseResources = () => canUseResources;
|
|
130
|
-
exports.getCanUseResources = getCanUseResources;
|
|
131
191
|
const initProxyToMediaKitUploadsMiddleware = ({
|
|
132
192
|
options,
|
|
133
193
|
express
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/uploader-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.91",
|
|
4
4
|
"description": "blocklet upload server",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"express-session": "1.17.3",
|
|
62
62
|
"isbot": "^5.1.17",
|
|
63
63
|
"mime-types": "^2.1.35",
|
|
64
|
+
"ms": "^2.1.3",
|
|
64
65
|
"p-queue": "6.6.2",
|
|
65
66
|
"ufo": "^1.5.4",
|
|
66
67
|
"url-join": "^4.0.1"
|