@decohere/http 0.0.1-dev.125 → 0.0.1-dev.5
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.
- package/package.json +4 -13
- package/src/app/app.ts +147 -0
- package/src/app/module.ts +19 -0
- package/src/auth/ability.ts +56 -0
- package/src/auth/auth.config.ts +34 -0
- package/src/auth/auth.extensions.ts +115 -0
- package/src/auth/auth.types.ts +124 -0
- package/src/auth/casl-authorization.service.ts +62 -0
- package/{types/src/auth/principal-provider.d.ts → src/auth/principal-provider.ts} +13 -5
- package/src/auth/safe-outbound-url.ts +117 -0
- package/src/auth/token-service.ts +192 -0
- package/src/builder/builder.ts +118 -0
- package/{es6/src/const.js → src/const.ts} +25 -17
- package/src/health/health.controller.ts +34 -0
- package/src/health/health.extensions.ts +53 -0
- package/src/health/readiness.service.ts +33 -0
- package/{types/src/health/readiness.types.d.ts → src/health/readiness.types.ts} +4 -8
- package/src/hosting/hosted-service-host.ts +102 -0
- package/src/hosting/hosted-service.ts +31 -0
- package/src/http/http.compression.ts +38 -0
- package/src/http/http.extensions.ts +244 -0
- package/{types/src/http/http.options.store.d.ts → src/http/http.options.store.ts} +11 -1
- package/src/http/http.options.ts +41 -0
- package/{types/src/http/http.security.d.ts → src/http/http.security.ts} +16 -10
- package/src/http/http.static.ts +359 -0
- package/{es6/src/index.js → src/index.ts} +1 -0
- package/src/openapi/index.ts +22 -0
- package/src/openapi/openapi.generator.ts +78 -0
- package/src/openapi/openapi.types.ts +60 -0
- package/src/openapi/request-schema.ts +155 -0
- package/src/openapi/request-validator.ts +95 -0
- package/src/providers/fastify.provider.ts +454 -0
- package/src/routing/anvil.types.ts +150 -0
- package/src/routing/decorators/argument.decorator.ts +33 -0
- package/src/routing/decorators/auth.decorator.ts +79 -0
- package/src/routing/decorators/controller.decorator.ts +9 -0
- package/src/routing/decorators/field.decorator.ts +15 -0
- package/src/routing/decorators/request.decorator.ts +34 -0
- package/src/routing/decorators/response.decorator.ts +18 -0
- package/src/routing/decorators/route.decorator.ts +52 -0
- package/src/routing/filters/exception-filter-host.ts +90 -0
- package/src/routing/filters/exception-filter.ts +29 -0
- package/src/routing/middleware/http-access-log.middleware.ts +36 -0
- package/src/routing/middleware/middleware.ts +26 -0
- package/src/routing/middleware/request-id.ts +18 -0
- package/src/routing/path.util.ts +38 -0
- package/src/routing/pipes/pipes.ts +132 -0
- package/src/routing/services/route-argument-resolver.ts +92 -0
- package/src/routing/services/route-registry.ts +229 -0
- package/src/routing/services/router.ts +166 -0
- package/src/sse/sse.decorator.ts +41 -0
- package/src/sse/sse.encoder.ts +86 -0
- package/src/sse/sse.types.ts +47 -0
- package/src/sse/sse.wire.ts +34 -0
- package/src/testing/boot-module.ts +63 -0
- package/src/testing/sse-reader.ts +120 -0
- package/tests/app.hosted-services.spec.ts +292 -0
- package/tests/app.shutdown.integration.spec.ts +160 -0
- package/tests/app.spec.ts +132 -0
- package/tests/auth.ability.spec.ts +48 -0
- package/tests/auth.decorators.spec.ts +20 -0
- package/tests/auth.fail-closed.pentest.spec.ts +77 -0
- package/tests/auth.integration.spec.ts +234 -0
- package/tests/auth.jwks-cache.spec.ts +52 -0
- package/tests/auth.missing-auth.pentest.spec.ts +56 -0
- package/tests/auth.oidc-ssrf.pentest.spec.ts +72 -0
- package/tests/auth.oidc.integration.spec.ts +161 -0
- package/tests/auth.token-service.spec.ts +251 -0
- package/tests/builder.spec.ts +12 -0
- package/tests/health.integration.spec.ts +111 -0
- package/tests/helpers/listen-ephemeral.ts +13 -0
- package/tests/helpers/local-oidc-server.ts +100 -0
- package/tests/http.access-log.integration.spec.ts +111 -0
- package/tests/http.boolean-query.integration.spec.ts +59 -0
- package/tests/http.compression.integration.spec.ts +604 -0
- package/tests/http.date-query.integration.spec.ts +71 -0
- package/tests/http.global-prefix.integration.spec.ts +284 -0
- package/tests/http.number-query.integration.spec.ts +65 -0
- package/tests/http.pino-roll-hmr.integration.spec.ts +79 -0
- package/tests/http.pipeline-order.integration.spec.ts +95 -0
- package/tests/http.request-cleanup.integration.spec.ts +57 -0
- package/tests/http.request-id-scope.pentest.spec.ts +50 -0
- package/tests/http.security.integration.spec.ts +106 -0
- package/tests/http.static.integration.spec.ts +847 -0
- package/tests/http.static.spec.ts +111 -0
- package/tests/http.surface.integration.spec.ts +167 -0
- package/tests/openapi.integration.spec.ts +193 -0
- package/tests/openapi.validator-cache.integration.spec.ts +55 -0
- package/tests/routing.decorators.spec.ts +15 -0
- package/tests/routing.registry.spec.ts +44 -0
- package/tests/routing.resolver.spec.ts +92 -0
- package/tests/sse.integration.spec.ts +421 -0
- package/tests/sse.wire.spec.ts +33 -0
- package/LICENSE +0 -15
- package/commonjs/src/app/app.js +0 -166
- package/commonjs/src/app/index.js +0 -19
- package/commonjs/src/app/module.js +0 -17
- package/commonjs/src/auth/ability.js +0 -54
- package/commonjs/src/auth/auth.config.js +0 -23
- package/commonjs/src/auth/auth.extensions.js +0 -106
- package/commonjs/src/auth/auth.types.js +0 -65
- package/commonjs/src/auth/casl-authorization.service.js +0 -36
- package/commonjs/src/auth/index.js +0 -23
- package/commonjs/src/auth/principal-provider.js +0 -19
- package/commonjs/src/auth/safe-outbound-url.js +0 -102
- package/commonjs/src/auth/token-service.js +0 -151
- package/commonjs/src/builder/builder.js +0 -95
- package/commonjs/src/builder/index.js +0 -18
- package/commonjs/src/const.js +0 -87
- package/commonjs/src/health/health.controller.js +0 -75
- package/commonjs/src/health/health.extensions.js +0 -50
- package/commonjs/src/health/index.js +0 -21
- package/commonjs/src/health/readiness.service.js +0 -67
- package/commonjs/src/health/readiness.types.js +0 -7
- package/commonjs/src/hosting/hosted-service-host.js +0 -88
- package/commonjs/src/hosting/hosted-service.js +0 -11
- package/commonjs/src/hosting/index.js +0 -19
- package/commonjs/src/http/http.compression.js +0 -27
- package/commonjs/src/http/http.extensions.js +0 -269
- package/commonjs/src/http/http.options.js +0 -26
- package/commonjs/src/http/http.options.store.js +0 -20
- package/commonjs/src/http/http.security.js +0 -27
- package/commonjs/src/http/http.static.js +0 -248
- package/commonjs/src/http/index.js +0 -22
- package/commonjs/src/index.js +0 -27
- package/commonjs/src/openapi/index.js +0 -45
- package/commonjs/src/openapi/openapi.generator.js +0 -103
- package/commonjs/src/openapi/openapi.types.js +0 -4
- package/commonjs/src/openapi/request-schema.js +0 -187
- package/commonjs/src/openapi/request-validator.js +0 -85
- package/commonjs/src/providers/fastify.provider.js +0 -391
- package/commonjs/src/providers/index.js +0 -18
- package/commonjs/src/routing/anvil.types.js +0 -99
- package/commonjs/src/routing/decorators/argument.decorator.js +0 -49
- package/commonjs/src/routing/decorators/auth.decorator.js +0 -70
- package/commonjs/src/routing/decorators/controller.decorator.js +0 -16
- package/commonjs/src/routing/decorators/field.decorator.js +0 -25
- package/commonjs/src/routing/decorators/index.js +0 -24
- package/commonjs/src/routing/decorators/request.decorator.js +0 -30
- package/commonjs/src/routing/decorators/response.decorator.js +0 -34
- package/commonjs/src/routing/decorators/route.decorator.js +0 -67
- package/commonjs/src/routing/filters/exception-filter-host.js +0 -145
- package/commonjs/src/routing/filters/exception-filter.js +0 -28
- package/commonjs/src/routing/index.js +0 -25
- package/commonjs/src/routing/middleware/http-access-log.middleware.js +0 -47
- package/commonjs/src/routing/middleware/middleware.js +0 -20
- package/commonjs/src/routing/middleware/request-id.js +0 -30
- package/commonjs/src/routing/path.util.js +0 -51
- package/commonjs/src/routing/pipes/index.js +0 -18
- package/commonjs/src/routing/pipes/pipes.js +0 -145
- package/commonjs/src/routing/services/index.js +0 -18
- package/commonjs/src/routing/services/route-argument-resolver.js +0 -77
- package/commonjs/src/routing/services/route-registry.js +0 -194
- package/commonjs/src/routing/services/router.js +0 -158
- package/commonjs/src/sse/index.js +0 -26
- package/commonjs/src/sse/sse.decorator.js +0 -42
- package/commonjs/src/sse/sse.encoder.js +0 -73
- package/commonjs/src/sse/sse.types.js +0 -36
- package/commonjs/src/sse/sse.wire.js +0 -40
- package/commonjs/src/testing/boot-module.js +0 -38
- package/commonjs/src/testing/index.js +0 -20
- package/commonjs/src/testing/sse-reader.js +0 -98
- package/es6/src/app/app.js +0 -148
- package/es6/src/app/index.js +0 -2
- package/es6/src/app/module.js +0 -7
- package/es6/src/auth/ability.js +0 -45
- package/es6/src/auth/auth.config.js +0 -19
- package/es6/src/auth/auth.extensions.js +0 -83
- package/es6/src/auth/auth.types.js +0 -35
- package/es6/src/auth/casl-authorization.service.js +0 -40
- package/es6/src/auth/index.js +0 -6
- package/es6/src/auth/principal-provider.js +0 -14
- package/es6/src/auth/safe-outbound-url.js +0 -99
- package/es6/src/auth/token-service.js +0 -141
- package/es6/src/builder/builder.js +0 -85
- package/es6/src/builder/index.js +0 -1
- package/es6/src/health/health.controller.js +0 -65
- package/es6/src/health/health.extensions.js +0 -40
- package/es6/src/health/index.js +0 -4
- package/es6/src/health/readiness.service.js +0 -57
- package/es6/src/health/readiness.types.js +0 -4
- package/es6/src/hosting/hosted-service-host.js +0 -81
- package/es6/src/hosting/hosted-service.js +0 -8
- package/es6/src/hosting/index.js +0 -2
- package/es6/src/http/http.compression.js +0 -9
- package/es6/src/http/http.extensions.js +0 -259
- package/es6/src/http/http.options.js +0 -16
- package/es6/src/http/http.options.store.js +0 -13
- package/es6/src/http/http.security.js +0 -9
- package/es6/src/http/http.static.js +0 -224
- package/es6/src/http/index.js +0 -5
- package/es6/src/openapi/index.js +0 -3
- package/es6/src/openapi/openapi.generator.js +0 -82
- package/es6/src/openapi/openapi.types.js +0 -1
- package/es6/src/openapi/request-schema.js +0 -160
- package/es6/src/openapi/request-validator.js +0 -71
- package/es6/src/providers/fastify.provider.js +0 -376
- package/es6/src/providers/index.js +0 -1
- package/es6/src/routing/anvil.types.js +0 -57
- package/es6/src/routing/decorators/argument.decorator.js +0 -28
- package/es6/src/routing/decorators/auth.decorator.js +0 -58
- package/es6/src/routing/decorators/controller.decorator.js +0 -6
- package/es6/src/routing/decorators/field.decorator.js +0 -15
- package/es6/src/routing/decorators/index.js +0 -7
- package/es6/src/routing/decorators/request.decorator.js +0 -24
- package/es6/src/routing/decorators/response.decorator.js +0 -16
- package/es6/src/routing/decorators/route.decorator.js +0 -37
- package/es6/src/routing/filters/exception-filter-host.js +0 -127
- package/es6/src/routing/filters/exception-filter.js +0 -10
- package/es6/src/routing/index.js +0 -8
- package/es6/src/routing/middleware/http-access-log.middleware.js +0 -37
- package/es6/src/routing/middleware/middleware.js +0 -10
- package/es6/src/routing/middleware/request-id.js +0 -14
- package/es6/src/routing/path.util.js +0 -33
- package/es6/src/routing/pipes/index.js +0 -1
- package/es6/src/routing/pipes/pipes.js +0 -118
- package/es6/src/routing/services/index.js +0 -1
- package/es6/src/routing/services/route-argument-resolver.js +0 -67
- package/es6/src/routing/services/route-registry.js +0 -184
- package/es6/src/routing/services/router.js +0 -148
- package/es6/src/sse/index.js +0 -2
- package/es6/src/sse/sse.decorator.js +0 -31
- package/es6/src/sse/sse.encoder.js +0 -67
- package/es6/src/sse/sse.types.js +0 -22
- package/es6/src/sse/sse.wire.js +0 -30
- package/es6/src/testing/boot-module.js +0 -35
- package/es6/src/testing/index.js +0 -2
- package/es6/src/testing/sse-reader.js +0 -91
- package/types/src/app/app.d.ts +0 -41
- package/types/src/app/module.d.ts +0 -15
- package/types/src/auth/ability.d.ts +0 -19
- package/types/src/auth/auth.config.d.ts +0 -28
- package/types/src/auth/auth.extensions.d.ts +0 -53
- package/types/src/auth/auth.types.d.ts +0 -73
- package/types/src/auth/casl-authorization.service.d.ts +0 -28
- package/types/src/auth/safe-outbound-url.d.ts +0 -9
- package/types/src/auth/token-service.d.ts +0 -31
- package/types/src/builder/builder.d.ts +0 -36
- package/types/src/const.d.ts +0 -32
- package/types/src/health/health.controller.d.ts +0 -16
- package/types/src/health/health.extensions.d.ts +0 -31
- package/types/src/health/readiness.service.d.ts +0 -9
- package/types/src/hosting/hosted-service-host.d.ts +0 -37
- package/types/src/hosting/hosted-service.d.ts +0 -31
- package/types/src/http/http.compression.d.ts +0 -32
- package/types/src/http/http.extensions.d.ts +0 -79
- package/types/src/http/http.options.d.ts +0 -39
- package/types/src/http/http.static.d.ts +0 -160
- package/types/src/index.d.ts +0 -10
- package/types/src/openapi/index.d.ts +0 -6
- package/types/src/openapi/openapi.generator.d.ts +0 -6
- package/types/src/openapi/openapi.types.d.ts +0 -58
- package/types/src/openapi/request-schema.d.ts +0 -21
- package/types/src/openapi/request-validator.d.ts +0 -9
- package/types/src/providers/fastify.provider.d.ts +0 -56
- package/types/src/routing/anvil.types.d.ts +0 -119
- package/types/src/routing/decorators/argument.decorator.d.ts +0 -11
- package/types/src/routing/decorators/auth.decorator.d.ts +0 -30
- package/types/src/routing/decorators/controller.decorator.d.ts +0 -3
- package/types/src/routing/decorators/field.decorator.d.ts +0 -2
- package/types/src/routing/decorators/request.decorator.d.ts +0 -8
- package/types/src/routing/decorators/response.decorator.d.ts +0 -4
- package/types/src/routing/decorators/route.decorator.d.ts +0 -7
- package/types/src/routing/filters/exception-filter-host.d.ts +0 -19
- package/types/src/routing/filters/exception-filter.d.ts +0 -16
- package/types/src/routing/middleware/http-access-log.middleware.d.ts +0 -8
- package/types/src/routing/middleware/middleware.d.ts +0 -10
- package/types/src/routing/middleware/request-id.d.ts +0 -6
- package/types/src/routing/path.util.d.ts +0 -9
- package/types/src/routing/pipes/pipes.d.ts +0 -21
- package/types/src/routing/services/route-argument-resolver.d.ts +0 -10
- package/types/src/routing/services/route-registry.d.ts +0 -20
- package/types/src/routing/services/router.d.ts +0 -22
- package/types/src/sse/sse.decorator.d.ts +0 -17
- package/types/src/sse/sse.encoder.d.ts +0 -16
- package/types/src/sse/sse.types.d.ts +0 -37
- package/types/src/sse/sse.wire.d.ts +0 -9
- package/types/src/testing/boot-module.d.ts +0 -34
- package/types/src/testing/sse-reader.d.ts +0 -29
- /package/{types/src/app/index.d.ts → src/app/index.ts} +0 -0
- /package/{types/src/auth/index.d.ts → src/auth/index.ts} +0 -0
- /package/{types/src/builder/index.d.ts → src/builder/index.ts} +0 -0
- /package/{types/src/health/index.d.ts → src/health/index.ts} +0 -0
- /package/{types/src/hosting/index.d.ts → src/hosting/index.ts} +0 -0
- /package/{types/src/http/index.d.ts → src/http/index.ts} +0 -0
- /package/{types/src/providers/index.d.ts → src/providers/index.ts} +0 -0
- /package/{types/src/routing/decorators/index.d.ts → src/routing/decorators/index.ts} +0 -0
- /package/{types/src/routing/index.d.ts → src/routing/index.ts} +0 -0
- /package/{types/src/routing/pipes/index.d.ts → src/routing/pipes/index.ts} +0 -0
- /package/{types/src/routing/services/index.d.ts → src/routing/services/index.ts} +0 -0
- /package/{types/src/sse/index.d.ts → src/sse/index.ts} +0 -0
- /package/{types/src/testing/index.d.ts → src/testing/index.ts} +0 -0
|
@@ -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 _anviltypes = require("../anvil.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 (#503).
|
|
64
|
-
throw new _anviltypes.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 _anviltypes.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 && _anviltypes.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 _anviltypes = require("../anvil.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 (#500).
|
|
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 _anviltypes.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 _anviltypes.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 (#497).
|
|
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 (#501).
|
|
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 _anviltypes.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");
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "encodeSse", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return encodeSse;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _scribe = require("@decohere/scribe");
|
|
12
|
-
const _ssewire = require("./sse.wire.js");
|
|
13
|
-
const logger = _scribe.scribe.logger("SseEncoder");
|
|
14
|
-
async function* encodeSse(source, options) {
|
|
15
|
-
const { signal, heartbeatMs } = options;
|
|
16
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
17
|
-
let onAbort;
|
|
18
|
-
const abortStep = new Promise((resolve)=>{
|
|
19
|
-
onAbort = ()=>resolve({
|
|
20
|
-
kind: "abort"
|
|
21
|
-
});
|
|
22
|
-
if (signal.aborted) onAbort();
|
|
23
|
-
else signal.addEventListener("abort", onAbort, {
|
|
24
|
-
once: true
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
let pending;
|
|
28
|
-
try {
|
|
29
|
-
yield _ssewire.sseWire.formatComment("open");
|
|
30
|
-
while(!signal.aborted){
|
|
31
|
-
pending ??= iterator.next().then((result)=>({
|
|
32
|
-
kind: "item",
|
|
33
|
-
result
|
|
34
|
-
}));
|
|
35
|
-
let timer;
|
|
36
|
-
const steps = [
|
|
37
|
-
pending,
|
|
38
|
-
abortStep
|
|
39
|
-
];
|
|
40
|
-
if (heartbeatMs > 0) {
|
|
41
|
-
steps.push(new Promise((resolve)=>{
|
|
42
|
-
timer = setTimeout(()=>resolve({
|
|
43
|
-
kind: "heartbeat"
|
|
44
|
-
}), heartbeatMs);
|
|
45
|
-
}));
|
|
46
|
-
}
|
|
47
|
-
let step;
|
|
48
|
-
try {
|
|
49
|
-
step = await Promise.race(steps);
|
|
50
|
-
} finally{
|
|
51
|
-
clearTimeout(timer);
|
|
52
|
-
}
|
|
53
|
-
if (step.kind === "abort") return;
|
|
54
|
-
if (step.kind === "heartbeat") {
|
|
55
|
-
yield _ssewire.sseWire.formatComment("heartbeat");
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
pending = undefined;
|
|
59
|
-
if (step.result.done) return;
|
|
60
|
-
yield _ssewire.sseWire.formatMessage(step.result.value);
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
// Headers are already sent, so the only honest thing left is to log and end the stream.
|
|
64
|
-
if (!signal.aborted) logger.error("SSE producer failed", error);
|
|
65
|
-
} finally{
|
|
66
|
-
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
67
|
-
// If the producer has not answered its last `next()`, `return()` waits behind it. That is
|
|
68
|
-
// why handlers must pass the signal to whatever they wait on.
|
|
69
|
-
options.onProducerStopped(Promise.resolve().then(()=>iterator.return?.()).then(()=>undefined, (error)=>{
|
|
70
|
-
if (!signal.aborted) logger.error("SSE producer failed while stopping", error);
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One server-sent event. A bare `string` yielded by a handler is shorthand for `{ data }`.
|
|
3
|
-
*
|
|
4
|
-
* `data` is written as-is when it is a string and as JSON otherwise.
|
|
5
|
-
*/ "use strict";
|
|
6
|
-
Object.defineProperty(exports, "__esModule", {
|
|
7
|
-
value: true
|
|
8
|
-
});
|
|
9
|
-
function _export(target, all) {
|
|
10
|
-
for(var name in all)Object.defineProperty(target, name, {
|
|
11
|
-
enumerable: true,
|
|
12
|
-
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
_export(exports, {
|
|
16
|
-
get DEFAULT_SSE_HEARTBEAT_MS () {
|
|
17
|
-
return DEFAULT_SSE_HEARTBEAT_MS;
|
|
18
|
-
},
|
|
19
|
-
get SseResponse () {
|
|
20
|
-
return SseResponse;
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
const DEFAULT_SSE_HEARTBEAT_MS = 15_000;
|
|
24
|
-
class SseResponse {
|
|
25
|
-
events;
|
|
26
|
-
onRelease;
|
|
27
|
-
released;
|
|
28
|
-
constructor(events, onRelease){
|
|
29
|
-
this.events = events;
|
|
30
|
-
this.onRelease = onRelease;
|
|
31
|
-
}
|
|
32
|
-
/** Safe to call more than once. */ release() {
|
|
33
|
-
this.released ??= this.onRelease();
|
|
34
|
-
return this.released;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "sseWire", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return sseWire;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
/** Line breaks would end a field early, so a client-controlled `id` could inject extra fields. */ function singleLine(value) {
|
|
12
|
-
return value.replace(/[\r\n]+/g, " ");
|
|
13
|
-
}
|
|
14
|
-
function toMessage(item) {
|
|
15
|
-
if (typeof item === "object" && item !== null && "data" in item) {
|
|
16
|
-
return item;
|
|
17
|
-
}
|
|
18
|
-
return {
|
|
19
|
-
data: item
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/** Encode one event as the text a browser's `EventSource` parses. */ function formatMessage(item) {
|
|
23
|
-
const { data, event, id, retry } = toMessage(item);
|
|
24
|
-
let frame = "";
|
|
25
|
-
if (id != null) frame += `id: ${singleLine(String(id))}\n`;
|
|
26
|
-
if (event != null) frame += `event: ${singleLine(event)}\n`;
|
|
27
|
-
if (retry != null && Number.isFinite(retry)) frame += `retry: ${Math.trunc(retry)}\n`;
|
|
28
|
-
const text = typeof data === "string" ? data : JSON.stringify(data) ?? "";
|
|
29
|
-
for (const line of text.split(/\r\n|\r|\n/)){
|
|
30
|
-
frame += `data: ${line}\n`;
|
|
31
|
-
}
|
|
32
|
-
return `${frame}\n`;
|
|
33
|
-
}
|
|
34
|
-
/** A comment line: ignored by `EventSource`, but it is traffic on the wire. */ function formatComment(text) {
|
|
35
|
-
return `: ${singleLine(text)}\n\n`;
|
|
36
|
-
}
|
|
37
|
-
const sseWire = {
|
|
38
|
-
formatMessage,
|
|
39
|
-
formatComment
|
|
40
|
-
};
|