clear-router 2.7.6 → 2.8.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 (116) hide show
  1. package/dist/ClearRequest.cjs +23 -0
  2. package/dist/ClearRequest.d.cts +28 -0
  3. package/dist/ClearRequest.d.mts +28 -0
  4. package/dist/ClearRequest.mjs +22 -0
  5. package/dist/Contracts.d.cts +12 -0
  6. package/dist/Contracts.d.mts +12 -0
  7. package/dist/Controller.cjs +12 -0
  8. package/dist/Controller.d.cts +14 -0
  9. package/dist/Controller.d.mts +14 -0
  10. package/dist/Controller.mjs +11 -0
  11. package/dist/{Request-DKXwa_W0.d.mts → Request-Ci0UQ-Vl.d.mts} +32 -5
  12. package/dist/ResourceRouteSelection.cjs +26 -0
  13. package/dist/ResourceRouteSelection.d.cts +20 -0
  14. package/dist/ResourceRouteSelection.d.mts +20 -0
  15. package/dist/ResourceRouteSelection.mjs +25 -0
  16. package/dist/ResourceRoutes.cjs +60 -0
  17. package/dist/ResourceRoutes.d.cts +37 -0
  18. package/dist/ResourceRoutes.d.mts +37 -0
  19. package/dist/ResourceRoutes.mjs +60 -0
  20. package/dist/Route.cjs +90 -0
  21. package/dist/Route.d.cts +62 -0
  22. package/dist/Route.d.mts +62 -0
  23. package/dist/Route.mjs +89 -0
  24. package/dist/core/Request.cjs +35 -0
  25. package/dist/core/Request.d.cts +25 -0
  26. package/dist/core/Request.d.mts +25 -0
  27. package/dist/core/Request.mjs +35 -0
  28. package/dist/core/Response.cjs +59 -0
  29. package/dist/core/Response.d.cts +24 -0
  30. package/dist/core/Response.d.mts +24 -0
  31. package/dist/core/Response.mjs +58 -0
  32. package/dist/{bindings-CLsZjOEy.cjs → core/bindings.cjs} +10 -160
  33. package/dist/{bindings-CNL7bpz5.d.mts → core/bindings.d.cts} +1 -1
  34. package/dist/{bindings-CxvtC8XS.d.cts → core/bindings.d.mts} +1 -1
  35. package/dist/{bindings-XLDXFpHZ.mjs → core/bindings.mjs} +3 -110
  36. package/dist/core/index.cjs +7 -17
  37. package/dist/core/index.d.cts +4 -1
  38. package/dist/core/index.d.mts +4 -1
  39. package/dist/core/index.mjs +4 -14
  40. package/dist/core/plugins.cjs +14 -0
  41. package/dist/core/plugins.d.cts +109 -0
  42. package/dist/core/plugins.d.mts +109 -0
  43. package/dist/core/plugins.mjs +13 -0
  44. package/dist/{responses-Bvnk0uvc.cjs → core/responses.cjs} +5 -20
  45. package/dist/{responses-BvETUeDL.mjs → core/responses.mjs} +2 -2
  46. package/dist/{router-C6W-k6sS.cjs → core/router.cjs} +67 -72
  47. package/dist/core/router.d.cts +286 -0
  48. package/dist/core/router.d.mts +286 -0
  49. package/dist/{router-Dc9w86Wn.mjs → core/router.mjs} +62 -62
  50. package/dist/decorators/index.cjs +1 -1
  51. package/dist/decorators/index.d.cts +1 -1
  52. package/dist/decorators/index.d.mts +1 -1
  53. package/dist/decorators/index.mjs +1 -1
  54. package/dist/decorators/setup.cjs +2 -2
  55. package/dist/decorators/setup.d.cts +1 -1
  56. package/dist/decorators/setup.d.mts +1 -2
  57. package/dist/decorators/setup.mjs +2 -2
  58. package/dist/express/index.cjs +2 -265
  59. package/dist/express/index.d.cts +1 -127
  60. package/dist/express/index.d.mts +1 -127
  61. package/dist/express/index.mjs +1 -264
  62. package/dist/express/router.cjs +265 -0
  63. package/dist/express/router.d.cts +132 -0
  64. package/dist/express/router.d.mts +132 -0
  65. package/dist/express/router.mjs +265 -0
  66. package/dist/fastify/index.cjs +2 -254
  67. package/dist/fastify/index.d.cts +1 -125
  68. package/dist/fastify/index.d.mts +1 -125
  69. package/dist/fastify/index.mjs +1 -253
  70. package/dist/fastify/router.cjs +254 -0
  71. package/dist/fastify/router.d.cts +130 -0
  72. package/dist/fastify/router.d.mts +130 -0
  73. package/dist/fastify/router.mjs +254 -0
  74. package/dist/h3/index.cjs +2 -260
  75. package/dist/h3/index.d.cts +1 -128
  76. package/dist/h3/index.d.mts +1 -128
  77. package/dist/h3/index.mjs +1 -259
  78. package/dist/h3/router.cjs +260 -0
  79. package/dist/h3/router.d.cts +133 -0
  80. package/dist/h3/router.d.mts +133 -0
  81. package/dist/h3/router.mjs +260 -0
  82. package/dist/hono/index.cjs +2 -251
  83. package/dist/hono/index.d.cts +1 -130
  84. package/dist/hono/index.d.mts +1 -130
  85. package/dist/hono/index.mjs +1 -250
  86. package/dist/hono/router.cjs +251 -0
  87. package/dist/hono/router.d.cts +135 -0
  88. package/dist/hono/router.d.mts +135 -0
  89. package/dist/hono/router.mjs +251 -0
  90. package/dist/index.cjs +16 -1097
  91. package/dist/index.d.cts +9 -563
  92. package/dist/index.d.mts +9 -563
  93. package/dist/index.mjs +8 -1089
  94. package/dist/koa/index.cjs +2 -261
  95. package/dist/koa/index.d.cts +1 -131
  96. package/dist/koa/index.d.mts +1 -131
  97. package/dist/koa/index.mjs +1 -260
  98. package/dist/koa/router.cjs +261 -0
  99. package/dist/koa/router.d.cts +136 -0
  100. package/dist/koa/router.d.mts +136 -0
  101. package/dist/koa/router.mjs +261 -0
  102. package/dist/types/basic.d.cts +53 -0
  103. package/dist/types/basic.d.mts +11 -1
  104. package/dist/types/express.d.cts +48 -0
  105. package/dist/types/express.d.mts +10 -4
  106. package/dist/types/fastify.d.cts +24 -0
  107. package/dist/types/fastify.d.mts +7 -4
  108. package/dist/types/h3.d.cts +46 -0
  109. package/dist/types/h3.d.mts +10 -5
  110. package/dist/types/hono.d.cts +22 -0
  111. package/dist/types/hono.d.mts +8 -6
  112. package/dist/types/koa.d.cts +26 -0
  113. package/dist/types/koa.d.mts +7 -5
  114. package/package.json +1 -1
  115. package/dist/router-BEgAxp5A.d.cts +0 -649
  116. package/dist/router-DKKYx23P.d.mts +0 -649
