@wxn0brp/falcon-frame 0.8.1 → 0.8.3
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/LICENSE +1 -1
- package/README.md +16 -17
- package/dist/compress.js +3 -0
- package/dist/helpers.d.ts +1 -2
- package/dist/helpers.js +0 -83
- package/dist/req.d.ts +1 -1
- package/dist/req.js +27 -9
- package/dist/res.d.ts +3 -2
- package/dist/res.js +4 -3
- package/dist/router.js +1 -1
- package/dist/sse.d.ts +4 -1
- package/dist/sse.js +8 -8
- package/dist/static.d.ts +2 -0
- package/dist/static.js +85 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js +2 -0
- package/package.json +4 -5
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
# FalconFrame
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A minimal, modular TypeScript web library.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Zero-dependency routing engine
|
|
8
|
+
- Middleware chaining
|
|
9
|
+
- Static file serving
|
|
10
|
+
- Request validation via inline schemas
|
|
11
|
+
- OpenAPI document generation
|
|
12
|
+
- Cookie management
|
|
13
|
+
- Debuggable logger
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
- 🧱 Middleware chaining
|
|
11
|
-
- 📁 Static file serving
|
|
12
|
-
- 📦 Request validation via inline schemas
|
|
13
|
-
- 🍪 Cookie management
|
|
14
|
-
- 🔍 Debuggable logger
|
|
15
|
-
|
|
16
|
-
## 📦 Installation
|
|
15
|
+
## Installation
|
|
17
16
|
|
|
18
17
|
```bash
|
|
19
|
-
|
|
18
|
+
bun add @wxn0brp/falcon-frame
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
##
|
|
21
|
+
## Usage Example
|
|
23
22
|
|
|
24
23
|
```ts
|
|
25
24
|
import FalconFrame, { validateBody } from "@wxn0brp/falcon-frame";
|
|
@@ -83,13 +82,13 @@ app.post(
|
|
|
83
82
|
// Protected route
|
|
84
83
|
app.get("/dashboard", requireAuth, (req, res) => {
|
|
85
84
|
return {
|
|
86
|
-
message:
|
|
85
|
+
message: `Welcome to the dashboard, ${req.cookies.session}`,
|
|
87
86
|
});
|
|
88
87
|
});
|
|
89
88
|
|
|
90
89
|
app.post("/logout", (req, res) => {
|
|
91
90
|
res.cookie("session", "", { maxAge: 0 });
|
|
92
|
-
res.json({ message: "
|
|
91
|
+
res.json({ message: "Logged out" });
|
|
93
92
|
});
|
|
94
93
|
|
|
95
94
|
// if no route matches
|
|
@@ -101,6 +100,6 @@ app.set404((req, res) => {
|
|
|
101
100
|
app.l(3000);
|
|
102
101
|
```
|
|
103
102
|
|
|
104
|
-
##
|
|
103
|
+
## License
|
|
105
104
|
|
|
106
|
-
Published under the MIT license
|
|
105
|
+
Published under the MIT license.
|
package/dist/compress.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { createDeflate, createGzip } from "zlib";
|
|
2
2
|
export function compression(req, res) {
|
|
3
|
+
if (req._compression)
|
|
4
|
+
return;
|
|
5
|
+
req._compression = true;
|
|
3
6
|
const encoding = req.headers["accept-encoding"];
|
|
4
7
|
if (!encoding || typeof encoding !== "string" || res.headersSent) {
|
|
5
8
|
return;
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Cookies
|
|
1
|
+
import { Cookies } from "./types.js";
|
|
2
2
|
export declare function parseCookies(cookieHeader: string): Cookies;
|
|
3
3
|
export declare function getContentType(filePath: string, utf8?: boolean): string;
|
|
4
|
-
export declare function handleStaticFiles(dirPath: string, opts: StaticServeOptions): RouteHandler;
|
|
5
4
|
export declare const ensureLeadingDot: (str: string) => string;
|
package/dist/helpers.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
1
|
import path from "path";
|
|
3
2
|
export function parseCookies(cookieHeader) {
|
|
4
3
|
const cookies = {};
|
|
@@ -33,86 +32,4 @@ export function getContentType(filePath, utf8 = false) {
|
|
|
33
32
|
contentType += "; charset=utf-8";
|
|
34
33
|
return contentType;
|
|
35
34
|
}
|
|
36
|
-
export function handleStaticFiles(dirPath, opts) {
|
|
37
|
-
opts = {
|
|
38
|
-
utf8: true,
|
|
39
|
-
render: true,
|
|
40
|
-
renderData: {},
|
|
41
|
-
etag: true,
|
|
42
|
-
errorIfDirNotFound: true,
|
|
43
|
-
...opts,
|
|
44
|
-
};
|
|
45
|
-
if (opts.errorIfDirNotFound && !fs.existsSync(dirPath)) {
|
|
46
|
-
throw new Error(`Directory ${dirPath} does not exist`);
|
|
47
|
-
}
|
|
48
|
-
const serveFile = (req, res, filePath, stats) => {
|
|
49
|
-
if (opts.render) {
|
|
50
|
-
const defaultRenderer = res.FF.getVar("view engine");
|
|
51
|
-
const renderStatement = (defaultRenderer && filePath.endsWith(ensureLeadingDot(defaultRenderer))) ||
|
|
52
|
-
(!opts.notRenderHtml && filePath.endsWith(".html"));
|
|
53
|
-
if (renderStatement) {
|
|
54
|
-
const relativePath = filePath.replace(dirPath + "/", "").replace(".html", "");
|
|
55
|
-
res.render(filePath, opts.renderData?.[relativePath] || {}, { notUseViews: true });
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (opts.etag) {
|
|
60
|
-
const etag = `W/"${stats.size}-${stats.mtime.getTime()}"`;
|
|
61
|
-
if (req.headers["if-none-match"] === etag) {
|
|
62
|
-
res.status(304).end();
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
res.setHeader("ETag", etag);
|
|
66
|
-
}
|
|
67
|
-
res.ct(getContentType(filePath, opts.utf8));
|
|
68
|
-
fs.createReadStream(filePath).pipe(res);
|
|
69
|
-
return true;
|
|
70
|
-
};
|
|
71
|
-
return (req, res, next) => {
|
|
72
|
-
if (req.method.toLowerCase() !== "get")
|
|
73
|
-
return next();
|
|
74
|
-
const apiPath = req.middleware.path;
|
|
75
|
-
const unsafePath = req.path.replace(apiPath, "");
|
|
76
|
-
const filePath = path.join(dirPath, path.normalize(unsafePath));
|
|
77
|
-
const resolvedPath = path.resolve(filePath);
|
|
78
|
-
const resolvedDir = path.resolve(dirPath);
|
|
79
|
-
if (!resolvedPath.startsWith(resolvedDir))
|
|
80
|
-
return next();
|
|
81
|
-
try {
|
|
82
|
-
const stats = fs.statSync(filePath);
|
|
83
|
-
if (stats.isFile()) {
|
|
84
|
-
return serveFile(req, res, filePath, stats);
|
|
85
|
-
}
|
|
86
|
-
if (stats.isDirectory()) {
|
|
87
|
-
const indexPath = path.join(filePath, "index.html");
|
|
88
|
-
try {
|
|
89
|
-
const indexStats = fs.statSync(indexPath);
|
|
90
|
-
if (indexStats.isFile()) {
|
|
91
|
-
if (!req.path.endsWith("/")) {
|
|
92
|
-
res.redirect(req.path + "/");
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
return serveFile(req, res, indexPath, indexStats);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch (e) {
|
|
99
|
-
/* index.html not found, do nothing */
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
catch (e) {
|
|
104
|
-
/* file/dir not found, proceed to check for .html */
|
|
105
|
-
}
|
|
106
|
-
try {
|
|
107
|
-
const htmlPath = filePath + ".html";
|
|
108
|
-
const htmlStats = fs.statSync(htmlPath);
|
|
109
|
-
if (htmlStats.isFile())
|
|
110
|
-
return serveFile(req, res, htmlPath, htmlStats);
|
|
111
|
-
}
|
|
112
|
-
catch (e) {
|
|
113
|
-
/* .html file not found, fall through to next() */
|
|
114
|
-
}
|
|
115
|
-
next();
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
35
|
export const ensureLeadingDot = (str) => (str.startsWith(".") ? str : "." + str);
|
package/dist/req.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import FalconFrame from "./index.js";
|
|
2
2
|
import { FFResponse } from "./res.js";
|
|
3
3
|
import { FFRequest } from "./types.js";
|
|
4
|
-
export declare function handleRequest(req: FFRequest, res: FFResponse, FF: FalconFrame<any
|
|
4
|
+
export declare function handleRequest(req: FFRequest, res: FFResponse, FF: FalconFrame<any>, reRoute?: boolean): void;
|
package/dist/req.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
1
2
|
import { URL } from "url";
|
|
2
3
|
import { parseCookies } from "./helpers.js";
|
|
3
4
|
import { getMiddlewares, matchMiddleware } from "./middleware.js";
|
|
4
5
|
import { FFResponse } from "./res.js";
|
|
5
6
|
import { validate } from "./valid.js";
|
|
6
|
-
export function handleRequest(req, res, FF) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
res.
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
export function handleRequest(req, res, FF, reRoute = false) {
|
|
8
|
+
if (!reRoute) {
|
|
9
|
+
Object.setPrototypeOf(res, FFResponse.prototype);
|
|
10
|
+
req.FF = FF;
|
|
11
|
+
res.FF = FF;
|
|
12
|
+
const originalEnd = res.end;
|
|
13
|
+
res.end = function (...any) {
|
|
14
|
+
res._ended = true;
|
|
15
|
+
return originalEnd.call(res, ...any);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
15
18
|
const { logger } = FF;
|
|
16
19
|
try {
|
|
17
20
|
const [path, params] = (req.url || "").split("?");
|
|
@@ -28,6 +31,16 @@ export function handleRequest(req, res, FF) {
|
|
|
28
31
|
req.cookies = parseCookies(req.headers.cookie || "");
|
|
29
32
|
req.params = {};
|
|
30
33
|
req.valid = (schema) => validate(schema, req.body);
|
|
34
|
+
req.reRoute = (fn) => {
|
|
35
|
+
fn(req);
|
|
36
|
+
handleRequest(req, res, FF, true);
|
|
37
|
+
};
|
|
38
|
+
if (FF.opts.xRequestId !== "disable") {
|
|
39
|
+
if (req.headers["x-request-id"])
|
|
40
|
+
res.setHeader("x-request-id", req.headers["x-request-id"]);
|
|
41
|
+
else if (FF.opts.xRequestId === "auto")
|
|
42
|
+
res.setHeader("x-request-id", randomUUID());
|
|
43
|
+
}
|
|
31
44
|
logger.info(`Incoming request: ${req.method} ${req.url}`);
|
|
32
45
|
const middlewaresPath = req.path + "/";
|
|
33
46
|
const middlewares = getMiddlewares(FF.middlewares, middlewaresPath.replace(/\/+/g, "/"));
|
|
@@ -98,6 +111,11 @@ export function handleRequest(req, res, FF) {
|
|
|
98
111
|
next();
|
|
99
112
|
return;
|
|
100
113
|
}
|
|
114
|
+
if (reRoute) {
|
|
115
|
+
logger.debug("Re-route. Executing middlewares");
|
|
116
|
+
next();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
101
119
|
req.body = {};
|
|
102
120
|
let bodyParserIndex = 0;
|
|
103
121
|
function nextBodyParser() {
|
package/dist/res.d.ts
CHANGED
|
@@ -38,13 +38,14 @@ export declare class FFResponse extends http.ServerResponse {
|
|
|
38
38
|
*/
|
|
39
39
|
status(code: number): this;
|
|
40
40
|
/**
|
|
41
|
-
* Set status code to
|
|
41
|
+
* Set status code to 303 and set location header to the provided url.
|
|
42
42
|
* If end is true, ends the response.
|
|
43
43
|
* @param url The url to redirect to
|
|
44
|
+
* @param status Status code to set
|
|
44
45
|
* @param end Whether to end the response after setting the headers
|
|
45
46
|
* @returns The response object
|
|
46
47
|
*/
|
|
47
|
-
redirect(url: string, end?: boolean): this;
|
|
48
|
+
redirect(url: string, status?: number, end?: boolean): this;
|
|
48
49
|
/**
|
|
49
50
|
* Sends a file as the response.
|
|
50
51
|
* Sets the "Content-Type" header based on the provided contentType or the file's extension.
|
package/dist/res.js
CHANGED
|
@@ -67,14 +67,15 @@ export class FFResponse extends http.ServerResponse {
|
|
|
67
67
|
return this;
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
|
-
* Set status code to
|
|
70
|
+
* Set status code to 303 and set location header to the provided url.
|
|
71
71
|
* If end is true, ends the response.
|
|
72
72
|
* @param url The url to redirect to
|
|
73
|
+
* @param status Status code to set
|
|
73
74
|
* @param end Whether to end the response after setting the headers
|
|
74
75
|
* @returns The response object
|
|
75
76
|
*/
|
|
76
|
-
redirect(url, end = true) {
|
|
77
|
-
this.statusCode =
|
|
77
|
+
redirect(url, status = 303, end = true) {
|
|
78
|
+
this.statusCode = status;
|
|
78
79
|
this.setHeader("Location", url);
|
|
79
80
|
if (end)
|
|
80
81
|
this.end();
|
package/dist/router.js
CHANGED
package/dist/sse.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { FFResponse } from "./res.js";
|
|
2
2
|
import type { FFRequest, RouteHandler } from "./types.js";
|
|
3
3
|
export declare class SSEManager {
|
|
4
|
-
|
|
4
|
+
_clients: Map<string, {
|
|
5
|
+
req: FFRequest;
|
|
6
|
+
res: FFResponse;
|
|
7
|
+
}>;
|
|
5
8
|
getMiddleware(lastHandler?: RouteHandler): RouteHandler;
|
|
6
9
|
getClients(): Map<string, {
|
|
7
10
|
req: FFRequest;
|
package/dist/sse.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
export class SSEManager {
|
|
3
|
-
|
|
3
|
+
_clients = new Map();
|
|
4
4
|
getMiddleware(lastHandler) {
|
|
5
5
|
return (req, res, next) => {
|
|
6
6
|
res.sseInit();
|
|
7
7
|
const id = randomUUID();
|
|
8
|
-
this.
|
|
8
|
+
this._clients.set(id, { req, res });
|
|
9
9
|
req.on("close", () => {
|
|
10
|
-
this.
|
|
10
|
+
this._clients.delete(id);
|
|
11
11
|
});
|
|
12
12
|
req.sseId = id;
|
|
13
13
|
lastHandler?.(req, res, next);
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
getClients() {
|
|
17
|
-
return this.
|
|
17
|
+
return this._clients;
|
|
18
18
|
}
|
|
19
19
|
sendAll(data) {
|
|
20
|
-
for (const { res } of this.
|
|
20
|
+
for (const { res } of this._clients.values()) {
|
|
21
21
|
res.sseSend(data);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
sendTo(id, data) {
|
|
25
|
-
const client = this.
|
|
25
|
+
const client = this._clients.get(id);
|
|
26
26
|
if (client) {
|
|
27
27
|
client.res.sseSend(data);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
disconnect(id) {
|
|
31
|
-
const client = this.
|
|
31
|
+
const client = this._clients.get(id);
|
|
32
32
|
if (client) {
|
|
33
33
|
client.res.end();
|
|
34
|
-
this.
|
|
34
|
+
this._clients.delete(id);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
package/dist/static.d.ts
ADDED
package/dist/static.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { ensureLeadingDot, getContentType } from "./helpers.js";
|
|
4
|
+
export function handleStaticFiles(dirPath, opts) {
|
|
5
|
+
opts = {
|
|
6
|
+
utf8: true,
|
|
7
|
+
render: true,
|
|
8
|
+
renderData: {},
|
|
9
|
+
etag: true,
|
|
10
|
+
errorIfDirNotFound: true,
|
|
11
|
+
...opts,
|
|
12
|
+
};
|
|
13
|
+
if (opts.errorIfDirNotFound && !fs.existsSync(dirPath)) {
|
|
14
|
+
throw new Error(`Directory ${dirPath} does not exist`);
|
|
15
|
+
}
|
|
16
|
+
const serveFile = (req, res, filePath, stats) => {
|
|
17
|
+
if (opts.render) {
|
|
18
|
+
const defaultRenderer = res.FF.getVar("view engine");
|
|
19
|
+
const renderStatement = (defaultRenderer && filePath.endsWith(ensureLeadingDot(defaultRenderer))) ||
|
|
20
|
+
(!opts.notRenderHtml && filePath.endsWith(".html"));
|
|
21
|
+
if (renderStatement) {
|
|
22
|
+
const relativePath = filePath.replace(dirPath + "/", "").replace(".html", "");
|
|
23
|
+
res.render(filePath, opts.renderData?.[relativePath] || {}, { notUseViews: true });
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (opts.etag) {
|
|
28
|
+
const etag = `W/"${stats.size}-${stats.mtime.getTime()}"`;
|
|
29
|
+
if (req.headers["if-none-match"] === etag) {
|
|
30
|
+
res.status(304).end();
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
res.setHeader("ETag", etag);
|
|
34
|
+
}
|
|
35
|
+
res.ct(getContentType(filePath, opts.utf8));
|
|
36
|
+
fs.createReadStream(filePath).pipe(res);
|
|
37
|
+
return true;
|
|
38
|
+
};
|
|
39
|
+
return (req, res, next) => {
|
|
40
|
+
if (req.method.toLowerCase() !== "get")
|
|
41
|
+
return next();
|
|
42
|
+
const apiPath = req.middleware.path;
|
|
43
|
+
const unsafePath = req.path.replace(apiPath, "");
|
|
44
|
+
const filePath = path.join(dirPath, path.normalize(unsafePath));
|
|
45
|
+
const resolvedPath = path.resolve(filePath);
|
|
46
|
+
const resolvedDir = path.resolve(dirPath);
|
|
47
|
+
if (!resolvedPath.startsWith(resolvedDir))
|
|
48
|
+
return next();
|
|
49
|
+
try {
|
|
50
|
+
const stats = fs.statSync(filePath);
|
|
51
|
+
if (stats.isFile()) {
|
|
52
|
+
return serveFile(req, res, filePath, stats);
|
|
53
|
+
}
|
|
54
|
+
if (stats.isDirectory()) {
|
|
55
|
+
const indexPath = path.join(filePath, "index.html");
|
|
56
|
+
try {
|
|
57
|
+
const indexStats = fs.statSync(indexPath);
|
|
58
|
+
if (indexStats.isFile()) {
|
|
59
|
+
if (!req.path.endsWith("/")) {
|
|
60
|
+
res.redirect(req.path + "/");
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return serveFile(req, res, indexPath, indexStats);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
/* index.html not found, do nothing */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
/* file/dir not found, proceed to check for .html */
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const htmlPath = filePath + ".html";
|
|
76
|
+
const htmlStats = fs.statSync(htmlPath);
|
|
77
|
+
if (htmlStats.isFile())
|
|
78
|
+
return serveFile(req, res, htmlPath, htmlStats);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
/* .html file not found, fall through to next() */
|
|
82
|
+
}
|
|
83
|
+
next();
|
|
84
|
+
};
|
|
85
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export declare class FFRequest extends http.IncomingMessage {
|
|
|
31
31
|
valid: (schema: ValidationSchema) => ValidationResult;
|
|
32
32
|
middleware: Middleware;
|
|
33
33
|
sseId?: string;
|
|
34
|
+
reRoute: (fn: (req: FFRequest) => void) => void;
|
|
35
|
+
_compression?: true;
|
|
34
36
|
}
|
|
35
37
|
export interface Middleware {
|
|
36
38
|
path: string;
|
|
@@ -80,6 +82,7 @@ export interface FFOpts {
|
|
|
80
82
|
bodyLimit?: string;
|
|
81
83
|
disableJsonParser?: boolean;
|
|
82
84
|
disableUrlencodedParser?: boolean;
|
|
85
|
+
xRequestId?: "auto" | "disable" | "manual";
|
|
83
86
|
}
|
|
84
87
|
export type FFVars = {
|
|
85
88
|
"render data": Record<string, any>;
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wxn0brp/falcon-frame",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"author": "wxn0brP",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"description": "Lightweight modular TypeScript web
|
|
9
|
+
"description": "Lightweight modular TypeScript web library",
|
|
10
10
|
"homepage": "https://github.com/wxn0brP/FalconFrame",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"keywords": [
|
|
16
16
|
"http",
|
|
17
17
|
"web",
|
|
18
|
-
"framework",
|
|
19
18
|
"typescript",
|
|
20
19
|
"modular",
|
|
21
20
|
"lightweight",
|
|
@@ -26,10 +25,10 @@
|
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@types/node": "*",
|
|
28
27
|
"tsc-alias": "*",
|
|
29
|
-
"typescript": "^
|
|
28
|
+
"typescript": "^7"
|
|
30
29
|
},
|
|
31
30
|
"dependencies": {
|
|
32
|
-
"@wxn0brp/lucerna-log": "^0.2.
|
|
31
|
+
"@wxn0brp/lucerna-log": "^0.2.4"
|
|
33
32
|
},
|
|
34
33
|
"files": [
|
|
35
34
|
"dist"
|