@decohere/http 0.0.1-dev.126 → 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.
Files changed (293) hide show
  1. package/README.md +2 -2
  2. package/package.json +4 -13
  3. package/src/app/app.ts +147 -0
  4. package/src/app/module.ts +19 -0
  5. package/src/auth/ability.ts +56 -0
  6. package/src/auth/auth.config.ts +34 -0
  7. package/src/auth/auth.extensions.ts +115 -0
  8. package/src/auth/auth.types.ts +124 -0
  9. package/src/auth/casl-authorization.service.ts +62 -0
  10. package/{types/src/auth/principal-provider.d.ts → src/auth/principal-provider.ts} +13 -5
  11. package/src/auth/safe-outbound-url.ts +117 -0
  12. package/src/auth/token-service.ts +192 -0
  13. package/src/builder/builder.ts +118 -0
  14. package/{es6/src/const.js → src/const.ts} +25 -17
  15. package/src/health/health.controller.ts +34 -0
  16. package/src/health/health.extensions.ts +53 -0
  17. package/src/health/readiness.service.ts +33 -0
  18. package/{types/src/health/readiness.types.d.ts → src/health/readiness.types.ts} +4 -8
  19. package/src/hosting/hosted-service-host.ts +102 -0
  20. package/src/hosting/hosted-service.ts +31 -0
  21. package/src/http/http.compression.ts +38 -0
  22. package/src/http/http.extensions.ts +244 -0
  23. package/{types/src/http/http.options.store.d.ts → src/http/http.options.store.ts} +11 -1
  24. package/src/http/http.options.ts +41 -0
  25. package/{types/src/http/http.security.d.ts → src/http/http.security.ts} +16 -10
  26. package/src/http/http.static.ts +359 -0
  27. package/{es6/src/index.js → src/index.ts} +1 -0
  28. package/src/openapi/index.ts +22 -0
  29. package/src/openapi/openapi.generator.ts +78 -0
  30. package/src/openapi/openapi.types.ts +60 -0
  31. package/src/openapi/request-schema.ts +155 -0
  32. package/src/openapi/request-validator.ts +95 -0
  33. package/src/providers/fastify.provider.ts +454 -0
  34. package/src/routing/anvil.types.ts +150 -0
  35. package/src/routing/decorators/argument.decorator.ts +33 -0
  36. package/src/routing/decorators/auth.decorator.ts +79 -0
  37. package/src/routing/decorators/controller.decorator.ts +9 -0
  38. package/src/routing/decorators/field.decorator.ts +15 -0
  39. package/src/routing/decorators/request.decorator.ts +34 -0
  40. package/src/routing/decorators/response.decorator.ts +18 -0
  41. package/src/routing/decorators/route.decorator.ts +52 -0
  42. package/src/routing/filters/exception-filter-host.ts +90 -0
  43. package/src/routing/filters/exception-filter.ts +29 -0
  44. package/src/routing/middleware/http-access-log.middleware.ts +36 -0
  45. package/src/routing/middleware/middleware.ts +26 -0
  46. package/src/routing/middleware/request-id.ts +18 -0
  47. package/src/routing/path.util.ts +38 -0
  48. package/src/routing/pipes/pipes.ts +132 -0
  49. package/src/routing/services/route-argument-resolver.ts +92 -0
  50. package/src/routing/services/route-registry.ts +229 -0
  51. package/src/routing/services/router.ts +166 -0
  52. package/src/sse/sse.decorator.ts +41 -0
  53. package/src/sse/sse.encoder.ts +86 -0
  54. package/src/sse/sse.types.ts +47 -0
  55. package/src/sse/sse.wire.ts +34 -0
  56. package/src/testing/boot-module.ts +63 -0
  57. package/src/testing/sse-reader.ts +120 -0
  58. package/tests/app.hosted-services.spec.ts +292 -0
  59. package/tests/app.shutdown.integration.spec.ts +160 -0
  60. package/tests/app.spec.ts +132 -0
  61. package/tests/auth.ability.spec.ts +48 -0
  62. package/tests/auth.decorators.spec.ts +20 -0
  63. package/tests/auth.fail-closed.pentest.spec.ts +77 -0
  64. package/tests/auth.integration.spec.ts +234 -0
  65. package/tests/auth.jwks-cache.spec.ts +52 -0
  66. package/tests/auth.missing-auth.pentest.spec.ts +56 -0
  67. package/tests/auth.oidc-ssrf.pentest.spec.ts +72 -0
  68. package/tests/auth.oidc.integration.spec.ts +161 -0
  69. package/tests/auth.token-service.spec.ts +251 -0
  70. package/tests/builder.spec.ts +12 -0
  71. package/tests/health.integration.spec.ts +111 -0
  72. package/tests/helpers/listen-ephemeral.ts +13 -0
  73. package/tests/helpers/local-oidc-server.ts +100 -0
  74. package/tests/http.access-log.integration.spec.ts +111 -0
  75. package/tests/http.boolean-query.integration.spec.ts +59 -0
  76. package/tests/http.compression.integration.spec.ts +604 -0
  77. package/tests/http.date-query.integration.spec.ts +71 -0
  78. package/tests/http.global-prefix.integration.spec.ts +284 -0
  79. package/tests/http.number-query.integration.spec.ts +65 -0
  80. package/tests/http.pino-roll-hmr.integration.spec.ts +79 -0
  81. package/tests/http.pipeline-order.integration.spec.ts +95 -0
  82. package/tests/http.request-cleanup.integration.spec.ts +57 -0
  83. package/tests/http.request-id-scope.pentest.spec.ts +50 -0
  84. package/tests/http.security.integration.spec.ts +106 -0
  85. package/tests/http.static.integration.spec.ts +847 -0
  86. package/tests/http.static.spec.ts +111 -0
  87. package/tests/http.surface.integration.spec.ts +167 -0
  88. package/tests/openapi.integration.spec.ts +193 -0
  89. package/tests/openapi.validator-cache.integration.spec.ts +55 -0
  90. package/tests/routing.decorators.spec.ts +15 -0
  91. package/tests/routing.registry.spec.ts +44 -0
  92. package/tests/routing.resolver.spec.ts +92 -0
  93. package/tests/sse.integration.spec.ts +421 -0
  94. package/tests/sse.wire.spec.ts +33 -0
  95. package/LICENSE +0 -15
  96. package/commonjs/src/app/app.js +0 -166
  97. package/commonjs/src/app/index.js +0 -19
  98. package/commonjs/src/app/module.js +0 -17
  99. package/commonjs/src/auth/ability.js +0 -54
  100. package/commonjs/src/auth/auth.config.js +0 -23
  101. package/commonjs/src/auth/auth.extensions.js +0 -106
  102. package/commonjs/src/auth/auth.types.js +0 -65
  103. package/commonjs/src/auth/casl-authorization.service.js +0 -36
  104. package/commonjs/src/auth/index.js +0 -23
  105. package/commonjs/src/auth/principal-provider.js +0 -19
  106. package/commonjs/src/auth/safe-outbound-url.js +0 -102
  107. package/commonjs/src/auth/token-service.js +0 -151
  108. package/commonjs/src/builder/builder.js +0 -95
  109. package/commonjs/src/builder/index.js +0 -18
  110. package/commonjs/src/const.js +0 -87
  111. package/commonjs/src/health/health.controller.js +0 -75
  112. package/commonjs/src/health/health.extensions.js +0 -50
  113. package/commonjs/src/health/index.js +0 -21
  114. package/commonjs/src/health/readiness.service.js +0 -67
  115. package/commonjs/src/health/readiness.types.js +0 -7
  116. package/commonjs/src/hosting/hosted-service-host.js +0 -88
  117. package/commonjs/src/hosting/hosted-service.js +0 -11
  118. package/commonjs/src/hosting/index.js +0 -19
  119. package/commonjs/src/http/http.compression.js +0 -27
  120. package/commonjs/src/http/http.extensions.js +0 -269
  121. package/commonjs/src/http/http.options.js +0 -26
  122. package/commonjs/src/http/http.options.store.js +0 -20
  123. package/commonjs/src/http/http.security.js +0 -27
  124. package/commonjs/src/http/http.static.js +0 -248
  125. package/commonjs/src/http/index.js +0 -22
  126. package/commonjs/src/index.js +0 -27
  127. package/commonjs/src/openapi/index.js +0 -45
  128. package/commonjs/src/openapi/openapi.generator.js +0 -103
  129. package/commonjs/src/openapi/openapi.types.js +0 -4
  130. package/commonjs/src/openapi/request-schema.js +0 -187
  131. package/commonjs/src/openapi/request-validator.js +0 -85
  132. package/commonjs/src/providers/fastify.provider.js +0 -391
  133. package/commonjs/src/providers/index.js +0 -18
  134. package/commonjs/src/routing/anvil.types.js +0 -99
  135. package/commonjs/src/routing/decorators/argument.decorator.js +0 -49
  136. package/commonjs/src/routing/decorators/auth.decorator.js +0 -70
  137. package/commonjs/src/routing/decorators/controller.decorator.js +0 -16
  138. package/commonjs/src/routing/decorators/field.decorator.js +0 -25
  139. package/commonjs/src/routing/decorators/index.js +0 -24
  140. package/commonjs/src/routing/decorators/request.decorator.js +0 -30
  141. package/commonjs/src/routing/decorators/response.decorator.js +0 -34
  142. package/commonjs/src/routing/decorators/route.decorator.js +0 -67
  143. package/commonjs/src/routing/filters/exception-filter-host.js +0 -145
  144. package/commonjs/src/routing/filters/exception-filter.js +0 -28
  145. package/commonjs/src/routing/index.js +0 -25
  146. package/commonjs/src/routing/middleware/http-access-log.middleware.js +0 -47
  147. package/commonjs/src/routing/middleware/middleware.js +0 -20
  148. package/commonjs/src/routing/middleware/request-id.js +0 -30
  149. package/commonjs/src/routing/path.util.js +0 -51
  150. package/commonjs/src/routing/pipes/index.js +0 -18
  151. package/commonjs/src/routing/pipes/pipes.js +0 -145
  152. package/commonjs/src/routing/services/index.js +0 -18
  153. package/commonjs/src/routing/services/route-argument-resolver.js +0 -77
  154. package/commonjs/src/routing/services/route-registry.js +0 -194
  155. package/commonjs/src/routing/services/router.js +0 -158
  156. package/commonjs/src/sse/index.js +0 -26
  157. package/commonjs/src/sse/sse.decorator.js +0 -42
  158. package/commonjs/src/sse/sse.encoder.js +0 -73
  159. package/commonjs/src/sse/sse.types.js +0 -36
  160. package/commonjs/src/sse/sse.wire.js +0 -40
  161. package/commonjs/src/testing/boot-module.js +0 -38
  162. package/commonjs/src/testing/index.js +0 -20
  163. package/commonjs/src/testing/sse-reader.js +0 -98
  164. package/es6/src/app/app.js +0 -148
  165. package/es6/src/app/index.js +0 -2
  166. package/es6/src/app/module.js +0 -7
  167. package/es6/src/auth/ability.js +0 -45
  168. package/es6/src/auth/auth.config.js +0 -19
  169. package/es6/src/auth/auth.extensions.js +0 -83
  170. package/es6/src/auth/auth.types.js +0 -35
  171. package/es6/src/auth/casl-authorization.service.js +0 -40
  172. package/es6/src/auth/index.js +0 -6
  173. package/es6/src/auth/principal-provider.js +0 -14
  174. package/es6/src/auth/safe-outbound-url.js +0 -99
  175. package/es6/src/auth/token-service.js +0 -141
  176. package/es6/src/builder/builder.js +0 -85
  177. package/es6/src/builder/index.js +0 -1
  178. package/es6/src/health/health.controller.js +0 -65
  179. package/es6/src/health/health.extensions.js +0 -40
  180. package/es6/src/health/index.js +0 -4
  181. package/es6/src/health/readiness.service.js +0 -57
  182. package/es6/src/health/readiness.types.js +0 -4
  183. package/es6/src/hosting/hosted-service-host.js +0 -81
  184. package/es6/src/hosting/hosted-service.js +0 -8
  185. package/es6/src/hosting/index.js +0 -2
  186. package/es6/src/http/http.compression.js +0 -9
  187. package/es6/src/http/http.extensions.js +0 -259
  188. package/es6/src/http/http.options.js +0 -16
  189. package/es6/src/http/http.options.store.js +0 -13
  190. package/es6/src/http/http.security.js +0 -9
  191. package/es6/src/http/http.static.js +0 -224
  192. package/es6/src/http/index.js +0 -5
  193. package/es6/src/openapi/index.js +0 -3
  194. package/es6/src/openapi/openapi.generator.js +0 -82
  195. package/es6/src/openapi/openapi.types.js +0 -1
  196. package/es6/src/openapi/request-schema.js +0 -160
  197. package/es6/src/openapi/request-validator.js +0 -71
  198. package/es6/src/providers/fastify.provider.js +0 -376
  199. package/es6/src/providers/index.js +0 -1
  200. package/es6/src/routing/anvil.types.js +0 -57
  201. package/es6/src/routing/decorators/argument.decorator.js +0 -28
  202. package/es6/src/routing/decorators/auth.decorator.js +0 -58
  203. package/es6/src/routing/decorators/controller.decorator.js +0 -6
  204. package/es6/src/routing/decorators/field.decorator.js +0 -15
  205. package/es6/src/routing/decorators/index.js +0 -7
  206. package/es6/src/routing/decorators/request.decorator.js +0 -24
  207. package/es6/src/routing/decorators/response.decorator.js +0 -16
  208. package/es6/src/routing/decorators/route.decorator.js +0 -37
  209. package/es6/src/routing/filters/exception-filter-host.js +0 -127
  210. package/es6/src/routing/filters/exception-filter.js +0 -10
  211. package/es6/src/routing/index.js +0 -8
  212. package/es6/src/routing/middleware/http-access-log.middleware.js +0 -37
  213. package/es6/src/routing/middleware/middleware.js +0 -10
  214. package/es6/src/routing/middleware/request-id.js +0 -14
  215. package/es6/src/routing/path.util.js +0 -33
  216. package/es6/src/routing/pipes/index.js +0 -1
  217. package/es6/src/routing/pipes/pipes.js +0 -118
  218. package/es6/src/routing/services/index.js +0 -1
  219. package/es6/src/routing/services/route-argument-resolver.js +0 -67
  220. package/es6/src/routing/services/route-registry.js +0 -184
  221. package/es6/src/routing/services/router.js +0 -148
  222. package/es6/src/sse/index.js +0 -2
  223. package/es6/src/sse/sse.decorator.js +0 -31
  224. package/es6/src/sse/sse.encoder.js +0 -67
  225. package/es6/src/sse/sse.types.js +0 -22
  226. package/es6/src/sse/sse.wire.js +0 -30
  227. package/es6/src/testing/boot-module.js +0 -35
  228. package/es6/src/testing/index.js +0 -2
  229. package/es6/src/testing/sse-reader.js +0 -91
  230. package/types/src/app/app.d.ts +0 -41
  231. package/types/src/app/module.d.ts +0 -15
  232. package/types/src/auth/ability.d.ts +0 -19
  233. package/types/src/auth/auth.config.d.ts +0 -28
  234. package/types/src/auth/auth.extensions.d.ts +0 -53
  235. package/types/src/auth/auth.types.d.ts +0 -73
  236. package/types/src/auth/casl-authorization.service.d.ts +0 -28
  237. package/types/src/auth/safe-outbound-url.d.ts +0 -9
  238. package/types/src/auth/token-service.d.ts +0 -31
  239. package/types/src/builder/builder.d.ts +0 -36
  240. package/types/src/const.d.ts +0 -32
  241. package/types/src/health/health.controller.d.ts +0 -16
  242. package/types/src/health/health.extensions.d.ts +0 -31
  243. package/types/src/health/readiness.service.d.ts +0 -9
  244. package/types/src/hosting/hosted-service-host.d.ts +0 -37
  245. package/types/src/hosting/hosted-service.d.ts +0 -31
  246. package/types/src/http/http.compression.d.ts +0 -32
  247. package/types/src/http/http.extensions.d.ts +0 -79
  248. package/types/src/http/http.options.d.ts +0 -39
  249. package/types/src/http/http.static.d.ts +0 -160
  250. package/types/src/index.d.ts +0 -10
  251. package/types/src/openapi/index.d.ts +0 -6
  252. package/types/src/openapi/openapi.generator.d.ts +0 -6
  253. package/types/src/openapi/openapi.types.d.ts +0 -58
  254. package/types/src/openapi/request-schema.d.ts +0 -21
  255. package/types/src/openapi/request-validator.d.ts +0 -9
  256. package/types/src/providers/fastify.provider.d.ts +0 -56
  257. package/types/src/routing/anvil.types.d.ts +0 -119
  258. package/types/src/routing/decorators/argument.decorator.d.ts +0 -11
  259. package/types/src/routing/decorators/auth.decorator.d.ts +0 -30
  260. package/types/src/routing/decorators/controller.decorator.d.ts +0 -3
  261. package/types/src/routing/decorators/field.decorator.d.ts +0 -2
  262. package/types/src/routing/decorators/request.decorator.d.ts +0 -8
  263. package/types/src/routing/decorators/response.decorator.d.ts +0 -4
  264. package/types/src/routing/decorators/route.decorator.d.ts +0 -7
  265. package/types/src/routing/filters/exception-filter-host.d.ts +0 -19
  266. package/types/src/routing/filters/exception-filter.d.ts +0 -16
  267. package/types/src/routing/middleware/http-access-log.middleware.d.ts +0 -8
  268. package/types/src/routing/middleware/middleware.d.ts +0 -10
  269. package/types/src/routing/middleware/request-id.d.ts +0 -6
  270. package/types/src/routing/path.util.d.ts +0 -9
  271. package/types/src/routing/pipes/pipes.d.ts +0 -21
  272. package/types/src/routing/services/route-argument-resolver.d.ts +0 -10
  273. package/types/src/routing/services/route-registry.d.ts +0 -20
  274. package/types/src/routing/services/router.d.ts +0 -22
  275. package/types/src/sse/sse.decorator.d.ts +0 -17
  276. package/types/src/sse/sse.encoder.d.ts +0 -16
  277. package/types/src/sse/sse.types.d.ts +0 -37
  278. package/types/src/sse/sse.wire.d.ts +0 -9
  279. package/types/src/testing/boot-module.d.ts +0 -34
  280. package/types/src/testing/sse-reader.d.ts +0 -29
  281. /package/{types/src/app/index.d.ts → src/app/index.ts} +0 -0
  282. /package/{types/src/auth/index.d.ts → src/auth/index.ts} +0 -0
  283. /package/{types/src/builder/index.d.ts → src/builder/index.ts} +0 -0
  284. /package/{types/src/health/index.d.ts → src/health/index.ts} +0 -0
  285. /package/{types/src/hosting/index.d.ts → src/hosting/index.ts} +0 -0
  286. /package/{types/src/http/index.d.ts → src/http/index.ts} +0 -0
  287. /package/{types/src/providers/index.d.ts → src/providers/index.ts} +0 -0
  288. /package/{types/src/routing/decorators/index.d.ts → src/routing/decorators/index.ts} +0 -0
  289. /package/{types/src/routing/index.d.ts → src/routing/index.ts} +0 -0
  290. /package/{types/src/routing/pipes/index.d.ts → src/routing/pipes/index.ts} +0 -0
  291. /package/{types/src/routing/services/index.d.ts → src/routing/services/index.ts} +0 -0
  292. /package/{types/src/sse/index.d.ts → src/sse/index.ts} +0 -0
  293. /package/{types/src/testing/index.d.ts → src/testing/index.ts} +0 -0
