@wxn0brp/falcon-frame 0.8.7 → 0.9.0

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,6 +1,5 @@
1
- import { FFResponse } from "./index.js";
2
- import type { FFRequest, ParseBodyFunction, RouteHandler, StandardBodyParserOptions } from "./types.js";
1
+ import { FFResponse } from "./res.js";
2
+ import type { FFRequest } from "./types.js";
3
3
  export declare function parseLimit(limit: string | number): number;
4
4
  export declare function getContentType(req: FFRequest): string | undefined;
5
5
  export declare function getRawBody(req: FFRequest, res: FFResponse, limit: number): Promise<string>;
6
- export declare function getStandardBodyParser(type: string, parser: ParseBodyFunction, opts: StandardBodyParserOptions): RouteHandler;
@@ -46,23 +46,3 @@ export function getRawBody(req, res, limit) {
46
46
  });
47
47
  });
48
48
  }
49
- export function getStandardBodyParser(type, parser, opts) {
50
- const limit = parseLimit(opts.limit || "100k");
51
- return async (req, res, next) => {
52
- if ((typeof req.body === "object" && Object.keys(req.body).length) ||
53
- getContentType(req) !== type) {
54
- return next();
55
- }
56
- try {
57
- const body = await getRawBody(req, res, limit);
58
- req.body = await parser(body, req, res);
59
- next();
60
- }
61
- catch (err) {
62
- if (res._ended)
63
- return;
64
- req.body = {};
65
- next();
66
- }
67
- };
68
- }
package/dist/body.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- import { RouteHandler, StandardBodyParserOptions } from "./types.js";
2
- export declare function json(opts?: StandardBodyParserOptions): RouteHandler;
3
- export declare function urlencoded(opts?: StandardBodyParserOptions): RouteHandler;
1
+ import { ParseBodyFunction } from "./types.js";
2
+ export declare const json: ParseBodyFunction;
3
+ export declare const urlencoded: ParseBodyFunction;
4
+ export declare const yaml: ParseBodyFunction;
5
+ export declare const toml: ParseBodyFunction;
6
+ export declare const json5: ParseBodyFunction;
7
+ export declare const xml: ParseBodyFunction;
8
+ export declare const text: ParseBodyFunction;
package/dist/body.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import querystring from "querystring";
2
- import { getStandardBodyParser } from "./body-utils.js";
3
- export function json(opts = {}) {
4
- return getStandardBodyParser("application/json", body => JSON.parse(body), opts);
5
- }
6
- export function urlencoded(opts = {}) {
7
- return getStandardBodyParser("application/x-www-form-urlencoded", body => querystring.parse(body), opts);
8
- }
2
+ export const json = body => JSON.parse(body);
3
+ export const urlencoded = body => querystring.parse(body);
4
+ export const yaml = body => Bun.YAML.parse(body);
5
+ export const toml = body => Bun.TOML.parse(body);
6
+ export const json5 = body => Bun.JSON5.parse(body);
7
+ export const xml = body => new DOMParser().parseFromString(body, "text/xml");
8
+ export const text = body => ({
9
+ data: body,
10
+ });
package/dist/debug.js CHANGED
@@ -24,14 +24,14 @@ export function createDebug(opts = {}) {
24
24
  return isHostAllowed(req) && checkAuth(req);
25
25
  }
26
26
  const router = new Router();
