clear-router 2.8.9 → 2.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.
Files changed (42) hide show
  1. package/dist/Route.cjs +200 -12
  2. package/dist/Route.d.cts +125 -1
  3. package/dist/Route.d.mts +125 -1
  4. package/dist/Route.mjs +199 -12
  5. package/dist/RouteGroup.cjs +1 -0
  6. package/dist/RouteGroup.mjs +1 -0
  7. package/dist/RouteRegistrar.cjs +68 -0
  8. package/dist/RouteRegistrar.d.cts +62 -0
  9. package/dist/RouteRegistrar.d.mts +62 -0
  10. package/dist/RouteRegistrar.mjs +67 -0
  11. package/dist/core/CoreRouter.cjs +307 -0
  12. package/dist/core/CoreRouter.d.cts +168 -0
  13. package/dist/core/CoreRouter.d.mts +168 -0
  14. package/dist/core/CoreRouter.mjs +307 -0
  15. package/dist/decorators/setup.d.mts +0 -1
  16. package/dist/express/router.cjs +13 -4
  17. package/dist/express/router.d.cts +1 -0
  18. package/dist/express/router.d.mts +1 -0
  19. package/dist/express/router.mjs +13 -4
  20. package/dist/fastify/router.cjs +13 -4
  21. package/dist/fastify/router.d.cts +1 -0
  22. package/dist/fastify/router.d.mts +1 -0
  23. package/dist/fastify/router.mjs +13 -4
  24. package/dist/h3/router.cjs +13 -4
  25. package/dist/h3/router.d.cts +1 -0
  26. package/dist/h3/router.d.mts +1 -0
  27. package/dist/h3/router.mjs +13 -4
  28. package/dist/hono/router.cjs +11 -4
  29. package/dist/hono/router.d.cts +1 -0
  30. package/dist/hono/router.d.mts +1 -0
  31. package/dist/hono/router.mjs +11 -4
  32. package/dist/index.cjs +3 -0
  33. package/dist/index.d.cts +3 -2
  34. package/dist/index.d.mts +3 -3
  35. package/dist/index.mjs +3 -2
  36. package/dist/koa/router.cjs +13 -4
  37. package/dist/koa/router.d.cts +1 -0
  38. package/dist/koa/router.d.mts +1 -0
  39. package/dist/koa/router.mjs +13 -4
  40. package/dist/types/basic.d.cts +2 -0
  41. package/dist/types/basic.d.mts +2 -0
  42. package/package.json +1 -1
package/dist/Route.cjs CHANGED
@@ -1,12 +1,40 @@
1
1
 
2
2
  //#region src/Route.ts
3
3
  /**
4
+ * Parse the placeholder parameters declared in a domain/host pattern such as
5
+ * `{account}.example.com`. Mirrors the path parameter syntax (supporting the
6
+ * optional `{name?}` form) so domain parameters feel consistent with path ones.
7
+ *
8
+ * @param pattern
9
+ * @returns
10
+ */
11
+ const parseDomainParameters = (pattern) => {
12
+ if (!pattern) return [];
13
+ const parameters = [];
14
+ const seen = /* @__PURE__ */ new Set();
15
+ const matcher = /\{([^{}]+)\}/g;
16
+ let match;
17
+ while ((match = matcher.exec(pattern)) !== null) {
18
+ const raw = match[1].trim();
19
+ const optional = raw.endsWith("?");
20
+ const [name, field] = (optional ? raw.slice(0, -1) : raw).split(":", 2).map((part) => part.trim());
21
+ if (!name || seen.has(name)) continue;
22
+ seen.add(name);
23
+ parameters.push({
24
+ name,
25
+ field: field || void 0,
26
+ optional
27
+ });
28
+ }
29
+ return parameters;
30
+ };
31
+ /**
4
32
  * @class clear-router Route
5
33
  * @description A route describes a single enpoint on clear-router
6
34
  * @author 3m1n3nc3
7
35
  * @repository https://github.com/arkstack-hq/clear-router
8
36
  */
