clear-router 2.5.4 → 2.5.6

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 (56) hide show
  1. package/README.md +5 -0
  2. package/dist/bindings-CV1e5jho.d.mts +20 -0
  3. package/dist/bindings-DIanvIVd.mjs +211 -0
  4. package/dist/bindings-DvV2DXWi.cjs +253 -0
  5. package/dist/bindings-NV0CdqGl.d.cts +20 -0
  6. package/dist/core/index.cjs +12 -2
  7. package/dist/core/index.d.cts +2 -2
  8. package/dist/core/index.d.mts +2 -2
  9. package/dist/core/index.mjs +9 -2
  10. package/dist/decorators/index.cjs +5 -0
  11. package/dist/decorators/index.d.cts +2 -0
  12. package/dist/decorators/index.d.mts +2 -0
  13. package/dist/decorators/index.mjs +3 -0
  14. package/dist/decorators/setup.cjs +15 -0
  15. package/dist/decorators/setup.d.cts +2 -0
  16. package/dist/decorators/setup.d.mts +2 -0
  17. package/dist/decorators/setup.mjs +13 -0
  18. package/dist/express/index.cjs +26 -9
  19. package/dist/express/index.d.cts +1 -1
  20. package/dist/express/index.d.mts +1 -1
  21. package/dist/express/index.mjs +26 -9
  22. package/dist/fastify/index.cjs +24 -8
  23. package/dist/fastify/index.d.cts +4 -2
  24. package/dist/fastify/index.d.mts +4 -2
  25. package/dist/fastify/index.mjs +24 -8
  26. package/dist/h3/index.cjs +26 -9
  27. package/dist/h3/index.d.cts +1 -1
  28. package/dist/h3/index.d.mts +1 -1
  29. package/dist/h3/index.mjs +26 -9
  30. package/dist/hono/index.cjs +28 -11
  31. package/dist/hono/index.d.cts +4 -2
  32. package/dist/hono/index.d.mts +4 -2
  33. package/dist/hono/index.mjs +28 -11
  34. package/dist/index.cjs +308 -28
  35. package/dist/index.d.cts +112 -18
  36. package/dist/index.d.mts +112 -18
  37. package/dist/index.mjs +305 -28
  38. package/dist/koa/index.cjs +24 -8
  39. package/dist/koa/index.d.cts +4 -2
  40. package/dist/koa/index.d.mts +4 -2
  41. package/dist/koa/index.mjs +24 -8
  42. package/dist/{responses-B-UirWFf.cjs → responses-JzXstGU5.cjs} +18 -1
  43. package/dist/{responses-CJaD0ugv.mjs → responses-_II3dOJ5.mjs} +19 -1
  44. package/dist/{router-BReOXz-F.mjs → router-B3QjblRX.mjs} +159 -48
  45. package/dist/{router-CS_2XQ7I.d.cts → router-BYZmNzrZ.d.cts} +97 -12
  46. package/dist/{router-CHg0pZUO.cjs → router-CU4V1kX0.cjs} +159 -48
  47. package/dist/{router-_w2VzMQF.d.mts → router-DCMtQ_Xi.d.mts} +96 -11
  48. package/dist/types/basic.d.mts +7 -0
  49. package/dist/types/core/Request.d.mts +25 -0
  50. package/dist/types/core/Response.d.mts +21 -0
  51. package/dist/types/express.d.mts +5 -2
  52. package/dist/types/fastify.d.mts +5 -2
  53. package/dist/types/h3.d.mts +5 -2
  54. package/dist/types/hono.d.mts +5 -2
  55. package/dist/types/koa.d.mts +5 -2
  56. package/package.json +16 -2
@@ -1,5 +1,6 @@
1
- import { t as CoreRouter } from "../router-BReOXz-F.mjs";
2
- import { n as resolveResponseMeta } from "../responses-CJaD0ugv.mjs";
1
+ import "../bindings-DIanvIVd.mjs";
2
+ import { t as CoreRouter } from "../router-B3QjblRX.mjs";
3
+ import { n as resolveResponseMeta } from "../responses-_II3dOJ5.mjs";
3
4
 
4
5
  //#region src/hono/router.ts
