@authup/server-core 1.0.0-beta.37 → 1.0.0-beta.39

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 (263) hide show
  1. package/dist/adapters/database/data-source/options/module.mjs +16 -16
  2. package/dist/adapters/database/domains/client/index.d.ts +0 -1
  3. package/dist/adapters/database/domains/client/index.d.ts.map +1 -1
  4. package/dist/adapters/database/domains/client/index.mjs +1 -2
  5. package/dist/adapters/database/domains/index.mjs +26 -28
  6. package/dist/adapters/database/domains/policy/repository.mjs +1 -1
  7. package/dist/adapters/database/domains/robot/index.d.ts +0 -1
  8. package/dist/adapters/database/domains/robot/index.d.ts.map +1 -1
  9. package/dist/adapters/database/domains/robot/index.mjs +1 -2
  10. package/dist/adapters/database/domains/role/repository.d.ts +0 -6
  11. package/dist/adapters/database/domains/role/repository.d.ts.map +1 -1
  12. package/dist/adapters/database/domains/role/repository.mjs +1 -58
  13. package/dist/adapters/database/domains/role/repository.mjs.map +1 -1
  14. package/dist/adapters/database/domains/role-permission/entity.mjs +1 -1
  15. package/dist/adapters/database/domains/user/repository.d.ts +1 -5
  16. package/dist/adapters/database/domains/user/repository.d.ts.map +1 -1
  17. package/dist/adapters/database/domains/user/repository.mjs +0 -60
  18. package/dist/adapters/database/domains/user/repository.mjs.map +1 -1
  19. package/dist/adapters/database/extra-attribute-repository/tree/repository.d.ts.map +1 -1
  20. package/dist/adapters/database/extra-attribute-repository/tree/repository.mjs +1 -0
  21. package/dist/adapters/database/extra-attribute-repository/tree/repository.mjs.map +1 -1
  22. package/dist/adapters/database/index.mjs +18 -20
  23. package/dist/adapters/http/adapters/index.mjs +2 -1
  24. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.d.ts +2 -1
  25. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.d.ts.map +1 -1
  26. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.mjs +10 -1
  27. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.mjs.map +1 -1
  28. package/dist/adapters/http/adapters/oauth2/grant-types/client-credentials.d.ts.map +1 -1
  29. package/dist/adapters/http/adapters/oauth2/grant-types/client-credentials.mjs +5 -13
  30. package/dist/adapters/http/adapters/oauth2/grant-types/client-credentials.mjs.map +1 -1
  31. package/dist/adapters/http/adapters/oauth2/grant-types/index.mjs +2 -1
  32. package/dist/adapters/http/adapters/oauth2/grant-types/password.d.ts +2 -1
  33. package/dist/adapters/http/adapters/oauth2/grant-types/password.d.ts.map +1 -1
  34. package/dist/adapters/http/adapters/oauth2/grant-types/password.mjs +11 -2
  35. package/dist/adapters/http/adapters/oauth2/grant-types/password.mjs.map +1 -1
  36. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.d.ts +5 -1
  37. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.d.ts.map +1 -1
  38. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.mjs +19 -1
  39. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.mjs.map +1 -1
  40. package/dist/adapters/http/adapters/oauth2/grant-types/types.d.ts +6 -1
  41. package/dist/adapters/http/adapters/oauth2/grant-types/types.d.ts.map +1 -1
  42. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.d.ts +15 -0
  43. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.d.ts.map +1 -0
  44. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs +57 -0
  45. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs.map +1 -0
  46. package/dist/adapters/http/adapters/oauth2/grant-types/utils/guess.mjs +1 -1
  47. package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.d.ts +1 -0
  48. package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.d.ts.map +1 -1
  49. package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.mjs +2 -1
  50. package/dist/adapters/http/adapters/oauth2/index.mjs +2 -1
  51. package/dist/adapters/http/controllers/entities/client/module.d.ts.map +1 -1
  52. package/dist/adapters/http/controllers/entities/client/module.mjs +1 -1
  53. package/dist/adapters/http/controllers/entities/client/module.mjs.map +1 -1
  54. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +1 -1
  55. package/dist/adapters/http/controllers/entities/permission/module.mjs +1 -1
  56. package/dist/adapters/http/controllers/entities/policy/module.mjs +1 -1
  57. package/dist/adapters/http/controllers/entities/policy/utils/attributes-validator.mjs +1 -1
  58. package/dist/adapters/http/controllers/entities/policy/utils/validation.d.ts.map +1 -1
  59. package/dist/adapters/http/controllers/entities/policy/utils/validation.mjs +1 -1
  60. package/dist/adapters/http/controllers/entities/policy/utils/validation.mjs.map +1 -1
  61. package/dist/adapters/http/controllers/entities/robot/module.d.ts.map +1 -1
  62. package/dist/adapters/http/controllers/entities/robot/module.mjs +1 -1
  63. package/dist/adapters/http/controllers/entities/robot/module.mjs.map +1 -1
  64. package/dist/adapters/http/controllers/workflows/authorize/module.d.ts.map +1 -1
  65. package/dist/adapters/http/controllers/workflows/authorize/module.mjs +5 -6
  66. package/dist/adapters/http/controllers/workflows/authorize/module.mjs.map +1 -1
  67. package/dist/adapters/http/controllers/workflows/token/module.d.ts.map +1 -1
  68. package/dist/adapters/http/controllers/workflows/token/module.mjs +4 -1
  69. package/dist/adapters/http/controllers/workflows/token/module.mjs.map +1 -1
  70. package/dist/adapters/http/controllers/workflows/token/types.d.ts +2 -1
  71. package/dist/adapters/http/controllers/workflows/token/types.d.ts.map +1 -1
  72. package/dist/adapters/http/index.mjs +2 -1
  73. package/dist/adapters/http/middleware/built-in/assets.mjs +3 -3
  74. package/dist/adapters/http/middleware/built-in/assets.mjs.map +1 -1
  75. package/dist/app/modules/database/repositories/bindings.d.ts +17 -0
  76. package/dist/app/modules/database/repositories/bindings.d.ts.map +1 -0
  77. package/dist/app/modules/database/repositories/bindings.mjs +40 -0
  78. package/dist/app/modules/database/repositories/bindings.mjs.map +1 -0
  79. package/dist/app/modules/database/repositories/client/repository.d.ts +5 -1
  80. package/dist/app/modules/database/repositories/client/repository.d.ts.map +1 -1
  81. package/dist/app/modules/database/repositories/client/repository.mjs +69 -1
  82. package/dist/app/modules/database/repositories/client/repository.mjs.map +1 -1
  83. package/dist/app/modules/database/repositories/permission/repository.mjs +1 -1
  84. package/dist/app/modules/database/repositories/permission/repository.mjs.map +1 -1
  85. package/dist/app/modules/database/repositories/policy/repository.mjs +1 -1
  86. package/dist/app/modules/database/repositories/policy/repository.mjs.map +1 -1
  87. package/dist/app/modules/database/repositories/realm/repository.mjs +1 -1
  88. package/dist/app/modules/database/repositories/realm/repository.mjs.map +1 -1
  89. package/dist/app/modules/database/repositories/robot/repository.d.ts +5 -1
  90. package/dist/app/modules/database/repositories/robot/repository.d.ts.map +1 -1
  91. package/dist/app/modules/database/repositories/robot/repository.mjs +61 -1
  92. package/dist/app/modules/database/repositories/robot/repository.mjs.map +1 -1
  93. package/dist/app/modules/database/repositories/role/repository.d.ts +3 -0
  94. package/dist/app/modules/database/repositories/role/repository.d.ts.map +1 -1
  95. package/dist/app/modules/database/repositories/role/repository.mjs +17 -1
  96. package/dist/app/modules/database/repositories/role/repository.mjs.map +1 -1
  97. package/dist/app/modules/database/repositories/scope/repository.mjs +1 -1
  98. package/dist/app/modules/database/repositories/scope/repository.mjs.map +1 -1
  99. package/dist/app/modules/database/repositories/user/repository.d.ts +4 -1
  100. package/dist/app/modules/database/repositories/user/repository.d.ts.map +1 -1
  101. package/dist/app/modules/database/repositories/user/repository.mjs +31 -2
  102. package/dist/app/modules/database/repositories/user/repository.mjs.map +1 -1
  103. package/dist/app/modules/http/modules/controller.d.ts +1 -2
  104. package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
  105. package/dist/app/modules/http/modules/controller.mjs +32 -34
  106. package/dist/app/modules/http/modules/controller.mjs.map +1 -1
  107. package/dist/app/modules/http/modules/middleware.d.ts.map +1 -1
  108. package/dist/app/modules/http/modules/middleware.mjs +2 -15
  109. package/dist/app/modules/http/modules/middleware.mjs.map +1 -1
  110. package/dist/app/modules/identity/constants.d.ts +3 -1
  111. package/dist/app/modules/identity/constants.d.ts.map +1 -1
  112. package/dist/app/modules/identity/constants.mjs +2 -0
  113. package/dist/app/modules/identity/constants.mjs.map +1 -1
  114. package/dist/app/modules/identity/module.d.ts.map +1 -1
  115. package/dist/app/modules/identity/module.mjs +42 -5
  116. package/dist/app/modules/identity/module.mjs.map +1 -1
  117. package/dist/app/modules/identity/repositories/client.d.ts +2 -2
  118. package/dist/app/modules/identity/repositories/client.d.ts.map +1 -1
  119. package/dist/app/modules/identity/repositories/client.mjs.map +1 -1
  120. package/dist/app/modules/identity/repositories/robot.d.ts +2 -2
  121. package/dist/app/modules/identity/repositories/robot.d.ts.map +1 -1
  122. package/dist/app/modules/identity/repositories/robot.mjs.map +1 -1
  123. package/dist/app/modules/oauth2/module.d.ts.map +1 -1
  124. package/dist/app/modules/oauth2/module.mjs +5 -2
  125. package/dist/app/modules/oauth2/module.mjs.map +1 -1
  126. package/dist/app/modules/provisioning/module.d.ts.map +1 -1
  127. package/dist/app/modules/provisioning/module.mjs +14 -9
  128. package/dist/app/modules/provisioning/module.mjs.map +1 -1
  129. package/dist/app/modules/provisioning/sources/default/module.d.ts.map +1 -1
  130. package/dist/app/modules/provisioning/sources/default/module.mjs +66 -10
  131. package/dist/app/modules/provisioning/sources/default/module.mjs.map +1 -1
  132. package/dist/components/database/unique-entries/module.mjs +1 -1
  133. package/dist/core/entities/client/service.d.ts +1 -1
  134. package/dist/core/entities/client/service.d.ts.map +1 -1
  135. package/dist/core/entities/client/service.mjs +27 -23
  136. package/dist/core/entities/client/service.mjs.map +1 -1
  137. package/dist/core/entities/client/types.d.ts +6 -2
  138. package/dist/core/entities/client/types.d.ts.map +1 -1
  139. package/dist/core/entities/client-scope/service.d.ts.map +1 -1
  140. package/dist/core/entities/client-scope/service.mjs +2 -0
  141. package/dist/core/entities/client-scope/service.mjs.map +1 -1
  142. package/dist/core/entities/identity-provider-role-mapping/service.d.ts.map +1 -1
  143. package/dist/core/entities/identity-provider-role-mapping/service.mjs +2 -0
  144. package/dist/core/entities/identity-provider-role-mapping/service.mjs.map +1 -1
  145. package/dist/core/entities/permission/service.mjs +1 -1
  146. package/dist/core/entities/policy/attributes-validator.mjs +1 -1
  147. package/dist/core/entities/policy/service.mjs +1 -1
  148. package/dist/core/entities/realm/service.mjs +1 -1
  149. package/dist/core/entities/robot/service.d.ts +1 -1
  150. package/dist/core/entities/robot/service.d.ts.map +1 -1
  151. package/dist/core/entities/robot/service.mjs +41 -26
  152. package/dist/core/entities/robot/service.mjs.map +1 -1
  153. package/dist/core/entities/robot/types.d.ts +6 -2
  154. package/dist/core/entities/robot/types.d.ts.map +1 -1
  155. package/dist/core/entities/role/service.mjs +1 -1
  156. package/dist/core/entities/role/types.d.ts +3 -0
  157. package/dist/core/entities/role/types.d.ts.map +1 -1
  158. package/dist/core/entities/role-attribute/service.d.ts +2 -0
  159. package/dist/core/entities/role-attribute/service.d.ts.map +1 -1
  160. package/dist/core/entities/role-attribute/service.mjs +7 -3
  161. package/dist/core/entities/role-attribute/service.mjs.map +1 -1
  162. package/dist/core/entities/scope/service.mjs +1 -1
  163. package/dist/core/entities/user/service.d.ts.map +1 -1
  164. package/dist/core/entities/user/service.mjs +20 -25
  165. package/dist/core/entities/user/service.mjs.map +1 -1
  166. package/dist/core/entities/user/types.d.ts +4 -1
  167. package/dist/core/entities/user/types.d.ts.map +1 -1
  168. package/dist/core/entities/user-attribute/service.d.ts +3 -1
  169. package/dist/core/entities/user-attribute/service.d.ts.map +1 -1
  170. package/dist/core/entities/user-attribute/service.mjs +44 -17
  171. package/dist/core/entities/user-attribute/service.mjs.map +1 -1
  172. package/dist/core/identity/index.d.ts +1 -0
  173. package/dist/core/identity/index.d.ts.map +1 -1
  174. package/dist/core/identity/index.mjs +2 -1
  175. package/dist/core/identity/password-recovery/service.d.ts.map +1 -1
  176. package/dist/core/identity/password-recovery/service.mjs +4 -4
  177. package/dist/core/identity/password-recovery/service.mjs.map +1 -1
  178. package/dist/core/identity/permission/module.d.ts +12 -6
  179. package/dist/core/identity/permission/module.d.ts.map +1 -1
  180. package/dist/core/identity/permission/module.mjs +11 -19
  181. package/dist/core/identity/permission/module.mjs.map +1 -1
  182. package/dist/core/identity/permission/types.d.ts +11 -13
  183. package/dist/core/identity/permission/types.d.ts.map +1 -1
  184. package/dist/core/identity/provider/account/module.d.ts.map +1 -1
  185. package/dist/core/identity/provider/account/module.mjs +3 -2
  186. package/dist/core/identity/provider/account/module.mjs.map +1 -1
  187. package/dist/core/identity/role/index.d.ts +3 -0
  188. package/dist/core/identity/role/index.d.ts.map +1 -0
  189. package/dist/core/identity/role/index.mjs +2 -0
  190. package/dist/core/identity/role/module.d.ts +15 -0
  191. package/dist/core/identity/role/module.d.ts.map +1 -0
  192. package/dist/core/identity/role/module.mjs +27 -0
  193. package/dist/core/identity/role/module.mjs.map +1 -0
  194. package/dist/core/identity/role/types.d.ts +14 -0
  195. package/dist/core/identity/role/types.d.ts.map +1 -0
  196. package/dist/core/identity/role/types.mjs +1 -0
  197. package/dist/core/index.mjs +3 -1
  198. package/dist/core/oauth2/authorization/code/verifier/module.d.ts.map +1 -1
  199. package/dist/core/oauth2/authorization/code/verifier/module.mjs +8 -4
  200. package/dist/core/oauth2/authorization/code/verifier/module.mjs.map +1 -1
  201. package/dist/core/oauth2/authorization/code/verifier/types.d.ts +2 -0
  202. package/dist/core/oauth2/authorization/code/verifier/types.d.ts.map +1 -1
  203. package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
  204. package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +7 -1
  205. package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
  206. package/dist/core/oauth2/client/authenticator.d.ts +17 -0
  207. package/dist/core/oauth2/client/authenticator.d.ts.map +1 -0
  208. package/dist/core/oauth2/client/authenticator.mjs +34 -0
  209. package/dist/core/oauth2/client/authenticator.mjs.map +1 -0
  210. package/dist/core/oauth2/client/index.d.ts +1 -0
  211. package/dist/core/oauth2/client/index.d.ts.map +1 -1
  212. package/dist/core/oauth2/client/index.mjs +2 -1
  213. package/dist/core/oauth2/grant-types/password.d.ts +7 -3
  214. package/dist/core/oauth2/grant-types/password.d.ts.map +1 -1
  215. package/dist/core/oauth2/grant-types/password.mjs +9 -7
  216. package/dist/core/oauth2/grant-types/password.mjs.map +1 -1
  217. package/dist/core/oauth2/index.mjs +3 -1
  218. package/dist/core/oauth2/token/issuer/access/module.d.ts +4 -1
  219. package/dist/core/oauth2/token/issuer/access/module.d.ts.map +1 -1
  220. package/dist/core/oauth2/token/issuer/access/module.mjs +24 -2
  221. package/dist/core/oauth2/token/issuer/access/module.mjs.map +1 -1
  222. package/dist/core/oauth2/token/issuer/base.d.ts.map +1 -1
  223. package/dist/core/oauth2/token/issuer/base.mjs +3 -2
  224. package/dist/core/oauth2/token/issuer/base.mjs.map +1 -1
  225. package/dist/core/provisioning/entities/permission/types.d.ts +8 -0
  226. package/dist/core/provisioning/entities/permission/types.d.ts.map +1 -1
  227. package/dist/core/provisioning/synchronizer/permission/module.d.ts +5 -1
  228. package/dist/core/provisioning/synchronizer/permission/module.d.ts.map +1 -1
  229. package/dist/core/provisioning/synchronizer/permission/module.mjs +23 -0
  230. package/dist/core/provisioning/synchronizer/permission/module.mjs.map +1 -1
  231. package/dist/core/provisioning/synchronizer/permission/types.d.ts +4 -1
  232. package/dist/core/provisioning/synchronizer/permission/types.d.ts.map +1 -1
  233. package/dist/core/provisioning/synchronizer/policy/module.d.ts.map +1 -1
  234. package/dist/core/provisioning/synchronizer/policy/module.mjs +4 -2
  235. package/dist/core/provisioning/synchronizer/policy/module.mjs.map +1 -1
  236. package/dist/index.mjs +19 -20
  237. package/dist/path.d.ts +2 -1
  238. package/dist/path.d.ts.map +1 -1
  239. package/dist/path.mjs +3 -2
  240. package/dist/path.mjs.map +1 -1
  241. package/dist/swagger.json +14 -0
  242. package/dist/ui/client/.vite/ssr-manifest.json +2777 -0
  243. package/dist/ui/client/assets/fa-brands-400-BP5tdqmh.woff2 +0 -0
  244. package/dist/ui/client/assets/fa-regular-400-nyy7hhHF.woff2 +0 -0
  245. package/dist/ui/client/assets/fa-solid-900-DRAAbZTg.woff2 +0 -0
  246. package/dist/ui/client/assets/index-BVfayRKv.css +1 -0
  247. package/dist/ui/client/assets/index-Noe7uiOY.js +41 -0
  248. package/dist/ui/client/index.html +22 -0
  249. package/dist/ui/server/assets/multipart-parser-pHQi-kA6.js +166 -0
  250. package/dist/ui/server/server.js +79116 -0
  251. package/package.json +30 -13
  252. package/dist/adapters/database/domains/client/repository.d.ts +0 -13
  253. package/dist/adapters/database/domains/client/repository.d.ts.map +0 -1
  254. package/dist/adapters/database/domains/client/repository.mjs +0 -75
  255. package/dist/adapters/database/domains/client/repository.mjs.map +0 -1
  256. package/dist/adapters/database/domains/robot/repository.d.ts +0 -13
  257. package/dist/adapters/database/domains/robot/repository.d.ts.map +0 -1
  258. package/dist/adapters/database/domains/robot/repository.mjs +0 -75
  259. package/dist/adapters/database/domains/robot/repository.mjs.map +0 -1
  260. package/dist/adapters/http/controllers/entities/user-attribute/utils/authorization.d.ts +0 -4
  261. package/dist/adapters/http/controllers/entities/user-attribute/utils/authorization.d.ts.map +0 -1
  262. package/dist/adapters/http/controllers/entities/user-attribute/utils/authorization.mjs +0 -35
  263. package/dist/adapters/http/controllers/entities/user-attribute/utils/authorization.mjs.map +0 -1