27
- router.get(url, (req, res, next) => {
27
+ router.get(url, (req, res) => {
28
28
  if (!isAllowed(req))
29
- return next();
29
+ return req.FF._404(req, res);
30
30
  res.sendFile(join(import.meta.dirname, "debug.html"));
31
31
  });
32
32
  const sse = router.sse(url + "/sse", (req, res, next) => {
33
33
  if (!isAllowed(req))
34
- return req.FF._413(req, res);
34
+ return req.FF._404(req, res);
35
35
  next();
36
36
  }, () => { });
37
37
  router.use("/", (req, res, next) => {
package/dist/helpers.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { Cookies } from "./types.js";
1
+ import { Cookies, FFRequest } from "./types.js";
2
2
  export declare function parseCookies(cookieHeader: string): Cookies;
3
+ export declare function getIP(req: FFRequest): string;
3
4
  export declare function getContentType(filePath: string, utf8?: boolean): string;
4
5
  export declare const ensureLeadingDot: (str: string) => string;
package/dist/helpers.js CHANGED
@@ -8,11 +8,24 @@ export function parseCookies(cookieHeader) {
8
8
  });
9
9
  return cookies;
10
10
  }
11
+ export function getIP(req) {
12
+ const forwarded = req.headers["x-forwarded-for"];
13
+ if (forwarded) {
14
+ return (typeof forwarded === "string" ? forwarded : forwarded[0])
15
+ .split(",")[0]
16
+ .trim();
17
+ }
18
+ return req.socket.remoteAddress || "";
19
+ }
11
20
  const mimeTypes = {
12
21
  ".html": "text/html",
13
22
  ".css": "text/css",
14
23
  ".js": "application/javascript",
15
24
  ".json": "application/json",
25
+ ".json5": "application/json5",
26
+ ".yaml": "application/yaml",
27
+ ".yml": "application/yaml",
28
+ ".toml": "application/toml",
16
29
  ".png": "image/png",
17
30
  ".jpg": "image/jpeg",
18
31
  ".jpeg": "image/jpeg",
package/dist/index.d.ts CHANGED
@@ -3,10 +3,10 @@ import http from "http";
3
3
  import { renderHTML } from "./render.js";
4
4
  import { FFResponse } from "./res.js";
5
5
  import { Router } from "./router.js";
6
- import type { BeforeHandleRequest, CombinedVars, EngineCallback, ErrorHandler, FFOpts, FFRequest, RouteHandler, ValidationErrorFormatter } from "./types.js";
6
+ import type { BeforeHandleRequest, BodyParserEntry, CombinedVars, EngineCallback, ErrorHandler, FFOpts, FFRequest, ParseBodyFunction, RouteHandler, StandardBodyParserOptions, ValidationErrorFormatter } from "./types.js";
7
7
  export declare class FalconFrame<Vars extends Record<string, any> = {}> extends Router {
8
8
  logger: Logger;
9
- bodyParsers: RouteHandler[];
9
+ bodyParsers: Record<string, BodyParserEntry>;
10
10
  vars: CombinedVars<Vars>;
11
11
  opts: FFOpts;
12
12
  engines: Record<string, EngineCallback>;
@@ -15,7 +15,7 @@ export declare class FalconFrame<Vars extends Record<string, any> = {}> extends
15
15
  _413: RouteHandler;
16
16
  _500: ErrorHandler;
17
17
  constructor(opts?: Partial<FFOpts>);
18
- addBodyParser(parser: RouteHandler): this;
18
+ addBodyParser(contentType: string, parser: ParseBodyFunction, opts?: StandardBodyParserOptions): this;
19
19
  listen(port: number | string, callback?: (() => void) | boolean, beforeHandleRequest?: BeforeHandleRequest): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
20
20
  getApp(beforeHandleRequest?: BeforeHandleRequest): (req: any, res: any) => Promise<void>;
21
21
  engine(ext: string, callback: EngineCallback): this;
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Logger } from "@wxn0brp/lucerna-log";
2
2
  import http from "http";
3
- import { json, urlencoded } from "./body.js";
3
+ import * as bodyParser from "./body.js";
4
+ import { parseLimit } from "./body-utils.js";
4
5
  import { createCORS } from "./cors.js";
5
6
  import { renderHTML } from "./render.js";
6
7
  import { handleRequest } from "./req.js";
@@ -8,7 +9,7 @@ import { FFResponse } from "./res.js";
8
9
  import { Router } from "./router.js";
9
10
  export class FalconFrame extends Router {
10
11
  logger;
11
- bodyParsers = [];
12
+ bodyParsers = {};
12
13
  vars = {};
13
14
  opts = {};
14
15
  engines = {};
@@ -39,14 +40,50 @@ export class FalconFrame extends Router {
39
40
  bodyLimit: "10m",
40
41
  ...opts,
41
42
  };
42
- if (!this.opts.disableJsonParser)
43
- this.addBodyParser(json({
44
- limit: this.opts.bodyLimit,
45
- }));
46
- if (!this.opts.disableUrlencodedParser)
47
- this.addBodyParser(urlencoded({
48
- limit: this.opts.bodyLimit,
49
- }));
43
+ const dp = this.opts.disableParser || {};
44
+ const isBun = !!globalThis.Bun;
45
+ const bunOnly = new Set([
46
+ "json5",
47
+ "yaml",
48
+ "toml",
49
+ ]);
50
+ const parsers = {
51
+ json: {
52
+ fn: bodyParser.json,
53
+ ct: "application/json",
54
+ },
55
+ urlencoded: {
56
+ fn: bodyParser.urlencoded,
57
+ ct: "application/x-www-form-urlencoded",
58
+ },
59
+ json5: {
60
+ fn: bodyParser.json5,
61
+ ct: "application/json5",
62
+ },
63
+ yaml: {
64
+ fn: bodyParser.yaml,
65
+ ct: "application/yaml",
66
+ },
67
+ toml: {
68
+ fn: bodyParser.toml,
69
+ ct: "application/toml",
70
+ },
71
+ xml: {
72
+ fn: bodyParser.xml,
73
+ ct: "application/xml",
74
+ },
75
+ text: {
76
+ fn: bodyParser.text,
77
+ ct: "text/plain",
78
+ },
79
+ };
80
+ for (const [key, { fn, ct }] of Object.entries(parsers)) {
81
+ if (dp[key])
82
+ continue;
83
+ if (bunOnly.has(key) && !isBun)
84
+ continue;
85
+ this.addBodyParser(ct, fn);
86
+ }
50
87
  this.engine(".html", (path, data, callback, FF) => {
51
88
  try {
52
89
  const content = renderHTML({
@@ -61,8 +98,11 @@ export class FalconFrame extends Router {
61
98
  }
62
99
  });
63
100
  }
64
- addBodyParser(parser) {
65
- this.bodyParsers.push(parser);
101
+ addBodyParser(contentType, parser, opts = {}) {
102
+ this.bodyParsers[contentType] = {
103
+ parse: parser,
104
+ limit: parseLimit(opts.limit || this.opts.bodyLimit || "10m"),
105
+ };
66
106
  return this;
67
107
  }
68
108
  listen(port, callback, beforeHandleRequest) {
package/dist/req.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { URL } from "url";
3
- import { parseCookies } from "./helpers.js";
3
+ import { getContentType, getRawBody } from "./body-utils.js";
4
+ import { getIP, parseCookies } from "./helpers.js";
4
5
  import { getMiddlewares, matchMiddleware } from "./middleware.js";
5
6
  import { FFResponse } from "./res.js";
6
7
  import { validate } from "./valid.js";
@@ -29,12 +30,20 @@ export function handleRequest(req, res, FF, reRoute = false) {
29
30
  return;
30
31
  }
31
32
  req.cookies = parseCookies(req.headers.cookie || "");
33
+ req.ip = getIP(req);
32
34
  req.params = {};
33
- req.valid = (schema) => validate(schema, req.body);
35
+ req.valid = (schema, regexRules) => validate({
36
+ schema,
37
+ data: req.body,
38
+ regexRules,
39
+ isBodyParsed: req.isBodyParsed,
40
+ });
34
41
  req.reRoute = fn => {
35
42
  fn(req);
36
43
  handleRequest(req, res, FF, true);
37
44
  };
45
+ req.header = (name) => req.headers[name.toLowerCase()] || "";
46
+ req.isBodyParsed = false;
38
47
  if (FF.opts.xRequestId !== "disable") {
39
48
  if (req.headers["x-request-id"]) {
40
49
  req.id = req.headers["x-request-id"];
@@ -122,15 +131,29 @@ export function handleRequest(req, res, FF, reRoute = false) {
122
131
  return;
123
132
  }
124
133
  req.body = {};
125
- let bodyParserIndex = 0;
126
- function nextBodyParser() {
127
- if (bodyParserIndex >= FF.bodyParsers.length) {
128
- logger.debug("No more body parsers. Executing middlewares");
129
- return next();
130
- }
131
- logger.debug(`Executing body parser ${bodyParserIndex} of ${FF.bodyParsers.length}`);
132
- const bodyParser = FF.bodyParsers[bodyParserIndex++];
133
- bodyParser(req, res, nextBodyParser);
134
+ const ct = getContentType(req) || "application/json";
135
+ const entry = FF.bodyParsers[ct];
136
+ if (!entry) {
137
+ logger.debug("No body parser found for content-type. Executing middlewares");
138
+ next();
139
+ return;
134
140
  }
135
- nextBodyParser();
141
+ logger.debug(`Executing body parser for content-type: ${ct}`);
142
+ getRawBody(req, res, entry.limit)
143
+ .then(async (rawBody) => {
144
+ try {
145
+ req.body = (await entry.parse(rawBody, req, res)) ?? {};
146
+ req.isBodyParsed = true;
147
+ }
148
+ catch (err) {
149
+ if (!res._ended)
150
+ req.body = {};
151
+ }
152
+ next();
153
+ })
154
+ .catch(() => {
155
+ if (!res._ended)
156
+ req.body = {};
157
+ next();
158
+ });
136
159
  }
package/dist/res.d.ts CHANGED
@@ -31,6 +31,7 @@ export declare class FFResponse extends http.ServerResponse {
31
31
  * @param options The options for the cookie
32
32
  */
33
33
  cookie(name: string, value: string, options?: CookieOptions): this;
34
+ clearCookie(name: string, options?: CookieOptions): this;
34
35
  /**
35
36
  * Set the status code for the response
36
37
  * @param code The status code to set
package/dist/res.js CHANGED
@@ -44,7 +44,7 @@ export class FFResponse extends http.ServerResponse {
44
44
  */
45
45
  cookie(name, value, options = {}) {
46
46
  let cookie = `${name}=${encodeURIComponent(value)}`;
47
- if (options.maxAge)
47
+ if (options.maxAge !== undefined)
48
48
  cookie += `; Max-Age=${options.maxAge}`;
49
49
  if (options.path)
50
50
  cookie += `; Path=${options.path}`;
@@ -57,6 +57,12 @@ export class FFResponse extends http.ServerResponse {
57
57
  this.setHeader("Set-Cookie", cookie);
58
58
  return this;
59
59
  }
60
+ clearCookie(name, options = {}) {
61
+ return this.cookie(name, "", {
62
+ ...options,
63
+ maxAge: 0,
64
+ });
65
+ }
60
66
  /**
61
67
  * Set the status code for the response
62
68
  * @param code The status code to set
package/dist/types.d.ts CHANGED
@@ -17,7 +17,11 @@ export interface Query {
17
17
  export interface Body {
18
18
  [key: string]: any;
19
19
  }
20
- export type ParseBodyFunction = (body: string, req: FFRequest, res: FFResponse) => Promise<Record<string, any>>;
20
+ export type ParseBodyFunction = (body: string, req: FFRequest, res: FFResponse) => Record<string, any> | Promise<Record<string, any>>;
21
+ export interface BodyParserEntry {
22
+ parse: ParseBodyFunction;
23
+ limit: number;
24
+ }
21
25
  export interface StandardBodyParserOptions {
22
26
  limit?: string | number;
23
27
  }
@@ -28,11 +32,14 @@ export declare class FFRequest extends http.IncomingMessage {
28
32
  params: Params;
29
33
  cookies: Cookies;
30
34
  body: Body;
31
- valid: (schema: ValidationSchema) => ValidationResult;
35
+ ip: string;
36
+ header: (name: string) => string;
37
+ valid: (schema: ValidationSchema, regexRules?: Record<string, RegExp | string>) => ValidationResult;
32
38
  middleware: Middleware;
33
39
  id?: string;
34
40
  sseId?: string;
35
41
  reRoute: (fn: (req: FFRequest) => void) => void;
42
+ isBodyParsed: boolean;
36
43
  _compression?: true;
37
44
  }
38
45
  export interface Middleware {
@@ -81,8 +88,15 @@ export interface RenderOptions {
81
88
  export interface FFOpts {
82
89
  loggerOpts?: LoggerOptions;
83
90
  bodyLimit?: string;
84
- disableJsonParser?: boolean;
85
- disableUrlencodedParser?: boolean;
91
+ disableParser?: {
92
+ json?: boolean;
93
+ urlencoded?: boolean;
94
+ json5?: boolean;
95
+ yaml?: boolean;
96
+ toml?: boolean;
97
+ xml?: boolean;
98
+ text?: boolean;
99
+ };
86
100
  xRequestId?: "auto" | "disable" | "manual";
87
101
  }
88
102
  export type FFVars = {
package/dist/types.js CHANGED
@@ -6,10 +6,13 @@ export class FFRequest extends http.IncomingMessage {
6
6
  params;
7
7
  cookies;
8
8
  body;
9
+ ip;
10
+ header;
9
11
  valid;
10
12
  middleware;
11
13
  id;
12
14
  sseId;
13
15
  reRoute;
16
+ isBodyParsed;
14
17
  _compression;
15
18
  }
package/dist/valid.d.ts CHANGED
@@ -1,3 +1,9 @@
1
1
  import { RouteHandler, ValidationResult, ValidationSchema } from "./types.js";
2
- export declare function validate(schema: ValidationSchema, data: any): ValidationResult;
3
- export declare function validateBody(schema: ValidationSchema): RouteHandler;
2
+ export interface ValidateBody {
3
+ schema: ValidationSchema;
4
+ data: any;
5
+ regexRules: Record<string, RegExp | string>;
6
+ isBodyParsed: boolean;
7
+ }
8
+ export declare function validate(opts: ValidateBody): ValidationResult;
9
+ export declare function validateBody(schema: ValidationSchema, regexRules?: Record<string, RegExp | string>): RouteHandler;
package/dist/valid.js CHANGED
@@ -1,28 +1,83 @@
1
- export function validate(schema, data) {
1
+ const optionalKeys = new Set([
2
+ "nullable",
3
+ "optional",
4
+ "opt",
5
+ ]);
6
+ export function validate(opts) {
7
+ if (!opts.isBodyParsed) {
8
+ return {
9
+ valid: false,
10
+ validErrors: {
11
+ _body: [
12
+ "Request body could not be parsed. Check Content-Type header and body format.",
13
+ ],
14
+ },
15
+ };
16
+ }
17
+ const { schema, data, regexRules } = opts;
2
18
  const errors = {};
3
19
  let isValid = true;
4
20
  for (const key in schema) {
5
21
  const rules = schema[key].split("|");
6
22
  const value = data[key];
7
23
  const fieldErrors = [];
24
+ const isOptional = rules.some(r => optionalKeys.has(r));
25
+ if (isOptional && (value === null || value === undefined)) {
26
+ continue;
27
+ }
8
28
  for (const rule of rules) {
9
29
  const [ruleName, param] = rule.split(":");
10
30
  switch (ruleName) {
11
31
  case "required":
32
+ case "r":
12
33
  if (!value && value !== 0) {
13
34
  fieldErrors.push(`${key} is required`);
14
35
  }
15
36
  break;
16
37
  case "string":
38
+ case "str":
39
+ case "s":
17
40
  if (typeof value !== "string") {
18
41
  fieldErrors.push(`${key} must be a string`);
19
42
  }
20
43
  break;
21
44
  case "number":
45
+ case "num":
46
+ case "n":
22
47
  if (typeof value !== "number") {
23
48
  fieldErrors.push(`${key} must be a number`);
24
49
  }
25
50
  break;
51
+ case "integer":
52
+ case "int":
53
+ case "i":
54
+ if (!Number.isInteger(value)) {
55
+ fieldErrors.push(`${key} must be an integer`);
56
+ }
57
+ break;
58
+ case "boolean":
59
+ case "bool":
60
+ case "b":
61
+ if (typeof value !== "boolean") {
62
+ fieldErrors.push(`${key} must be a boolean`);
63
+ }
64
+ break;
65
+ case "array":
66
+ case "arr":
67
+ case "a":
68
+ if (!Array.isArray(value)) {
69
+ fieldErrors.push(`${key} must be an array`);
70
+ }
71
+ break;
72
+ case "object":
73
+ case "obj":
74
+ case "o":
75
+ if (typeof value !== "object" ||
76
+ Array.isArray(value) ||
77
+ value === null) {
78
+ fieldErrors.push(`${key} must be an object`);
79
+ }
80
+ break;
26
81
  case "min":
27
82
  if (typeof value === "string" && value.length < parseInt(param)) {
28
83
  fieldErrors.push(`${key} must be at least ${param} characters long`);
@@ -30,6 +85,9 @@ export function validate(schema, data) {
30
85
  if (typeof value === "number" && value < parseInt(param)) {
31
86
  fieldErrors.push(`${key} must be at least ${param}`);
32
87
  }
88
+ if (Array.isArray(value) && value.length < parseInt(param)) {
89
+ fieldErrors.push(`${key} must have at least ${param} items`);
90
+ }
33
91
  break;
34
92
  case "max":
35
93
  if (typeof value === "string" && value.length > parseInt(param)) {
@@ -38,7 +96,36 @@ export function validate(schema, data) {
38
96
  if (typeof value === "number" && value > parseInt(param)) {
39
97
  fieldErrors.push(`${key} must not exceed ${param}`);
40
98
  }
99
+ if (Array.isArray(value) && value.length > parseInt(param)) {
100
+ fieldErrors.push(`${key} must not exceed ${param} items`);
101
+ }
102
+ break;
103
+ case "between": {
104
+ const [min, max] = param.split(",");
105
+ if (typeof value === "number" &&
106
+ (value < parseInt(min) || value > parseInt(max))) {
107
+ fieldErrors.push(`${key} must be between ${min} and ${max}`);
108
+ }
109
+ if (typeof value === "string" &&
110
+ (value.length < parseInt(min) || value.length > parseInt(max))) {
111
+ fieldErrors.push(`${key} must be between ${min} and ${max} characters`);
112
+ }
41
113
  break;
114
+ }
115
+ case "in": {
116
+ const values = param.split(",");
117
+ if (!values.includes(String(value))) {
118
+ fieldErrors.push(`${key} must be one of: ${values.join(", ")}`);
119
+ }
120
+ break;
121
+ }
122
+ case "not_in": {
123
+ const values = param.split(",");
124
+ if (values.includes(String(value))) {
125
+ fieldErrors.push(`${key} must not be one of: ${values.join(", ")}`);
126
+ }
127
+ break;
128
+ }
42
129
  case "email": {
43
130
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
44
131
  if (!emailRegex.test(value)) {
@@ -46,6 +133,29 @@ export function validate(schema, data) {
46
133
  }
47
134
  break;
48
135
  }
136
+ case "same": {
137
+ const otherValue = data[param];
138
+ if (value !== otherValue) {
139
+ fieldErrors.push(`${key} must be the same as ${param}`);
140
+ }
141
+ break;
142
+ }
143
+ case "diff":
144
+ case "different": {
145
+ const otherValue = data[param];
146
+ if (value === otherValue) {
147
+ fieldErrors.push(`${key} must be different from ${param}`);
148
+ }
149
+ break;
150
+ }
151
+ }
152
+ }
153
+ if (regexRules && regexRules[key] !== undefined) {
154
+ const regex = regexRules[key] instanceof RegExp
155
+ ? regexRules[key]
156
+ : new RegExp(regexRules[key]);
157
+ if (!regex.test(value)) {
158
+ fieldErrors.push(`${key} format is invalid`);
49
159
  }
50
160
  }
51
161
  if (fieldErrors.length > 0) {
@@ -58,13 +168,14 @@ export function validate(schema, data) {
58
168
  validErrors: errors,
59
169
  };
60
170
  }
61
- export function validateBody(schema) {
171
+ export function validateBody(schema, regexRules) {
62
172
  return (req, res, next) => {
63
- const validationResult = req.valid(schema);
64
- if (validationResult.valid) {
65
- return next ? next() : undefined;
173
+ const validationResult = req.valid(schema, regexRules);
174
+ if (!validationResult.valid) {
175
+ const errorResponse = res.FF._400_formatter(validationResult.validErrors);
176
+ res.status(400).json(errorResponse);
177
+ return;
66
178
  }
67
- const errorResponse = res.FF._400_formatter(validationResult.validErrors);
68
- res.status(400).json(errorResponse);
179
+ next();
69
180
  };
70
181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/falcon-frame",
3
- "version": "0.8.7",
3
+ "version": "0.9.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "wxn0brP",
@@ -23,7 +23,7 @@
23
23
  "middleware-chain"
24
24
  ],
25
25
  "devDependencies": {
26
- "@types/node": "*",
26
+ "@types/bun": "*",
27
27
  "@wxn0brp/biome": "*",
28
28
  "tsc-alias": "*",
29
29
  "typescript": "^7"