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