@@ -1,54 +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 ADMIN_ROLE () {
13
- return ADMIN_ROLE;
14
- },
15
- get createPrincipalFromPayload () {
16
- return createPrincipalFromPayload;
17
- },
18
- get defineAbilitiesFor () {
19
- return defineAbilitiesFor;
20
- }
21
- });
22
- const _ability = require("@casl/ability");
23
- const ADMIN_ROLE = "admin";
24
- function defineAbilitiesFor(principal) {
25
- const { can, build } = new _ability.AbilityBuilder(_ability.createMongoAbility);
26
- if (principal.roles?.includes(ADMIN_ROLE)) {
27
- can("manage", "all");
28
- return build();
29
- }
30
- for (const scope of principal.scopes ?? []){
31
- const [action, subject] = scope.split(":");
32
- if (action && subject) can(action, subject);
33
- }
34
- return build();
35
- }
36
- function createPrincipalFromPayload(payload) {
37
- const sub = typeof payload.sub === "string" ? payload.sub : "";
38
- const fromScopeClaim = typeof payload.scope === "string" ? payload.scope.split(" ").filter(Boolean) : Array.isArray(payload.scopes) ? payload.scopes.filter((s)=>typeof s === "string") : [];
39
- const fromPermissions = Array.isArray(payload.permissions) ? payload.permissions.filter((s)=>typeof s === "string") : [];
40
- const merged = [
41
- ...new Set([
42
- ...fromScopeClaim,
43
- ...fromPermissions
44
- ])
45
- ];
46
- const scopes = merged.length > 0 ? merged : undefined;
47
- const roles = Array.isArray(payload.roles) ? payload.roles.filter((r)=>typeof r === "string") : undefined;
48
- return {
49
- ...payload,
50
- sub,
51
- roles: roles && roles.length > 0 ? roles : undefined,
52
- scopes
53
- };
54
- }
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "AuthConfig", {
6
- enumerable: true,
7
- get: function() {
8
- return AuthConfig;
9
- }
10
- });
11
- class AuthConfig {
12
- /** OIDC discovery URL — the issuer base URL, e.g. https://accounts.google.com.
13
- * The framework appends `/.well-known/openid-configuration` automatically.
14
- * Use this instead of `jwksUrl` for any standard OIDC-compliant IdP.
15
- */ discoveryUrl;
16
- /** JWKS endpoint URL (RS256 / ES256 via remote key set). */ jwksUrl;
17
- /** PEM-encoded public key or JWK JSON string (RS256 / ES256 static key). */ publicKey;
18
- algorithms;
19
- /** Shared secret for HS256. */ secret;
20
- /** Issuer claim to validate (all non-devStatic variants). */ issuer;
21
- /** Audience claim to validate (all non-devStatic variants). */ audience;
22
- /** Static principal injected for every request (development only). */ devStatic;
23
- }
@@ -1,106 +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 ADMIN_ROLE () {
13
- return _ability.ADMIN_ROLE;
14
- },
15
- get BuilderExtensions () {
16
- return BuilderExtensions;
17
- },
18
- get createPrincipalFromPayload () {
19
- return _ability.createPrincipalFromPayload;
20
- },
21
- get defineAbilitiesFor () {
22
- return _ability.defineAbilitiesFor;
23
- }
24
- });
25
- const _extensibility = require("@decohere/core/extensibility");
26
- const _builder = require("../builder/builder.js");
27
- const _const = require("../const.js");
28
- const _ability = require("./ability.js");
29
- const _authconfig = require("./auth.config.js");
30
- const _authtypes = require("./auth.types.js");
31
- const _caslauthorizationservice = require("./casl-authorization.service.js");
32
- const _tokenservice = require("./token-service.js");
33
- function _ts_decorate(decorators, target, key, desc) {
34
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
35
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
36
- 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;
37
- return c > 3 && r && Object.defineProperty(target, key, r), r;
38
- }
39
- function _ts_metadata(k, v) {
40
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
41
- }
42
- class BuilderExtensions {
43
- static withAuth(builder, abilityFactory = _ability.defineAbilitiesFor, options) {
44
- builder.registerPreBuildStep(async (configService, containerBuilder)=>{
45
- const authConfig = await configService.get(_authconfig.AuthConfig);
46
- const tokenConfig = toTokenServiceConfig(authConfig);
47
- const tokenService = new _tokenservice.TokenService(tokenConfig, options?.principalMapper);
48
- containerBuilder.registerSingleton(_const.TokenServiceToken, tokenService);
49
- containerBuilder.registerSingleton(_const.AuthorizationServiceToken, new _caslauthorizationservice.CaslAuthorizationService(abilityFactory, tokenService));
50
- });
51
- return builder;
52
- }
53
- }
54
- _ts_decorate([
55
- (0, _extensibility.extension)(_builder.Builder),
56
- _ts_metadata("design:type", Function),
57
- _ts_metadata("design:paramtypes", [
58
- typeof _builder.Builder === "undefined" ? Object : _builder.Builder,
59
- typeof AbilityFactory === "undefined" ? Object : AbilityFactory,
60
- typeof WithAuthOptions === "undefined" ? Object : WithAuthOptions
61
- ]),
62
- _ts_metadata("design:returntype", void 0)
63
- ], BuilderExtensions, "withAuth", null);
64
- function toTokenServiceConfig(config) {
65
- // Prefer real verification strategies over devStatic so a leftover
66
- // development block cannot disable OIDC/JWKS in any environment.
67
- if (config.discoveryUrl != null) {
68
- (0, _authtypes.assertNonEmptyAudience)(config.audience);
69
- return {
70
- discoveryUrl: config.discoveryUrl,
71
- audience: config.audience
72
- };
73
- }
74
- if (config.jwksUrl != null) {
75
- (0, _authtypes.assertNonEmptyAudience)(config.audience);
76
- return {
77
- jwksUrl: config.jwksUrl,
78
- issuer: config.issuer,
79
- audience: config.audience
80
- };
81
- }
82
- if (config.publicKey != null) {
83
- (0, _authtypes.assertNonEmptyAudience)(config.audience);
84
- return {
85
- publicKey: config.publicKey,
86
- algorithms: config.algorithms,
87
- issuer: config.issuer,
88
- audience: config.audience
89
- };
90
- }
91
- if (config.secret != null) {
92
- (0, _authtypes.assertNonEmptyAudience)(config.audience);
93
- return {
94
- secret: config.secret,
95
- issuer: config.issuer,
96
- audience: config.audience
97
- };
98
- }
99
- if (config.devStatic != null) {
100
- (0, _authtypes.assertDevStaticAllowed)();
101
- return {
102
- devStatic: config.devStatic
103
- };
104
- }
105
- throw new Error("AuthConfig must specify one of: discoveryUrl, jwksUrl, publicKey, secret, or devStatic");
106
- }
@@ -1,65 +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 assertDevStaticAllowed () {
13
- return assertDevStaticAllowed;
14
- },
15
- get assertNonEmptyAudience () {
16
- return assertNonEmptyAudience;
17
- },
18
- get isDevStaticConfig () {
19
- return isDevStaticConfig;
20
- },
21
- get isDevelopmentNodeEnv () {
22
- return isDevelopmentNodeEnv;
23
- },
24
- get isDiscoveryConfig () {
25
- return isDiscoveryConfig;
26
- },
27
- get isJwksConfig () {
28
- return isJwksConfig;
29
- },
30
- get isPublicKeyConfig () {
31
- return isPublicKeyConfig;
32
- },
33
- get isSecretConfig () {
34
- return isSecretConfig;
35
- }
36
- });
37
- function isDiscoveryConfig(config) {
38
- return "discoveryUrl" in config;
39
- }
40
- function isDevStaticConfig(config) {
41
- return "devStatic" in config;
42
- }
43
- function isJwksConfig(config) {
44
- return "jwksUrl" in config;
45
- }
46
- function isPublicKeyConfig(config) {
47
- return "publicKey" in config;
48
- }
49
- function isSecretConfig(config) {
50
- return "secret" in config;
51
- }
52
- function isDevelopmentNodeEnv(nodeEnv = process.env.NODE_ENV) {
53
- const env = nodeEnv?.toLowerCase();
54
- return env === "development" || env === "dev";
55
- }
56
- function assertDevStaticAllowed(nodeEnv = process.env.NODE_ENV) {
57
- if (!isDevelopmentNodeEnv(nodeEnv)) {
58
- throw new Error(`AuthConfig.devStatic is only allowed when NODE_ENV is "development" or "dev" (got ${JSON.stringify(nodeEnv ?? "")}).`);
59
- }
60
- }
61
- function assertNonEmptyAudience(audience) {
62
- if (typeof audience !== "string" || audience.trim().length === 0) {
63
- throw new Error(`JWT audience must be a non-empty string (got ${JSON.stringify(audience)}). ` + "Empty audience disables aud validation and accepts tokens minted for other APIs.");
64
- }
65
- }
@@ -1,36 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "CaslAuthorizationService", {
6
- enumerable: true,
7
- get: function() {
8
- return CaslAuthorizationService;
9
- }
10
- });
11
- const _anviltypes = require("../routing/anvil.types.js");
12
- class CaslAuthorizationService {
13
- factory;
14
- tokenService;
15
- constructor(factory, tokenService){
16
- this.factory = factory;
17
- this.tokenService = tokenService;
18
- }
19
- async authorizeRequest(request, action, subject) {
20
- const principal = await this.authenticateRequest(request);
21
- await this.authorize(principal, action, subject);
22
- return principal;
23
- }
24
- async authenticateRequest(request) {
25
- if (!this.tokenService) {
26
- throw new Error("CaslAuthorizationService requires a TokenService to authenticate requests. Register it via .withAuth().");
27
- }
28
- return this.tokenService.verifyRequest(request);
29
- }
30
- async authorize(principal, action, subject) {
31
- const ability = this.factory(principal);
32
- if (ability.cannot(action, subject)) {
33
- throw new _anviltypes.ForbiddenError(`Cannot perform "${action}" on "${subject}"`);
34
- }
35
- }
36
- }
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- _export_star(require("./ability.js"), exports);
6
- _export_star(require("./auth.config.js"), exports);
7
- _export_star(require("./auth.types.js"), exports);
8
- _export_star(require("./casl-authorization.service.js"), exports);
9
- _export_star(require("./principal-provider.js"), exports);
10
- _export_star(require("./token-service.js"), exports);
11
- function _export_star(from, to) {
12
- Object.keys(from).forEach(function(k) {
13
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
14
- Object.defineProperty(to, k, {
15
- enumerable: true,
16
- get: function() {
17
- return from[k];
18
- }
19
- });
20
- }
21
- });
22
- return from;
23
- }
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "PrincipalProvider", {
6
- enumerable: true,
7
- get: function() {
8
- return PrincipalProvider;
9
- }
10
- });
11
- class PrincipalProvider {
12
- _principal;
13
- get currentPrincipal() {
14
- return this._principal;
15
- }
16
- setPrincipal(principal) {
17
- this._principal = principal;
18
- }
19
- }
@@ -1,102 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "assertSafeOutboundUrl", {
6
- enumerable: true,
7
- get: function() {
8
- return assertSafeOutboundUrl;
9
- }
10
- });
11
- const _promises = require("node:dns/promises");
12
- const _nodenet = require("node:net");
13
- async function assertSafeOutboundUrl(raw, label) {
14
- let url;
15
- try {
16
- url = new URL(raw);
17
- } catch {
18
- throw new Error(`Invalid ${label}: ${raw}`);
19
- }
20
- if (url.protocol !== "https:" && url.protocol !== "http:") {
21
- throw new Error(`${label} must use http or https (got ${url.protocol})`);
22
- }
23
- if (url.username || url.password) {
24
- throw new Error(`${label} must not include credentials`);
25
- }
26
- const hostname = url.hostname.replace(/^\[|\]$/g, "");
27
- if (isBlockedHostname(hostname)) {
28
- throw new Error(`${label} host is not allowed (${hostname})`);
29
- }
30
- const ips = await resolveIps(hostname);
31
- const allowLoopback = isLoopbackAllowed();
32
- for (const ip of ips){
33
- if (isBlockedIp(ip, allowLoopback)) {
34
- throw new Error(`${label} resolves to a blocked address (${ip})`);
35
- }
36
- }
37
- if (url.protocol === "http:") {
38
- const loopbackOnly = isLoopbackHostname(hostname) || ips.length > 0 && ips.every((ip)=>isLoopbackIp(ip));
39
- if (!loopbackOnly || !allowLoopback) {
40
- throw new Error(`${label} must use https unless targeting loopback in development/test`);
41
- }
42
- }
43
- return url;
44
- }
45
- function isLoopbackAllowed() {
46
- const env = process.env.NODE_ENV ?? "";
47
- return env === "development" || env === "dev" || env === "test";
48
- }
49
- function isLoopbackHostname(hostname) {
50
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
51
- }
52
- function isBlockedHostname(hostname) {
53
- const lower = hostname.toLowerCase();
54
- return lower === "metadata.google.internal" || lower === "metadata" || lower.endsWith(".metadata.google.internal");
55
- }
56
- async function resolveIps(hostname) {
57
- if ((0, _nodenet.isIP)(hostname)) {
58
- return [
59
- hostname
60
- ];
61
- }
62
- const results = await (0, _promises.lookup)(hostname, {
63
- all: true,
64
- verbatim: true
65
- });
66
- return results.map((r)=>r.address);
67
- }
68
- function isLoopbackIp(ip) {
69
- const list = new _nodenet.BlockList();
70
- list.addSubnet("127.0.0.0", 8, "ipv4");
71
- list.addAddress("::1", "ipv6");
72
- list.addSubnet("::ffff:127.0.0.0", 104, "ipv6");
73
- return list.check(ip);
74
- }
75
- function isBlockedIp(ip, allowLoopback) {
76
- if (allowLoopback && isLoopbackIp(ip)) {
77
- return false;
78
- }
79
- const list = new _nodenet.BlockList();
80
- // IPv4 special-use / private
81
- list.addSubnet("0.0.0.0", 8, "ipv4");
82
- list.addSubnet("10.0.0.0", 8, "ipv4");
83
- list.addSubnet("100.64.0.0", 10, "ipv4"); // shared address space
84
- list.addSubnet("127.0.0.0", 8, "ipv4");
85
- list.addSubnet("169.254.0.0", 16, "ipv4"); // link-local / cloud metadata
86
- list.addSubnet("172.16.0.0", 12, "ipv4");
87
- list.addSubnet("192.168.0.0", 16, "ipv4");
88
- list.addSubnet("198.18.0.0", 15, "ipv4"); // benchmarking
89
- // IPv6
90
- list.addAddress("::1", "ipv6");
91
- list.addSubnet("fc00::", 7, "ipv6"); // unique local
92
- list.addSubnet("fe80::", 10, "ipv6"); // link-local
93
- if (list.check(ip)) {
94
- return true;
95
- }
96
- // Mapped IPv4 inside IPv6 (::ffff:a.b.c.d)
97
- const mapped = ip.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);
98
- if (mapped) {
99
- return isBlockedIp(mapped[1], allowLoopback);
100
- }
101
- return false;
102
- }
@@ -1,151 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "TokenService", {
6
- enumerable: true,
7
- get: function() {
8
- return TokenService;
9
- }
10
- });
11
- const _jose = require("jose");
12
- const _anviltypes = require("../routing/anvil.types.js");
13
- const _ability = require("./ability.js");
14
- const _authtypes = require("./auth.types.js");
15
- const _safeoutboundurl = require("./safe-outbound-url.js");
16
- class TokenService {
17
- config;
18
- principalMapper;
19
- /** Lazily resolved JWKS set when using OIDC discovery. */ discoveryJwks;
20
- discoveryIssuer;
21
- /** Remote key set for `jwksUrl` mode, created once so jose can cache the keys. */ configuredJwks;
22
- constructor(config, principalMapper){
23
- if ((0, _authtypes.isDevStaticConfig)(config)) {
24
- (0, _authtypes.assertDevStaticAllowed)();
25
- } else {
26
- (0, _authtypes.assertNonEmptyAudience)(config.audience);
27
- }
28
- this.config = config;
29
- this.principalMapper = principalMapper;
30
- }
31
- async verifyRequest(request) {
32
- const authHeader = request.headers.authorization;
33
- if (!authHeader) {
34
- throw new _anviltypes.UnauthorizedError("Missing Authorization header");
35
- }
36
- const spaceIdx = authHeader.indexOf(" ");
37
- if (spaceIdx === -1) {
38
- throw new _anviltypes.UnauthorizedError("Malformed Authorization header");
39
- }
40
- const scheme = authHeader.slice(0, spaceIdx);
41
- if (scheme !== "Bearer") {
42
- throw new _anviltypes.UnauthorizedError(`Unsupported authorization scheme: ${scheme}`);
43
- }
44
- const credentials = authHeader.slice(spaceIdx + 1);
45
- return this.verify(credentials);
46
- }
47
- async verify(credentials) {
48
- if ((0, _authtypes.isDevStaticConfig)(this.config)) {
49
- return this.config.devStatic;
50
- }
51
- try {
52
- const { key, issuer, audience } = await this.resolveVerificationContext();
53
- // jose's overloads don't accept Key | JWKS-getter as a union; runtime does.
54
- const { payload } = await (0, _jose.jwtVerify)(credentials, key, {
55
- issuer,
56
- audience
57
- });
58
- return this.mapPrincipal(payload);
59
- } catch (err) {
60
- throw new _anviltypes.UnauthorizedError(err instanceof Error ? err.message : "Token verification failed");
61
- }
62
- }
63
- /**
64
- * Resolve how to verify tokens for the configured strategy:
65
- * - OIDC discovery → fetch JWKS + issuer from `/.well-known/openid-configuration`
66
- * - explicit JWKS URL → remote key set + configured issuer/audience
67
- * - public key / shared secret → static key material + configured issuer/audience
68
- */ async resolveVerificationContext() {
69
- if ((0, _authtypes.isDiscoveryConfig)(this.config)) {
70
- const { jwks, issuer } = await this.resolveOidcDiscovery();
71
- return {
72
- key: jwks,
73
- issuer,
74
- audience: this.config.audience
75
- };
76
- }
77
- if ((0, _authtypes.isJwksConfig)(this.config)) {
78
- this.configuredJwks ??= (0, _jose.createRemoteJWKSet)(await (0, _safeoutboundurl.assertSafeOutboundUrl)(this.config.jwksUrl, "jwksUrl"));
79
- return {
80
- key: this.configuredJwks,
81
- issuer: this.config.issuer,
82
- audience: this.config.audience
83
- };
84
- }
85
- return {
86
- key: await this.getStaticKey(),
87
- issuer: this.config.issuer,
88
- audience: this.config.audience
89
- };
90
- }
91
- async resolveOidcDiscovery() {
92
- if (this.discoveryJwks && this.discoveryIssuer) {
93
- return {
94
- jwks: this.discoveryJwks,
95
- issuer: this.discoveryIssuer
96
- };
97
- }
98
- const { discoveryUrl } = this.config;
99
- await (0, _safeoutboundurl.assertSafeOutboundUrl)(discoveryUrl, "discoveryUrl");
100
- const resp = await fetch(`${discoveryUrl.replace(/\/$/, "")}/.well-known/openid-configuration`, {
101
- redirect: "error"
102
- });
103
- if (!resp.ok) {
104
- throw new Error(`OIDC discovery failed for ${discoveryUrl}: HTTP ${resp.status}`);
105
- }
106
- const doc = await resp.json();
107
- if (typeof doc.jwks_uri !== "string" || doc.jwks_uri.length === 0) {
108
- throw new Error(`OIDC discovery for ${discoveryUrl} did not return jwks_uri`);
109
- }
110
- const jwksUrl = await (0, _safeoutboundurl.assertSafeOutboundUrl)(doc.jwks_uri, "jwks_uri");
111
- this.discoveryIssuer = doc.issuer;
112
- this.discoveryJwks = (0, _jose.createRemoteJWKSet)(jwksUrl);
113
- return {
114
- jwks: this.discoveryJwks,
115
- issuer: this.discoveryIssuer
116
- };
117
- }
118
- /**
119
- * Sign a payload and return a JWT string.
120
- * Only available when configured with a SecretConfig (HS256).
121
- * For RS256/ES256 issuance, the caller is responsible for key management.
122
- */ async sign(payload, expiresIn = "1h") {
123
- if (!(0, _authtypes.isSecretConfig)(this.config)) {
124
- throw new Error("TokenService.sign() requires SecretConfig (shared secret / HS256)");
125
- }
126
- const key = new TextEncoder().encode(this.config.secret);
127
- return new _jose.SignJWT(payload).setProtectedHeader({
128
- alg: "HS256"
129
- }).setIssuedAt().setIssuer(this.config.issuer ?? "").setAudience(this.config.audience ?? "").setExpirationTime(expiresIn).sign(key);
130
- }
131
- async getStaticKey() {
132
- if ((0, _authtypes.isPublicKeyConfig)(this.config)) {
133
- const cfg = this.config;
134
- const trimmed = cfg.publicKey.trim();
135
- if (trimmed.startsWith("{")) {
136
- const jwk = JSON.parse(trimmed);
137
- return (0, _jose.importJWK)(jwk);
138
- }
139
- return (0, _jose.importSPKI)(trimmed, cfg.algorithms?.[0] ?? "RS256");
140
- }
141
- if ((0, _authtypes.isSecretConfig)(this.config)) {
142
- const enc = new TextEncoder().encode(this.config.secret);
143
- return enc;
144
- }
145
- throw new Error("Invalid TokenService configuration");
146
- }
147
- mapPrincipal(payload) {
148
- if (this.principalMapper) return this.principalMapper(payload);
149
- return (0, _ability.createPrincipalFromPayload)(payload);
150
- }
151
- }
@@ -1,95 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "Builder", {
6
- enumerable: true,
7
- get: function() {
8
- return Builder;
9
- }
10
- });
11
- const _crucible = require("@decohere/crucible");
12
- const _configuration = require("@decohere/core/configuration");
13
- const _scribe = require("@decohere/scribe");
14
- const _app = require("../app/app.js");
15
- const _const = require("../const.js");
16
- const _hostedservicehost = require("../hosting/hosted-service-host.js");
17
- class Builder {
18
- static create(options) {
19
- return new Builder(options);
20
- }
21
- containerBuilder;
22
- applicationName;
23
- logger = _scribe.scribe.logger("name");
24
- userServices = [];
25
- preBuildSteps = [];
26
- postBuildSteps = [];
27
- hostedServices = new _hostedservicehost.HostedServiceHost();
28
- constructor(options){
29
- this.containerBuilder = options?.containerBuilder ?? new _crucible.ServiceContainerBuilder();
30
- this.applicationName = options?.applicationName;
31
- }
32
- withServices(userServices) {
33
- this.userServices.push(userServices);
34
- return this;
35
- }
36
- /**
37
- * Run {@link HostedService}s for the life of the app: started in this order before the HTTP
38
- * server listens, stopped in reverse when the app stops (including SIGTERM and Flux reboots).
39
- * Each is registered as a singleton, so other services can inject it by its class.
40
- */ withHostedService(...types) {
41
- for (const type of types)this.containerBuilder.registerSingleton(type);
42
- this.hostedServices.add(...types);
43
- return this;
44
- }
45
- registerPreBuildStep(step) {
46
- this.preBuildSteps.push(step);
47
- }
48
- registerPostBuildStep(step) {
49
- this.postBuildSteps.push(step);
50
- }
51
- async buildAndStart(type) {
52
- const app = await this.build(type);
53
- await app.start();
54
- this.logger.info("App started...");
55
- return app;
56
- }
57
- async build(type) {
58
- this.logger.info("Building App...");
59
- this.configureUserServices();
60
- this.configureApp(type);
61
- await this.runPreBuildSteps(this.containerBuilder);
62
- const container = this.containerBuilder.build();
63
- await this.runPostBuildSteps(container);
64
- const app = this.resolveApp(container, type);
65
- return app;
66
- }
67
- configureUserServices() {
68
- for (const userService of this.userServices){
69
- userService(this.containerBuilder);
70
- }
71
- }
72
- async runPreBuildSteps(containerBuilder) {
73
- if (this.preBuildSteps.length === 0) {
74
- return;
75
- }
76
- const container = containerBuilder.build();
77
- const config = container.resolve(_configuration.ConfigurationServiceToken);
78
- for (const step of this.preBuildSteps){
79
- await step(config, containerBuilder);
80
- }
81
- }
82
- async runPostBuildSteps(container) {
83
- for (const step of this.postBuildSteps){
84
- await step(container);
85
- }
86
- }
87
- configureApp(type) {
88
- this.containerBuilder.registerSingleton(_const.HostedServiceHostToken, this.hostedServices);
89
- this.containerBuilder.registerSingleton(type ?? _app.App);
90
- }
91
- resolveApp(container, type) {
92
- const app = type ? container.resolve(type) : container.resolve(_app.App);
93
- return app;
94
- }
95
- }