9
- var Route = class {
37
+ var Route = class Route {
10
38
  ctx;
11
39
  body = {};
12
40
  query = {};
@@ -23,6 +51,9 @@ var Route = class {
23
51
  actionName;
24
52
  handlerType;
25
53
  middlewareCount;
54
+ domainPattern;
55
+ domainParameters;
56
+ constraints = {};
26
57
  constructor(methods, path, handler, middlewares = [], options = {}) {
27
58
  this.methods = methods;
28
59
  this.path = path;
@@ -34,16 +65,65 @@ var Route = class {
34
65
  this.middlewareCount = middlewares.length;
35
66
  this.controllerName = Array.isArray(handler) ? handler[0]?.name : void 0;
36
67
  this.actionName = Array.isArray(handler) ? handler[1] : typeof handler === "function" ? handler.constructor.name ?? handler.name : void 0;
68
+ this.domainPattern = options.domain;
69
+ this.domainParameters = parseDomainParameters(options.domain);
37
70
  this.onName = options.onName;
38
71
  this.normalizeMiddleware = options.normalizeMiddleware;
39
72
  }
40
73
  onName;
41
74
  normalizeMiddleware;
75
+ static currentResolvers;
76
+ /**
77
+ * Wire the resolvers used by the static `current*` accessors. Called once by
78
+ * `CoreRouter` so `Route.current()` reflects the active request.
79
+ *
80
+ * @internal
81
+ * @param resolvers
82
+ */
83
+ static bindCurrentResolvers(resolvers) {
84
+ Route.currentResolvers = resolvers;
85
+ }
86
+ /**
87
+ * Get the route currently being dispatched, if any.
88
+ *
89
+ * @returns
90
+ */
91
+ static current() {
92
+ return Route.currentResolvers?.current();
93
+ }
94
+ /**
95
+ * Get the name of the route currently being dispatched.
96
+ *
97
+ * @returns
98
+ */
99
+ static currentRouteName() {
100
+ return Route.currentResolvers?.currentRouteName() ?? "";
101
+ }
102
+ /**
103
+ * Get the action (controller@method or `Closure`) of the route currently
104
+ * being dispatched.
105
+ *
106
+ * @returns
107
+ */
108
+ static currentRouteAction() {
109
+ return Route.currentResolvers?.currentRouteAction() ?? "";
110
+ }
111
+ /**
112
+ * The route action expressed as `Controller@method` for controller routes or
113
+ * `Closure` for callback routes.
114
+ */
115
+ get action() {
116
+ if (this.handlerType === "controller") {
117
+ const method = String(this.actionName ?? "");
118
+ return this.controllerName ? `${this.controllerName}@${method}` : method;
119
+ }
120
+ return "Closure";
121
+ }
42
122
  /**
43
123
  * Set the route name
44
- *
45
- * @param name
46
- * @returns
124
+ *
125
+ * @param name
126
+ * @returns
47
127
  */
48
128
  name(name) {
49
129
  const previousName = this.routeName;
@@ -52,10 +132,96 @@ var Route = class {
52
132
  return this;
53
133
  }
54
134
  /**
135
+ * Constrain the route to a host pattern such as `{account}.example.com`.
136
+ * Any `{placeholder}` segments are exposed as route parameters once matched.
137
+ *
138
+ * @param pattern
139
+ * @returns
140
+ */
141
+ domain(pattern) {
142
+ this.domainPattern = pattern;
143
+ this.domainParameters = parseDomainParameters(pattern);
144
+ return this;
145
+ }
146
+ /**
147
+ * Constrain one or more route parameters with a regular expression. Accepts
148
+ * either `where(name, pattern)` or `where({ name: pattern, ... })`.
149
+ *
150
+ * @param name
151
+ * @param pattern
152
+ * @returns
153
+ */
154
+ where(name, pattern) {
155
+ if (typeof name === "object") Object.assign(this.constraints, name);
156
+ else if (typeof pattern !== "undefined") this.constraints[name] = pattern;
157
+ return this;
158
+ }
159
+ /**
160
+ * Constrain the given parameters to numeric values.
161
+ *
162
+ * @param names
163
+ * @returns
164
+ */
165
+ whereNumber(...names) {
166
+ return this.applyConstraint(names, "[0-9]+");
167
+ }
168
+ /**
169
+ * Constrain the given parameters to alphabetic values.
170
+ *
171
+ * @param names
172
+ * @returns
173
+ */
174
+ whereAlpha(...names) {
175
+ return this.applyConstraint(names, "[a-zA-Z]+");
176
+ }
177
+ /**
178
+ * Constrain the given parameters to alphanumeric values.
179
+ *
180
+ * @param names
181
+ * @returns
182
+ */
183
+ whereAlphaNumeric(...names) {
184
+ return this.applyConstraint(names, "[a-zA-Z0-9]+");
185
+ }
186
+ /**
187
+ * Constrain the given parameters to UUID values.
188
+ *
189
+ * @param names
190
+ * @returns
191
+ */
192
+ whereUuid(...names) {
193
+ return this.applyConstraint(names, "[\\da-fA-F]{8}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{12}");
194
+ }
195
+ /**
196
+ * Constrain the given parameters to ULID values.
197
+ *
198
+ * @param names
199
+ * @returns
200
+ */
201
+ whereUlid(...names) {
202
+ return this.applyConstraint(names, "[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}");
203
+ }
204
+ /**
205
+ * Constrain a parameter to one of the given values.
206
+ *
207
+ * @param name
208
+ * @param values
209
+ * @returns
210
+ */
211
+ whereIn(name, values) {
212
+ const escaped = values.map((value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, (match) => `\\${match}`));
213
+ this.constraints[name] = escaped.join("|");
214
+ return this;
215
+ }
216
+ applyConstraint(names, pattern) {
217
+ for (const name of names) this.constraints[name] = pattern;
218
+ return this;
219
+ }
220
+ /**
55
221
  * Register one or more middleware that will be executed before the route.
56
- *
57
- * @param middlewares
58
- * @returns
222
+ *
223
+ * @param middlewares
224
+ * @returns
59
225
  */
60
226
  middleware(middlewares) {
61
227
  const normalized = (Array.isArray(middlewares) ? middlewares : [middlewares]).map((middleware) => this.normalizeMiddleware?.(middleware) ?? middleware);
@@ -64,13 +230,32 @@ var Route = class {
64
230
  return this;
65
231
  }
66
232
  /**
233
+ * Resolve the route's domain pattern into a concrete host using the given
234
+ * parameters.
235
+ *
236
+ * @param params
237
+ * @returns
238
+ */
239
+ resolveDomainHost(params) {
240
+ return this.domainPattern.replace(/\{([^{}]+)\}/g, (_, raw) => {
241
+ const optional = raw.endsWith("?");
242
+ const name = (optional ? raw.slice(0, -1) : raw).split(":", 2)[0].trim();
243
+ const value = params[name];
244
+ if (typeof value === "undefined" || value === null || value === "") {
245
+ if (optional) return "";
246
+ throw new Error(`Missing required route domain parameter: ${name}`);
247
+ }
248
+ return encodeURIComponent(String(value));
249
+ });
250
+ }
251
+ /**
67
252
  * Get the path generated and accessible by this route
68
- *
69
- * @param params
70
- * @returns
253
+ *
254
+ * @param params
255
+ * @returns
71
256
  */
72
257
  toPath(params = {}) {
73
- return this.path.replace(/\/?\{([^{}]+)\}/g, (segment, raw) => {
258
+ const resolved = this.path.replace(/\/?\{([^{}]+)\}/g, (segment, raw) => {
74
259
  const optional = raw.endsWith("?");
75
260
  const [rawName, rawField] = (optional ? raw.slice(0, -1) : raw).split(":", 2);
76
261
  const name = rawName.trim();
@@ -83,8 +268,11 @@ var Route = class {
83
268
  }
84
269
  return `${segment.startsWith("/") ? "/" : ""}${encodeURIComponent(String(resolved))}`;
85
270
  }) || "/";
271
+ if (!this.domainPattern) return resolved;
272
+ return `//${this.resolveDomainHost(params)}${resolved}`;
86
273
  }
87
274
  };
88
275
 
89
276
  //#endregion
90
- exports.Route = Route;
277
+ exports.Route = Route;
278
+ exports.parseDomainParameters = parseDomainParameters;
package/dist/Route.d.cts CHANGED
@@ -5,6 +5,24 @@ import { ClearRequest } from "./ClearRequest.cjs";
5
5
  import { HttpMethod, RequestData } from "./types/basic.cjs";
6
6
 
7
7
  //#region src/Route.d.ts
8
+ /**
9
+ * Parse the placeholder parameters declared in a domain/host pattern such as
10
+ * `{account}.example.com`. Mirrors the path parameter syntax (supporting the
11
+ * optional `{name?}` form) so domain parameters feel consistent with path ones.
12
+ *
13
+ * @param pattern
14
+ * @returns
15
+ */
16
+ declare const parseDomainParameters: (pattern?: string) => RouteParameter[];
17
+ /**
18
+ * Resolvers wired up by `CoreRouter` so the `Route` facade can expose the
19
+ * currently dispatching route without depending on the router directly.
20
+ */
21
+ interface CurrentRouteResolvers {
22
+ current: () => Route<any, any, any> | undefined;
23
+ currentRouteName: () => string;
24
+ currentRouteAction: () => string;
25
+ }
8
26
  /**
9
27
  * @class clear-router Route
10
28
  * @description A route describes a single enpoint on clear-router
@@ -28,14 +46,51 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
28
46
  actionName?: string;
29
47
  handlerType: 'function' | 'controller';
30
48
  middlewareCount: number;
49
+ domainPattern?: string;
50
+ domainParameters: RouteParameter[];
51
+ constraints: Record<string, string | RegExp>;
31
52
  constructor(methods: HttpMethod[], path: string, handler: H, middlewares?: M[], options?: {
32
53
  registrationPaths?: string[];
33
54
  parameters?: RouteParameter[];
55
+ domain?: string;
34
56
  onName?: (name: string, route: Route<X, M, H>, previousName?: string) => void;
35
57
  normalizeMiddleware?: (middleware: M) => M;
36
58
  });
37
59
  private onName?;
38
60
  private normalizeMiddleware?;
61
+ private static currentResolvers?;
62
+ /**
63
+ * Wire the resolvers used by the static `current*` accessors. Called once by
64
+ * `CoreRouter` so `Route.current()` reflects the active request.
65
+ *
66
+ * @internal
67
+ * @param resolvers
68
+ */
69
+ static bindCurrentResolvers(resolvers: CurrentRouteResolvers): void;
70
+ /**
71
+ * Get the route currently being dispatched, if any.
72
+ *
73
+ * @returns
74
+ */
75
+ static current(): Route<any, any, any> | undefined;
76
+ /**
77
+ * Get the name of the route currently being dispatched.
78
+ *
79
+ * @returns
80
+ */
81
+ static currentRouteName(): string;
82
+ /**
83
+ * Get the action (controller@method or `Closure`) of the route currently
84
+ * being dispatched.
85
+ *
86
+ * @returns
87
+ */
88
+ static currentRouteAction(): string;
89
+ /**
90
+ * The route action expressed as `Controller@method` for controller routes or
91
+ * `Closure` for callback routes.
92
+ */
93
+ get action(): string;
39
94
  /**
40
95
  * Set the route name
41
96
  *
@@ -43,6 +98,67 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
43
98
  * @returns
44
99
  */
45
100
  name(name: string): this;
101
+ /**
102
+ * Constrain the route to a host pattern such as `{account}.example.com`.
103
+ * Any `{placeholder}` segments are exposed as route parameters once matched.
104
+ *
105
+ * @param pattern
106
+ * @returns
107
+ */
108
+ domain(pattern: string): this;
109
+ /**
110
+ * Constrain one or more route parameters with a regular expression. Accepts
111
+ * either `where(name, pattern)` or `where({ name: pattern, ... })`.
112
+ *
113
+ * @param name
114
+ * @param pattern
115
+ * @returns
116
+ */
117
+ where(name: string | Record<string, string | RegExp>, pattern?: string | RegExp): this;
118
+ /**
119
+ * Constrain the given parameters to numeric values.
120
+ *
121
+ * @param names
122
+ * @returns
123
+ */
124
+ whereNumber(...names: string[]): this;
125
+ /**
126
+ * Constrain the given parameters to alphabetic values.
127
+ *
128
+ * @param names
129
+ * @returns
130
+ */
131
+ whereAlpha(...names: string[]): this;
132
+ /**
133
+ * Constrain the given parameters to alphanumeric values.
134
+ *
135
+ * @param names
136
+ * @returns
137
+ */
138
+ whereAlphaNumeric(...names: string[]): this;
139
+ /**
140
+ * Constrain the given parameters to UUID values.
141
+ *
142
+ * @param names
143
+ * @returns
144
+ */
145
+ whereUuid(...names: string[]): this;
146
+ /**
147
+ * Constrain the given parameters to ULID values.
148
+ *
149
+ * @param names
150
+ * @returns
151
+ */
152
+ whereUlid(...names: string[]): this;
153
+ /**
154
+ * Constrain a parameter to one of the given values.
155
+ *
156
+ * @param name
157
+ * @param values
158
+ * @returns
159
+ */
160
+ whereIn(name: string, values: Array<string | number>): this;
161
+ private applyConstraint;
46
162
  /**
47
163
  * Register one or more middleware that will be executed before the route.
48
164
  *
@@ -50,6 +166,14 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
50
166
  * @returns
51
167
  */
52
168
  middleware(middlewares: M[] | M): this;
169
+ /**
170
+ * Resolve the route's domain pattern into a concrete host using the given
171
+ * parameters.
172
+ *
173
+ * @param params
174
+ * @returns
175
+ */
176
+ private resolveDomainHost;
53
177
  /**
54
178
  * Get the path generated and accessible by this route
55
179
  *
@@ -59,4 +183,4 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
59
183
  toPath(params?: RequestData): string;
60
184
  }
61
185
  //#endregion
62
- export { Route };
186
+ export { Route, parseDomainParameters };
package/dist/Route.d.mts CHANGED
@@ -5,6 +5,24 @@ import { ClearRequest } from "./ClearRequest.mjs";
5
5
  import { HttpMethod, RequestData } from "./types/basic.mjs";
6
6
 
7
7
  //#region src/Route.d.ts
8
+ /**
9
+ * Parse the placeholder parameters declared in a domain/host pattern such as
10
+ * `{account}.example.com`. Mirrors the path parameter syntax (supporting the
11
+ * optional `{name?}` form) so domain parameters feel consistent with path ones.
12
+ *
13
+ * @param pattern
14
+ * @returns
15
+ */
16
+ declare const parseDomainParameters: (pattern?: string) => RouteParameter[];
17
+ /**
18
+ * Resolvers wired up by `CoreRouter` so the `Route` facade can expose the
19
+ * currently dispatching route without depending on the router directly.
20
+ */
21
+ interface CurrentRouteResolvers {
22
+ current: () => Route<any, any, any> | undefined;
23
+ currentRouteName: () => string;
24
+ currentRouteAction: () => string;
25
+ }
8
26
  /**
9
27
  * @class clear-router Route
10
28
  * @description A route describes a single enpoint on clear-router
@@ -28,14 +46,51 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
28
46
  actionName?: string;
29
47
  handlerType: 'function' | 'controller';
30
48
  middlewareCount: number;
49
+ domainPattern?: string;
50
+ domainParameters: RouteParameter[];
51
+ constraints: Record<string, string | RegExp>;
31
52
  constructor(methods: HttpMethod[], path: string, handler: H, middlewares?: M[], options?: {
32
53
  registrationPaths?: string[];
33
54
  parameters?: RouteParameter[];
55
+ domain?: string;
34
56
  onName?: (name: string, route: Route<X, M, H>, previousName?: string) => void;
35
57
  normalizeMiddleware?: (middleware: M) => M;
36
58
  });
37
59
  private onName?;
38
60
  private normalizeMiddleware?;
61
+ private static currentResolvers?;
62
+ /**
63
+ * Wire the resolvers used by the static `current*` accessors. Called once by
64
+ * `CoreRouter` so `Route.current()` reflects the active request.
65
+ *
66
+ * @internal
67
+ * @param resolvers
68
+ */
69
+ static bindCurrentResolvers(resolvers: CurrentRouteResolvers): void;
70
+ /**
71
+ * Get the route currently being dispatched, if any.
72
+ *
73
+ * @returns
74
+ */
75
+ static current(): Route<any, any, any> | undefined;
76
+ /**
77
+ * Get the name of the route currently being dispatched.
78
+ *
79
+ * @returns
80
+ */
81
+ static currentRouteName(): string;
82
+ /**
83
+ * Get the action (controller@method or `Closure`) of the route currently
84
+ * being dispatched.
85
+ *
86
+ * @returns
87
+ */
88
+ static currentRouteAction(): string;
89
+ /**
90
+ * The route action expressed as `Controller@method` for controller routes or
91
+ * `Closure` for callback routes.
92
+ */
93
+ get action(): string;
39
94
  /**
40
95
  * Set the route name
41
96
  *
@@ -43,6 +98,67 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
43
98
  * @returns
44
99
  */
45
100
  name(name: string): this;
101
+ /**
102
+ * Constrain the route to a host pattern such as `{account}.example.com`.
103
+ * Any `{placeholder}` segments are exposed as route parameters once matched.
104
+ *
105
+ * @param pattern
106
+ * @returns
107
+ */
108
+ domain(pattern: string): this;
109
+ /**
110
+ * Constrain one or more route parameters with a regular expression. Accepts
111
+ * either `where(name, pattern)` or `where({ name: pattern, ... })`.
112
+ *
113
+ * @param name
114
+ * @param pattern
115
+ * @returns
116
+ */
117
+ where(name: string | Record<string, string | RegExp>, pattern?: string | RegExp): this;
118
+ /**
119
+ * Constrain the given parameters to numeric values.
120
+ *
121
+ * @param names
122
+ * @returns
123
+ */
124
+ whereNumber(...names: string[]): this;
125
+ /**
126
+ * Constrain the given parameters to alphabetic values.
127
+ *
128
+ * @param names
129
+ * @returns
130
+ */
131
+ whereAlpha(...names: string[]): this;
132
+ /**
133
+ * Constrain the given parameters to alphanumeric values.
134
+ *
135
+ * @param names
136
+ * @returns
137
+ */
138
+ whereAlphaNumeric(...names: string[]): this;
139
+ /**
140
+ * Constrain the given parameters to UUID values.
141
+ *
142
+ * @param names
143
+ * @returns
144
+ */
145
+ whereUuid(...names: string[]): this;
146
+ /**
147
+ * Constrain the given parameters to ULID values.
148
+ *
149
+ * @param names
150
+ * @returns
151
+ */
152
+ whereUlid(...names: string[]): this;
153
+ /**
154
+ * Constrain a parameter to one of the given values.
155
+ *
156
+ * @param name
157
+ * @param values
158
+ * @returns
159
+ */
160
+ whereIn(name: string, values: Array<string | number>): this;
161
+ private applyConstraint;
46
162
  /**
47
163
  * Register one or more middleware that will be executed before the route.
48
164
  *
@@ -50,6 +166,14 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
50
166
  * @returns
51
167
  */
52
168
  middleware(middlewares: M[] | M): this;
169
+ /**
170
+ * Resolve the route's domain pattern into a concrete host using the given
171
+ * parameters.
172
+ *
173
+ * @param params
174
+ * @returns
175
+ */
176
+ private resolveDomainHost;
53
177
  /**
54
178
  * Get the path generated and accessible by this route
55
179
  *
@@ -59,4 +183,4 @@ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
59
183
  toPath(params?: RequestData): string;
60
184
  }
61
185
  //#endregion
62
- export { Route };
186
+ export { Route, parseDomainParameters };