5
6
  /**
@@ -19,9 +20,13 @@ var Router = class Router extends CoreRouter {
19
20
  });
20
21
  if (!meta) return void 0;
21
22
  if (meta.isNativeResponse) return meta.body;
22
- if (meta.isEmpty) return ctx.body(null, meta.status);
23
- if (meta.contentType?.startsWith("application/json")) return ctx.json(meta.body, meta.status);
24
- return ctx.body(meta.body, meta.status, meta.contentType ? { "Content-Type": meta.contentType } : void 0);
23
+ const headers = meta.headers ? {} : meta.contentType ? { "Content-Type": meta.contentType } : void 0;
24
+ meta.headers?.forEach((headerValue, key) => {
25
+ if (headers) headers[key] = headerValue;
26
+ });
27
+ if (meta.isEmpty) return ctx.body(null, meta.status, headers);
28
+ if (meta.contentType?.startsWith("application/json")) return ctx.body(JSON.stringify(meta.body), meta.status, headers);
29
+ return ctx.body(meta.body, meta.status, headers);
25
30
  }
26
31
  static getParams(ctx) {
27
32
  try {
@@ -168,10 +173,18 @@ var Router = class Router extends CoreRouter {
168
173
  for (const route of this.routes) {
169
174
  let handlerFunction = null;
170
175
  let instance = null;
176
+ let bindingTarget;
177
+ let bindingMethod;
178
+ let bindingHandler;
179
+ let bindingMetadata;
171
180
  try {
172
181
  const resolved = this.resolveHandler(route);
173
182
  handlerFunction = resolved.handlerFunction;
174
183
  instance = resolved.instance;
184
+ bindingTarget = resolved.bindingTarget;
185
+ bindingMethod = resolved.bindingMethod;
186
+ bindingHandler = resolved.bindingHandler;
187
+ bindingMetadata = resolved.bindingMetadata;
175
188
  } catch (error) {
176
189
  console.error(`[ROUTES] Error setting up route ${route.path}:`, error.message);
177
190
  throw error;
@@ -198,11 +211,13 @@ var Router = class Router extends CoreRouter {
198
211
  Router.bindRequestToInstance(ctx, inst, route, {
199
212
  body: reqBody,
200
213
  query: ctx.req.query(),
201
- params: Router.getParams(ctx)
214
+ params: Router.getParams(ctx),
215
+ method
202
216
  });
203
- const result = handlerFunction(ctx, inst.clearRequest);
217
+ const result = await Router.callHandler(handlerFunction, ctx, bindingTarget, bindingMethod, bindingHandler, bindingMetadata);
204
218
  const resolved = await Promise.resolve(result);
205
- return Router.toResponse(ctx, resolved, method, route.path);
219
+ const outgoing = typeof resolved === "undefined" && ctx.clearResponse?.sent ? ctx.clearResponse : resolved;
220
+ return Router.toResponse(ctx, outgoing, method, route.path);
206
221
  });
207
222
  if ([
208
223
  "put",
@@ -216,11 +231,13 @@ var Router = class Router extends CoreRouter {
216
231
  Router.bindRequestToInstance(ctx, inst, route, {
217
232
  body: reqBody,
218
233
  query: ctx.req.query(),
219
- params: Router.getParams(ctx)
234
+ params: Router.getParams(ctx),
235
+ method
220
236
  });
221
- const result = handlerFunction(ctx, inst.clearRequest);
237
+ const result = await Router.callHandler(handlerFunction, ctx, bindingTarget, bindingMethod, bindingHandler, bindingMetadata);
222
238
  const resolved = await Promise.resolve(result);
223
- return Router.toResponse(ctx, resolved, method, route.path);
239
+ const outgoing = typeof resolved === "undefined" && ctx.clearResponse?.sent ? ctx.clearResponse : resolved;
240
+ return Router.toResponse(ctx, outgoing, method, route.path);
224
241
  });
225
242
  }
226
243
  }
package/dist/index.cjs CHANGED
@@ -59,6 +59,152 @@ var Route = class {
59
59
  }
60
60
  };
61
61
 
62
+ //#endregion
63
+ //#region src/core/Request.ts
64
+ var Request = class extends ClearRequest {
65
+ original;
66
+ method = "GET";
67
+ path = "/";
68
+ url = "/";
69
+ headers = {};
70
+ constructor(init) {
71
+ super(init);
72
+ Object.assign(this, init);
73
+ }
74
+ getBody() {
75
+ return this.body ?? {};
76
+ }
77
+ header(name) {
78
+ if (typeof this.headers.get === "function") return this.headers.get(name) || "";
79
+ const headers = this.headers;
80
+ const value = headers[name] ?? headers[name.toLowerCase()];
81
+ return Array.isArray(value) ? String(value[0] ?? "") : String(value ?? "");
82
+ }
83
+ param(name) {
84
+ return this.params?.[name];
85
+ }
86
+ input(name) {
87
+ return this.body?.[name] ?? this.query?.[name] ?? this.params?.[name];
88
+ }
89
+ is(method) {
90
+ return this.method.toLowerCase() === String(method).toLowerCase();
91
+ }
92
+ };
93
+
94
+ //#endregion
95
+ //#region src/core/Response.ts
96
+ var Response = class {
97
+ body;
98
+ headers = new Headers();
99
+ sent = false;
100
+ statusCode = 200;
101
+ constructor(init) {
102
+ Object.assign(this, init);
103
+ if (init?.headers && !(init.headers instanceof Headers)) this.headers = new Headers(init.headers);
104
+ }
105
+ status(code) {
106
+ this.statusCode = code;
107
+ return this;
108
+ }
109
+ code(code) {
110
+ return this.status(code);
111
+ }
112
+ setHeader(name, value) {
113
+ this.headers.set(name, value);
114
+ return this;
115
+ }
116
+ header(name, value) {
117
+ return this.setHeader(name, value);
118
+ }
119
+ set(name, value) {
120
+ return this.setHeader(name, value);
121
+ }
122
+ type(contentType) {
123
+ return this.setHeader("Content-Type", contentType);
124
+ }
125
+ send(body) {
126
+ this.body = body;
127
+ this.sent = true;
128
+ return this;
129
+ }
130
+ json(body) {
131
+ return this.type("application/json; charset=utf-8").send(body);
132
+ }
133
+ html(body) {
134
+ return this.type("text/html; charset=utf-8").send(body);
135
+ }
136
+ text(body) {
137
+ return this.type("text/plain; charset=utf-8").send(body);
138
+ }
139
+ noContent() {
140
+ return this.status(204).send(null);
141
+ }
142
+ };
143
+
144
+ //#endregion
145
+ //#region src/core/plugins.ts
146
+ function definePlugin(plugin) {
147
+ return plugin;
148
+ }
149
+
150
+ //#endregion
151
+ //#region src/core/bindings.ts
152
+ const metadataKey = Symbol.for("clear-router:binding-metadata");
153
+ const bindings = /* @__PURE__ */ new WeakMap();
154
+ var Container = class {
155
+ static registry = /* @__PURE__ */ new Map();
156
+ static bind(token, value) {
157
+ this.registry.set(token, value);
158
+ }
159
+ static unbind(token) {
160
+ this.registry.delete(token);
161
+ }
162
+ static clear() {
163
+ this.registry.clear();
164
+ }
165
+ static has(token) {
166
+ return this.registry.has(token);
167
+ }
168
+ static async resolve(token, ctx, autoDiscover = false) {
169
+ if (token === Request) return ctx.clearRequest;
170
+ if (token === Response) return ctx.clearResponse;
171
+ if (this.registry.has(token)) return this.resolveBinding(this.registry.get(token), ctx, autoDiscover);
172
+ if (autoDiscover && typeof token === "function") return new token();
173
+ }
174
+ static async resolveBinding(binding, ctx, autoDiscover) {
175
+ if (!binding) return void 0;
176
+ if (typeof binding !== "function") return binding;
177
+ if (isClass(binding)) return new binding();
178
+ const resolved = await binding(ctx);
179
+ if (typeof resolved === "function" && autoDiscover && isClass(resolved)) return new resolved();
180
+ return resolved;
181
+ }
182
+ };
183
+ function getStandardMetadata(metadata, propertyKey) {
184
+ const store = metadata && metadata[metadataKey];
185
+ if (!store) return void 0;
186
+ return propertyKey ? store[propertyKey] : void 0;
187
+ }
188
+ function getBindingMetadataFromTargets(targets) {
189
+ for (const { target, propertyKey } of targets) {
190
+ if (!target) continue;
191
+ const metadata = getBindingMetadata(target, propertyKey);
192
+ if (metadata) return metadata;
193
+ const standardMetadata = getStandardMetadata(target[Symbol.metadata], propertyKey);
194
+ if (standardMetadata) return standardMetadata;
195
+ }
196
+ }
197
+ function getBindingMetadata(target, propertyKey) {
198
+ if (propertyKey) return bindings.get(target)?.get(propertyKey);
199
+ return bindings.get(target)?.get("__route_handler__");
200
+ }
201
+ function getDesignParamTypes(target, propertyKey) {
202
+ return Reflect.getMetadata?.("design:paramtypes", target, propertyKey) ?? [];
203
+ }
204
+ function isClass(value) {
205
+ return typeof value === "function" && /^class\s/.test(Function.prototype.toString.call(value));
206
+ }
207
+
62
208
  //#endregion
