clear-router 2.1.12 → 2.2.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
@@ -60,15 +60,15 @@ yarn add clear-router express
60
60
 
61
61
  ### Express JS
62
62
 
63
- See the [Express JS documentation](./docs/EXPRESS.md) for details.
63
+ See the [Express JS documentation](https://arkstack-hq.github.io/clear-router/express) for details.
64
64
 
65
65
  ### H3
66
66
 
67
- See the [H3 documentation](./docs/H3.md) for details.
67
+ See the [H3 documentation](https://arkstack-hq.github.io/clear-router/h3) for details.
68
68
 
69
69
  ## API Reference
70
70
 
71
- See [API.md](./docs/API.md) for complete API documentation.
71
+ See [API.md](https://arkstack-hq.github.io/clear-router/api) for complete API documentation.
72
72
 
73
73
  ## Middleware Execution Order
74
74
 
@@ -92,7 +92,7 @@ npm run test:esm # Test ESM
92
92
  npm run test:ts # Test TypeScript
93
93
  ```
94
94
 
95
- See [TESTING.md](./docs/TESTING.md) for a detailed testing guide.
95
+ See [TESTING.md](https://arkstack-hq.github.io/clear-router/TESTING.md) for a detailed testing guide.
96
96
 
97
97
  ## Examples
98
98
 
@@ -0,0 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_router = require('../router-BNVIrTi3.cjs');
3
+
4
+ exports.CoreRouter = require_router.CoreRouter;
@@ -0,0 +1,2 @@
1
+ import { t as CoreRouter } from "../router-CZIh1ZPJ.cjs";
2
+ export { CoreRouter };
@@ -0,0 +1,2 @@
1
+ import { t as CoreRouter } from "../router-C1jVRytA.mjs";
2
+ export { CoreRouter };
@@ -0,0 +1,3 @@
1
+ import { t as CoreRouter } from "../router-BiCuy5TZ.mjs";
2
+
3
+ export { CoreRouter };
@@ -1,295 +1,141 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_Route = require('../Route-DhC4kNPX.cjs');
3
- let node_async_hooks = require("node:async_hooks");
2
+ const require_router = require('../router-BNVIrTi3.cjs');
4
3
 
5
4
  //#region src/express/router.ts
6
5
  /**
7
- * @class clear-router
6
+ * @class clear-router Express Router
8
7
  * @description Laravel-style routing system for Express.js and H3 with support for CommonJS, ESM, and TypeScript
9
8
  * @author Refkinscallv
10
9
  * @author 3m1n3nc3
11
10
  * @repository https://github.com/toneflix/clear-router
12
11
  */
13
- var Router = class Router {
14
- static config = { methodOverride: {
15
- enabled: true,
16
- bodyKeys: ["_method"],
17
- headerKeys: ["x-http-method"]
18
- } };
19
- static groupContext = new node_async_hooks.AsyncLocalStorage();
20
- /**
21
- * All registered routes
22
- */
23
- static routes = [];
24
- /**
25
- * Mapping of routes by path and method for quick lookup.
26
- */
27
- static routesByPathMethod = {};
28
- /**
29
- * Mapping of routes by method for quick lookup.
30
- */
31
- static routesByMethod = {};
32
- /**
33
- * Current route prefix
34
- */
35
- static prefix = "";
36
- /**
37
- * Group-level middlewares
38
- */
39
- static groupMiddlewares = [];
40
- /**
41
- * Global-level middlewares
42
- */
43
- static globalMiddlewares = [];
44
- /**
45
- * Normalize path by removing duplicate slashes and ensuring leading slash
46
- * @param path - Path to normalize
47
- * @returns Normalized path
48
- */
49
- static normalizePath(path) {
50
- return "/" + path.split("/").filter(Boolean).join("/");
51
- }
52
- /**
53
- * Configure router settings to modify behavior.
54
- *
55
- * @param options - Configuration options for the router
56
- * @returns
57
- */
58
- static configure(options) {
59
- if (!this.config.methodOverride) this.config.methodOverride = {
60
- enabled: true,
61
- bodyKeys: ["_method"],
62
- headerKeys: ["x-http-method"]
63
- };
64
- const override = options?.methodOverride;
65
- if (!override) return;
66
- if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
67
- const bodyKeys = override.bodyKeys;
68
- if (typeof bodyKeys !== "undefined") this.config.methodOverride.bodyKeys = (Array.isArray(bodyKeys) ? bodyKeys : [bodyKeys]).map((e) => String(e).trim()).filter(Boolean);
69
- const headerKeys = override.headerKeys;
70
- if (typeof headerKeys !== "undefined") this.config.methodOverride.headerKeys = (Array.isArray(headerKeys) ? headerKeys : [headerKeys]).map((e) => String(e).trim().toLowerCase()).filter(Boolean);
71
- }
12
+ var Router = class Router extends require_router.CoreRouter {
72
13
  static ensureRequestBodyAccessor(req) {
73
14
  if (typeof req.getBody !== "function") req.getBody = () => req.body ?? {};
74
15
  }
75
- static resolveMethodOverride(method, headers, body) {
76
- if (!this.config.methodOverride?.enabled || method.toLowerCase() !== "post") return null;
77
- let override;
78
- for (const key of this.config.methodOverride?.headerKeys || []) {
79
- const value = headers?.[key];
80
- if (Array.isArray(value) ? value[0] : value) {
81
- override = Array.isArray(value) ? value[0] : value;
82
- break;
83
- }
84
- }
85
- if (!override && body && typeof body === "object") for (const key of this.config.methodOverride?.bodyKeys || []) {
86
- const value = body[key];
87
- if (typeof value !== "undefined" && value !== null && value !== "") {
88
- override = value;
89
- break;
90
- }
91
- }
92
- const normalized = String(override || "").trim().toLowerCase();
93
- if (!normalized) return null;
94
- if ([
95
- "put",
96
- "patch",
97
- "delete",
98
- "post"
99
- ].includes(normalized)) return normalized;
100
- return null;
101
- }
102
16
  /**
103
- * Add a route with specified HTTP methods, path, handler, and middlewares
104
- * @param methods - HTTP method(s) for the route
105
- * @param path - Route path
106
- * @param handler - Route handler function or controller reference
107
- * @param middlewares - Array of middleware functions
17
+ * Adds a new route to the router with the specified HTTP methods, path, handler, and optional middlewares.
18
+ *
19
+ * @param methods
20
+ * @param path
21
+ * @param handler
22
+ * @param middlewares
108
23
  */
109
24
  static add(methods, path, handler, middlewares) {
110
- const context = this.groupContext.getStore();
111
- const activePrefix = context?.prefix ?? this.prefix;
112
- const activeGroupMiddlewares = context?.groupMiddlewares ?? this.groupMiddlewares;
113
- methods = Array.isArray(methods) ? methods : [methods];
114
- middlewares = middlewares ? Array.isArray(middlewares) ? middlewares : [middlewares] : void 0;
115
- const fullPath = this.normalizePath(`${activePrefix}/${path}`);
116
- const route = new require_Route.Route(methods.includes("options") ? methods : methods.concat("options"), fullPath, handler, [
117
- ...this.globalMiddlewares,
118
- ...activeGroupMiddlewares,
119
- ...middlewares || []
120
- ]);
121
- if (!methods.includes("options") && !this.routesByPathMethod[`OPTIONS ${fullPath}`]) this.options(path, ({ res }) => {
122
- res.set("Allow", "GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD");
123
- res.sendStatus(204);
124
- });
125
- this.routes.push(route);
126
- for (const method of methods.map((m) => m.toUpperCase())) {
127
- this.routesByPathMethod[`${method.toUpperCase()} ${fullPath}`] = route;
128
- if (!this.routesByMethod[method]) this.routesByMethod[method] = [];
129
- this.routesByMethod[method].push(route);
130
- }
25
+ super.add(methods, path, handler, middlewares);
131
26
  }
132
27
  /**
133
- * Register RESTful API resource routes for a controller with optional action filtering
28
+ * Adds a new API resource route to the router for the specified base path and controller, with
29
+ * optional configuration for included/excluded actions and middlewares.
134
30
  *
135
- * @param basePath - Base path for the resource
136
- * @param controller - Controller object containing action methods
137
- * @param options - Optional filtering options for actions
31
+ * @param basePath
32
+ * @param controller
33
+ * @param options
138
34
  */
139
35
  static apiResource(basePath, controller, options) {
140
- const actions = {
141
- index: {
142
- method: "get",
143
- path: "/"
144
- },
145
- show: {
146
- method: "get",
147
- path: "/:id"
148
- },
149
- create: {
150
- method: "post",
151
- path: "/"
152
- },
153
- update: {
154
- method: "put",
155
- path: "/:id"
156
- },
157
- destroy: {
158
- method: "delete",
159
- path: "/:id"
160
- }
161
- };
162
- const only = options?.only || Object.keys(actions);
163
- const except = options?.except || [];
164
- const preController = typeof controller === "function" ? new controller() : controller;
165
- for (const action of only) {
166
- if (except.includes(action)) continue;
167
- if (typeof preController[action] === "function") {
168
- const { method, path } = actions[action];
169
- const actionMiddlewares = typeof options?.middlewares === "object" && !Array.isArray(options.middlewares) ? options.middlewares[action] : options?.middlewares;
170
- this.add(method, `${basePath}${path}`, [controller, action], Array.isArray(actionMiddlewares) ? actionMiddlewares : actionMiddlewares ? [actionMiddlewares] : void 0);
171
- }
172
- }
36
+ super.apiResource(basePath, controller, options);
173
37
  }
174
38
  /**
175
- * Register a GET route
176
- * @param path - Route path
177
- * @param handler - Route handler
178
- * @param middlewares - Middleware functions
39
+ * Adds a new GET route to the router with the specified path, handler, and optional middlewares.
40
+ *
41
+ * @param path
42
+ * @param handler
43
+ * @param middlewares
179
44
  */
180
45
  static get(path, handler, middlewares) {
181
- this.add("get", path, handler, middlewares);
46
+ super.get(path, handler, middlewares);
182
47
  }
183
48
  /**
184
- * Register a POST route
185
- * @param path - Route path
186
- * @param handler - Route handler
187
- * @param middlewares - Middleware functions
49
+ * Adds a new POST route to the router with the specified path, handler, and optional middlewares.
50
+ *
51
+ * @param path
52
+ * @param handler
53
+ * @param middlewares
188
54
  */
189
55
  static post(path, handler, middlewares) {
190
- this.add("post", path, handler, middlewares);
56
+ super.post(path, handler, middlewares);
191
57
  }
192
58
  /**
193
- * Register a PUT route
194
- * @param path - Route path
195
- * @param handler - Route handler
196
- * @param middlewares - Middleware functions
59
+ * Adds a new PUT route to the router with the specified path, handler, and optional middlewares.
60
+ *
61
+ * @param path
62
+ * @param handler
63
+ * @param middlewares
197
64
  */
198
65
  static put(path, handler, middlewares) {
199
- this.add("put", path, handler, middlewares);
66
+ super.put(path, handler, middlewares);
200
67
  }
201
68
  /**
202
- * Register a DELETE route
203
- * @param path - Route path
204
- * @param handler - Route handler
205
- * @param middlewares - Middleware functions
69
+ * Adds a new DELETE route to the router with the specified path, handler, and optional middlewares.
70
+ *
71
+ * @param path
72
+ * @param handler
73
+ * @param middlewares
206
74
  */
207
75
  static delete(path, handler, middlewares) {
208
- this.add("delete", path, handler, middlewares);
76
+ super.delete(path, handler, middlewares);
209
77
  }
210
78
  /**
211
- * Register a PATCH route
212
- * @param path - Route path
213
- * @param handler - Route handler
214
- * @param middlewares - Middleware functions
79
+ * Adds a new PATCH route to the router with the specified path, handler, and optional middlewares.
80
+ *
81
+ * @param path
82
+ * @param handler
83
+ * @param middlewares
215
84
  */
216
85
  static patch(path, handler, middlewares) {
217
- this.add("patch", path, handler, middlewares);
86
+ super.patch(path, handler, middlewares);
218
87
  }
219
88
  /**
220
- * Register an OPTIONS route
221
- * @param path - Route path
222
- * @param handler - Route handler
223
- * @param middlewares - Middleware functions
89
+ * Adds a new OPTIONS route to the router with the specified path, handler, and optional middlewares.
90
+ *
91
+ * @param path
92
+ * @param handler
93
+ * @param middlewares
224
94
  */
225
95
  static options(path, handler, middlewares) {
226
- this.add("options", path, handler, middlewares);
96
+ super.options(path, handler, middlewares);
227
97
  }
228
98
  /**
229
- * Register a HEAD route
230
- * @param path - Route path
231
- * @param handler - Route handler
232
- * @param middlewares - Middleware functions
99
+ * Adds a new HEAD route to the router with the specified path, handler, and optional middlewares.
100
+ *
101
+ * @param path
102
+ * @param handler
103
+ * @param middlewares
233
104
  */
234
105
  static head(path, handler, middlewares) {
235
- this.add("head", path, handler, middlewares);
106
+ super.head(path, handler, middlewares);
236
107
  }
237
108
  /**
238
- * Group routes with a common prefix and middlewares
239
- * @param prefix - URL prefix for grouped routes
240
- * @param callback - Function containing route definitions
241
- * @param middlewares - Middleware functions applied to all routes in group
109
+ * Defines a group of routes with a common prefix and optional middlewares, allowing for better
110
+ * organization and reuse of route configurations.
111
+ *
112
+ * @param prefix
113
+ * @param callback
114
+ * @param middlewares
242
115
  */
243
116
  static async group(prefix, callback, middlewares) {
244
- const context = this.groupContext.getStore();
245
- const previousPrefix = context?.prefix ?? this.prefix;
246
- const previousMiddlewares = context?.groupMiddlewares ?? this.groupMiddlewares;
247
- const fullPrefix = [previousPrefix, prefix].filter(Boolean).join("/");
248
- const nextContext = {
249
- prefix: this.normalizePath(fullPrefix),
250
- groupMiddlewares: [...previousMiddlewares, ...middlewares || []]
251
- };
252
- await this.groupContext.run(nextContext, async () => {
253
- await Promise.resolve(callback());
254
- });
117
+ await super.group(prefix, callback, middlewares);
255
118
  }
256
119
  /**
257
- * Apply global middlewares for the duration of the callback
258
- * @param middlewares - Middleware functions
259
- * @param callback - Function containing route definitions
120
+ * Adds global middlewares to the router, which will be applied to all routes.
121
+ *
122
+ * @param middlewares
123
+ * @param callback
260
124
  */
261
125
  static middleware(middlewares, callback) {
262
- const prevMiddlewares = this.globalMiddlewares;
263
- this.globalMiddlewares = [...prevMiddlewares, ...middlewares || []];
264
- callback();
265
- this.globalMiddlewares = prevMiddlewares;
126
+ super.middleware(middlewares, callback);
266
127
  }
267
128
  static allRoutes(type) {
268
- if (type === "method") return this.routesByMethod;
269
- if (type === "path") return this.routesByPathMethod;
270
- return this.routes.filter((e) => e.methods.length > 1 || e.methods[0] !== "options");
129
+ return super.allRoutes(type);
271
130
  }
272
131
  static async apply(router) {
273
132
  for (const route of this.routes) {
274
133
  let handlerFunction = null;
275
134
  let instance = null;
276
135
  try {
277
- if (typeof route.handler === "function")
278
- /**
279
- * Since we do not have a controller instance, we will call the handler function directly and the route instance will be the this argument. This allows for both controller-based and function-based handlers to work seamlessly.
280
- */
281
- handlerFunction = route.handler.bind(route);
282
- else if (Array.isArray(route.handler) && route.handler.length === 2) {
283
- const [Controller, method] = route.handler;
284
- if (["function", "object"].includes(typeof Controller) && typeof Controller[method] === "function") {
285
- instance = Controller;
286
- handlerFunction = Controller[method].bind(Controller);
287
- } else if (typeof Controller === "function") {
288
- instance = new Controller();
289
- if (typeof instance[method] === "function") handlerFunction = instance[method].bind(instance);
290
- else throw new Error(`Method "${method}" not found in controller instance "${Controller.name}"`);
291
- } else throw new Error(`Invalid controller type for route: ${route.path}`);
292
- } else throw new Error(`Invalid handler format for route: ${route.path}`);
136
+ const resolved = this.resolveHandler(route);
137
+ handlerFunction = resolved.handlerFunction;
138
+ instance = resolved.instance;
293
139
  } catch (error) {
294
140
  console.error(`[ROUTES] Error setting up route ${route.path}:`, error.message);
295
141
  throw error;
@@ -311,7 +157,7 @@ var Router = class Router {
311
157
  console.error("[ROUTES]", error.message);
312
158
  throw error;
313
159
  }
314
- router[method](route.path, (req, res, next) => {
160
+ router[method](route.path, (req, _res, next) => {
315
161
  Router.ensureRequestBodyAccessor(req);
316
162
  const override = Router.resolveMethodOverride(req.method, req.headers, req.body);
317
163
  if (method === "post" && override && override !== "post") return next("route");
@@ -325,7 +171,11 @@ var Router = class Router {
325
171
  next
326
172
  };
327
173
  const inst = instance ?? route;
328
- await Router.bindRequestToInstance(ctx, inst, route);
174
+ Router.bindRequestToInstance(ctx, inst, route, {
175
+ body: ctx.req.getBody(),
176
+ query: ctx.req.query,
177
+ params: ctx.req.params
178
+ });
329
179
  const result = handlerFunction(ctx, inst.clearRequest);
330
180
  await Promise.resolve(result);
331
181
  } catch (error) {
@@ -336,7 +186,7 @@ var Router = class Router {
336
186
  "put",
337
187
  "patch",
338
188
  "delete"
339
- ].includes(method)) router.post(route.path, (req, res, next) => {
189
+ ].includes(method)) router.post(route.path, (req, _res, next) => {
340
190
  Router.ensureRequestBodyAccessor(req);
341
191
  if (Router.resolveMethodOverride(req.method, req.headers, req.body) !== method) return next("route");
342
192
  req.method = method.toUpperCase();
@@ -350,7 +200,11 @@ var Router = class Router {
350
200
  next
351
201
  };
352
202
  const inst = instance ?? route;
353
- await Router.bindRequestToInstance(ctx, inst, route);
203
+ Router.bindRequestToInstance(ctx, inst, route, {
204
+ body: ctx.req.getBody(),
205
+ query: ctx.req.query,
206
+ params: ctx.req.params
207
+ });
354
208
  const result = handlerFunction(ctx, inst.clearRequest);
355
209
  await Promise.resolve(result);
356
210
  } catch (error) {
@@ -360,21 +214,6 @@ var Router = class Router {
360
214
  }
361
215
  }
362
216
  }
363
- static async bindRequestToInstance(ctx, instance, route) {
364
- if (!instance) return;
365
- Router.ensureRequestBodyAccessor(ctx.req);
366
- instance.ctx = ctx;
367
- instance.body = ctx.req.getBody();
368
- instance.query = ctx.req.query;
369
- instance.params = ctx.req.params;
370
- instance.clearRequest = new require_Route.ClearRequest({
371
- ctx,
372
- route,
373
- body: instance.body,
374
- query: instance.query,
375
- params: instance.params
376
- });
377
- }
378
217
  };
379
218
 
380
219
  //#endregion