@@ -1,7 +1,11 @@
1
1
  import { ScopeName } from "@authup/core-kit";
2
2
  import { isSimpleMatch } from "@authup/kit";
3
- import { OAuth2Error, hasOAuth2Scopes } from "@authup/specs";
3
+ import { OAuth2AuthorizationResponseType, OAuth2Error, hasOAuth2Scopes } from "@authup/specs";
4
4
  //#region src/core/oauth2/authorization/code-request/verifier/module.ts
5
+ function willIssueCode(responseType) {
6
+ if (!responseType) return false;
7
+ return responseType.split(" ").includes(OAuth2AuthorizationResponseType.CODE);
8
+ }
5
9
  var OAuth2AuthorizationCodeRequestVerifier = class {
6
10
  clientRepository;
7
11
  scopeRepository;
@@ -17,6 +21,8 @@ var OAuth2AuthorizationCodeRequestVerifier = class {
17
21
  const client = await this.clientRepository.findOneByIdOrName(data.client_id, data.realm_id);
18
22
  if (!client) throw OAuth2Error.clientInvalid();
19
23
  if (!client.active) throw OAuth2Error.clientInactive();
24
+ if (!client.is_confidential && !data.code_challenge && willIssueCode(data.response_type)) throw OAuth2Error.requestInvalid("PKCE code_challenge is required for public clients.");
25
+ if (!client.is_confidential && !data.state && willIssueCode(data.response_type)) throw OAuth2Error.requestInvalid("state is required for public clients in the code flow.");
20
26
  data.client_id = client.id;
21
27
  data.realm_id = client.realm_id;
22
28
  const scopes = await this.scopeRepository.findByClientId(client.id);
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["ScopeName","isSimpleMatch","OAuth2Error","hasOAuth2Scopes","OAuth2AuthorizationCodeRequestVerifier","clientRepository","scopeRepository","ctx","verify","data","client_id","clientInvalid","client","findOneByIdOrName","realm_id","active","clientInactive","id","scopes","findByClientId","scopeNames","map","scope","name","GLOBAL","scopeInsufficient","join","redirect_uri","redirectUris","split","redirectUriMismatch"],"sources":["../../../../../../src/core/oauth2/authorization/code-request/verifier/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2AuthorizationCodeRequest } from '@authup/core-kit';\nimport { ScopeName } from '@authup/core-kit';\nimport { isSimpleMatch } from '@authup/kit';\nimport { OAuth2Error, hasOAuth2Scopes } from '@authup/specs';\nimport type { IOAuth2ClientRepository } from '../../../client/index.ts';\nimport type { IOAuth2ScopeRepository } from '../../../scope/index.ts';\nimport type {\n IOAuth2AuthorizationCodeRequestVerifier,\n OAuth2AuthorizationCodeRequestVerificationResult,\n OAuth2AuthorizationCodeRequestVerifierContext,\n} from './types.ts';\n\nexport class OAuth2AuthorizationCodeRequestVerifier implements IOAuth2AuthorizationCodeRequestVerifier {\n protected clientRepository: IOAuth2ClientRepository;\n\n protected scopeRepository: IOAuth2ScopeRepository;\n\n constructor(ctx: OAuth2AuthorizationCodeRequestVerifierContext) {\n this.clientRepository = ctx.clientRepository;\n this.scopeRepository = ctx.scopeRepository;\n }\n\n /**\n * Verify validated authorization code request.\n * @param data\n */\n async verify(\n data: OAuth2AuthorizationCodeRequest,\n ) : Promise<OAuth2AuthorizationCodeRequestVerificationResult> {\n if (!data.client_id) {\n throw OAuth2Error.clientInvalid();\n }\n\n const client = await this.clientRepository.findOneByIdOrName(data.client_id, data.realm_id);\n if (!client) {\n throw OAuth2Error.clientInvalid();\n }\n\n if (!client.active) {\n throw OAuth2Error.clientInactive();\n }\n\n data.client_id = client.id;\n data.realm_id = client.realm_id;\n\n const scopes = await this.scopeRepository.findByClientId(client.id);\n const scopeNames = scopes.map((scope) => scope.name);\n if (data.scope) {\n if (\n !hasOAuth2Scopes(scopeNames, data.scope) &&\n !hasOAuth2Scopes(data.scope, ScopeName.GLOBAL)\n ) {\n throw OAuth2Error.scopeInsufficient();\n }\n } else {\n data.scope = scopeNames.join(' ');\n }\n\n if (client.redirect_uri && data.redirect_uri) {\n const redirectUris = client.redirect_uri.split(',');\n\n if (!isSimpleMatch(data.redirect_uri, redirectUris)) {\n throw OAuth2Error.redirectUriMismatch();\n }\n }\n\n return {\n data,\n client,\n scopes,\n };\n }\n}\n"],"mappings":";;;;AAmBA,IAAaI,yCAAb,MAAaA;CACCC;CAEAC;CAEV,YAAYC,KAAoD;AAC5D,OAAKF,mBAAmBE,IAAIF;AAC5B,OAAKC,kBAAkBC,IAAID;;;;;IAO/B,MAAME,OACFC,MAC0D;AAC1D,MAAI,CAACA,KAAKC,UACN,OAAMR,YAAYS,eAAa;EAGnC,MAAMC,SAAS,MAAM,KAAKP,iBAAiBQ,kBAAkBJ,KAAKC,WAAWD,KAAKK,SAAQ;AAC1F,MAAI,CAACF,OACD,OAAMV,YAAYS,eAAa;AAGnC,MAAI,CAACC,OAAOG,OACR,OAAMb,YAAYc,gBAAc;AAGpCP,OAAKC,YAAYE,OAAOK;AACxBR,OAAKK,WAAWF,OAAOE;EAEvB,MAAMI,SAAS,MAAM,KAAKZ,gBAAgBa,eAAeP,OAAOK,GAAE;EAClE,MAAMG,aAAaF,OAAOG,KAAKC,UAAUA,MAAMC,KAAI;AACnD,MAAId,KAAKa;OAED,CAACnB,gBAAgBiB,YAAYX,KAAKa,MAAK,IACvC,CAACnB,gBAAgBM,KAAKa,OAAOtB,UAAUwB,OAAM,CAE7C,OAAMtB,YAAYuB,mBAAiB;QAGvChB,MAAKa,QAAQF,WAAWM,KAAK,IAAA;AAGjC,MAAId,OAAOe,gBAAgBlB,KAAKkB,cAAc;GAC1C,MAAMC,eAAehB,OAAOe,aAAaE,MAAM,IAAA;AAE/C,OAAI,CAAC5B,cAAcQ,KAAKkB,cAAcC,aAAAA,CAClC,OAAM1B,YAAY4B,qBAAmB;;AAI7C,SAAO;GACHrB;GACAG;GACAM;GACJ"}
1
+ {"version":3,"file":"module.mjs","names":["ScopeName","isSimpleMatch","OAuth2AuthorizationResponseType","OAuth2Error","hasOAuth2Scopes","willIssueCode","responseType","split","includes","CODE","OAuth2AuthorizationCodeRequestVerifier","clientRepository","scopeRepository","ctx","verify","data","client_id","clientInvalid","client","findOneByIdOrName","realm_id","active","clientInactive","is_confidential","code_challenge","response_type","requestInvalid","state","id","scopes","findByClientId","scopeNames","map","scope","name","GLOBAL","scopeInsufficient","join","redirect_uri","redirectUris","redirectUriMismatch"],"sources":["../../../../../../src/core/oauth2/authorization/code-request/verifier/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2AuthorizationCodeRequest } from '@authup/core-kit';\nimport { ScopeName } from '@authup/core-kit';\nimport { isSimpleMatch } from '@authup/kit';\nimport {\n OAuth2AuthorizationResponseType,\n OAuth2Error,\n hasOAuth2Scopes,\n} from '@authup/specs';\nimport type { IOAuth2ClientRepository } from '../../../client/index.ts';\nimport type { IOAuth2ScopeRepository } from '../../../scope/index.ts';\nimport type {\n IOAuth2AuthorizationCodeRequestVerifier,\n OAuth2AuthorizationCodeRequestVerificationResult,\n OAuth2AuthorizationCodeRequestVerifierContext,\n} from './types.ts';\n\nfunction willIssueCode(responseType: string | undefined): boolean {\n if (!responseType) {\n return false;\n }\n return responseType.split(' ').includes(OAuth2AuthorizationResponseType.CODE);\n}\n\nexport class OAuth2AuthorizationCodeRequestVerifier implements IOAuth2AuthorizationCodeRequestVerifier {\n protected clientRepository: IOAuth2ClientRepository;\n\n protected scopeRepository: IOAuth2ScopeRepository;\n\n constructor(ctx: OAuth2AuthorizationCodeRequestVerifierContext) {\n this.clientRepository = ctx.clientRepository;\n this.scopeRepository = ctx.scopeRepository;\n }\n\n /**\n * Verify validated authorization code request.\n * @param data\n */\n async verify(\n data: OAuth2AuthorizationCodeRequest,\n ) : Promise<OAuth2AuthorizationCodeRequestVerificationResult> {\n if (!data.client_id) {\n throw OAuth2Error.clientInvalid();\n }\n\n const client = await this.clientRepository.findOneByIdOrName(data.client_id, data.realm_id);\n if (!client) {\n throw OAuth2Error.clientInvalid();\n }\n\n if (!client.active) {\n throw OAuth2Error.clientInactive();\n }\n\n // Public clients MUST use PKCE for the code flow (RFC 7636 §4.4.1,\n // OAuth 2.1). Without PKCE a public client's code flow has no second\n // factor — anyone who intercepts the redirect can redeem the code at\n // /token. Only enforce when an authorization code will actually be\n // issued; implicit/id_token-only flows don't involve a code.\n if (!client.is_confidential && !data.code_challenge && willIssueCode(data.response_type)) {\n throw OAuth2Error.requestInvalid('PKCE code_challenge is required for public clients.');\n }\n\n // Public clients SHOULD include state to bind the redirect to the\n // initiating session and prevent CSRF (RFC 6749 §10.12). Confidential\n // clients are exempt because the /token exchange already authenticates\n // them via client_secret.\n if (!client.is_confidential && !data.state && willIssueCode(data.response_type)) {\n throw OAuth2Error.requestInvalid('state is required for public clients in the code flow.');\n }\n\n data.client_id = client.id;\n data.realm_id = client.realm_id;\n\n const scopes = await this.scopeRepository.findByClientId(client.id);\n const scopeNames = scopes.map((scope) => scope.name);\n if (data.scope) {\n if (\n !hasOAuth2Scopes(scopeNames, data.scope) &&\n !hasOAuth2Scopes(data.scope, ScopeName.GLOBAL)\n ) {\n throw OAuth2Error.scopeInsufficient();\n }\n } else {\n data.scope = scopeNames.join(' ');\n }\n\n if (client.redirect_uri && data.redirect_uri) {\n const redirectUris = client.redirect_uri.split(',');\n\n if (!isSimpleMatch(data.redirect_uri, redirectUris)) {\n throw OAuth2Error.redirectUriMismatch();\n }\n }\n\n return {\n data,\n client,\n scopes,\n };\n }\n}\n"],"mappings":";;;;AAuBA,SAASK,cAAcC,cAAgC;AACnD,KAAI,CAACA,aACD,QAAO;AAEX,QAAOA,aAAaC,MAAM,IAAA,CAAKC,SAASN,gCAAgCO,KAAI;;AAGhF,IAAaC,yCAAb,MAAaA;CACCC;CAEAC;CAEV,YAAYC,KAAoD;AAC5D,OAAKF,mBAAmBE,IAAIF;AAC5B,OAAKC,kBAAkBC,IAAID;;;;;IAO/B,MAAME,OACFC,MAC0D;AAC1D,MAAI,CAACA,KAAKC,UACN,OAAMb,YAAYc,eAAa;EAGnC,MAAMC,SAAS,MAAM,KAAKP,iBAAiBQ,kBAAkBJ,KAAKC,WAAWD,KAAKK,SAAQ;AAC1F,MAAI,CAACF,OACD,OAAMf,YAAYc,eAAa;AAGnC,MAAI,CAACC,OAAOG,OACR,OAAMlB,YAAYmB,gBAAc;AAQpC,MAAI,CAACJ,OAAOK,mBAAmB,CAACR,KAAKS,kBAAkBnB,cAAcU,KAAKU,cAAa,CACnF,OAAMtB,YAAYuB,eAAe,sDAAA;AAOrC,MAAI,CAACR,OAAOK,mBAAmB,CAACR,KAAKY,SAAStB,cAAcU,KAAKU,cAAa,CAC1E,OAAMtB,YAAYuB,eAAe,yDAAA;AAGrCX,OAAKC,YAAYE,OAAOU;AACxBb,OAAKK,WAAWF,OAAOE;EAEvB,MAAMS,SAAS,MAAM,KAAKjB,gBAAgBkB,eAAeZ,OAAOU,GAAE;EAClE,MAAMG,aAAaF,OAAOG,KAAKC,UAAUA,MAAMC,KAAI;AACnD,MAAInB,KAAKkB;OAED,CAAC7B,gBAAgB2B,YAAYhB,KAAKkB,MAAK,IACvC,CAAC7B,gBAAgBW,KAAKkB,OAAOjC,UAAUmC,OAAM,CAE7C,OAAMhC,YAAYiC,mBAAiB;QAGvCrB,MAAKkB,QAAQF,WAAWM,KAAK,IAAA;AAGjC,MAAInB,OAAOoB,gBAAgBvB,KAAKuB,cAAc;GAC1C,MAAMC,eAAerB,OAAOoB,aAAa/B,MAAM,IAAA;AAE/C,OAAI,CAACN,cAAcc,KAAKuB,cAAcC,aAAAA,CAClC,OAAMpC,YAAYqC,qBAAmB;;AAI7C,SAAO;GACHzB;GACAG;GACAW;GACJ"}
@@ -0,0 +1,17 @@
1
+ import type { Client } from '@authup/core-kit';
2
+ import { ClientCredentialsService } from '../../authentication/credential/index.ts';
3
+ import type { IIdentityResolver } from '../../identity/index.ts';
4
+ /**
5
+ * Authenticates a client at the OAuth2 token endpoint. Confidential clients
6
+ * MUST present a valid client_secret (RFC 6749 §3.2.1, §4.1.3, §4.3.2, §6);
7
+ * public clients identify via client_id only.
8
+ *
9
+ * Used by authorization_code, refresh_token, and password grants.
10
+ */
11
+ export declare class OAuth2ClientAuthenticator {
12
+ protected identityResolver: IIdentityResolver;
13
+ protected credentialsService: ClientCredentialsService;
14
+ constructor(identityResolver: IIdentityResolver);
15
+ authenticate(clientId: string | undefined, clientSecret?: string, realmId?: string): Promise<Client>;
16
+ }
17
+ //# sourceMappingURL=authenticator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticator.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/client/authenticator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;;;GAMG;AACH,qBAAa,yBAAyB;IAClC,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAE9C,SAAS,CAAC,kBAAkB,EAAE,wBAAwB,CAAC;gBAE3C,gBAAgB,EAAE,iBAAiB;IAKzC,YAAY,CACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC;CA2BrB"}
@@ -0,0 +1,34 @@
1
+ import { ClientCredentialsService } from "../../authentication/credential/entities/client/module.mjs";
2
+ import "../../authentication/credential/index.mjs";
3
+ import { IdentityType } from "@authup/core-kit";
4
+ import { OAuth2Error } from "@authup/specs";
5
+ //#region src/core/oauth2/client/authenticator.ts
6
+ /**
7
+ * Authenticates a client at the OAuth2 token endpoint. Confidential clients
8
+ * MUST present a valid client_secret (RFC 6749 §3.2.1, §4.1.3, §4.3.2, §6);
9
+ * public clients identify via client_id only.
10
+ *
11
+ * Used by authorization_code, refresh_token, and password grants.
12
+ */ var OAuth2ClientAuthenticator = class {
13
+ identityResolver;
14
+ credentialsService;
15
+ constructor(identityResolver) {
16
+ this.identityResolver = identityResolver;
17
+ this.credentialsService = new ClientCredentialsService();
18
+ }
19
+ async authenticate(clientId, clientSecret, realmId) {
20
+ if (!clientId) throw OAuth2Error.clientInvalid();
21
+ const identity = await this.identityResolver.resolve(IdentityType.CLIENT, clientId, realmId);
22
+ if (!identity || identity.type !== IdentityType.CLIENT) throw OAuth2Error.clientInvalid();
23
+ if (!identity.data.active) throw OAuth2Error.clientInactive();
24
+ if (identity.data.is_confidential) {
25
+ if (!clientSecret) throw OAuth2Error.clientInvalid();
26
+ if (!await this.credentialsService.verify(clientSecret, identity.data)) throw OAuth2Error.clientInvalid();
27
+ }
28
+ return identity.data;
29
+ }
30
+ };
31
+ //#endregion
32
+ export { OAuth2ClientAuthenticator };
33
+
34
+ //# sourceMappingURL=authenticator.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticator.mjs","names":["IdentityType","OAuth2Error","ClientCredentialsService","OAuth2ClientAuthenticator","identityResolver","credentialsService","authenticate","clientId","clientSecret","realmId","clientInvalid","identity","resolve","CLIENT","type","data","active","clientInactive","is_confidential","verified","verify"],"sources":["../../../../src/core/oauth2/client/authenticator.ts"],"sourcesContent":["/*\n * Copyright (c) 2025-2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Client } from '@authup/core-kit';\nimport { IdentityType } from '@authup/core-kit';\nimport { OAuth2Error } from '@authup/specs';\nimport { ClientCredentialsService } from '../../authentication/credential/index.ts';\nimport type { IIdentityResolver } from '../../identity/index.ts';\n\n/**\n * Authenticates a client at the OAuth2 token endpoint. Confidential clients\n * MUST present a valid client_secret (RFC 6749 §3.2.1, §4.1.3, §4.3.2, §6);\n * public clients identify via client_id only.\n *\n * Used by authorization_code, refresh_token, and password grants.\n */\nexport class OAuth2ClientAuthenticator {\n protected identityResolver: IIdentityResolver;\n\n protected credentialsService: ClientCredentialsService;\n\n constructor(identityResolver: IIdentityResolver) {\n this.identityResolver = identityResolver;\n this.credentialsService = new ClientCredentialsService();\n }\n\n async authenticate(\n clientId: string | undefined,\n clientSecret?: string,\n realmId?: string,\n ): Promise<Client> {\n if (!clientId) {\n throw OAuth2Error.clientInvalid();\n }\n\n const identity = await this.identityResolver.resolve(IdentityType.CLIENT, clientId, realmId);\n if (!identity || identity.type !== IdentityType.CLIENT) {\n throw OAuth2Error.clientInvalid();\n }\n\n if (!identity.data.active) {\n throw OAuth2Error.clientInactive();\n }\n\n if (identity.data.is_confidential) {\n if (!clientSecret) {\n throw OAuth2Error.clientInvalid();\n }\n\n const verified = await this.credentialsService.verify(clientSecret, identity.data);\n if (!verified) {\n throw OAuth2Error.clientInvalid();\n }\n }\n\n return identity.data;\n }\n}\n"],"mappings":";;;;;;;;;;;GAoBA,IAAaG,4BAAb,MAAaA;CACCC;CAEAC;CAEV,YAAYD,kBAAqC;AAC7C,OAAKA,mBAAmBA;AACxB,OAAKC,qBAAqB,IAAIH,0BAAAA;;CAGlC,MAAMI,aACFC,UACAC,cACAC,SACe;AACf,MAAI,CAACF,SACD,OAAMN,YAAYS,eAAa;EAGnC,MAAMC,WAAW,MAAM,KAAKP,iBAAiBQ,QAAQZ,aAAaa,QAAQN,UAAUE,QAAAA;AACpF,MAAI,CAACE,YAAYA,SAASG,SAASd,aAAaa,OAC5C,OAAMZ,YAAYS,eAAa;AAGnC,MAAI,CAACC,SAASI,KAAKC,OACf,OAAMf,YAAYgB,gBAAc;AAGpC,MAAIN,SAASI,KAAKG,iBAAiB;AAC/B,OAAI,CAACV,aACD,OAAMP,YAAYS,eAAa;AAInC,OAAI,CAACS,MADkB,KAAKd,mBAAmBe,OAAOZ,cAAcG,SAASI,KAAI,CAE7E,OAAMd,YAAYS,eAAa;;AAIvC,SAAOC,SAASI"}
@@ -1,2 +1,3 @@
1
+ export * from './authenticator.ts';
1
2
  export * from './types.ts';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/client/index.ts"],"names":[],"mappings":"AAOA,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/client/index.ts"],"names":[],"mappings":"AAOA,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC"}
@@ -1 +1,2 @@
1
- export {};
1
+ import { OAuth2ClientAuthenticator } from "./authenticator.mjs";
2
+ export { OAuth2ClientAuthenticator };
@@ -1,11 +1,15 @@
1
1
  import type { OAuth2TokenGrantResponse } from '@authup/specs';
2
- import type { User } from '@authup/core-kit';
2
+ import type { Client, User } from '@authup/core-kit';
3
3
  import type { IOAuth2TokenIssuer } from '../token/index.ts';
4
4
  import { OAuth2BaseGrant } from './base.ts';
5
5
  import type { OAuth2GrantRunWIthOptions, OAuth2PasswordGrantContext } from './types.ts';
6
- export declare class PasswordGrantType extends OAuth2BaseGrant<User> {
6
+ export type OAuth2PasswordGrantInput = {
7
+ user: User;
8
+ client?: Client;
9
+ };
10
+ export declare class PasswordGrantType extends OAuth2BaseGrant<OAuth2PasswordGrantInput> {
7
11
  protected refreshTokenIssuer: IOAuth2TokenIssuer;
8
12
  constructor(ctx: OAuth2PasswordGrantContext);
9
- runWith(input: User, options?: OAuth2GrantRunWIthOptions): Promise<OAuth2TokenGrantResponse>;
13
+ runWith(input: OAuth2PasswordGrantInput, options?: OAuth2GrantRunWIthOptions): Promise<OAuth2TokenGrantResponse>;
10
14
  }
11
15
  //# sourceMappingURL=password.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/grant-types/password.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAsB,MAAM,eAAe,CAAC;AAElF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAM7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAExF,qBAAa,iBAAkB,SAAQ,eAAe,CAAC,IAAI,CAAC;IACxD,SAAS,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;gBAEtC,GAAG,EAAE,0BAA0B;IASrC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,GAAE,yBAA8B,GAAI,OAAO,CAAC,wBAAwB,CAAC;CAgC1G"}
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/grant-types/password.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAsB,MAAM,eAAe,CAAC;AAElF,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAMrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,MAAM,wBAAwB,GAAG;IACnC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,iBAAkB,SAAQ,eAAe,CAAC,wBAAwB,CAAC;IAC5E,SAAS,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;gBAEtC,GAAG,EAAE,0BAA0B;IASrC,OAAO,CAAC,KAAK,EAAE,wBAAwB,EAAE,OAAO,GAAE,yBAA8B,GAAI,OAAO,CAAC,wBAAwB,CAAC;CAmC9H"}
@@ -13,24 +13,26 @@ var PasswordGrantType = class extends OAuth2BaseGrant {
13
13
  this.refreshTokenIssuer = ctx.refreshTokenIssuer;
14
14
  }
15
15
  async runWith(input, options = {}) {
16
+ const { user, client } = input;
17
+ const clientId = client?.id;
16
18
  const session = await this.sessionManager.create({
17
19
  user_agent: options.userAgent,
18
20
  ip_address: options.ipAddress,
19
- realm_id: input.realm_id,
20
- client_id: input.client_id || void 0,
21
- sub: input.id,
21
+ realm_id: user.realm_id,
22
+ client_id: clientId,
23
+ sub: user.id,
22
24
  sub_kind: IdentityType.USER
23
25
  });
24
26
  const issuePayload = {
25
- client_id: input.client_id || void 0,
27
+ client_id: clientId,
26
28
  session_id: session.id,
27
29
  user_agent: session.user_agent,
28
30
  remote_address: session.ip_address,
29
31
  scope: ScopeName.GLOBAL,
30
- sub: input.id,
32
+ sub: user.id,
31
33
  sub_kind: OAuth2SubKind.USER,
32
- realm_id: input.realm_id,
33
- realm_name: input.realm?.name
34
+ realm_id: user.realm_id,
35
+ realm_name: user.realm?.name
34
36
  };
35
37
  const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue(issuePayload);
36
38
  const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue(issuePayload);
@@ -1 +1 @@
1
- {"version":3,"file":"password.mjs","names":["OAuth2SubKind","IdentityType","ScopeName","buildOAuth2BearerTokenResponse","OAuth2BaseGrant","PasswordGrantType","refreshTokenIssuer","ctx","accessTokenIssuer","sessionManager","runWith","input","options","session","create","user_agent","userAgent","ip_address","ipAddress","realm_id","client_id","undefined","sub","id","sub_kind","USER","issuePayload","session_id","remote_address","scope","GLOBAL","realm_name","realm","name","accessToken","accessTokenPayload","issue","refreshToken","refreshTokenPayload"],"sources":["../../../../src/core/oauth2/grant-types/password.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2SubKind } from '@authup/specs';\nimport type { User } from '@authup/core-kit';\nimport {\n IdentityType,\n ScopeName,\n} from '@authup/core-kit';\nimport { buildOAuth2BearerTokenResponse } from '../response/index.ts';\nimport type { IOAuth2TokenIssuer } from '../token/index.ts';\nimport { OAuth2BaseGrant } from './base.ts';\nimport type { OAuth2GrantRunWIthOptions, OAuth2PasswordGrantContext } from './types.ts';\n\nexport class PasswordGrantType extends OAuth2BaseGrant<User> {\n protected refreshTokenIssuer : IOAuth2TokenIssuer;\n\n constructor(ctx: OAuth2PasswordGrantContext) {\n super({\n accessTokenIssuer: ctx.accessTokenIssuer,\n sessionManager: ctx.sessionManager,\n });\n\n this.refreshTokenIssuer = ctx.refreshTokenIssuer;\n }\n\n async runWith(input: User, options: OAuth2GrantRunWIthOptions = {}) : Promise<OAuth2TokenGrantResponse> {\n const session = await this.sessionManager.create({\n user_agent: options.userAgent,\n ip_address: options.ipAddress,\n realm_id: input.realm_id,\n client_id: input.client_id || undefined,\n sub: input.id,\n sub_kind: IdentityType.USER,\n });\n\n const issuePayload : Partial<OAuth2TokenPayload> = {\n client_id: input.client_id || undefined,\n session_id: session.id,\n user_agent: session.user_agent,\n remote_address: session.ip_address,\n scope: ScopeName.GLOBAL,\n sub: input.id,\n sub_kind: OAuth2SubKind.USER,\n realm_id: input.realm_id,\n realm_name: input.realm?.name,\n };\n\n const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue(issuePayload);\n const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue(issuePayload);\n\n return buildOAuth2BearerTokenResponse({\n accessToken,\n accessTokenPayload,\n refreshToken,\n refreshTokenPayload,\n });\n }\n}\n"],"mappings":";;;;;AAmBA,IAAaK,oBAAb,cAAuCD,gBAAAA;CACzBE;CAEV,YAAYC,KAAiC;AACzC,QAAM;GACFC,mBAAmBD,IAAIC;GACvBC,gBAAgBF,IAAIE;GACxB,CAAA;AAEA,OAAKH,qBAAqBC,IAAID;;CAGlC,MAAMI,QAAQC,OAAaC,UAAqC,EAAE,EAAsC;EACpG,MAAMC,UAAU,MAAM,KAAKJ,eAAeK,OAAO;GAC7CC,YAAYH,QAAQI;GACpBC,YAAYL,QAAQM;GACpBC,UAAUR,MAAMQ;GAChBC,WAAWT,MAAMS,aAAaC,KAAAA;GAC9BC,KAAKX,MAAMY;GACXC,UAAUvB,aAAawB;GAC3B,CAAA;EAEA,MAAMC,eAA6C;GAC/CN,WAAWT,MAAMS,aAAaC,KAAAA;GAC9BM,YAAYd,QAAQU;GACpBR,YAAYF,QAAQE;GACpBa,gBAAgBf,QAAQI;GACxBY,OAAO3B,UAAU4B;GACjBR,KAAKX,MAAMY;GACXC,UAAUxB,cAAcyB;GACxBN,UAAUR,MAAMQ;GAChBY,YAAYpB,MAAMqB,OAAOC;GAC7B;EAEA,MAAM,CAACC,aAAaC,sBAAsB,MAAM,KAAK3B,kBAAkB4B,MAAMV,aAAAA;EAC7E,MAAM,CAACW,cAAcC,uBAAuB,MAAM,KAAKhC,mBAAmB8B,MAAMV,aAAAA;AAEhF,SAAOvB,+BAA+B;GAClC+B;GACAC;GACAE;GACAC;GACJ,CAAA"}
1
+ {"version":3,"file":"password.mjs","names":["OAuth2SubKind","IdentityType","ScopeName","buildOAuth2BearerTokenResponse","OAuth2BaseGrant","PasswordGrantType","refreshTokenIssuer","ctx","accessTokenIssuer","sessionManager","runWith","input","options","user","client","clientId","id","session","create","user_agent","userAgent","ip_address","ipAddress","realm_id","client_id","sub","sub_kind","USER","issuePayload","session_id","remote_address","scope","GLOBAL","realm_name","realm","name","accessToken","accessTokenPayload","issue","refreshToken","refreshTokenPayload"],"sources":["../../../../src/core/oauth2/grant-types/password.ts"],"sourcesContent":["/*\n * Copyright (c) 2022-2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2SubKind } from '@authup/specs';\nimport type { Client, User } from '@authup/core-kit';\nimport {\n IdentityType,\n ScopeName,\n} from '@authup/core-kit';\nimport { buildOAuth2BearerTokenResponse } from '../response/index.ts';\nimport type { IOAuth2TokenIssuer } from '../token/index.ts';\nimport { OAuth2BaseGrant } from './base.ts';\nimport type { OAuth2GrantRunWIthOptions, OAuth2PasswordGrantContext } from './types.ts';\n\nexport type OAuth2PasswordGrantInput = {\n user: User,\n client?: Client,\n};\n\nexport class PasswordGrantType extends OAuth2BaseGrant<OAuth2PasswordGrantInput> {\n protected refreshTokenIssuer : IOAuth2TokenIssuer;\n\n constructor(ctx: OAuth2PasswordGrantContext) {\n super({\n accessTokenIssuer: ctx.accessTokenIssuer,\n sessionManager: ctx.sessionManager,\n });\n\n this.refreshTokenIssuer = ctx.refreshTokenIssuer;\n }\n\n async runWith(input: OAuth2PasswordGrantInput, options: OAuth2GrantRunWIthOptions = {}) : Promise<OAuth2TokenGrantResponse> {\n const { user, client } = input;\n const clientId = client?.id;\n\n const session = await this.sessionManager.create({\n user_agent: options.userAgent,\n ip_address: options.ipAddress,\n realm_id: user.realm_id,\n client_id: clientId,\n sub: user.id,\n sub_kind: IdentityType.USER,\n });\n\n const issuePayload : Partial<OAuth2TokenPayload> = {\n client_id: clientId,\n session_id: session.id,\n user_agent: session.user_agent,\n remote_address: session.ip_address,\n scope: ScopeName.GLOBAL,\n sub: user.id,\n sub_kind: OAuth2SubKind.USER,\n realm_id: user.realm_id,\n realm_name: user.realm?.name,\n };\n\n const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue(issuePayload);\n const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue(issuePayload);\n\n return buildOAuth2BearerTokenResponse({\n accessToken,\n accessTokenPayload,\n refreshToken,\n refreshTokenPayload,\n });\n }\n}\n"],"mappings":";;;;;AAwBA,IAAaK,oBAAb,cAAuCD,gBAAAA;CACzBE;CAEV,YAAYC,KAAiC;AACzC,QAAM;GACFC,mBAAmBD,IAAIC;GACvBC,gBAAgBF,IAAIE;GACxB,CAAA;AAEA,OAAKH,qBAAqBC,IAAID;;CAGlC,MAAMI,QAAQC,OAAiCC,UAAqC,EAAE,EAAsC;EACxH,MAAM,EAAEC,MAAMC,WAAWH;EACzB,MAAMI,WAAWD,QAAQE;EAEzB,MAAMC,UAAU,MAAM,KAAKR,eAAeS,OAAO;GAC7CC,YAAYP,QAAQQ;GACpBC,YAAYT,QAAQU;GACpBC,UAAUV,KAAKU;GACfC,WAAWT;GACXU,KAAKZ,KAAKG;GACVU,UAAUzB,aAAa0B;GAC3B,CAAA;EAEA,MAAMC,eAA6C;GAC/CJ,WAAWT;GACXc,YAAYZ,QAAQD;GACpBG,YAAYF,QAAQE;GACpBW,gBAAgBb,QAAQI;GACxBU,OAAO7B,UAAU8B;GACjBP,KAAKZ,KAAKG;GACVU,UAAU1B,cAAc2B;GACxBJ,UAAUV,KAAKU;GACfU,YAAYpB,KAAKqB,OAAOC;GAC5B;EAEA,MAAM,CAACC,aAAaC,sBAAsB,MAAM,KAAK7B,kBAAkB8B,MAAMV,aAAAA;EAC7E,MAAM,CAACW,cAAcC,uBAAuB,MAAM,KAAKlC,mBAAmBgC,MAAMV,aAAAA;AAEhF,SAAOzB,+BAA+B;GAClCiC;GACAC;GACAE;GACAC;GACJ,CAAA"}
@@ -6,6 +6,8 @@ import { OAuth2AuthorizationCodeRequestValidator } from "./authorization/code-re
6
6
  import { OAuth2AuthorizationStateManager } from "./authorization/state/module.mjs";
7
7
  import { OAuth2Authorization } from "./authorization/module.mjs";
8
8
  import "./authorization/index.mjs";
9
+ import { OAuth2ClientAuthenticator } from "./client/authenticator.mjs";
10
+ import "./client/index.mjs";
9
11
  import { buildOAuth2BearerTokenResponse } from "./response/bearer.mjs";
10
12
  import { OAuth2AuthorizeGrant } from "./grant-types/authorize.mjs";
11
13
  import { ClientCredentialsGrant } from "./grant-types/client-credentials.mjs";
@@ -25,4 +27,4 @@ import { OAuth2TokenRevoker } from "./token/revoker/module.mjs";
25
27
  import { OAuth2TokenSigner } from "./token/signer/module.mjs";
26
28
  import { OAuth2TokenVerifier } from "./token/verifier/module.mjs";
27
29
  import "./token/index.mjs";
28
- export { ClientCredentialsGrant, IdentityGrantType, OAuth2AccessTokenIssuer, OAuth2Authorization, OAuth2AuthorizationCodeIssuer, OAuth2AuthorizationCodeRequestValidator, OAuth2AuthorizationCodeRequestVerifier, OAuth2AuthorizationCodeVerifier, OAuth2AuthorizationStateManager, OAuth2AuthorizeGrant, OAuth2OpenIDClaimsBuilder, OAuth2OpenIDTokenIssuer, OAuth2RefreshTokenGrant, OAuth2RefreshTokenIssuer, OAuth2ScopeAttributesResolver, OAuth2TokenRevoker, OAuth2TokenSigner, OAuth2TokenVerifier, PasswordGrantType, RobotCredentialsGrant, base64URLEncode, buildOAuth2BearerTokenResponse, buildOAuth2CodeChallenge, buildOAuth2TokenHash, generateOAuth2CodeVerifier };
30
+ export { ClientCredentialsGrant, IdentityGrantType, OAuth2AccessTokenIssuer, OAuth2Authorization, OAuth2AuthorizationCodeIssuer, OAuth2AuthorizationCodeRequestValidator, OAuth2AuthorizationCodeRequestVerifier, OAuth2AuthorizationCodeVerifier, OAuth2AuthorizationStateManager, OAuth2AuthorizeGrant, OAuth2ClientAuthenticator, OAuth2OpenIDClaimsBuilder, OAuth2OpenIDTokenIssuer, OAuth2RefreshTokenGrant, OAuth2RefreshTokenIssuer, OAuth2ScopeAttributesResolver, OAuth2TokenRevoker, OAuth2TokenSigner, OAuth2TokenVerifier, PasswordGrantType, RobotCredentialsGrant, base64URLEncode, buildOAuth2BearerTokenResponse, buildOAuth2CodeChallenge, buildOAuth2TokenHash, generateOAuth2CodeVerifier };
@@ -3,10 +3,13 @@ import type { IOAuth2TokenSigner } from '../../signer/index.ts';
3
3
  import type { IOAuth2TokenRepository } from '../../repository/index.ts';
4
4
  import { OAuth2BaseTokenIssuer } from '../base.ts';
5
5
  import type { IOAuth2TokenIssuer, OAuth2TokenIssuerOptions, OAuth2TokenIssuerResponse } from '../types.ts';
6
+ import type { IIdentityRoleProvider } from '../../../../identity/index.ts';
6
7
  export declare class OAuth2AccessTokenIssuer extends OAuth2BaseTokenIssuer implements IOAuth2TokenIssuer {
7
8
  protected repository: IOAuth2TokenRepository;
8
9
  protected signer: IOAuth2TokenSigner;
9
- constructor(repository: IOAuth2TokenRepository, signer: IOAuth2TokenSigner, options?: OAuth2TokenIssuerOptions);
10
+ protected identityRoleProvider?: IIdentityRoleProvider;
11
+ constructor(repository: IOAuth2TokenRepository, signer: IOAuth2TokenSigner, options?: OAuth2TokenIssuerOptions, identityRoleProvider?: IIdentityRoleProvider);
10
12
  issue(input?: OAuth2TokenPayload): Promise<OAuth2TokenIssuerResponse>;
13
+ protected buildAccessClaims(input: OAuth2TokenPayload): Promise<Pick<OAuth2TokenPayload, 'realm_access' | 'global_access'>>;
11
14
  }
12
15
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/core/oauth2/token/issuer/access/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAE3G,qBAAa,uBAAwB,SAAQ,qBAAsB,YAAW,kBAAkB;IAC5F,SAAS,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAE7C,SAAS,CAAC,MAAM,EAAG,kBAAkB,CAAC;gBAGlC,UAAU,EAAE,sBAAsB,EAClC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,wBAA6B;IAQpC,KAAK,CAAC,KAAK,GAAE,kBAAuB,GAAI,OAAO,CAAC,yBAAyB,CAAC;CAgBnF"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/core/oauth2/token/issuer/access/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC3G,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAE3E,qBAAa,uBAAwB,SAAQ,qBAAsB,YAAW,kBAAkB;IAC5F,SAAS,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAE7C,SAAS,CAAC,MAAM,EAAG,kBAAkB,CAAC;IAEtC,SAAS,CAAC,oBAAoB,CAAC,EAAE,qBAAqB,CAAC;gBAGnD,UAAU,EAAE,sBAAsB,EAClC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,wBAA6B,EACtC,oBAAoB,CAAC,EAAE,qBAAqB;IAS1C,KAAK,CAAC,KAAK,GAAE,kBAAuB,GAAI,OAAO,CAAC,yBAAyB,CAAC;cAoBhE,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,GAAI,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC;CA6BrI"}
@@ -4,23 +4,45 @@ import { OAuth2TokenKind } from "@authup/specs";
4
4
  var OAuth2AccessTokenIssuer = class extends OAuth2BaseTokenIssuer {
5
5
  repository;
6
6
  signer;
7
- constructor(repository, signer, options = {}) {
7
+ identityRoleProvider;
8
+ constructor(repository, signer, options = {}, identityRoleProvider) {
8
9
  super(options);
9
10
  this.repository = repository;
10
11
  this.signer = signer;
12
+ this.identityRoleProvider = identityRoleProvider;
11
13
  }
12
14
  async issue(input = {}) {
13
15
  const iss = this.buildIss(input);
16
+ const accessClaims = await this.buildAccessClaims(input);
14
17
  const data = await this.repository.insert({
15
18
  ...input,
16
19
  kind: OAuth2TokenKind.ACCESS,
17
20
  exp: this.buildExp(input),
18
- ...iss ? { iss } : {}
21
+ ...iss ? { iss } : {},
22
+ ...accessClaims
19
23
  });
20
24
  const token = await this.signer.sign(data);
21
25
  await this.repository.saveWithSignature(data, token);
22
26
  return [token, data];
23
27
  }
28
+ async buildAccessClaims(input) {
29
+ if (!this.identityRoleProvider || !input.sub || !input.sub_kind) return {};
30
+ const roles = await this.identityRoleProvider.getRolesFor({
31
+ type: input.sub_kind,
32
+ id: input.sub,
33
+ clientId: input.client_id,
34
+ realmId: input.realm_id,
35
+ realmName: input.realm_name
36
+ });
37
+ const realmRoles = [];
38
+ const globalRoles = [];
39
+ for (const role of roles) if (!role.realm_id) globalRoles.push(role.name);
40
+ else if (input.realm_id && role.realm_id === input.realm_id) realmRoles.push(role.name);
41
+ return {
42
+ realm_access: { roles: realmRoles },
43
+ global_access: { roles: globalRoles }
44
+ };
45
+ }
24
46
  };
25
47
  //#endregion
26
48
  export { OAuth2AccessTokenIssuer };
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["OAuth2TokenKind","OAuth2BaseTokenIssuer","OAuth2AccessTokenIssuer","repository","signer","options","issue","input","iss","buildIss","data","insert","kind","ACCESS","exp","buildExp","token","sign","saveWithSignature"],"sources":["../../../../../../src/core/oauth2/token/issuer/access/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2TokenKind } from '@authup/specs';\nimport type { IOAuth2TokenSigner } from '../../signer/index.ts';\nimport type { IOAuth2TokenRepository } from '../../repository/index.ts';\nimport { OAuth2BaseTokenIssuer } from '../base.ts';\nimport type { IOAuth2TokenIssuer, OAuth2TokenIssuerOptions, OAuth2TokenIssuerResponse } from '../types.ts';\n\nexport class OAuth2AccessTokenIssuer extends OAuth2BaseTokenIssuer implements IOAuth2TokenIssuer {\n protected repository: IOAuth2TokenRepository;\n\n protected signer : IOAuth2TokenSigner;\n\n constructor(\n repository: IOAuth2TokenRepository,\n signer: IOAuth2TokenSigner,\n options: OAuth2TokenIssuerOptions = {},\n ) {\n super(options);\n\n this.repository = repository;\n this.signer = signer;\n }\n\n async issue(input: OAuth2TokenPayload = {}) : Promise<OAuth2TokenIssuerResponse> {\n const iss = this.buildIss(input);\n\n const data = await this.repository.insert({\n ...input,\n kind: OAuth2TokenKind.ACCESS,\n exp: this.buildExp(input),\n ...(iss ? { iss } : {}),\n });\n\n const token = await this.signer.sign(data);\n\n await this.repository.saveWithSignature(data, token);\n\n return [token, data];\n }\n}\n"],"mappings":";;;AAcA,IAAaE,0BAAb,cAA6CD,sBAAAA;CAC/BE;CAEAC;CAEV,YACID,YACAC,QACAC,UAAoC,EAAE,EACxC;AACE,QAAMA,QAAAA;AAEN,OAAKF,aAAaA;AAClB,OAAKC,SAASA;;CAGlB,MAAME,MAAMC,QAA4B,EAAE,EAAuC;EAC7E,MAAMC,MAAM,KAAKC,SAASF,MAAAA;EAE1B,MAAMG,OAAO,MAAM,KAAKP,WAAWQ,OAAO;GACtC,GAAGJ;GACHK,MAAMZ,gBAAgBa;GACtBC,KAAK,KAAKC,SAASR,MAAAA;GACnB,GAAIC,MAAM,EAAEA,KAAI,GAAI,EAAE;GAC1B,CAAA;EAEA,MAAMQ,QAAQ,MAAM,KAAKZ,OAAOa,KAAKP,KAAAA;AAErC,QAAM,KAAKP,WAAWe,kBAAkBR,MAAMM,MAAAA;AAE9C,SAAO,CAACA,OAAON,KAAK"}
1
+ {"version":3,"file":"module.mjs","names":["OAuth2TokenKind","OAuth2BaseTokenIssuer","OAuth2AccessTokenIssuer","repository","signer","identityRoleProvider","options","issue","input","iss","buildIss","accessClaims","buildAccessClaims","data","insert","kind","ACCESS","exp","buildExp","token","sign","saveWithSignature","sub","sub_kind","roles","getRolesFor","type","id","clientId","client_id","realmId","realm_id","realmName","realm_name","realmRoles","globalRoles","role","push","name","realm_access","global_access"],"sources":["../../../../../../src/core/oauth2/token/issuer/access/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2TokenKind } from '@authup/specs';\nimport type { IOAuth2TokenSigner } from '../../signer/index.ts';\nimport type { IOAuth2TokenRepository } from '../../repository/index.ts';\nimport { OAuth2BaseTokenIssuer } from '../base.ts';\nimport type { IOAuth2TokenIssuer, OAuth2TokenIssuerOptions, OAuth2TokenIssuerResponse } from '../types.ts';\nimport type { IIdentityRoleProvider } from '../../../../identity/index.ts';\n\nexport class OAuth2AccessTokenIssuer extends OAuth2BaseTokenIssuer implements IOAuth2TokenIssuer {\n protected repository: IOAuth2TokenRepository;\n\n protected signer : IOAuth2TokenSigner;\n\n protected identityRoleProvider?: IIdentityRoleProvider;\n\n constructor(\n repository: IOAuth2TokenRepository,\n signer: IOAuth2TokenSigner,\n options: OAuth2TokenIssuerOptions = {},\n identityRoleProvider?: IIdentityRoleProvider,\n ) {\n super(options);\n\n this.repository = repository;\n this.signer = signer;\n this.identityRoleProvider = identityRoleProvider;\n }\n\n async issue(input: OAuth2TokenPayload = {}) : Promise<OAuth2TokenIssuerResponse> {\n const iss = this.buildIss(input);\n\n const accessClaims = await this.buildAccessClaims(input);\n\n const data = await this.repository.insert({\n ...input,\n kind: OAuth2TokenKind.ACCESS,\n exp: this.buildExp(input),\n ...(iss ? { iss } : {}),\n ...accessClaims,\n });\n\n const token = await this.signer.sign(data);\n\n await this.repository.saveWithSignature(data, token);\n\n return [token, data];\n }\n\n protected async buildAccessClaims(input: OAuth2TokenPayload) : Promise<Pick<OAuth2TokenPayload, 'realm_access' | 'global_access'>> {\n if (!this.identityRoleProvider || !input.sub || !input.sub_kind) {\n return {};\n }\n\n const roles = await this.identityRoleProvider.getRolesFor({\n type: input.sub_kind,\n id: input.sub,\n clientId: input.client_id,\n realmId: input.realm_id,\n realmName: input.realm_name,\n });\n\n const realmRoles: string[] = [];\n const globalRoles: string[] = [];\n\n for (const role of roles) {\n if (!role.realm_id) {\n globalRoles.push(role.name);\n } else if (input.realm_id && role.realm_id === input.realm_id) {\n realmRoles.push(role.name);\n }\n }\n\n return {\n realm_access: { roles: realmRoles },\n global_access: { roles: globalRoles },\n };\n }\n}\n"],"mappings":";;;AAeA,IAAaE,0BAAb,cAA6CD,sBAAAA;CAC/BE;CAEAC;CAEAC;CAEV,YACIF,YACAC,QACAE,UAAoC,EAAE,EACtCD,sBACF;AACE,QAAMC,QAAAA;AAEN,OAAKH,aAAaA;AAClB,OAAKC,SAASA;AACd,OAAKC,uBAAuBA;;CAGhC,MAAME,MAAMC,QAA4B,EAAE,EAAuC;EAC7E,MAAMC,MAAM,KAAKC,SAASF,MAAAA;EAE1B,MAAMG,eAAe,MAAM,KAAKC,kBAAkBJ,MAAAA;EAElD,MAAMK,OAAO,MAAM,KAAKV,WAAWW,OAAO;GACtC,GAAGN;GACHO,MAAMf,gBAAgBgB;GACtBC,KAAK,KAAKC,SAASV,MAAAA;GACnB,GAAIC,MAAM,EAAEA,KAAI,GAAI,EAAE;GACtB,GAAGE;GACP,CAAA;EAEA,MAAMQ,QAAQ,MAAM,KAAKf,OAAOgB,KAAKP,KAAAA;AAErC,QAAM,KAAKV,WAAWkB,kBAAkBR,MAAMM,MAAAA;AAE9C,SAAO,CAACA,OAAON,KAAK;;CAGxB,MAAgBD,kBAAkBJ,OAAiG;AAC/H,MAAI,CAAC,KAAKH,wBAAwB,CAACG,MAAMc,OAAO,CAACd,MAAMe,SACnD,QAAO,EAAC;EAGZ,MAAMC,QAAQ,MAAM,KAAKnB,qBAAqBoB,YAAY;GACtDC,MAAMlB,MAAMe;GACZI,IAAInB,MAAMc;GACVM,UAAUpB,MAAMqB;GAChBC,SAAStB,MAAMuB;GACfC,WAAWxB,MAAMyB;GACrB,CAAA;EAEA,MAAMC,aAAuB,EAAE;EAC/B,MAAMC,cAAwB,EAAE;AAEhC,OAAK,MAAMC,QAAQZ,MACf,KAAI,CAACY,KAAKL,SACNI,aAAYE,KAAKD,KAAKE,KAAI;WACnB9B,MAAMuB,YAAYK,KAAKL,aAAavB,MAAMuB,SACjDG,YAAWG,KAAKD,KAAKE,KAAI;AAIjC,SAAO;GACHC,cAAc,EAAEf,OAAOU,YAAW;GAClCM,eAAe,EAAEhB,OAAOW,aAAY;GACxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../src/core/oauth2/token/issuer/base.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE1G,8BAAsB,qBAAsB,YAAW,kBAAkB;IACrE,SAAS,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAI5C,SAAS,aAAa,OAAO,CAAC,EAAE,wBAAwB;IAMxD,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAIjH,QAAQ,CAAC,KAAK,GAAE,kBAAuB,GAAI,MAAM,GAAG,SAAS;IAY7D;;;;OAIG;IACH,QAAQ,CAAC,KAAK,GAAE,kBAAuB,GAAI,MAAM;CAYpD"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../src/core/oauth2/token/issuer/base.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE1G,8BAAsB,qBAAsB,YAAW,kBAAkB;IACrE,SAAS,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAI5C,SAAS,aAAa,OAAO,CAAC,EAAE,wBAAwB;IAMxD,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAIjH,QAAQ,CAAC,KAAK,GAAE,kBAAuB,GAAI,MAAM,GAAG,SAAS;IAiB7D;;;;OAIG;IACH,QAAQ,CAAC,KAAK,GAAE,kBAAuB,GAAI,MAAM;CAYpD"}
@@ -6,8 +6,9 @@ var OAuth2BaseTokenIssuer = class {
6
6
  }
7
7
  buildIss(input = {}) {
8
8
  if (!this.options.issuer) return;
9
- if (input.realm_name) return `${this.options.issuer}/realms/${input.realm_name}`;
10
- return this.options.issuer;
9
+ const base = this.options.issuer.replace(/\/+$/, "");
10
+ if (input.realm_name) return `${base}/realms/${input.realm_name}`;
11
+ return base;
11
12
  }
12
13
  /**
13
14
  * Build utc expire time (in seconds).
@@ -1 +1 @@
1
- {"version":3,"file":"base.mjs","names":["OAuth2BaseTokenIssuer","options","buildIss","input","issuer","undefined","realm_name","buildExp","exp","utc","Math","floor","Date","getTime","maxAge"],"sources":["../../../../../src/core/oauth2/token/issuer/base.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport type { IOAuth2TokenIssuer, OAuth2TokenIssuerOptions, OAuth2TokenIssuerResponse } from './types.ts';\n\nexport abstract class OAuth2BaseTokenIssuer implements IOAuth2TokenIssuer {\n protected options: OAuth2TokenIssuerOptions;\n\n // ------------------------------------------------------------------\n\n protected constructor(options?: OAuth2TokenIssuerOptions) {\n this.options = options || {};\n }\n\n // ------------------------------------------------------------------\n\n abstract issue(input: OAuth2TokenPayload, options?: OAuth2TokenIssuerOptions): Promise<OAuth2TokenIssuerResponse>;\n\n // ------------------------------------------------------------------\n\n buildIss(input: OAuth2TokenPayload = {}) : string | undefined {\n if (!this.options.issuer) {\n return undefined;\n }\n\n if (input.realm_name) {\n return `${this.options.issuer}/realms/${input.realm_name}`;\n }\n\n return this.options.issuer;\n }\n\n /**\n * Build utc expire time (in seconds).\n *\n * @param input\n */\n buildExp(input: OAuth2TokenPayload = {}) : number {\n if (input.exp) {\n return input.exp;\n }\n\n const utc = Math.floor(new Date().getTime() / 1000);\n if (this.options.maxAge) {\n return utc + this.options.maxAge;\n }\n\n return utc + 3_600;\n }\n}\n"],"mappings":";AAUA,IAAsBA,wBAAtB,MAAsBA;CACRC;CAIV,YAAsBA,SAAoC;AACtD,OAAKA,UAAUA,WAAW,EAAC;;CAS/BC,SAASC,QAA4B,EAAE,EAAuB;AAC1D,MAAI,CAAC,KAAKF,QAAQG,OACd;AAGJ,MAAID,MAAMG,WACN,QAAO,GAAG,KAAKL,QAAQG,OAAO,UAAUD,MAAMG;AAGlD,SAAO,KAAKL,QAAQG;;;;;;IAQxBG,SAASJ,QAA4B,EAAE,EAAW;AAC9C,MAAIA,MAAMK,IACN,QAAOL,MAAMK;EAGjB,MAAMC,MAAMC,KAAKC,uBAAM,IAAIC,MAAAA,EAAOC,SAAO,GAAK,IAAA;AAC9C,MAAI,KAAKZ,QAAQa,OACb,QAAOL,MAAM,KAAKR,QAAQa;AAG9B,SAAOL,MAAM"}
1
+ {"version":3,"file":"base.mjs","names":["OAuth2BaseTokenIssuer","options","buildIss","input","issuer","undefined","base","replace","realm_name","buildExp","exp","utc","Math","floor","Date","getTime","maxAge"],"sources":["../../../../../src/core/oauth2/token/issuer/base.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport type { IOAuth2TokenIssuer, OAuth2TokenIssuerOptions, OAuth2TokenIssuerResponse } from './types.ts';\n\nexport abstract class OAuth2BaseTokenIssuer implements IOAuth2TokenIssuer {\n protected options: OAuth2TokenIssuerOptions;\n\n // ------------------------------------------------------------------\n\n protected constructor(options?: OAuth2TokenIssuerOptions) {\n this.options = options || {};\n }\n\n // ------------------------------------------------------------------\n\n abstract issue(input: OAuth2TokenPayload, options?: OAuth2TokenIssuerOptions): Promise<OAuth2TokenIssuerResponse>;\n\n // ------------------------------------------------------------------\n\n buildIss(input: OAuth2TokenPayload = {}) : string | undefined {\n if (!this.options.issuer) {\n return undefined;\n }\n\n // Strip a trailing slash so a configured issuer like\n // `https://auth.example.com/` doesn't produce a malformed\n // `https://auth.example.com//realms/master`.\n const base = this.options.issuer.replace(/\\/+$/, '');\n\n if (input.realm_name) {\n return `${base}/realms/${input.realm_name}`;\n }\n\n return base;\n }\n\n /**\n * Build utc expire time (in seconds).\n *\n * @param input\n */\n buildExp(input: OAuth2TokenPayload = {}) : number {\n if (input.exp) {\n return input.exp;\n }\n\n const utc = Math.floor(new Date().getTime() / 1000);\n if (this.options.maxAge) {\n return utc + this.options.maxAge;\n }\n\n return utc + 3_600;\n }\n}\n"],"mappings":";AAUA,IAAsBA,wBAAtB,MAAsBA;CACRC;CAIV,YAAsBA,SAAoC;AACtD,OAAKA,UAAUA,WAAW,EAAC;;CAS/BC,SAASC,QAA4B,EAAE,EAAuB;AAC1D,MAAI,CAAC,KAAKF,QAAQG,OACd;EAMJ,MAAME,OAAO,KAAKL,QAAQG,OAAOG,QAAQ,QAAQ,GAAA;AAEjD,MAAIJ,MAAMK,WACN,QAAO,GAAGF,KAAK,UAAUH,MAAMK;AAGnC,SAAOF;;;;;;IAQXG,SAASN,QAA4B,EAAE,EAAW;AAC9C,MAAIA,MAAMO,IACN,QAAOP,MAAMO;EAGjB,MAAMC,MAAMC,KAAKC,uBAAM,IAAIC,MAAAA,EAAOC,SAAO,GAAK,IAAA;AAC9C,MAAI,KAAKd,QAAQe,OACb,QAAOL,MAAM,KAAKV,QAAQe;AAG9B,SAAOL,MAAM"}
@@ -1,6 +1,14 @@
1
1
  import type { Permission } from '@authup/core-kit';
2
2
  import type { BaseProvisioningEntity } from '../types.ts';
3
+ export type PermissionProvisioningRelations = {
4
+ /**
5
+ * Policy names to attach to this permission via auth_permission_policies.
6
+ * Resolved to IDs and inserted as junction rows during provisioning.
7
+ */
8
+ policies?: string[];
9
+ };
3
10
  export type PermissionProvisioningEntity = BaseProvisioningEntity<Permission> & {
4
11
  attributes: Partial<Permission>;
12
+ relations?: PermissionProvisioningRelations;
5
13
  };
6
14
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/entities/permission/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,4BAA4B,GAAG,sBAAsB,CAAC,UAAU,CAAC,GAAG;IAC5E,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;CAClC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/entities/permission/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,+BAA+B,GAAG;IAC1C;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,sBAAsB,CAAC,UAAU,CAAC,GAAG;IAC5E,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,+BAA+B,CAAC;CAC/C,CAAC"}
@@ -1,10 +1,14 @@
1
- import type { IPermissionRepository } from '../../../entities/index.ts';
1
+ import type { IPermissionPolicyRepository } from '../../../entities/permission-policy/types.ts';
2
+ import type { IPermissionRepository, IPolicyRepository } from '../../../entities/index.ts';
2
3
  import type { PermissionProvisioningEntity } from '../../entities/permission';
3
4
  import { BaseProvisioningSynchronizer } from '../base.ts';
4
5
  import type { PermissionProvisioningSynchronizerContext } from './types.ts';
5
6
  export declare class PermissionProvisioningSynchronizer extends BaseProvisioningSynchronizer<PermissionProvisioningEntity> {
6
7
  protected repository: IPermissionRepository;
8
+ protected policyRepository?: IPolicyRepository;
9
+ protected permissionPolicyRepository?: IPermissionPolicyRepository;
7
10
  constructor(ctx: PermissionProvisioningSynchronizerContext);
8
11
  synchronize(input: PermissionProvisioningEntity): Promise<PermissionProvisioningEntity>;
12
+ private synchronizePolicies;
9
13
  }
10
14
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/permission/module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAE9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,yCAAyC,EAAE,MAAM,YAAY,CAAC;AAE5E,qBAAa,kCAAmC,SAAQ,4BAA4B,CAAC,4BAA4B,CAAC;IAC9G,SAAS,CAAC,UAAU,EAAG,qBAAqB,CAAC;gBAEjC,GAAG,EAAE,yCAAyC;IAMpD,WAAW,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,4BAA4B,CAAC;CA6ChG"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/permission/module.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAChG,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAE9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,yCAAyC,EAAE,MAAM,YAAY,CAAC;AAE5E,qBAAa,kCAAmC,SAAQ,4BAA4B,CAAC,4BAA4B,CAAC;IAC9G,SAAS,CAAC,UAAU,EAAG,qBAAqB,CAAC;IAE7C,SAAS,CAAC,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAE/C,SAAS,CAAC,0BAA0B,CAAC,EAAE,2BAA2B,CAAC;gBAEvD,GAAG,EAAE,yCAAyC;IAQpD,WAAW,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,4BAA4B,CAAC;YAkD/E,mBAAmB;CAgCpC"}
@@ -6,9 +6,13 @@ import { pickRecord } from "@authup/kit";
6
6
  //#region src/core/provisioning/synchronizer/permission/module.ts
7
7
  var PermissionProvisioningSynchronizer = class extends BaseProvisioningSynchronizer {
8
8
  repository;
9
+ policyRepository;
10
+ permissionPolicyRepository;
9
11
  constructor(ctx) {
10
12
  super();
11
13
  this.repository = ctx.repository;
14
+ this.policyRepository = ctx.policyRepository;
15
+ this.permissionPolicyRepository = ctx.permissionPolicyRepository;
12
16
  }
13
17
  async synchronize(input) {
14
18
  const strategy = normalizeEntityProvisioningStrategy(input.strategy);
@@ -35,11 +39,30 @@ var PermissionProvisioningSynchronizer = class extends BaseProvisioningSynchroni
35
39
  break;
36
40
  }
37
41
  else attributes = await this.repository.save(this.repository.create(input.attributes));
42
+ if (input.relations?.policies && input.relations.policies.length > 0) await this.synchronizePolicies(attributes, input.relations.policies);
38
43
  return {
39
44
  ...input,
40
45
  attributes
41
46
  };
42
47
  }
48
+ async synchronizePolicies(permission, policyNames) {
49
+ if (!this.policyRepository || !this.permissionPolicyRepository) throw new Error("Provisioning: policy/permissionPolicy repositories must be wired to attach policies to permissions.");
50
+ for (const policyName of policyNames) {
51
+ const policy = await this.policyRepository.findOneByName(policyName);
52
+ if (!policy) throw new Error(`Provisioning: policy '${policyName}' not found for permission '${permission.name}'.`);
53
+ if (await this.permissionPolicyRepository.findOneBy({
54
+ permission_id: permission.id,
55
+ policy_id: policy.id
56
+ })) continue;
57
+ const entry = this.permissionPolicyRepository.create({
58
+ permission_id: permission.id,
59
+ permission_realm_id: permission.realm_id,
60
+ policy_id: policy.id,
61
+ policy_realm_id: policy.realm_id
62
+ });
63
+ await this.permissionPolicyRepository.save(entry);
64
+ }
65
+ }
43
66
  };