63
209
  //#region src/core/router.ts
64
210
  /**
@@ -71,6 +217,41 @@ var CoreRouter = class {
71
217
  static routerStateNamespace = "clear-router:core";
72
218
  static stateStoreKey = Symbol.for("clear-router:router-state");
73
219
  static stateBoundKey = Symbol.for("clear-router:router-state-bound");
220
+ static defaultConfigKey = Symbol.for("clear-router:default-config");
221
+ static pluginStoreKey = Symbol.for("clear-router:plugins");
222
+ static createBaseConfig() {
223
+ return {
224
+ methodOverride: {
225
+ enabled: true,
226
+ bodyKeys: ["_method"],
227
+ headerKeys: ["x-http-method"]
228
+ },
229
+ container: {
230
+ enabled: false,
231
+ autoDiscover: false
232
+ }
233
+ };
234
+ }
235
+ static mergeConfig(target, source) {
236
+ if (!source) return target;
237
+ if (source.methodOverride) target.methodOverride = {
238
+ ...target.methodOverride || {},
239
+ ...source.methodOverride
240
+ };
241
+ if (source.container) target.container = {
242
+ ...target.container || {},
243
+ ...source.container
244
+ };
245
+ return target;
246
+ }
247
+ static getDefaultConfig() {
248
+ const g = globalThis;
249
+ if (!g[this.defaultConfigKey]) g[this.defaultConfigKey] = this.createBaseConfig();
250
+ return {
251
+ methodOverride: { ...g[this.defaultConfigKey].methodOverride },
252
+ container: { ...g[this.defaultConfigKey].container }
253
+ };
254
+ }
74
255
  static resolveStateNamespace() {
75
256
  return String(this.routerStateNamespace || this.name || "clear-router:core");
76
257
  }
@@ -79,13 +260,14 @@ var CoreRouter = class {
79
260
  if (!g[this.stateStoreKey]) g[this.stateStoreKey] = Object.create(null);
80
261
  return g[this.stateStoreKey];
81
262
  }
263
+ static getPluginStore() {
264
+ const g = globalThis;
265
+ if (!g[this.pluginStoreKey]) g[this.pluginStoreKey] = /* @__PURE__ */ new Set();
266
+ return g[this.pluginStoreKey];
267
+ }
82
268
  static createDefaultState() {
83
269
  return {
84
- config: { methodOverride: {
85
- enabled: true,
86
- bodyKeys: ["_method"],
87
- headerKeys: ["x-http-method"]
88
- } },
270
+ config: this.getDefaultConfig(),
89
271
  groupContext: new node_async_hooks.AsyncLocalStorage(),
90
272
  routes: [],
91
273
  routesByPathMethod: {},
@@ -162,11 +344,47 @@ var CoreRouter = class {
162
344
  }
163
345
  };
164
346
  }
