@authup/server-core 1.0.0-beta.59 → 1.0.0-beta.60

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 (409) hide show
  1. package/dist/adapters/database/domains/client/entity.d.ts.map +1 -1
  2. package/dist/adapters/database/domains/client/entity.mjs +58 -30
  3. package/dist/adapters/database/domains/client/entity.mjs.map +1 -1
  4. package/dist/adapters/database/domains/client-permission/entity.d.ts.map +1 -1
  5. package/dist/adapters/database/domains/client-permission/entity.mjs +48 -24
  6. package/dist/adapters/database/domains/client-permission/entity.mjs.map +1 -1
  7. package/dist/adapters/database/domains/client-role/entity.d.ts.map +1 -1
  8. package/dist/adapters/database/domains/client-role/entity.mjs +37 -17
  9. package/dist/adapters/database/domains/client-role/entity.mjs.map +1 -1
  10. package/dist/adapters/database/domains/client-scope/entity.d.ts.map +1 -1
  11. package/dist/adapters/database/domains/client-scope/entity.mjs +30 -14
  12. package/dist/adapters/database/domains/client-scope/entity.mjs.map +1 -1
  13. package/dist/adapters/database/domains/consent/entity.d.ts.map +1 -1
  14. package/dist/adapters/database/domains/consent/entity.mjs +34 -18
  15. package/dist/adapters/database/domains/consent/entity.mjs.map +1 -1
  16. package/dist/adapters/database/domains/event/entity.d.ts +1 -0
  17. package/dist/adapters/database/domains/event/entity.d.ts.map +1 -1
  18. package/dist/adapters/database/domains/event/entity.mjs +48 -23
  19. package/dist/adapters/database/domains/event/entity.mjs.map +1 -1
  20. package/dist/adapters/database/domains/identity-provider/entity.d.ts.map +1 -1
  21. package/dist/adapters/database/domains/identity-provider/entity.mjs +43 -23
  22. package/dist/adapters/database/domains/identity-provider/entity.mjs.map +1 -1
  23. package/dist/adapters/database/domains/identity-provider-account/entity.d.ts.map +1 -1
  24. package/dist/adapters/database/domains/identity-provider-account/entity.mjs +50 -22
  25. package/dist/adapters/database/domains/identity-provider-account/entity.mjs.map +1 -1
  26. package/dist/adapters/database/domains/identity-provider-attribute/entity.d.ts.map +1 -1
  27. package/dist/adapters/database/domains/identity-provider-attribute/entity.mjs +14 -6
  28. package/dist/adapters/database/domains/identity-provider-attribute/entity.mjs.map +1 -1
  29. package/dist/adapters/database/domains/identity-provider-attribute-mapping/entity.d.ts.map +1 -1
  30. package/dist/adapters/database/domains/identity-provider-attribute-mapping/entity.mjs +5 -1
  31. package/dist/adapters/database/domains/identity-provider-attribute-mapping/entity.mjs.map +1 -1
  32. package/dist/adapters/database/domains/identity-provider-permission-mapping/entity.d.ts.map +1 -1
  33. package/dist/adapters/database/domains/identity-provider-permission-mapping/entity.mjs +18 -6
  34. package/dist/adapters/database/domains/identity-provider-permission-mapping/entity.mjs.map +1 -1
  35. package/dist/adapters/database/domains/identity-provider-role-mapping/entity.d.ts.map +1 -1
  36. package/dist/adapters/database/domains/identity-provider-role-mapping/entity.mjs +34 -14
  37. package/dist/adapters/database/domains/identity-provider-role-mapping/entity.mjs.map +1 -1
  38. package/dist/adapters/database/domains/key/entity.d.ts.map +1 -1
  39. package/dist/adapters/database/domains/key/entity.mjs +35 -19
  40. package/dist/adapters/database/domains/key/entity.mjs.map +1 -1
  41. package/dist/adapters/database/domains/permission/entity.d.ts.map +1 -1
  42. package/dist/adapters/database/domains/permission/entity.mjs +35 -19
  43. package/dist/adapters/database/domains/permission/entity.mjs.map +1 -1
  44. package/dist/adapters/database/domains/permission-policy/entity.d.ts.map +1 -1
  45. package/dist/adapters/database/domains/permission-policy/entity.mjs +37 -17
  46. package/dist/adapters/database/domains/permission-policy/entity.mjs.map +1 -1
  47. package/dist/adapters/database/domains/policy/entity.d.ts.map +1 -1
  48. package/dist/adapters/database/domains/policy/entity.mjs +51 -27
  49. package/dist/adapters/database/domains/policy/entity.mjs.map +1 -1
  50. package/dist/adapters/database/domains/policy-attribute/entity.d.ts.map +1 -1
  51. package/dist/adapters/database/domains/policy-attribute/entity.mjs +14 -6
  52. package/dist/adapters/database/domains/policy-attribute/entity.mjs.map +1 -1
  53. package/dist/adapters/database/domains/realm/entity.d.ts.map +1 -1
  54. package/dist/adapters/database/domains/realm/entity.mjs +36 -20
  55. package/dist/adapters/database/domains/realm/entity.mjs.map +1 -1
  56. package/dist/adapters/database/domains/role/entity.d.ts.map +1 -1
  57. package/dist/adapters/database/domains/role/entity.mjs +44 -24
  58. package/dist/adapters/database/domains/role/entity.mjs.map +1 -1
  59. package/dist/adapters/database/domains/role-attribute/entity.d.ts.map +1 -1
  60. package/dist/adapters/database/domains/role-attribute/entity.mjs +30 -14
  61. package/dist/adapters/database/domains/role-attribute/entity.mjs.map +1 -1
  62. package/dist/adapters/database/domains/role-permission/entity.d.ts.map +1 -1
  63. package/dist/adapters/database/domains/role-permission/entity.mjs +45 -21
  64. package/dist/adapters/database/domains/role-permission/entity.mjs.map +1 -1
  65. package/dist/adapters/database/domains/scope/entity.d.ts.map +1 -1
  66. package/dist/adapters/database/domains/scope/entity.mjs +35 -19
  67. package/dist/adapters/database/domains/scope/entity.mjs.map +1 -1
  68. package/dist/adapters/database/domains/session/entity.d.ts.map +1 -1
  69. package/dist/adapters/database/domains/session/entity.mjs +63 -31
  70. package/dist/adapters/database/domains/session/entity.mjs.map +1 -1
  71. package/dist/adapters/database/domains/session-token/entity.d.ts +4 -1
  72. package/dist/adapters/database/domains/session-token/entity.d.ts.map +1 -1
  73. package/dist/adapters/database/domains/session-token/entity.mjs +40 -11
  74. package/dist/adapters/database/domains/session-token/entity.mjs.map +1 -1
  75. package/dist/adapters/database/domains/trust-anchor/entity.d.ts.map +1 -1
  76. package/dist/adapters/database/domains/trust-anchor/entity.mjs +25 -13
  77. package/dist/adapters/database/domains/trust-anchor/entity.mjs.map +1 -1
  78. package/dist/adapters/database/domains/user/entity.d.ts.map +1 -1
  79. package/dist/adapters/database/domains/user/entity.mjs +58 -34
  80. package/dist/adapters/database/domains/user/entity.mjs.map +1 -1
  81. package/dist/adapters/database/domains/user-attribute/entity.d.ts.map +1 -1
  82. package/dist/adapters/database/domains/user-attribute/entity.mjs +27 -11
  83. package/dist/adapters/database/domains/user-attribute/entity.mjs.map +1 -1
  84. package/dist/adapters/database/domains/user-authenticator/entity.d.ts.map +1 -1
  85. package/dist/adapters/database/domains/user-authenticator/entity.mjs +43 -23
  86. package/dist/adapters/database/domains/user-authenticator/entity.mjs.map +1 -1
  87. package/dist/adapters/database/domains/user-permission/entity.d.ts.map +1 -1
  88. package/dist/adapters/database/domains/user-permission/entity.mjs +45 -21
  89. package/dist/adapters/database/domains/user-permission/entity.mjs.map +1 -1
  90. package/dist/adapters/database/domains/user-role/entity.d.ts.map +1 -1
  91. package/dist/adapters/database/domains/user-role/entity.mjs +37 -17
  92. package/dist/adapters/database/domains/user-role/entity.mjs.map +1 -1
  93. package/dist/adapters/database/errors/driver.d.ts +9 -0
  94. package/dist/adapters/database/errors/driver.d.ts.map +1 -1
  95. package/dist/adapters/database/errors/driver.mjs +20 -1
  96. package/dist/adapters/database/errors/driver.mjs.map +1 -1
  97. package/dist/adapters/database/errors/index.mjs +2 -2
  98. package/dist/adapters/database/helpers/index.mjs +2 -2
  99. package/dist/adapters/database/helpers/is-supported.d.ts +7 -0
  100. package/dist/adapters/database/helpers/is-supported.d.ts.map +1 -1
  101. package/dist/adapters/database/helpers/is-supported.mjs +9 -1
  102. package/dist/adapters/database/helpers/is-supported.mjs.map +1 -1
  103. package/dist/adapters/database/index.mjs +3 -3
  104. package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.d.ts +66 -0
  105. package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.d.ts.map +1 -0
  106. package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.mjs +181 -0
  107. package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.mjs.map +1 -0
  108. package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.d.ts +44 -0
  109. package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.d.ts.map +1 -0
  110. package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.mjs +1294 -0
  111. package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.mjs.map +1 -0
  112. package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.d.ts +43 -0
  113. package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.d.ts.map +1 -0
  114. package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.mjs +120 -0
  115. package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.mjs.map +1 -0
  116. package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.d.ts +44 -0
  117. package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.d.ts.map +1 -0
  118. package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.mjs +987 -0
  119. package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.mjs.map +1 -0
  120. package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +14 -2
  121. package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
  122. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +85 -19
  123. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
  124. package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts +4 -1
  125. package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
  126. package/dist/adapters/http/controllers/entities/identity-provider-account/index.d.ts.map +1 -0
  127. package/dist/adapters/http/controllers/entities/identity-provider-account/index.mjs +5 -0
  128. package/dist/adapters/http/controllers/entities/identity-provider-account/module.d.ts +15 -0
  129. package/dist/adapters/http/controllers/entities/identity-provider-account/module.d.ts.map +1 -0
  130. package/dist/adapters/http/controllers/entities/identity-provider-account/module.mjs +94 -0
  131. package/dist/adapters/http/controllers/entities/identity-provider-account/module.mjs.map +1 -0
  132. package/dist/adapters/http/controllers/entities/index.d.ts +2 -0
  133. package/dist/adapters/http/controllers/entities/index.d.ts.map +1 -1
  134. package/dist/adapters/http/controllers/entities/index.mjs +5 -1
  135. package/dist/adapters/http/controllers/entities/session-token/index.d.ts +2 -0
  136. package/dist/adapters/http/controllers/entities/session-token/index.d.ts.map +1 -0
  137. package/dist/adapters/http/controllers/entities/session-token/index.mjs +5 -0
  138. package/dist/adapters/http/controllers/entities/session-token/module.d.ts +23 -0
  139. package/dist/adapters/http/controllers/entities/session-token/module.d.ts.map +1 -0
  140. package/dist/adapters/http/controllers/entities/session-token/module.mjs +112 -0
  141. package/dist/adapters/http/controllers/entities/session-token/module.mjs.map +1 -0
  142. package/dist/adapters/http/controllers/index.mjs +3 -1
  143. package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.d.ts.map +1 -1
  144. package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.mjs +1 -0
  145. package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.mjs.map +1 -1
  146. package/dist/adapters/http/index.mjs +3 -1
  147. package/dist/adapters/http/middleware/built-in/error.d.ts.map +1 -1
  148. package/dist/adapters/http/middleware/built-in/error.mjs +4 -3
  149. package/dist/adapters/http/middleware/built-in/error.mjs.map +1 -1
  150. package/dist/adapters/http/request/event-context.d.ts.map +1 -1
  151. package/dist/adapters/http/request/event-context.mjs +2 -0
  152. package/dist/adapters/http/request/event-context.mjs.map +1 -1
  153. package/dist/app/index.mjs +2 -2
  154. package/dist/app/modules/database/index.mjs +2 -1
  155. package/dist/app/modules/database/repositories/identity-provider-account/index.d.ts +2 -0
  156. package/dist/app/modules/database/repositories/identity-provider-account/index.d.ts.map +1 -0
  157. package/dist/app/modules/database/repositories/identity-provider-account/index.mjs +5 -0
  158. package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts +18 -0
  159. package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts.map +1 -0
  160. package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs +69 -0
  161. package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs.map +1 -0
  162. package/dist/app/modules/database/repositories/index.d.ts +1 -0
  163. package/dist/app/modules/database/repositories/index.d.ts.map +1 -1
  164. package/dist/app/modules/database/repositories/index.mjs +3 -1
  165. package/dist/app/modules/database/repositories/key/repository.d.ts +23 -0
  166. package/dist/app/modules/database/repositories/key/repository.d.ts.map +1 -1
  167. package/dist/app/modules/database/repositories/key/repository.mjs +39 -3
  168. package/dist/app/modules/database/repositories/key/repository.mjs.map +1 -1
  169. package/dist/app/modules/database/repositories/schema-validation.d.ts +14 -6
  170. package/dist/app/modules/database/repositories/schema-validation.d.ts.map +1 -1
  171. package/dist/app/modules/database/repositories/schema-validation.mjs +18 -6
  172. package/dist/app/modules/database/repositories/schema-validation.mjs.map +1 -1
  173. package/dist/app/modules/http/modules/controller.d.ts +3 -1
  174. package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
  175. package/dist/app/modules/http/modules/controller.mjs +37 -1
  176. package/dist/app/modules/http/modules/controller.mjs.map +1 -1
  177. package/dist/app/modules/identity/index.mjs +1 -2
  178. package/dist/app/modules/identity/module.d.ts.map +1 -1
  179. package/dist/app/modules/identity/module.mjs +2 -2
  180. package/dist/app/modules/identity/module.mjs.map +1 -1
  181. package/dist/app/modules/identity/repositories/index.mjs +1 -2
  182. package/dist/app/modules/identity/repositories/provider/index.d.ts +0 -1
  183. package/dist/app/modules/identity/repositories/provider/index.d.ts.map +1 -1
  184. package/dist/app/modules/identity/repositories/provider/index.mjs +1 -3
  185. package/dist/app/modules/index.mjs +2 -2
  186. package/dist/app/modules/logger/module.d.ts.map +1 -1
  187. package/dist/app/modules/logger/module.mjs +1 -0
  188. package/dist/app/modules/logger/module.mjs.map +1 -1
  189. package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts +25 -1
  190. package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts.map +1 -1
  191. package/dist/app/modules/oauth2/repositories/session-token/repository.mjs +70 -1
  192. package/dist/app/modules/oauth2/repositories/session-token/repository.mjs.map +1 -1
  193. package/dist/app/modules/provisioning/module.d.ts.map +1 -1
  194. package/dist/app/modules/provisioning/module.mjs +3 -1
  195. package/dist/app/modules/provisioning/module.mjs.map +1 -1
  196. package/dist/app/modules/provisioning/sources/default/module.d.ts.map +1 -1
  197. package/dist/app/modules/provisioning/sources/default/module.mjs +1 -0
  198. package/dist/app/modules/provisioning/sources/default/module.mjs.map +1 -1
  199. package/dist/core/entities/client/schema.d.ts.map +1 -1
  200. package/dist/core/entities/client/schema.mjs +29 -10
  201. package/dist/core/entities/client/schema.mjs.map +1 -1
  202. package/dist/core/entities/client-permission/schema.d.ts.map +1 -1
  203. package/dist/core/entities/client-permission/schema.mjs +29 -6
  204. package/dist/core/entities/client-permission/schema.mjs.map +1 -1
  205. package/dist/core/entities/client-role/schema.d.ts.map +1 -1
  206. package/dist/core/entities/client-role/schema.mjs +27 -6
  207. package/dist/core/entities/client-role/schema.mjs.map +1 -1
  208. package/dist/core/entities/client-scope/schema.d.ts.map +1 -1
  209. package/dist/core/entities/client-scope/schema.mjs +19 -5
  210. package/dist/core/entities/client-scope/schema.mjs.map +1 -1
  211. package/dist/core/entities/consent/schema.d.ts.map +1 -1
  212. package/dist/core/entities/consent/schema.mjs +28 -6
  213. package/dist/core/entities/consent/schema.mjs.map +1 -1
  214. package/dist/core/entities/event/entity-event-handler.d.ts.map +1 -1
  215. package/dist/core/entities/event/entity-event-handler.mjs +2 -0
  216. package/dist/core/entities/event/entity-event-handler.mjs.map +1 -1
  217. package/dist/core/entities/event/sanitize.d.ts.map +1 -1
  218. package/dist/core/entities/event/sanitize.mjs +7 -4
  219. package/dist/core/entities/event/sanitize.mjs.map +1 -1
  220. package/dist/core/entities/event/schema.d.ts.map +1 -1
  221. package/dist/core/entities/event/schema.mjs +45 -16
  222. package/dist/core/entities/event/schema.mjs.map +1 -1
  223. package/dist/core/entities/event/service.d.ts.map +1 -1
  224. package/dist/core/entities/event/service.mjs +2 -0
  225. package/dist/core/entities/event/service.mjs.map +1 -1
  226. package/dist/core/entities/event/types.d.ts +2 -0
  227. package/dist/core/entities/event/types.d.ts.map +1 -1
  228. package/dist/core/entities/identity-provider/schema.d.ts.map +1 -1
  229. package/dist/core/entities/identity-provider/schema.mjs +29 -11
  230. package/dist/core/entities/identity-provider/schema.mjs.map +1 -1
  231. package/dist/core/entities/identity-provider-account/error.d.ts +7 -0
  232. package/dist/core/entities/identity-provider-account/error.d.ts.map +1 -0
  233. package/dist/core/entities/identity-provider-account/error.mjs +24 -0
  234. package/dist/core/entities/identity-provider-account/error.mjs.map +1 -0
  235. package/dist/core/entities/identity-provider-account/index.d.ts +5 -0
  236. package/dist/core/entities/identity-provider-account/index.d.ts.map +1 -0
  237. package/dist/core/entities/identity-provider-account/index.mjs +8 -0
  238. package/dist/core/entities/identity-provider-account/schema.d.ts +3 -0
  239. package/dist/core/entities/identity-provider-account/schema.d.ts.map +1 -0
  240. package/dist/core/entities/identity-provider-account/schema.mjs +52 -0
  241. package/dist/core/entities/identity-provider-account/schema.mjs.map +1 -0
  242. package/dist/core/entities/identity-provider-account/service.d.ts +24 -0
  243. package/dist/core/entities/identity-provider-account/service.d.ts.map +1 -0
  244. package/dist/core/entities/identity-provider-account/service.mjs +129 -0
  245. package/dist/core/entities/identity-provider-account/service.mjs.map +1 -0
  246. package/dist/core/entities/identity-provider-account/types.d.ts +69 -0
  247. package/dist/core/entities/identity-provider-account/types.d.ts.map +1 -0
  248. package/dist/core/entities/identity-provider-account/types.mjs +17 -0
  249. package/dist/core/entities/identity-provider-account/types.mjs.map +1 -0
  250. package/dist/core/entities/identity-provider-role-mapping/schema.d.ts.map +1 -1
  251. package/dist/core/entities/identity-provider-role-mapping/schema.mjs +27 -6
  252. package/dist/core/entities/identity-provider-role-mapping/schema.mjs.map +1 -1
  253. package/dist/core/entities/index.d.ts +2 -0
  254. package/dist/core/entities/index.d.ts.map +1 -1
  255. package/dist/core/entities/index.mjs +9 -1
  256. package/dist/core/entities/key/schema.d.ts.map +1 -1
  257. package/dist/core/entities/key/schema.mjs +39 -17
  258. package/dist/core/entities/key/schema.mjs.map +1 -1
  259. package/dist/core/entities/key/service.d.ts.map +1 -1
  260. package/dist/core/entities/key/service.mjs +1 -0
  261. package/dist/core/entities/key/service.mjs.map +1 -1
  262. package/dist/core/entities/permission/schema.d.ts.map +1 -1
  263. package/dist/core/entities/permission/schema.mjs +34 -13
  264. package/dist/core/entities/permission/schema.mjs.map +1 -1
  265. package/dist/core/entities/permission-policy/schema.d.ts.map +1 -1
  266. package/dist/core/entities/permission-policy/schema.mjs +27 -6
  267. package/dist/core/entities/permission-policy/schema.mjs.map +1 -1
  268. package/dist/core/entities/policy/schema.d.ts.map +1 -1
  269. package/dist/core/entities/policy/schema.mjs +31 -12
  270. package/dist/core/entities/policy/schema.mjs.map +1 -1
  271. package/dist/core/entities/realm/schema.d.ts.map +1 -1
  272. package/dist/core/entities/realm/schema.mjs +26 -12
  273. package/dist/core/entities/realm/schema.mjs.map +1 -1
  274. package/dist/core/entities/role/schema.d.ts.map +1 -1
  275. package/dist/core/entities/role/schema.mjs +36 -14
  276. package/dist/core/entities/role/schema.mjs.map +1 -1
  277. package/dist/core/entities/role-attribute/schema.d.ts.map +1 -1
  278. package/dist/core/entities/role-attribute/schema.mjs +28 -14
  279. package/dist/core/entities/role-attribute/schema.mjs.map +1 -1
  280. package/dist/core/entities/role-permission/schema.d.ts.map +1 -1
  281. package/dist/core/entities/role-permission/schema.mjs +29 -6
  282. package/dist/core/entities/role-permission/schema.mjs.map +1 -1
  283. package/dist/core/entities/scope/schema.d.ts.map +1 -1
  284. package/dist/core/entities/scope/schema.mjs +28 -12
  285. package/dist/core/entities/scope/schema.mjs.map +1 -1
  286. package/dist/core/entities/session/schema.d.ts.map +1 -1
  287. package/dist/core/entities/session/schema.mjs +41 -9
  288. package/dist/core/entities/session/schema.mjs.map +1 -1
  289. package/dist/core/entities/session-token/index.d.ts +4 -0
  290. package/dist/core/entities/session-token/index.d.ts.map +1 -0
  291. package/dist/core/entities/session-token/index.mjs +6 -0
  292. package/dist/core/entities/session-token/schema.d.ts +12 -0
  293. package/dist/core/entities/session-token/schema.d.ts.map +1 -0
  294. package/dist/core/entities/session-token/schema.mjs +66 -0
  295. package/dist/core/entities/session-token/schema.mjs.map +1 -0
  296. package/dist/core/entities/session-token/service.d.ts +70 -0
  297. package/dist/core/entities/session-token/service.d.ts.map +1 -0
  298. package/dist/core/entities/session-token/service.mjs +216 -0
  299. package/dist/core/entities/session-token/service.mjs.map +1 -0
  300. package/dist/core/entities/session-token/types.d.ts +37 -0
  301. package/dist/core/entities/session-token/types.d.ts.map +1 -0
  302. package/dist/core/entities/session-token/types.mjs +4 -0
  303. package/dist/core/entities/trust-anchor/schema.d.ts.map +1 -1
  304. package/dist/core/entities/trust-anchor/schema.mjs +27 -13
  305. package/dist/core/entities/trust-anchor/schema.mjs.map +1 -1
  306. package/dist/core/entities/trust-anchor/service.d.ts.map +1 -1
  307. package/dist/core/entities/trust-anchor/service.mjs +1 -0
  308. package/dist/core/entities/trust-anchor/service.mjs.map +1 -1
  309. package/dist/core/entities/user/schema.d.ts.map +1 -1
  310. package/dist/core/entities/user/schema.mjs +29 -12
  311. package/dist/core/entities/user/schema.mjs.map +1 -1
  312. package/dist/core/entities/user-attribute/schema.d.ts.map +1 -1
  313. package/dist/core/entities/user-attribute/schema.mjs +28 -14
  314. package/dist/core/entities/user-attribute/schema.mjs.map +1 -1
  315. package/dist/core/entities/user-authenticator/schema.d.ts.map +1 -1
  316. package/dist/core/entities/user-authenticator/schema.mjs +29 -12
  317. package/dist/core/entities/user-authenticator/schema.mjs.map +1 -1
  318. package/dist/core/entities/user-authenticator/service.d.ts +2 -1
  319. package/dist/core/entities/user-authenticator/service.d.ts.map +1 -1
  320. package/dist/core/entities/user-authenticator/service.mjs +5 -0
  321. package/dist/core/entities/user-authenticator/service.mjs.map +1 -1
  322. package/dist/core/entities/user-authenticator/types.d.ts +7 -1
  323. package/dist/core/entities/user-authenticator/types.d.ts.map +1 -1
  324. package/dist/core/entities/user-authenticator/types.mjs.map +1 -1
  325. package/dist/core/entities/user-permission/schema.d.ts.map +1 -1
  326. package/dist/core/entities/user-permission/schema.mjs +29 -6
  327. package/dist/core/entities/user-permission/schema.mjs.map +1 -1
  328. package/dist/core/entities/user-role/schema.d.ts.map +1 -1
  329. package/dist/core/entities/user-role/schema.mjs +27 -6
  330. package/dist/core/entities/user-role/schema.mjs.map +1 -1
  331. package/dist/core/identity/index.mjs +2 -1
  332. package/dist/core/identity/provider/account/error.d.ts +7 -0
  333. package/dist/core/identity/provider/account/error.d.ts.map +1 -0
  334. package/dist/core/identity/provider/account/error.mjs +24 -0
  335. package/dist/core/identity/provider/account/error.mjs.map +1 -0
  336. package/dist/core/identity/provider/account/index.d.ts +1 -0
  337. package/dist/core/identity/provider/account/index.d.ts.map +1 -1
  338. package/dist/core/identity/provider/account/index.mjs +2 -1
  339. package/dist/core/identity/provider/account/module.d.ts +2 -0
  340. package/dist/core/identity/provider/account/module.d.ts.map +1 -1
  341. package/dist/core/identity/provider/account/module.mjs +30 -0
  342. package/dist/core/identity/provider/account/module.mjs.map +1 -1
  343. package/dist/core/identity/provider/account/types.d.ts +12 -10
  344. package/dist/core/identity/provider/account/types.d.ts.map +1 -1
  345. package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts +1 -0
  346. package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
  347. package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +5 -1
  348. package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
  349. package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts +7 -0
  350. package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts.map +1 -1
  351. package/dist/core/identity/provider/index.mjs +2 -1
  352. package/dist/core/index.mjs +10 -2
  353. package/dist/core/oauth2/authorization/module.d.ts.map +1 -1
  354. package/dist/core/oauth2/authorization/module.mjs +2 -0
  355. package/dist/core/oauth2/authorization/module.mjs.map +1 -1
  356. package/dist/core/oauth2/authorization/state/types.d.ts +11 -0
  357. package/dist/core/oauth2/authorization/state/types.d.ts.map +1 -1
  358. package/dist/core/oauth2/end-session/service.mjs +2 -2
  359. package/dist/core/oauth2/end-session/service.mjs.map +1 -1
  360. package/dist/core/oauth2/grant-types/authorize.d.ts.map +1 -1
  361. package/dist/core/oauth2/grant-types/authorize.mjs +1 -5
  362. package/dist/core/oauth2/grant-types/authorize.mjs.map +1 -1
  363. package/dist/core/oauth2/grant-types/password.mjs +2 -5
  364. package/dist/core/oauth2/grant-types/password.mjs.map +1 -1
  365. package/dist/core/oauth2/grant-types/refresh-token.d.ts.map +1 -1
  366. package/dist/core/oauth2/grant-types/refresh-token.mjs +37 -24
  367. package/dist/core/oauth2/grant-types/refresh-token.mjs.map +1 -1
  368. package/dist/core/oauth2/index.mjs +3 -1
  369. package/dist/core/oauth2/mfa-login/module.d.ts.map +1 -1
  370. package/dist/core/oauth2/mfa-login/module.mjs +4 -7
  371. package/dist/core/oauth2/mfa-login/module.mjs.map +1 -1
  372. package/dist/core/oauth2/session-token/error.d.ts +36 -0
  373. package/dist/core/oauth2/session-token/error.d.ts.map +1 -0
  374. package/dist/core/oauth2/session-token/error.mjs +49 -0
  375. package/dist/core/oauth2/session-token/error.mjs.map +1 -0
  376. package/dist/core/oauth2/session-token/index.d.ts +1 -0
  377. package/dist/core/oauth2/session-token/index.d.ts.map +1 -1
  378. package/dist/core/oauth2/session-token/index.mjs +2 -1
  379. package/dist/core/oauth2/session-token/types.d.ts +40 -0
  380. package/dist/core/oauth2/session-token/types.d.ts.map +1 -1
  381. package/dist/core/oauth2/token/issuer/access/module.d.ts.map +1 -1
  382. package/dist/core/oauth2/token/issuer/access/module.mjs +1 -0
  383. package/dist/core/oauth2/token/issuer/access/module.mjs.map +1 -1
  384. package/dist/core/oauth2/token/issuer/base.d.ts +1 -1
  385. package/dist/core/oauth2/token/issuer/base.d.ts.map +1 -1
  386. package/dist/core/oauth2/token/issuer/base.mjs.map +1 -1
  387. package/dist/core/oauth2/token/issuer/refresh/module.d.ts.map +1 -1
  388. package/dist/core/oauth2/token/issuer/refresh/module.mjs +1 -0
  389. package/dist/core/oauth2/token/issuer/refresh/module.mjs.map +1 -1
  390. package/dist/core/query/index.mjs +2 -2
  391. package/dist/core/query/module.d.ts +19 -9
  392. package/dist/core/query/module.d.ts.map +1 -1
  393. package/dist/core/query/module.mjs +22 -10
  394. package/dist/core/query/module.mjs.map +1 -1
  395. package/dist/index.mjs +6 -4
  396. package/dist/swagger.json +869 -140
  397. package/dist/utils/error.d.ts +20 -3
  398. package/dist/utils/error.d.ts.map +1 -1
  399. package/dist/utils/error.mjs +102 -5
  400. package/dist/utils/error.mjs.map +1 -1
  401. package/dist/utils/index.mjs +2 -2
  402. package/package.json +23 -21
  403. package/dist/app/modules/identity/repositories/provider/account/index.d.ts.map +0 -1
  404. package/dist/app/modules/identity/repositories/provider/account/index.mjs +0 -5
  405. package/dist/app/modules/identity/repositories/provider/account/module.d.ts +0 -10
  406. package/dist/app/modules/identity/repositories/provider/account/module.d.ts.map +0 -1
  407. package/dist/app/modules/identity/repositories/provider/account/module.mjs +0 -28
  408. package/dist/app/modules/identity/repositories/provider/account/module.mjs.map +0 -1
  409. /package/dist/{app/modules/identity/repositories/provider/account → adapters/http/controllers/entities/identity-provider-account}/index.d.ts +0 -0