44
67
  //#endregion
45
68
  export { PermissionProvisioningSynchronizer };
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["pickRecord","ProvisioningEntityStrategyType","normalizeEntityProvisioningStrategy","BaseProvisioningSynchronizer","PermissionProvisioningSynchronizer","repository","ctx","synchronize","input","strategy","attributes","findOneBy","name","realm_id","client_id","type","ABSENT","remove","MERGE","merge","save","REPLACE","id","create"],"sources":["../../../../../src/core/provisioning/synchronizer/permission/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { pickRecord } from '@authup/kit';\nimport type { IPermissionRepository } from '../../../entities/index.ts';\nimport type { PermissionProvisioningEntity } from '../../entities/permission';\nimport { ProvisioningEntityStrategyType, normalizeEntityProvisioningStrategy } from '../../strategy/index.ts';\nimport { BaseProvisioningSynchronizer } from '../base.ts';\nimport type { PermissionProvisioningSynchronizerContext } from './types.ts';\n\nexport class PermissionProvisioningSynchronizer extends BaseProvisioningSynchronizer<PermissionProvisioningEntity> {\n protected repository : IPermissionRepository;\n\n constructor(ctx: PermissionProvisioningSynchronizerContext) {\n super();\n\n this.repository = ctx.repository;\n }\n\n async synchronize(input: PermissionProvisioningEntity): Promise<PermissionProvisioningEntity> {\n const strategy = normalizeEntityProvisioningStrategy(input.strategy);\n\n let attributes = await this.repository.findOneBy({\n name: input.attributes.name,\n realm_id: input.attributes.realm_id || null,\n client_id: input.attributes.client_id || null,\n });\n\n if (strategy.type === ProvisioningEntityStrategyType.ABSENT) {\n if (attributes) {\n await this.repository.remove(attributes);\n }\n return {\n ...input,\n attributes: attributes || input.attributes, \n };\n }\n\n if (attributes) {\n switch (strategy.type) {\n case ProvisioningEntityStrategyType.MERGE:\n attributes = this.repository.merge(\n attributes,\n strategy.attributes ?\n pickRecord(input.attributes, strategy.attributes) :\n input.attributes,\n );\n\n attributes = await this.repository.save(attributes);\n break;\n case ProvisioningEntityStrategyType.REPLACE:\n input.attributes.id = attributes.id;\n attributes = await this.repository.save(this.repository.create(input.attributes));\n break;\n }\n } else {\n attributes = await this.repository.save(this.repository.create(input.attributes));\n }\n\n return {\n ...input,\n attributes,\n };\n }\n}\n"],"mappings":";;;;;;AAcA,IAAaI,qCAAb,cAAwDD,6BAAAA;CAC1CE;CAEV,YAAYC,KAAgD;AACxD,SAAK;AAEL,OAAKD,aAAaC,IAAID;;CAG1B,MAAME,YAAYC,OAA4E;EAC1F,MAAMC,WAAWP,oCAAoCM,MAAMC,SAAQ;EAEnE,IAAIC,aAAa,MAAM,KAAKL,WAAWM,UAAU;GAC7CC,MAAMJ,MAAME,WAAWE;GACvBC,UAAUL,MAAME,WAAWG,YAAY;GACvCC,WAAWN,MAAME,WAAWI,aAAa;GAC7C,CAAA;AAEA,MAAIL,SAASM,SAASd,+BAA+Be,QAAQ;AACzD,OAAIN,WACA,OAAM,KAAKL,WAAWY,OAAOP,WAAAA;AAEjC,UAAO;IACH,GAAGF;IACHE,YAAYA,cAAcF,MAAME;IACpC;;AAGJ,MAAIA,WACA,SAAQD,SAASM,MAAjB;GACI,KAAKd,+BAA+BiB;AAChCR,iBAAa,KAAKL,WAAWc,MACzBT,YACAD,SAASC,aACLV,WAAWQ,MAAME,YAAYD,SAASC,WAAU,GAChDF,MAAME,WAAU;AAGxBA,iBAAa,MAAM,KAAKL,WAAWe,KAAKV,WAAAA;AACxC;GACJ,KAAKT,+BAA+BoB;AAChCb,UAAME,WAAWY,KAAKZ,WAAWY;AACjCZ,iBAAa,MAAM,KAAKL,WAAWe,KAAK,KAAKf,WAAWkB,OAAOf,MAAME,WAAU,CAAA;AAC/E;;MAGRA,cAAa,MAAM,KAAKL,WAAWe,KAAK,KAAKf,WAAWkB,OAAOf,MAAME,WAAU,CAAA;AAGnF,SAAO;GACH,GAAGF;GACHE;GACJ"}
1
+ {"version":3,"file":"module.mjs","names":["pickRecord","ProvisioningEntityStrategyType","normalizeEntityProvisioningStrategy","BaseProvisioningSynchronizer","PermissionProvisioningSynchronizer","repository","policyRepository","permissionPolicyRepository","ctx","synchronize","input","strategy","attributes","findOneBy","name","realm_id","client_id","type","ABSENT","remove","MERGE","merge","save","REPLACE","id","create","relations","policies","length","synchronizePolicies","permission","policyNames","Error","policyName","policy","findOneByName","existing","permission_id","policy_id","entry","permission_realm_id","policy_realm_id"],"sources":["../../../../../src/core/provisioning/synchronizer/permission/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { pickRecord } from '@authup/kit';\nimport type { Permission } from '@authup/core-kit';\nimport type { IPermissionPolicyRepository } from '../../../entities/permission-policy/types.ts';\nimport type { IPermissionRepository, IPolicyRepository } from '../../../entities/index.ts';\nimport type { PermissionProvisioningEntity } from '../../entities/permission';\nimport { ProvisioningEntityStrategyType, normalizeEntityProvisioningStrategy } from '../../strategy/index.ts';\nimport { BaseProvisioningSynchronizer } from '../base.ts';\nimport type { PermissionProvisioningSynchronizerContext } from './types.ts';\n\nexport class PermissionProvisioningSynchronizer extends BaseProvisioningSynchronizer<PermissionProvisioningEntity> {\n protected repository : IPermissionRepository;\n\n protected policyRepository?: IPolicyRepository;\n\n protected permissionPolicyRepository?: IPermissionPolicyRepository;\n\n constructor(ctx: PermissionProvisioningSynchronizerContext) {\n super();\n\n this.repository = ctx.repository;\n this.policyRepository = ctx.policyRepository;\n this.permissionPolicyRepository = ctx.permissionPolicyRepository;\n }\n\n async synchronize(input: PermissionProvisioningEntity): Promise<PermissionProvisioningEntity> {\n const strategy = normalizeEntityProvisioningStrategy(input.strategy);\n\n let attributes = await this.repository.findOneBy({\n name: input.attributes.name,\n realm_id: input.attributes.realm_id || null,\n client_id: input.attributes.client_id || null,\n });\n\n if (strategy.type === ProvisioningEntityStrategyType.ABSENT) {\n if (attributes) {\n await this.repository.remove(attributes);\n }\n return {\n ...input,\n attributes: attributes || input.attributes,\n };\n }\n\n if (attributes) {\n switch (strategy.type) {\n case ProvisioningEntityStrategyType.MERGE:\n attributes = this.repository.merge(\n attributes,\n strategy.attributes ?\n pickRecord(input.attributes, strategy.attributes) :\n input.attributes,\n );\n\n attributes = await this.repository.save(attributes);\n break;\n case ProvisioningEntityStrategyType.REPLACE:\n input.attributes.id = attributes.id;\n attributes = await this.repository.save(this.repository.create(input.attributes));\n break;\n }\n } else {\n attributes = await this.repository.save(this.repository.create(input.attributes));\n }\n\n if (input.relations?.policies && input.relations.policies.length > 0) {\n await this.synchronizePolicies(attributes, input.relations.policies);\n }\n\n return {\n ...input,\n attributes,\n };\n }\n\n private async synchronizePolicies(permission: Permission, policyNames: string[]): Promise<void> {\n if (!this.policyRepository || !this.permissionPolicyRepository) {\n throw new Error(\n 'Provisioning: policy/permissionPolicy repositories must be wired to attach policies to permissions.',\n );\n }\n\n for (const policyName of policyNames) {\n const policy = await this.policyRepository.findOneByName(policyName);\n if (!policy) {\n throw new Error(\n `Provisioning: policy '${policyName}' not found for permission '${permission.name}'.`,\n );\n }\n\n const existing = await this.permissionPolicyRepository.findOneBy({\n permission_id: permission.id,\n policy_id: policy.id,\n });\n if (existing) {\n continue;\n }\n\n const entry = this.permissionPolicyRepository.create({\n permission_id: permission.id,\n permission_realm_id: permission.realm_id,\n policy_id: policy.id,\n policy_realm_id: policy.realm_id,\n });\n await this.permissionPolicyRepository.save(entry);\n }\n }\n}\n"],"mappings":";;;;;;AAgBA,IAAaI,qCAAb,cAAwDD,6BAAAA;CAC1CE;CAEAC;CAEAC;CAEV,YAAYC,KAAgD;AACxD,SAAK;AAEL,OAAKH,aAAaG,IAAIH;AACtB,OAAKC,mBAAmBE,IAAIF;AAC5B,OAAKC,6BAA6BC,IAAID;;CAG1C,MAAME,YAAYC,OAA4E;EAC1F,MAAMC,WAAWT,oCAAoCQ,MAAMC,SAAQ;EAEnE,IAAIC,aAAa,MAAM,KAAKP,WAAWQ,UAAU;GAC7CC,MAAMJ,MAAME,WAAWE;GACvBC,UAAUL,MAAME,WAAWG,YAAY;GACvCC,WAAWN,MAAME,WAAWI,aAAa;GAC7C,CAAA;AAEA,MAAIL,SAASM,SAAShB,+BAA+BiB,QAAQ;AACzD,OAAIN,WACA,OAAM,KAAKP,WAAWc,OAAOP,WAAAA;AAEjC,UAAO;IACH,GAAGF;IACHE,YAAYA,cAAcF,MAAME;IACpC;;AAGJ,MAAIA,WACA,SAAQD,SAASM,MAAjB;GACI,KAAKhB,+BAA+BmB;AAChCR,iBAAa,KAAKP,WAAWgB,MACzBT,YACAD,SAASC,aACLZ,WAAWU,MAAME,YAAYD,SAASC,WAAU,GAChDF,MAAME,WAAU;AAGxBA,iBAAa,MAAM,KAAKP,WAAWiB,KAAKV,WAAAA;AACxC;GACJ,KAAKX,+BAA+BsB;AAChCb,UAAME,WAAWY,KAAKZ,WAAWY;AACjCZ,iBAAa,MAAM,KAAKP,WAAWiB,KAAK,KAAKjB,WAAWoB,OAAOf,MAAME,WAAU,CAAA;AAC/E;;MAGRA,cAAa,MAAM,KAAKP,WAAWiB,KAAK,KAAKjB,WAAWoB,OAAOf,MAAME,WAAU,CAAA;AAGnF,MAAIF,MAAMgB,WAAWC,YAAYjB,MAAMgB,UAAUC,SAASC,SAAS,EAC/D,OAAM,KAAKC,oBAAoBjB,YAAYF,MAAMgB,UAAUC,SAAQ;AAGvE,SAAO;GACH,GAAGjB;GACHE;GACJ;;CAGJ,MAAciB,oBAAoBC,YAAwBC,aAAsC;AAC5F,MAAI,CAAC,KAAKzB,oBAAoB,CAAC,KAAKC,2BAChC,OAAM,IAAIyB,MACN,sGAAA;AAIR,OAAK,MAAMC,cAAcF,aAAa;GAClC,MAAMG,SAAS,MAAM,KAAK5B,iBAAiB6B,cAAcF,WAAAA;AACzD,OAAI,CAACC,OACD,OAAM,IAAIF,MACN,yBAAyBC,WAAW,8BAA8BH,WAAWhB,KAAK,IAAG;AAQ7F,OAAIsB,MAJmB,KAAK7B,2BAA2BM,UAAU;IAC7DwB,eAAeP,WAAWN;IAC1Bc,WAAWJ,OAAOV;IACtB,CAAA,CAEI;GAGJ,MAAMe,QAAQ,KAAKhC,2BAA2BkB,OAAO;IACjDY,eAAeP,WAAWN;IAC1BgB,qBAAqBV,WAAWf;IAChCuB,WAAWJ,OAAOV;IAClBiB,iBAAiBP,OAAOnB;IAC5B,CAAA;AACA,SAAM,KAAKR,2BAA2Be,KAAKiB,MAAAA"}
@@ -1,5 +1,8 @@
1
- import type { IPermissionRepository } from '../../../entities/index.ts';
1
+ import type { IPermissionPolicyRepository } from '../../../entities/permission-policy/types.ts';
2
+ import type { IPermissionRepository, IPolicyRepository } from '../../../entities/index.ts';
2
3
  export type PermissionProvisioningSynchronizerContext = {
3
4
  repository: IPermissionRepository;
5
+ policyRepository?: IPolicyRepository;
6
+ permissionPolicyRepository?: IPermissionPolicyRepository;
4
7
  };