165
- static config = { methodOverride: {
166
- enabled: true,
167
- bodyKeys: ["_method"],
168
- headerKeys: ["x-http-method"]
169
- } };
347
+ static config = {
348
+ methodOverride: {
349
+ enabled: true,
350
+ bodyKeys: ["_method"],
351
+ headerKeys: ["x-http-method"]
352
+ },
353
+ container: {
354
+ enabled: false,
355
+ autoDiscover: false
356
+ }
357
+ };
358
+ static configureDefaults(options) {
359
+ const g = globalThis;
360
+ const defaults = this.mergeConfig(g[this.defaultConfigKey] || this.createBaseConfig(), options);
361
+ g[this.defaultConfigKey] = defaults;
362
+ const store = this.getStateStore();
363
+ for (const state of Object.values(store)) state.config = this.mergeConfig(state.config || this.createBaseConfig(), options);
364
+ }
365
+ /**
366
+ * Use a registered plugin
367
+ *
368
+ * @param this
369
+ * @param plugin
370
+ * @param options
371
+ * @returns
372
+ */
373
+ static use(plugin, options) {
374
+ const name = typeof plugin === "function" ? plugin.name : plugin.name;
375
+ const store = this.getPluginStore();
376
+ if (name && store.has(name)) return;
377
+ const ctx = {
378
+ container: Container,
379
+ bind: Container.bind.bind(Container),
380
+ configure: this.configure.bind(this),
381
+ configureDefaults: this.configureDefaults.bind(this),
382
+ options
383
+ };
384
+ if (typeof plugin === "function") plugin(ctx);
385
+ else plugin.setup(ctx);
386
+ if (name) store.add(name);
387
+ }
170
388
  static groupContext = new node_async_hooks.AsyncLocalStorage();
