@increase21/simplenodejs 1.1.1 → 2.0.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.
package/README.md CHANGED
@@ -97,39 +97,44 @@ Controllers are auto-loaded from `controllersDir` at startup. The file path maps
97
97
 
98
98
  ```
99
99
  controllers/
100
- users/
101
- auth.ts → /users/auth
102
- profile.ts → /users/profile
103
100
  drivers/
104
- vehicles.ts → /drivers/vehicles
105
- accountProfiles → /drivers/account-profiles
101
+ auths.ts → /users/auths
102
+
103
+ customers/
104
+ auths.ts → /customers/auths
105
+ accounts → /customers/accounts
106
106
  ```
107
107
 
108
- Controllers are plain classes — no base class required. Each method represents an endpoint and returns an array of `SimpleJsEndpointDescriptor` objects that declare which HTTP methods are supported and which handler to call.
108
+ Controllers are plain classes — no base class required. Each method represents an endpoint and returns a `SimpleJsEndpoint` (an array of `SimpleJsEndpointDescriptor` objects) that declares which HTTP methods are supported and which handler to call.
109
+
110
+ Every controller receives the request context (`SimpleJsCtx`) via its constructor and it is also available as `this.ctx` anywhere inside the class — in endpoint methods, descriptor handlers, and private helpers.
109
111
 
110
112
  ```ts
111
113
  // controllers/drivers/auths.ts
112
- import { SimpleJsCtx, SimpleJsEndpointDescriptor } from "@increase21/simplenodejs";
114
+ import { SimpleJsCtx, SimpleJsEndpoint } from "@increase21/simplenodejs";
113
115
 
114
116
  export default class AuthController {
117
+ ctx: SimpleJsCtx;
115
118
 
116
- async login(_ctx: SimpleJsCtx): Promise<SimpleJsEndpointDescriptor[]> {
117
- return [
118
- { method: "get", handler: getLogin, middleware:LoginGetMiddleware },
119
- { method: "post", handler: postLogin, middleware:LoginPostMiddleware },
120
- ];
119
+ // single HTTP method — access this.ctx directly, no descriptor needed
120
+ async login(): Promise<void> {
121
+ if (this.ctx.method !== "post") return this.ctx.res.status(405).json({ error: "Method Not Allowed" });
122
+ // handler logic...
121
123
  }
122
124
 
123
- async account(_ctx: SimpleJsCtx, id: string): Promise<SimpleJsEndpointDescriptor[]> {
125
+ // multiple HTTP methods return a SimpleJsEndpoint array
126
+ async vehicleList(id?: string): Promise<SimpleJsEndpoint> {
124
127
  return [
125
- { method: "get", id: "optional", handler: getAccount },
126
- { method: "put", id: "required", handler: updateAccount },
127
- { method: "delete", id: "required", handler: deleteAccount },
128
+ { method: "get", id: "optional", handler: getVehicles },
129
+ { method: "put", id: "required", handler: updateVehicle },
130
+ { method: "delete", id: "required", handler: deleteVehicle },
128
131
  ];
129
132
  }
130
133
  }
131
134
  ```
132
135
 
136
+ > `this.ctx` is injected automatically by the router on every request. You do not need to pass it around manually — it is always available anywhere in the class.
137
+
133
138
  ### Endpoint Naming
134
139
 
135
140
  Controller methods use **camelCase** and are exposed as **kebab-case** URLs.
@@ -145,22 +150,17 @@ Controller methods use **camelCase** and are exposed as **kebab-case** URLs.
145
150
  Declare `id` in the endpoint method signature to indicate it accepts an ID segment. Use the descriptor's `id` field to enforce whether it is required or optional at the routing level.
146
151
 
147
152
  ```ts
148
- // GET /drivers/auths/account → id is optional
149
- // GET /drivers/auths/account/123 → id = "123"
150
- // PUT /drivers/auths/account/123 → required, 404 if missing
151
- async account(_ctx: SimpleJsCtx, id?: string): Promise<SimpleJsEndpointDescriptor[]> {
152
- return [
153
- { method: "get", id: "optional", handler: getAccount },
154
- { method: "put", id: "required", handler: updateAccount },
155
- ];
156
- }
153
+ // GET /drivers/auths/vehicle-list → id is optional
154
+ // GET /drivers/auths/vehicle-list/123 → id = "123"
155
+ // PUT /drivers/auths/vehicle-list/123 → required, 404 if missing
156
+ // DELETE /drivers/auths/vehicle-list/123 → required, 404 if missing
157
157
  ```
