Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Commit

Permalink
Patch and Fix
Browse files Browse the repository at this point in the history
Signed-off-by: GitHub <[email protected]>
  • Loading branch information
Sirherobrine23 authored Oct 27, 2023
1 parent 2ba7b9f commit e2a32c2
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 24 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,42 @@ app.listen(3000, () => {
});
```

### Example

#### Standalone Nodejs

```js
import neste from "neste";
const app = neste();

app.get("/", (req, res) => res.set("Content-Type", "text/html").send("<p>Hello world</p>"));

const PORT = Number(process.env.PORT || 3000);
app.listen(PORT, () => console.log("Listen on %s", PORT));
```

#### Next.js API Routes

- path: `/[...root].ts`

```js
import { Router } from "Neste";
const app = new Router();
export default app;

app.get("/", (req, res) => res.send(`<p>Hello from root API</p>`));
```

- path: `/form/[...formsSlugs].ts`

```js
import { Router } from "Neste";
const app = new Router({ "app path": "/form" });
export default app;

app.get("/", (req, res) => res.send(`<p>Hello from forms router</p>`));
```

## 3.x notice

version 3.0.0 is removing support for CommonJS, keeping only the ESM module. if you app/module is Commonjs module migrate to ESM or keep on ExpressJS.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"license": "MIT",
"type": "module",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/Sirherobrine23/neste.git"
Expand All @@ -16,7 +17,6 @@
"keywords": [
"express",
"framework",
"sinatra",
"web",
"http",
"rest",
Expand All @@ -35,7 +35,7 @@
"devDependencies": {
"@types/busboy": "^1.5.2",
"@types/cookie": "^0.5.3",
"@types/node": "^20.8.8",
"@types/node": "^20.8.9",
"@types/ws": "^8.5.8",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
Expand Down
13 changes: 13 additions & 0 deletions src/app.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { tmpdir } from "os";
import neste, { parseBody } from "./index.js";
const app = neste(), app2 = neste();

app.use(parseBody({ formData: { tmpFolder: tmpdir() }, formEncoded: { limit: -1 } }));

app.all("/", ({ path, reqPath, hostname, app, body }, res) => res.json({ path, reqPath, hostname, sets: Array.from(app.settings.entries()), body }));

app.use(app2).use("/gg", app2);
app2.settings.set("json space", 4);
app2.get("/gg", ({ path, reqPath, hostname, app, body }, res) => res.json({ path, reqPath, hostname, sets: Array.from(app.settings.entries()), body }));

app.listen(3000, () => console.log("Listen on %s", 3000));
41 changes: 36 additions & 5 deletions src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import path from "path";
import { parse } from "url";
import util from "util";
import { WebSocket, WebSocketServer } from "ws";
import { ErrorRequestHandler, Handlers, Layer, NextFunction, RequestHandler, WsRequestHandler, assignRequest, assignResponse, assignWsResponse } from "./handler.js";
import { ErrorRequestHandler, Handlers, Layer, NextFunction, RequestHandler, WsRequestHandler, WsResponse, assignRequest, assignResponse, assignWsResponse } from "./handler.js";
import { Methods, methods } from "./util.js";

export type RouterSettingsConfig = Record<string, any>;
Expand Down Expand Up @@ -32,22 +32,44 @@ export interface Router {
options(path: string|RegExp, ...fn: RequestHandler[]): this;
}

export class WsRoom extends Map<string, WsResponse[]> {
/**
* Send data to all connections
* @param room - room name
* @param data - Data
*/
async send(room: string, data: string|Buffer|ArrayBuffer) {
if (!(super.has(room))) return;
await Promise.all(super.get(room).filter(s => !(s.CLOSED||s.CLOSING)).map(s => new Promise<void>((done, reject) => s.send(data, err => err ? reject(err) : done()))));
}

/**
* Close connections and delete room
* @param room - room name
*/
close(room: string, code?: number) {
if (!(super.has(room))) return;
super.get(room).forEach(s => s.close(code));
super.delete(room);
}
}

export class Router extends Function {
constructor(routeOpts?: RouterSettingsConfig) {
super("if (typeof this.handler === 'function') { this.handler.apply(this, arguments); } else if (typeof arguments.callee === 'function') { arguments.callee.apply(arguments.callee, arguments); } else { throw new Error('Cannot get Router class'); }");
this.settings = new RouterSettings(routeOpts);
this.settings.set("env", process.env.NODE_ENV || "development");
this.settings.set("path resolve", true).set("json space", 2);
this.settings.set("env", process.env.NODE_ENV || "development").set("path resolve", true).set("json space", 2);
this.settings.set("json replacer", (_key: string, value: any) => {
if (value instanceof BigInt || typeof value === "bigint") return { type: "bigint", value: value.toString() };
// else if (!(Array.isArray(value)) && value[Symbol.iterator]) return Array.from(value);
else if (value && typeof value.toJSON === "function") return value.toJSON();
return value;
});
}

layers: Layer[] = [];
wsRooms: Map<string, WsRequestHandler[]> = new Map();
settings: RouterSettings;
wsRooms: WsRoom = new WsRoom();

handler(req: IncomingMessage, res: WebSocket|ServerResponse, next?: NextFunction) {
if (typeof next !== "function") next = (err?: any) => {
Expand Down Expand Up @@ -92,7 +114,7 @@ export class Router extends Function {
} else {
if (res instanceof WebSocket) {
const fn = layer.handler as WsRequestHandler;
await fn(assignRequest(this, req, method, Object.assign({}, saveParms, layerMatch.params)), assignWsResponse(res), nextHandler);
await fn(assignRequest(this, req, method, Object.assign({}, saveParms, layerMatch.params)), assignWsResponse(this, res), nextHandler);
} else {
const fn = layer.handler as RequestHandler;
await fn(assignRequest(this, req, method, Object.assign({}, saveParms, layerMatch.params)), assignResponse(this, res), nextHandler);
Expand All @@ -119,6 +141,15 @@ export class Router extends Function {
return this;
}

all(path: string|RegExp, ...handlers: RequestHandler[]) {
if (!(path instanceof RegExp || typeof path === "string" && path.trim())) throw new Error("Set path");
for (const fn of handlers) {
const layerHand = new Layer(path, fn);
this.layers.push(layerHand);
}
return this;
}

__method(method: Methods, path: string|RegExp, ...handlers: RequestHandler[]) {
if (!(path instanceof RegExp || typeof path === "string" && path.trim())) throw new Error("Set path");
for (const fn of handlers) {
Expand Down
32 changes: 22 additions & 10 deletions src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,24 @@ export class Response {
}
};

export interface WsResponse extends WebSocket {}
export class WsResponse {};
export interface WsResponse extends WebSocket {
app: Router;
}

export class WsResponse {
join(room: string) {
if (!(this.app.wsRooms.has(room))) this.app.wsRooms.set(room, []);
this.app.wsRooms.get(room).push(this);
this.once("close", () => this.app.wsRooms.set(room, this.app.wsRooms.get(room).filter(s => s !== this)));
return this;
}

left(room: string) {
if (!(this.app.wsRooms.has(room))) throw new TypeError("Room no exists in current Router!");
this.app.wsRooms.set(room, this.app.wsRooms.get(room).filter(s => s !== this));
return this;
}
};

export interface NextFunction {
/**
Expand Down Expand Up @@ -436,15 +452,13 @@ export class Layer {
}

export function assignRequest(app: Router, req: IncomingMessage, method: string, params: Record<string, string>): Request {
if (req["__Neste"]) return req as any;
const parseQuery = new URLSearchParams(parse(req.url).query);
mixin(req, Request.prototype, false);
mixin(req, { app, params }, true);
defineProperties(req, {
app: { writable: true, configurable: true, enumerable: true, value: app },
method: { writable: true, configurable: true, enumerable: true, value: method },
Cookies: { writable: true, configurable: true, enumerable: true, value: new CookieManeger((req.headers||{}).cookie||"") },
query: { writable: true, configurable: true, enumerable: true, value: Object.assign(Array.from(parseQuery.keys()).reduce<Record<string, string>>((acc, key) => { acc[key] = parseQuery.get(key); return acc; }, {}), req["query"]) },
params: { writable: true, configurable: true, enumerable: true, value: params },
protocol: {
configurable: true,
enumerable: true,
Expand Down Expand Up @@ -512,15 +526,13 @@ export function assignRequest(app: Router, req: IncomingMessage, method: string,
}

export function assignResponse(app: Router, res: ServerResponse): Response {
if (res["__Neste"]) return res as any;
mixin(res, Response.prototype, false);
defineProperties(res, {
app: { writable: true, configurable: true, enumerable: true, value: app }
});
mixin(res, { app }, true);
return res as any;
}

export function assignWsResponse(res: WebSocket): WsResponse {
export function assignWsResponse(app: Router, res: WebSocket): WsResponse {
mixin(res, WsResponse.prototype, false);
mixin(res, { app }, true);
return res as any;
}
13 changes: 10 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { CookieManeger, Handlers, ErrorRequestHandler, RequestHandler, WsRequestHandler, Layer, NextFunction, Request, Response, WsResponse } from "./handler.js";
import { Neste, Router, RouterSettings, RouterSettingsConfig } from "./application.js";
import { CookieManeger, Layer, Request, Response, WsResponse } from "./handler.js";
import { Neste, Router, RouterSettings, WsRoom } from "./application.js";

export { staticFile } from "./middles/staticFile.js";
export { parseBody } from "./middles/bodyParse.js";
export type { FileStorage, LocalFile, ParseBodyOptions } from "./middles/bodyParse.js";

export type { Handlers, ErrorRequestHandler, RequestHandler, WsRequestHandler, NextFunction } from "./handler.js";
export type { RouterSettingsConfig } from "./application.js";

function router() { return new Router(); }
function neste() { return new Neste(); }
export { neste, router, CookieManeger, Handlers, ErrorRequestHandler, RequestHandler, WsRequestHandler, Layer, NextFunction, Request, Response, WsResponse, Neste, Router, RouterSettings, RouterSettingsConfig };
export { neste, router, CookieManeger, Layer, Request, Response, WsResponse, Neste, Router, RouterSettings, WsRoom };
export default neste;
2 changes: 1 addition & 1 deletion src/middles/staticFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { RequestHandler } from "../handler.js";

export function staticFile(folderPath: string): RequestHandler {
folderPath = path.resolve(process.cwd(), folderPath);
if (!(fs.existsSync(folderPath))) throw new Error("Set valid foldwr");
if (!(fs.existsSync(folderPath))) throw new Error("Set valid folder");
return (req, res, next) => {
if (req.method.toLowerCase() !== "get") return next();
const localFile = path.join(folderPath, req.path.substring(1));
Expand Down
6 changes: 4 additions & 2 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export function mixin<T, C>(dest: T, src: C, redefine?: boolean): T & C {
return dest as any;
}

export function defineProperties(obj: any, config: Record<string, PropertyDescriptor & ThisType<any>>) {
export function defineProperties(obj: any, config: Record<string, PropertyDescriptor & ThisType<any>>, redefine?: boolean) {
if (redefine === undefined) redefine = true; // Default to true
for (let key in config) {
if (config[key].value !== undefined) obj[key] = config[key].value;
// Skip desriptor
if (!redefine && Object.hasOwnProperty.call(obj, key)) continue;
else Object.defineProperty(obj, key, config[key]);
}
return obj;
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"declaration": true,
"strict": false,
"noUnusedLocals": true,
"isolatedModules": false,
"isolatedModules": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
Expand Down

0 comments on commit e2a32c2

Please sign in to comment.