@spinajs/http 2.0.486 → 2.0.487

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 (74) hide show
  1. package/README.md +370 -5
  2. package/lib/cjs/base-controller.d.ts +35 -0
  3. package/lib/cjs/base-controller.d.ts.map +1 -0
  4. package/lib/cjs/base-controller.js +100 -0
  5. package/lib/cjs/base-controller.js.map +1 -0
  6. package/lib/cjs/cache.d.ts +25 -3
  7. package/lib/cjs/cache.d.ts.map +1 -1
  8. package/lib/cjs/cache.js +26 -9
  9. package/lib/cjs/cache.js.map +1 -1
  10. package/lib/cjs/cli/GenerateControllerCache.d.ts +13 -4
  11. package/lib/cjs/cli/GenerateControllerCache.d.ts.map +1 -1
  12. package/lib/cjs/cli/GenerateControllerCache.js +37 -10
  13. package/lib/cjs/cli/GenerateControllerCache.js.map +1 -1
  14. package/lib/cjs/controller-sources.d.ts +36 -0
  15. package/lib/cjs/controller-sources.d.ts.map +1 -0
  16. package/lib/cjs/controller-sources.js +73 -0
  17. package/lib/cjs/controller-sources.js.map +1 -0
  18. package/lib/cjs/controllers.d.ts +19 -36
  19. package/lib/cjs/controllers.d.ts.map +1 -1
  20. package/lib/cjs/controllers.js +98 -302
  21. package/lib/cjs/controllers.js.map +1 -1
  22. package/lib/cjs/exceptions.d.ts +12 -0
  23. package/lib/cjs/exceptions.d.ts.map +1 -1
  24. package/lib/cjs/exceptions.js +15 -1
  25. package/lib/cjs/exceptions.js.map +1 -1
  26. package/lib/cjs/index.d.ts +4 -0
  27. package/lib/cjs/index.d.ts.map +1 -1
  28. package/lib/cjs/index.js +4 -0
  29. package/lib/cjs/index.js.map +1 -1
  30. package/lib/cjs/middlewares/RequestId.d.ts.map +1 -1
  31. package/lib/cjs/middlewares/RequestId.js +4 -0
  32. package/lib/cjs/middlewares/RequestId.js.map +1 -1
  33. package/lib/cjs/route-builder.d.ts +61 -0
  34. package/lib/cjs/route-builder.d.ts.map +1 -0
  35. package/lib/cjs/route-builder.js +228 -0
  36. package/lib/cjs/route-builder.js.map +1 -0
  37. package/lib/mjs/base-controller.d.ts +35 -0
  38. package/lib/mjs/base-controller.d.ts.map +1 -0
  39. package/lib/mjs/base-controller.js +93 -0
  40. package/lib/mjs/base-controller.js.map +1 -0
  41. package/lib/mjs/cache.d.ts +25 -3
  42. package/lib/mjs/cache.d.ts.map +1 -1
  43. package/lib/mjs/cache.js +25 -10
  44. package/lib/mjs/cache.js.map +1 -1
  45. package/lib/mjs/cli/GenerateControllerCache.d.ts +13 -4
  46. package/lib/mjs/cli/GenerateControllerCache.d.ts.map +1 -1
  47. package/lib/mjs/cli/GenerateControllerCache.js +39 -12
  48. package/lib/mjs/cli/GenerateControllerCache.js.map +1 -1
  49. package/lib/mjs/controller-sources.d.ts +36 -0
  50. package/lib/mjs/controller-sources.d.ts.map +1 -0
  51. package/lib/mjs/controller-sources.js +69 -0
  52. package/lib/mjs/controller-sources.js.map +1 -0
  53. package/lib/mjs/controllers.d.ts +19 -36
  54. package/lib/mjs/controllers.d.ts.map +1 -1
  55. package/lib/mjs/controllers.js +95 -298
  56. package/lib/mjs/controllers.js.map +1 -1
  57. package/lib/mjs/exceptions.d.ts +12 -0
  58. package/lib/mjs/exceptions.d.ts.map +1 -1
  59. package/lib/mjs/exceptions.js +12 -0
  60. package/lib/mjs/exceptions.js.map +1 -1
  61. package/lib/mjs/index.d.ts +4 -0
  62. package/lib/mjs/index.d.ts.map +1 -1
  63. package/lib/mjs/index.js +4 -0
  64. package/lib/mjs/index.js.map +1 -1
  65. package/lib/mjs/middlewares/RequestId.d.ts.map +1 -1
  66. package/lib/mjs/middlewares/RequestId.js +4 -0
  67. package/lib/mjs/middlewares/RequestId.js.map +1 -1
  68. package/lib/mjs/route-builder.d.ts +61 -0
  69. package/lib/mjs/route-builder.d.ts.map +1 -0
  70. package/lib/mjs/route-builder.js +216 -0
  71. package/lib/mjs/route-builder.js.map +1 -0
  72. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  73. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  74. package/package.json +11 -11