158
158
 
159
159
  ---
160
160
 
161
161
  ## SimpleJsCtx
162
162
 
163
- The context object passed to every endpoint method and handler.
163
+ The context object passed to every endpoint method and handler. Accepts an optional generic type `T` for `customData`.
164
164
 
165
165
  | Property | Type | Description |
166
166
  |---|---|---|
@@ -168,18 +168,28 @@ The context object passed to every endpoint method and handler.
168
168
  | `res` | `ResponseObject` | Raw response object |
169
169
  | `body` | `object` | Parsed request body |
170
170
  | `query` | `object` | Parsed query string |
171
- | `customData` | `any` | Data attached by plugins/middlewares via `req._custom_data` |
171
+ | `method` | `HttpMethod` | HTTP method of the request (`"get"`, `"post"`, etc.) |
172
+ | `customData` | `T` (default `any`) | Data attached by plugins/middlewares via `req._custom_data` |
173
+
174
+ ```ts
175
+ // Typed customData
176
+ const cookies = (ctx as SimpleJsCtx<{ cookies: Record<string, string> }>).customData.cookies;
177
+ ```
178
+
179
+ ## SimpleJsEndpoint
180
+
181
+ `SimpleJsEndpoint` is the return type for controller endpoint methods. It is equivalent to `SimpleJsEndpointDescriptor[]`.
172
182
 
173
183
  ## SimpleJsEndpointDescriptor
174
184
 
175
- Returned by endpoint methods to declare HTTP method handlers.
185
+ Each object in the `SimpleJsEndpoint` array describes one HTTP verb handler.
176
186
 
177
187
  | Property | Type | Required | Description |
178
188
  |---|---|---|---|
179
189
  | `method` | `HttpMethod` | ✅ | HTTP verb: `"get"`, `"post"`, `"put"`, `"patch"`, `"delete"` |
180
190
  | `handler` | `(ctx, id?) => any` | ✅ | Method reference to call for this HTTP verb |
181
191
  | `id` | `"required" \| "optional"` | ❌ | ID routing rule. Omit if the endpoint never uses an ID |
182
- | `middleware` | `(req, res, next)` | ❌ | A function to execute before the handler is called |
192
+ | `middleware` | `Middleware[]` | ❌ | Array of middlewares to run before the handler |
183
193
 
184
194
  ---
185
195
 
@@ -189,9 +199,6 @@ Extends Node's `IncomingMessage` with additional properties.
189
199
 
190
200
  | Property | Type | Description |
191
201
  |---|---|---|
192
- | `req.url` | `string` | Full request URL |
193
- | `req.method` | `string` | HTTP method |
194
- | `req.headers` | `object` | Request headers |
195
202
  | `req.query` | `object` | Parsed query string parameters |
196
203
  | `req.body` | `any` | Parsed request body (set by `SetBodyParser`) |
197
204
  | `req.id` | `string` | Auto-generated UUID for the request (also sent as `X-Request-Id` header) |
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { CreateSimpleJsHttpServer, CreateSimpleJsHttpsServer } from "./server";
2
2
  export { SetCORS, SetHSTS, SetCSP, SetFrameGuard, SetNoSniff, SetReferrerPolicy, SetPermissionsPolicy, SetCOEP, SetCOOP, SetHelmet, SetRateLimiter, SetBodyParser, } from "./utils/simpleMiddleware";
3
3
  export * from "./utils/simplePlugins";
4
4
  export type { RequestObject, ResponseObject } from "./typings/general";