@@ -8,6 +8,7 @@ import { ClientRoleRepositoryAdapter } from "./repositories/client-role/reposito
8
8
  import { ClientScopeRepositoryAdapter } from "./repositories/client-scope/repository.mjs";
9
9
  import { EventRepositoryAdapter } from "./repositories/event/repository.mjs";
10
10
  import { IdentityProviderRepositoryAdapter } from "./repositories/identity-provider/repository.mjs";
11
+ import { IdentityProviderAccountRepositoryAdapter } from "./repositories/identity-provider-account/repository.mjs";
11
12
  import { KeyRepositoryAdapter } from "./repositories/key/repository.mjs";
12
13
  import { PermissionRepositoryAdapter } from "./repositories/permission/repository.mjs";
13
14
  import { PermissionPolicyRepositoryAdapter } from "./repositories/permission-policy/repository.mjs";
@@ -27,4 +28,4 @@ import { IdentityProviderRoleMappingRepositoryAdapter } from "./repositories/ide
27
28
  import "./repositories/index.mjs";
28
29
  import { DatabaseInjectionKey } from "./constants.mjs";
29
30
  import { DatabaseModule } from "./module.mjs";
30
- export { ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, DatabaseInjectionKey, DatabaseModule, EventRepositoryAdapter, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, ScopeRepositoryAdapter, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter };
31
+ export { ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, DatabaseInjectionKey, DatabaseModule, EventRepositoryAdapter, IdentityProviderAccountRepositoryAdapter, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, ScopeRepositoryAdapter, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter };
@@ -0,0 +1,2 @@
1
+ export * from './repository.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/identity-provider-account/index.ts"],"names":[],"mappings":"AAOA,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { IdentityProviderAccountRepositoryAdapter } from "./repository.mjs";
5
+ export { IdentityProviderAccountRepositoryAdapter };
@@ -0,0 +1,18 @@
1
+ import type { IdentityProviderAccount } from '@authup/core-kit';
2
+ import type { IQuery } from '@rapiq/core';
3
+ import type { EntityRepositoryFindManyResult } from '@authup/server-kit';
4
+ import type { DataSource, DeepPartial, Repository } from 'typeorm';
5
+ import { IdentityProviderAccountEntity } from '../../../../../adapters/database/domains/index.ts';
6
+ import type { IIdentityProviderAccountRepository, IdentityProviderAccountFindManyOptions, IdentityProviderIdentity } from '../../../../../core/index.ts';
7
+ export declare class IdentityProviderAccountRepositoryAdapter implements IIdentityProviderAccountRepository {
8
+ protected dataSource: DataSource;
9
+ protected repository: Repository<IdentityProviderAccountEntity>;
10
+ constructor(dataSource: DataSource);
11
+ findMany(query: IQuery, options?: IdentityProviderAccountFindManyOptions): Promise<EntityRepositoryFindManyResult<IdentityProviderAccount>>;
12
+ findOneById(id: string): Promise<IdentityProviderAccount | null>;
13
+ removeGuarded(entity: IdentityProviderAccount, userHasOtherLogin: boolean): Promise<boolean>;
14
+ findOneByProviderIdentity(identity: IdentityProviderIdentity): Promise<IdentityProviderAccount | null>;
15
+ save(entity: DeepPartial<IdentityProviderAccount>): Promise<IdentityProviderAccount>;
16
+ remove(entity: IdentityProviderAccount): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/identity-provider-account/repository.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EACR,UAAU,EACV,WAAW,EACX,UAAU,EACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAC;AAElG,OAAO,KAAK,EACR,kCAAkC,EAClC,sCAAsC,EACtC,wBAAwB,EAC3B,MAAM,8BAA8B,CAAC;AAEtC,qBAAa,wCAAyC,YAAW,kCAAkC;IAC/F,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC;IAEjC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,6BAA6B,CAAC,CAAC;gBAEpD,UAAU,EAAE,UAAU;IAK5B,QAAQ,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,sCAA2C,GACrD,OAAO,CAAC,8BAA8B,CAAC,uBAAuB,CAAC,CAAC;IAuC7D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAIhE,aAAa,CAAC,MAAM,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAsC5F,yBAAyB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAUtG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,uBAAuB,CAAC,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAIpF,MAAM,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/D"}
@@ -0,0 +1,69 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { isDatabaseTypeRowLockable } from "../../../../../adapters/database/helpers/is-supported.mjs";
5
+ import "../../../../../adapters/database/helpers/index.mjs";
6
+ import { IdentityProviderAccountEntity } from "../../../../../adapters/database/domains/identity-provider-account/entity.mjs";
7
+ import "../../../../../adapters/database/domains/index.mjs";
8
+ import { applyQuery, redactFieldConditions } from "../query.mjs";
9
+ //#region src/app/modules/database/repositories/identity-provider-account/repository.ts
10
+ var IdentityProviderAccountRepositoryAdapter = class {
11
+ dataSource;
12
+ repository;
13
+ constructor(dataSource) {
14
+ this.dataSource = dataSource;
15
+ this.repository = dataSource.getRepository(IdentityProviderAccountEntity);
16
+ }
17
+ async findMany(query, options = {}) {
18
+ const qb = this.repository.createQueryBuilder("identityProviderAccount");
19
+ const { pagination } = applyQuery(qb, query);
20
+ const existing = new Set(qb.expressionMap.selects.map((select) => select.selection));
21
+ const selections = ["userId", "userRealmId"].map((column) => `identityProviderAccount.${column}`).filter((selection) => !existing.has(selection));
22
+ if (selections.length > 0) qb.addSelect(selections);
23
+ if (options.userId) qb.andWhere("identityProviderAccount.userId = :ownerUserId", { ownerUserId: options.userId });
24
+ if (options.realmId) qb.andWhere("identityProviderAccount.userRealmId = :ownerRealmId", { ownerRealmId: options.realmId });
25
+ const [entities, total] = await qb.getManyAndCount();
26
+ return {
27
+ data: redactFieldConditions(query, entities),
28
+ meta: {
29
+ total,
30
+ ...pagination
31
+ }
32
+ };
33
+ }
34
+ async findOneById(id) {
35
+ return this.repository.findOneBy({ id });
36
+ }
37
+ async removeGuarded(entity, userHasOtherLogin) {
38
+ if (!isDatabaseTypeRowLockable(this.dataSource.options.type)) {
39
+ if (await this.repository.countBy({ userId: entity.userId }) <= 1 && !userHasOtherLogin) return false;
40
+ await this.repository.remove(entity);
41
+ return true;
42
+ }
43
+ return this.dataSource.transaction(async (manager) => {
44
+ const repository = manager.getRepository(IdentityProviderAccountEntity);
45
+ if ((await repository.createQueryBuilder("identityProviderAccount").select(["identityProviderAccount.id"]).where("identityProviderAccount.userId = :userId", { userId: entity.userId }).setLock("pessimistic_write").getMany()).length <= 1 && !userHasOtherLogin) return false;
46
+ await repository.remove(entity);
47
+ return true;
48
+ });
49
+ }
50
+ async findOneByProviderIdentity(identity) {
51
+ return this.repository.findOne({
52
+ where: {
53
+ providerUserId: identity.id,
54
+ providerId: identity.provider.id
55
+ },
56
+ relations: { user: true }
57
+ });
58
+ }
59
+ async save(entity) {
60
+ return this.repository.save(entity);
61
+ }
62
+ async remove(entity) {
63
+ await this.repository.remove(entity);
64
+ }
65
+ };
66
+ //#endregion
67
+ export { IdentityProviderAccountRepositoryAdapter };
68
+
69
+ //# sourceMappingURL=repository.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.mjs","names":["applyQuery","redactFieldConditions","IdentityProviderAccountEntity","isDatabaseTypeRowLockable","IdentityProviderAccountRepositoryAdapter","dataSource","repository","getRepository","findMany","query","options","qb","createQueryBuilder","pagination","existing","Set","expressionMap","selects","map","select","selection","selections","column","filter","has","length","addSelect","userId","andWhere","ownerUserId","realmId","ownerRealmId","entities","total","getManyAndCount","data","meta","findOneById","id","findOneBy","removeGuarded","entity","userHasOtherLogin","type","count","countBy","remove","transaction","manager","rows","where","setLock","getMany","findOneByProviderIdentity","identity","findOne","providerUserId","providerId","provider","relations","user","save"],"sources":["../../../../../../src/app/modules/database/repositories/identity-provider-account/repository.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 { IdentityProviderAccount } from '@authup/core-kit';\nimport type { IQuery } from '@rapiq/core';\nimport type { EntityRepositoryFindManyResult } from '@authup/server-kit';\nimport type {\n DataSource, \n DeepPartial, \n Repository,\n} from 'typeorm';\nimport { applyQuery, redactFieldConditions } from '../query.ts';\nimport { IdentityProviderAccountEntity } from '../../../../../adapters/database/domains/index.ts';\nimport { isDatabaseTypeRowLockable } from '../../../../../adapters/database/helpers/index.ts';\nimport type {\n IIdentityProviderAccountRepository,\n IdentityProviderAccountFindManyOptions,\n IdentityProviderIdentity,\n} from '../../../../../core/index.ts';\n\nexport class IdentityProviderAccountRepositoryAdapter implements IIdentityProviderAccountRepository {\n protected dataSource: DataSource;\n\n protected repository: Repository<IdentityProviderAccountEntity>;\n\n constructor(dataSource: DataSource) {\n this.dataSource = dataSource;\n this.repository = dataSource.getRepository(IdentityProviderAccountEntity);\n }\n\n async findMany(\n query: IQuery,\n options: IdentityProviderAccountFindManyOptions = {},\n ): Promise<EntityRepositoryFindManyResult<IdentityProviderAccount>> {\n const qb = this.repository.createQueryBuilder('identityProviderAccount');\n\n const { pagination } = applyQuery(qb, query);\n\n // plan-039 force-select: the per-row gate reads userId (ownership)\n // and userRealmId (realm reach). The shared applyRealmScopeSelect\n // pins a `realmId` column this entity does not have, so dedupe and\n // add the two columns the same way it would.\n const existing = new Set(qb.expressionMap.selects.map((select) => select.selection));\n const selections = ['userId', 'userRealmId']\n .map((column) => `identityProviderAccount.${column}`)\n .filter((selection) => !existing.has(selection));\n if (selections.length > 0) {\n qb.addSelect(selections);\n }\n\n if (options.userId) {\n // mandatory constraint — not overridable by a rapiq filter\n qb.andWhere('identityProviderAccount.userId = :ownerUserId', { ownerUserId: options.userId });\n }\n\n if (options.realmId) {\n // nested `/realms/:realmId/identity-provider-accounts` mount —\n // mandatory constraint, not overridable by a rapiq filter\n qb.andWhere('identityProviderAccount.userRealmId = :ownerRealmId', { ownerRealmId: options.realmId });\n }\n\n const [entities, total] = await qb.getManyAndCount();\n\n return {\n data: redactFieldConditions(query, entities),\n meta: {\n total,\n ...pagination,\n },\n };\n }\n\n async findOneById(id: string): Promise<IdentityProviderAccount | null> {\n return this.repository.findOneBy({ id });\n }\n\n async removeGuarded(entity: IdentityProviderAccount, userHasOtherLogin: boolean): Promise<boolean> {\n if (!isDatabaseTypeRowLockable(this.dataSource.options.type)) {\n // better-sqlite3: a single synchronous writer, so the\n // count/delete race cannot manifest and no transaction is\n // needed. Deliberately NOT wrapped in one — a held write\n // transaction would contend the database lock (single-file\n // driver) without buying any atomicity here. Plain\n // count-then-remove, exactly as the un-guarded path did.\n const count = await this.repository.countBy({ userId: entity.userId });\n if (count <= 1 && !userHasOtherLogin) {\n return false;\n }\n\n await this.repository.remove(entity as IdentityProviderAccountEntity);\n return true;\n }\n\n // mysql / postgres: real concurrency. Lock the user's account rows,\n // count, and delete in one transaction so two concurrent unlinks for\n // the same user cannot both read > 1 and both delete.\n return this.dataSource.transaction(async (manager) => {\n const repository = manager.getRepository(IdentityProviderAccountEntity);\n\n const rows = await repository.createQueryBuilder('identityProviderAccount')\n .select(['identityProviderAccount.id'])\n .where('identityProviderAccount.userId = :userId', { userId: entity.userId })\n .setLock('pessimistic_write')\n .getMany();\n\n if (rows.length <= 1 && !userHasOtherLogin) {\n return false;\n }\n\n await repository.remove(entity as IdentityProviderAccountEntity);\n return true;\n });\n }\n\n async findOneByProviderIdentity(identity: IdentityProviderIdentity): Promise<IdentityProviderAccount | null> {\n return this.repository.findOne({\n where: {\n providerUserId: identity.id,\n providerId: identity.provider.id,\n },\n relations: { user: true },\n });\n }\n\n async save(entity: DeepPartial<IdentityProviderAccount>): Promise<IdentityProviderAccount> {\n return this.repository.save(entity);\n }\n\n async remove(entity: IdentityProviderAccount): Promise<void> {\n await this.repository.remove(entity as IdentityProviderAccountEntity);\n }\n}\n"],"mappings":";;;;;;;;;AAwBA,IAAaI,2CAAb,MAAaA;CACCC;CAEAC;CAEV,YAAYD,YAAwB;EAChC,KAAKA,aAAaA;EAClB,KAAKC,aAAaD,WAAWE,cAAcL,6BAAAA;CAC/C;CAEA,MAAMM,SACFC,OACAC,UAAkD,CAAC,GACa;EAChE,MAAMC,KAAK,KAAKL,WAAWM,mBAAmB,yBAAA;EAE9C,MAAM,EAAEC,eAAeb,WAAWW,IAAIF,KAAAA;EAMtC,MAAMK,WAAW,IAAIC,IAAIJ,GAAGK,cAAcC,QAAQC,KAAKC,WAAWA,OAAOC,SAAS,CAAA;EAClF,MAAMC,aAAa,CAAC,UAAU,aAAc,CAAA,CACvCH,KAAKI,WAAW,2BAA2BA,QAAQ,CAAA,CACnDC,QAAQH,cAAc,CAACN,SAASU,IAAIJ,SAAAA,CAAAA;EACzC,IAAIC,WAAWI,SAAS,GACpBd,GAAGe,UAAUL,UAAAA;EAGjB,IAAIX,QAAQiB,QAERhB,GAAGiB,SAAS,iDAAiD,EAAEC,aAAanB,QAAQiB,OAAO,CAAA;EAG/F,IAAIjB,QAAQoB,SAGRnB,GAAGiB,SAAS,uDAAuD,EAAEG,cAAcrB,QAAQoB,QAAQ,CAAA;EAGvG,MAAM,CAACE,UAAUC,SAAS,MAAMtB,GAAGuB,gBAAe;EAElD,OAAO;GACHC,MAAMlC,sBAAsBQ,OAAOuB,QAAAA;GACnCI,MAAM;IACFH;IACA,GAAGpB;GACP;EACJ;CACJ;CAEA,MAAMwB,YAAYC,IAAqD;EACnE,OAAO,KAAKhC,WAAWiC,UAAU,EAAED,GAAG,CAAA;CAC1C;CAEA,MAAME,cAAcC,QAAiCC,mBAA8C;EAC/F,IAAI,CAACvC,0BAA0B,KAAKE,WAAWK,QAAQiC,IAAI,GAAG;GAQ1D,IAAIC,MADgB,KAAKtC,WAAWuC,QAAQ,EAAElB,QAAQc,OAAOd,OAAO,CAAA,KACvD,KAAK,CAACe,mBACf,OAAO;GAGX,MAAM,KAAKpC,WAAWwC,OAAOL,MAAAA;GAC7B,OAAO;EACX;EAKA,OAAO,KAAKpC,WAAW0C,YAAY,OAAOC,YAAAA;GACtC,MAAM1C,aAAa0C,QAAQzC,cAAcL,6BAAAA;GAQzC,KAAI+C,MANe3C,WAAWM,mBAAmB,yBAAA,CAAA,CAC5CO,OAAO,CAAC,4BAA6B,CAAA,CAAA,CACrC+B,MAAM,4CAA4C,EAAEvB,QAAQc,OAAOd,OAAO,CAAA,CAAA,CAC1EwB,QAAQ,mBAAA,CAAA,CACRC,QAAO,EAAA,CAEH3B,UAAU,KAAK,CAACiB,mBACrB,OAAO;GAGX,MAAMpC,WAAWwC,OAAOL,MAAAA;GACxB,OAAO;EACX,CAAA;CACJ;CAEA,MAAMY,0BAA0BC,UAA6E;EACzG,OAAO,KAAKhD,WAAWiD,QAAQ;GAC3BL,OAAO;IACHM,gBAAgBF,SAAShB;IACzBmB,YAAYH,SAASI,SAASpB;GAClC;GACAqB,WAAW,EAAEC,MAAM,KAAK;EAC5B,CAAA;CACJ;CAEA,MAAMC,KAAKpB,QAAgF;EACvF,OAAO,KAAKnC,WAAWuD,KAAKpB,MAAAA;CAChC;CAEA,MAAMK,OAAOL,QAAgD;EACzD,MAAM,KAAKnC,WAAWwC,OAAOL,MAAAA;CACjC;AACJ"}
@@ -4,6 +4,7 @@ export * from './client-role/index.ts';
4
4
  export * from './client-scope/index.ts';
5
5
  export * from './event/index.ts';
6
6
  export * from './identity-provider/index.ts';
7
+ export * from './identity-provider-account/index.ts';
7
8
  export * from './key/index.ts';
8
9
  export * from './permission/index.ts';
9
10
  export * from './permission-policy/index.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/app/modules/database/repositories/index.ts"],"names":[],"mappings":"AAOA,cAAc,mBAAmB,CAAC;AAClC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2CAA2C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/app/modules/database/repositories/index.ts"],"names":[],"mappings":"AAOA,cAAc,mBAAmB,CAAC;AAClC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2CAA2C,CAAC"}
@@ -14,6 +14,8 @@ import { EventRepositoryAdapter } from "./event/repository.mjs";
14
14
  import "./event/index.mjs";
15
15
  import { IdentityProviderRepositoryAdapter } from "./identity-provider/repository.mjs";
16
16
  import "./identity-provider/index.mjs";
17
+ import { IdentityProviderAccountRepositoryAdapter } from "./identity-provider-account/repository.mjs";
18
+ import "./identity-provider-account/index.mjs";
17
19
  import { KeyRepositoryAdapter } from "./key/repository.mjs";
18
20
  import "./key/index.mjs";
19
21
  import { PermissionRepositoryAdapter } from "./permission/repository.mjs";
@@ -47,4 +49,4 @@ import { UserRoleRepositoryAdapter } from "./user-role/repository.mjs";
47
49
  import "./user-role/index.mjs";
48
50
  import { IdentityProviderRoleMappingRepositoryAdapter } from "./identity-provider-role-mapping/repository.mjs";
49
51
  import "./identity-provider-role-mapping/index.mjs";
50
- export { ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, EventRepositoryAdapter, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, ScopeRepositoryAdapter, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter };
52
+ export { ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, EventRepositoryAdapter, IdentityProviderAccountRepositoryAdapter, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, ScopeRepositoryAdapter, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter };
@@ -24,9 +24,32 @@ export declare class KeyRepositoryAdapter implements IKeyRepository, IKeyStore {
24
24
  protected secretsCipher: ISymmetricCipher | null;
25
25
  protected realmRepository: IRealmRepository;
26
26
  protected logger?: Logger;
27
+ /**
28
+ * In-flight mints keyed `<realmId>:<use>` — see {@link mintExclusive}.
29
+ */
30
+ protected mints: Map<string, Promise<Key>>;
27
31
  constructor(dataSource: DataSource, options?: KeyRepositoryAdapterOptions);
28
32
  protected get repository(): Repository<KeyEntity>;
33
+ protected findActiveKey(realmId: string, use: `${JWKUse}`): Promise<KeyEntity | null>;
29
34
  resolveOrCreate(realmId: string, use: `${JWKUse}`): Promise<Key>;
35
+ /**
36
+ * Minting is check-then-act (read, count, insert), and the callers are
37
+ * hot paths — the token signer resolves a signature key for EVERY
38
+ * issuance, the realm cipher an encryption key for every MFA seed — so
39
+ * a freshly created realm routinely takes several simultaneous calls
40
+ * and each one would insert its own key. Concurrent mints for one
41
+ * (realm, use) therefore share a single in-flight promise.
42
+ *
43
+ * The map is per adapter instance, and the store is a DI singleton, so
44
+ * it is scoped to one application: two applications in one process
45
+ * (the test suite) never share mint state. Separate PROCESSES can still
46
+ * race, which is why the duplicate stays tolerable rather than fatal —
47
+ * both keys are published in JWKS and verify, and `findActiveKey`
48
+ * orders deterministically, so a duplicate costs a redundant row, not
49
+ * a broken token.
50
+ */
51
+ protected mintExclusive(realmId: string, use: `${JWKUse}`): Promise<Key>;
52
+ protected mint(realmId: string, use: `${JWKUse}`): Promise<Key>;
30
53
  resolveById(id: string): Promise<Key | null>;
31
54
  protected createSignatureKey(repository: Repository<KeyEntity>, realmId: string): Promise<Key>;
32
55
  protected createEncryptionKey(repository: Repository<KeyEntity>, realmId: string): Promise<Key>;
@@ -1 +1 @@
1
- {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/key/repository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../../../../src/app/modules/database/repositories/key/repository.ts"],"names":[],"mappings":"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"}
@@ -31,6 +31,9 @@ import { validateEntityJoinColumns } from "typeorm-extension";
31
31
  secretsCipher;
32
32
  realmRepository;
33
33
  logger;
34
+ /**
35
+ * In-flight mints keyed `<realmId>:<use>` — see {@link mintExclusive}.
36
+ */ mints = /* @__PURE__ */ new Map();
34
37
  constructor(dataSource, options = {}) {
35
38
  this.dataSource = dataSource;
36
39
  this.secretsCipher = options.secretsCipher ?? null;
@@ -40,9 +43,8 @@ import { validateEntityJoinColumns } from "typeorm-extension";
40
43
  get repository() {
41
44
  return this.dataSource.getRepository(KeyEntity);
42
45
  }
43
- async resolveOrCreate(realmId, use) {
44
- const { repository } = this;
45
- const entity = await repository.findOne({
46
+ findActiveKey(realmId, use) {
47
+ return this.repository.findOne({
46
48
  select: {
47
49
  id: true,
48
50
  name: true,
@@ -65,6 +67,40 @@ import { validateEntityJoinColumns } from "typeorm-extension";
65
67
  id: "ASC"
66
68
  }
67
69
  });
70
+ }
71
+ async resolveOrCreate(realmId, use) {
72
+ const entity = await this.findActiveKey(realmId, use);
73
+ if (entity) return this.afterLoad(this.repository, entity);
74
+ return this.mintExclusive(realmId, use);
75
+ }
76
+ /**
77
+ * Minting is check-then-act (read, count, insert), and the callers are
78
+ * hot paths — the token signer resolves a signature key for EVERY
79
+ * issuance, the realm cipher an encryption key for every MFA seed — so
80
+ * a freshly created realm routinely takes several simultaneous calls
81
+ * and each one would insert its own key. Concurrent mints for one
82
+ * (realm, use) therefore share a single in-flight promise.
83
+ *
84
+ * The map is per adapter instance, and the store is a DI singleton, so
85
+ * it is scoped to one application: two applications in one process
86
+ * (the test suite) never share mint state. Separate PROCESSES can still
87
+ * race, which is why the duplicate stays tolerable rather than fatal —
88
+ * both keys are published in JWKS and verify, and `findActiveKey`
89
+ * orders deterministically, so a duplicate costs a redundant row, not
90
+ * a broken token.
91
+ */ mintExclusive(realmId, use) {
92
+ const cacheKey = `${realmId}:${use}`;
93
+ const inFlight = this.mints.get(cacheKey);
94
+ if (inFlight) return inFlight;
95
+ const promise = this.mint(realmId, use);
96
+ this.mints.set(cacheKey, promise);
97
+ return promise.finally(() => {
98
+ this.mints.delete(cacheKey);
99
+ });
100
+ }
101
+ async mint(realmId, use) {
102
+ const { repository } = this;
103
+ const entity = await this.findActiveKey(realmId, use);
68
104
  if (entity) return this.afterLoad(repository, entity);
69
105
  const total = await repository.countBy({
70
106
  realmId,
@@ -1 +1 @@
1
- {"version":3,"file":"repository.mjs","names":["AuthupError","KeyStatus","arrayBufferToBase64","createNanoID","isUUID","AsymmetricKey","CryptoAsymmetricAlgorithm","createAsymmetricKeyPair","JWKType","JWKUse","JWTAlgorithm","Like","validateEntityJoinColumns","applyQuery","redactFieldConditions","getRandomValues","DatabaseConflictError","KeyEntity","RealmEntity","UserAuthenticatorEntity","REALM_CIPHER_BLOB_VERSION","isWrappedKeyMaterial","unwrapKeyMaterial","wrapKeyMaterial","applyRealmScopeSelect","isEntityUnique","translateWhereConditions","RealmRepositoryAdapter","KeyRepositoryAdapter","dataSource","secretsCipher","realmRepository","logger","options","getRepository","repository","resolveOrCreate","realmId","use","entity","findOne","select","id","name","type","status","signatureAlgorithm","encryptionKey","decryptionKey","where","ACTIVE","order","priority","createdAt","afterLoad","total","countBy","ENCRYPTION","createEncryptionKey","createSignatureKey","resolveById","keyPair","RSASSA_PKCS1_V1_5","privateKeyContainer","privateKey","publicKeyContainer","publicKey","material","toBase64","create","generateName","SIGNATURE","RSA","protect","RS256","save","raw","Uint8Array","buffer","OCT","update","e","warn","error","findMany","query","qb","createQueryBuilder","groupBy","pagination","entities","getManyAndCount","data","meta","findOneById","findOneBy","findOneByName","realmKey","resolveId","findOneByIdOrName","idOrName","realm","findManyBy","findBy","merge","saved","remove","validateJoinColumns","entityTarget","checkUniqueness","existing","isUnique","entityExisting","countBlobReferences","keyId","secret","findHighestPriority","maximum"],"sources":["../../../../../../src/app/modules/database/repositories/key/repository.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 { AuthupError } from '@authup/errors';\nimport type { IQuery } from '@rapiq/core';\nimport type { Key } from '@authup/core-kit';\nimport { KeyStatus } from '@authup/core-kit';\nimport { arrayBufferToBase64, createNanoID, isUUID } from '@authup/kit';\nimport {\n AsymmetricKey,\n CryptoAsymmetricAlgorithm,\n type EntityRepositoryFindManyResult,\n type ISymmetricCipher,\n type Logger,\n createAsymmetricKeyPair,\n} from '@authup/server-kit';\nimport { JWKType, JWKUse, JWTAlgorithm } from '@authup/specs';\nimport type { DataSource, FindOptionsWhere, Repository } from 'typeorm';\nimport { Like } from 'typeorm';\nimport { validateEntityJoinColumns } from 'typeorm-extension';\nimport { applyQuery, redactFieldConditions } from '../query.ts';\nimport { getRandomValues } from 'uncrypto';\nimport {\n DatabaseConflictError,\n KeyEntity,\n RealmEntity,\n UserAuthenticatorEntity,\n} from '../../../../../adapters/database/index.ts';\nimport type { IKeyRepository, IKeyStore, IRealmRepository } from '../../../../../core/index.ts';\nimport {\n REALM_CIPHER_BLOB_VERSION,\n isWrappedKeyMaterial,\n unwrapKeyMaterial,\n wrapKeyMaterial,\n} from '../../../../../core/index.ts';\nimport { applyRealmScopeSelect, isEntityUnique, translateWhereConditions } from '../helpers.ts';\nimport { RealmRepositoryAdapter } from '../realm/repository.ts';\n\nexport type KeyRepositoryAdapterOptions = {\n /**\n * Optional KEK (config secretsEncryptionKey) — when present, key\n * material is persisted wrapped and unwrapped transparently on read.\n */\n secretsCipher?: ISymmetricCipher | null,\n logger?: Logger,\n};\n\n/**\n * One adapter, two ports: the entity CRUD surface (IKeyRepository) for the\n * key management API and the material-resolving store (IKeyStore) for the\n * signer / verifier / realm cipher. Entity reads never select\n * decryptionKey; only the IKeyStore surface hands out (unwrapped) material.\n */\nexport class KeyRepositoryAdapter implements IKeyRepository, IKeyStore {\n protected dataSource : DataSource;\n\n protected secretsCipher : ISymmetricCipher | null;\n\n protected realmRepository : IRealmRepository;\n\n protected logger? : Logger;\n\n constructor(dataSource: DataSource, options: KeyRepositoryAdapterOptions = {}) {\n this.dataSource = dataSource;\n this.secretsCipher = options.secretsCipher ?? null;\n this.logger = options.logger;\n this.realmRepository = new RealmRepositoryAdapter(dataSource.getRepository(RealmEntity));\n }\n\n protected get repository() : Repository<KeyEntity> {\n return this.dataSource.getRepository(KeyEntity);\n }\n\n // ------------------------------------------------------------------\n // IKeyStore — material resolution (signer / verifier / realm cipher)\n // ------------------------------------------------------------------\n\n async resolveOrCreate(realmId: string, use: `${JWKUse}`): Promise<Key> {\n const { repository } = this;\n\n const entity = await repository.findOne({\n select: {\n id: true,\n name: true,\n type: true,\n use: true,\n status: true,\n signatureAlgorithm: true,\n encryptionKey: true,\n decryptionKey: true,\n realmId: true,\n },\n where: {\n realmId,\n use,\n status: KeyStatus.ACTIVE,\n },\n // createdAt + id break priority ties deterministically (e.g.\n // duplicate mints from a concurrent zero-row backstop race —\n // benign, both keys verify, but selection must be stable).\n order: {\n priority: 'DESC', \n createdAt: 'DESC', \n id: 'ASC', \n },\n });\n\n if (entity) {\n return this.afterLoad(repository, entity);\n }\n\n const total = await repository.countBy({ realmId, use });\n if (total > 0) {\n // an admin who disabled every key meant it — do not silently\n // re-mint around the kill switch.\n throw new AuthupError(\n `No active ${use} key is available for realm ${realmId} ` +\n `(${total} key(s) exist, none active).`,\n );\n }\n\n if (use === JWKUse.ENCRYPTION) {\n return this.createEncryptionKey(repository, realmId);\n }\n\n return this.createSignatureKey(repository, realmId);\n }\n\n async resolveById(id: string): Promise<Key | null> {\n const { repository } = this;\n\n // `id` reaches here from an attacker-controlled JWT `kid` header on the\n // token-verification hot path. A non-UUID value binds against a\n // postgres `uuid` column as a driver-level type error (500) instead of\n // a clean miss — short-circuit to \"not found\" so a garbage kid is a\n // plain verification failure.\n if (!isUUID(id)) {\n return null;\n }\n\n const entity = await repository.findOne({\n select: {\n id: true,\n name: true,\n type: true,\n use: true,\n status: true,\n signatureAlgorithm: true,\n encryptionKey: true,\n decryptionKey: true,\n realmId: true,\n },\n where: { id },\n });\n\n if (!entity) {\n return null;\n }\n\n return this.afterLoad(repository, entity);\n }\n\n protected async createSignatureKey(\n repository: Repository<KeyEntity>,\n realmId: string,\n ) : Promise<Key> {\n const keyPair = await createAsymmetricKeyPair({ name: CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5 });\n\n const privateKeyContainer = new AsymmetricKey(keyPair.privateKey);\n const publicKeyContainer = new AsymmetricKey(keyPair.publicKey);\n\n const material = await privateKeyContainer.toBase64();\n\n const entity = repository.create({\n name: this.generateName(JWKUse.SIGNATURE),\n type: JWKType.RSA,\n use: JWKUse.SIGNATURE,\n status: KeyStatus.ACTIVE,\n decryptionKey: await this.protect(material),\n encryptionKey: await publicKeyContainer.toBase64(),\n realmId,\n signatureAlgorithm: `${JWTAlgorithm.RS256}`,\n });\n\n await repository.save(entity);\n\n // hand the caller usable material regardless of the persisted form.\n entity.decryptionKey = material;\n\n return entity;\n }\n\n protected async createEncryptionKey(\n repository: Repository<KeyEntity>,\n realmId: string,\n ) : Promise<Key> {\n const raw = new Uint8Array(32);\n getRandomValues(raw);\n\n const material = arrayBufferToBase64(raw.buffer);\n\n const entity = repository.create({\n name: this.generateName(JWKUse.ENCRYPTION),\n type: JWKType.OCT,\n use: JWKUse.ENCRYPTION,\n status: KeyStatus.ACTIVE,\n decryptionKey: await this.protect(material),\n encryptionKey: null,\n realmId,\n signatureAlgorithm: null,\n });\n\n await repository.save(entity);\n\n entity.decryptionKey = material;\n\n return entity;\n }\n\n protected generateName(use: `${JWKUse}`) : string {\n return `${use}-${createNanoID(10)}`;\n }\n\n protected async afterLoad(\n repository: Repository<KeyEntity>,\n entity: KeyEntity,\n ) : Promise<Key> {\n if (!entity.decryptionKey) {\n return entity;\n }\n\n if (isWrappedKeyMaterial(entity.decryptionKey)) {\n entity.decryptionKey = await unwrapKeyMaterial(this.secretsCipher, entity.decryptionKey);\n return entity;\n }\n\n if (this.secretsCipher) {\n // lazy wrap-on-read: a KEK added to a running deployment\n // hardens existing rows without a migration step. Best-effort —\n // the material stays readable either way.\n const material = entity.decryptionKey;\n try {\n await repository.update(entity.id, { decryptionKey: await wrapKeyMaterial(this.secretsCipher, material) });\n } catch (e) {\n // Best-effort — the material stays readable and the next read\n // retries. Surface it though: a persistent failure (e.g. a\n // read-only replica) means the row is never hardened at rest.\n this.logger?.warn(`Failed to wrap key material at rest for key ${entity.id}.`, { error: e });\n }\n entity.decryptionKey = material;\n }\n\n return entity;\n }\n\n protected async protect(material: string) : Promise<string> {\n if (!this.secretsCipher) {\n return material;\n }\n\n return wrapKeyMaterial(this.secretsCipher, material);\n }\n\n // ------------------------------------------------------------------\n // IKeyRepository — entity CRUD surface (key management API)\n // ------------------------------------------------------------------\n\n async findMany(query: IQuery): Promise<EntityRepositoryFindManyResult<Key>> {\n const qb = this.repository.createQueryBuilder('keyEntity');\n qb.groupBy('keyEntity.id');\n\n const { pagination } = applyQuery(qb, query);\n\n applyRealmScopeSelect(qb, 'keyEntity');\n\n const [entities, total] = await qb.getManyAndCount();\n\n return {\n data: redactFieldConditions(query, entities),\n meta: {\n total,\n ...pagination,\n },\n };\n }\n\n async findOneById(id: string): Promise<Key | null> {\n return this.findOneBy({ id });\n }\n\n async findOneByName(name: string, realmKey?: string): Promise<Key | null> {\n const where : FindOptionsWhere<KeyEntity> = { name };\n\n if (realmKey) {\n const realmId = await this.realmRepository.resolveId(realmKey);\n if (!realmId) {\n return null;\n }\n\n where.realmId = realmId;\n }\n\n return this.repository.findOneBy(where);\n }\n\n async findOneByIdOrName(idOrName: string, realm?: string): Promise<Key | null> {\n return isUUID(idOrName) ?\n this.findOneById(idOrName) :\n this.findOneByName(idOrName, realm);\n }\n\n async findManyBy(where: Record<string, any>): Promise<Key[]> {\n return this.repository.findBy(translateWhereConditions(where));\n }\n\n async findOneBy(where: Record<string, any>): Promise<Key | null> {\n return this.repository.findOneBy(translateWhereConditions(where));\n }\n\n create(data: Partial<Key>): Key {\n return this.repository.create(data);\n }\n\n merge(entity: Key, data: Partial<Key>): Key {\n return this.repository.merge(entity as KeyEntity, data);\n }\n\n async save(entity: Key): Promise<Key> {\n if (\n entity.decryptionKey &&\n this.secretsCipher &&\n !isWrappedKeyMaterial(entity.decryptionKey)\n ) {\n const material = entity.decryptionKey;\n entity.decryptionKey = await wrapKeyMaterial(this.secretsCipher, material);\n const saved = await this.repository.save(entity as KeyEntity);\n saved.decryptionKey = material;\n return saved;\n }\n\n return this.repository.save(entity as KeyEntity);\n }\n\n async remove(entity: Key): Promise<void> {\n await this.repository.remove(entity as KeyEntity);\n }\n\n async validateJoinColumns(data: Partial<Key>): Promise<void> {\n await validateEntityJoinColumns(data, {\n dataSource: this.dataSource,\n entityTarget: KeyEntity,\n });\n }\n\n async checkUniqueness(data: Partial<Key>, existing?: Key): Promise<void> {\n const isUnique = await isEntityUnique({\n dataSource: this.dataSource,\n entityTarget: KeyEntity,\n entity: data,\n entityExisting: existing,\n });\n\n if (!isUnique) {\n throw new DatabaseConflictError();\n }\n }\n\n async countBlobReferences(keyId: string): Promise<number> {\n return this.dataSource.getRepository(UserAuthenticatorEntity).countBy({ secret: Like(`${REALM_CIPHER_BLOB_VERSION}.${keyId}.%`) });\n }\n\n async findHighestPriority(realmId: string, use: string): Promise<number | null> {\n return this.repository.maximum('priority', { realmId, use: use as `${JWKUse}` });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"repository.mjs","names":["AuthupError","KeyStatus","arrayBufferToBase64","createNanoID","isUUID","AsymmetricKey","CryptoAsymmetricAlgorithm","createAsymmetricKeyPair","JWKType","JWKUse","JWTAlgorithm","Like","validateEntityJoinColumns","applyQuery","redactFieldConditions","getRandomValues","DatabaseConflictError","KeyEntity","RealmEntity","UserAuthenticatorEntity","REALM_CIPHER_BLOB_VERSION","isWrappedKeyMaterial","unwrapKeyMaterial","wrapKeyMaterial","applyRealmScopeSelect","isEntityUnique","translateWhereConditions","RealmRepositoryAdapter","KeyRepositoryAdapter","dataSource","secretsCipher","realmRepository","logger","mints","Map","options","getRepository","repository","findActiveKey","realmId","use","findOne","select","id","name","type","status","signatureAlgorithm","encryptionKey","decryptionKey","where","ACTIVE","order","priority","createdAt","resolveOrCreate","entity","afterLoad","mintExclusive","cacheKey","inFlight","get","promise","mint","set","finally","delete","total","countBy","ENCRYPTION","createEncryptionKey","createSignatureKey","resolveById","keyPair","RSASSA_PKCS1_V1_5","privateKeyContainer","privateKey","publicKeyContainer","publicKey","material","toBase64","create","generateName","SIGNATURE","RSA","protect","RS256","save","raw","Uint8Array","buffer","OCT","update","e","warn","error","findMany","query","qb","createQueryBuilder","groupBy","pagination","entities","getManyAndCount","data","meta","findOneById","findOneBy","findOneByName","realmKey","resolveId","findOneByIdOrName","idOrName","realm","findManyBy","findBy","merge","saved","remove","validateJoinColumns","entityTarget","checkUniqueness","existing","isUnique","entityExisting","countBlobReferences","keyId","secret","findHighestPriority","maximum"],"sources":["../../../../../../src/app/modules/database/repositories/key/repository.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 { AuthupError } from '@authup/errors';\nimport type { IQuery } from '@rapiq/core';\nimport type { Key } from '@authup/core-kit';\nimport { KeyStatus } from '@authup/core-kit';\nimport { arrayBufferToBase64, createNanoID, isUUID } from '@authup/kit';\nimport {\n AsymmetricKey,\n CryptoAsymmetricAlgorithm,\n type EntityRepositoryFindManyResult,\n type ISymmetricCipher,\n type Logger,\n createAsymmetricKeyPair,\n} from '@authup/server-kit';\nimport { JWKType, JWKUse, JWTAlgorithm } from '@authup/specs';\nimport type { DataSource, FindOptionsWhere, Repository } from 'typeorm';\nimport { Like } from 'typeorm';\nimport { validateEntityJoinColumns } from 'typeorm-extension';\nimport { applyQuery, redactFieldConditions } from '../query.ts';\nimport { getRandomValues } from 'uncrypto';\nimport {\n DatabaseConflictError,\n KeyEntity,\n RealmEntity,\n UserAuthenticatorEntity,\n} from '../../../../../adapters/database/index.ts';\nimport type { IKeyRepository, IKeyStore, IRealmRepository } from '../../../../../core/index.ts';\nimport {\n REALM_CIPHER_BLOB_VERSION,\n isWrappedKeyMaterial,\n unwrapKeyMaterial,\n wrapKeyMaterial,\n} from '../../../../../core/index.ts';\nimport { applyRealmScopeSelect, isEntityUnique, translateWhereConditions } from '../helpers.ts';\nimport { RealmRepositoryAdapter } from '../realm/repository.ts';\n\nexport type KeyRepositoryAdapterOptions = {\n /**\n * Optional KEK (config secretsEncryptionKey) — when present, key\n * material is persisted wrapped and unwrapped transparently on read.\n */\n secretsCipher?: ISymmetricCipher | null,\n logger?: Logger,\n};\n\n/**\n * One adapter, two ports: the entity CRUD surface (IKeyRepository) for the\n * key management API and the material-resolving store (IKeyStore) for the\n * signer / verifier / realm cipher. Entity reads never select\n * decryptionKey; only the IKeyStore surface hands out (unwrapped) material.\n */\nexport class KeyRepositoryAdapter implements IKeyRepository, IKeyStore {\n protected dataSource : DataSource;\n\n protected secretsCipher : ISymmetricCipher | null;\n\n protected realmRepository : IRealmRepository;\n\n protected logger? : Logger;\n\n /**\n * In-flight mints keyed `<realmId>:<use>` — see {@link mintExclusive}.\n */\n protected mints : Map<string, Promise<Key>> = new Map();\n\n constructor(dataSource: DataSource, options: KeyRepositoryAdapterOptions = {}) {\n this.dataSource = dataSource;\n this.secretsCipher = options.secretsCipher ?? null;\n this.logger = options.logger;\n this.realmRepository = new RealmRepositoryAdapter(dataSource.getRepository(RealmEntity));\n }\n\n protected get repository() : Repository<KeyEntity> {\n return this.dataSource.getRepository(KeyEntity);\n }\n\n // ------------------------------------------------------------------\n // IKeyStore — material resolution (signer / verifier / realm cipher)\n // ------------------------------------------------------------------\n\n protected findActiveKey(realmId: string, use: `${JWKUse}`) : Promise<KeyEntity | null> {\n return this.repository.findOne({\n select: {\n id: true,\n name: true,\n type: true,\n use: true,\n status: true,\n signatureAlgorithm: true,\n encryptionKey: true,\n decryptionKey: true,\n realmId: true,\n },\n where: {\n realmId,\n use,\n status: KeyStatus.ACTIVE,\n },\n // createdAt + id break priority ties deterministically, so key\n // selection stays stable whenever a realm holds several active\n // keys (a rotation in progress, or a cross-process mint race).\n order: {\n priority: 'DESC',\n createdAt: 'DESC',\n id: 'ASC',\n },\n });\n }\n\n async resolveOrCreate(realmId: string, use: `${JWKUse}`): Promise<Key> {\n const entity = await this.findActiveKey(realmId, use);\n if (entity) {\n return this.afterLoad(this.repository, entity);\n }\n\n return this.mintExclusive(realmId, use);\n }\n\n /**\n * Minting is check-then-act (read, count, insert), and the callers are\n * hot paths — the token signer resolves a signature key for EVERY\n * issuance, the realm cipher an encryption key for every MFA seed — so\n * a freshly created realm routinely takes several simultaneous calls\n * and each one would insert its own key. Concurrent mints for one\n * (realm, use) therefore share a single in-flight promise.\n *\n * The map is per adapter instance, and the store is a DI singleton, so\n * it is scoped to one application: two applications in one process\n * (the test suite) never share mint state. Separate PROCESSES can still\n * race, which is why the duplicate stays tolerable rather than fatal —\n * both keys are published in JWKS and verify, and `findActiveKey`\n * orders deterministically, so a duplicate costs a redundant row, not\n * a broken token.\n */\n protected mintExclusive(realmId: string, use: `${JWKUse}`) : Promise<Key> {\n const cacheKey = `${realmId}:${use}`;\n\n const inFlight = this.mints.get(cacheKey);\n if (inFlight) {\n return inFlight;\n }\n\n const promise = this.mint(realmId, use);\n this.mints.set(cacheKey, promise);\n\n return promise.finally(() => {\n this.mints.delete(cacheKey);\n });\n }\n\n protected async mint(realmId: string, use: `${JWKUse}`) : Promise<Key> {\n const { repository } = this;\n\n // Re-read under the guard: the caller's lookup may predate a mint\n // that has since completed and left the map, so the in-flight\n // check alone would not see it.\n const entity = await this.findActiveKey(realmId, use);\n if (entity) {\n return this.afterLoad(repository, entity);\n }\n\n const total = await repository.countBy({ realmId, use });\n if (total > 0) {\n // an admin who disabled every key meant it — do not silently\n // re-mint around the kill switch.\n throw new AuthupError(\n `No active ${use} key is available for realm ${realmId} ` +\n `(${total} key(s) exist, none active).`,\n );\n }\n\n if (use === JWKUse.ENCRYPTION) {\n return this.createEncryptionKey(repository, realmId);\n }\n\n return this.createSignatureKey(repository, realmId);\n }\n\n async resolveById(id: string): Promise<Key | null> {\n const { repository } = this;\n\n // `id` reaches here from an attacker-controlled JWT `kid` header on the\n // token-verification hot path. A non-UUID value binds against a\n // postgres `uuid` column as a driver-level type error (500) instead of\n // a clean miss — short-circuit to \"not found\" so a garbage kid is a\n // plain verification failure.\n if (!isUUID(id)) {\n return null;\n }\n\n const entity = await repository.findOne({\n select: {\n id: true,\n name: true,\n type: true,\n use: true,\n status: true,\n signatureAlgorithm: true,\n encryptionKey: true,\n decryptionKey: true,\n realmId: true,\n },\n where: { id },\n });\n\n if (!entity) {\n return null;\n }\n\n return this.afterLoad(repository, entity);\n }\n\n protected async createSignatureKey(\n repository: Repository<KeyEntity>,\n realmId: string,\n ) : Promise<Key> {\n const keyPair = await createAsymmetricKeyPair({ name: CryptoAsymmetricAlgorithm.RSASSA_PKCS1_V1_5 });\n\n const privateKeyContainer = new AsymmetricKey(keyPair.privateKey);\n const publicKeyContainer = new AsymmetricKey(keyPair.publicKey);\n\n const material = await privateKeyContainer.toBase64();\n\n const entity = repository.create({\n name: this.generateName(JWKUse.SIGNATURE),\n type: JWKType.RSA,\n use: JWKUse.SIGNATURE,\n status: KeyStatus.ACTIVE,\n decryptionKey: await this.protect(material),\n encryptionKey: await publicKeyContainer.toBase64(),\n realmId,\n signatureAlgorithm: `${JWTAlgorithm.RS256}`,\n });\n\n await repository.save(entity);\n\n // hand the caller usable material regardless of the persisted form.\n entity.decryptionKey = material;\n\n return entity;\n }\n\n protected async createEncryptionKey(\n repository: Repository<KeyEntity>,\n realmId: string,\n ) : Promise<Key> {\n const raw = new Uint8Array(32);\n getRandomValues(raw);\n\n const material = arrayBufferToBase64(raw.buffer);\n\n const entity = repository.create({\n name: this.generateName(JWKUse.ENCRYPTION),\n type: JWKType.OCT,\n use: JWKUse.ENCRYPTION,\n status: KeyStatus.ACTIVE,\n decryptionKey: await this.protect(material),\n encryptionKey: null,\n realmId,\n signatureAlgorithm: null,\n });\n\n await repository.save(entity);\n\n entity.decryptionKey = material;\n\n return entity;\n }\n\n protected generateName(use: `${JWKUse}`) : string {\n return `${use}-${createNanoID(10)}`;\n }\n\n protected async afterLoad(\n repository: Repository<KeyEntity>,\n entity: KeyEntity,\n ) : Promise<Key> {\n if (!entity.decryptionKey) {\n return entity;\n }\n\n if (isWrappedKeyMaterial(entity.decryptionKey)) {\n entity.decryptionKey = await unwrapKeyMaterial(this.secretsCipher, entity.decryptionKey);\n return entity;\n }\n\n if (this.secretsCipher) {\n // lazy wrap-on-read: a KEK added to a running deployment\n // hardens existing rows without a migration step. Best-effort —\n // the material stays readable either way.\n const material = entity.decryptionKey;\n try {\n await repository.update(entity.id, { decryptionKey: await wrapKeyMaterial(this.secretsCipher, material) });\n } catch (e) {\n // Best-effort — the material stays readable and the next read\n // retries. Surface it though: a persistent failure (e.g. a\n // read-only replica) means the row is never hardened at rest.\n this.logger?.warn(`Failed to wrap key material at rest for key ${entity.id}.`, { error: e });\n }\n entity.decryptionKey = material;\n }\n\n return entity;\n }\n\n protected async protect(material: string) : Promise<string> {\n if (!this.secretsCipher) {\n return material;\n }\n\n return wrapKeyMaterial(this.secretsCipher, material);\n }\n\n // ------------------------------------------------------------------\n // IKeyRepository — entity CRUD surface (key management API)\n // ------------------------------------------------------------------\n\n async findMany(query: IQuery): Promise<EntityRepositoryFindManyResult<Key>> {\n const qb = this.repository.createQueryBuilder('keyEntity');\n qb.groupBy('keyEntity.id');\n\n const { pagination } = applyQuery(qb, query);\n\n applyRealmScopeSelect(qb, 'keyEntity');\n\n const [entities, total] = await qb.getManyAndCount();\n\n return {\n data: redactFieldConditions(query, entities),\n meta: {\n total,\n ...pagination,\n },\n };\n }\n\n async findOneById(id: string): Promise<Key | null> {\n return this.findOneBy({ id });\n }\n\n async findOneByName(name: string, realmKey?: string): Promise<Key | null> {\n const where : FindOptionsWhere<KeyEntity> = { name };\n\n if (realmKey) {\n const realmId = await this.realmRepository.resolveId(realmKey);\n if (!realmId) {\n return null;\n }\n\n where.realmId = realmId;\n }\n\n return this.repository.findOneBy(where);\n }\n\n async findOneByIdOrName(idOrName: string, realm?: string): Promise<Key | null> {\n return isUUID(idOrName) ?\n this.findOneById(idOrName) :\n this.findOneByName(idOrName, realm);\n }\n\n async findManyBy(where: Record<string, any>): Promise<Key[]> {\n return this.repository.findBy(translateWhereConditions(where));\n }\n\n async findOneBy(where: Record<string, any>): Promise<Key | null> {\n return this.repository.findOneBy(translateWhereConditions(where));\n }\n\n create(data: Partial<Key>): Key {\n return this.repository.create(data);\n }\n\n merge(entity: Key, data: Partial<Key>): Key {\n return this.repository.merge(entity as KeyEntity, data);\n }\n\n async save(entity: Key): Promise<Key> {\n if (\n entity.decryptionKey &&\n this.secretsCipher &&\n !isWrappedKeyMaterial(entity.decryptionKey)\n ) {\n const material = entity.decryptionKey;\n entity.decryptionKey = await wrapKeyMaterial(this.secretsCipher, material);\n const saved = await this.repository.save(entity as KeyEntity);\n saved.decryptionKey = material;\n return saved;\n }\n\n return this.repository.save(entity as KeyEntity);\n }\n\n async remove(entity: Key): Promise<void> {\n await this.repository.remove(entity as KeyEntity);\n }\n\n async validateJoinColumns(data: Partial<Key>): Promise<void> {\n await validateEntityJoinColumns(data, {\n dataSource: this.dataSource,\n entityTarget: KeyEntity,\n });\n }\n\n async checkUniqueness(data: Partial<Key>, existing?: Key): Promise<void> {\n const isUnique = await isEntityUnique({\n dataSource: this.dataSource,\n entityTarget: KeyEntity,\n entity: data,\n entityExisting: existing,\n });\n\n if (!isUnique) {\n throw new DatabaseConflictError();\n }\n }\n\n async countBlobReferences(keyId: string): Promise<number> {\n return this.dataSource.getRepository(UserAuthenticatorEntity).countBy({ secret: Like(`${REALM_CIPHER_BLOB_VERSION}.${keyId}.%`) });\n }\n\n async findHighestPriority(realmId: string, use: string): Promise<number | null> {\n return this.repository.maximum('priority', { realmId, use: use as `${JWKUse}` });\n }\n}\n"],"mappings":"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"}
@@ -14,12 +14,20 @@ export declare function assertSchemaFieldsCoverEntity(name: string, schema: {
14
14
  }, metadata: EntityMetadata): void;
15
15
  /**
16
16
  * Validate every registered entity schema against its TypeORM
17
- * metadata (`@rapiq/adapter-typeorm`'s `assertSchemaMatchesEntity`: allow-lists,
18
- * fields/sort defaults and the filters default condition tree must
19
- * reference existing columns/relations) and assert its field allow-list
20
- * covers every selectable column. Called by
21
- * `DatabaseModule.setup` once the DataSource is initialized
22
- * schema/entity drift fails the boot, fail-fast.
17
+ * metadata (`@rapiq/adapter-typeorm`'s `assertSchemaMatchesEntity`:
18
+ * allow-lists, fields/sort defaults and the filters default condition
19
+ * tree must reference existing columns/relations, AND every declared
20
+ * index must be a leftmost prefix of a real primary key, unique
21
+ * constraint or index) and assert its field allow-list covers every
22
+ * selectable column. Called by `DatabaseModule.setup` once the
23
+ * DataSource is initialized — schema/entity drift fails the boot,
24
+ * fail-fast.
25
+ *
26
+ * The index half was an authup-side assert until rapiq 2.1.0 folded it
27
+ * upstream (tada5hi/rapiq#902 closed #898); the local copy is gone,
28
+ * since the upstream check is the same leftmost-prefix rule over the
29
+ * same structures and additionally verifies the index keys are real
30
+ * columns.
23
31
  */
24
32
  export declare function validateEntitySchemas(dataSource: DataSource): void;
25
33
  //# sourceMappingURL=schema-validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-validation.d.ts","sourceRoot":"","sources":["../../../../../src/app/modules/database/repositories/schema-validation.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAgB,MAAM,SAAS,CAAC;AA2ExE;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAAE,EAC/D,QAAQ,EAAE,cAAc,GACxB,IAAI,CAiBP;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAI,IAAI,CAQnE"}
1
+ {"version":3,"file":"schema-validation.d.ts","sourceRoot":"","sources":["../../../../../src/app/modules/database/repositories/schema-validation.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAgB,MAAM,SAAS,CAAC;AA+ExE;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAAE,EAC/D,QAAQ,EAAE,cAAc,GACxB,IAAI,CAiBP;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAI,IAAI,CAQnE"}
@@ -17,8 +17,10 @@ import { UserAttributeEntity } from "../../../../adapters/database/domains/user-
17
17
  import { ConsentEntity } from "../../../../adapters/database/domains/consent/entity.mjs";
18
18
  import { EventEntity } from "../../../../adapters/database/domains/event/entity.mjs";
19
19
  import { IdentityProviderEntity } from "../../../../adapters/database/domains/identity-provider/entity.mjs";
20
+ import { IdentityProviderAccountEntity } from "../../../../adapters/database/domains/identity-provider-account/entity.mjs";
20
21
  import { IdentityProviderRoleMappingEntity } from "../../../../adapters/database/domains/identity-provider-role-mapping/entity.mjs";
21
22
  import { SessionEntity } from "../../../../adapters/database/domains/session/entity.mjs";
23
+ import { SessionTokenEntity } from "../../../../adapters/database/domains/session-token/entity.mjs";
22
24
  import { TrustAnchorEntity } from "../../../../adapters/database/domains/trust-anchor/entity.mjs";
23
25
  import { PermissionPolicyEntity } from "../../../../adapters/database/domains/permission-policy/entity.mjs";
24
26
  import { RolePermissionEntity } from "../../../../adapters/database/domains/role-permission/entity.mjs";
@@ -43,6 +45,7 @@ import { assertSchemaMatchesEntity } from "@rapiq/adapter-typeorm";
43
45
  [EntityType.CONSENT]: ConsentEntity,
44
46
  [EntityType.EVENT]: EventEntity,
45
47
  [EntityType.IDENTITY_PROVIDER]: IdentityProviderEntity,
48
+ [EntityType.IDENTITY_PROVIDER_ACCOUNT]: IdentityProviderAccountEntity,
46
49
  [EntityType.IDENTITY_PROVIDER_ROLE_MAPPING]: IdentityProviderRoleMappingEntity,
47
50
  [EntityType.KEY]: KeyEntity,
48
51
  [EntityType.PERMISSION]: PermissionEntity,
@@ -54,6 +57,7 @@ import { assertSchemaMatchesEntity } from "@rapiq/adapter-typeorm";
54
57
  [EntityType.ROLE_PERMISSION]: RolePermissionEntity,
55
58
  [EntityType.SCOPE]: ScopeEntity,
56
59
  [EntityType.SESSION]: SessionEntity,
60
+ [EntityType.SESSION_TOKEN]: SessionTokenEntity,
57
61
  [EntityType.TRUST_ANCHOR]: TrustAnchorEntity,
58
62
  [EntityType.USER]: UserEntity,
59
63
  [EntityType.USER_ATTRIBUTE]: UserAttributeEntity,
@@ -81,12 +85,20 @@ import { assertSchemaMatchesEntity } from "@rapiq/adapter-typeorm";
81
85
  }
82
86
  /**
83
87
  * Validate every registered entity schema against its TypeORM
84
- * metadata (`@rapiq/adapter-typeorm`'s `assertSchemaMatchesEntity`: allow-lists,
85
- * fields/sort defaults and the filters default condition tree must
86
- * reference existing columns/relations) and assert its field allow-list
87
- * covers every selectable column. Called by
88
- * `DatabaseModule.setup` once the DataSource is initialized
89
- * schema/entity drift fails the boot, fail-fast.
88
+ * metadata (`@rapiq/adapter-typeorm`'s `assertSchemaMatchesEntity`:
89
+ * allow-lists, fields/sort defaults and the filters default condition
90
+ * tree must reference existing columns/relations, AND every declared
91
+ * index must be a leftmost prefix of a real primary key, unique
92
+ * constraint or index) and assert its field allow-list covers every
93
+ * selectable column. Called by `DatabaseModule.setup` once the
94
+ * DataSource is initialized — schema/entity drift fails the boot,
95
+ * fail-fast.
96
+ *
97
+ * The index half was an authup-side assert until rapiq 2.1.0 folded it
98
+ * upstream (tada5hi/rapiq#902 closed #898); the local copy is gone,
99
+ * since the upstream check is the same leftmost-prefix rule over the
100
+ * same structures and additionally verifies the index keys are real
101
+ * columns.
90
102
  */ function validateEntitySchemas(dataSource) {
91
103
  for (const [name, target] of Object.entries(SCHEMA_ENTITY_TARGETS)) {
92
104
  const schema = schemaRegistry.getOrFail(name);
@@ -1 +1 @@
1
- {"version":3,"file":"schema-validation.mjs","names":["assertSchemaMatchesEntity","EntityType","schemaRegistry","ClientEntity","ClientPermissionEntity","ClientRoleEntity","ClientScopeEntity","ConsentEntity","EventEntity","IdentityProviderEntity","IdentityProviderRoleMappingEntity","KeyEntity","PermissionEntity","PermissionPolicyEntity","PolicyEntity","RealmEntity","RoleAttributeEntity","RoleEntity","RolePermissionEntity","ScopeEntity","SessionEntity","TrustAnchorEntity","UserAttributeEntity","UserAuthenticatorEntity","UserEntity","UserPermissionEntity","UserRoleEntity","SCHEMA_ENTITY_TARGETS","CLIENT","CLIENT_PERMISSION","CLIENT_ROLE","CLIENT_SCOPE","CONSENT","EVENT","IDENTITY_PROVIDER","IDENTITY_PROVIDER_ROLE_MAPPING","KEY","PERMISSION","PERMISSION_POLICY","POLICY","REALM","ROLE","ROLE_ATTRIBUTE","ROLE_PERMISSION","SCOPE","SESSION","TRUST_ANCHOR","USER","USER_ATTRIBUTE","USER_AUTHENTICATOR","USER_PERMISSION","USER_ROLE","SCHEMA_FIELD_EXCLUSIONS","assertSchemaFieldsCoverEntity","name","schema","metadata","declared","Set","fields","default","allowed","excluded","missing","columns","filter","column","isSelect","map","propertyName","has","length","Error","join","validateEntitySchemas","dataSource","target","Object","entries","getOrFail","getMetadata"],"sources":["../../../../../src/app/modules/database/repositories/schema-validation.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 { ObjectLiteral } from '@rapiq/core';\nimport { assertSchemaMatchesEntity } from '@rapiq/adapter-typeorm';\nimport type { DataSource, EntityMetadata, EntityTarget } from 'typeorm';\nimport { EntityType } from '@authup/core-kit';\nimport { schemaRegistry } from '../../../../core/index.ts';\nimport {\n ClientEntity,\n ClientPermissionEntity,\n ClientRoleEntity,\n ClientScopeEntity,\n ConsentEntity,\n EventEntity,\n IdentityProviderEntity,\n IdentityProviderRoleMappingEntity,\n KeyEntity,\n PermissionEntity,\n PermissionPolicyEntity,\n PolicyEntity,\n RealmEntity,\n RoleAttributeEntity,\n RoleEntity,\n RolePermissionEntity,\n ScopeEntity,\n SessionEntity,\n TrustAnchorEntity,\n UserAttributeEntity,\n UserAuthenticatorEntity,\n UserEntity,\n UserPermissionEntity,\n UserRoleEntity,\n} from '../../../../adapters/database/domains/index.ts';\n\n/**\n * Entity class per registered schema name — the iteration source for\n * the boot-time validation. A mapped name missing from the registry\n * fails via `getOrFail`, so a renamed/removed schema surfaces here too.\n */\nconst SCHEMA_ENTITY_TARGETS : Record<string, EntityTarget<ObjectLiteral>> = {\n [EntityType.CLIENT]: ClientEntity,\n [EntityType.CLIENT_PERMISSION]: ClientPermissionEntity,\n [EntityType.CLIENT_ROLE]: ClientRoleEntity,\n [EntityType.CLIENT_SCOPE]: ClientScopeEntity,\n [EntityType.CONSENT]: ConsentEntity,\n [EntityType.EVENT]: EventEntity,\n [EntityType.IDENTITY_PROVIDER]: IdentityProviderEntity,\n [EntityType.IDENTITY_PROVIDER_ROLE_MAPPING]: IdentityProviderRoleMappingEntity,\n [EntityType.KEY]: KeyEntity,\n [EntityType.PERMISSION]: PermissionEntity,\n [EntityType.PERMISSION_POLICY]: PermissionPolicyEntity,\n [EntityType.POLICY]: PolicyEntity,\n [EntityType.REALM]: RealmEntity,\n [EntityType.ROLE]: RoleEntity,\n [EntityType.ROLE_ATTRIBUTE]: RoleAttributeEntity,\n [EntityType.ROLE_PERMISSION]: RolePermissionEntity,\n [EntityType.SCOPE]: ScopeEntity,\n [EntityType.SESSION]: SessionEntity,\n [EntityType.TRUST_ANCHOR]: TrustAnchorEntity,\n [EntityType.USER]: UserEntity,\n [EntityType.USER_ATTRIBUTE]: UserAttributeEntity,\n [EntityType.USER_AUTHENTICATOR]: UserAuthenticatorEntity,\n [EntityType.USER_PERMISSION]: UserPermissionEntity,\n [EntityType.USER_ROLE]: UserRoleEntity,\n};\n\n/**\n * Selectable columns deliberately kept out of a schema's field\n * allow-list. `select: false` columns are skipped automatically (the\n * entity already declares them hidden); everything listed here is a\n * column that IS selectable but must never ride the API projection.\n */\nconst SCHEMA_FIELD_EXCLUSIONS : Record<string, string[]> = {\n // device-internal credential blob (TOTP config, WebAuthn public key +\n // signature counter) — surfaced only through the challenge endpoint's\n // trimmed view.\n [EntityType.USER_AUTHENTICATOR]: ['parameters'],\n};\n\n/**\n * Every selectable column must appear in the schema's field allow-list:\n * rapiq derives the root projection from `fields` (`default` when\n * present, else `allowed`), so a column missing from BOTH silently\n * vanishes from every collection response — no error, just an absent\n * property (`role.builtIn` went missing this way).\n */\nexport function assertSchemaFieldsCoverEntity(\n name: string,\n schema: { fields?: { default?: string[], allowed?: string[] } },\n metadata: EntityMetadata,\n) : void {\n const declared = new Set([\n ...(schema.fields?.default || []),\n ...(schema.fields?.allowed || []),\n ]);\n\n const excluded = new Set(SCHEMA_FIELD_EXCLUSIONS[name] || []);\n const missing = metadata.columns\n .filter((column) => column.isSelect)\n .map((column) => column.propertyName)\n .filter((propertyName) => !declared.has(propertyName) && !excluded.has(propertyName));\n\n if (missing.length > 0) {\n throw new Error(\n `The schema \"${name}\" does not declare the field(s): ${missing.join(', ')}.`,\n );\n }\n}\n\n/**\n * Validate every registered entity schema against its TypeORM\n * metadata (`@rapiq/adapter-typeorm`'s `assertSchemaMatchesEntity`: allow-lists,\n * fields/sort defaults and the filters default condition tree must\n * reference existing columns/relations) and assert its field allow-list\n * covers every selectable column. Called by\n * `DatabaseModule.setup` once the DataSource is initialized —\n * schema/entity drift fails the boot, fail-fast.\n */\nexport function validateEntitySchemas(dataSource: DataSource) : void {\n for (const [name, target] of Object.entries(SCHEMA_ENTITY_TARGETS)) {\n const schema = schemaRegistry.getOrFail(name);\n const metadata = dataSource.getMetadata(target);\n\n assertSchemaMatchesEntity(schema, metadata);\n assertSchemaFieldsCoverEntity(name, schema, metadata);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CA,MAAM2B,wBAAsE;EACvE1B,WAAW2B,SAASzB;EACpBF,WAAW4B,oBAAoBzB;EAC/BH,WAAW6B,cAAczB;EACzBJ,WAAW8B,eAAezB;EAC1BL,WAAW+B,UAAUzB;EACrBN,WAAWgC,QAAQzB;EACnBP,WAAWiC,oBAAoBzB;EAC/BR,WAAWkC,iCAAiCzB;EAC5CT,WAAWmC,MAAMzB;EACjBV,WAAWoC,aAAazB;EACxBX,WAAWqC,oBAAoBzB;EAC/BZ,WAAWsC,SAASzB;EACpBb,WAAWuC,QAAQzB;EACnBd,WAAWwC,OAAOxB;EAClBhB,WAAWyC,iBAAiB1B;EAC5Bf,WAAW0C,kBAAkBzB;EAC7BjB,WAAW2C,QAAQzB;EACnBlB,WAAW4C,UAAUzB;EACrBnB,WAAW6C,eAAezB;EAC1BpB,WAAW8C,OAAOvB;EAClBvB,WAAW+C,iBAAiB1B;EAC5BrB,WAAWgD,qBAAqB1B;EAChCtB,WAAWiD,kBAAkBzB;EAC7BxB,WAAWkD,YAAYzB;AAC5B;;;;;;GAQA,MAAM0B,0BAAqD,GAItDnD,WAAWgD,qBAAqB,CAAC,YAAa,EACnD;;;;;;;GASA,SAAgBI,8BACZC,MACAC,QACAC,UAAwB;CAExB,MAAMC,2BAAW,IAAIC,IAAI,CACjBH,GAAAA,OAAOI,QAAQC,WAAW,CAAA,GAC1BL,GAAAA,OAAOI,QAAQE,WAAW,CAAA,CACjC,CAAA;CAED,MAAMC,WAAW,IAAIJ,IAAIN,wBAAwBE,SAAS,CAAA,CAAE;CAC5D,MAAMS,UAAUP,SAASQ,QACpBC,QAAQC,WAAWA,OAAOC,QAAQ,CAAA,CAClCC,KAAKF,WAAWA,OAAOG,YAAY,CAAA,CACnCJ,QAAQI,iBAAiB,CAACZ,SAASa,IAAID,YAAAA,KAAiB,CAACP,SAASQ,IAAID,YAAAA,CAAAA;CAE3E,IAAIN,QAAQQ,SAAS,GACjB,MAAM,IAAIC,MACN,eAAelB,KAAK,mCAAmCS,QAAQU,KAAK,IAAA,EAAM,EAAE;AAGxF;;;;;;;;;GAWA,SAAgBC,sBAAsBC,YAAsB;CACxD,KAAK,MAAM,CAACrB,MAAMsB,WAAWC,OAAOC,QAAQnD,qBAAAA,GAAwB;EAChE,MAAM4B,SAASrD,eAAe6E,UAAUzB,IAAAA;EACxC,MAAME,WAAWmB,WAAWK,YAAYJ,MAAAA;EAExC5E,0BAA0BuD,QAAQC,QAAAA;EAClCH,8BAA8BC,MAAMC,QAAQC,QAAAA;CAChD;AACJ"}
1
+ {"version":3,"file":"schema-validation.mjs","names":["assertSchemaMatchesEntity","EntityType","schemaRegistry","ClientEntity","ClientPermissionEntity","ClientRoleEntity","ClientScopeEntity","ConsentEntity","EventEntity","IdentityProviderAccountEntity","IdentityProviderEntity","IdentityProviderRoleMappingEntity","KeyEntity","PermissionEntity","PermissionPolicyEntity","PolicyEntity","RealmEntity","RoleAttributeEntity","RoleEntity","RolePermissionEntity","ScopeEntity","SessionEntity","SessionTokenEntity","TrustAnchorEntity","UserAttributeEntity","UserAuthenticatorEntity","UserEntity","UserPermissionEntity","UserRoleEntity","SCHEMA_ENTITY_TARGETS","CLIENT","CLIENT_PERMISSION","CLIENT_ROLE","CLIENT_SCOPE","CONSENT","EVENT","IDENTITY_PROVIDER","IDENTITY_PROVIDER_ACCOUNT","IDENTITY_PROVIDER_ROLE_MAPPING","KEY","PERMISSION","PERMISSION_POLICY","POLICY","REALM","ROLE","ROLE_ATTRIBUTE","ROLE_PERMISSION","SCOPE","SESSION","SESSION_TOKEN","TRUST_ANCHOR","USER","USER_ATTRIBUTE","USER_AUTHENTICATOR","USER_PERMISSION","USER_ROLE","SCHEMA_FIELD_EXCLUSIONS","assertSchemaFieldsCoverEntity","name","schema","metadata","declared","Set","fields","default","allowed","excluded","missing","columns","filter","column","isSelect","map","propertyName","has","length","Error","join","validateEntitySchemas","dataSource","target","Object","entries","getOrFail","getMetadata"],"sources":["../../../../../src/app/modules/database/repositories/schema-validation.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 { ObjectLiteral } from '@rapiq/core';\nimport { assertSchemaMatchesEntity } from '@rapiq/adapter-typeorm';\nimport type { DataSource, EntityMetadata, EntityTarget } from 'typeorm';\nimport { EntityType } from '@authup/core-kit';\nimport { schemaRegistry } from '../../../../core/index.ts';\nimport {\n ClientEntity,\n ClientPermissionEntity,\n ClientRoleEntity,\n ClientScopeEntity,\n ConsentEntity,\n EventEntity,\n IdentityProviderAccountEntity,\n IdentityProviderEntity,\n IdentityProviderRoleMappingEntity,\n KeyEntity,\n PermissionEntity,\n PermissionPolicyEntity,\n PolicyEntity,\n RealmEntity,\n RoleAttributeEntity,\n RoleEntity,\n RolePermissionEntity,\n ScopeEntity,\n SessionEntity,\n SessionTokenEntity,\n TrustAnchorEntity,\n UserAttributeEntity,\n UserAuthenticatorEntity,\n UserEntity,\n UserPermissionEntity,\n UserRoleEntity,\n} from '../../../../adapters/database/domains/index.ts';\n\n/**\n * Entity class per registered schema name — the iteration source for\n * the boot-time validation. A mapped name missing from the registry\n * fails via `getOrFail`, so a renamed/removed schema surfaces here too.\n */\nconst SCHEMA_ENTITY_TARGETS : Record<string, EntityTarget<ObjectLiteral>> = {\n [EntityType.CLIENT]: ClientEntity,\n [EntityType.CLIENT_PERMISSION]: ClientPermissionEntity,\n [EntityType.CLIENT_ROLE]: ClientRoleEntity,\n [EntityType.CLIENT_SCOPE]: ClientScopeEntity,\n [EntityType.CONSENT]: ConsentEntity,\n [EntityType.EVENT]: EventEntity,\n [EntityType.IDENTITY_PROVIDER]: IdentityProviderEntity,\n [EntityType.IDENTITY_PROVIDER_ACCOUNT]: IdentityProviderAccountEntity,\n [EntityType.IDENTITY_PROVIDER_ROLE_MAPPING]: IdentityProviderRoleMappingEntity,\n [EntityType.KEY]: KeyEntity,\n [EntityType.PERMISSION]: PermissionEntity,\n [EntityType.PERMISSION_POLICY]: PermissionPolicyEntity,\n [EntityType.POLICY]: PolicyEntity,\n [EntityType.REALM]: RealmEntity,\n [EntityType.ROLE]: RoleEntity,\n [EntityType.ROLE_ATTRIBUTE]: RoleAttributeEntity,\n [EntityType.ROLE_PERMISSION]: RolePermissionEntity,\n [EntityType.SCOPE]: ScopeEntity,\n [EntityType.SESSION]: SessionEntity,\n [EntityType.SESSION_TOKEN]: SessionTokenEntity,\n [EntityType.TRUST_ANCHOR]: TrustAnchorEntity,\n [EntityType.USER]: UserEntity,\n [EntityType.USER_ATTRIBUTE]: UserAttributeEntity,\n [EntityType.USER_AUTHENTICATOR]: UserAuthenticatorEntity,\n [EntityType.USER_PERMISSION]: UserPermissionEntity,\n [EntityType.USER_ROLE]: UserRoleEntity,\n};\n\n/**\n * Selectable columns deliberately kept out of a schema's field\n * allow-list. `select: false` columns are skipped automatically (the\n * entity already declares them hidden); everything listed here is a\n * column that IS selectable but must never ride the API projection.\n */\nconst SCHEMA_FIELD_EXCLUSIONS : Record<string, string[]> = {\n // device-internal credential blob (TOTP config, WebAuthn public key +\n // signature counter) — surfaced only through the challenge endpoint's\n // trimmed view.\n [EntityType.USER_AUTHENTICATOR]: ['parameters'],\n};\n\n/**\n * Every selectable column must appear in the schema's field allow-list:\n * rapiq derives the root projection from `fields` (`default` when\n * present, else `allowed`), so a column missing from BOTH silently\n * vanishes from every collection response — no error, just an absent\n * property (`role.builtIn` went missing this way).\n */\nexport function assertSchemaFieldsCoverEntity(\n name: string,\n schema: { fields?: { default?: string[], allowed?: string[] } },\n metadata: EntityMetadata,\n) : void {\n const declared = new Set([\n ...(schema.fields?.default || []),\n ...(schema.fields?.allowed || []),\n ]);\n\n const excluded = new Set(SCHEMA_FIELD_EXCLUSIONS[name] || []);\n const missing = metadata.columns\n .filter((column) => column.isSelect)\n .map((column) => column.propertyName)\n .filter((propertyName) => !declared.has(propertyName) && !excluded.has(propertyName));\n\n if (missing.length > 0) {\n throw new Error(\n `The schema \"${name}\" does not declare the field(s): ${missing.join(', ')}.`,\n );\n }\n}\n\n/**\n * Validate every registered entity schema against its TypeORM\n * metadata (`@rapiq/adapter-typeorm`'s `assertSchemaMatchesEntity`:\n * allow-lists, fields/sort defaults and the filters default condition\n * tree must reference existing columns/relations, AND every declared\n * index must be a leftmost prefix of a real primary key, unique\n * constraint or index) and assert its field allow-list covers every\n * selectable column. Called by `DatabaseModule.setup` once the\n * DataSource is initialized schema/entity drift fails the boot,\n * fail-fast.\n *\n * The index half was an authup-side assert until rapiq 2.1.0 folded it\n * upstream (tada5hi/rapiq#902 closed #898); the local copy is gone,\n * since the upstream check is the same leftmost-prefix rule over the\n * same structures and additionally verifies the index keys are real\n * columns.\n */\nexport function validateEntitySchemas(dataSource: DataSource) : void {\n for (const [name, target] of Object.entries(SCHEMA_ENTITY_TARGETS)) {\n const schema = schemaRegistry.getOrFail(name);\n const metadata = dataSource.getMetadata(target);\n\n assertSchemaMatchesEntity(schema, metadata);\n assertSchemaFieldsCoverEntity(name, schema, metadata);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CA,MAAM6B,wBAAsE;EACvE5B,WAAW6B,SAAS3B;EACpBF,WAAW8B,oBAAoB3B;EAC/BH,WAAW+B,cAAc3B;EACzBJ,WAAWgC,eAAe3B;EAC1BL,WAAWiC,UAAU3B;EACrBN,WAAWkC,QAAQ3B;EACnBP,WAAWmC,oBAAoB1B;EAC/BT,WAAWoC,4BAA4B5B;EACvCR,WAAWqC,iCAAiC3B;EAC5CV,WAAWsC,MAAM3B;EACjBX,WAAWuC,aAAa3B;EACxBZ,WAAWwC,oBAAoB3B;EAC/Bb,WAAWyC,SAAS3B;EACpBd,WAAW0C,QAAQ3B;EACnBf,WAAW2C,OAAO1B;EAClBjB,WAAW4C,iBAAiB5B;EAC5BhB,WAAW6C,kBAAkB3B;EAC7BlB,WAAW8C,QAAQ3B;EACnBnB,WAAW+C,UAAU3B;EACrBpB,WAAWgD,gBAAgB3B;EAC3BrB,WAAWiD,eAAe3B;EAC1BtB,WAAWkD,OAAOzB;EAClBzB,WAAWmD,iBAAiB5B;EAC5BvB,WAAWoD,qBAAqB5B;EAChCxB,WAAWqD,kBAAkB3B;EAC7B1B,WAAWsD,YAAY3B;AAC5B;;;;;;GAQA,MAAM4B,0BAAqD,GAItDvD,WAAWoD,qBAAqB,CAAC,YAAa,EACnD;;;;;;;GASA,SAAgBI,8BACZC,MACAC,QACAC,UAAwB;CAExB,MAAMC,2BAAW,IAAIC,IAAI,CACjBH,GAAAA,OAAOI,QAAQC,WAAW,CAAA,GAC1BL,GAAAA,OAAOI,QAAQE,WAAW,CAAA,CACjC,CAAA;CAED,MAAMC,WAAW,IAAIJ,IAAIN,wBAAwBE,SAAS,CAAA,CAAE;CAC5D,MAAMS,UAAUP,SAASQ,QACpBC,QAAQC,WAAWA,OAAOC,QAAQ,CAAA,CAClCC,KAAKF,WAAWA,OAAOG,YAAY,CAAA,CACnCJ,QAAQI,iBAAiB,CAACZ,SAASa,IAAID,YAAAA,KAAiB,CAACP,SAASQ,IAAID,YAAAA,CAAAA;CAE3E,IAAIN,QAAQQ,SAAS,GACjB,MAAM,IAAIC,MACN,eAAelB,KAAK,mCAAmCS,QAAQU,KAAK,IAAA,EAAM,EAAE;AAGxF;;;;;;;;;;;;;;;;;GAmBA,SAAgBC,sBAAsBC,YAAsB;CACxD,KAAK,MAAM,CAACrB,MAAMsB,WAAWC,OAAOC,QAAQrD,qBAAAA,GAAwB;EAChE,MAAM8B,SAASzD,eAAeiF,UAAUzB,IAAAA;EACxC,MAAME,WAAWmB,WAAWK,YAAYJ,MAAAA;EAExChF,0BAA0B2D,QAAQC,QAAAA;EAClCH,8BAA8BC,MAAMC,QAAQC,QAAAA;CAChD;AACJ"}
@@ -1,5 +1,5 @@
1
1
  import type { App } from 'routup';
2
- import { ClientController, ClientPermissionController, ClientRoleController, ClientScopeController, ConsentController, EventController, IdentityProviderController, IdentityProviderRoleMappingController, KeyController, PermissionController, PermissionPolicyController, PolicyController, RealmController, RoleAttributeController, RoleController, RolePermissionController, ScopeController, SessionController, TrustAnchorController, UserAttributeController, UserAuthenticatorController, UserController, UserPermissionController, UserRoleController } from '../../../../adapters/http/index.ts';
2
+ import { ClientController, ClientPermissionController, ClientRoleController, ClientScopeController, ConsentController, EventController, IdentityProviderAccountController, IdentityProviderController, IdentityProviderRoleMappingController, KeyController, PermissionController, PermissionPolicyController, PolicyController, RealmController, RoleAttributeController, RoleController, RolePermissionController, ScopeController, SessionController, SessionTokenController, TrustAnchorController, UserAttributeController, UserAuthenticatorController, UserController, UserPermissionController, UserRoleController } from '../../../../adapters/http/index.ts';
3
3
  import { AccountController, ActivateController, AuthenticatorChallengeController, AuthorizeController, JwkController, LogoutController, OpenIDController, PasswordForgotController, PasswordResetController, RegisterController, StatusController, TokenController, UserInfoController } from '../../../../adapters/http/controllers/index.ts';
4
4
  import type { IContainer } from 'eldin';
5
5
  import { ConsentService, OAuth2AccessPolicyEvaluator, OAuth2MfaLoginService, PasswordRecoveryService, RegistrationService, UserAuthenticatorService, UserService } from '../../../../core/index.ts';
@@ -35,9 +35,11 @@ export declare class HTTPControllerModule {
35
35
  createScopeController(container: IContainer): ScopeController;
36
36
  createKeyController(container: IContainer): KeyController;
37
37
  createTrustAnchorController(container: IContainer): TrustAnchorController;
38
+ createSessionTokenController(container: IContainer): SessionTokenController;
38
39
  createSessionController(container: IContainer): SessionController;
39
40
  protected createConsentService(container: IContainer): ConsentService;
40
41
  createConsentController(container: IContainer): ConsentController;
42
+ createIdentityProviderAccountController(container: IContainer): IdentityProviderAccountController;
41
43
  private accessPolicyEvaluator?;
42
44
  protected resolveAccessPolicyEvaluator(container: IContainer): OAuth2AccessPolicyEvaluator;
43
45
  private userAuthenticatorService?;
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/app/modules/http/modules/controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/app/modules/http/modules/controller.ts"],"names":[],"mappings":"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"}