tezx 1.0.21 → 1.0.23
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/.gitignore +22 -0
- package/.npmignore +18 -0
- package/MiddlewareConfigure.d.ts +17 -0
- package/MiddlewareConfigure.js +63 -0
- package/adapter.d.ts +10 -0
- package/adapter.js +162 -0
- package/common.d.ts +21 -0
- package/common.js +11 -0
- package/config/config.d.ts +17 -0
- package/config/config.js +31 -0
- package/context.d.ts +195 -0
- package/context.js +424 -0
- package/environment.d.ts +6 -0
- package/environment.js +30 -0
- package/header.d.ts +71 -0
- package/header.js +81 -0
- package/package.json +2 -6
- package/request.d.ts +82 -0
- package/request.js +76 -0
- package/router.d.ts +191 -0
- package/router.js +373 -0
- package/server.d.ts +54 -0
- package/server.js +166 -0
- package/utils/colors.d.ts +21 -0
- package/utils/colors.js +21 -0
- package/utils/debugging.d.ts +7 -0
- package/utils/debugging.js +13 -0
- package/utils/formData.d.ts +5 -0
- package/utils/formData.js +213 -0
- package/utils/params.d.ts +7 -0
- package/utils/params.js +91 -0
- package/utils/state.d.ts +50 -0
- package/utils/state.js +30 -0
- package/utils/staticFile.d.ts +9 -0
- package/utils/staticFile.js +154 -0
- package/utils/url.d.ts +16 -0
- package/utils/url.js +55 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { EnvironmentDetector } from "../environment";
|
|
2
|
+
export async function parseJsonBody(req) {
|
|
3
|
+
const runtime = EnvironmentDetector.getEnvironment;
|
|
4
|
+
if (runtime === "node") {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
let body = "";
|
|
7
|
+
req.on("data", (chunk) => {
|
|
8
|
+
body += chunk.toString();
|
|
9
|
+
});
|
|
10
|
+
req.on("end", () => {
|
|
11
|
+
try {
|
|
12
|
+
resolve(JSON.parse(body));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
reject(new Error("Invalid JSON format"));
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
else if (runtime === "deno" || runtime === "bun") {
|
|
21
|
+
return await req.json();
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
throw new Error("Unsupported environment for multipart parsing");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function parseTextBody(req) {
|
|
28
|
+
const runtime = EnvironmentDetector.getEnvironment;
|
|
29
|
+
if (runtime === "node") {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
let body = "";
|
|
32
|
+
req.on("data", (chunk) => {
|
|
33
|
+
body += chunk.toString();
|
|
34
|
+
});
|
|
35
|
+
req.on("end", () => {
|
|
36
|
+
try {
|
|
37
|
+
resolve(body);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
reject(new Error("Invalid JSON format"));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else if (runtime === "deno" || runtime === "bun") {
|
|
46
|
+
return await req.text();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
throw new Error("Unsupported environment for multipart parsing");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export async function parseUrlEncodedBody(req) {
|
|
53
|
+
const runtime = EnvironmentDetector.getEnvironment;
|
|
54
|
+
if (runtime === "node") {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
let body = "";
|
|
57
|
+
req.on("data", (chunk) => {
|
|
58
|
+
body += chunk.toString("binary");
|
|
59
|
+
});
|
|
60
|
+
req.on("end", () => {
|
|
61
|
+
try {
|
|
62
|
+
const pairs = body.split("&");
|
|
63
|
+
const formData = {};
|
|
64
|
+
pairs.forEach((pair) => {
|
|
65
|
+
const [key, value] = pair.split("=");
|
|
66
|
+
formData[decodeURIComponent(key)] = decodeURIComponent(value || "");
|
|
67
|
+
});
|
|
68
|
+
resolve(formData);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
reject(new Error("Invalid x-www-form-urlencoded format"));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else if (runtime === "deno" || runtime === "bun") {
|
|
77
|
+
const formData = await req.formData();
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const [key, value] of formData.entries()) {
|
|
80
|
+
result[key] = value;
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new Error("Unsupported environment for multipart parsing");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export async function parseMultipartBody(req, boundary, options) {
|
|
89
|
+
const runtime = EnvironmentDetector.getEnvironment;
|
|
90
|
+
const x = options?.sanitized;
|
|
91
|
+
if (runtime === "node") {
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
let body = "";
|
|
94
|
+
req.on("data", (chunk) => {
|
|
95
|
+
body += chunk.toString("binary");
|
|
96
|
+
});
|
|
97
|
+
req.on("end", () => {
|
|
98
|
+
try {
|
|
99
|
+
const formDataField = {};
|
|
100
|
+
const formDataFieldParts = body.split("----------------------------");
|
|
101
|
+
formDataFieldParts.forEach((part) => {
|
|
102
|
+
const match = part.match(/name="(.*)"\r\n\r\n(.*)\r\n/);
|
|
103
|
+
if (match && match.length === 3) {
|
|
104
|
+
const name = match[1];
|
|
105
|
+
const value = match[2];
|
|
106
|
+
formDataField[name] = value;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const parts = body.split(`--${boundary}`);
|
|
110
|
+
for (const part of parts) {
|
|
111
|
+
if (part.includes("filename")) {
|
|
112
|
+
const filenameMatch = part.match(/filename="([^"]+)"/);
|
|
113
|
+
const fieldNameMatch = part.match(/name="([^"]+)"/);
|
|
114
|
+
const contentTypeMatch = part.match(/Content-Type: ([^\r\n]+)/);
|
|
115
|
+
if (filenameMatch && fieldNameMatch && contentTypeMatch) {
|
|
116
|
+
let filename = filenameMatch[1];
|
|
117
|
+
const fieldName = fieldNameMatch[1];
|
|
118
|
+
const contentType = contentTypeMatch[1];
|
|
119
|
+
if (options?.sanitized) {
|
|
120
|
+
filename =
|
|
121
|
+
`${Date.now()}-${filename.replace(/\s+/g, "")?.replace(/[^a-zA-Z0-9.-]/g, "-")}`?.toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(options?.allowedTypes) &&
|
|
124
|
+
!options.allowedTypes?.includes(contentType)) {
|
|
125
|
+
reject(`Invalid file type: "${contentType}". Allowed types: ${options.allowedTypes.join(", ")}`);
|
|
126
|
+
}
|
|
127
|
+
const fileContentStartIndex = part.indexOf("\r\n\r\n") + 4;
|
|
128
|
+
const fileContent = Buffer.from(part.substring(fileContentStartIndex), "binary");
|
|
129
|
+
const arrayBuffer = fileContent.buffer.slice(fileContent.byteOffset, fileContent.byteOffset + fileContent.byteLength);
|
|
130
|
+
if (typeof options?.maxSize !== "undefined" &&
|
|
131
|
+
fileContent.byteLength > options.maxSize) {
|
|
132
|
+
reject(`File size exceeds the limit: ${fileContent.byteLength} bytes (Max: ${options.maxSize} bytes)`);
|
|
133
|
+
}
|
|
134
|
+
const file = new File([arrayBuffer], filename, {
|
|
135
|
+
type: contentType,
|
|
136
|
+
});
|
|
137
|
+
if (typeof options?.maxFiles != "undefined" &&
|
|
138
|
+
options.maxFiles == 0) {
|
|
139
|
+
reject(`Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
140
|
+
}
|
|
141
|
+
if (formDataField[fieldName]) {
|
|
142
|
+
if (Array.isArray(formDataField[fieldName])) {
|
|
143
|
+
if (typeof options?.maxFiles != "undefined" &&
|
|
144
|
+
formDataField[fieldName]?.length >= options.maxFiles) {
|
|
145
|
+
reject(`Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
146
|
+
}
|
|
147
|
+
formDataField[fieldName].push(file);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
formDataField[fieldName] = [formDataField[fieldName], file];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
formDataField[fieldName] = file;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
resolve(formDataField);
|
|
160
|
+
}
|
|
161
|
+
catch { }
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else if (runtime === "deno" || runtime === "bun") {
|
|
166
|
+
const formData = await req.formData();
|
|
167
|
+
const result = {};
|
|
168
|
+
for (const [key, value] of formData.entries()) {
|
|
169
|
+
let val = value;
|
|
170
|
+
if (val instanceof File && typeof options == "object") {
|
|
171
|
+
let filename = val.name;
|
|
172
|
+
if (options?.sanitized) {
|
|
173
|
+
filename =
|
|
174
|
+
`${Date.now()}-${filename.replace(/\s+/g, "")?.replace(/[^a-zA-Z0-9.-]/g, "-")}`?.toLowerCase();
|
|
175
|
+
}
|
|
176
|
+
if (Array.isArray(options?.allowedTypes) &&
|
|
177
|
+
!options.allowedTypes?.includes(val.type)) {
|
|
178
|
+
throw new Error(`Invalid file type: "${val.type}". Allowed types: ${options.allowedTypes.join(", ")}`);
|
|
179
|
+
}
|
|
180
|
+
if (typeof options?.maxSize !== "undefined" &&
|
|
181
|
+
val.size > options.maxSize) {
|
|
182
|
+
throw new Error(`File size exceeds the limit: ${val.size} bytes (Max: ${options.maxSize} bytes)`);
|
|
183
|
+
}
|
|
184
|
+
if (typeof options?.maxFiles != "undefined" && options.maxFiles == 0) {
|
|
185
|
+
throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
186
|
+
}
|
|
187
|
+
val = new File([await val.arrayBuffer()], filename, {
|
|
188
|
+
type: val.type,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (result[key]) {
|
|
192
|
+
if (Array.isArray(result[key])) {
|
|
193
|
+
if (val instanceof File &&
|
|
194
|
+
typeof options?.maxFiles != "undefined" &&
|
|
195
|
+
result[key]?.length >= options.maxFiles) {
|
|
196
|
+
throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
|
|
197
|
+
}
|
|
198
|
+
result[key].push(val);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
result[key] = [result[key], val];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
result[key] = val;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
throw new Error("Unsupported environment for multipart parsing");
|
|
212
|
+
}
|
|
213
|
+
}
|
package/utils/params.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export function useParams({ path, urlPattern, }) {
|
|
2
|
+
let params = {};
|
|
3
|
+
path = path.replace(/^\/+|\/+$/g, "");
|
|
4
|
+
urlPattern = urlPattern.replace(/^\/+|\/+$/g, "");
|
|
5
|
+
const pathSegments = path ? path.split("/") : [];
|
|
6
|
+
const patternSegments = urlPattern ? urlPattern.split("/") : [];
|
|
7
|
+
const pathLength = pathSegments.length;
|
|
8
|
+
const patternLength = patternSegments.length;
|
|
9
|
+
if (pathLength > patternLength && !urlPattern.includes("*")) {
|
|
10
|
+
return { success: false, params: {} };
|
|
11
|
+
}
|
|
12
|
+
let pathIndex = 0;
|
|
13
|
+
for (let i = 0; i < patternLength; i++) {
|
|
14
|
+
const patternSegment = patternSegments[i];
|
|
15
|
+
if (patternSegment?.startsWith("*")) {
|
|
16
|
+
const trailingPatterns = patternSegments.slice(i + 1);
|
|
17
|
+
let paramName = patternSegment.length == 1 ? "*" : patternSegment?.slice(1);
|
|
18
|
+
if (trailingPatterns.length > 0) {
|
|
19
|
+
const expectedTrailing = trailingPatterns.join("/");
|
|
20
|
+
const actualTrailing = pathSegments
|
|
21
|
+
.slice(pathLength - trailingPatterns.length)
|
|
22
|
+
.join("/");
|
|
23
|
+
const wildcardPath = pathSegments
|
|
24
|
+
.slice(pathIndex, pathLength - trailingPatterns.length)
|
|
25
|
+
.join("/");
|
|
26
|
+
if (expectedTrailing !== actualTrailing || !wildcardPath) {
|
|
27
|
+
return { success: false, params: {} };
|
|
28
|
+
}
|
|
29
|
+
params[paramName] = wildcardPath;
|
|
30
|
+
return { success: true, params };
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const wildcardPath = pathSegments.slice(pathIndex).join("/");
|
|
34
|
+
if (!wildcardPath) {
|
|
35
|
+
return { success: false, params: {} };
|
|
36
|
+
}
|
|
37
|
+
params[paramName] = wildcardPath;
|
|
38
|
+
return { success: true, params };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (patternSegment.startsWith(":") && patternSegment.endsWith("?")) {
|
|
42
|
+
const paramName = patternSegment.slice(1, -1);
|
|
43
|
+
const nextPattern = patternSegments[i + 1];
|
|
44
|
+
if (nextPattern &&
|
|
45
|
+
!nextPattern.startsWith(":") &&
|
|
46
|
+
nextPattern !== "*" &&
|
|
47
|
+
pathIndex < pathLength &&
|
|
48
|
+
pathSegments[pathIndex] === nextPattern) {
|
|
49
|
+
params[paramName] = null;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const remainingPatterns = patternSegments.slice(i + 1);
|
|
53
|
+
const requiredCount = remainingPatterns.filter((seg) => !(seg.startsWith(":") && seg.endsWith("?"))).length;
|
|
54
|
+
const remainingPath = pathLength - pathIndex;
|
|
55
|
+
if (remainingPath === requiredCount) {
|
|
56
|
+
params[paramName] = null;
|
|
57
|
+
}
|
|
58
|
+
else if (pathIndex < pathLength) {
|
|
59
|
+
params[paramName] = pathSegments[pathIndex];
|
|
60
|
+
pathIndex++;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
params[paramName] = null;
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (patternSegment.startsWith(":")) {
|
|
68
|
+
const paramName = patternSegment.slice(1);
|
|
69
|
+
if (!/^[a-zA-Z0-9_]+$/.test(paramName)) {
|
|
70
|
+
return { success: false, params: {} };
|
|
71
|
+
}
|
|
72
|
+
if (pathIndex < pathLength) {
|
|
73
|
+
params[paramName] = pathSegments[pathIndex];
|
|
74
|
+
pathIndex++;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return { success: false, params: {} };
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const pathSegment = pathSegments[pathIndex];
|
|
82
|
+
if (patternSegment !== pathSegment) {
|
|
83
|
+
return { success: false, params: {} };
|
|
84
|
+
}
|
|
85
|
+
pathIndex++;
|
|
86
|
+
}
|
|
87
|
+
if (pathIndex < pathLength) {
|
|
88
|
+
return { success: false, params: {} };
|
|
89
|
+
}
|
|
90
|
+
return { success: true, params };
|
|
91
|
+
}
|
package/utils/state.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple key-value storage class using Map.
|
|
3
|
+
*/
|
|
4
|
+
export declare class State {
|
|
5
|
+
private state;
|
|
6
|
+
constructor();
|
|
7
|
+
/**
|
|
8
|
+
* Store a value with a specific key.
|
|
9
|
+
* @param key - The key for the value.
|
|
10
|
+
* @param value - The value to be stored.
|
|
11
|
+
*/
|
|
12
|
+
set(key: string, value: any): void;
|
|
13
|
+
/**
|
|
14
|
+
* Retrieve a value by key.
|
|
15
|
+
* @param key - The key of the value to retrieve.
|
|
16
|
+
* @returns The stored value or undefined if not found.
|
|
17
|
+
*/
|
|
18
|
+
get(key: string): any | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Delete a key from storage.
|
|
21
|
+
* @param key - The key to remove.
|
|
22
|
+
* @returns True if the key was deleted, false otherwise.
|
|
23
|
+
*/
|
|
24
|
+
delete(key: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a key exists in the storage.
|
|
27
|
+
* @param key - The key to check.
|
|
28
|
+
* @returns True if the key exists, false otherwise.
|
|
29
|
+
*/
|
|
30
|
+
has(key: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Get an array of all stored keys.
|
|
33
|
+
* @returns An array of keys.
|
|
34
|
+
*/
|
|
35
|
+
keys(): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Get an array of all stored values.
|
|
38
|
+
* @returns An array of values.
|
|
39
|
+
*/
|
|
40
|
+
values(): any[];
|
|
41
|
+
/**
|
|
42
|
+
* Get an array of all key-value pairs.
|
|
43
|
+
* @returns An array of [key, value] tuples.
|
|
44
|
+
*/
|
|
45
|
+
entries(): [string, any][];
|
|
46
|
+
/**
|
|
47
|
+
* Remove all entries from storage.
|
|
48
|
+
*/
|
|
49
|
+
clear(): void;
|
|
50
|
+
}
|
package/utils/state.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class State {
|
|
2
|
+
state;
|
|
3
|
+
constructor() {
|
|
4
|
+
this.state = new Map();
|
|
5
|
+
}
|
|
6
|
+
set(key, value) {
|
|
7
|
+
this.state.set(key, value);
|
|
8
|
+
}
|
|
9
|
+
get(key) {
|
|
10
|
+
return this.state.get(key);
|
|
11
|
+
}
|
|
12
|
+
delete(key) {
|
|
13
|
+
return this.state.delete(key);
|
|
14
|
+
}
|
|
15
|
+
has(key) {
|
|
16
|
+
return this.state.has(key);
|
|
17
|
+
}
|
|
18
|
+
keys() {
|
|
19
|
+
return Array.from(this.state.keys());
|
|
20
|
+
}
|
|
21
|
+
values() {
|
|
22
|
+
return Array.from(this.state.values());
|
|
23
|
+
}
|
|
24
|
+
entries() {
|
|
25
|
+
return Array.from(this.state.entries());
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
this.state.clear();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Router, StaticServeOption } from "../router";
|
|
2
|
+
export declare const mimeTypes: {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const defaultMimeType = "application/octet-stream";
|
|
6
|
+
export declare function getFiles(dir: string, basePath: string | undefined, ref: Router<any>, option: StaticServeOption): Promise<{
|
|
7
|
+
file: string;
|
|
8
|
+
path: string;
|
|
9
|
+
}[]>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { EnvironmentDetector } from "../environment";
|
|
2
|
+
export const mimeTypes = {
|
|
3
|
+
html: "text/html",
|
|
4
|
+
htm: "text/html",
|
|
5
|
+
css: "text/css",
|
|
6
|
+
js: "text/javascript",
|
|
7
|
+
mjs: "text/javascript",
|
|
8
|
+
json: "application/json",
|
|
9
|
+
xml: "application/xml",
|
|
10
|
+
txt: "text/plain",
|
|
11
|
+
md: "text/markdown",
|
|
12
|
+
csv: "text/csv",
|
|
13
|
+
tsv: "text/tab-separated-values",
|
|
14
|
+
rtf: "application/rtf",
|
|
15
|
+
markdown: "text/markdown",
|
|
16
|
+
png: "image/png",
|
|
17
|
+
jpg: "image/jpeg",
|
|
18
|
+
jpeg: "image/jpeg",
|
|
19
|
+
gif: "image/gif",
|
|
20
|
+
svg: "image/svg+xml",
|
|
21
|
+
webp: "image/webp",
|
|
22
|
+
ico: "image/x-icon",
|
|
23
|
+
bmp: "image/bmp",
|
|
24
|
+
tiff: "image/tiff",
|
|
25
|
+
psd: "image/vnd.adobe.photoshop",
|
|
26
|
+
mp4: "video/mp4",
|
|
27
|
+
webm: "video/webm",
|
|
28
|
+
ogg: "video/ogg",
|
|
29
|
+
mov: "video/quicktime",
|
|
30
|
+
avi: "video/x-msvideo",
|
|
31
|
+
wmv: "video/x-ms-wmv",
|
|
32
|
+
flv: "video/x-flv",
|
|
33
|
+
"3gp": "video/3gpp",
|
|
34
|
+
mp3: "audio/mpeg",
|
|
35
|
+
wav: "audio/wav",
|
|
36
|
+
aac: "audio/aac",
|
|
37
|
+
flac: "audio/flac",
|
|
38
|
+
m4a: "audio/mp4",
|
|
39
|
+
mid: "audio/midi",
|
|
40
|
+
midi: "audio/midi",
|
|
41
|
+
woff: "font/woff",
|
|
42
|
+
woff2: "font/woff2",
|
|
43
|
+
ttf: "font/ttf",
|
|
44
|
+
otf: "font/otf",
|
|
45
|
+
eot: "application/vnd.ms-fontobject",
|
|
46
|
+
pdf: "application/pdf",
|
|
47
|
+
odp: "application/vnd.oasis.opendocument.presentation",
|
|
48
|
+
zip: "application/zip",
|
|
49
|
+
gz: "application/gzip",
|
|
50
|
+
tar: "application/x-tar",
|
|
51
|
+
rar: "application/x-rar-compressed",
|
|
52
|
+
_7z: "application/x-7z-compressed",
|
|
53
|
+
bz2: "application/x-bzip2",
|
|
54
|
+
"7z": "application/x-7z-compressed",
|
|
55
|
+
doc: "application/msword",
|
|
56
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
57
|
+
xls: "application/vnd.ms-excel",
|
|
58
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
59
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
60
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
61
|
+
odt: "application/vnd.oasis.opendocument.text",
|
|
62
|
+
ods: "application/vnd.oasis.opendocument.spreadsheet",
|
|
63
|
+
wasm: "application/wasm",
|
|
64
|
+
map: "application/json",
|
|
65
|
+
yaml: "application/yaml",
|
|
66
|
+
yml: "application/yaml",
|
|
67
|
+
proto: "text/plain",
|
|
68
|
+
graphql: "application/graphql",
|
|
69
|
+
pem: "application/x-pem-file",
|
|
70
|
+
cer: "application/pkix-cert",
|
|
71
|
+
crt: "application/x-x509-ca-cert",
|
|
72
|
+
key: "application/x-pem-file",
|
|
73
|
+
pfx: "application/x-pkcs12",
|
|
74
|
+
glb: "model/gltf-binary",
|
|
75
|
+
gltf: "model/gltf+json",
|
|
76
|
+
obj: "model/obj",
|
|
77
|
+
stl: "model/stl",
|
|
78
|
+
usdz: "model/vnd.usdz+zip",
|
|
79
|
+
exe: "application/x-msdownload",
|
|
80
|
+
dmg: "application/x-apple-diskimage",
|
|
81
|
+
deb: "application/x-debian-package",
|
|
82
|
+
rpm: "application/x-redhat-package-manager",
|
|
83
|
+
apk: "application/vnd.android.package-archive",
|
|
84
|
+
webmanifest: "application/manifest+json",
|
|
85
|
+
ics: "text/calendar",
|
|
86
|
+
vcf: "text/vcard",
|
|
87
|
+
warc: "application/warc",
|
|
88
|
+
atom: "application/atom+xml",
|
|
89
|
+
rss: "application/rss+xml",
|
|
90
|
+
dll: "application/x-msdownload",
|
|
91
|
+
sh: "application/x-sh",
|
|
92
|
+
py: "text/x-python",
|
|
93
|
+
rb: "text/x-ruby",
|
|
94
|
+
pl: "text/x-perl",
|
|
95
|
+
php: "application/x-httpd-php",
|
|
96
|
+
torrent: "application/x-bittorrent",
|
|
97
|
+
ipa: "application/vnd.iphone",
|
|
98
|
+
eps: "application/postscript",
|
|
99
|
+
ps: "application/postscript",
|
|
100
|
+
ai: "application/postscript",
|
|
101
|
+
swf: "application/x-shockwave-flash",
|
|
102
|
+
jar: "application/java-archive",
|
|
103
|
+
gcode: "text/x.gcode",
|
|
104
|
+
};
|
|
105
|
+
export const defaultMimeType = "application/octet-stream";
|
|
106
|
+
export async function getFiles(dir, basePath = "/", ref, option) {
|
|
107
|
+
const files = [];
|
|
108
|
+
const runtime = EnvironmentDetector.getEnvironment;
|
|
109
|
+
if (runtime == "deno") {
|
|
110
|
+
for await (const entry of Deno.readDir(dir)) {
|
|
111
|
+
const path = `${dir}/${entry.name}`;
|
|
112
|
+
if (entry.isDirectory) {
|
|
113
|
+
files.push(...(await getFiles(path, `${basePath}/${entry.name}`, ref, option)));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const x = `${basePath}/${entry.name}`;
|
|
117
|
+
files.push({
|
|
118
|
+
file: path,
|
|
119
|
+
path: x.replace(/\\/g, "/"),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const fs = await import("fs/promises");
|
|
126
|
+
const path = await import("path");
|
|
127
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
const fullPath = path.join(dir, entry.name);
|
|
130
|
+
if (entry.isDirectory()) {
|
|
131
|
+
files.push(...(await getFiles(fullPath, `${basePath}/${entry.name}`, ref, option)));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const path = `${basePath}/${entry.name}`;
|
|
135
|
+
files.push({
|
|
136
|
+
file: fullPath,
|
|
137
|
+
path: path.replace(/\\/g, "/"),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
files.forEach((r) => {
|
|
143
|
+
ref.get(r.path, (ctx) => {
|
|
144
|
+
if (option.cacheControl) {
|
|
145
|
+
ctx.headers.set("Cache-Control", option.cacheControl);
|
|
146
|
+
}
|
|
147
|
+
if (option.headers) {
|
|
148
|
+
ctx.headers.add(option.headers);
|
|
149
|
+
}
|
|
150
|
+
return ctx.sendFile(r.file);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
return files;
|
|
154
|
+
}
|
package/utils/url.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type UrlRef = {
|
|
2
|
+
hash: string | undefined;
|
|
3
|
+
protocol: string | undefined;
|
|
4
|
+
origin: string | undefined;
|
|
5
|
+
username: string | undefined;
|
|
6
|
+
password: string | undefined;
|
|
7
|
+
hostname: string | undefined;
|
|
8
|
+
port: string | undefined;
|
|
9
|
+
href: string | undefined;
|
|
10
|
+
query: {
|
|
11
|
+
[key: string]: string;
|
|
12
|
+
};
|
|
13
|
+
pathname: string | undefined;
|
|
14
|
+
};
|
|
15
|
+
export declare function sanitizePathSplit(basePath: string, path: string): string[];
|
|
16
|
+
export declare function urlParse(url: string): UrlRef;
|
package/utils/url.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function sanitizePathSplit(basePath, path) {
|
|
2
|
+
const parts = `${basePath}/${path}`
|
|
3
|
+
.replace(/\\/g, "")
|
|
4
|
+
?.split("/")
|
|
5
|
+
.filter(Boolean);
|
|
6
|
+
return parts;
|
|
7
|
+
}
|
|
8
|
+
export function urlParse(url) {
|
|
9
|
+
const urlPattern = /^(?:(\w+):\/\/)?(?:([^:@]+)?(?::([^@]+))?@)?([^:/?#]+)?(?::(\d+))?(\/[^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/;
|
|
10
|
+
let matches = url.match(urlPattern);
|
|
11
|
+
if (!matches) {
|
|
12
|
+
href: url;
|
|
13
|
+
}
|
|
14
|
+
const [_, protocol, username, password, hostname, port, path, queryString, hash,] = matches;
|
|
15
|
+
let origin = hostname;
|
|
16
|
+
if (protocol) {
|
|
17
|
+
origin = protocol + "://" + hostname;
|
|
18
|
+
}
|
|
19
|
+
if (port) {
|
|
20
|
+
origin = origin + ":" + port;
|
|
21
|
+
}
|
|
22
|
+
let p = path;
|
|
23
|
+
if (p?.endsWith("/"))
|
|
24
|
+
p.slice(0, -1);
|
|
25
|
+
function query() {
|
|
26
|
+
if (queryString) {
|
|
27
|
+
const queryPart = decodeURIComponent(queryString);
|
|
28
|
+
const keyValuePairs = queryPart.split("&");
|
|
29
|
+
const paramsObj = keyValuePairs?.map((keyValue) => {
|
|
30
|
+
const [key, value] = keyValue.split("=");
|
|
31
|
+
return {
|
|
32
|
+
[key]: value,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return paramsObj.reduce(function (total, value) {
|
|
36
|
+
return { ...total, ...value };
|
|
37
|
+
}, {});
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
pathname: p,
|
|
45
|
+
hash,
|
|
46
|
+
protocol,
|
|
47
|
+
origin,
|
|
48
|
+
username,
|
|
49
|
+
password,
|
|
50
|
+
hostname,
|
|
51
|
+
href: url,
|
|
52
|
+
port,
|
|
53
|
+
query: query(),
|
|
54
|
+
};
|
|
55
|
+
}
|