5
- export type { SimpleJsCtx, SimpleJsEndpointDescriptor, SimpleJsHttpsServer, Middleware as SimpleJsMiddleware, ErrorMiddleware as SimpleJsErrorMiddleware } from "./typings/simpletypes";
5
+ export type { SimpleJsCtx, SimpleJsEndpoint, SimpleJsHttpsServer, Middleware as SimpleJsMiddleware, ErrorMiddleware as SimpleJsErrorMiddleware } from "./typings/simpletypes";
package/dist/router.js CHANGED
@@ -23,6 +23,7 @@ async function route(req, res) {
23
23
  req, res,
24
24
  body: req.body,
25
25
  query: req.query,
26
+ method: httpMethod,
26
27
  customData: req._custom_data,
27
28
  };
28
29
  const ControllerClass = meta.Controller;
@@ -50,6 +51,8 @@ async function route(req, res) {
50
51
  if (id.length && (!controller[methodName].length || controller[methodName].length === 1)) {
51
52
  return (0, helpers_1.throwHttpError)(404, "Resource not found");
52
53
  }
54
+ //also add the context to the controller instance so that it can be accessed in the methods without passing it as a parameter
55
+ controller.ctx = ctx;
53
56
  const descriptors = await controller[methodName](ctx, ...id);
54
57
  // If the controller method has already sent a response, do not proceed
55
58
  if (res.writableEnded)
@@ -66,6 +69,13 @@ async function route(req, res) {
66
69
  return (0, helpers_1.throwHttpError)(404, "Resource not found");
67
70
  if (descriptor.id === "required" && !id.length)
68
71
  return (0, helpers_1.throwHttpError)(404, "Resource not found");
72
+ // Run endpoint-level middlewares before the handler
73
+ if (descriptor.middleware?.length) {
74
+ await (0, helpers_1.composeMiddleware)(descriptor.middleware)(req, res);
75
+ }
76
+ // If the handler has already sent a response, do not proceed
77
+ if (res.writableEnded)
78
+ return;
69
79
  // bind to controller so `this` works in regular methods too
70
80
  await descriptor.handler.bind(controller)(ctx, ...id);
71
81
  if (!res.writableEnded)
@@ -3,15 +3,15 @@ export type HttpMethod = "get" | "post" | "put" | "patch" | "delete";
3
3
  export type ObjectPayload = {
4
4
  [key: string]: any;
5
5
  };
6
- export type RequestObject = IncomingMessage & {
6
+ export interface RequestObject extends IncomingMessage {
7
7
  body?: any;
8
8
  query?: any;
9
9
  id?: string;
10
10
  _end_point_path?: string[];
11
11
  _custom_data?: ObjectPayload;
12
- };
13
- export type ResponseObject = ServerResponse & {
12
+ }
13
+ export interface ResponseObject extends ServerResponse {
14
14
  status: (value: number) => ResponseObject;
15
15
  json: (value: object) => void;
16
16
  text: (value?: string) => void;
17
- };
17
+ }
@@ -39,15 +39,18 @@ export interface SimpleJsHttpsServer extends https.Server {
39
39
  useError: (mw: ErrorMiddleware) => void;
40
40
  registerPlugin: (plugin: Plugin) => Promise<any> | void;
41
41
  }
42
- export interface SimpleJsCtx {
42
+ export interface SimpleJsCtx<T = any> {
43
43
  body: ObjectPayload;
44
44
  res: ResponseObject;
45
45
  req: RequestObject;
46
46
  query: ObjectPayload;
47
- customData: any;
47
+ method: HttpMethod;
48
+ customData: T;
48
49
  }
49
50
  export interface SimpleJsEndpointDescriptor {
50
51
  method: HttpMethod;
51
52
  id?: "required" | "optional";
53
+ middleware?: Middleware[];
52
54
  handler: (ctx: SimpleJsCtx, id?: string) => any;
53
55
  }
56
+ export type SimpleJsEndpoint = SimpleJsEndpointDescriptor[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@increase21/simplenodejs",
3
- "version": "1.1.1",
3
+ "version": "2.0.0",
4
4
  "description": "Lightweight Node.js HTTP framework with middlewares and plugins",
5
5
  "dev": "dist/index.js",
6
6
  "bugs": "https://github.com/increase21/simplenodejs/issues",
@@ -40,4 +40,4 @@
40
40
  "devDependencies": {
41
41
  "typescript": "^5.3.0"
42
42
  }
43
- }
43
+ }