@@ -29,6 +29,10 @@ let RequestId = class RequestId extends interfaces_js_1.ServerMiddleware {
29
29
  before() {
30
30
  return (req, res, next) => {
31
31
  req.storage.requestId = (0, uuid_1.v4)();
32
+ // Emitted here, not in after(): ServerMiddleware after() handlers never
33
+ // run for matched controller routes ( response is flushed inside the
34
+ // controllers router without calling next() ).
35
+ res.header('x-request-id', req.storage.requestId);
32
36
  // Continue an inbound W3C traceparent ( or start a new trace ) and seed
33
37
  // traceId / spanId onto req.storage so the ambient log context merges them
34
38
  // into every log line — trace ids are shared across services.
@@ -1 +1 @@
1
- {"version":3,"file":"RequestId.js","sourceRoot":"","sources":["../../../src/middlewares/RequestId.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oDAAyE;AAEzE,+BAAoC;AACpC,oCAAyC;AACzC,sCAAiF;AAG1E,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,gCAAgB;IAC7C;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAEM,KAAK;QACV,uEAAuE;QACvE,0EAA0E;QAC1E,uEAAuE;QACvE,yEAAyE;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,MAAM;QACX,OAAO,CAAC,GAAa,EAAE,GAAqB,EAAE,IAA0B,EAAE,EAAE;YAC1E,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,IAAA,SAAM,GAAE,CAAC;YAEjC,wEAAwE;YACxE,2EAA2E;YAC3E,8DAA8D;YAC9D,MAAM,EAAE,GAAkB,IAAA,qBAAe,EAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAuB,CAAC,CAAC;YAC5F,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;YACjC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;YAE/B,oEAAoE;YACpE,0EAA0E;YAC1E,yEAAyE;YACzE,2EAA2E;YAC3E,sDAAsD;YACtD,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,IAAA,uBAAiB,EAAC,EAAE,CAAC,CAAC,CAAC;YAEjD,IAAI,EAAE,CAAC;QACT,CAAC,CAAC;IACJ,CAAC;CACF,CAAA;AAnCY,8BAAS;oBAAT,SAAS;IADrB,IAAA,eAAU,EAAC,gCAAgB,CAAC;;GAChB,SAAS,CAmCrB"}
1
+ {"version":3,"file":"RequestId.js","sourceRoot":"","sources":["../../../src/middlewares/RequestId.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oDAAyE;AAEzE,+BAAoC;AACpC,oCAAyC;AACzC,sCAAiF;AAG1E,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,gCAAgB;IAC7C;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;IAEM,KAAK;QACV,uEAAuE;QACvE,0EAA0E;QAC1E,uEAAuE;QACvE,yEAAyE;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,MAAM;QACX,OAAO,CAAC,GAAa,EAAE,GAAqB,EAAE,IAA0B,EAAE,EAAE;YAC1E,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,IAAA,SAAM,GAAE,CAAC;YAEjC,wEAAwE;YACxE,qEAAqE;YACrE,+CAA+C;YAC/C,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAElD,wEAAwE;YACxE,2EAA2E;YAC3E,8DAA8D;YAC9D,MAAM,EAAE,GAAkB,IAAA,qBAAe,EAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAuB,CAAC,CAAC;YAC5F,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;YACjC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;YAE/B,oEAAoE;YACpE,0EAA0E;YAC1E,yEAAyE;YACzE,2EAA2E;YAC3E,sDAAsD;YACtD,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,IAAA,uBAAiB,EAAC,EAAE,CAAC,CAAC,CAAC;YAEjD,IAAI,EAAE,CAAC;QACT,CAAC,CAAC;IACJ,CAAC;CACF,CAAA;AAxCY,8BAAS;oBAAT,SAAS;IADrB,IAAA,eAAU,EAAC,gCAAgB,CAAC;;GAChB,SAAS,CAwCrB"}
@@ -0,0 +1,61 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import Express from 'express';
3
+ import { IContainer } from '@spinajs/di';
4
+ import { Log } from '@spinajs/log';
5
+ import { Configuration } from '@spinajs/configuration';
6
+ import { Request as sRequest, IController, IControllerDescriptor, RouteMiddleware, IRoute, BasePolicy, IActionLocalStoregeContext } from './interfaces.js';
7
+ /**
8
+ * Controller shape needed by the route wiring helpers: the IController
9
+ * surface plus indexed access to action methods. Structural on purpose —
10
+ * avoids importing BaseController and creating a module cycle.
11
+ */
12
+ export type ControllerActionHost = IController & {
13
+ [action: string]: any;
14
+ };
15
+ /**
16
+ * Computes the final express path for a route: `/BasePath/Path`, falling back
17
+ * to the method name when the route has no explicit path, with optional
18
+ * global route prefix (`http.controllers.route.prefix`).
19
+ */
20
+ export declare function buildRoutePath(basePath: string, route: IRoute, globalPrefix?: string): string;
21
+ /**
22
+ * Resolves controller-wise + route-wise middleware descriptors into instances.
23
+ */
24
+ export declare function resolveRouteMiddlewares(descriptor: IControllerDescriptor, route: IRoute, container: IContainer): Promise<RouteMiddleware[]>;
25
+ /**
26
+ * Resolves controller-wise + route-wise policy descriptors into instances.
27
+ *
28
+ * String policy descriptors are configuration keys pointing at a policy type
29
+ * name. A key that does not resolve to a registered BasePolicy type throws
30
+ * {@link RouteRegistrationException} — a silently dropped policy would leave
31
+ * the route unprotected.
32
+ */
33
+ export declare function resolveRoutePolicies(descriptor: IControllerDescriptor, route: IRoute, container: IContainer, cfg: Configuration, log: Log, controllerName: string, path: string): Promise<BasePolicy[]>;
34
+ /**
35
+ * Express handler gating a route behind its policies.
36
+ *
37
+ * Executes all policies enabled for the route; if at least ONE policy resolves
38
+ * without error the route is allowed to execute. This allows multiple access
39
+ * paths to a resource, e.g. token access & session.
40
+ */
41
+ export declare function createPolicyGate(policies: BasePolicy[], route: IRoute, controller: IController, log: Log): Express.RequestHandler;
42
+ /**
43
+ * Wraps a middleware onBefore/onAfter action into an express handler that
44
+ * forwards both resolution and rejection to `next`.
45
+ */
46
+ export declare function wrapMiddlewareAction(source: object, action: (req: Express.Request, res: Express.Response, route: IRoute, controller: IController) => Promise<void>, route: IRoute, controller: IController): Express.RequestHandler;
47
+ /**
48
+ * Express handler invoking the controller action: extracts route arguments,
49
+ * runs the action inside the request-scoped AsyncLocalStorage context, lets
50
+ * middlewares inspect the produced Response and stores it in
51
+ * `res.locals.response` for the response pipeline. All sync and async errors
52
+ * are forwarded to `next`.
53
+ */
54
+ export declare function createActionHandler(controller: ControllerActionHost, route: IRoute, enabledMiddlewares: RouteMiddleware[], storage: AsyncLocalStorage<IActionLocalStoregeContext>): Express.RequestHandler;
55
+ /**
56
+ * Extracts route argument values for an action call. Route-arg handlers are
57
+ * resolved from DI by parameter type and executed in Priority order
58
+ * (higher first).
59
+ */
60
+ export declare function extractRouteArgs(route: IRoute, req: sRequest, res: Express.Response, controllerName: string): Promise<any[]>;
61
+ //# sourceMappingURL=route-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-builder.d.ts","sourceRoot":"","sources":["../../src/route-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,OAAO,MAAM,SAAS,CAAC;AAI9B,OAAO,EAAM,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAY,WAAW,EAAE,qBAAqB,EAAqB,eAAe,EAAE,MAAM,EAAyB,UAAU,EAAiB,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAG9N;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG;IAAE,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAmB7F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAM3I;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,qBAAqB,EACjC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,UAAU,EACrB,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,EAAE,CAAC,CAkBvB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,cAAc,CAiDjI;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,EAC9G,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,WAAW,GACtB,OAAO,CAAC,cAAc,CAgBxB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,oBAAoB,EAChC,KAAK,EAAE,MAAM,EACb,kBAAkB,EAAE,eAAe,EAAE,EACrC,OAAO,EAAE,iBAAiB,CAAC,0BAA0B,CAAC,GACrD,OAAO,CAAC,cAAc,CA2CxB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAkClI"}
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildRoutePath = buildRoutePath;
7
+ exports.resolveRouteMiddlewares = resolveRouteMiddlewares;
8
+ exports.resolveRoutePolicies = resolveRoutePolicies;
9
+ exports.createPolicyGate = createPolicyGate;
10
+ exports.wrapMiddlewareAction = wrapMiddlewareAction;
11
+ exports.createActionHandler = createActionHandler;
12
+ exports.extractRouteArgs = extractRouteArgs;
13
+ const util_1 = require("@spinajs/util");
14
+ const lodash_1 = __importDefault(require("lodash"));
15
+ const di_1 = require("@spinajs/di");
16
+ const exceptions_1 = require("@spinajs/exceptions");
17
+ const interfaces_js_1 = require("./interfaces.js");
18
+ const exceptions_js_1 = require("./exceptions.js");
19
+ /**
20
+ * Computes the final express path for a route: `/BasePath/Path`, falling back
21
+ * to the method name when the route has no explicit path, with optional
22
+ * global route prefix (`http.controllers.route.prefix`).
23
+ */
24
+ function buildRoutePath(basePath, route, globalPrefix) {
25
+ let path = '';
26
+ if (route.Path) {
27
+ if (route.Path === '/') {
28
+ path = `/${basePath}`;
29
+ }
30
+ else if (basePath === '/') {
31
+ path = `/${route.Path}`;
32
+ }
33
+ else {
34
+ path = `/${basePath}/${route.Path}`;
35
+ }
36
+ }
37
+ else {
38
+ path = `/${basePath}/${String(route.Method)}`;
39
+ }
40
+ if (globalPrefix) {
41
+ path = `/${globalPrefix}${path}`;
42
+ }
43
+ return path;
44
+ }
45
+ /**
46
+ * Resolves controller-wise + route-wise middleware descriptors into instances.
47
+ */
48
+ function resolveRouteMiddlewares(descriptor, route, container) {
49
+ return Promise.all(descriptor.Middlewares.concat(route.Middlewares || []).map((m) => {
50
+ return container.resolve(m.Type, m.Options);
51
+ }));
52
+ }
53
+ /**
54
+ * Resolves controller-wise + route-wise policy descriptors into instances.
55
+ *
56
+ * String policy descriptors are configuration keys pointing at a policy type
57
+ * name. A key that does not resolve to a registered BasePolicy type throws
58
+ * {@link RouteRegistrationException} — a silently dropped policy would leave
59
+ * the route unprotected.
60
+ */
61
+ function resolveRoutePolicies(descriptor, route, container, cfg, log, controllerName, path) {
62
+ return Promise.all(descriptor.Policies.concat(route.Policies || []).map((m) => {
63
+ if (lodash_1.default.isString(m.Type)) {
64
+ const policyType = cfg.get(m.Type);
65
+ if (!policyType || !di_1.DI.checkType(interfaces_js_1.BasePolicy, policyType)) {
66
+ throw new exceptions_js_1.RouteRegistrationException(`No policy named ${policyType ?? '<undefined>'} is registered for route ${controllerName}::${String(route.Method)} at path ${path} ( check your configuration at ${m.Type} )`);
67
+ }
68
+ log.trace(`Policy ${policyType} is used in controller ${controllerName}::${String(route.Method)} at path ${path}`);
69
+ return container.resolve(policyType, m.Options);
70
+ }
71
+ log.trace(`Policy ${m.Type.name} is used in controller ${controllerName}::${String(route.Method)} at path ${path}`);
72
+ return container.resolve(m.Type, m.Options);
73
+ }));
74
+ }
75
+ /**
76
+ * Express handler gating a route behind its policies.
77
+ *
78
+ * Executes all policies enabled for the route; if at least ONE policy resolves
79
+ * without error the route is allowed to execute. This allows multiple access
80
+ * paths to a resource, e.g. token access & session.
81
+ */
82
+ function createPolicyGate(policies, route, controller, log) {
83
+ const routeName = `${controller.constructor.name}:${String(route.Method)} ${controller.BasePath}/${String(route.Path || route.Method)}`;
84
+ return (req, _res, next) => {
85
+ // Only policies enabled for this concrete route participate in the gate.
86
+ // A route whose policies are ALL disabled has no active authorization
87
+ // check, so it is allowed through — same semantics as having no policies
88
+ // at all. Computing this up front is what prevents the request from
89
+ // hanging: `Promise.allSettled([])` resolves to `[]`, which matches
90
+ // neither the fulfilled nor the rejected branch below, so `next` would
91
+ // never be called.
92
+ const enabledPolicies = policies.filter((p) => p.isEnabled(route, controller));
93
+ if (enabledPolicies.length === 0) {
94
+ next();
95
+ return;
96
+ }
97
+ Promise.allSettled(enabledPolicies.map((p) => {
98
+ return p
99
+ .execute(req, route, controller)
100
+ .then(() => {
101
+ log.trace(`Policy succeded for route ${routeName}, policy: ${p.constructor.name}`);
102
+ })
103
+ .catch((err) => {
104
+ log.trace(`Policy failed for route ${routeName} error ${err}, policy: ${p.constructor.name}`);
105
+ throw err;
106
+ });
107
+ }))
108
+ .then((results) => {
109
+ const fullfilled = results.find((r) => r.status === 'fulfilled');
110
+ if (fullfilled) {
111
+ log.trace(`Policy for route ${routeName} succeded, continue execution`);
112
+ next();
113
+ return;
114
+ }
115
+ // Every policy rejected — forward the first failure to the express
116
+ // error handler. Use next(err) directly (not `throw next(...)`,
117
+ // which would reject this .then() with `undefined` as an unhandled
118
+ // rejection while the error was already forwarded).
119
+ const failed = results.find((r) => r.status === 'rejected');
120
+ next(failed ? failed.reason : new exceptions_1.UnexpectedServerError('Policy evaluation produced no result'));
121
+ })
122
+ // Guard against unexpected throws in the settle/handler chain so the
123
+ // request can never stall without a response.
124
+ .catch((err) => next(err));
125
+ };
126
+ }
127
+ /**
128
+ * Wraps a middleware onBefore/onAfter action into an express handler that
129
+ * forwards both resolution and rejection to `next`.
130
+ */
131
+ function wrapMiddlewareAction(source, action, route, controller) {
132
+ const wrapper = (req, res, next) => {
133
+ action(req, res, route, controller)
134
+ .then(() => {
135
+ next();
136
+ })
137
+ .catch((err) => {
138
+ next(err);
139
+ });
140
+ };
141
+ Object.defineProperty(wrapper, 'name', {
142
+ value: source.constructor.name,
143
+ writable: true,
144
+ });
145
+ return wrapper;
146
+ }
147
+ /**
148
+ * Express handler invoking the controller action: extracts route arguments,
149
+ * runs the action inside the request-scoped AsyncLocalStorage context, lets
150
+ * middlewares inspect the produced Response and stores it in
151
+ * `res.locals.response` for the response pipeline. All sync and async errors
152
+ * are forwarded to `next`.
153
+ */
154
+ function createActionHandler(controller, route, enabledMiddlewares, storage) {
155
+ const actionHandler = async (req, res, next) => {
156
+ try {
157
+ await storage.run(req.storage, async () => {
158
+ const args = (await extractRouteArgs(route, req, res, controller.constructor.name)).concat([req, res, next]);
159
+ try {
160
+ const result = controller[route.Method].call(controller, ...args);
161
+ if ((0, util_1.isPromise)(result)) {
162
+ result
163
+ .then((r) => {
164
+ if (r instanceof interfaces_js_1.Response) {
165
+ enabledMiddlewares.forEach((x) => x.onResponse(r, route, controller));
166
+ }
167
+ res.locals.response = r;
168
+ next();
169
+ })
170
+ .catch((err) => {
171
+ next(err);
172
+ });
173
+ }
174
+ else {
175
+ if (result instanceof interfaces_js_1.Response) {
176
+ enabledMiddlewares.forEach((x) => x.onResponse(result, route, controller));
177
+ }
178
+ res.locals.response = result;
179
+ next();
180
+ }
181
+ }
182
+ catch (err) {
183
+ next(err);
184
+ }
185
+ });
186
+ }
187
+ catch (err) {
188
+ next(err);
189
+ }
190
+ };
191
+ Object.defineProperty(actionHandler, 'name', {
192
+ value: controller.constructor.name,
193
+ writable: true,
194
+ });
195
+ return actionHandler;
196
+ }
197
+ /**
198
+ * Extracts route argument values for an action call. Route-arg handlers are
199
+ * resolved from DI by parameter type and executed in Priority order
200
+ * (higher first).
201
+ */
202
+ async function extractRouteArgs(route, req, res, controllerName) {
203
+ const callArgs = new Array(route.Parameters.size);
204
+ const argsCache = new Map();
205
+ let callData = {
206
+ Payload: {},
207
+ };
208
+ // Sort parameters by priority (higher priority first)
209
+ // Get all parameters as array, resolve their handlers to check priority, then sort
210
+ const paramsWithPriority = await Promise.all(Array.from(route.Parameters.values()).map(async (param) => {
211
+ const handler = await (0, util_1.tryGetHash)(argsCache, param.Type, () => di_1.DI.resolve(param.Type));
212
+ return { param, handler, priority: handler?.Priority ?? 0 };
213
+ }));
214
+ // Sort by priority descending (higher priority first)
215
+ const sortedParams = paramsWithPriority.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
216
+ for (const { param, handler: routeArgsHandler } of sortedParams) {
217
+ if (!routeArgsHandler) {
218
+ throw new exceptions_1.UnexpectedServerError(`Route parameter not registered for parameter: ${param.Name},
219
+ in method: ${String(route.Method)},
220
+ in controller: ${controllerName}. Check if you have registered it in DI container.`);
221
+ }
222
+ const { Args, CallData } = await routeArgsHandler.extract(callData, callArgs, param, req, res, route);
223
+ callData = CallData;
224
+ callArgs[param.Index] = Args;
225
+ }
226
+ return callArgs;
227
+ }
228
+ //# sourceMappingURL=route-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-builder.js","sourceRoot":"","sources":["../../src/route-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import Express from 'express';
3
+ import { AsyncService, IContainer } from '@spinajs/di';
4
+ import { Log } from '@spinajs/log';
5
+ import { DataValidator } from '@spinajs/validation';
6
+ import { Configuration } from '@spinajs/configuration';
7
+ import { IController, IControllerDescriptor, IActionLocalStoregeContext } from './interfaces.js';
8
+ export declare abstract class BaseController extends AsyncService implements IController {
9
+ /**
10
+ * Array index getter
11
+ */
12
+ [action: string]: any;
13
+ protected _router: Express.Router;
14
+ protected _container: IContainer;
15
+ protected _validator: DataValidator;
16
+ protected _log: Log;
17
+ protected _actionLocalStorage: AsyncLocalStorage<IActionLocalStoregeContext>;
18
+ protected _cfg: Configuration;
19
+ /**
20
+ * Express router with middleware stack
21
+ */
22
+ get Router(): Express.Router;
23
+ /**
24
+ * Controller descriptor
25
+ */
26
+ get Descriptor(): IControllerDescriptor;
27
+ /**
28
+ * Base path for all controller routes eg. my/custom/path/
29
+ *
30
+ * It can be defined via `@BasePath` decorator, defaults to controller name without `Controller` part.
31
+ */
32
+ get BasePath(): string;
33
+ resolve(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=base-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-controller.d.ts","sourceRoot":"","sources":["../../src/base-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAyB,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAU,GAAG,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAOjG,8BAAsB,cAAe,SAAQ,YAAa,YAAW,WAAW;IAC9E;;OAEG;IACH,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC;IAEtB,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC,MAAM,CAAC;IAGnC,SAAS,CAAC,UAAU,EAAG,UAAU,CAAC;IAGlC,SAAS,CAAC,UAAU,EAAG,aAAa,CAAC;IAGrC,SAAS,CAAC,IAAI,EAAG,GAAG,CAAC;IAGrB,SAAS,CAAC,mBAAmB,EAAG,iBAAiB,CAAC,0BAA0B,CAAC,CAAC;IAG9E,SAAS,CAAC,IAAI,EAAG,aAAa,CAAC;IAE/B;;OAEG;IACH,IAAW,MAAM,IAAI,OAAO,CAAC,MAAM,CAElC;IAED;;OAEG;IACH,IAAW,UAAU,IAAI,qBAAqB,CAE7C;IAED;;;;OAIG;IACH,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAEY,OAAO;CAsCrB"}
@@ -0,0 +1,93 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { AsyncLocalStorage } from 'node:async_hooks';
11
+ import Express from 'express';
12
+ import { AsyncService, Autoinject, Container } from '@spinajs/di';
13
+ import { Logger, Log } from '@spinajs/log';
14
+ import { DataValidator } from '@spinajs/validation';
15
+ import { Configuration } from '@spinajs/configuration';
16
+ import { CONTROLLED_DESCRIPTOR_SYMBOL } from './decorators.js';
17
+ import { RouteRegistrationException } from './exceptions.js';
18
+ import { __handle_response__ } from './response.js';
19
+ import { __handle_error__ } from './error.js';
20
+ import { buildRoutePath, resolveRouteMiddlewares, resolveRoutePolicies, createPolicyGate, createActionHandler, wrapMiddlewareAction } from './route-builder.js';
21
+ export class BaseController extends AsyncService {
22
+ /**
23
+ * Express router with middleware stack
24
+ */
25
+ get Router() {
26
+ return this._router;
27
+ }
28
+ /**
29
+ * Controller descriptor
30
+ */
31
+ get Descriptor() {
32
+ return Reflect.getMetadata(CONTROLLED_DESCRIPTOR_SYMBOL, this);
33
+ }
34
+ /**
35
+ * Base path for all controller routes eg. my/custom/path/
36
+ *
37
+ * It can be defined via `@BasePath` decorator, defaults to controller name without `Controller` part.
38
+ */
39
+ get BasePath() {
40
+ return this.Descriptor.BasePath ? this.Descriptor.BasePath : this.constructor.name.toLowerCase();
41
+ }
42
+ async resolve() {
43
+ await super.resolve();
44
+ if (!this.Descriptor) {
45
+ this._log.warn(`Controller ${this.constructor.name} does not have descriptor. If its abstract or base class ignore this message.`);
46
+ return;
47
+ }
48
+ this._router = Express.Router();
49
+ for (const [, route] of this.Descriptor.Routes) {
50
+ // Fail fast: an unknown route type means the route decorator never set a
51
+ // valid express method — mounting the rest of the controller while
52
+ // silently dropping this route would hide the bug.
53
+ if (route.InternalType === 'unknown') {
54
+ throw new RouteRegistrationException(`Unknown route type for ${this.constructor.name}::${String(route.Method)}`);
55
+ }
56
+ const path = buildRoutePath(this.BasePath, route, this._cfg.get('http.controllers.route.prefix'));
57
+ const middlewares = await resolveRouteMiddlewares(this.Descriptor, route, this._container);
58
+ const policies = await resolveRoutePolicies(this.Descriptor, route, this._container, this._cfg, this._log, this.constructor.name, path);
59
+ const enabledMiddlewares = middlewares.filter((m) => m.isEnabled(route, this));
60
+ this._log.trace(`Registering route ${route.Type.toUpperCase()} ${this.constructor.name}::${String(route.Method)} at ${path}`);
61
+ const handlers = [
62
+ createPolicyGate(policies, route, this, this._log),
63
+ ...enabledMiddlewares.map((m) => wrapMiddlewareAction(m, m.onBefore.bind(m), route, this)),
64
+ createActionHandler(this, route, enabledMiddlewares, this._actionLocalStorage),
65
+ ...enabledMiddlewares.map((m) => wrapMiddlewareAction(m, m.onAfter.bind(m), route, this)),
66
+ __handle_response__(),
67
+ __handle_error__(),
68
+ ];
69
+ this._router[route.InternalType](path, handlers);
70
+ }
71
+ }
72
+ }
73
+ __decorate([
74
+ Autoinject(Container),
75
+ __metadata("design:type", Object)
76
+ ], BaseController.prototype, "_container", void 0);
77
+ __decorate([
78
+ Autoinject(),
79
+ __metadata("design:type", DataValidator)
80
+ ], BaseController.prototype, "_validator", void 0);
81
+ __decorate([
82
+ Logger('http'),
83
+ __metadata("design:type", Log)
84
+ ], BaseController.prototype, "_log", void 0);
85
+ __decorate([
86
+ Autoinject(),
87
+ __metadata("design:type", AsyncLocalStorage)
88
+ ], BaseController.prototype, "_actionLocalStorage", void 0);
89
+ __decorate([
90
+ Autoinject(Configuration),
91
+ __metadata("design:type", Configuration)
92
+ ], BaseController.prototype, "_cfg", void 0);
93
+ //# sourceMappingURL=base-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-controller.js","sourceRoot":"","sources":["../../src/base-controller.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,YAAY,EAAc,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAwB,MAAM,oBAAoB,CAAC;AAEtL,MAAM,OAAgB,cAAe,SAAQ,YAAY;IAuBvD;;OAEG;IACH,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,IAAW,UAAU;QACnB,OAAO,OAAO,CAAC,WAAW,CAAC,4BAA4B,EAAE,IAAI,CAA0B,CAAC;IAC1F,CAAC;IAED;;;;OAIG;IACH,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACnG,CAAC;IAEM,KAAK,CAAC,OAAO;QAClB,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;QAEtB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,WAAW,CAAC,IAAI,+EAA+E,CAAC,CAAC;YACnI,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAEhC,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;YAC/C,yEAAyE;YACzE,mEAAmE;YACnE,mDAAmD;YACnD,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;gBACrC,MAAM,IAAI,0BAA0B,CAAC,0BAA0B,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnH,CAAC;YAED,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;YAElG,MAAM,WAAW,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3F,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACxI,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;YAE/E,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,qBAAqB,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAE9H,MAAM,QAAQ,GAA6D;gBACzE,gBAAgB,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;gBAClD,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;gBAC1F,mBAAmB,CAAC,IAA4B,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,CAAC,mBAAmB,CAAC;gBACtG,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;gBACzF,mBAAmB,EAAE;gBACrB,gBAAgB,EAAE;aACnB,CAAC;YAED,IAAI,CAAC,OAAe,CAAC,KAAK,CAAC,YAAsB,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;CACF;AA3EW;IADT,UAAU,CAAC,SAAS,CAAC;;kDACY;AAGxB;IADT,UAAU,EAAE;8BACU,aAAa;kDAAC;AAG3B;IADT,MAAM,CAAC,MAAM,CAAC;8BACE,GAAG;4CAAC;AAGX;IADT,UAAU,EAAE;8BACmB,iBAAiB;2DAA6B;AAGpE;IADT,UAAU,CAAC,aAAa,CAAC;8BACT,aAAa;4CAAC"}
@@ -1,7 +1,7 @@
1
1
  import ts from 'typescript';
2
2
  import { AsyncService, ClassInfo } from '@spinajs/di';
3
3
  import { fs as fFs, FileHasher } from '@spinajs/fs';
4
- import type { BaseController } from './controllers.js';
4
+ import type { BaseController } from './base-controller.js';
5
5
  import { Log } from '@spinajs/log';
6
6
  export interface IParamDoc {
7
7
  name: string;
@@ -83,8 +83,18 @@ export declare class DefaultControllerCache extends AsyncService {
83
83
  protected CacheFS: fFs;
84
84
  protected Hasher: FileHasher;
85
85
  resolve(): Promise<void>;
86
- /** Returns parameter-name map used for route argument binding. */
87
- getCache(controller: ClassInfo<BaseController>): Promise<Record<string, string[]>>;
86
+ /**
87
+ * Returns parameter-name map used for route argument binding.
88
+ *
89
+ * Cache entries are keyed by source-file content hash, so a changed file
90
+ * naturally gets a fresh entry. `options.rebuild` forces regeneration and
91
+ * overwrite even when entries for the current hash already exist — used by
92
+ * the `http:controllers:cache` CLI command to refresh a pre-built cache
93
+ * (e.g. inside a docker image build).
94
+ */
95
+ getCache(controller: ClassInfo<BaseController>, options?: {
96
+ rebuild?: boolean;
97
+ }): Promise<Record<string, string[]>>;
88
98
  /** Whether `file` points at a real on-disk source we can parse. */
89
99
  private isResolvableSource;
90
100
  /**
@@ -160,4 +170,16 @@ export declare class DefaultControllerCache extends AsyncService {
160
170
  */
161
171
  private schemaFromNamedType;
162
172
  }
173
+ /**
174
+ * Whether a ClassInfo `file` points at a real on-disk source. Bracketed
175
+ * sentinels (e.g. `<di>`, `<dynamic>`) are used by Controllers for entries
176
+ * that were never loaded from a file.
177
+ */
178
+ export declare function isOnDiskSource(file: string | undefined): boolean;
179
+ /**
180
+ * Pull parameter names from `Function.prototype.toString()` output. Modern V8
181
+ * preserves the literal signature so we can regex out `(a, b = 1, ...rest)`.
182
+ * Stripped of default values and TypeScript type annotations.
183
+ */
184
+ export declare function parseFnParamNames(fn: Function): string[];
163
185
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"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"}
package/lib/mjs/cache.js CHANGED
@@ -51,8 +51,16 @@ let DefaultControllerCache = class DefaultControllerCache extends AsyncService {
51
51
  await super.resolve();
52
52
  this.Log.info(`Controller cache dir is: ${this.CacheFS.resolvePath('')}`);
53
53
  }
54
- /** Returns parameter-name map used for route argument binding. */
55
- async getCache(controller) {
54
+ /**
55
+ * Returns parameter-name map used for route argument binding.
56
+ *
57
+ * Cache entries are keyed by source-file content hash, so a changed file
58
+ * naturally gets a fresh entry. `options.rebuild` forces regeneration and
59
+ * overwrite even when entries for the current hash already exist — used by
60
+ * the `http:controllers:cache` CLI command to refresh a pre-built cache
61
+ * (e.g. inside a docker image build).
62
+ */
63
+ async getCache(controller, options) {
56
64
  // Sentinel values like `<di>` are set by Controllers.resolve() / add() for
57
65
  // controllers registered through DI rather than a file scan. There's no
58
66
  // on-disk source to parse, so fall back to a runtime extraction of
@@ -63,8 +71,9 @@ let DefaultControllerCache = class DefaultControllerCache extends AsyncService {
63
71
  const file = resolvePath(controller.file.replace('.js', '.d.ts'));
64
72
  const hash = await this.Hasher.hash(file);
65
73
  const docHash = `doc_${hash}`;
66
- const paramExists = await this.CacheFS.exists(hash);
67
- const docExists = await this.CacheFS.exists(docHash);
74
+ const rebuild = options?.rebuild === true;
75
+ const paramExists = !rebuild && (await this.CacheFS.exists(hash));
76
+ const docExists = !rebuild && (await this.CacheFS.exists(docHash));
68
77
  if (!paramExists || !docExists) {
69
78
  this.Log.info(`Generating controller cache for ${controller.name}`);
70
79
  const { parameters, documentation } = this.extractAll(file, controller.name);
@@ -78,11 +87,7 @@ let DefaultControllerCache = class DefaultControllerCache extends AsyncService {
78
87
  }
79
88
  /** Whether `file` points at a real on-disk source we can parse. */
80
89
  isResolvableSource(file) {
81
- if (!file)
82
- return false;
83
- // Bracketed sentinels (e.g. `<di>`, `<dynamic>`) are used by Controllers
84
- // for entries that were never loaded from a file.
85
- return !(file.startsWith('<') && file.endsWith('>'));
90
+ return isOnDiskSource(file);
86
91
  }
87
92
  /**
88
93
  * Fallback: derive route method parameter names by parsing each method's
@@ -537,6 +542,16 @@ DefaultControllerCache = __decorate([
537
542
  Singleton()
538
543
  ], DefaultControllerCache);
539
544
  export { DefaultControllerCache };
545
+ /**
546
+ * Whether a ClassInfo `file` points at a real on-disk source. Bracketed
547
+ * sentinels (e.g. `<di>`, `<dynamic>`) are used by Controllers for entries
548
+ * that were never loaded from a file.
549
+ */
550
+ export function isOnDiskSource(file) {
551
+ if (!file)
552
+ return false;
553
+ return !(file.startsWith('<') && file.endsWith('>'));
554
+ }
540
555
  /** Rightmost identifier of an entity name. */
541
556
  function entityNameRight(name) {
542
557
  return ts.isIdentifier(name) ? name.text : name.right.text;
@@ -546,7 +561,7 @@ function entityNameRight(name) {
546
561
  * preserves the literal signature so we can regex out `(a, b = 1, ...rest)`.
547
562
  * Stripped of default values and TypeScript type annotations.
548
563
  */
549
- function parseFnParamNames(fn) {
564
+ export function parseFnParamNames(fn) {
550
565
  const src = Function.prototype.toString.call(fn);
551
566
  const match = src.match(/^[^(]*\(([\s\S]*?)\)/);
552
567
  if (!match)