package/dist/index.cjs CHANGED
@@ -1,1098 +1,17 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- let node_async_hooks = require("node:async_hooks");
3
- let node_module = require("node:module");
4
-
5
- //#region src/ClearRequest.ts
6
- var ClearRequest = class {
7
- /**
8
- * @param body - Parsed request body
9
- */
10
- body;
11
- /**
12
- * @param query - Parsed query parameters
13
- */
14
- query;
15
- /**
16
- * @param params - Parsed route parameters
17
- */
18
- params;
19
- route;
20
- constructor(init) {
21
- Object.assign(this, init);
22
- }
23
- };
24
-
25
- //#endregion
26
- //#region src/Controller.ts
27
- var Controller = class {
28
- ctx;
29
- body;
30
- query;
31
- params;
32
- clearRequest;
33
- };
34
-
35
- //#endregion
36
- //#region src/Route.ts
37
- var Route = class {
38
- ctx;
39
- body = {};
40
- query = {};
41
- params = {};
42
- clearRequest;
43
- methods;
44
- path;
45
- registrationPaths;
46
- parameters;
47
- routeName;
48
- handler;
49
- middlewares;
50
- controllerName;
51
- actionName;
52
- handlerType;
53
- middlewareCount;
54
- constructor(methods, path, handler, middlewares = [], options = {}) {
55
- this.methods = methods;
56
- this.path = path;
57
- this.registrationPaths = options.registrationPaths || [path];
58
- this.parameters = options.parameters || [];
59
- this.handler = handler;
60
- this.middlewares = middlewares;
61
- this.handlerType = Array.isArray(handler) ? "controller" : "function";
62
- this.middlewareCount = middlewares.length;
63
- this.controllerName = Array.isArray(handler) ? handler[0]?.name : void 0;
64
- this.actionName = Array.isArray(handler) ? handler[1] : typeof handler === "function" ? handler.constructor.name ?? handler.name : void 0;
65
- this.onName = options.onName;
66
- }
67
- onName;
68
- name(name) {
69
- const previousName = this.routeName;
70
- this.routeName = name;
71
- this.onName?.(name, this, previousName);
72
- return this;
73
- }
74
- toPath(params = {}) {
75
- return this.path.replace(/\/?\{([^{}]+)\}/g, (segment, raw) => {
76
- const optional = raw.endsWith("?");
77
- const [rawName, rawField] = (optional ? raw.slice(0, -1) : raw).split(":", 2);
78
- const name = rawName.trim();
79
- const field = rawField?.trim();
80
- const value = params[name];
81
- const resolved = field && value && typeof value === "object" ? value[field] : value;
82
- if (typeof resolved === "undefined" || resolved === null || resolved === "") {
83
- if (optional) return "";
84
- throw new Error(`Missing required route parameter: ${name}`);
85
- }
86
- return `${segment.startsWith("/") ? "/" : ""}${encodeURIComponent(String(resolved))}`;
87
- }) || "/";
88
- }
89
- };
90
-
91
- //#endregion
92
- //#region src/core/Request.ts
93
- var Request = class extends ClearRequest {
94
- original;
95
- method = "GET";
96
- path = "/";
97
- url = "/";
98
- headers = {};
99
- constructor(init) {
100
- super(init);
101
- Object.assign(this, init);
102
- }
103
- getBody() {
104
- return this.body ?? {};
105
- }
106
- header(name) {
107
- if (typeof this.headers.get === "function") return this.headers.get(name) || "";
108
- const headers = this.headers;
109
- const value = headers[name] ?? headers[name.toLowerCase()];
110
- return Array.isArray(value) ? String(value[0] ?? "") : String(value ?? "");
111
- }
112
- param(name) {
113
- return this.params?.[name];
114
- }
115
- input(name) {
116
- return this.body?.[name] ?? this.query?.[name] ?? this.params?.[name];
117
- }
118
- is(method) {
119
- return this.method.toLowerCase() === String(method).toLowerCase();
120
- }
121
- };
122
-
123
- //#endregion
124
- //#region src/core/Response.ts
125
- var Response = class {
126
- body;
127
- headers = new Headers();
128
- sent = false;
129
- statusCode = 200;
130
- statusText = "OK";
131
- constructor(init) {
132
- const { status: _, ...rest } = init ?? {};
133
- Object.assign(this, rest);
134
- if (init?.headers && !(init.headers instanceof Headers)) this.headers = new Headers(init.headers);
135
- if (init?.status && typeof init.status === "number") this.statusCode = init?.status;
136
- }
137
- status(code) {
138
- this.statusCode = code;
139
- return this;
140
- }
141
- setStatusText(text) {
142
- this.statusText = text;
143
- return this;
144
- }
145
- code(code) {
146
- return this.status(code);
147
- }
148
- setHeader(name, value) {
149
- this.headers.set(name, value);
150
- return this;
151
- }
152
- header(name, value) {
153
- return this.setHeader(name, value);
154
- }
155
- set(name, value) {
156
- return this.setHeader(name, value);
157
- }
158
- type(contentType) {
159
- return this.setHeader("Content-Type", contentType);
160
- }
161
- send(body) {
162
- this.body = body;
163
- this.sent = true;
164
- return this;
165
- }
166
- json(body) {
167
- return this.type("application/json; charset=utf-8").send(body);
168
- }
169
- html(body) {
170
- return this.type("text/html; charset=utf-8").send(body);
171
- }
172
- text(body) {
173
- return this.type("text/plain; charset=utf-8").send(body);
174
- }
175
- noContent() {
176
- return this.status(204).send(null);
177
- }
178
- };
179
-
180
- //#endregion
181
- //#region src/core/plugins.ts
182
- /**
183
- * Creates a new plugin
184
- *
185
- * @param plugin
186
- * @returns
187
- */
188
- function definePlugin(plugin) {
189
- return plugin;
190
- }
191
-
192
- //#endregion
193
- //#region src/core/bindings.ts
194
- const metadataKey = Symbol.for("clear-router:binding-metadata");
195
- const bindings = /* @__PURE__ */ new WeakMap();
196
- var Container = class {
197
- static registry = /* @__PURE__ */ new Map();
198
- static bind(token, value) {
199
- this.registry.set(token, value);
200
- }
201
- static unbind(token) {
202
- this.registry.delete(token);
203
- }
204
- static clear() {
205
- this.registry.clear();
206
- }
207
- static has(token) {
208
- return this.registry.has(token) || Boolean(this.findEquivalentToken(token));
209
- }
210
- static bindings() {
211
- return Object.fromEntries(this.registry.entries());
212
- }
213
- static async resolve(token, ctx, autoDiscover = false) {
214
- if (token === Request) return ctx.clearRequest;
215
- if (token === Response) return ctx.clearResponse;
216
- const binding = this.getBinding(token);
217
- if (binding) return this.resolveBinding(binding, ctx, autoDiscover);
218
- if (autoDiscover && typeof token === "function") return new token();
219
- }
220
- static getBinding(token) {
221
- if (this.registry.has(token)) return this.registry.get(token);
222
- const equivalent = this.findEquivalentToken(token);
223
- return equivalent ? this.registry.get(equivalent) : void 0;
224
- }
225
- static findEquivalentToken(token) {
226
- const name = token.name;
227
- if (!name) return;
228
- const tokenParent = Object.getPrototypeOf(token);
229
- const tokenProps = this.getComparableStaticProps(token);
230
- for (const registered of this.registry.keys()) {
231
- if (registered === token) continue;
232
- if (registered.name !== name) continue;
233
- const registeredParent = Object.getPrototypeOf(registered);
234
- if (tokenParent && registeredParent && tokenParent.name !== registeredParent.name) continue;
235
- const registeredProps = this.getComparableStaticProps(registered);
236
- if (!this.staticPropsMatch(token, registered, tokenProps, registeredProps)) continue;
237
- return registered;
238
- }
239
- }
240
- static getComparableStaticProps(token) {
241
- return Object.getOwnPropertyNames(token).filter((prop) => {
242
- return ![
243
- "length",
244
- "name",
245
- "prototype",
246
- "arguments",
247
- "caller"
248
- ].includes(prop);
249
- });
250
- }
251
- static staticPropsMatch(token, registered, tokenProps, registeredProps) {
252
- if (tokenProps.length !== registeredProps.length) return false;
253
- for (const prop of tokenProps) {
254
- if (!registeredProps.includes(prop)) return false;
255
- if (Reflect.get(token, prop) !== Reflect.get(registered, prop)) return false;
256
- }
257
- return true;
258
- }
259
- static async resolveBinding(binding, ctx, autoDiscover) {
260
- if (!binding) return void 0;
261
- if (typeof binding !== "function") return binding;
262
- if (isClass(binding)) return new binding();
263
- const resolved = await binding(ctx);
264
- if (typeof resolved === "function" && autoDiscover && isClass(resolved)) return new resolved();
265
- return resolved;
266
- }
267
- };
268
- function getStandardMetadata(metadata, propertyKey) {
269
- const store = metadata && metadata[metadataKey];
270
- if (!store) return void 0;
271
- return propertyKey ? store[propertyKey] : void 0;
272
- }
273
- function getBindingMetadataFromTargets(targets) {
274
- for (const { target, propertyKey } of targets) {
275
- if (!target) continue;
276
- const metadata = getBindingMetadata(target, propertyKey);
277
- if (metadata) return metadata;
278
- const standardMetadata = getStandardMetadata(target[Symbol.metadata], propertyKey);
279
- if (standardMetadata) return standardMetadata;
280
- }
281
- }
282
- function getBindingMetadata(target, propertyKey) {
283
- if (propertyKey) return bindings.get(target)?.get(propertyKey);
284
- return bindings.get(target)?.get("__route_handler__");
285
- }
286
- function getDesignParamTypes(target, propertyKey) {
287
- return Reflect.getMetadata?.("design:paramtypes", target, propertyKey) ?? [];
288
- }
289
- function isClass(value) {
290
- return typeof value === "function" && /^class\s/.test(Function.prototype.toString.call(value));
291
- }
292
-
293
- //#endregion
294
- //#region src/core/router.ts
295
- /**
296
- * @class clear-router CoreRouter
297
- * @description Core routing logic for clear-router, shared between all supported adapters (Express.js, H3, etc.)
298
- * @author 3m1n3nc3
299
- * @repository https://github.com/arkstack-tmp/clear-router
300
- */
301
- var CoreRouter = class {
302
- static routerStateNamespace = "clear-router:core";
303
- static stateStoreKey = Symbol.for("clear-router:router-state");
304
- static stateBoundKey = Symbol.for("clear-router:router-state-bound");
305
- static defaultConfigKey = Symbol.for("clear-router:default-config");
306
- static pluginStoreKey = Symbol.for("clear-router:plugins");
307
- static pluginPendingKey = Symbol.for("clear-router:plugin-promises");
308
- static pluginHttpCtxResolversKey = Symbol.for("clear-router:plugin-http-ctx");
309
- static pluginArgumentResolversKey = Symbol.for("clear-router:plugin-argument-resolvers");
310
- static requestProvider;
311
- static responseProvider;
312
- static config = {
313
- inferParamName: false,
314
- methodOverride: {
315
- enabled: true,
316
- bodyKeys: ["_method"],
317
- headerKeys: ["x-http-method"]
318
- },
319
- container: {
320
- enabled: false,
321
- autoDiscover: false
322
- }
323
- };
324
- static groupContext = new node_async_hooks.AsyncLocalStorage();
325
- static pluginRequestContext = new node_async_hooks.AsyncLocalStorage();
326
- static routes = /* @__PURE__ */ new Set([]);
327
- static routesByPathMethod = /* @__PURE__ */ new Map();
328
- static routesByMethod = /* @__PURE__ */ new Map();
329
- static routesByName = /* @__PURE__ */ new Map();
330
- static prefix = "";
331
- static groupMiddlewares = [];
332
- static globalMiddlewares = [];
333
- /**
334
- * Resets the router to it's default state
335
- */
336
- static reset() {
337
- this.routes.clear();
338
- this.prefix = "";
339
- this.groupMiddlewares = [];
340
- this.globalMiddlewares = [];
341
- this.routesByPathMethod.clear();
342
- this.routesByMethod.clear();
343
- this.routesByName.clear();
344
- return this;
345
- }
346
- static createBaseConfig() {
347
- return {
348
- inferParamName: false,
349
- methodOverride: {
350
- enabled: true,
351
- bodyKeys: ["_method"],
352
- headerKeys: ["x-http-method"]
353
- },
354
- container: {
355
- enabled: false,
356
- autoDiscover: false
357
- }
358
- };
359
- }
360
- static mergeConfig(target, source) {
361
- if (!source) return target;
362
- if (source.methodOverride) target.methodOverride = {
363
- ...target.methodOverride || {},
364
- ...source.methodOverride
365
- };
366
- if (source.container) target.container = {
367
- ...target.container || {},
368
- ...source.container
369
- };
370
- return target;
371
- }
372
- static getDefaultConfig() {
373
- const g = globalThis;
374
- if (!g[this.defaultConfigKey]) g[this.defaultConfigKey] = this.createBaseConfig();
375
- return {
376
- inferParamName: g[this.defaultConfigKey].inferParamName,
377
- methodOverride: { ...g[this.defaultConfigKey].methodOverride },
378
- container: { ...g[this.defaultConfigKey].container }
379
- };
380
- }
381
- static resolveStateNamespace() {
382
- return String(this.routerStateNamespace || this.name || "clear-router:core");
383
- }
384
- static getStateStore() {
385
- const g = globalThis;
386
- if (!g[this.stateStoreKey]) g[this.stateStoreKey] = Object.create(null);
387
- return g[this.stateStoreKey];
388
- }
389
- static getPluginStore() {
390
- const g = globalThis;
391
- if (!g[this.pluginStoreKey]) g[this.pluginStoreKey] = /* @__PURE__ */ new Set();
392
- return g[this.pluginStoreKey];
393
- }
394
- static getPluginPendingStore() {
395
- const g = globalThis;
396
- if (!g[this.pluginPendingKey]) g[this.pluginPendingKey] = /* @__PURE__ */ new Set();
397
- return g[this.pluginPendingKey];
398
- }
399
- static getPluginArgumentResolvers() {
400
- const g = globalThis;
401
- if (!g[this.pluginArgumentResolversKey]) g[this.pluginArgumentResolversKey] = /* @__PURE__ */ new Set();
402
- return g[this.pluginArgumentResolversKey];
403
- }
404
- static getPluginHttpCtxResolvers() {
405
- const g = globalThis;
406
- if (!g[this.pluginHttpCtxResolversKey]) g[this.pluginHttpCtxResolversKey] = /* @__PURE__ */ new Set();
407
- return g[this.pluginHttpCtxResolversKey];
408
- }
409
- static createDefaultState() {
410
- return {
411
- config: this.getDefaultConfig(),
412
- groupContext: new node_async_hooks.AsyncLocalStorage(),
413
- routes: /* @__PURE__ */ new Set([]),
414
- routesByPathMethod: /* @__PURE__ */ new Map(),
415
- routesByMethod: /* @__PURE__ */ new Map(),
416
- routesByName: /* @__PURE__ */ new Map(),
417
- prefix: "",
418
- groupMiddlewares: [],
419
- globalMiddlewares: []
420
- };
421
- }
422
- static bindStateAccessors() {
423
- if (Object.prototype.hasOwnProperty.call(this, this.stateBoundKey)) return;
424
- const namespace = this.resolveStateNamespace();
425
- const store = this.getStateStore();
426
- if (!store[namespace]) store[namespace] = this.createDefaultState();
427
- for (const key of [
428
- "config",
429
- "groupContext",
430
- "routes",
431
- "routesByPathMethod",
432
- "routesByMethod",
433
- "routesByName",
434
- "prefix",
435
- "groupMiddlewares",
436
- "globalMiddlewares"
437
- ]) Object.defineProperty(this, key, {
438
- get() {
439
- const ns = this.resolveStateNamespace();
440
- const registry = this.getStateStore();
441
- if (!registry[ns]) registry[ns] = this.createDefaultState();
442
- return registry[ns][key];
443
- },
444
- set(value) {
445
- const ns = this.resolveStateNamespace();
446
- const registry = this.getStateStore();
447
- if (!registry[ns]) registry[ns] = this.createDefaultState();
448
- registry[ns][key] = value;
449
- },
450
- configurable: true,
451
- enumerable: true
452
- });
453
- Object.defineProperty(this, this.stateBoundKey, {
454
- value: true,
455
- configurable: false,
456
- enumerable: false,
457
- writable: false
458
- });
459
- }
460
- static createDefaultOptionsHandler() {
461
- return (ctx) => {
462
- const allow = "GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD";
463
- if (ctx?.header && ctx?.status && ctx?.body) {
464
- ctx.header("Allow", allow);
465
- ctx.status(204);
466
- return ctx.body(null);
467
- }
468
- if (ctx?.res?.headers?.set) {
469
- ctx.res.headers.set("Allow", allow);
470
- ctx.res.status = 204;
471
- return;
472
- }
473
- if (ctx?.res?.set) {
474
- ctx.res.set("Allow", allow);
475
- ctx.res.sendStatus(204);
476
- return;
477
- }
478
- if (ctx?.reply?.header) {
479
- ctx.reply.header("Allow", allow);
480
- ctx.reply.code(204).send();
481
- return;
482
- }
483
- if (ctx?.set && "status" in ctx) {
484
- ctx.set("Allow", allow);
485
- ctx.status = 204;
486
- ctx.body = null;
487
- }
488
- };
489
- }
490
- /**
491
- * Default configuration used for everytime the router is reset
492
- *
493
- * @param options
494
- */
495
- static configureDefaults(options) {
496
- const g = globalThis;
497
- const defaults = this.mergeConfig(g[this.defaultConfigKey] || this.createBaseConfig(), options);
498
- g[this.defaultConfigKey] = defaults;
499
- const store = this.getStateStore();
500
- for (const state of Object.values(store)) state.config = this.mergeConfig(state.config || this.createBaseConfig(), options);
501
- }
502
- /**
503
- * Use a registered plugin
504
- *
505
- * @param this
506
- * @param plugin
507
- * @param options
508
- * @returns
509
- */
510
- static async use(plugin, options) {
511
- const name = typeof plugin === "function" ? plugin.name : plugin.name;
512
- const store = this.getPluginStore();
513
- if (name && store.has(name)) return;
514
- if (name) store.add(name);
515
- const setup = async () => {
516
- const ctx = {
517
- container: Container,
518
- bind: this.createPluginBind(),
519
- resolveArguments: (resolver) => {
520
- this.getPluginArgumentResolvers().add(resolver);
521
- },
522
- useHttpContext: (resolver) => {
523
- this.getPluginHttpCtxResolvers().add(resolver);
524
- },
525
- bindings: Container.bindings(),
526
- configure: this.configure.bind(this),
527
- configureDefaults: this.configureDefaults.bind(this),
528
- get request() {
529
- return this.getRequest();
530
- },
531
- get response() {
532
- return this.getResponse();
533
- },
534
- getRequest: () => this.getCurrentPluginRequestContext()?.request,
535
- getResponse: () => this.getCurrentPluginRequestContext()?.response,
536
- options
537
- };
538
- if (typeof plugin === "function") await plugin(ctx);
539
- else await plugin.setup(ctx);
540
- };
541
- const pending = this.getPluginPendingStore();
542
- const promise = setup();
543
- pending.add(promise);
544
- try {
545
- await promise;
546
- } catch (error) {
547
- if (name) store.delete(name);
548
- throw error;
549
- } finally {
550
- pending.delete(promise);
551
- }
552
- }
553
- static async pluginsReady() {
554
- const pending = Array.from(this.getPluginPendingStore());
555
- if (!pending.length) return;
556
- await Promise.all(pending);
557
- }
558
- static getCurrentPluginRequestContext() {
559
- return this.pluginRequestContext.getStore();
560
- }
561
- static createPluginRequestContext(ctx) {
562
- const request = ctx.clearRequest;
563
- const response = ctx.clearResponse;
564
- return {
565
- ...ctx,
566
- ctx,
567
- request,
568
- response,
569
- getBindings: () => Container.bindings()
570
- };
571
- }
572
- static createPluginBind() {
573
- const bind = (token, value) => {
574
- if (typeof value === "function" && !isClass(value)) {
575
- const factory = value;
576
- Container.bind(token, (ctx) => factory(this.createPluginRequestContext(ctx)));
577
- return;
578
- }
579
- Container.bind(token, value);
580
- };
581
- return bind;
582
- }
583
- static async resolvePluginArguments(ctx, routeContext) {
584
- const resolvers = Array.from(this.getPluginArgumentResolvers());
585
- if (!resolvers.length) return void 0;
586
- const pluginContext = {
587
- ...this.createPluginRequestContext(ctx),
588
- ...routeContext
589
- };
590
- for (const resolver of resolvers) {
591
- const args = await resolver(pluginContext);
592
- if (Array.isArray(args)) return args;
593
- }
594
- }
595
- static async resolvePluginHttpCtx(ctx) {
596
- const resolvers = Array.from(this.getPluginHttpCtxResolvers());
597
- if (!resolvers.length) return void 0;
598
- const pluginContext = this.createPluginRequestContext(ctx);
599
- for (const resolver of resolvers) await resolver(pluginContext);
600
- }
601
- static ensureState() {
602
- this.bindStateAccessors();
603
- if (!this.config) this.config = { methodOverride: {
604
- enabled: true,
605
- bodyKeys: ["_method"],
606
- headerKeys: ["x-http-method"]
607
- } };
608
- if (!this.groupContext) this.groupContext = new node_async_hooks.AsyncLocalStorage();
609
- if (!this.routes || Array.isArray(this.routes)) this.routes = new Set(this.routes ?? []);
610
- if (!this.routesByPathMethod) this.routesByPathMethod = /* @__PURE__ */ new Map();
611
- if (!this.routesByMethod) this.routesByMethod = /* @__PURE__ */ new Map();
612
- if (!this.routesByName) this.routesByName = /* @__PURE__ */ new Map();
613
- if (typeof this.prefix !== "string") this.prefix = "";
614
- if (!Array.isArray(this.groupMiddlewares)) this.groupMiddlewares = [];
615
- if (!Array.isArray(this.globalMiddlewares)) this.globalMiddlewares = [];
616
- }
617
- /**
618
- * Normalizes a path by ensuring it starts with a single slash and does not have trailing
619
- * slashes, while preserving dynamic segments and parameters.
620
- *
621
- * @param path The path to normalize.
622
- * @returns The normalized path.
623
- */
624
- static normalizePath(path) {
625
- return "/" + path.split("/").filter(Boolean).join("/");
626
- }
627
- static parseRouteParameters(path) {
628
- const parameters = [];
629
- const seen = /* @__PURE__ */ new Set();
630
- const pattern = /\{([^{}]+)\}/g;
631
- let match;
632
- while ((match = pattern.exec(path)) !== null) {
633
- const raw = match[1].trim();
634
- const optional = raw.endsWith("?");
635
- const [name, field] = (optional ? raw.slice(0, -1) : raw).split(":", 2).map((part) => part.trim());
636
- if (!name || seen.has(name)) continue;
637
- seen.add(name);
638
- parameters.push({
639
- name,
640
- field: field || void 0,
641
- optional
642
- });
643
- }
644
- return parameters;
645
- }
646
- static expandRoutePath(path) {
647
- let paths = [""];
648
- const segments = this.normalizePath(path).split("/").filter(Boolean);
649
- for (const segment of segments) {
650
- const match = segment.match(/^\{([^{}]+)\}$/);
651
- if (!match) {
652
- paths = paths.map((current) => `${current}/${segment}`);
653
- continue;
654
- }
655
- const raw = match[1].trim();
656
- const optional = raw.endsWith("?");
657
- const [rawName] = (optional ? raw.slice(0, -1) : raw).split(":", 2);
658
- const name = rawName.trim();
659
- if (!name) continue;
660
- const parameterSegment = `/:${name}`;
661
- paths = optional ? paths.flatMap((current) => [current, `${current}${parameterSegment}`]) : paths.map((current) => `${current}${parameterSegment}`);
662
- }
663
- return paths.map((path) => path || "/");
664
- }
665
- static routeRegistrationPaths(path) {
666
- return this.expandRoutePath(path);
667
- }
668
- /**
669
- * Configures the router with the given options, such as method override settings.
670
- *
671
- * @param this
672
- * @param options
673
- * @returns
674
- */
675
- static configure(options) {
676
- this.ensureState();
677
- this.config = this.mergeConfig(this.getDefaultConfig(), this.config);
678
- const container = options?.container;
679
- if (container) {
680
- if (typeof container.enabled === "boolean") this.config.container.enabled = container.enabled;
681
- if (typeof container.autoDiscover === "boolean") this.config.container.autoDiscover = container.autoDiscover;
682
- }
683
- if (options?.inferParamName) this.config.inferParamName = options?.inferParamName;
684
- const override = options?.methodOverride;
685
- if (override) {
686
- if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
687
- const bodyKeys = override.bodyKeys;
688
- if (typeof bodyKeys !== "undefined") this.config.methodOverride.bodyKeys = (Array.isArray(bodyKeys) ? bodyKeys : [bodyKeys]).map((e) => String(e).trim()).filter(Boolean);
689
- const headerKeys = override.headerKeys;
690
- if (typeof headerKeys !== "undefined") this.config.methodOverride.headerKeys = (Array.isArray(headerKeys) ? headerKeys : [headerKeys]).map((e) => String(e).trim().toLowerCase()).filter(Boolean);
691
- }
692
- }
693
- static resolveMethodOverride(method, headers, body) {
694
- this.ensureState();
695
- if (!this.config.methodOverride?.enabled || method.toLowerCase() !== "post") return null;
696
- let override;
697
- const headerValueFor = (key) => {
698
- if (typeof headers.get === "function") return headers.get(key);
699
- const value = headers?.[key];
700
- return Array.isArray(value) ? value[0] : value;
701
- };
702
- for (const key of this.config.methodOverride?.headerKeys || []) {
703
- const value = headerValueFor(key);
704
- if (value) {
705
- override = value;
706
- break;
707
- }
708
- }
709
- if (!override && body && typeof body === "object") for (const key of this.config.methodOverride?.bodyKeys || []) {
710
- const value = body[key];
711
- if (typeof value !== "undefined" && value !== null && value !== "") {
712
- override = value;
713
- break;
714
- }
715
- }
716
- const normalized = String(override || "").trim().toLowerCase();
717
- if (!normalized) return null;
718
- if ([
719
- "put",
720
- "patch",
721
- "delete",
722
- "post"
723
- ].includes(normalized)) return normalized;
724
- return null;
725
- }
726
- /**
727
- * Adds a new route to the router.
728
- *
729
- * @param this
730
- * @param methods
731
- * @param path
732
- * @param handler
733
- * @param middlewares
734
- */
735
- static add(methods, path, handler, middlewares) {
736
- this.ensureState();
737
- const context = this.groupContext.getStore();
738
- const activePrefix = context?.prefix ?? this.prefix;
739
- const activeGroupMiddlewares = context?.groupMiddlewares ?? this.groupMiddlewares;
740
- methods = Array.isArray(methods) ? methods : [methods];
741
- middlewares = middlewares ? Array.isArray(middlewares) ? middlewares : [middlewares] : void 0;
742
- const fullPath = this.normalizePath(`${activePrefix}/${path}`);
743
- const registrationPaths = this.routeRegistrationPaths(fullPath);
744
- const parameters = this.parseRouteParameters(fullPath);
745
- const route = new Route(methods.includes("options") ? methods : methods.concat("options"), fullPath, handler, [
746
- ...this.globalMiddlewares,
747
- ...activeGroupMiddlewares,
748
- ...middlewares || []
749
- ], {
750
- registrationPaths,
751
- parameters,
752
- onName: (name, route, previousName) => {
753
- if (previousName && this.routesByName.get(previousName) === route) this.routesByName.delete(previousName);
754
- this.routesByName.set(name, route);
755
- }
756
- });
757
- if (!methods.includes("options") && !this.routesByPathMethod.get(`OPTIONS ${fullPath}`)) this.options(path, this.createDefaultOptionsHandler());
758
- this.routes.add(route);
759
- for (const method of methods.map((m) => m.toUpperCase())) {
760
- this.routesByPathMethod.set(`${method} ${fullPath}`, route);
761
- if (!this.routesByMethod.has(method)) this.routesByMethod.set(method, []);
762
- this.routesByMethod.get(method)?.push(route);
763
- }
764
- return route;
765
- }
766
- /**
767
- * Define a resourceful API controller with standard CRUD routes.
768
- *
769
- * @param this
770
- * @param basePath
771
- * @param controller
772
- * @param options
773
- */
774
- static apiResource(basePath, controller, options) {
775
- let paramName = "id";
776
- if (!!this.config.inferParamName && this.hasPackageInstalled("@h3ravel/support")) {
777
- const { str } = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("@h3ravel/support");
778
- paramName = str(basePath).singular().afterLast("/").toString();
779
- }
780
- const actions = {
781
- index: {
782
- method: "get",
783
- path: "/"
784
- },
785
- show: {
786
- method: "get",
787
- path: `/:${paramName}`
788
- },
789
- create: {
790
- method: "post",
791
- path: "/"
792
- },
793
- update: {
794
- method: "put",
795
- path: `/:${paramName}`
796
- },
797
- destroy: {
798
- method: "delete",
799
- path: `/:${paramName}`
800
- }
801
- };
802
- const only = options?.only || Object.keys(actions);
803
- const except = options?.except || [];
804
- const preController = typeof controller === "function" ? new controller() : controller;
805
- for (const action of only) {
806
- if (except.includes(action)) continue;
807
- if (typeof preController[action] === "function") {
808
- const { method, path } = actions[action];
809
- const actionMiddlewares = typeof options?.middlewares === "object" && !Array.isArray(options.middlewares) ? options.middlewares[action] : options?.middlewares;
810
- const name = `${basePath}${path}`.replace(/\/:[^/]+|\/\{[^}]+\}/g, "").replace(/\{(\w+):[^}]+\}/g, "$1").replace(/\/|:|[{}]/g, ".").replace(/\.{2,}/g, ".").replace(/^\.|\.$/g, "");
811
- this.add(method, `${basePath}${path}`, [controller, action], Array.isArray(actionMiddlewares) ? actionMiddlewares : actionMiddlewares ? [actionMiddlewares] : void 0).name(name + "." + action.toLowerCase());
812
- }
813
- }
814
- }
815
- /**
816
- * Adds a new GET route to the router.
817
- *
818
- * @param this The router instance.
819
- * @param path The path for the GET route.
820
- * @param handler The handler function for the GET route.
821
- * @param middlewares Optional middlewares to apply to the GET route.
822
- */
823
- static get(path, handler, middlewares) {
824
- return this.add("get", path, handler, middlewares);
825
- }
826
- /**
827
- * Adds a new POST route to the router.
828
- *
829
- * @param this
830
- * @param path
831
- * @param handler
832
- * @param middlewares
833
- */
834
- static post(path, handler, middlewares) {
835
- return this.add("post", path, handler, middlewares);
836
- }
837
- /**
838
- * Adds a new PUT route to the router.
839
- *
840
- * @param this
841
- * @param path
842
- * @param handler
843
- * @param middlewares
844
- */
845
- static put(path, handler, middlewares) {
846
- return this.add("put", path, handler, middlewares);
847
- }
848
- /**
849
- * Adds a new DELETE route to the router.
850
- *
851
- * @param this
852
- * @param path
853
- * @param handler
854
- * @param middlewares
855
- */
856
- static delete(path, handler, middlewares) {
857
- return this.add("delete", path, handler, middlewares);
858
- }
859
- /**
860
- * Adds a new PATCH route to the router.
861
- *
862
- * @param this
863
- * @param path
864
- * @param handler
865
- * @param middlewares
866
- */
867
- static patch(path, handler, middlewares) {
868
- return this.add("patch", path, handler, middlewares);
869
- }
870
- /**
871
- * Adds a new OPTIONS route to the router.
872
- *
873
- * @param this
874
- * @param path
875
- * @param handler
876
- * @param middlewares
877
- */
878
- static options(path, handler, middlewares) {
879
- return this.add("options", path, handler, middlewares);
880
- }
881
- /**
882
- * Adds a new HEAD route to the router.
883
- *
884
- * @param this
885
- * @param path
886
- * @param handler
887
- * @param middlewares
888
- */
889
- static head(path, handler, middlewares) {
890
- return this.add("head", path, handler, middlewares);
891
- }
892
- /**
893
- * Defines a group of routes with a common prefix.
894
- *
895
- * @param this
896
- * @param prefix
897
- * @param callback
898
- * @param middlewares
899
- */
900
- static async group(prefix, callback, middlewares) {
901
- this.ensureState();
902
- const context = this.groupContext.getStore();
903
- const previousPrefix = context?.prefix ?? this.prefix;
904
- const previousMiddlewares = context?.groupMiddlewares ?? this.groupMiddlewares;
905
- const fullPrefix = [previousPrefix, prefix].filter(Boolean).join("/");
906
- const nextContext = {
907
- prefix: this.normalizePath(fullPrefix),
908
- groupMiddlewares: [...previousMiddlewares, ...middlewares || []]
909
- };
910
- await this.groupContext.run(nextContext, async () => {
911
- await Promise.resolve(callback());
912
- });
913
- }
914
- /**
915
- * Adds global middlewares to the router, which will be applied to all routes.
916
- *
917
- * @param this
918
- * @param middlewares
919
- * @param callback
920
- */
921
- static middleware(middlewares, callback) {
922
- this.ensureState();
923
- const prevMiddlewares = this.globalMiddlewares;
924
- this.globalMiddlewares = [...prevMiddlewares, ...middlewares || []];
925
- callback();
926
- this.globalMiddlewares = prevMiddlewares;
927
- }
928
- static allRoutes(type) {
929
- this.ensureState();
930
- if (type === "method") return Object.fromEntries(this.routesByMethod.entries());
931
- if (type === "path") return Object.fromEntries(this.routesByPathMethod.entries());
932
- if (type === "name") return Object.fromEntries(this.routesByName.entries());
933
- return Array.from(this.routes).filter((e) => e.methods.length > 1 || e.methods[0] !== "options");
934
- }
935
- static route(name) {
936
- this.ensureState();
937
- return this.routesByName.get(name);
938
- }
939
- static url(name, params) {
940
- return this.route(name)?.toPath(params);
941
- }
942
- /**
943
- * Provide a class that will overide the base Request instance
944
- *
945
- * @param provider
946
- */
947
- static setRequestProvider(provider) {
948
- this.requestProvider = provider;
949
- }
950
- /**
951
- * Provide a class that will overide the base Response instance
952
- *
953
- * @param provider
954
- */
955
- static setResponseProvider(provider) {
956
- this.responseProvider = provider;
957
- }
958
- static hasPackageInstalled(name) {
959
- try {
960
- (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href).resolve(name, { paths: [process.cwd()] });
961
- return true;
962
- } catch {
963
- return false;
964
- }
965
- }
966
- static initializeInstance(provider, args) {
967
- const isRequest = [
968
- "CoreRequest",
969
- "Request",
970
- "ClearRequest"
971
- ].includes(provider.name);
972
- const isResponse = [
973
- "CoreResponse",
974
- "Response",
975
- "ClearResponse"
976
- ].includes(provider.name);
977
- if (isRequest && this.requestProvider) return new this.requestProvider(args);
978
- else if (isResponse && this.responseProvider) return new this.responseProvider(args);
979
- return new provider(args);
980
- }
981
- static resolveHandler(route) {
982
- let handlerFunction;
983
- let instance = null;
984
- let bindingTarget;
985
- let bindingMethod;
986
- let bindingHandler;
987
- let bindingMetadata;
988
- if (typeof route.handler === "function") {
989
- handlerFunction = route.handler.bind(route);
990
- bindingTarget = route.handler;
991
- bindingHandler = route.handler;
992
- } else if (Array.isArray(route.handler) && route.handler.length === 2) {
993
- const [ControllerType, method] = route.handler;
994
- if (["function", "object"].includes(typeof ControllerType) && typeof ControllerType[method] === "function") {
995
- instance = ControllerType;
996
- handlerFunction = ControllerType[method].bind(ControllerType);
997
- bindingTarget = ControllerType;
998
- bindingMethod = method;
999
- bindingHandler = ControllerType[method];
1000
- bindingMetadata = ControllerType[Symbol.metadata];
1001
- } else if (typeof ControllerType === "function") {
1002
- instance = new ControllerType();
1003
- if (typeof instance[method] === "function") {
1004
- handlerFunction = instance[method].bind(instance);
1005
- bindingTarget = ControllerType.prototype;
1006
- bindingMethod = method;
1007
- bindingHandler = instance[method];
1008
- bindingMetadata = ControllerType[Symbol.metadata];
1009
- } else throw new Error(`Method "${method}" not found in controller instance "${ControllerType.name}"`);
1010
- } else throw new Error(`Invalid controller type for route: ${route.path}`);
1011
- } else throw new Error(`Invalid handler format for route: ${route.path}`);
1012
- return {
1013
- handlerFunction,
1014
- instance,
1015
- bindingTarget,
1016
- bindingMethod,
1017
- bindingHandler,
1018
- bindingMetadata
1019
- };
1020
- }
1021
- static async callHandler(handlerFunction, ctx, bindingTarget, bindingMethod, bindingHandler, bindingMetadata) {
1022
- return this.pluginRequestContext.run(this.createPluginRequestContext(ctx), async () => {
1023
- await this.pluginsReady();
1024
- await this.resolvePluginHttpCtx(ctx);
1025
- if (!this.config.container?.enabled) return handlerFunction(ctx, ctx.clearRequest);
1026
- const designTokens = [...bindingTarget ? getDesignParamTypes(bindingTarget, bindingMethod) : [], ...bindingHandler ? getDesignParamTypes(bindingHandler) : []];
1027
- const metadata = getBindingMetadataFromTargets([
1028
- {
1029
- target: bindingTarget,
1030
- propertyKey: bindingMethod
1031
- },
1032
- { target: bindingHandler },
1033
- {
1034
- target: bindingTarget,
1035
- propertyKey: "__class__"
1036
- }
1037
- ]) ?? getStandardMetadata(bindingMetadata, bindingMethod) ?? getStandardMetadata(bindingMetadata, "__class__");
1038
- const tokens = metadata?.tokens?.length ? metadata.tokens : designTokens;
1039
- const pluginArgs = await this.resolvePluginArguments(ctx, {
1040
- target: bindingTarget,
1041
- method: bindingMethod,
1042
- handler: bindingHandler,
1043
- metadata: bindingMetadata,
1044
- tokens,
1045
- designTokens
1046
- });
1047
- if (pluginArgs?.length) return handlerFunction(...pluginArgs);
1048
- if (!metadata || !tokens.length) return handlerFunction(ctx, ctx.clearRequest);
1049
- const args = [];
1050
- for (const token of tokens) {
1051
- const resolved = await Container.resolve(token, ctx, Boolean(this.config.container?.autoDiscover));
1052
- if (typeof resolved === "undefined") return handlerFunction(ctx, ctx.clearRequest);
1053
- args.push(resolved);
1054
- }
1055
- return handlerFunction(...args);
1056
- });
1057
- }
1058
- static bindRequestToInstance(ctx, instance, route, payload) {
1059
- const clearRequest = ctx.clearRequest instanceof Request ? ctx.clearRequest : this.initializeInstance(Request, {
1060
- ctx,
1061
- route,
1062
- body: payload.body,
1063
- query: payload.query,
1064
- params: payload.params,
1065
- method: String(payload.method || ctx.req?.method || ctx.method || "GET").toUpperCase(),
1066
- path: String(ctx.path || ctx.req?.path || ctx.req?.url || route.path),
1067
- url: String(ctx.url || ctx.req?.url || ctx.req?.originalUrl || route.path),
1068
- headers: ctx.req?.headers || ctx.headers || {},
1069
- original: ctx.req || ctx.request || ctx
1070
- });
1071
- clearRequest.ctx = ctx;
1072
- clearRequest.route = route;
1073
- clearRequest.body = payload.body;
1074
- clearRequest.query = payload.query;
1075
- clearRequest.params = payload.params;
1076
- ctx.clearRequest = clearRequest;
1077
- Container.bind(Request, ctx.clearRequest);
1078
- if (!(ctx.clearResponse instanceof Response)) {
1079
- ctx.clearResponse = this.initializeInstance(Response, ctx.response ?? ctx.reply ?? ctx.res);
1080
- Container.bind(Response, ctx.clearResponse);
1081
- }
1082
- if (!instance) return;
1083
- instance.ctx = ctx;
1084
- instance.body = payload.body;
1085
- instance.query = payload.query;
1086
- instance.params = payload.params;
1087
- instance.clearRequest = clearRequest;
1088
- }
1089
- };
1090
-
1091
- //#endregion
1092
- exports.ClearRequest = ClearRequest;
1093
- exports.Controller = Controller;
1094
- exports.CoreRouter = CoreRouter;
1095
- exports.Request = Request;
1096
- exports.Response = Response;
1097
- exports.Route = Route;
1098
- exports.definePlugin = definePlugin;
2
+ const require_ClearRequest = require('./ClearRequest.cjs');
3
+ const require_Controller = require('./Controller.cjs');
4
+ const require_Route = require('./Route.cjs');
5
+ const require_Request = require('./core/Request.cjs');
6
+ const require_Response = require('./core/Response.cjs');
7
+ const require_plugins = require('./core/plugins.cjs');
8
+ const require_router = require('./core/router.cjs');
9
+ require('./core/index.cjs');
10
+
11
+ exports.ClearRequest = require_ClearRequest.ClearRequest;
12
+ exports.Controller = require_Controller.Controller;
13
+ exports.CoreRouter = require_router.CoreRouter;
14
+ exports.Request = require_Request.Request;
15
+ exports.Response = require_Response.Response;
16
+ exports.Route = require_Route.Route;
17
+ exports.definePlugin = require_plugins.definePlugin;