5
8
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/permission/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,MAAM,MAAM,yCAAyC,GAAG;IACpD,UAAU,EAAE,qBAAqB,CAAC;CACrC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/permission/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAChG,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE3F,MAAM,MAAM,yCAAyC,GAAG;IACpD,UAAU,EAAE,qBAAqB,CAAC;IAClC,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,0BAA0B,CAAC,EAAE,2BAA2B,CAAC;CAC5D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/policy/module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAChG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,8BAA+B,SAAQ,4BAA4B,CAAC,wBAAwB,CAAC;IACtG,SAAS,CAAC,UAAU,EAAE,iBAAiB,CAAC;IAExC,SAAS,CAAC,0BAA0B,EAAE,2BAA2B,CAAC;gBAEtD,GAAG,EAAE,qCAAqC;IAOhD,WAAW,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC;YA2BvE,mBAAmB;YAgBnB,oBAAoB;YAgBpB,iBAAiB;CAclC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/policy/module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAChG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,8BAA+B,SAAQ,4BAA4B,CAAC,wBAAwB,CAAC;IACtG,SAAS,CAAC,UAAU,EAAE,iBAAiB,CAAC;IAExC,SAAS,CAAC,0BAA0B,EAAE,2BAA2B,CAAC;gBAEtD,GAAG,EAAE,qCAAqC;IAOhD,WAAW,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC;YAmCvE,mBAAmB;YAgBnB,oBAAoB;YAgBpB,iBAAiB;CAclC"}
@@ -14,12 +14,14 @@ var PolicyProvisioningSynchronizer = class extends BaseProvisioningSynchronizer
14
14
  realm_id: input.attributes.realm_id || null