171
389
  static routes = [];
172
390
  static routesByPathMethod = {};
@@ -208,11 +426,12 @@ var CoreRouter = class {
208
426
  */
209
427
  static configure(options) {
210
428
  this.ensureState();
211
- if (!this.config.methodOverride) this.config.methodOverride = {
212
- enabled: true,
213
- bodyKeys: ["_method"],
214
- headerKeys: ["x-http-method"]
215
- };
429
+ this.config = this.mergeConfig(this.getDefaultConfig(), this.config);
430
+ const container = options?.container;
431
+ if (container) {
432
+ if (typeof container.enabled === "boolean") this.config.container.enabled = container.enabled;
433
+ if (typeof container.autoDiscover === "boolean") this.config.container.autoDiscover = container.autoDiscover;
434
+ }
216
435
  const override = options?.methodOverride;
217
436
  if (!override) return;
218
437
  if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
@@ -449,36 +668,94 @@ var CoreRouter = class {
449
668
  static resolveHandler(route) {
450
669
  let handlerFunction;
451
670
  let instance = null;
452
- if (typeof route.handler === "function") handlerFunction = route.handler.bind(route);
453
- else if (Array.isArray(route.handler) && route.handler.length === 2) {
671
+ let bindingTarget;
672
+ let bindingMethod;
673
+ let bindingHandler;
674
+ let bindingMetadata;
675
+ if (typeof route.handler === "function") {
676
+ handlerFunction = route.handler.bind(route);
677
+ bindingTarget = route.handler;
678
+ bindingHandler = route.handler;
679
+ } else if (Array.isArray(route.handler) && route.handler.length === 2) {
454
680
  const [ControllerType, method] = route.handler;
455
681
  if (["function", "object"].includes(typeof ControllerType) && typeof ControllerType[method] === "function") {
456
682
  instance = ControllerType;
457
683
  handlerFunction = ControllerType[method].bind(ControllerType);
684
+ bindingTarget = ControllerType;
685
+ bindingMethod = method;
686
+ bindingHandler = ControllerType[method];
687
+ bindingMetadata = ControllerType[Symbol.metadata];
458
688
  } else if (typeof ControllerType === "function") {
459
689
  instance = new ControllerType();
460
- if (typeof instance[method] === "function") handlerFunction = instance[method].bind(instance);
461
- else throw new Error(`Method "${method}" not found in controller instance "${ControllerType.name}"`);
690
+ if (typeof instance[method] === "function") {
691
+ handlerFunction = instance[method].bind(instance);
692
+ bindingTarget = ControllerType.prototype;
693
+ bindingMethod = method;
694
+ bindingHandler = instance[method];
695
+ bindingMetadata = ControllerType[Symbol.metadata];
696
+ } else throw new Error(`Method "${method}" not found in controller instance "${ControllerType.name}"`);
462
697
  } else throw new Error(`Invalid controller type for route: ${route.path}`);
463
698
  } else throw new Error(`Invalid handler format for route: ${route.path}`);
464
699
  return {
465
700
  handlerFunction,
466
- instance
701
+ instance,
702
+ bindingTarget,
703
+ bindingMethod,
704
+ bindingHandler,
705
+ bindingMetadata
467
706
  };
468
707
  }
708
+ static async callHandler(handlerFunction, ctx, bindingTarget, bindingMethod, bindingHandler, bindingMetadata) {
709
+ if (!this.config.container?.enabled) return handlerFunction(ctx, ctx.clearRequest);
710
+ const metadata = getBindingMetadataFromTargets([
711
+ {
712
+ target: bindingTarget,
713
+ propertyKey: bindingMethod
714
+ },
715
+ { target: bindingHandler },
716
+ {
717
+ target: bindingTarget,
718
+ propertyKey: "__class__"
719
+ }
720
+ ]) ?? getStandardMetadata(bindingMetadata, bindingMethod) ?? getStandardMetadata(bindingMetadata, "__class__");
721
+ if (!metadata) return handlerFunction(ctx, ctx.clearRequest);
722
+ const designTokens = [...bindingTarget ? getDesignParamTypes(bindingTarget, bindingMethod) : [], ...bindingHandler ? getDesignParamTypes(bindingHandler) : []];
723
+ const tokens = metadata.tokens?.length ? metadata.tokens : designTokens;
724
+ if (!tokens.length) return handlerFunction(ctx, ctx.clearRequest);
725
+ const args = [];
726
+ for (const token of tokens) {
727
+ const resolved = await Container.resolve(token, ctx, Boolean(this.config.container?.autoDiscover));
728
+ if (typeof resolved === "undefined") return handlerFunction(ctx, ctx.clearRequest);
729
+ args.push(resolved);
730
+ }
731
+ return handlerFunction(...args);
732
+ }
469
733
  static bindRequestToInstance(ctx, instance, route, payload) {
734
+ const clearRequest = ctx.clearRequest instanceof Request ? ctx.clearRequest : new Request({
735
+ ctx,
736
+ route,
737
+ body: payload.body,
738
+ query: payload.query,
739
+ params: payload.params,
740
+ method: String(payload.method || ctx.req?.method || ctx.method || "GET").toUpperCase(),
741
+ path: String(ctx.path || ctx.req?.path || ctx.req?.url || route.path),
742
+ url: String(ctx.url || ctx.req?.url || ctx.req?.originalUrl || route.path),
743
+ headers: ctx.req?.headers || ctx.headers || {},
744
+ original: ctx.req || ctx.request || ctx
745
+ });
746
+ clearRequest.ctx = ctx;
747
+ clearRequest.route = route;
748
+ clearRequest.body = payload.body;
749
+ clearRequest.query = payload.query;
750
+ clearRequest.params = payload.params;
751
+ ctx.clearRequest = clearRequest;
752
+ if (!(ctx.clearResponse instanceof Response)) ctx.clearResponse = new Response();
470
753
  if (!instance) return;
471
754
  instance.ctx = ctx;
472
755
  instance.body = payload.body;
473
756
  instance.query = payload.query;
474
757
  instance.params = payload.params;
475
- instance.clearRequest = new ClearRequest({
476
- ctx,
477
- route,
478
- body: instance.body,
479
- query: instance.query,
480
- params: instance.params
481
- });
758
+ instance.clearRequest = clearRequest;
482
759
  }
483
760
  };
484
761
 
@@ -486,4 +763,7 @@ var CoreRouter = class {
486
763
  exports.ClearRequest = ClearRequest;
487
764
  exports.Controller = Controller;
488
765
  exports.CoreRouter = CoreRouter;
489
- exports.Route = Route;
766
+ exports.Request = Request;
767
+ exports.Response = Response;
768
+ exports.Route = Route;
769
+ exports.definePlugin = definePlugin;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { NextFunction, Request, Response as Response$1 } from "express";
2
- import { Middleware } from "h3";
1
+ import { NextFunction, Request as Request$1, Response as Response$2 } from "express";
2
+ import { Middleware as Middleware$1 } from "h3";
3
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
4
 
5
5
  //#region types/basic.d.ts
@@ -26,16 +26,37 @@ interface RouterConfig {
26
26
  bodyKeys?: string[] | string; /** Keys in the request headers to check for method override */
27
27
  headerKeys?: string[] | string;
28
28
  };
29
+ /**
30
+ * Optional method binding / container resolution support. Disabled by default.
31
+ */
32
+ container?: {
33
+ /** Whether decorated handler parameter binding is enabled */enabled?: boolean; /** Whether unknown constructor tokens should be instantiated automatically */
34
+ autoDiscover?: boolean;
35
+ };
29
36
  }
30
37
  //#endregion
31
- //#region types/express.d.ts
32
- /**
33
- * Middleware function type
34
- */
35
- type Middleware$1 = (req: Request, res: Response$1, next: NextFunction) => any | Promise<any>;
38
+ //#region src/core/Response.d.ts
39
+ declare class Response$1 {
40
+ body: any;
41
+ headers: Headers;
42
+ sent: boolean;
43
+ statusCode: number;
44
+ constructor(init?: Partial<Response$1>);
45
+ status(code: number): this;
46
+ code(code: number): this;
47
+ setHeader(name: string, value: string): this;
48
+ header(name: string, value: string): this;
49
+ set(name: string, value: string): this;
50
+ type(contentType: string): this;
51
+ send(body?: any): this;
52
+ json(body: any): this;
53
+ html(body: string): this;
54
+ text(body: string): this;
55
+ noContent(): this;
56
+ }
36
57
  //#endregion
37
58
  //#region src/Route.d.ts
38
- declare class Route<X = any, M = Middleware | Middleware$1, H = any> {
59
+ declare class Route<X = any, M = Middleware$1 | Middleware, H = any> {
39
60
  ctx: X;
40
61
  body: RequestData;
41
62
  query: RequestData;
@@ -52,8 +73,34 @@ declare class Route<X = any, M = Middleware | Middleware$1, H = any> {
52
73
  constructor(methods: HttpMethod[], path: string, handler: H, middlewares?: M[]);
53
74
  }
54
75
  //#endregion
76
+ //#region src/core/Request.d.ts
77
+ declare class Request<X = any, M = any> extends ClearRequest<X, M> {
78
+ original?: any;
79
+ method: string;
80
+ path: string;
81
+ url: string;
82
+ headers: Headers | Record<string, any>;
83
+ constructor(init?: Partial<Request<X, M>> & {
84
+ body?: RequestData;
85
+ query?: RequestData;
86
+ params?: RequestData;
87
+ route?: Route<X, M>;
88
+ });
89
+ getBody(): RequestData;
90
+ header(name: string): string;
91
+ param(name: string): any;
92
+ input(name: string): any;
93
+ is(method: HttpMethod | string): boolean;
94
+ }
95
+ //#endregion
96
+ //#region types/express.d.ts
97
+ /**
98
+ * Middleware function type
99
+ */
100
+ type Middleware = (req: Request$1, res: Response$2, next: NextFunction) => any | Promise<any>;
101
+ //#endregion
55
102
  //#region src/ClearRequest.d.ts
56
- declare class ClearRequest<X = any, M = Middleware | Middleware$1> {
103
+ declare class ClearRequest<X = any, M = Middleware$1 | Middleware> {
57
104
  [key: string]: any;
58
105
  /**
59
106
  * @param body - Parsed request body
@@ -81,6 +128,37 @@ declare abstract class Controller<X = any> {
81
128
  clearRequest: ClearRequest;
82
129
  }
83
130
  //#endregion
131
+ //#region src/core/bindings.d.ts
132
+ type BindToken<T = any> = abstract new (...args: any[]) => T;
133
+ type BindFactory<T = any> = (ctx: any) => T | Promise<T>;
134
+ type BindValue<T = any> = T | BindFactory<T> | BindToken<T>;
135
+ declare class Container {
136
+ private static readonly registry;
137
+ static bind<T>(token: BindToken<T>, value: BindValue<T>): void;
138
+ static unbind<T>(token: BindToken<T>): void;
139
+ static clear(): void;
140
+ static has<T>(token: BindToken<T>): boolean;
141
+ static resolve<T>(token: BindToken<T>, ctx: any, autoDiscover?: boolean): Promise<T | undefined>;
142
+ private static resolveBinding;
143
+ }
144
+ //#endregion
145
+ //#region src/core/plugins.d.ts
146
+ type PluginSetupResult = void;
147
+ type PluginBind = <T>(token: BindToken<T>, value: BindValue<T>) => void;
148
+ interface ClearRouterPluginContext<Options = any> {
149
+ container: typeof Container;
150
+ bind: PluginBind;
151
+ configure: (options: RouterConfig) => void;
152
+ configureDefaults: (options: RouterConfig) => void;
153
+ options: Options;
154
+ }
155
+ interface ClearRouterPlugin<Options = any> {
156
+ name?: string;
157
+ setup: (ctx: ClearRouterPluginContext<Options>) => PluginSetupResult;
158
+ }
159
+ type ClearRouterPluginInput<Options = any> = ClearRouterPlugin<Options> | ((ctx: ClearRouterPluginContext<Options>) => PluginSetupResult);
160
+ declare function definePlugin<Options = any>(plugin: ClearRouterPlugin<Options>): ClearRouterPlugin<Options>;
161
+ //#endregion
84
162
  //#region src/core/router.d.ts
85
163
  /**
86
164
  * @class clear-router CoreRouter
@@ -92,16 +170,16 @@ declare abstract class CoreRouter {
92
170
  protected static routerStateNamespace: string;
93
171
  private static readonly stateStoreKey;
94
172
  private static readonly stateBoundKey;
173
+ private static readonly defaultConfigKey;
174
+ private static readonly pluginStoreKey;
175
+ protected static createBaseConfig(): RouterConfig;
176
+ protected static mergeConfig(target: RouterConfig, source?: RouterConfig): RouterConfig;
177
+ protected static getDefaultConfig(): RouterConfig;
95
178
  protected static resolveStateNamespace(this: any): string;
96
179
  protected static getStateStore(): Record<string, any>;
180
+ protected static getPluginStore(): Set<string>;
97
181
  protected static createDefaultState(): {
98
- config: {
99
- methodOverride: {
100
- enabled: boolean;
101
- bodyKeys: string[];
102
- headerKeys: string[];
103
- };
104
- };
182
+ config: RouterConfig;
105
183
  groupContext: AsyncLocalStorage<{
106
184
  prefix: string;
107
185
  groupMiddlewares: any[];
@@ -116,6 +194,16 @@ declare abstract class CoreRouter {
116
194
  protected static bindStateAccessors(this: any): void;
117
195
  protected static createDefaultOptionsHandler(): any;
118
196
  static config: RouterConfig;
197
+ static configureDefaults(this: any, options?: RouterConfig): void;
198
+ /**
199
+ * Use a registered plugin
200
+ *
201
+ * @param this
202
+ * @param plugin
203
+ * @param options
204
+ * @returns
205
+ */
206
+ static use<Options = any>(this: any, plugin: ClearRouterPluginInput<Options>, options?: Options): void;
119
207
  protected static groupContext: AsyncLocalStorage<{
120
208
  prefix: string;
121
209
  groupMiddlewares: any[];
@@ -265,14 +353,20 @@ declare abstract class CoreRouter {
265
353
  */
266
354
  static allRoutes(this: any, type: 'method'): { [method in Uppercase<HttpMethod>]?: Array<Route<any, any, any>> };
267
355
  protected static resolveHandler(route: Route<any, any, any>): {
268
- handlerFunction: ((ctx: any, req: ClearRequest) => any | Promise<any>) | null;
356
+ handlerFunction: ((ctx: any, req: Request) => any | Promise<any>) | null;
269
357
  instance: Controller<any> | null;
358
+ bindingTarget?: object;
359
+ bindingMethod?: PropertyKey;
360
+ bindingHandler?: object;
361
+ bindingMetadata?: object;
270
362
  };
363
+ protected static callHandler(this: any, handlerFunction: (ctx: any, req: Request) => any | Promise<any>, ctx: any, bindingTarget?: object, bindingMethod?: PropertyKey, bindingHandler?: object, bindingMetadata?: object): Promise<any>;
271
364
  protected static bindRequestToInstance(ctx: any, instance: Controller<any> | Route<any, any, any> | null, route: Route<any, any, any>, payload: {
272
365
  body: Record<string, any>;
273
366
  query: Record<string, any>;
274
367
  params: Record<string, any>;
368
+ method?: HttpMethod | string;
275
369
  }): void;
276
370
  }
277
371
  //#endregion
278
- export { ClearRequest, Controller, CoreRouter, Route };
372
+ export { ClearRequest, ClearRouterPlugin, ClearRouterPluginContext, ClearRouterPluginInput, Controller, CoreRouter, PluginBind, PluginSetupResult, Request, Response$1 as Response, Route, definePlugin };