@decohere/http 0.0.1-dev.130 → 0.0.1-dev.20261105.103

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 (70) hide show
  1. package/es6/src/routing/services/route-registry.js +5 -0
  2. package/package.json +9 -14
  3. package/commonjs/src/app/app.js +0 -166
  4. package/commonjs/src/app/index.js +0 -19
  5. package/commonjs/src/app/module.js +0 -17
  6. package/commonjs/src/auth/ability.js +0 -54
  7. package/commonjs/src/auth/auth.config.js +0 -23
  8. package/commonjs/src/auth/auth.extensions.js +0 -106
  9. package/commonjs/src/auth/auth.types.js +0 -65
  10. package/commonjs/src/auth/casl-authorization.service.js +0 -36
  11. package/commonjs/src/auth/index.js +0 -23
  12. package/commonjs/src/auth/principal-provider.js +0 -19
  13. package/commonjs/src/auth/safe-outbound-url.js +0 -102
  14. package/commonjs/src/auth/token-service.js +0 -151
  15. package/commonjs/src/builder/builder.js +0 -95
  16. package/commonjs/src/builder/index.js +0 -18
  17. package/commonjs/src/const.js +0 -86
  18. package/commonjs/src/health/health.controller.js +0 -75
  19. package/commonjs/src/health/health.extensions.js +0 -50
  20. package/commonjs/src/health/index.js +0 -21
  21. package/commonjs/src/health/readiness.service.js +0 -67
  22. package/commonjs/src/health/readiness.types.js +0 -7
  23. package/commonjs/src/hosting/hosted-service-host.js +0 -88
  24. package/commonjs/src/hosting/hosted-service.js +0 -11
  25. package/commonjs/src/hosting/index.js +0 -19
  26. package/commonjs/src/http/http.compression.js +0 -27
  27. package/commonjs/src/http/http.extensions.js +0 -269
  28. package/commonjs/src/http/http.options.js +0 -26
  29. package/commonjs/src/http/http.options.store.js +0 -20
  30. package/commonjs/src/http/http.security.js +0 -27
  31. package/commonjs/src/http/http.static.js +0 -248
  32. package/commonjs/src/http/index.js +0 -22
  33. package/commonjs/src/index.js +0 -27
  34. package/commonjs/src/openapi/index.js +0 -45
  35. package/commonjs/src/openapi/openapi.generator.js +0 -103
  36. package/commonjs/src/openapi/openapi.types.js +0 -4
  37. package/commonjs/src/openapi/request-schema.js +0 -187
  38. package/commonjs/src/openapi/request-validator.js +0 -85
  39. package/commonjs/src/providers/fastify.provider.js +0 -391
  40. package/commonjs/src/providers/index.js +0 -18
  41. package/commonjs/src/routing/decorators/argument.decorator.js +0 -49
  42. package/commonjs/src/routing/decorators/auth.decorator.js +0 -70
  43. package/commonjs/src/routing/decorators/controller.decorator.js +0 -16
  44. package/commonjs/src/routing/decorators/field.decorator.js +0 -25
  45. package/commonjs/src/routing/decorators/index.js +0 -24
  46. package/commonjs/src/routing/decorators/request.decorator.js +0 -30
  47. package/commonjs/src/routing/decorators/response.decorator.js +0 -34
  48. package/commonjs/src/routing/decorators/route.decorator.js +0 -67
  49. package/commonjs/src/routing/filters/exception-filter-host.js +0 -145
  50. package/commonjs/src/routing/filters/exception-filter.js +0 -28
  51. package/commonjs/src/routing/http.types.js +0 -99
  52. package/commonjs/src/routing/index.js +0 -25
  53. package/commonjs/src/routing/middleware/http-access-log.middleware.js +0 -47
  54. package/commonjs/src/routing/middleware/middleware.js +0 -20
  55. package/commonjs/src/routing/middleware/request-id.js +0 -30
  56. package/commonjs/src/routing/path.util.js +0 -51
  57. package/commonjs/src/routing/pipes/index.js +0 -18
  58. package/commonjs/src/routing/pipes/pipes.js +0 -145
  59. package/commonjs/src/routing/services/index.js +0 -18
  60. package/commonjs/src/routing/services/route-argument-resolver.js +0 -77
  61. package/commonjs/src/routing/services/route-registry.js +0 -194
  62. package/commonjs/src/routing/services/router.js +0 -158
  63. package/commonjs/src/sse/index.js +0 -26
  64. package/commonjs/src/sse/sse.decorator.js +0 -42
  65. package/commonjs/src/sse/sse.encoder.js +0 -73
  66. package/commonjs/src/sse/sse.types.js +0 -36
  67. package/commonjs/src/sse/sse.wire.js +0 -40
  68. package/commonjs/src/testing/boot-module.js +0 -38
  69. package/commonjs/src/testing/index.js +0 -20
  70. package/commonjs/src/testing/sse-reader.js +0 -98