15
15
  });
16
16
  if (entity) {
17
- entity = this.repository.merge(entity, {
17
+ const mergeData = {
18
18
  type: input.attributes.type,
19
19
  built_in: input.attributes.built_in,
20
20
  parent_id: input.attributes.parent_id,
21
21
  parent: input.attributes.parent
22
- });
22
+ };
23
+ if (typeof input.attributes.invert !== "undefined") mergeData.invert = input.attributes.invert;
24
+ entity = this.repository.merge(entity, mergeData);
23
25
  await this.repository.saveWithEA(entity, input.extraAttributes);
24
26
  } else {
25
27
  entity = this.repository.create(input.attributes);
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["BaseProvisioningSynchronizer","PolicyProvisioningSynchronizer","repository","permissionPolicyRepository","ctx","synchronize","input","entity","findOneBy","name","attributes","realm_id","merge","type","built_in","parent_id","parent","saveWithEA","extraAttributes","create","synchronizeChildren","id","children","parentId","declaredNames","map","c","reduce","prev","child","Promise","resolve","cleanupStaleChildren","existingChildren","findManyBy","staleChildren","filter","includes","cleanupStaleChild","referencingJunctions","policy_id","length","deleteFromTree","detached"],"sources":["../../../../../src/core/provisioning/synchronizer/policy/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Policy } from '@authup/core-kit';\nimport type { IPermissionPolicyRepository } from '../../../entities/permission-policy/types.ts';\nimport type { IPolicyRepository } from '../../../entities/index.ts';\nimport type { PolicyProvisioningEntity } from '../../entities/policy/index.ts';\nimport { BaseProvisioningSynchronizer } from '../base.ts';\nimport type { PolicyProvisioningSynchronizerContext } from './types.ts';\n\nexport class PolicyProvisioningSynchronizer extends BaseProvisioningSynchronizer<PolicyProvisioningEntity> {\n protected repository: IPolicyRepository;\n\n protected permissionPolicyRepository: IPermissionPolicyRepository;\n\n constructor(ctx: PolicyProvisioningSynchronizerContext) {\n super();\n\n this.repository = ctx.repository;\n this.permissionPolicyRepository = ctx.permissionPolicyRepository;\n }\n\n async synchronize(input: PolicyProvisioningEntity): Promise<PolicyProvisioningEntity> {\n let entity = await this.repository.findOneBy({\n name: input.attributes.name,\n realm_id: input.attributes.realm_id || null,\n });\n\n if (entity) {\n entity = this.repository.merge(entity, {\n type: input.attributes.type,\n built_in: input.attributes.built_in,\n parent_id: input.attributes.parent_id,\n parent: input.attributes.parent,\n });\n await this.repository.saveWithEA(entity, input.extraAttributes);\n } else {\n entity = this.repository.create(input.attributes);\n await this.repository.saveWithEA(entity, input.extraAttributes);\n }\n\n await this.synchronizeChildren(entity.id, input.children || []);\n\n return {\n ...input,\n attributes: entity,\n };\n }\n\n private async synchronizeChildren(\n parentId: string,\n children: PolicyProvisioningEntity[] = [],\n ): Promise<void> {\n const declaredNames = children.map((c) => c.attributes.name);\n\n await children.reduce(async (prev, child) => {\n await prev;\n child.attributes.parent_id = parentId;\n child.attributes.parent = { id: parentId } as any;\n await this.synchronize(child);\n }, Promise.resolve());\n\n await this.cleanupStaleChildren(parentId, declaredNames);\n }\n\n private async cleanupStaleChildren(\n parentId: string,\n declaredNames: (string | undefined)[],\n ): Promise<void> {\n const existingChildren = await this.repository.findManyBy({ parent_id: parentId });\n\n const staleChildren = existingChildren.filter(\n (child) => !declaredNames.includes(child.name),\n );\n\n await staleChildren.reduce(async (prev, child) => {\n await prev;\n await this.cleanupStaleChild(child);\n }, Promise.resolve());\n }\n\n private async cleanupStaleChild(child: Policy): Promise<void> {\n const referencingJunctions = await this.permissionPolicyRepository.findManyBy({ policy_id: child.id });\n\n if (referencingJunctions.length === 0) {\n await this.repository.deleteFromTree(child);\n } else {\n const detached = this.repository.merge(child, {\n parent_id: null,\n parent: null,\n built_in: false,\n });\n await this.repository.saveWithEA(detached);\n }\n }\n}\n"],"mappings":";;AAcA,IAAaC,iCAAb,cAAoDD,6BAAAA;CACtCE;CAEAC;CAEV,YAAYC,KAA4C;AACpD,SAAK;AAEL,OAAKF,aAAaE,IAAIF;AACtB,OAAKC,6BAA6BC,IAAID;;CAG1C,MAAME,YAAYC,OAAoE;EAClF,IAAIC,SAAS,MAAM,KAAKL,WAAWM,UAAU;GACzCC,MAAMH,MAAMI,WAAWD;GACvBE,UAAUL,MAAMI,WAAWC,YAAY;GAC3C,CAAA;AAEA,MAAIJ,QAAQ;AACRA,YAAS,KAAKL,WAAWU,MAAML,QAAQ;IACnCM,MAAMP,MAAMI,WAAWG;IACvBC,UAAUR,MAAMI,WAAWI;IAC3BC,WAAWT,MAAMI,WAAWK;IAC5BC,QAAQV,MAAMI,WAAWM;IAC7B,CAAA;AACA,SAAM,KAAKd,WAAWe,WAAWV,QAAQD,MAAMY,gBAAe;SAC3D;AACHX,YAAS,KAAKL,WAAWiB,OAAOb,MAAMI,WAAU;AAChD,SAAM,KAAKR,WAAWe,WAAWV,QAAQD,MAAMY,gBAAe;;AAGlE,QAAM,KAAKE,oBAAoBb,OAAOc,IAAIf,MAAMgB,YAAY,EAAE,CAAA;AAE9D,SAAO;GACH,GAAGhB;GACHI,YAAYH;GAChB;;CAGJ,MAAca,oBACVG,UACAD,WAAuC,EAAE,EAC5B;EACb,MAAME,gBAAgBF,SAASG,KAAKC,MAAMA,EAAEhB,WAAWD,KAAI;AAE3D,QAAMa,SAASK,OAAO,OAAOC,MAAMC,UAAAA;AAC/B,SAAMD;AACNC,SAAMnB,WAAWK,YAAYQ;AAC7BM,SAAMnB,WAAWM,SAAS,EAAEK,IAAIE,UAAS;AACzC,SAAM,KAAKlB,YAAYwB,MAAAA;KACxBC,QAAQC,SAAO,CAAA;AAElB,QAAM,KAAKC,qBAAqBT,UAAUC,cAAAA;;CAG9C,MAAcQ,qBACVT,UACAC,eACa;AAOb,SAJsBS,MAFS,KAAK/B,WAAWgC,WAAW,EAAEnB,WAAWQ,UAAS,CAAA,EAEzCa,QAClCP,UAAU,CAACL,cAAca,SAASR,MAAMpB,KAAI,CAG3C0B,CAAcR,OAAO,OAAOC,MAAMC,UAAAA;AACpC,SAAMD;AACN,SAAM,KAAKU,kBAAkBT,MAAAA;KAC9BC,QAAQC,SAAO,CAAA;;CAGtB,MAAcO,kBAAkBT,OAA8B;AAG1D,OAAIU,MAF+B,KAAKpC,2BAA2B+B,WAAW,EAAEM,WAAWX,MAAMR,IAAG,CAAA,EAE3EoB,WAAW,EAChC,OAAM,KAAKvC,WAAWwC,eAAeb,MAAAA;OAClC;GACH,MAAMc,WAAW,KAAKzC,WAAWU,MAAMiB,OAAO;IAC1Cd,WAAW;IACXC,QAAQ;IACRF,UAAU;IACd,CAAA;AACA,SAAM,KAAKZ,WAAWe,WAAW0B,SAAAA"}
1
+ {"version":3,"file":"module.mjs","names":["BaseProvisioningSynchronizer","PolicyProvisioningSynchronizer","repository","permissionPolicyRepository","ctx","synchronize","input","entity","findOneBy","name","attributes","realm_id","mergeData","type","built_in","parent_id","parent","invert","merge","saveWithEA","extraAttributes","create","synchronizeChildren","id","children","parentId","declaredNames","map","c","reduce","prev","child","Promise","resolve","cleanupStaleChildren","existingChildren","findManyBy","staleChildren","filter","includes","cleanupStaleChild","referencingJunctions","policy_id","length","deleteFromTree","detached"],"sources":["../../../../../src/core/provisioning/synchronizer/policy/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Policy } from '@authup/core-kit';\nimport type { IPermissionPolicyRepository } from '../../../entities/permission-policy/types.ts';\nimport type { IPolicyRepository } from '../../../entities/index.ts';\nimport type { PolicyProvisioningEntity } from '../../entities/policy/index.ts';\nimport { BaseProvisioningSynchronizer } from '../base.ts';\nimport type { PolicyProvisioningSynchronizerContext } from './types.ts';\n\nexport class PolicyProvisioningSynchronizer extends BaseProvisioningSynchronizer<PolicyProvisioningEntity> {\n protected repository: IPolicyRepository;\n\n protected permissionPolicyRepository: IPermissionPolicyRepository;\n\n constructor(ctx: PolicyProvisioningSynchronizerContext) {\n super();\n\n this.repository = ctx.repository;\n this.permissionPolicyRepository = ctx.permissionPolicyRepository;\n }\n\n async synchronize(input: PolicyProvisioningEntity): Promise<PolicyProvisioningEntity> {\n let entity = await this.repository.findOneBy({\n name: input.attributes.name,\n realm_id: input.attributes.realm_id || null,\n });\n\n if (entity) {\n // Only assign `invert` when the source declares it explicitly.\n // TypeORM's `merge` is a plain assign and would otherwise clobber\n // an existing flag with `undefined` (turning `invert: true` into\n // `null`/`false` on every reprovisioning pass).\n const mergeData: Partial<Policy> = {\n type: input.attributes.type,\n built_in: input.attributes.built_in,\n parent_id: input.attributes.parent_id,\n parent: input.attributes.parent,\n };\n if (typeof input.attributes.invert !== 'undefined') {\n mergeData.invert = input.attributes.invert;\n }\n entity = this.repository.merge(entity, mergeData);\n await this.repository.saveWithEA(entity, input.extraAttributes);\n } else {\n entity = this.repository.create(input.attributes);\n await this.repository.saveWithEA(entity, input.extraAttributes);\n }\n\n await this.synchronizeChildren(entity.id, input.children || []);\n\n return {\n ...input,\n attributes: entity,\n };\n }\n\n private async synchronizeChildren(\n parentId: string,\n children: PolicyProvisioningEntity[] = [],\n ): Promise<void> {\n const declaredNames = children.map((c) => c.attributes.name);\n\n await children.reduce(async (prev, child) => {\n await prev;\n child.attributes.parent_id = parentId;\n child.attributes.parent = { id: parentId } as any;\n await this.synchronize(child);\n }, Promise.resolve());\n\n await this.cleanupStaleChildren(parentId, declaredNames);\n }\n\n private async cleanupStaleChildren(\n parentId: string,\n declaredNames: (string | undefined)[],\n ): Promise<void> {\n const existingChildren = await this.repository.findManyBy({ parent_id: parentId });\n\n const staleChildren = existingChildren.filter(\n (child) => !declaredNames.includes(child.name),\n );\n\n await staleChildren.reduce(async (prev, child) => {\n await prev;\n await this.cleanupStaleChild(child);\n }, Promise.resolve());\n }\n\n private async cleanupStaleChild(child: Policy): Promise<void> {\n const referencingJunctions = await this.permissionPolicyRepository.findManyBy({ policy_id: child.id });\n\n if (referencingJunctions.length === 0) {\n await this.repository.deleteFromTree(child);\n } else {\n const detached = this.repository.merge(child, {\n parent_id: null,\n parent: null,\n built_in: false,\n });\n await this.repository.saveWithEA(detached);\n }\n }\n}\n"],"mappings":";;AAcA,IAAaC,iCAAb,cAAoDD,6BAAAA;CACtCE;CAEAC;CAEV,YAAYC,KAA4C;AACpD,SAAK;AAEL,OAAKF,aAAaE,IAAIF;AACtB,OAAKC,6BAA6BC,IAAID;;CAG1C,MAAME,YAAYC,OAAoE;EAClF,IAAIC,SAAS,MAAM,KAAKL,WAAWM,UAAU;GACzCC,MAAMH,MAAMI,WAAWD;GACvBE,UAAUL,MAAMI,WAAWC,YAAY;GAC3C,CAAA;AAEA,MAAIJ,QAAQ;GAKR,MAAMK,YAA6B;IAC/BC,MAAMP,MAAMI,WAAWG;IACvBC,UAAUR,MAAMI,WAAWI;IAC3BC,WAAWT,MAAMI,WAAWK;IAC5BC,QAAQV,MAAMI,WAAWM;IAC7B;AACA,OAAI,OAAOV,MAAMI,WAAWO,WAAW,YACnCL,WAAUK,SAASX,MAAMI,WAAWO;AAExCV,YAAS,KAAKL,WAAWgB,MAAMX,QAAQK,UAAAA;AACvC,SAAM,KAAKV,WAAWiB,WAAWZ,QAAQD,MAAMc,gBAAe;SAC3D;AACHb,YAAS,KAAKL,WAAWmB,OAAOf,MAAMI,WAAU;AAChD,SAAM,KAAKR,WAAWiB,WAAWZ,QAAQD,MAAMc,gBAAe;;AAGlE,QAAM,KAAKE,oBAAoBf,OAAOgB,IAAIjB,MAAMkB,YAAY,EAAE,CAAA;AAE9D,SAAO;GACH,GAAGlB;GACHI,YAAYH;GAChB;;CAGJ,MAAce,oBACVG,UACAD,WAAuC,EAAE,EAC5B;EACb,MAAME,gBAAgBF,SAASG,KAAKC,MAAMA,EAAElB,WAAWD,KAAI;AAE3D,QAAMe,SAASK,OAAO,OAAOC,MAAMC,UAAAA;AAC/B,SAAMD;AACNC,SAAMrB,WAAWK,YAAYU;AAC7BM,SAAMrB,WAAWM,SAAS,EAAEO,IAAIE,UAAS;AACzC,SAAM,KAAKpB,YAAY0B,MAAAA;KACxBC,QAAQC,SAAO,CAAA;AAElB,QAAM,KAAKC,qBAAqBT,UAAUC,cAAAA;;CAG9C,MAAcQ,qBACVT,UACAC,eACa;AAOb,SAJsBS,MAFS,KAAKjC,WAAWkC,WAAW,EAAErB,WAAWU,UAAS,CAAA,EAEzCa,QAClCP,UAAU,CAACL,cAAca,SAASR,MAAMtB,KAAI,CAG3C4B,CAAcR,OAAO,OAAOC,MAAMC,UAAAA;AACpC,SAAMD;AACN,SAAM,KAAKU,kBAAkBT,MAAAA;KAC9BC,QAAQC,SAAO,CAAA;;CAGtB,MAAcO,kBAAkBT,OAA8B;AAG1D,OAAIU,MAF+B,KAAKtC,2BAA2BiC,WAAW,EAAEM,WAAWX,MAAMR,IAAG,CAAA,EAE3EoB,WAAW,EAChC,OAAM,KAAKzC,WAAW0C,eAAeb,MAAAA;OAClC;GACH,MAAMc,WAAW,KAAK3C,WAAWgB,MAAMa,OAAO;IAC1ChB,WAAW;IACXC,QAAQ;IACRF,UAAU;IACd,CAAA;AACA,SAAM,KAAKZ,WAAWiB,WAAW0B,SAAAA"}