@@ -1,145 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get BooleanPipe () {
13
- return BooleanPipe;
14
- },
15
- get DatePipe () {
16
- return DatePipe;
17
- },
18
- get JsonPipe () {
19
- return JsonPipe;
20
- },
21
- get NumberPipe () {
22
- return NumberPipe;
23
- },
24
- get Pipe () {
25
- return Pipe;
26
- }
27
- });
28
- const _reflection = require("@decohere/core/reflection");
29
- const _httptypes = require("../http.types.js");
30
- const invalidBooleanIssue = {
31
- path: "/value",
32
- message: "Invalid boolean",
33
- keyword: "type"
34
- };
35
- const invalidNumberIssue = {
36
- path: "/value",
37
- message: "Invalid number",
38
- keyword: "type"
39
- };
40
- const invalidDateIssue = {
41
- path: "/value",
42
- message: "Invalid date",
43
- keyword: "format"
44
- };
45
- class Pipe {
46
- }
47
- class BooleanPipe extends Pipe {
48
- transform(value, _context) {
49
- if (typeof value === "boolean") {
50
- return value;
51
- }
52
- const normalized = typeof value === "string" ? value.trim().toLowerCase() : value;
53
- switch(normalized){
54
- case "true":
55
- case "1":
56
- case 1:
57
- return true;
58
- case "false":
59
- case "0":
60
- case 0:
61
- return false;
62
- default:
63
- throw new _httptypes.ValidationError("Validation failed", [
64
- invalidBooleanIssue
65
- ]);
66
- }
67
- }
68
- }
69
- class DatePipe extends Pipe {
70
- transform(value, _context) {
71
- if (value instanceof Date) {
72
- if (Number.isNaN(value.getTime())) {
73
- throw new _httptypes.ValidationError("Validation failed", [
74
- invalidDateIssue
75
- ]);
76
- }
77
- return value;
78
- }
79
- if (typeof value === "string") {
80
- const trimmed = value.trim();
81
- if (trimmed === "") {
82
- throw new _httptypes.ValidationError("Validation failed", [
83
- invalidDateIssue
84
- ]);
85
- }
86
- if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
87
- return new Date(Number(trimmed));
88
- }
89
- const parsed = new Date(trimmed);
90
- if (Number.isNaN(parsed.getTime())) {
91
- throw new _httptypes.ValidationError("Validation failed", [
92
- invalidDateIssue
93
- ]);
94
- }
95
- return parsed;
96
- }
97
- if (typeof value === "number" && !Number.isNaN(value)) {
98
- return new Date(value);
99
- }
100
- throw new _httptypes.ValidationError("Validation failed", [
101
- invalidDateIssue
102
- ]);
103
- }
104
- }
105
- class JsonPipe extends Pipe {
106
- transform(value, context) {
107
- try {
108
- const obj = JSON.parse(value, (fieldKey, fieldValue)=>{
109
- const val = this.reviver(context?.fieldTypes, fieldKey, fieldValue);
110
- return val;
111
- });
112
- return obj;
113
- } catch (err) {
114
- throw new _httptypes.TransformError(`Error parsing json ${err}`);
115
- }
116
- }
117
- reviver(fieldTypes, fieldKey, value) {
118
- if (!fieldKey) {
119
- return value;
120
- }
121
- if (!fieldTypes) {
122
- return value;
123
- }
124
- const fieldType = fieldTypes[fieldKey];
125
- if (fieldType == null) {
126
- return value;
127
- }
128
- if (!(0, _reflection.isDateType)(fieldType)) {
129
- return value;
130
- }
131
- return new Date(value.toString());
132
- }
133
- }
134
- class NumberPipe extends Pipe {
135
- /** Finite numbers only. Blank or non-numeric input is a 400, not `undefined`. */ transform(value, _context) {
136
- const text = typeof value === "number" ? null : String(value).trim();
137
- const number = text == null ? value : text === "" ? Number.NaN : Number(text);
138
- if (!Number.isFinite(number)) {
139
- throw new _httptypes.ValidationError("Validation failed", [
140
- invalidNumberIssue
141
- ]);
142
- }
143
- return number;
144
- }
145
- }
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- _export_star(require("./router.js"), exports);
6
- function _export_star(from, to) {
7
- Object.keys(from).forEach(function(k) {
8
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
9
- Object.defineProperty(to, k, {
10
- enumerable: true,
11
- get: function() {
12
- return from[k];
13
- }
14
- });
15
- }
16
- });
17
- return from;
18
- }
@@ -1,77 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "RouteArgumentResolve", {
6
- enumerable: true,
7
- get: function() {
8
- return RouteArgumentResolve;
9
- }
10
- });
11
- const _reflection = require("@decohere/core/reflection");
12
- class RouteArgumentResolve {
13
- resolveArguments(httpRequest, routeArgs, principalProvider) {
14
- const argsValues = [];
15
- for (const [argIdx, routeArg] of routeArgs.entries()){
16
- const val = this.getValue(httpRequest, routeArg, principalProvider);
17
- argsValues[argIdx] = val;
18
- }
19
- return argsValues;
20
- }
21
- getValue(httpRequest, routeArg, principalProvider) {
22
- switch(routeArg.argumentLocation){
23
- case "principal":
24
- return principalProvider?.currentPrincipal;
25
- case "signal":
26
- return httpRequest.signal;
27
- case "lastEventId":
28
- return httpRequest.headers["last-event-id"];
29
- }
30
- const value = (0, _reflection.isPrimitiveOrDateType)(routeArg.argumentType) ? this.mapPrimitive(httpRequest, routeArg) : this.mapObject(httpRequest, routeArg);
31
- return value;
32
- }
33
- mapPrimitive(httpRequest, routeArg) {
34
- const { argumentLocation, mappingKey, pipes } = routeArg;
35
- const value = httpRequest[argumentLocation][mappingKey];
36
- const tranformedValue = this.transform(value, pipes, routeArg.fieldMap);
37
- return tranformedValue;
38
- }
39
- mapObject(httpRequest, routeArg) {
40
- const { argumentType } = routeArg;
41
- const inst = new argumentType();
42
- const { fieldMap } = routeArg;
43
- for (const [fieldKey, meta] of fieldMap.entries()){
44
- const { fieldLocation, mappingKey, pipes } = meta;
45
- const value = httpRequest[fieldLocation][mappingKey];
46
- const transformedValue = this.transform(value, pipes, fieldMap);
47
- inst[fieldKey] = transformedValue;
48
- }
49
- return inst;
50
- }
51
- transform(value, pipes, fieldMap) {
52
- let transformed = value;
53
- if (value == null) {
54
- return value;
55
- }
56
- const context = this.pipeContext(fieldMap);
57
- for (const pipeConstructor of pipes ?? []){
58
- const pipe = new pipeConstructor();
59
- transformed = pipe.transform(transformed, context);
60
- }
61
- return transformed;
62
- }
63
- pipeContext(fieldMap) {
64
- if (fieldMap == null || fieldMap.size === 0) {
65
- return undefined;
66
- }
67
- const fieldTypes = {};
68
- for (const [key, meta] of fieldMap.entries()){
69
- if (meta.fieldType != null) {
70
- fieldTypes[key] = meta.fieldType;
71
- }
72
- }
73
- return Object.keys(fieldTypes).length > 0 ? {
74
- fieldTypes
75
- } : undefined;
76
- }
77
- }
@@ -1,194 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "RouteRegistry", {
6
- enumerable: true,
7
- get: function() {
8
- return RouteRegistry;
9
- }
10
- });
11
- const _decorators = require("@decohere/crucible/decorators");
12
- const _reflection = require("@decohere/core/reflection");
13
- const _const = require("../../const.js");
14
- const _httptypes = require("../http.types.js");
15
- const _pathutil = require("../path.util.js");
16
- const _pipes = require("../pipes/pipes.js");
17
- function _ts_decorate(decorators, target, key, desc) {
18
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
- 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;
21
- return c > 3 && r && Object.defineProperty(target, key, r), r;
22
- }
23
- function _ts_metadata(k, v) {
24
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
- }
26
- function _ts_param(paramIndex, decorator) {
27
- return function(target, key) {
28
- decorator(target, key, paramIndex);
29
- };
30
- }
31
- class RouteRegistry {
32
- routeMap = new Map();
33
- httpOptions;
34
- constructor(httpOptions){
35
- this.httpOptions = httpOptions;
36
- }
37
- addController(controller) {
38
- const funcs = (0, _reflection.getFunctions)(controller);
39
- for (const func of funcs){
40
- this.addControllerRoute(controller, func);
41
- }
42
- }
43
- get routes() {
44
- return this.routeMap.values();
45
- }
46
- getRoute(key) {
47
- return this.routeMap.get(key);
48
- }
49
- addControllerRoute(controller, prop) {
50
- const func = prop.value;
51
- const handler = func.name;
52
- const route = (0, _reflection.getMeta)(_const.MetadataKeys.route, func);
53
- if (route == null) {
54
- return;
55
- }
56
- const globalPrefix = this.takesGlobalPrefix(controller) ? (0, _pathutil.normalizePrefix)(this.httpOptions?.globalPrefix) : "";
57
- const controllerPrefix = this.getControllerPrefix(controller);
58
- const path = (0, _pathutil.applyGlobalPrefix)(globalPrefix, (0, _pathutil.joinRoutePath)(controllerPrefix, route.path));
59
- const { method } = route;
60
- const key = `${method}|${path}`;
61
- const existing = this.routeMap.get(key);
62
- if (existing != null) {
63
- // Last one used to win silently, leaving the other handler unreachable.
64
- throw new _httptypes.RouteConfigurationError(`Duplicate route ${method.toUpperCase()} ${path}: ${existing.controller.name}.${existing.handler} and ${controller.name}.${handler}`);
65
- }
66
- const routeArgs = this.getRouteArguments(controller, func);
67
- const httpCode = (0, _reflection.getMeta)(_const.MetadataKeys.httpCode, func);
68
- const headers = (0, _reflection.getMeta)(_const.MetadataKeys.headers, func);
69
- const sse = (0, _reflection.getMeta)(_const.MetadataKeys.sse, func);
70
- this.routeMap.set(key, {
71
- key,
72
- controller,
73
- handler,
74
- path,
75
- method,
76
- routeArgs,
77
- httpCode,
78
- headers,
79
- sse
80
- });
81
- }
82
- /** `@Controller({ globalPrefix: false })` opts out, unless the app put it back under. */ takesGlobalPrefix(controller) {
83
- const meta = (0, _reflection.getMeta)(_const.MetadataKeys.controller, controller.prototype);
84
- return meta?.globalPrefix !== false || this.httpOptions?.underGlobalPrefix.has(controller) === true;
85
- }
86
- getControllerPrefix(controller) {
87
- const meta = (0, _reflection.getMeta)(_const.MetadataKeys.controller, controller.prototype);
88
- if (meta?.prefix) {
89
- return (0, _pathutil.normalizePrefix)(meta.prefix);
90
- }
91
- const controllerName = controller.name.toLowerCase().replace("controller", "");
92
- return controllerName !== "" ? `/${controllerName}` : "";
93
- }
94
- getRouteArguments(controller, handler) {
95
- const types = (0, _reflection.getFunctionArgs)(controller.prototype, handler) ?? [];
96
- const args = [];
97
- for (const [argumentIndex, argumentType] of types.entries()){
98
- const argMeta = (0, _reflection.getArgumentMeta)(_const.MetadataKeys.parameter, handler, argumentIndex);
99
- if (argMeta == null && !(0, _reflection.isConstructable)(argumentType)) {
100
- continue;
101
- }
102
- args.push(this.getRouteArgument(argumentType, argumentIndex, handler));
103
- }
104
- return args;
105
- }
106
- getRouteArgument(argumentType, argumentIndex, handler) {
107
- const argMeta = (0, _reflection.getArgumentMeta)(_const.MetadataKeys.parameter, handler, argumentIndex);
108
- // @CurrentUser() / interface params are Object (or other non-DTO types) — no field map.
109
- if (isInjectedPart(argMeta?.argumentLocation) || !(0, _reflection.isConstructable)(argumentType)) {
110
- return {
111
- ...argMeta,
112
- pipes: [],
113
- argumentIndex,
114
- argumentType: (0, _reflection.isConstructable)(argumentType) ? argumentType : Object,
115
- fieldMap: new Map()
116
- };
117
- }
118
- const pipes = argMeta != null ? this.getDefaultPipes(argumentType) : [];
119
- const fieldMap = this.getFields(argumentType, argumentIndex, argMeta);
120
- const routeArg = {
121
- ...argMeta,
122
- pipes,
123
- argumentIndex,
124
- argumentType,
125
- fieldMap
126
- };
127
- return routeArg;
128
- }
129
- getFields(argumentType, argumentIndex, argMeta) {
130
- const inst = new argumentType();
131
- const fields = (0, _reflection.getFields)(inst);
132
- const fieldMap = (0, _reflection.getMeta)(_const.MetadataKeys.fieldMap, argumentType.prototype) ?? new Map();
133
- for (const field of fields){
134
- const fieldKey = field.key;
135
- const fieldMeta = fieldMap.get(field.key);
136
- if (fieldMeta && fieldMeta.fieldLocation == null && argMeta?.argumentLocation == null) {
137
- throw new _httptypes.RouteConfigurationError(`field ${fieldMeta.fieldKey} must specify a location because location was not specified for the route argument at idx ${argumentIndex}`);
138
- }
139
- const enriched = this.enrichField(field, fieldMeta, argMeta);
140
- fieldMap.set(fieldKey, enriched);
141
- }
142
- return fieldMap;
143
- }
144
- enrichField(field, fieldMeta, argMeta) {
145
- const fieldLocation = fieldMeta?.fieldLocation ?? argMeta.argumentLocation;
146
- const pipes = this.getDefaultPipes(fieldMeta?.fieldType);
147
- return {
148
- fieldKey: field.key,
149
- mappingKey: field.key,
150
- ...fieldMeta,
151
- fieldLocation,
152
- pipes
153
- };
154
- }
155
- getDefaultPipes(argumentType) {
156
- if (argumentType == null) {
157
- return [];
158
- }
159
- let pipe;
160
- if (!(0, _reflection.isPrimitiveOrDateType)(argumentType)) {
161
- pipe = _pipes.JsonPipe;
162
- return [
163
- pipe
164
- ];
165
- }
166
- switch(argumentType.name){
167
- case "Number":
168
- pipe = _pipes.NumberPipe;
169
- break;
170
- case "Boolean":
171
- pipe = _pipes.BooleanPipe;
172
- break;
173
- case "Date":
174
- pipe = _pipes.DatePipe;
175
- break;
176
- default:
177
- return [];
178
- }
179
- return [
180
- pipe
181
- ];
182
- }
183
- }
184
- RouteRegistry = _ts_decorate([
185
- (0, _decorators.injectable)(),
186
- _ts_param(0, (0, _decorators.inject)(_const.HttpOptionsToken)),
187
- _ts_metadata("design:type", Function),
188
- _ts_metadata("design:paramtypes", [
189
- typeof HttpOptions === "undefined" ? Object : HttpOptions
190
- ])
191
- ], RouteRegistry);
192
- function isInjectedPart(location) {
193
- return location != null && _httptypes.InjectedParts.includes(location);
194
- }
@@ -1,158 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "Router", {
6
- enumerable: true,
7
- get: function() {
8
- return Router;
9
- }
10
- });
11
- const _crucible = require("@decohere/crucible");
12
- const _decorators = require("@decohere/crucible/decorators");
13
- const _scribe = require("@decohere/scribe");
14
- const _const = require("../../const.js");
15
- const _requestvalidator = require("../../openapi/request-validator.js");
16
- const _ssetypes = require("../../sse/sse.types.js");
17
- const _httptypes = require("../http.types.js");
18
- const _authdecorator = require("../decorators/auth.decorator.js");
19
- const _middleware = require("../middleware/middleware.js");
20
- const _routeargumentresolver = require("./route-argument-resolver.js");
21
- const _routeregistry = require("./route-registry.js");
22
- function _ts_decorate(decorators, target, key, desc) {
23
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
24
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
25
- 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;
26
- return c > 3 && r && Object.defineProperty(target, key, r), r;
27
- }
28
- function _ts_metadata(k, v) {
29
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
30
- }
31
- function _ts_param(paramIndex, decorator) {
32
- return function(target, key) {
33
- decorator(target, key, paramIndex);
34
- };
35
- }
36
- class Router {
37
- argResolver = new _routeargumentresolver.RouteArgumentResolve();
38
- lifetimeScope;
39
- routeRegistry;
40
- authService;
41
- httpOptions;
42
- logger = _scribe.scribe.logger(Router.name);
43
- constructor(routeRegistry, lifetimeScope, authService, httpOptions){
44
- this.routeRegistry = routeRegistry;
45
- this.lifetimeScope = lifetimeScope;
46
- this.authService = authService;
47
- this.httpOptions = httpOptions;
48
- this.assertAuthConfiguredForProtectedRoutes();
49
- }
50
- /**
51
- * Without an authorization service nothing checks tokens, so a route marked @Authorize
52
- * would be served to anyone. Refuse to start instead of failing open.
53
- */ assertAuthConfiguredForProtectedRoutes() {
54
- if (this.authService != null) {
55
- return;
56
- }
57
- const protectedRoutes = [
58
- ...this.routeRegistry.routes
59
- ].filter(({ controller, handler })=>(0, _authdecorator.getAuthorizeOptions)(controller.prototype, controller.prototype[handler])).map(({ controller, handler })=>`${controller.name}.${String(handler)}`);
60
- if (protectedRoutes.length > 0) {
61
- throw new _httptypes.RoutingError(`Routes use @Authorize but auth is not configured, so they would be open to anyone: ${protectedRoutes.join(", ")}. Add .withAuth() to the builder, or remove @Authorize.`);
62
- }
63
- }
64
- async route(routeKey, httpRequest) {
65
- const routeConfig = this.routeRegistry.getRoute(routeKey);
66
- if (!routeConfig) {
67
- throw new _httptypes.RoutingError(`Route was not configured for key ${routeKey}`);
68
- }
69
- const { controller, handler, routeArgs } = routeConfig;
70
- // Unnamed: the request id comes from the client, so it is not unique.
71
- // Disposed before we respond, so async cleanup (e.g. rolling back a DB transaction)
72
- // finishes first. An SSE route is the exception: its scope lives as long as the stream.
73
- const scope = this.lifetimeScope.beginScope();
74
- let scopeHandedOff = false;
75
- // Runs inside the middleware chain so rejections (401/403/400) reach middleware such as
76
- // the access log. Auth comes first so anonymous callers learn nothing about the body.
77
- const handle = async ()=>{
78
- const principal = await this.authorize(routeConfig, httpRequest);
79
- if (this.httpOptions?.openapi?.validateRequests !== false && this.httpOptions?.openapi) {
80
- (0, _requestvalidator.validateRequest)(routeConfig, httpRequest);
81
- }
82
- const provider = scope.resolve(_const.IPrincipalProviderToken);
83
- provider.setPrincipal(principal);
84
- const controllerInstance = scope.resolve(controller);
85
- const func = controllerInstance[handler];
86
- const argValues = this.argResolver.resolveArguments(httpRequest, routeArgs, provider);
87
- try {
88
- const result = await func.apply(controllerInstance, argValues);
89
- if (routeConfig.sse == null) {
90
- return result;
91
- }
92
- if (typeof result?.[Symbol.asyncIterator] !== "function") {
93
- throw new _httptypes.RoutingError(`${controller.name}.${String(handler)} is marked @Sse() so it must return an AsyncIterable (an async generator method works)`);
94
- }
95
- scopeHandedOff = true;
96
- return new _ssetypes.SseResponse(result, ()=>scope[Symbol.asyncDispose]());
97
- } catch (error) {
98
- this.logger.error(error.message, error.stack);
99
- throw error;
100
- }
101
- };
102
- try {
103
- const middlewares = this.resolveMiddlewares(scope);
104
- if (middlewares.length === 0) {
105
- return await handle();
106
- }
107
- return await (0, _middleware.composeMiddleware)(middlewares, handle, {
108
- request: httpRequest,
109
- route: routeConfig
110
- });
111
- } catch (error) {
112
- // A middleware failed after the handler returned: nobody will consume the stream.
113
- scopeHandedOff = false;
114
- throw error;
115
- } finally{
116
- if (!scopeHandedOff) {
117
- await scope[Symbol.asyncDispose]();
118
- }
119
- }
120
- }
121
- resolveMiddlewares(scope) {
122
- const types = this.httpOptions?.middlewareTypes ?? [];
123
- return types.map((type)=>scope.resolve(type));
124
- }
125
- async authorize(routeConfig, httpRequest) {
126
- // Optional DI may resolve as null when auth is not registered.
127
- if (this.authService == null) {
128
- return;
129
- }
130
- const { controller, handler } = routeConfig;
131
- const handlerFn = controller.prototype[handler];
132
- if ((0, _authdecorator.isAllowAnonymous)(controller.prototype, handlerFn)) {
133
- return;
134
- }
135
- const authOptions = (0, _authdecorator.getAuthorizeOptions)(controller.prototype, handlerFn);
136
- if (authOptions === undefined) {
137
- // Auth is enabled but the route has no @Authorize — require a valid
138
- // token (fail closed) without checking a specific ability.
139
- return this.authService.authenticateRequest(httpRequest);
140
- }
141
- return this.authService.authorizeRequest(httpRequest, authOptions.action, authOptions.subject);
142
- }
143
- }
144
- Router = _ts_decorate([
145
- (0, _decorators.injectable)(),
146
- _ts_param(0, (0, _decorators.inject)(_const.RouteRegistryToken)),
147
- _ts_param(1, (0, _decorators.inject)(_crucible.LifetimeScopeToken)),
148
- _ts_param(2, (0, _decorators.inject)(_const.AuthorizationServiceToken)),
149
- _ts_param(2, (0, _decorators.optional)()),
150
- _ts_param(3, (0, _decorators.inject)(_const.HttpOptionsToken)),
151
- _ts_metadata("design:type", Function),
152
- _ts_metadata("design:paramtypes", [
153
- typeof _routeregistry.RouteRegistry === "undefined" ? Object : _routeregistry.RouteRegistry,
154
- typeof LifetimeScope === "undefined" ? Object : LifetimeScope,
155
- typeof IAuthorizationService === "undefined" ? Object : IAuthorizationService,
156
- typeof HttpOptions === "undefined" ? Object : HttpOptions
157
- ])
158
- ], Router);
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get LastEventId () {
13
- return _ssedecorator.LastEventId;
14
- },
15
- get Signal () {
16
- return _ssedecorator.Signal;
17
- },
18
- get Sse () {
19
- return _ssedecorator.Sse;
20
- },
21
- get SseResponse () {
22
- return _ssetypes.SseResponse;
23
- }
24
- });
25
- const _ssedecorator = require("./sse.decorator.js");
26
- const _ssetypes = require("./sse.types.js");
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get LastEventId () {
13
- return LastEventId;
14
- },
15
- get Signal () {
16
- return Signal;
17
- },
18
- get Sse () {
19
- return Sse;
20
- }
21
- });
22
- const _reflection = require("@decohere/core/reflection");
23
- const _const = require("../const.js");
24
- function Sse(options = {}) {
25
- return (_target, _methodName, descriptor)=>{
26
- (0, _reflection.defineMeta)(_const.MetadataKeys.sse, options, descriptor.value);
27
- };
28
- }
29
- function injected(location) {
30
- return ()=>(target, propertyKey, parameterIndex)=>{
31
- const fn = target[propertyKey];
32
- const meta = {
33
- argumentIndex: parameterIndex,
34
- argumentLocation: location,
35
- mappingKey: undefined,
36
- pipes: []
37
- };
38
- (0, _reflection.defineArgumentMeta)(_const.MetadataKeys.parameter, meta, fn, parameterIndex);
39
- };
40
- }
41
- const Signal = injected("signal");
42
- const LastEventId = injected("lastEventId");