@robelest/convex-auth 0.0.4-preview.2 → 0.0.4-preview.21

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 (798) hide show
  1. package/README.md +67 -26
  2. package/dist/authorization/index.d.ts +63 -0
  3. package/dist/authorization/index.d.ts.map +1 -0
  4. package/dist/authorization/index.js +63 -0
  5. package/dist/authorization/index.js.map +1 -0
  6. package/dist/bin.js +6185 -0
  7. package/dist/client/core/types.d.ts +20 -0
  8. package/dist/client/core/types.d.ts.map +1 -0
  9. package/dist/client/index.d.ts +2 -299
  10. package/dist/client/index.d.ts.map +1 -1
  11. package/dist/client/index.js +407 -534
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/component/_generated/api.d.ts +42 -0
  14. package/dist/component/_generated/api.d.ts.map +1 -1
  15. package/dist/component/_generated/api.js.map +1 -1
  16. package/dist/component/_generated/component.d.ts +2546 -90
  17. package/dist/component/_generated/component.d.ts.map +1 -1
  18. package/dist/component/client/core/types.d.ts +2 -0
  19. package/dist/component/client/index.d.ts +2 -0
  20. package/dist/component/convex.config.d.ts +2 -2
  21. package/dist/component/functions.d.ts +11 -9
  22. package/dist/component/functions.d.ts.map +1 -1
  23. package/dist/component/functions.js.map +1 -1
  24. package/dist/component/index.d.ts +7 -11
  25. package/dist/component/index.js +2 -3
  26. package/dist/component/model.d.ts +153 -0
  27. package/dist/component/model.d.ts.map +1 -0
  28. package/dist/component/model.js +349 -0
  29. package/dist/component/model.js.map +1 -0
  30. package/dist/component/providers/anonymous.d.ts +54 -0
  31. package/dist/component/providers/anonymous.d.ts.map +1 -0
  32. package/dist/component/providers/credentials.d.ts +5 -5
  33. package/dist/component/providers/credentials.d.ts.map +1 -1
  34. package/dist/component/providers/device.d.ts +67 -0
  35. package/dist/component/providers/device.d.ts.map +1 -0
  36. package/dist/component/providers/email.d.ts +62 -0
  37. package/dist/component/providers/email.d.ts.map +1 -0
  38. package/dist/component/providers/oauth.d.ts.map +1 -1
  39. package/dist/component/providers/oauth.js.map +1 -1
  40. package/dist/component/providers/passkey.d.ts +57 -0
  41. package/dist/component/providers/passkey.d.ts.map +1 -0
  42. package/dist/component/providers/password.d.ts +88 -0
  43. package/dist/component/providers/password.d.ts.map +1 -0
  44. package/dist/component/providers/phone.d.ts +48 -0
  45. package/dist/component/providers/phone.d.ts.map +1 -0
  46. package/dist/component/providers/sso.d.ts +50 -0
  47. package/dist/component/providers/sso.d.ts.map +1 -0
  48. package/dist/component/providers/totp.d.ts +45 -0
  49. package/dist/component/providers/totp.d.ts.map +1 -0
  50. package/dist/component/public/enterprise/audit.d.ts +73 -0
  51. package/dist/component/public/enterprise/audit.d.ts.map +1 -0
  52. package/dist/component/public/enterprise/audit.js +108 -0
  53. package/dist/component/public/enterprise/audit.js.map +1 -0
  54. package/dist/component/public/enterprise/core.d.ts +176 -0
  55. package/dist/component/public/enterprise/core.d.ts.map +1 -0
  56. package/dist/component/public/enterprise/core.js +292 -0
  57. package/dist/component/public/enterprise/core.js.map +1 -0
  58. package/dist/component/public/enterprise/domains.d.ts +174 -0
  59. package/dist/component/public/enterprise/domains.d.ts.map +1 -0
  60. package/dist/component/public/enterprise/domains.js +271 -0
  61. package/dist/component/public/enterprise/domains.js.map +1 -0
  62. package/dist/component/public/enterprise/scim.d.ts +245 -0
  63. package/dist/component/public/enterprise/scim.d.ts.map +1 -0
  64. package/dist/component/public/enterprise/scim.js +344 -0
  65. package/dist/component/public/enterprise/scim.js.map +1 -0
  66. package/dist/component/public/enterprise/secrets.d.ts +78 -0
  67. package/dist/component/public/enterprise/secrets.d.ts.map +1 -0
  68. package/dist/component/public/enterprise/secrets.js +118 -0
  69. package/dist/component/public/enterprise/secrets.js.map +1 -0
  70. package/dist/component/public/enterprise/webhooks.d.ts +211 -0
  71. package/dist/component/public/enterprise/webhooks.d.ts.map +1 -0
  72. package/dist/component/public/enterprise/webhooks.js +300 -0
  73. package/dist/component/public/enterprise/webhooks.js.map +1 -0
  74. package/dist/component/public/factors/devices.d.ts +157 -0
  75. package/dist/component/public/factors/devices.d.ts.map +1 -0
  76. package/dist/component/public/factors/devices.js +216 -0
  77. package/dist/component/public/factors/devices.js.map +1 -0
  78. package/dist/component/public/factors/passkeys.d.ts +175 -0
  79. package/dist/component/public/factors/passkeys.d.ts.map +1 -0
  80. package/dist/component/public/factors/passkeys.js +238 -0
  81. package/dist/component/public/factors/passkeys.js.map +1 -0
  82. package/dist/component/public/factors/totp.d.ts +189 -0
  83. package/dist/component/public/factors/totp.d.ts.map +1 -0
  84. package/dist/component/public/factors/totp.js +254 -0
  85. package/dist/component/public/factors/totp.js.map +1 -0
  86. package/dist/component/public/groups/core.d.ts +137 -0
  87. package/dist/component/public/groups/core.d.ts.map +1 -0
  88. package/dist/component/public/groups/core.js +321 -0
  89. package/dist/component/public/groups/core.js.map +1 -0
  90. package/dist/component/public/groups/invites.d.ts +217 -0
  91. package/dist/component/public/groups/invites.d.ts.map +1 -0
  92. package/dist/component/public/groups/invites.js +457 -0
  93. package/dist/component/public/groups/invites.js.map +1 -0
  94. package/dist/component/public/groups/members.d.ts +204 -0
  95. package/dist/component/public/groups/members.d.ts.map +1 -0
  96. package/dist/component/public/groups/members.js +355 -0
  97. package/dist/component/public/groups/members.js.map +1 -0
  98. package/dist/component/public/identity/accounts.d.ts +147 -0
  99. package/dist/component/public/identity/accounts.d.ts.map +1 -0
  100. package/dist/component/public/identity/accounts.js +200 -0
  101. package/dist/component/public/identity/accounts.js.map +1 -0
  102. package/dist/component/public/identity/codes.d.ts +104 -0
  103. package/dist/component/public/identity/codes.d.ts.map +1 -0
  104. package/dist/component/public/identity/codes.js +140 -0
  105. package/dist/component/public/identity/codes.js.map +1 -0
  106. package/dist/component/public/identity/sessions.d.ts +128 -0
  107. package/dist/component/public/identity/sessions.d.ts.map +1 -0
  108. package/dist/component/public/identity/sessions.js +192 -0
  109. package/dist/component/public/identity/sessions.js.map +1 -0
  110. package/dist/component/public/identity/tokens.d.ts +169 -0
  111. package/dist/component/public/identity/tokens.d.ts.map +1 -0
  112. package/dist/component/public/identity/tokens.js +227 -0
  113. package/dist/component/public/identity/tokens.js.map +1 -0
  114. package/dist/component/public/identity/users.d.ts +212 -0
  115. package/dist/component/public/identity/users.d.ts.map +1 -0
  116. package/dist/component/public/identity/users.js +311 -0
  117. package/dist/component/public/identity/users.js.map +1 -0
  118. package/dist/component/public/identity/verifiers.d.ts +116 -0
  119. package/dist/component/public/identity/verifiers.d.ts.map +1 -0
  120. package/dist/component/public/identity/verifiers.js +154 -0
  121. package/dist/component/public/identity/verifiers.js.map +1 -0
  122. package/dist/component/public/security/keys.d.ts +209 -0
  123. package/dist/component/public/security/keys.d.ts.map +1 -0
  124. package/dist/component/public/security/keys.js +319 -0
  125. package/dist/component/public/security/keys.js.map +1 -0
  126. package/dist/component/public/security/limits.d.ts +114 -0
  127. package/dist/component/public/security/limits.d.ts.map +1 -0
  128. package/dist/component/public/security/limits.js +169 -0
  129. package/dist/component/public/security/limits.js.map +1 -0
  130. package/dist/component/public.d.ts +24 -271
  131. package/dist/component/public.d.ts.map +1 -1
  132. package/dist/component/public.js +21 -1229
  133. package/dist/component/schema.d.ts +473 -110
  134. package/dist/component/schema.js +162 -73
  135. package/dist/component/schema.js.map +1 -1
  136. package/dist/component/server/auth.d.ts +318 -373
  137. package/dist/component/server/auth.d.ts.map +1 -1
  138. package/dist/component/server/auth.js +204 -123
  139. package/dist/component/server/auth.js.map +1 -1
  140. package/dist/component/server/authError.js +34 -0
  141. package/dist/component/server/authError.js.map +1 -0
  142. package/dist/component/server/{providers.js → config.js} +43 -12
  143. package/dist/component/server/config.js.map +1 -0
  144. package/dist/component/server/cookies.js +3 -0
  145. package/dist/component/server/cookies.js.map +1 -1
  146. package/dist/component/server/core.js +713 -0
  147. package/dist/component/server/core.js.map +1 -0
  148. package/dist/component/server/crypto.js +38 -0
  149. package/dist/component/server/crypto.js.map +1 -0
  150. package/dist/component/server/{implementation/db.js → db.js} +2 -1
  151. package/dist/component/server/db.js.map +1 -0
  152. package/dist/component/server/device.js +109 -0
  153. package/dist/component/server/device.js.map +1 -0
  154. package/dist/component/server/enterprise/config.js +46 -0
  155. package/dist/component/server/enterprise/config.js.map +1 -0
  156. package/dist/component/server/enterprise/domain.js +885 -0
  157. package/dist/component/server/enterprise/domain.js.map +1 -0
  158. package/dist/component/server/enterprise/http.js +766 -0
  159. package/dist/component/server/enterprise/http.js.map +1 -0
  160. package/dist/component/server/enterprise/oidc.js +248 -0
  161. package/dist/component/server/enterprise/oidc.js.map +1 -0
  162. package/dist/component/server/enterprise/policy.js +85 -0
  163. package/dist/component/server/enterprise/policy.js.map +1 -0
  164. package/dist/component/server/enterprise/saml.js +338 -0
  165. package/dist/component/server/enterprise/saml.js.map +1 -0
  166. package/dist/component/server/enterprise/scim.js +97 -0
  167. package/dist/component/server/enterprise/scim.js.map +1 -0
  168. package/dist/component/server/enterprise/shared.js +51 -0
  169. package/dist/component/server/enterprise/shared.js.map +1 -0
  170. package/dist/component/server/errors.d.ts +1 -0
  171. package/dist/component/server/errors.js +24 -16
  172. package/dist/component/server/errors.js.map +1 -1
  173. package/dist/component/server/http.js +288 -0
  174. package/dist/component/server/http.js.map +1 -0
  175. package/dist/component/server/identity.js +13 -0
  176. package/dist/component/server/identity.js.map +1 -0
  177. package/dist/{server/implementation → component/server}/keys.js +9 -31
  178. package/dist/component/server/keys.js.map +1 -0
  179. package/dist/component/server/limits.js +61 -0
  180. package/dist/component/server/limits.js.map +1 -0
  181. package/dist/component/server/mutations/account.js +44 -0
  182. package/dist/component/server/mutations/account.js.map +1 -0
  183. package/dist/component/server/{implementation/mutations → mutations}/code.js +7 -4
  184. package/dist/component/server/mutations/code.js.map +1 -0
  185. package/dist/component/server/mutations/invalidate.js +32 -0
  186. package/dist/component/server/mutations/invalidate.js.map +1 -0
  187. package/dist/component/server/mutations/oauth.js +110 -0
  188. package/dist/component/server/mutations/oauth.js.map +1 -0
  189. package/dist/component/server/mutations/refresh.js +119 -0
  190. package/dist/component/server/mutations/refresh.js.map +1 -0
  191. package/dist/component/server/mutations/register.js +83 -0
  192. package/dist/component/server/mutations/register.js.map +1 -0
  193. package/dist/component/server/mutations/retrieve.js +65 -0
  194. package/dist/component/server/mutations/retrieve.js.map +1 -0
  195. package/dist/component/server/mutations/signature.js +32 -0
  196. package/dist/component/server/mutations/signature.js.map +1 -0
  197. package/dist/component/server/{implementation/mutations → mutations}/signin.js +2 -2
  198. package/dist/component/server/mutations/signin.js.map +1 -0
  199. package/dist/component/server/mutations/signout.js +27 -0
  200. package/dist/component/server/mutations/signout.js.map +1 -0
  201. package/dist/component/server/mutations/store/refs.js +15 -0
  202. package/dist/component/server/mutations/store/refs.js.map +1 -0
  203. package/dist/component/server/mutations/store.js +85 -0
  204. package/dist/component/server/mutations/store.js.map +1 -0
  205. package/dist/component/server/mutations/verifier.js +18 -0
  206. package/dist/component/server/mutations/verifier.js.map +1 -0
  207. package/dist/component/server/mutations/verify.js +98 -0
  208. package/dist/component/server/mutations/verify.js.map +1 -0
  209. package/dist/component/server/oauth.js +106 -60
  210. package/dist/component/server/oauth.js.map +1 -1
  211. package/dist/component/server/passkey.js +328 -0
  212. package/dist/component/server/passkey.js.map +1 -0
  213. package/dist/{server/implementation → component/server}/redirects.js +13 -11
  214. package/dist/component/server/redirects.js.map +1 -0
  215. package/dist/component/server/refresh.js +96 -0
  216. package/dist/component/server/refresh.js.map +1 -0
  217. package/dist/component/server/runtime.d.ts +136 -0
  218. package/dist/component/server/runtime.d.ts.map +1 -0
  219. package/dist/component/server/runtime.js +413 -0
  220. package/dist/component/server/runtime.js.map +1 -0
  221. package/dist/{server/implementation → component/server}/sessions.js +14 -8
  222. package/dist/component/server/sessions.js.map +1 -0
  223. package/dist/component/server/signin.js +201 -0
  224. package/dist/component/server/signin.js.map +1 -0
  225. package/dist/component/server/tokens.js +17 -0
  226. package/dist/component/server/tokens.js.map +1 -0
  227. package/dist/component/server/totp.js +148 -0
  228. package/dist/component/server/totp.js.map +1 -0
  229. package/dist/component/server/types.d.ts +387 -298
  230. package/dist/component/server/types.d.ts.map +1 -1
  231. package/dist/component/server/{implementation/types.js → types.js} +1 -1
  232. package/dist/component/server/types.js.map +1 -0
  233. package/dist/component/server/{implementation/users.js → users.js} +54 -35
  234. package/dist/component/server/users.js.map +1 -0
  235. package/dist/component/server/utils.js +110 -4
  236. package/dist/component/server/utils.js.map +1 -1
  237. package/dist/core/types.d.ts +369 -0
  238. package/dist/core/types.d.ts.map +1 -0
  239. package/dist/factors/device.js +105 -0
  240. package/dist/factors/device.js.map +1 -0
  241. package/dist/factors/passkey.js +181 -0
  242. package/dist/factors/passkey.js.map +1 -0
  243. package/dist/factors/totp.js +122 -0
  244. package/dist/factors/totp.js.map +1 -0
  245. package/dist/providers/anonymous.d.ts +3 -9
  246. package/dist/providers/anonymous.d.ts.map +1 -1
  247. package/dist/providers/anonymous.js +1 -18
  248. package/dist/providers/anonymous.js.map +1 -1
  249. package/dist/providers/credentials.d.ts +8 -10
  250. package/dist/providers/credentials.d.ts.map +1 -1
  251. package/dist/providers/credentials.js +3 -5
  252. package/dist/providers/credentials.js.map +1 -1
  253. package/dist/providers/device.d.ts +18 -10
  254. package/dist/providers/device.d.ts.map +1 -1
  255. package/dist/providers/device.js +4 -8
  256. package/dist/providers/device.js.map +1 -1
  257. package/dist/providers/email.d.ts +50 -23
  258. package/dist/providers/email.d.ts.map +1 -1
  259. package/dist/providers/email.js +58 -34
  260. package/dist/providers/email.js.map +1 -1
  261. package/dist/providers/index.d.ts +7 -3
  262. package/dist/providers/index.js +4 -1
  263. package/dist/providers/oauth.d.ts.map +1 -1
  264. package/dist/providers/oauth.js.map +1 -1
  265. package/dist/providers/passkey.d.ts +12 -9
  266. package/dist/providers/passkey.d.ts.map +1 -1
  267. package/dist/providers/passkey.js +1 -7
  268. package/dist/providers/passkey.js.map +1 -1
  269. package/dist/providers/password.d.ts +6 -12
  270. package/dist/providers/password.d.ts.map +1 -1
  271. package/dist/providers/password.js +189 -89
  272. package/dist/providers/password.js.map +1 -1
  273. package/dist/providers/phone.d.ts +40 -11
  274. package/dist/providers/phone.d.ts.map +1 -1
  275. package/dist/providers/phone.js +52 -21
  276. package/dist/providers/phone.js.map +1 -1
  277. package/dist/providers/sso.d.ts +50 -0
  278. package/dist/providers/sso.d.ts.map +1 -0
  279. package/dist/providers/sso.js +34 -0
  280. package/dist/providers/sso.js.map +1 -0
  281. package/dist/providers/totp.d.ts +12 -9
  282. package/dist/providers/totp.d.ts.map +1 -1
  283. package/dist/providers/totp.js +1 -7
  284. package/dist/providers/totp.js.map +1 -1
  285. package/dist/runtime/browser.js +68 -0
  286. package/dist/runtime/browser.js.map +1 -0
  287. package/dist/runtime/invite.js +51 -0
  288. package/dist/runtime/invite.js.map +1 -0
  289. package/dist/runtime/proxy.js +70 -0
  290. package/dist/runtime/proxy.js.map +1 -0
  291. package/dist/runtime/storage.js +37 -0
  292. package/dist/runtime/storage.js.map +1 -0
  293. package/dist/server/auth.d.ts +335 -370
  294. package/dist/server/auth.d.ts.map +1 -1
  295. package/dist/server/auth.js +204 -123
  296. package/dist/server/auth.js.map +1 -1
  297. package/dist/server/authError.d.ts +46 -0
  298. package/dist/server/authError.d.ts.map +1 -0
  299. package/dist/server/authError.js +34 -0
  300. package/dist/server/authError.js.map +1 -0
  301. package/dist/server/config.d.ts +1 -0
  302. package/dist/server/{providers.js → config.js} +43 -12
  303. package/dist/server/config.js.map +1 -0
  304. package/dist/server/cookies.d.ts +1 -38
  305. package/dist/server/cookies.js +3 -0
  306. package/dist/server/cookies.js.map +1 -1
  307. package/dist/server/core.d.ts +1436 -0
  308. package/dist/server/core.d.ts.map +1 -0
  309. package/dist/server/core.js +713 -0
  310. package/dist/server/core.js.map +1 -0
  311. package/dist/server/crypto.d.ts +8 -0
  312. package/dist/server/crypto.d.ts.map +1 -0
  313. package/dist/server/crypto.js +38 -0
  314. package/dist/server/crypto.js.map +1 -0
  315. package/dist/server/db.d.ts +1 -0
  316. package/dist/server/{implementation/db.js → db.js} +2 -1
  317. package/dist/server/db.js.map +1 -0
  318. package/dist/server/device.d.ts +1 -0
  319. package/dist/server/device.js +109 -0
  320. package/dist/server/device.js.map +1 -0
  321. package/dist/server/enterprise/config.d.ts +1 -0
  322. package/dist/server/enterprise/config.js +46 -0
  323. package/dist/server/enterprise/config.js.map +1 -0
  324. package/dist/server/enterprise/domain.d.ts +409 -0
  325. package/dist/server/enterprise/domain.d.ts.map +1 -0
  326. package/dist/server/enterprise/domain.js +885 -0
  327. package/dist/server/enterprise/domain.js.map +1 -0
  328. package/dist/server/enterprise/http.d.ts +26 -0
  329. package/dist/server/enterprise/http.d.ts.map +1 -0
  330. package/dist/server/enterprise/http.js +766 -0
  331. package/dist/server/enterprise/http.js.map +1 -0
  332. package/dist/server/enterprise/oidc.d.ts +1 -0
  333. package/dist/server/enterprise/oidc.js +248 -0
  334. package/dist/server/enterprise/oidc.js.map +1 -0
  335. package/dist/server/enterprise/policy.d.ts +1 -0
  336. package/dist/server/enterprise/policy.js +85 -0
  337. package/dist/server/enterprise/policy.js.map +1 -0
  338. package/dist/server/enterprise/saml.d.ts +1 -0
  339. package/dist/server/enterprise/saml.js +338 -0
  340. package/dist/server/enterprise/saml.js.map +1 -0
  341. package/dist/server/enterprise/scim.d.ts +1 -0
  342. package/dist/server/enterprise/scim.js +97 -0
  343. package/dist/server/enterprise/scim.js.map +1 -0
  344. package/dist/server/enterprise/shared.d.ts +5 -0
  345. package/dist/server/enterprise/shared.d.ts.map +1 -0
  346. package/dist/server/enterprise/shared.js +51 -0
  347. package/dist/server/enterprise/shared.js.map +1 -0
  348. package/dist/server/enterprise/validators.d.ts +1 -0
  349. package/dist/server/enterprise/validators.js +60 -0
  350. package/dist/server/enterprise/validators.js.map +1 -0
  351. package/dist/server/errors.d.ts +33 -1
  352. package/dist/server/errors.d.ts.map +1 -1
  353. package/dist/server/errors.js +44 -1
  354. package/dist/server/errors.js.map +1 -1
  355. package/dist/server/http.d.ts +59 -0
  356. package/dist/server/http.d.ts.map +1 -0
  357. package/dist/server/http.js +288 -0
  358. package/dist/server/http.js.map +1 -0
  359. package/dist/server/identity.d.ts +1 -0
  360. package/dist/server/identity.js +13 -0
  361. package/dist/server/identity.js.map +1 -0
  362. package/dist/server/index.d.ts +4 -182
  363. package/dist/server/index.js +4 -376
  364. package/dist/server/keys.d.ts +1 -0
  365. package/dist/{component/server/implementation → server}/keys.js +9 -31
  366. package/dist/server/keys.js.map +1 -0
  367. package/dist/server/limits.d.ts +1 -0
  368. package/dist/server/limits.js +61 -0
  369. package/dist/server/limits.js.map +1 -0
  370. package/dist/server/mounts.d.ts +647 -0
  371. package/dist/server/mounts.d.ts.map +1 -0
  372. package/dist/server/mounts.js +643 -0
  373. package/dist/server/mounts.js.map +1 -0
  374. package/dist/server/mutations/account.d.ts +30 -0
  375. package/dist/server/mutations/account.d.ts.map +1 -0
  376. package/dist/server/mutations/account.js +44 -0
  377. package/dist/server/mutations/account.js.map +1 -0
  378. package/dist/server/mutations/code.d.ts +30 -0
  379. package/dist/server/mutations/code.d.ts.map +1 -0
  380. package/dist/server/{implementation/mutations → mutations}/code.js +7 -4
  381. package/dist/server/mutations/code.js.map +1 -0
  382. package/dist/server/mutations/index.d.ts +14 -0
  383. package/dist/server/mutations/index.js +15 -0
  384. package/dist/server/mutations/invalidate.d.ts +20 -0
  385. package/dist/server/mutations/invalidate.d.ts.map +1 -0
  386. package/dist/server/mutations/invalidate.js +32 -0
  387. package/dist/server/mutations/invalidate.js.map +1 -0
  388. package/dist/server/mutations/oauth.d.ts +28 -0
  389. package/dist/server/mutations/oauth.d.ts.map +1 -0
  390. package/dist/server/mutations/oauth.js +110 -0
  391. package/dist/server/mutations/oauth.js.map +1 -0
  392. package/dist/server/mutations/refresh.d.ts +21 -0
  393. package/dist/server/mutations/refresh.d.ts.map +1 -0
  394. package/dist/server/mutations/refresh.js +119 -0
  395. package/dist/server/mutations/refresh.js.map +1 -0
  396. package/dist/server/mutations/register.d.ts +38 -0
  397. package/dist/server/mutations/register.d.ts.map +1 -0
  398. package/dist/server/mutations/register.js +83 -0
  399. package/dist/server/mutations/register.js.map +1 -0
  400. package/dist/server/mutations/retrieve.d.ts +33 -0
  401. package/dist/server/mutations/retrieve.d.ts.map +1 -0
  402. package/dist/server/mutations/retrieve.js +65 -0
  403. package/dist/server/mutations/retrieve.js.map +1 -0
  404. package/dist/server/mutations/signature.d.ts +22 -0
  405. package/dist/server/mutations/signature.d.ts.map +1 -0
  406. package/dist/server/mutations/signature.js +32 -0
  407. package/dist/server/mutations/signature.js.map +1 -0
  408. package/dist/server/mutations/signin.d.ts +22 -0
  409. package/dist/server/mutations/signin.d.ts.map +1 -0
  410. package/dist/server/{implementation/mutations → mutations}/signin.js +2 -2
  411. package/dist/server/mutations/signin.js.map +1 -0
  412. package/dist/server/mutations/signout.d.ts +16 -0
  413. package/dist/server/mutations/signout.d.ts.map +1 -0
  414. package/dist/server/mutations/signout.js +27 -0
  415. package/dist/server/mutations/signout.js.map +1 -0
  416. package/dist/server/mutations/store/refs.d.ts +12 -0
  417. package/dist/server/mutations/store/refs.d.ts.map +1 -0
  418. package/dist/server/mutations/store/refs.js +15 -0
  419. package/dist/server/mutations/store/refs.js.map +1 -0
  420. package/dist/server/mutations/store.d.ts +306 -0
  421. package/dist/server/mutations/store.d.ts.map +1 -0
  422. package/dist/server/mutations/store.js +85 -0
  423. package/dist/server/mutations/store.js.map +1 -0
  424. package/dist/server/mutations/verifier.d.ts +13 -0
  425. package/dist/server/mutations/verifier.d.ts.map +1 -0
  426. package/dist/server/mutations/verifier.js +18 -0
  427. package/dist/server/mutations/verifier.js.map +1 -0
  428. package/dist/server/mutations/verify.d.ts +26 -0
  429. package/dist/server/mutations/verify.d.ts.map +1 -0
  430. package/dist/server/mutations/verify.js +98 -0
  431. package/dist/server/mutations/verify.js.map +1 -0
  432. package/dist/server/oauth.d.ts +1 -48
  433. package/dist/server/oauth.js +107 -64
  434. package/dist/server/oauth.js.map +1 -1
  435. package/dist/server/passkey.d.ts +27 -0
  436. package/dist/server/passkey.d.ts.map +1 -0
  437. package/dist/server/passkey.js +328 -0
  438. package/dist/server/passkey.js.map +1 -0
  439. package/dist/server/redirects.d.ts +1 -0
  440. package/dist/{component/server/implementation → server}/redirects.js +13 -11
  441. package/dist/server/redirects.js.map +1 -0
  442. package/dist/server/refresh.d.ts +1 -0
  443. package/dist/server/refresh.js +96 -0
  444. package/dist/server/refresh.js.map +1 -0
  445. package/dist/server/runtime.d.ts +136 -0
  446. package/dist/server/runtime.d.ts.map +1 -0
  447. package/dist/server/runtime.js +413 -0
  448. package/dist/server/runtime.js.map +1 -0
  449. package/dist/server/sessions.d.ts +1 -0
  450. package/dist/{component/server/implementation → server}/sessions.js +14 -8
  451. package/dist/server/sessions.js.map +1 -0
  452. package/dist/server/signin.d.ts +1 -0
  453. package/dist/server/signin.js +201 -0
  454. package/dist/server/signin.js.map +1 -0
  455. package/dist/server/ssr.d.ts +226 -0
  456. package/dist/server/ssr.d.ts.map +1 -0
  457. package/dist/server/ssr.js +786 -0
  458. package/dist/server/ssr.js.map +1 -0
  459. package/dist/server/templates.d.ts +1 -21
  460. package/dist/server/templates.js +2 -1
  461. package/dist/server/templates.js.map +1 -1
  462. package/dist/server/tokens.d.ts +1 -0
  463. package/dist/server/tokens.js +17 -0
  464. package/dist/server/tokens.js.map +1 -0
  465. package/dist/server/totp.d.ts +1 -0
  466. package/dist/server/totp.js +148 -0
  467. package/dist/server/totp.js.map +1 -0
  468. package/dist/server/types.d.ts +498 -306
  469. package/dist/server/types.d.ts.map +1 -1
  470. package/dist/server/types.js +108 -1
  471. package/dist/server/types.js.map +1 -0
  472. package/dist/server/users.d.ts +1 -0
  473. package/dist/server/{implementation/users.js → users.js} +54 -35
  474. package/dist/server/users.js.map +1 -0
  475. package/dist/server/utils.d.ts +1 -6
  476. package/dist/server/utils.js +110 -4
  477. package/dist/server/utils.js.map +1 -1
  478. package/package.json +49 -46
  479. package/src/authorization/index.ts +83 -0
  480. package/src/cli/bin.ts +5 -0
  481. package/src/cli/command.ts +6 -5
  482. package/src/cli/index.ts +456 -248
  483. package/src/cli/keys.ts +3 -0
  484. package/src/client/core/types.ts +437 -0
  485. package/src/client/factors/device.ts +160 -0
  486. package/src/client/factors/passkey.ts +282 -0
  487. package/src/client/factors/totp.ts +150 -0
  488. package/src/client/index.ts +745 -989
  489. package/src/client/runtime/browser.ts +112 -0
  490. package/src/client/runtime/invite.ts +65 -0
  491. package/src/client/runtime/proxy.ts +111 -0
  492. package/src/client/runtime/storage.ts +79 -0
  493. package/src/component/_generated/api.ts +42 -0
  494. package/src/component/_generated/component.ts +3123 -102
  495. package/src/component/functions.ts +38 -22
  496. package/src/component/index.ts +10 -20
  497. package/src/component/model.ts +449 -0
  498. package/src/component/public/enterprise/audit.ts +120 -0
  499. package/src/component/public/enterprise/core.ts +354 -0
  500. package/src/component/public/enterprise/domains.ts +323 -0
  501. package/src/component/public/enterprise/scim.ts +396 -0
  502. package/src/component/public/enterprise/secrets.ts +132 -0
  503. package/src/component/public/enterprise/webhooks.ts +306 -0
  504. package/src/component/public/factors/devices.ts +223 -0
  505. package/src/component/public/factors/passkeys.ts +242 -0
  506. package/src/component/public/factors/totp.ts +258 -0
  507. package/src/component/public/groups/core.ts +481 -0
  508. package/src/component/public/groups/invites.ts +602 -0
  509. package/src/component/public/groups/members.ts +409 -0
  510. package/src/component/public/identity/accounts.ts +206 -0
  511. package/src/component/public/identity/codes.ts +148 -0
  512. package/src/component/public/identity/sessions.ts +209 -0
  513. package/src/component/public/identity/tokens.ts +250 -0
  514. package/src/component/public/identity/users.ts +354 -0
  515. package/src/component/public/identity/verifiers.ts +157 -0
  516. package/src/component/public/security/keys.ts +365 -0
  517. package/src/component/public/security/limits.ts +173 -0
  518. package/src/component/public.ts +26 -1766
  519. package/src/component/schema.ts +273 -100
  520. package/src/providers/anonymous.ts +10 -20
  521. package/src/providers/credentials.ts +14 -22
  522. package/src/providers/device.ts +3 -14
  523. package/src/providers/email.ts +83 -47
  524. package/src/providers/index.ts +7 -0
  525. package/src/providers/oauth.ts +5 -3
  526. package/src/providers/passkey.ts +0 -13
  527. package/src/providers/password.ts +307 -130
  528. package/src/providers/phone.ts +81 -37
  529. package/src/providers/sso.ts +54 -0
  530. package/src/providers/totp.ts +0 -13
  531. package/src/samlify.d.ts +53 -0
  532. package/src/server/auth.ts +701 -247
  533. package/src/server/authError.ts +44 -0
  534. package/src/server/{providers.ts → config.ts} +84 -15
  535. package/src/server/cookies.ts +8 -1
  536. package/src/server/core.ts +2095 -0
  537. package/src/server/crypto.ts +88 -0
  538. package/src/server/{implementation/db.ts → db.ts} +90 -15
  539. package/src/server/device.ts +221 -0
  540. package/src/server/enterprise/config.ts +51 -0
  541. package/src/server/enterprise/domain.ts +1751 -0
  542. package/src/server/enterprise/http.ts +1324 -0
  543. package/src/server/enterprise/oidc.ts +500 -0
  544. package/src/server/enterprise/policy.ts +128 -0
  545. package/src/server/enterprise/saml.ts +578 -0
  546. package/src/server/enterprise/scim.ts +135 -0
  547. package/src/server/enterprise/shared.ts +134 -0
  548. package/src/server/enterprise/validators.ts +93 -0
  549. package/src/server/errors.ts +130 -119
  550. package/src/server/http.ts +531 -0
  551. package/src/server/identity.ts +18 -0
  552. package/src/server/index.ts +32 -650
  553. package/src/server/{implementation/keys.ts → keys.ts} +16 -44
  554. package/src/server/limits.ts +134 -0
  555. package/src/server/mounts.ts +948 -0
  556. package/src/server/mutations/account.ts +76 -0
  557. package/src/server/{implementation/mutations → mutations}/code.ts +22 -11
  558. package/src/server/mutations/index.ts +13 -0
  559. package/src/server/mutations/invalidate.ts +50 -0
  560. package/src/server/mutations/oauth.ts +237 -0
  561. package/src/server/mutations/refresh.ts +298 -0
  562. package/src/server/mutations/register.ts +200 -0
  563. package/src/server/mutations/retrieve.ts +109 -0
  564. package/src/server/mutations/signature.ts +50 -0
  565. package/src/server/{implementation/mutations → mutations}/signin.ts +9 -7
  566. package/src/server/mutations/signout.ts +43 -0
  567. package/src/server/mutations/store/refs.ts +10 -0
  568. package/src/server/mutations/store.ts +138 -0
  569. package/src/server/mutations/verifier.ts +34 -0
  570. package/src/server/mutations/verify.ts +202 -0
  571. package/src/server/oauth.ts +243 -131
  572. package/src/server/passkey.ts +784 -0
  573. package/src/server/{implementation/redirects.ts → redirects.ts} +21 -16
  574. package/src/server/refresh.ts +222 -0
  575. package/src/server/runtime.ts +880 -0
  576. package/src/server/{implementation/sessions.ts → sessions.ts} +33 -25
  577. package/src/server/signin.ts +438 -0
  578. package/src/server/ssr.ts +1764 -0
  579. package/src/server/templates.ts +8 -3
  580. package/src/server/{implementation/tokens.ts → tokens.ts} +11 -5
  581. package/src/server/totp.ts +349 -0
  582. package/src/server/types.ts +972 -207
  583. package/src/server/{implementation/users.ts → users.ts} +129 -75
  584. package/src/server/utils.ts +192 -5
  585. package/src/test.ts +28 -4
  586. package/dist/bin.cjs +0 -27757
  587. package/dist/component/providers/email.js +0 -47
  588. package/dist/component/providers/email.js.map +0 -1
  589. package/dist/component/public.js.map +0 -1
  590. package/dist/component/server/implementation/db.js.map +0 -1
  591. package/dist/component/server/implementation/device.js +0 -135
  592. package/dist/component/server/implementation/device.js.map +0 -1
  593. package/dist/component/server/implementation/index.d.ts +0 -870
  594. package/dist/component/server/implementation/index.d.ts.map +0 -1
  595. package/dist/component/server/implementation/index.js +0 -610
  596. package/dist/component/server/implementation/index.js.map +0 -1
  597. package/dist/component/server/implementation/keys.js.map +0 -1
  598. package/dist/component/server/implementation/mutations/account.js +0 -39
  599. package/dist/component/server/implementation/mutations/account.js.map +0 -1
  600. package/dist/component/server/implementation/mutations/code.js.map +0 -1
  601. package/dist/component/server/implementation/mutations/index.js +0 -70
  602. package/dist/component/server/implementation/mutations/index.js.map +0 -1
  603. package/dist/component/server/implementation/mutations/invalidate.js +0 -29
  604. package/dist/component/server/implementation/mutations/invalidate.js.map +0 -1
  605. package/dist/component/server/implementation/mutations/oauth.js +0 -51
  606. package/dist/component/server/implementation/mutations/oauth.js.map +0 -1
  607. package/dist/component/server/implementation/mutations/refresh.js +0 -85
  608. package/dist/component/server/implementation/mutations/refresh.js.map +0 -1
  609. package/dist/component/server/implementation/mutations/register.js +0 -65
  610. package/dist/component/server/implementation/mutations/register.js.map +0 -1
  611. package/dist/component/server/implementation/mutations/retrieve.js +0 -50
  612. package/dist/component/server/implementation/mutations/retrieve.js.map +0 -1
  613. package/dist/component/server/implementation/mutations/signature.js +0 -27
  614. package/dist/component/server/implementation/mutations/signature.js.map +0 -1
  615. package/dist/component/server/implementation/mutations/signin.js.map +0 -1
  616. package/dist/component/server/implementation/mutations/signout.js +0 -27
  617. package/dist/component/server/implementation/mutations/signout.js.map +0 -1
  618. package/dist/component/server/implementation/mutations/store.js +0 -12
  619. package/dist/component/server/implementation/mutations/store.js.map +0 -1
  620. package/dist/component/server/implementation/mutations/verifier.js +0 -16
  621. package/dist/component/server/implementation/mutations/verifier.js.map +0 -1
  622. package/dist/component/server/implementation/mutations/verify.js +0 -105
  623. package/dist/component/server/implementation/mutations/verify.js.map +0 -1
  624. package/dist/component/server/implementation/passkey.js +0 -307
  625. package/dist/component/server/implementation/passkey.js.map +0 -1
  626. package/dist/component/server/implementation/provider.js +0 -19
  627. package/dist/component/server/implementation/provider.js.map +0 -1
  628. package/dist/component/server/implementation/ratelimit.js +0 -48
  629. package/dist/component/server/implementation/ratelimit.js.map +0 -1
  630. package/dist/component/server/implementation/redirects.js.map +0 -1
  631. package/dist/component/server/implementation/refresh.js +0 -109
  632. package/dist/component/server/implementation/refresh.js.map +0 -1
  633. package/dist/component/server/implementation/sessions.js.map +0 -1
  634. package/dist/component/server/implementation/signin.js +0 -148
  635. package/dist/component/server/implementation/signin.js.map +0 -1
  636. package/dist/component/server/implementation/tokens.js +0 -15
  637. package/dist/component/server/implementation/tokens.js.map +0 -1
  638. package/dist/component/server/implementation/totp.js +0 -142
  639. package/dist/component/server/implementation/totp.js.map +0 -1
  640. package/dist/component/server/implementation/types.d.ts +0 -42
  641. package/dist/component/server/implementation/types.d.ts.map +0 -1
  642. package/dist/component/server/implementation/types.js.map +0 -1
  643. package/dist/component/server/implementation/users.js.map +0 -1
  644. package/dist/component/server/implementation/utils.js +0 -56
  645. package/dist/component/server/implementation/utils.js.map +0 -1
  646. package/dist/component/server/providers.js.map +0 -1
  647. package/dist/component/server/templates.js +0 -84
  648. package/dist/component/server/templates.js.map +0 -1
  649. package/dist/server/cookies.d.ts.map +0 -1
  650. package/dist/server/implementation/db.d.ts +0 -86
  651. package/dist/server/implementation/db.d.ts.map +0 -1
  652. package/dist/server/implementation/db.js.map +0 -1
  653. package/dist/server/implementation/device.d.ts +0 -30
  654. package/dist/server/implementation/device.d.ts.map +0 -1
  655. package/dist/server/implementation/device.js +0 -135
  656. package/dist/server/implementation/device.js.map +0 -1
  657. package/dist/server/implementation/index.d.ts +0 -870
  658. package/dist/server/implementation/index.d.ts.map +0 -1
  659. package/dist/server/implementation/index.js +0 -610
  660. package/dist/server/implementation/index.js.map +0 -1
  661. package/dist/server/implementation/keys.d.ts +0 -66
  662. package/dist/server/implementation/keys.d.ts.map +0 -1
  663. package/dist/server/implementation/keys.js.map +0 -1
  664. package/dist/server/implementation/mutations/account.d.ts +0 -27
  665. package/dist/server/implementation/mutations/account.d.ts.map +0 -1
  666. package/dist/server/implementation/mutations/account.js +0 -39
  667. package/dist/server/implementation/mutations/account.js.map +0 -1
  668. package/dist/server/implementation/mutations/code.d.ts +0 -29
  669. package/dist/server/implementation/mutations/code.d.ts.map +0 -1
  670. package/dist/server/implementation/mutations/code.js.map +0 -1
  671. package/dist/server/implementation/mutations/index.d.ts +0 -310
  672. package/dist/server/implementation/mutations/index.d.ts.map +0 -1
  673. package/dist/server/implementation/mutations/index.js +0 -70
  674. package/dist/server/implementation/mutations/index.js.map +0 -1
  675. package/dist/server/implementation/mutations/invalidate.d.ts +0 -18
  676. package/dist/server/implementation/mutations/invalidate.d.ts.map +0 -1
  677. package/dist/server/implementation/mutations/invalidate.js +0 -29
  678. package/dist/server/implementation/mutations/invalidate.js.map +0 -1
  679. package/dist/server/implementation/mutations/oauth.d.ts +0 -23
  680. package/dist/server/implementation/mutations/oauth.d.ts.map +0 -1
  681. package/dist/server/implementation/mutations/oauth.js +0 -51
  682. package/dist/server/implementation/mutations/oauth.js.map +0 -1
  683. package/dist/server/implementation/mutations/refresh.d.ts +0 -20
  684. package/dist/server/implementation/mutations/refresh.d.ts.map +0 -1
  685. package/dist/server/implementation/mutations/refresh.js +0 -85
  686. package/dist/server/implementation/mutations/refresh.js.map +0 -1
  687. package/dist/server/implementation/mutations/register.d.ts +0 -37
  688. package/dist/server/implementation/mutations/register.d.ts.map +0 -1
  689. package/dist/server/implementation/mutations/register.js +0 -65
  690. package/dist/server/implementation/mutations/register.js.map +0 -1
  691. package/dist/server/implementation/mutations/retrieve.d.ts +0 -31
  692. package/dist/server/implementation/mutations/retrieve.d.ts.map +0 -1
  693. package/dist/server/implementation/mutations/retrieve.js +0 -50
  694. package/dist/server/implementation/mutations/retrieve.js.map +0 -1
  695. package/dist/server/implementation/mutations/signature.d.ts +0 -19
  696. package/dist/server/implementation/mutations/signature.d.ts.map +0 -1
  697. package/dist/server/implementation/mutations/signature.js +0 -27
  698. package/dist/server/implementation/mutations/signature.js.map +0 -1
  699. package/dist/server/implementation/mutations/signin.d.ts +0 -21
  700. package/dist/server/implementation/mutations/signin.d.ts.map +0 -1
  701. package/dist/server/implementation/mutations/signin.js.map +0 -1
  702. package/dist/server/implementation/mutations/signout.d.ts +0 -14
  703. package/dist/server/implementation/mutations/signout.d.ts.map +0 -1
  704. package/dist/server/implementation/mutations/signout.js +0 -27
  705. package/dist/server/implementation/mutations/signout.js.map +0 -1
  706. package/dist/server/implementation/mutations/store.d.ts +0 -11
  707. package/dist/server/implementation/mutations/store.d.ts.map +0 -1
  708. package/dist/server/implementation/mutations/store.js +0 -12
  709. package/dist/server/implementation/mutations/store.js.map +0 -1
  710. package/dist/server/implementation/mutations/verifier.d.ts +0 -11
  711. package/dist/server/implementation/mutations/verifier.d.ts.map +0 -1
  712. package/dist/server/implementation/mutations/verifier.js +0 -16
  713. package/dist/server/implementation/mutations/verifier.js.map +0 -1
  714. package/dist/server/implementation/mutations/verify.d.ts +0 -25
  715. package/dist/server/implementation/mutations/verify.d.ts.map +0 -1
  716. package/dist/server/implementation/mutations/verify.js +0 -105
  717. package/dist/server/implementation/mutations/verify.js.map +0 -1
  718. package/dist/server/implementation/passkey.d.ts +0 -24
  719. package/dist/server/implementation/passkey.d.ts.map +0 -1
  720. package/dist/server/implementation/passkey.js +0 -307
  721. package/dist/server/implementation/passkey.js.map +0 -1
  722. package/dist/server/implementation/provider.d.ts +0 -10
  723. package/dist/server/implementation/provider.d.ts.map +0 -1
  724. package/dist/server/implementation/provider.js +0 -19
  725. package/dist/server/implementation/provider.js.map +0 -1
  726. package/dist/server/implementation/ratelimit.d.ts +0 -10
  727. package/dist/server/implementation/ratelimit.d.ts.map +0 -1
  728. package/dist/server/implementation/ratelimit.js +0 -48
  729. package/dist/server/implementation/ratelimit.js.map +0 -1
  730. package/dist/server/implementation/redirects.d.ts +0 -10
  731. package/dist/server/implementation/redirects.d.ts.map +0 -1
  732. package/dist/server/implementation/redirects.js.map +0 -1
  733. package/dist/server/implementation/refresh.d.ts +0 -37
  734. package/dist/server/implementation/refresh.d.ts.map +0 -1
  735. package/dist/server/implementation/refresh.js +0 -109
  736. package/dist/server/implementation/refresh.js.map +0 -1
  737. package/dist/server/implementation/sessions.d.ts +0 -29
  738. package/dist/server/implementation/sessions.d.ts.map +0 -1
  739. package/dist/server/implementation/sessions.js.map +0 -1
  740. package/dist/server/implementation/signin.d.ts +0 -55
  741. package/dist/server/implementation/signin.d.ts.map +0 -1
  742. package/dist/server/implementation/signin.js +0 -148
  743. package/dist/server/implementation/signin.js.map +0 -1
  744. package/dist/server/implementation/tokens.d.ts +0 -11
  745. package/dist/server/implementation/tokens.d.ts.map +0 -1
  746. package/dist/server/implementation/tokens.js +0 -15
  747. package/dist/server/implementation/tokens.js.map +0 -1
  748. package/dist/server/implementation/totp.d.ts +0 -31
  749. package/dist/server/implementation/totp.d.ts.map +0 -1
  750. package/dist/server/implementation/totp.js +0 -142
  751. package/dist/server/implementation/totp.js.map +0 -1
  752. package/dist/server/implementation/types.d.ts +0 -189
  753. package/dist/server/implementation/types.d.ts.map +0 -1
  754. package/dist/server/implementation/types.js +0 -97
  755. package/dist/server/implementation/types.js.map +0 -1
  756. package/dist/server/implementation/users.d.ts +0 -30
  757. package/dist/server/implementation/users.d.ts.map +0 -1
  758. package/dist/server/implementation/users.js.map +0 -1
  759. package/dist/server/implementation/utils.d.ts +0 -19
  760. package/dist/server/implementation/utils.d.ts.map +0 -1
  761. package/dist/server/implementation/utils.js +0 -56
  762. package/dist/server/implementation/utils.js.map +0 -1
  763. package/dist/server/index.d.ts.map +0 -1
  764. package/dist/server/index.js.map +0 -1
  765. package/dist/server/oauth.d.ts.map +0 -1
  766. package/dist/server/providers.d.ts +0 -72
  767. package/dist/server/providers.d.ts.map +0 -1
  768. package/dist/server/providers.js.map +0 -1
  769. package/dist/server/templates.d.ts.map +0 -1
  770. package/dist/server/utils.d.ts.map +0 -1
  771. package/dist/server/version.d.ts +0 -5
  772. package/dist/server/version.d.ts.map +0 -1
  773. package/dist/server/version.js +0 -6
  774. package/dist/server/version.js.map +0 -1
  775. package/src/cli/utils.ts +0 -248
  776. package/src/server/implementation/device.ts +0 -307
  777. package/src/server/implementation/index.ts +0 -1583
  778. package/src/server/implementation/mutations/account.ts +0 -50
  779. package/src/server/implementation/mutations/index.ts +0 -157
  780. package/src/server/implementation/mutations/invalidate.ts +0 -42
  781. package/src/server/implementation/mutations/oauth.ts +0 -73
  782. package/src/server/implementation/mutations/refresh.ts +0 -175
  783. package/src/server/implementation/mutations/register.ts +0 -100
  784. package/src/server/implementation/mutations/retrieve.ts +0 -79
  785. package/src/server/implementation/mutations/signature.ts +0 -39
  786. package/src/server/implementation/mutations/signout.ts +0 -35
  787. package/src/server/implementation/mutations/store.ts +0 -7
  788. package/src/server/implementation/mutations/verifier.ts +0 -24
  789. package/src/server/implementation/mutations/verify.ts +0 -194
  790. package/src/server/implementation/passkey.ts +0 -620
  791. package/src/server/implementation/provider.ts +0 -36
  792. package/src/server/implementation/ratelimit.ts +0 -79
  793. package/src/server/implementation/refresh.ts +0 -172
  794. package/src/server/implementation/signin.ts +0 -296
  795. package/src/server/implementation/totp.ts +0 -342
  796. package/src/server/implementation/types.ts +0 -444
  797. package/src/server/implementation/utils.ts +0 -91
  798. package/src/server/version.ts +0 -2
@@ -0,0 +1,1751 @@
1
+ import { GenericActionCtx, GenericDataModel } from "convex/server";
2
+
3
+ import { Fx } from "@robelest/fx";
4
+
5
+ import { AuthError } from "../authError";
6
+ import type { EnterprisePolicyPatch } from "../types";
7
+
8
+ type ComponentCtx = Pick<
9
+ GenericActionCtx<GenericDataModel>,
10
+ "runQuery" | "runMutation"
11
+ >;
12
+ type ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, "runQuery">;
13
+
14
+ /**
15
+ * Build the enterprise and SSO management domain.
16
+ */
17
+ export function createEnterpriseDomain(deps: any) {
18
+ const {
19
+ config,
20
+ normalizeEnterprisePolicy,
21
+ normalizeDomain,
22
+ getEnterpriseSecret,
23
+ loadEnterpriseOrThrow,
24
+ validateEnterprisePolicy,
25
+ recordEnterpriseAuditEvent,
26
+ emitEnterpriseWebhookDeliveries,
27
+ enterpriseNotFoundError,
28
+ ENTERPRISE_OIDC_CLIENT_SECRET_KIND,
29
+ requireEnv,
30
+ generateRandomString,
31
+ INVITE_TOKEN_ALPHABET,
32
+ sha256,
33
+ encryptSecret,
34
+ upsertProtocolConfig,
35
+ parseSamlIdpMetadata,
36
+ createServiceProviderMetadata,
37
+ getSamlServiceProviderOptions,
38
+ getPublicOidcConfig,
39
+ withOidcSecretState,
40
+ getOidcConfig,
41
+ getEnterpriseOidcUrls,
42
+ enterpriseOidcProviderId,
43
+ getPolicyFromEnterprise,
44
+ patchEnterprisePolicy,
45
+ } = deps;
46
+
47
+ const ENTERPRISE_DOMAIN_VERIFICATION_PREFIX = "_convex-auth-verification";
48
+ const ENTERPRISE_DOMAIN_VERIFICATION_TTL_MS = 1000 * 60 * 60 * 24 * 7;
49
+
50
+ const toDomainSummary = (domain: {
51
+ _id: string;
52
+ domain: string;
53
+ isPrimary: boolean;
54
+ verifiedAt?: number;
55
+ }) => ({
56
+ domainId: domain._id,
57
+ domain: domain.domain,
58
+ isPrimary: domain.isPrimary,
59
+ verified: domain.verifiedAt !== undefined,
60
+ verifiedAt: domain.verifiedAt ?? null,
61
+ });
62
+
63
+ const getDomainVerificationRecordName = (domain: string) =>
64
+ `${ENTERPRISE_DOMAIN_VERIFICATION_PREFIX}.${normalizeDomain(domain)}`;
65
+
66
+ const parseTxtAnswer = (value: string) => {
67
+ const quoted = [...value.matchAll(/"([^"]*)"/g)].map((match) => match[1]);
68
+ if (quoted.length > 0) {
69
+ return quoted.join("");
70
+ }
71
+ return value.replace(/^"|"$/g, "").trim();
72
+ };
73
+
74
+ const resolveTxtValues = async (recordName: string) => {
75
+ const url = new URL("https://dns.google/resolve");
76
+ url.searchParams.set("name", recordName);
77
+ url.searchParams.set("type", "TXT");
78
+
79
+ const response = await fetch(url, {
80
+ headers: { accept: "application/json" },
81
+ });
82
+ if (!response.ok) {
83
+ throw new Error(`DNS TXT lookup failed with status ${response.status}.`);
84
+ }
85
+ const data = (await response.json()) as {
86
+ Answer?: Array<{ data?: string }>;
87
+ };
88
+ return (data.Answer ?? [])
89
+ .map((answer) =>
90
+ typeof answer.data === "string" ? parseTxtAnswer(answer.data) : null,
91
+ )
92
+ .filter((value): value is string => value !== null && value.length > 0);
93
+ };
94
+
95
+ return {
96
+ connection: {
97
+ create: async (
98
+ ctx: ComponentCtx,
99
+ data: {
100
+ groupId: string;
101
+ slug?: string;
102
+ name?: string;
103
+ status?: "draft" | "active" | "disabled";
104
+ policy?: EnterprisePolicyPatch;
105
+ config?: Record<string, unknown>;
106
+ extend?: Record<string, unknown>;
107
+ },
108
+ ): Promise<{ ok: true; enterpriseId: string; groupId: string }> => {
109
+ const enterpriseId = (await ctx.runMutation(
110
+ config.component.public.enterpriseCreate,
111
+ {
112
+ ...data,
113
+ policy: normalizeEnterprisePolicy(data.policy),
114
+ },
115
+ )) as string;
116
+ return {
117
+ ok: true,
118
+ enterpriseId,
119
+ groupId: data.groupId,
120
+ };
121
+ },
122
+ get: async (ctx: ComponentReadCtx, enterpriseId: string) => {
123
+ return await ctx.runQuery(config.component.public.enterpriseGet, {
124
+ enterpriseId,
125
+ });
126
+ },
127
+ getByGroup: async (ctx: ComponentReadCtx, groupId: string) => {
128
+ return await ctx.runQuery(
129
+ config.component.public.enterpriseGetByGroup,
130
+ {
131
+ groupId,
132
+ },
133
+ );
134
+ },
135
+ getByDomain: async (ctx: ComponentReadCtx, domain: string) => {
136
+ return await ctx.runQuery(
137
+ config.component.public.enterpriseGetByDomain,
138
+ {
139
+ domain: normalizeDomain(domain),
140
+ },
141
+ );
142
+ },
143
+ list: async (
144
+ ctx: ComponentReadCtx,
145
+ opts?: {
146
+ where?: {
147
+ groupId?: string;
148
+ slug?: string;
149
+ status?: "draft" | "active" | "disabled";
150
+ };
151
+ limit?: number;
152
+ cursor?: string | null;
153
+ orderBy?: "_creationTime" | "name" | "slug" | "status";
154
+ order?: "asc" | "desc";
155
+ },
156
+ ) => {
157
+ return await ctx.runQuery(config.component.public.enterpriseList, {
158
+ where: opts?.where,
159
+ limit: opts?.limit,
160
+ cursor: opts?.cursor,
161
+ orderBy: opts?.orderBy,
162
+ order: opts?.order,
163
+ });
164
+ },
165
+ update: async (
166
+ ctx: ComponentCtx,
167
+ enterpriseId: string,
168
+ data: Record<string, unknown>,
169
+ ) => {
170
+ await ctx.runMutation(config.component.public.enterpriseUpdate, {
171
+ enterpriseId,
172
+ data,
173
+ });
174
+ return { ok: true as const, enterpriseId };
175
+ },
176
+ delete: async (ctx: ComponentCtx, enterpriseId: string) => {
177
+ await ctx.runMutation(config.component.public.enterpriseDelete, {
178
+ enterpriseId,
179
+ });
180
+ return { ok: true as const, enterpriseId };
181
+ },
182
+ /**
183
+ * Aggregate readiness status across all configured protocols for an
184
+ * enterprise connection.
185
+ *
186
+ * Returns a structured result indicating whether the connection is
187
+ * ready, with per-protocol checks so callers can surface actionable
188
+ * diagnostics without running full network validation.
189
+ */
190
+ status: async (ctx: ComponentReadCtx, enterpriseId: string) => {
191
+ const enterprise = await ctx.runQuery(
192
+ config.component.public.enterpriseGet,
193
+ { enterpriseId },
194
+ );
195
+ if (!enterprise) {
196
+ throw new AuthError(
197
+ "INVALID_PARAMETERS",
198
+ enterpriseNotFoundError,
199
+ ).toConvexError();
200
+ }
201
+ const policy = getPolicyFromEnterprise(enterprise);
202
+ const protocols = enterprise.config?.protocols ?? {};
203
+ const oidcConfig = protocols.oidc;
204
+ const oidcSecret = await getEnterpriseSecret(
205
+ ctx,
206
+ enterprise._id,
207
+ ENTERPRISE_OIDC_CLIENT_SECRET_KIND,
208
+ );
209
+ const samlConfig = protocols.saml;
210
+ const scimConfig = await ctx.runQuery(
211
+ config.component.public.enterpriseScimConfigGetByEnterprise,
212
+ { enterpriseId },
213
+ );
214
+ const domains = await ctx.runQuery(
215
+ config.component.public.enterpriseDomainList,
216
+ { enterpriseId },
217
+ );
218
+
219
+ const oidcReady =
220
+ oidcConfig?.enabled === true &&
221
+ typeof oidcConfig?.clientId === "string" &&
222
+ oidcConfig.clientId.length > 0 &&
223
+ oidcSecret !== null &&
224
+ (typeof oidcConfig?.issuer === "string" ||
225
+ typeof oidcConfig?.discoveryUrl === "string");
226
+ const samlReady =
227
+ samlConfig?.enabled === true &&
228
+ typeof samlConfig?.idp?.entityId === "string";
229
+ const scimReady =
230
+ scimConfig !== null &&
231
+ scimConfig !== undefined &&
232
+ (scimConfig as any).status === "active";
233
+
234
+ const ready =
235
+ enterprise.status === "active" && (oidcReady || samlReady);
236
+
237
+ return {
238
+ enterpriseId: enterprise._id,
239
+ status: enterprise.status,
240
+ ready,
241
+ domainCount: (domains as unknown[]).length,
242
+ protocols: {
243
+ oidc: {
244
+ configured: oidcReady,
245
+ ready: oidcReady,
246
+ clientId: oidcConfig?.clientId ?? null,
247
+ issuer: oidcConfig?.issuer ?? oidcConfig?.discoveryUrl ?? null,
248
+ },
249
+ saml: {
250
+ configured: samlReady,
251
+ ready: samlReady,
252
+ entityId: samlConfig?.idp?.entityId ?? null,
253
+ },
254
+ scim: {
255
+ configured: scimReady,
256
+ ready: scimReady,
257
+ basePath: scimConfig?.basePath ?? null,
258
+ deprovisionMode: policy.provisioning.deprovision.mode,
259
+ },
260
+ },
261
+ };
262
+ },
263
+ },
264
+ domain: {
265
+ add: async (
266
+ ctx: ComponentCtx,
267
+ data: {
268
+ enterpriseId: string;
269
+ groupId: string;
270
+ domain: string;
271
+ isPrimary?: boolean;
272
+ },
273
+ ): Promise<string> => {
274
+ return (await ctx.runMutation(
275
+ config.component.public.enterpriseDomainAdd,
276
+ {
277
+ ...data,
278
+ domain: normalizeDomain(data.domain),
279
+ },
280
+ )) as string;
281
+ },
282
+ list: async (ctx: ComponentReadCtx, enterpriseId: string) => {
283
+ return await ctx.runQuery(
284
+ config.component.public.enterpriseDomainList,
285
+ {
286
+ enterpriseId,
287
+ },
288
+ );
289
+ },
290
+ validate: async (ctx: ComponentReadCtx, enterpriseId: string) => {
291
+ const enterprise = await ctx.runQuery(
292
+ config.component.public.enterpriseGet,
293
+ { enterpriseId },
294
+ );
295
+ if (enterprise === null) {
296
+ throw new AuthError(
297
+ "INVALID_PARAMETERS",
298
+ enterpriseNotFoundError,
299
+ ).toConvexError();
300
+ }
301
+
302
+ const domains = await ctx.runQuery(
303
+ config.component.public.enterpriseDomainList,
304
+ { enterpriseId },
305
+ );
306
+ const primaryDomains = domains.filter(
307
+ (domain: (typeof domains)[number]) => domain.isPrimary,
308
+ );
309
+ const verifiedDomains = domains.filter(
310
+ (domain: (typeof domains)[number]) => domain.verifiedAt !== undefined,
311
+ );
312
+
313
+ const warnings: string[] = [];
314
+ if (domains.length === 0) {
315
+ warnings.push("No domains configured.");
316
+ }
317
+ if (primaryDomains.length === 0 && domains.length > 0) {
318
+ warnings.push("No primary domain configured.");
319
+ }
320
+ if (primaryDomains.length > 1) {
321
+ warnings.push("Multiple primary domains configured.");
322
+ }
323
+ if (verifiedDomains.length === 0 && domains.length > 0) {
324
+ warnings.push("No verified domains yet.");
325
+ }
326
+
327
+ return {
328
+ enterpriseId,
329
+ ready:
330
+ enterprise.status === "active" &&
331
+ domains.length > 0 &&
332
+ primaryDomains.length === 1 &&
333
+ verifiedDomains.length > 0,
334
+ summary: {
335
+ domainCount: domains.length,
336
+ primaryCount: primaryDomains.length,
337
+ verifiedCount: verifiedDomains.length,
338
+ },
339
+ domains: domains.map((domain: (typeof domains)[number]) =>
340
+ toDomainSummary(domain),
341
+ ),
342
+ warnings,
343
+ };
344
+ },
345
+ remove: async (ctx: ComponentCtx, domainId: string) => {
346
+ await ctx.runMutation(config.component.public.enterpriseDomainDelete, {
347
+ domainId,
348
+ });
349
+ },
350
+ verification: {
351
+ request: async (
352
+ ctx: ComponentCtx,
353
+ args: { enterpriseId: string; domain: string },
354
+ ) => {
355
+ const enterprise = await loadEnterpriseOrThrow(
356
+ ctx,
357
+ args.enterpriseId,
358
+ );
359
+ const normalizedDomain = normalizeDomain(args.domain);
360
+ const domains = await ctx.runQuery(
361
+ config.component.public.enterpriseDomainList,
362
+ { enterpriseId: enterprise._id },
363
+ );
364
+ const domain = domains.find(
365
+ (entry: (typeof domains)[number]) =>
366
+ entry.domain === normalizedDomain,
367
+ );
368
+ if (!domain) {
369
+ throw new AuthError(
370
+ "INVALID_PARAMETERS",
371
+ "Domain is not attached to this enterprise.",
372
+ ).toConvexError();
373
+ }
374
+
375
+ const requestedAt = Date.now();
376
+ const expiresAt = requestedAt + ENTERPRISE_DOMAIN_VERIFICATION_TTL_MS;
377
+ const token = generateRandomString(32, INVITE_TOKEN_ALPHABET);
378
+ const tokenHash = await sha256(token);
379
+ const recordName = getDomainVerificationRecordName(normalizedDomain);
380
+
381
+ await ctx.runMutation(
382
+ config.component.public.enterpriseDomainVerificationUpsert,
383
+ {
384
+ enterpriseId: enterprise._id,
385
+ groupId: enterprise.groupId,
386
+ domainId: domain._id,
387
+ domain: normalizedDomain,
388
+ recordName,
389
+ token,
390
+ tokenHash,
391
+ requestedAt,
392
+ expiresAt,
393
+ },
394
+ );
395
+
396
+ await recordEnterpriseAuditEvent(ctx, {
397
+ enterpriseId: enterprise._id,
398
+ groupId: enterprise.groupId,
399
+ eventType: "enterprise.domain.verification_requested",
400
+ actorType: "system",
401
+ subjectType: "enterprise_domain",
402
+ subjectId: domain._id,
403
+ ok: true,
404
+ metadata: { domain: normalizedDomain, recordName, expiresAt },
405
+ });
406
+
407
+ return {
408
+ ok: true as const,
409
+ enterpriseId: enterprise._id,
410
+ domain: normalizedDomain,
411
+ requestedAt,
412
+ expiresAt,
413
+ challenge: {
414
+ recordType: "TXT" as const,
415
+ recordName,
416
+ recordValue: token,
417
+ },
418
+ };
419
+ },
420
+ confirm: async (
421
+ ctx: ComponentCtx,
422
+ args: { enterpriseId: string; domain: string },
423
+ ) => {
424
+ const enterprise = await loadEnterpriseOrThrow(
425
+ ctx,
426
+ args.enterpriseId,
427
+ );
428
+ const normalizedDomain = normalizeDomain(args.domain);
429
+ const domains = await ctx.runQuery(
430
+ config.component.public.enterpriseDomainList,
431
+ { enterpriseId: enterprise._id },
432
+ );
433
+ const domain = domains.find(
434
+ (entry: (typeof domains)[number]) =>
435
+ entry.domain === normalizedDomain,
436
+ );
437
+ if (!domain) {
438
+ throw new AuthError(
439
+ "INVALID_PARAMETERS",
440
+ "Domain is not attached to this enterprise.",
441
+ ).toConvexError();
442
+ }
443
+
444
+ if (domain.verifiedAt !== undefined) {
445
+ return {
446
+ ok: true,
447
+ enterpriseId: enterprise._id,
448
+ domain: normalizedDomain,
449
+ verifiedAt: domain.verifiedAt,
450
+ checks: [
451
+ {
452
+ name: "domain_verified",
453
+ ok: true,
454
+ message: "Domain is already verified.",
455
+ },
456
+ ],
457
+ };
458
+ }
459
+
460
+ const verification = await ctx.runQuery(
461
+ config.component.public.enterpriseDomainVerificationGet,
462
+ { domainId: domain._id },
463
+ );
464
+ const checks: Array<{ name: string; ok: boolean; message?: string }> =
465
+ [];
466
+ if (!verification) {
467
+ checks.push({
468
+ name: "verification_requested",
469
+ ok: false,
470
+ message: "No active domain verification challenge exists.",
471
+ });
472
+ return {
473
+ ok: false,
474
+ enterpriseId: enterprise._id,
475
+ domain: normalizedDomain,
476
+ checks,
477
+ };
478
+ }
479
+
480
+ checks.push({ name: "verification_requested", ok: true });
481
+
482
+ if (verification.expiresAt < Date.now()) {
483
+ await ctx.runMutation(
484
+ config.component.public.enterpriseDomainVerificationDelete,
485
+ { domainId: domain._id },
486
+ );
487
+ checks.push({
488
+ name: "challenge_active",
489
+ ok: false,
490
+ message: "The verification challenge expired. Request a new one.",
491
+ });
492
+ return {
493
+ ok: false,
494
+ enterpriseId: enterprise._id,
495
+ domain: normalizedDomain,
496
+ checks,
497
+ };
498
+ }
499
+
500
+ checks.push({ name: "challenge_active", ok: true });
501
+
502
+ let txtValues: string[];
503
+ try {
504
+ txtValues = await resolveTxtValues(verification.recordName);
505
+ } catch (error) {
506
+ throw new AuthError(
507
+ "INTERNAL_ERROR",
508
+ error instanceof Error
509
+ ? error.message
510
+ : "Failed to resolve DNS TXT records.",
511
+ ).toConvexError();
512
+ }
513
+
514
+ checks.push({
515
+ name: "dns_record_present",
516
+ ok: txtValues.length > 0,
517
+ message:
518
+ txtValues.length > 0
519
+ ? undefined
520
+ : `No TXT records found at ${verification.recordName}.`,
521
+ });
522
+
523
+ const matches = txtValues.includes(verification.token);
524
+ checks.push({
525
+ name: "dns_record_matches",
526
+ ok: matches,
527
+ message: matches
528
+ ? undefined
529
+ : `TXT record at ${verification.recordName} does not match the expected value.`,
530
+ });
531
+
532
+ if (!checks.every((check) => check.ok)) {
533
+ return {
534
+ ok: false,
535
+ enterpriseId: enterprise._id,
536
+ domain: normalizedDomain,
537
+ checks,
538
+ };
539
+ }
540
+
541
+ const verifiedAt = Date.now();
542
+ await ctx.runMutation(
543
+ config.component.public.enterpriseDomainVerify,
544
+ {
545
+ domainId: domain._id,
546
+ verifiedAt,
547
+ },
548
+ );
549
+
550
+ await recordEnterpriseAuditEvent(ctx, {
551
+ enterpriseId: enterprise._id,
552
+ groupId: enterprise.groupId,
553
+ eventType: "enterprise.domain.verified",
554
+ actorType: "system",
555
+ subjectType: "enterprise_domain",
556
+ subjectId: domain._id,
557
+ ok: true,
558
+ metadata: { domain: normalizedDomain, verifiedAt },
559
+ });
560
+
561
+ return {
562
+ ok: true,
563
+ enterpriseId: enterprise._id,
564
+ domain: normalizedDomain,
565
+ verifiedAt,
566
+ checks,
567
+ };
568
+ },
569
+ },
570
+ },
571
+ saml: {
572
+ configure: async <DataModel extends GenericDataModel>(
573
+ ctx: GenericActionCtx<DataModel>,
574
+ data: {
575
+ enterpriseId: string;
576
+ metadataXml?: string;
577
+ metadataUrl?: string;
578
+ domains?: string[];
579
+ signAuthnRequests?: boolean;
580
+ attributeMapping?: {
581
+ subject?: string;
582
+ email?: string;
583
+ name?: string;
584
+ firstName?: string;
585
+ lastName?: string;
586
+ };
587
+ sp?: {
588
+ entityId?: string;
589
+ acsUrl?: string;
590
+ sloUrl?: string;
591
+ signingCert?: string | string[];
592
+ encryptCert?: string | string[];
593
+ privateKey?: string;
594
+ privateKeyPass?: string;
595
+ encPrivateKey?: string;
596
+ encPrivateKeyPass?: string;
597
+ };
598
+ },
599
+ ) => {
600
+ return await Fx.run(
601
+ Fx.gen(function* () {
602
+ const enterprise = yield* Fx.from({
603
+ ok: () =>
604
+ ctx.runQuery(config.component.public.enterpriseGet, {
605
+ enterpriseId: data.enterpriseId,
606
+ }),
607
+ err: () =>
608
+ new AuthError("INTERNAL_ERROR", "Failed to load enterprise."),
609
+ }).pipe(
610
+ Fx.chain((ent) =>
611
+ ent === null
612
+ ? Fx.fail(
613
+ new AuthError(
614
+ "INVALID_PARAMETERS",
615
+ enterpriseNotFoundError,
616
+ ),
617
+ )
618
+ : Fx.succeed(ent),
619
+ ),
620
+ );
621
+ const metadataXml = yield* data.metadataXml
622
+ ? Fx.succeed(data.metadataXml)
623
+ : data.metadataUrl
624
+ ? Fx.defer(() =>
625
+ Fx.from({
626
+ ok: async () => {
627
+ const response = await fetch(data.metadataUrl!);
628
+ if (!response.ok) {
629
+ throw new Error(
630
+ `Failed to fetch SAML metadata: ${response.status}`,
631
+ );
632
+ }
633
+ return await response.text();
634
+ },
635
+ err: (error) =>
636
+ new AuthError(
637
+ "INVALID_PARAMETERS",
638
+ error instanceof Error
639
+ ? error.message
640
+ : "Failed to fetch SAML metadata",
641
+ ),
642
+ }),
643
+ ).pipe(
644
+ Fx.timeout(10_000),
645
+ Fx.retry(
646
+ Fx.retry.compose(
647
+ Fx.retry.jittered(Fx.retry.exponential(200)),
648
+ Fx.retry.recurs(2),
649
+ ),
650
+ ),
651
+ Fx.recover((error) =>
652
+ Fx.fail(
653
+ new AuthError(
654
+ "INVALID_PARAMETERS",
655
+ error instanceof Error
656
+ ? error.message
657
+ : "Failed to fetch SAML metadata",
658
+ ),
659
+ ),
660
+ ),
661
+ )
662
+ : Fx.fail(
663
+ new AuthError(
664
+ "INVALID_PARAMETERS",
665
+ "SAML registration requires metadataXml or metadataUrl.",
666
+ ),
667
+ );
668
+
669
+ const parsed = yield* Fx.from({
670
+ ok: () => parseSamlIdpMetadata(metadataXml),
671
+ err: () =>
672
+ new AuthError(
673
+ "INVALID_PARAMETERS",
674
+ "Failed to parse SAML metadata.",
675
+ ),
676
+ });
677
+
678
+ const baseConfig = upsertProtocolConfig(enterprise.config, "saml", {
679
+ enabled: true,
680
+ idp: {
681
+ metadataXml,
682
+ ...parsed,
683
+ },
684
+ sp: data.sp,
685
+ signAuthnRequests:
686
+ data.signAuthnRequests ?? parsed.wantsSignedAuthnRequests,
687
+ attributeMapping: data.attributeMapping,
688
+ });
689
+ const normalizedDomains = data.domains?.map(normalizeDomain);
690
+ const nextConfig = normalizedDomains
691
+ ? { ...baseConfig, domains: normalizedDomains }
692
+ : baseConfig;
693
+
694
+ yield* Fx.from({
695
+ ok: () =>
696
+ ctx.runMutation(config.component.public.enterpriseUpdate, {
697
+ enterpriseId: enterprise._id,
698
+ data: {
699
+ status: "active",
700
+ config: nextConfig,
701
+ },
702
+ }),
703
+ err: () =>
704
+ new AuthError(
705
+ "INTERNAL_ERROR",
706
+ "Failed to persist SAML registration.",
707
+ ),
708
+ });
709
+
710
+ if (normalizedDomains) {
711
+ for (const [index, domain] of normalizedDomains.entries()) {
712
+ yield* Fx.from({
713
+ ok: () =>
714
+ ctx.runMutation(
715
+ config.component.public.enterpriseDomainAdd,
716
+ {
717
+ enterpriseId: enterprise._id,
718
+ groupId: enterprise.groupId,
719
+ domain,
720
+ isPrimary: index === 0,
721
+ },
722
+ ),
723
+ err: () =>
724
+ new AuthError(
725
+ "INTERNAL_ERROR",
726
+ "Failed to persist enterprise domain.",
727
+ ),
728
+ });
729
+ }
730
+ }
731
+
732
+ yield* Fx.from({
733
+ ok: () =>
734
+ recordEnterpriseAuditEvent(ctx, {
735
+ enterpriseId: enterprise._id,
736
+ groupId: enterprise.groupId,
737
+ eventType: "enterprise.saml.registered",
738
+ actorType: "system",
739
+ subjectType: "enterprise_saml",
740
+ subjectId: enterprise._id,
741
+ ok: true,
742
+ metadata: {
743
+ metadataUrl: data.metadataUrl,
744
+ domains: normalizedDomains,
745
+ },
746
+ }),
747
+ err: () =>
748
+ new AuthError(
749
+ "INTERNAL_ERROR",
750
+ "Failed to record SAML registration audit event.",
751
+ ),
752
+ });
753
+
754
+ return {
755
+ ok: true as const,
756
+ enterpriseId: enterprise._id,
757
+ groupId: enterprise.groupId,
758
+ };
759
+ }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),
760
+ );
761
+ },
762
+ metadata: async <DataModel extends GenericDataModel>(
763
+ ctx: GenericActionCtx<DataModel>,
764
+ opts: {
765
+ enterpriseId: string;
766
+ entityId?: string;
767
+ acsUrl?: string;
768
+ sloUrl?: string;
769
+ },
770
+ ) => {
771
+ const enterprise = await ctx.runQuery(
772
+ config.component.public.enterpriseGet,
773
+ {
774
+ enterpriseId: opts.enterpriseId,
775
+ },
776
+ );
777
+ if (!enterprise) {
778
+ throw new AuthError(
779
+ "INVALID_PARAMETERS",
780
+ "Enterprise not found.",
781
+ ).toConvexError();
782
+ }
783
+
784
+ return createServiceProviderMetadata(
785
+ getSamlServiceProviderOptions({
786
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
787
+ source: { kind: "enterprise", id: enterprise._id },
788
+ config: enterprise.config,
789
+ overrides: {
790
+ entityId: opts.entityId,
791
+ acsUrl: opts.acsUrl,
792
+ sloUrl: opts.sloUrl,
793
+ },
794
+ }),
795
+ );
796
+ },
797
+ /**
798
+ * Validate the stored SAML config for an enterprise connection.
799
+ *
800
+ * Re-parses IdP metadata, checks signing cert presence, and verifies
801
+ * SP metadata can be generated. Returns a structured result with
802
+ * per-check details rather than throwing on first failure.
803
+ */
804
+ validate: async <DataModel extends GenericDataModel>(
805
+ ctx: GenericActionCtx<DataModel>,
806
+ enterpriseId: string,
807
+ ) => {
808
+ const checks: Array<{
809
+ name: string;
810
+ ok: boolean;
811
+ message?: string;
812
+ }> = [];
813
+
814
+ const enterprise = await ctx.runQuery(
815
+ config.component.public.enterpriseGet,
816
+ { enterpriseId },
817
+ );
818
+
819
+ if (!enterprise) {
820
+ return {
821
+ ok: false,
822
+ enterpriseId,
823
+ checks: [
824
+ {
825
+ name: "enterprise_exists",
826
+ ok: false,
827
+ message: "Enterprise not found.",
828
+ },
829
+ ],
830
+ };
831
+ }
832
+
833
+ const samlConfig = enterprise.config?.protocols?.saml;
834
+ const samlConfigured =
835
+ samlConfig?.enabled === true &&
836
+ typeof samlConfig?.idp?.metadataXml === "string";
837
+
838
+ checks.push({
839
+ name: "saml_configured",
840
+ ok: samlConfigured,
841
+ message: samlConfigured ? undefined : "SAML is not configured.",
842
+ });
843
+
844
+ const hasIdpMetadata =
845
+ typeof samlConfig?.idp?.metadataXml === "string" &&
846
+ samlConfig.idp.metadataXml.length > 0;
847
+ checks.push({
848
+ name: "idp_metadata_present",
849
+ ok: hasIdpMetadata,
850
+ message: hasIdpMetadata ? undefined : "IdP metadata XML is missing.",
851
+ });
852
+
853
+ const hasEntityId =
854
+ typeof samlConfig?.idp?.entityId === "string" &&
855
+ samlConfig.idp.entityId.length > 0;
856
+ checks.push({
857
+ name: "idp_entity_id",
858
+ ok: hasEntityId,
859
+ message: hasEntityId
860
+ ? undefined
861
+ : "IdP entityId could not be parsed from metadata.",
862
+ });
863
+
864
+ let spMetadataOk = false;
865
+ let spMetadataMessage: string | undefined;
866
+ if (samlConfigured) {
867
+ try {
868
+ createServiceProviderMetadata(
869
+ getSamlServiceProviderOptions({
870
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
871
+ source: { kind: "enterprise", id: enterprise._id },
872
+ config: enterprise.config,
873
+ overrides: {},
874
+ }),
875
+ );
876
+ spMetadataOk = true;
877
+ } catch (e) {
878
+ spMetadataMessage =
879
+ e instanceof Error ? e.message : "SP metadata generation failed.";
880
+ }
881
+ } else {
882
+ spMetadataMessage = "Skipped — SAML not configured.";
883
+ }
884
+ checks.push({
885
+ name: "sp_metadata_generates",
886
+ ok: spMetadataOk,
887
+ message: spMetadataMessage,
888
+ });
889
+
890
+ return {
891
+ ok: checks.every((c) => c.ok),
892
+ enterpriseId: enterprise._id,
893
+ checks,
894
+ };
895
+ },
896
+ },
897
+ policy: {
898
+ get: async (ctx: ComponentReadCtx, enterpriseId: string) => {
899
+ const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);
900
+ return getPolicyFromEnterprise(enterprise);
901
+ },
902
+ update: async (
903
+ ctx: ComponentCtx,
904
+ enterpriseId: string,
905
+ patch: EnterprisePolicyPatch,
906
+ ) => {
907
+ const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);
908
+ const policy = patchEnterprisePolicy(enterprise.policy, patch);
909
+ await ctx.runMutation(config.component.public.enterpriseUpdate, {
910
+ enterpriseId,
911
+ data: { policy },
912
+ });
913
+ await recordEnterpriseAuditEvent(ctx, {
914
+ enterpriseId: enterprise._id,
915
+ groupId: enterprise.groupId,
916
+ eventType: "enterprise.policy.updated",
917
+ actorType: "system",
918
+ subjectType: "enterprise_policy",
919
+ subjectId: enterprise._id,
920
+ ok: true,
921
+ metadata: { version: policy.version },
922
+ });
923
+ return policy;
924
+ },
925
+ validate: async (ctx: ComponentReadCtx, enterpriseId: string) => {
926
+ const enterprise = await ctx.runQuery(
927
+ config.component.public.enterpriseGet,
928
+ { enterpriseId },
929
+ );
930
+ if (!enterprise) {
931
+ return {
932
+ ok: false,
933
+ enterpriseId,
934
+ checks: [
935
+ {
936
+ name: "enterprise_exists",
937
+ ok: false,
938
+ message: enterpriseNotFoundError,
939
+ },
940
+ ],
941
+ };
942
+ }
943
+ const policy = getPolicyFromEnterprise(enterprise);
944
+ const checks = validateEnterprisePolicy(policy);
945
+ return {
946
+ ok: checks.every((check: { ok: boolean }) => check.ok),
947
+ enterpriseId,
948
+ policy,
949
+ checks,
950
+ };
951
+ },
952
+ },
953
+ oidc: {
954
+ /**
955
+ * Register or update enterprise OIDC connection settings.
956
+ *
957
+ * Persists protocol config under `enterprise.config.protocols.oidc` and
958
+ * records an `enterprise.oidc.registered` audit event.
959
+ */
960
+ configure: async (
961
+ ctx: ComponentCtx,
962
+ data: {
963
+ enterpriseId: string;
964
+ issuer?: string;
965
+ discoveryUrl?: string;
966
+ clientId: string;
967
+ clientSecret?: string;
968
+ scopes?: string[];
969
+ authorizationParams?: Record<string, string>;
970
+ clockToleranceSeconds?: number;
971
+ strictIssuer?: boolean;
972
+ /**
973
+ * Map OIDC claim names to `user.extend` field names.
974
+ * Example: `{ department: "department", role: "job_title" }` means
975
+ * the OIDC `department` claim is stored as `user.extend.department`.
976
+ */
977
+ extraFields?: Record<string, string>;
978
+ },
979
+ ) => {
980
+ return await Fx.run(
981
+ Fx.gen(function* () {
982
+ yield* Fx.guard(
983
+ data.issuer === undefined && data.discoveryUrl === undefined,
984
+ Fx.fail(
985
+ new AuthError(
986
+ "INVALID_PARAMETERS",
987
+ "OIDC registration requires issuer or discoveryUrl.",
988
+ ),
989
+ ),
990
+ );
991
+
992
+ const enterprise = yield* Fx.from({
993
+ ok: () =>
994
+ ctx.runQuery(config.component.public.enterpriseGet, {
995
+ enterpriseId: data.enterpriseId,
996
+ }),
997
+ err: () =>
998
+ new AuthError("INTERNAL_ERROR", "Failed to load enterprise."),
999
+ }).pipe(
1000
+ Fx.chain((ent) =>
1001
+ ent === null
1002
+ ? Fx.fail(
1003
+ new AuthError(
1004
+ "INVALID_PARAMETERS",
1005
+ enterpriseNotFoundError,
1006
+ ),
1007
+ )
1008
+ : Fx.succeed(ent),
1009
+ ),
1010
+ );
1011
+ const nextConfig = upsertProtocolConfig(enterprise.config, "oidc", {
1012
+ enabled: true,
1013
+ issuer: data.issuer,
1014
+ discoveryUrl: data.discoveryUrl,
1015
+ clientId: data.clientId,
1016
+ scopes: data.scopes ?? ["openid", "profile", "email"],
1017
+ authorizationParams: data.authorizationParams,
1018
+ clockToleranceSeconds: data.clockToleranceSeconds,
1019
+ strictIssuer: data.strictIssuer,
1020
+ extraFields: data.extraFields,
1021
+ });
1022
+
1023
+ yield* Fx.from({
1024
+ ok: () =>
1025
+ ctx.runMutation(config.component.public.enterpriseUpdate, {
1026
+ enterpriseId: data.enterpriseId,
1027
+ data: { config: nextConfig },
1028
+ }),
1029
+ err: () =>
1030
+ new AuthError(
1031
+ "INTERNAL_ERROR",
1032
+ "Failed to persist OIDC registration.",
1033
+ ),
1034
+ });
1035
+
1036
+ if (data.clientSecret !== undefined) {
1037
+ const ciphertext = yield* Fx.from({
1038
+ ok: () => encryptSecret(data.clientSecret!),
1039
+ err: () =>
1040
+ new AuthError(
1041
+ "INTERNAL_ERROR",
1042
+ "Failed to encrypt OIDC client secret.",
1043
+ ),
1044
+ });
1045
+ yield* Fx.from({
1046
+ ok: () =>
1047
+ ctx.runMutation(
1048
+ config.component.public.enterpriseSecretUpsert,
1049
+ {
1050
+ enterpriseId: data.enterpriseId,
1051
+ groupId: enterprise.groupId,
1052
+ kind: ENTERPRISE_OIDC_CLIENT_SECRET_KIND,
1053
+ ciphertext,
1054
+ updatedAt: Date.now(),
1055
+ },
1056
+ ),
1057
+ err: () =>
1058
+ new AuthError(
1059
+ "INTERNAL_ERROR",
1060
+ "Failed to persist OIDC client secret.",
1061
+ ),
1062
+ });
1063
+ }
1064
+
1065
+ yield* Fx.from({
1066
+ ok: () =>
1067
+ recordEnterpriseAuditEvent(ctx, {
1068
+ enterpriseId: data.enterpriseId,
1069
+ groupId: enterprise.groupId,
1070
+ eventType: "enterprise.oidc.registered",
1071
+ actorType: "system",
1072
+ subjectType: "enterprise_oidc",
1073
+ subjectId: data.enterpriseId,
1074
+ ok: true,
1075
+ metadata: {
1076
+ issuer: data.issuer,
1077
+ discoveryUrl: data.discoveryUrl,
1078
+ },
1079
+ }),
1080
+ err: () =>
1081
+ new AuthError(
1082
+ "INTERNAL_ERROR",
1083
+ "Failed to record OIDC registration audit event.",
1084
+ ),
1085
+ });
1086
+
1087
+ const secret = yield* Fx.from({
1088
+ ok: () =>
1089
+ getEnterpriseSecret(
1090
+ ctx,
1091
+ data.enterpriseId,
1092
+ ENTERPRISE_OIDC_CLIENT_SECRET_KIND,
1093
+ ),
1094
+ err: () =>
1095
+ new AuthError(
1096
+ "INTERNAL_ERROR",
1097
+ "Failed to load OIDC secret metadata.",
1098
+ ),
1099
+ });
1100
+
1101
+ return withOidcSecretState(
1102
+ getPublicOidcConfig(nextConfig),
1103
+ secret !== null,
1104
+ );
1105
+ }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),
1106
+ );
1107
+ },
1108
+ /**
1109
+ * Fetch the stored OIDC config for an enterprise.
1110
+ */
1111
+ get: async (ctx: ComponentReadCtx, enterpriseId: string) => {
1112
+ return await Fx.run(
1113
+ Fx.from({
1114
+ ok: () =>
1115
+ ctx.runQuery(config.component.public.enterpriseGet, {
1116
+ enterpriseId,
1117
+ }),
1118
+ err: () =>
1119
+ new AuthError("INTERNAL_ERROR", "Failed to load enterprise."),
1120
+ }).pipe(
1121
+ Fx.chain((ent) =>
1122
+ ent === null
1123
+ ? Fx.fail(
1124
+ new AuthError(
1125
+ "INVALID_PARAMETERS",
1126
+ enterpriseNotFoundError,
1127
+ ),
1128
+ )
1129
+ : Fx.succeed(ent),
1130
+ ),
1131
+ Fx.chain((enterprise) =>
1132
+ Fx.from({
1133
+ ok: async () => {
1134
+ const secret = await getEnterpriseSecret(
1135
+ ctx,
1136
+ enterprise._id,
1137
+ ENTERPRISE_OIDC_CLIENT_SECRET_KIND,
1138
+ );
1139
+ return withOidcSecretState(
1140
+ getPublicOidcConfig(enterprise.config),
1141
+ secret !== null,
1142
+ );
1143
+ },
1144
+ err: () =>
1145
+ new AuthError(
1146
+ "INTERNAL_ERROR",
1147
+ "Failed to load OIDC secret metadata.",
1148
+ ),
1149
+ }),
1150
+ ),
1151
+ Fx.recover((e) => Fx.fatal(e.toConvexError())),
1152
+ ),
1153
+ );
1154
+ },
1155
+ /**
1156
+ * Resolve enterprise OIDC sign-in route from enterprise id, domain, or
1157
+ * user email domain.
1158
+ */
1159
+ signIn: async (
1160
+ ctx: ComponentReadCtx,
1161
+ data: {
1162
+ enterpriseId?: string;
1163
+ email?: string;
1164
+ domain?: string;
1165
+ redirectTo?: string;
1166
+ },
1167
+ ) => {
1168
+ return await Fx.run(
1169
+ Fx.gen(function* () {
1170
+ const enterprise =
1171
+ data.enterpriseId !== undefined
1172
+ ? yield* Fx.from({
1173
+ ok: () =>
1174
+ ctx.runQuery(config.component.public.enterpriseGet, {
1175
+ enterpriseId: data.enterpriseId,
1176
+ }),
1177
+ err: () =>
1178
+ new AuthError(
1179
+ "INTERNAL_ERROR",
1180
+ "Failed to load enterprise.",
1181
+ ),
1182
+ }).pipe(
1183
+ Fx.chain((ent) =>
1184
+ ent === null
1185
+ ? Fx.fail(
1186
+ new AuthError(
1187
+ "INVALID_PARAMETERS",
1188
+ enterpriseNotFoundError,
1189
+ ),
1190
+ )
1191
+ : Fx.succeed(ent),
1192
+ ),
1193
+ )
1194
+ : data.domain !== undefined || data.email !== undefined
1195
+ ? yield* Fx.from({
1196
+ ok: () =>
1197
+ ctx.runQuery(
1198
+ config.component.public.enterpriseGetByDomain,
1199
+ {
1200
+ domain: normalizeDomain(
1201
+ data.domain ??
1202
+ String(data.email).split("@").at(-1) ??
1203
+ "",
1204
+ ),
1205
+ },
1206
+ ),
1207
+ err: () =>
1208
+ new AuthError(
1209
+ "INTERNAL_ERROR",
1210
+ "Failed to resolve enterprise by domain.",
1211
+ ),
1212
+ }).pipe(
1213
+ Fx.chain((result) =>
1214
+ result?.enterprise &&
1215
+ result.domain?.verifiedAt !== undefined
1216
+ ? Fx.succeed(result.enterprise)
1217
+ : Fx.fail(
1218
+ new AuthError(
1219
+ "INVALID_PARAMETERS",
1220
+ "No enterprise OIDC connection matched the provided input.",
1221
+ ),
1222
+ ),
1223
+ ),
1224
+ )
1225
+ : yield* Fx.fail(
1226
+ new AuthError(
1227
+ "INVALID_PARAMETERS",
1228
+ "No enterprise OIDC connection matched the provided input.",
1229
+ ),
1230
+ );
1231
+
1232
+ yield* Fx.guard(
1233
+ enterprise.status !== "active",
1234
+ Fx.fail(
1235
+ new AuthError(
1236
+ "INVALID_PARAMETERS",
1237
+ "Enterprise connection is not active.",
1238
+ ),
1239
+ ),
1240
+ );
1241
+
1242
+ const oidc = getOidcConfig(enterprise.config);
1243
+ yield* Fx.guard(
1244
+ oidc.enabled !== true,
1245
+ Fx.fail(
1246
+ new AuthError(
1247
+ "PROVIDER_NOT_CONFIGURED",
1248
+ "OIDC is not configured for this enterprise.",
1249
+ ),
1250
+ ),
1251
+ );
1252
+
1253
+ const urls = getEnterpriseOidcUrls({
1254
+ rootUrl: requireEnv("CONVEX_SITE_URL"),
1255
+ enterpriseId: enterprise._id,
1256
+ });
1257
+ return {
1258
+ enterpriseId: enterprise._id,
1259
+ providerId: enterpriseOidcProviderId(enterprise._id),
1260
+ signInPath: urls.signInUrl,
1261
+ callbackPath: urls.callbackUrl,
1262
+ redirectTo: data.redirectTo,
1263
+ };
1264
+ }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),
1265
+ );
1266
+ },
1267
+ /**
1268
+ * Validate the stored OIDC config for an enterprise connection.
1269
+ *
1270
+ * Fetches the OIDC discovery document from the configured issuer or
1271
+ * discoveryUrl, verifies required fields are present, and checks that
1272
+ * clientId is set. Returns a structured result with per-check details.
1273
+ */
1274
+ validate: async (ctx: ComponentReadCtx, enterpriseId: string) => {
1275
+ const checks: Array<{
1276
+ name: string;
1277
+ ok: boolean;
1278
+ message?: string;
1279
+ }> = [];
1280
+
1281
+ const enterprise = await ctx.runQuery(
1282
+ config.component.public.enterpriseGet,
1283
+ { enterpriseId },
1284
+ );
1285
+
1286
+ if (!enterprise) {
1287
+ return {
1288
+ ok: false,
1289
+ enterpriseId,
1290
+ checks: [
1291
+ {
1292
+ name: "enterprise_exists",
1293
+ ok: false,
1294
+ message: "Enterprise not found.",
1295
+ },
1296
+ ],
1297
+ };
1298
+ }
1299
+
1300
+ const oidc = getOidcConfig(enterprise.config);
1301
+ const secret = await getEnterpriseSecret(
1302
+ ctx,
1303
+ enterprise._id,
1304
+ ENTERPRISE_OIDC_CLIENT_SECRET_KIND,
1305
+ );
1306
+ const oidcConfigured =
1307
+ oidc.enabled === true &&
1308
+ typeof oidc.clientId === "string" &&
1309
+ oidc.clientId.length > 0;
1310
+
1311
+ checks.push({
1312
+ name: "oidc_configured",
1313
+ ok: oidcConfigured,
1314
+ message: oidcConfigured ? undefined : "OIDC is not configured.",
1315
+ });
1316
+
1317
+ const hasClientId =
1318
+ typeof oidc.clientId === "string" && oidc.clientId.length > 0;
1319
+ checks.push({
1320
+ name: "client_id_present",
1321
+ ok: hasClientId,
1322
+ message: hasClientId ? undefined : "clientId is missing.",
1323
+ });
1324
+
1325
+ checks.push({
1326
+ name: "client_secret_stored",
1327
+ ok: secret !== null,
1328
+ message:
1329
+ secret !== null ? undefined : "OIDC client secret is missing.",
1330
+ });
1331
+
1332
+ const discoveryTarget = oidc.discoveryUrl ?? oidc.issuer;
1333
+ const hasDiscovery =
1334
+ typeof discoveryTarget === "string" && discoveryTarget.length > 0;
1335
+ checks.push({
1336
+ name: "issuer_or_discovery_url_present",
1337
+ ok: hasDiscovery,
1338
+ message: hasDiscovery
1339
+ ? undefined
1340
+ : "issuer or discoveryUrl is missing.",
1341
+ });
1342
+
1343
+ let discoveryOk = false;
1344
+ let discoveryMessage: string | undefined;
1345
+ if (hasDiscovery) {
1346
+ const discoveryUrl = oidc.discoveryUrl?.length
1347
+ ? oidc.discoveryUrl
1348
+ : `${oidc.issuer}/.well-known/openid-configuration`;
1349
+ try {
1350
+ const res = await fetch(discoveryUrl, {
1351
+ headers: { Accept: "application/json" },
1352
+ signal: AbortSignal.timeout(8_000),
1353
+ });
1354
+ if (!res.ok) {
1355
+ discoveryMessage = `Discovery endpoint returned ${res.status}.`;
1356
+ } else {
1357
+ const json = (await res.json()) as Record<string, unknown>;
1358
+ if (typeof json.issuer !== "string") {
1359
+ discoveryMessage =
1360
+ "Discovery document is missing issuer field.";
1361
+ } else if (typeof json.authorization_endpoint !== "string") {
1362
+ discoveryMessage =
1363
+ "Discovery document is missing authorization_endpoint.";
1364
+ } else {
1365
+ discoveryOk = true;
1366
+ }
1367
+ }
1368
+ } catch (e) {
1369
+ discoveryMessage =
1370
+ e instanceof Error
1371
+ ? `Discovery fetch failed: ${e.message}`
1372
+ : "Discovery fetch failed.";
1373
+ }
1374
+ } else {
1375
+ discoveryMessage = "Skipped — issuer or discoveryUrl not set.";
1376
+ }
1377
+ checks.push({
1378
+ name: "discovery_reachable",
1379
+ ok: discoveryOk,
1380
+ message: discoveryMessage,
1381
+ });
1382
+
1383
+ return {
1384
+ ok: checks.every((c) => c.ok),
1385
+ enterpriseId: enterprise._id,
1386
+ checks,
1387
+ };
1388
+ },
1389
+ },
1390
+ scim: {
1391
+ configure: async (
1392
+ ctx: ComponentCtx,
1393
+ data: {
1394
+ enterpriseId: string;
1395
+ basePath?: string;
1396
+ status?: "draft" | "active" | "disabled";
1397
+ },
1398
+ ) => {
1399
+ const enterprise = await ctx.runQuery(
1400
+ config.component.public.enterpriseGet,
1401
+ {
1402
+ enterpriseId: data.enterpriseId,
1403
+ },
1404
+ );
1405
+ if (enterprise === null) {
1406
+ throw new AuthError(
1407
+ "INVALID_PARAMETERS",
1408
+ "Enterprise not found.",
1409
+ ).toConvexError();
1410
+ }
1411
+ const rawToken = generateRandomString(48, INVITE_TOKEN_ALPHABET);
1412
+ const tokenHash = await sha256(rawToken);
1413
+ const configId = (await ctx.runMutation(
1414
+ config.component.public.enterpriseScimConfigUpsert,
1415
+ {
1416
+ enterpriseId: enterprise._id,
1417
+ groupId: enterprise.groupId,
1418
+ status: data.status ?? "active",
1419
+ basePath:
1420
+ data.basePath ??
1421
+ `${requireEnv("CONVEX_SITE_URL")}/api/auth/sso/${enterprise._id}/scim/v2`,
1422
+ tokenHash,
1423
+ lastRotatedAt: Date.now(),
1424
+ },
1425
+ )) as string;
1426
+ const auditEventId = await recordEnterpriseAuditEvent(ctx, {
1427
+ enterpriseId: enterprise._id,
1428
+ groupId: enterprise.groupId,
1429
+ eventType: "enterprise.scim.configured",
1430
+ actorType: "system",
1431
+ subjectType: "enterprise_scim",
1432
+ subjectId: configId,
1433
+ ok: true,
1434
+ });
1435
+ await emitEnterpriseWebhookDeliveries(ctx, {
1436
+ enterpriseId: enterprise._id,
1437
+ eventType: "enterprise.scim.configured",
1438
+ auditEventId,
1439
+ payload: { enterpriseId: enterprise._id, scimConfigId: configId },
1440
+ });
1441
+ return {
1442
+ ok: true as const,
1443
+ enterpriseId: enterprise._id,
1444
+ configId,
1445
+ basePath:
1446
+ data.basePath ??
1447
+ `${requireEnv("CONVEX_SITE_URL")}/api/auth/sso/${enterprise._id}/scim/v2`,
1448
+ token: rawToken,
1449
+ };
1450
+ },
1451
+ get: async (ctx: ComponentReadCtx, enterpriseId: string) => {
1452
+ return await ctx.runQuery(
1453
+ config.component.public.enterpriseScimConfigGetByEnterprise,
1454
+ { enterpriseId },
1455
+ );
1456
+ },
1457
+ getConfigByToken: async (ctx: ComponentReadCtx, token: string) => {
1458
+ return await ctx.runQuery(
1459
+ config.component.public.enterpriseScimConfigGetByTokenHash,
1460
+ { tokenHash: await sha256(token) },
1461
+ );
1462
+ },
1463
+ /**
1464
+ * Validate the stored SCIM config for an enterprise connection.
1465
+ *
1466
+ * Checks that a SCIM config record exists, is active, has a token
1467
+ * hash set, and has a non-empty basePath. Returns a structured result
1468
+ * with per-check details.
1469
+ */
1470
+ validate: async (ctx: ComponentReadCtx, enterpriseId: string) => {
1471
+ const checks: Array<{
1472
+ name: string;
1473
+ ok: boolean;
1474
+ message?: string;
1475
+ }> = [];
1476
+
1477
+ const enterprise = await ctx.runQuery(
1478
+ config.component.public.enterpriseGet,
1479
+ { enterpriseId },
1480
+ );
1481
+
1482
+ if (!enterprise) {
1483
+ return {
1484
+ ok: false,
1485
+ enterpriseId,
1486
+ checks: [
1487
+ {
1488
+ name: "enterprise_exists",
1489
+ ok: false,
1490
+ message: "Enterprise not found.",
1491
+ },
1492
+ ],
1493
+ };
1494
+ }
1495
+
1496
+ const policy = getPolicyFromEnterprise(enterprise);
1497
+
1498
+ const scimConfig = await ctx.runQuery(
1499
+ config.component.public.enterpriseScimConfigGetByEnterprise,
1500
+ { enterpriseId },
1501
+ );
1502
+
1503
+ const hasConfig = scimConfig !== null && scimConfig !== undefined;
1504
+ checks.push({
1505
+ name: "scim_config_exists",
1506
+ ok: hasConfig,
1507
+ message: hasConfig ? undefined : "SCIM has not been configured.",
1508
+ });
1509
+
1510
+ const isActive = hasConfig && (scimConfig as any).status === "active";
1511
+ checks.push({
1512
+ name: "scim_config_active",
1513
+ ok: isActive,
1514
+ message: isActive
1515
+ ? undefined
1516
+ : `SCIM config status is ${hasConfig ? (scimConfig as any).status : "unknown"}.`,
1517
+ });
1518
+
1519
+ const hasToken =
1520
+ hasConfig &&
1521
+ typeof (scimConfig as any).tokenHash === "string" &&
1522
+ (scimConfig as any).tokenHash.length > 0;
1523
+ checks.push({
1524
+ name: "token_hash_set",
1525
+ ok: hasToken,
1526
+ message: hasToken ? undefined : "SCIM bearer token has not been set.",
1527
+ });
1528
+
1529
+ const hasBasePath =
1530
+ hasConfig &&
1531
+ typeof (scimConfig as any).basePath === "string" &&
1532
+ (scimConfig as any).basePath.length > 0;
1533
+ checks.push({
1534
+ name: "base_path_set",
1535
+ ok: hasBasePath,
1536
+ message: hasBasePath ? undefined : "SCIM basePath is missing.",
1537
+ });
1538
+
1539
+ return {
1540
+ ok: checks.every((c) => c.ok),
1541
+ enterpriseId: enterprise._id,
1542
+ basePath: hasBasePath ? (scimConfig as any).basePath : null,
1543
+ deprovisionMode: policy.provisioning.deprovision.mode,
1544
+ checks,
1545
+ };
1546
+ },
1547
+ identity: {
1548
+ get: async (
1549
+ ctx: ComponentReadCtx,
1550
+ data: {
1551
+ enterpriseId: string;
1552
+ resourceType: "user" | "group";
1553
+ externalId: string;
1554
+ },
1555
+ ) => {
1556
+ return await ctx.runQuery(
1557
+ config.component.public.enterpriseScimIdentityGet,
1558
+ data,
1559
+ );
1560
+ },
1561
+ upsert: async (
1562
+ ctx: ComponentCtx,
1563
+ data: {
1564
+ enterpriseId: string;
1565
+ groupId: string;
1566
+ resourceType: "user" | "group";
1567
+ externalId: string;
1568
+ userId?: string;
1569
+ mappedGroupId?: string;
1570
+ active?: boolean;
1571
+ raw?: Record<string, unknown>;
1572
+ },
1573
+ ) => {
1574
+ return (await ctx.runMutation(
1575
+ config.component.public.enterpriseScimIdentityUpsert,
1576
+ { ...data, lastProvisionedAt: Date.now() },
1577
+ )) as string;
1578
+ },
1579
+ },
1580
+ },
1581
+ audit: {
1582
+ record: async (
1583
+ ctx: ComponentCtx,
1584
+ data: {
1585
+ enterpriseId: string;
1586
+ groupId: string;
1587
+ eventType: string;
1588
+ actorType: "user" | "system" | "scim" | "api_key" | "webhook";
1589
+ actorId?: string;
1590
+ subjectType: string;
1591
+ subjectId?: string;
1592
+ ok: boolean;
1593
+ requestId?: string;
1594
+ ip?: string;
1595
+ metadata?: Record<string, unknown>;
1596
+ },
1597
+ ) => {
1598
+ return await recordEnterpriseAuditEvent(ctx, data);
1599
+ },
1600
+ list: async (
1601
+ ctx: ComponentReadCtx,
1602
+ data: { enterpriseId?: string; groupId?: string; limit?: number },
1603
+ ) => {
1604
+ return await ctx.runQuery(
1605
+ config.component.public.enterpriseAuditEventList,
1606
+ data,
1607
+ );
1608
+ },
1609
+ },
1610
+ webhook: {
1611
+ endpoint: {
1612
+ get: async (ctx: ComponentReadCtx, endpointId: string) => {
1613
+ return await ctx.runQuery(
1614
+ config.component.public.enterpriseWebhookEndpointGet,
1615
+ { endpointId },
1616
+ );
1617
+ },
1618
+ create: async (
1619
+ ctx: ComponentCtx,
1620
+ data: {
1621
+ enterpriseId: string;
1622
+ url: string;
1623
+ secret: string;
1624
+ subscriptions: string[];
1625
+ createdByUserId?: string;
1626
+ },
1627
+ ) => {
1628
+ const enterprise = await ctx.runQuery(
1629
+ config.component.public.enterpriseGet,
1630
+ {
1631
+ enterpriseId: data.enterpriseId,
1632
+ },
1633
+ );
1634
+ if (enterprise === null) {
1635
+ throw new AuthError(
1636
+ "INVALID_PARAMETERS",
1637
+ "Enterprise not found.",
1638
+ ).toConvexError();
1639
+ }
1640
+ const secretHash = await sha256(data.secret);
1641
+ const endpointId = (await ctx.runMutation(
1642
+ config.component.public.enterpriseWebhookEndpointCreate,
1643
+ {
1644
+ enterpriseId: enterprise._id,
1645
+ groupId: enterprise.groupId,
1646
+ url: data.url,
1647
+ secretHash,
1648
+ subscriptions: data.subscriptions,
1649
+ createdByUserId: data.createdByUserId,
1650
+ },
1651
+ )) as string;
1652
+ await recordEnterpriseAuditEvent(ctx, {
1653
+ enterpriseId: enterprise._id,
1654
+ groupId: enterprise.groupId,
1655
+ eventType: "enterprise.webhook.endpoint.created",
1656
+ actorType: data.createdByUserId ? "user" : "system",
1657
+ actorId: data.createdByUserId,
1658
+ subjectType: "enterprise_webhook_endpoint",
1659
+ subjectId: endpointId,
1660
+ ok: true,
1661
+ });
1662
+ return { ok: true as const, endpointId };
1663
+ },
1664
+ list: async (ctx: ComponentReadCtx, enterpriseId: string) => {
1665
+ return await ctx.runQuery(
1666
+ config.component.public.enterpriseWebhookEndpointList,
1667
+ { enterpriseId },
1668
+ );
1669
+ },
1670
+ disable: async (ctx: ComponentCtx, endpointId: string) => {
1671
+ await ctx.runMutation(
1672
+ config.component.public.enterpriseWebhookEndpointUpdate,
1673
+ { endpointId, data: { status: "disabled" } },
1674
+ );
1675
+ return { ok: true as const, endpointId };
1676
+ },
1677
+ },
1678
+ emit: async (
1679
+ ctx: ComponentCtx,
1680
+ data: {
1681
+ enterpriseId: string;
1682
+ eventType: string;
1683
+ payload: Record<string, unknown>;
1684
+ auditEventId?: string;
1685
+ },
1686
+ ) => {
1687
+ await emitEnterpriseWebhookDeliveries(ctx, data);
1688
+ },
1689
+ delivery: {
1690
+ list: async (
1691
+ ctx: ComponentReadCtx,
1692
+ data: { enterpriseId: string; limit?: number },
1693
+ ) => {
1694
+ return await ctx.runQuery(
1695
+ (config.component.public as any).enterpriseWebhookDeliveryList,
1696
+ data,
1697
+ );
1698
+ },
1699
+ listReady: async (ctx: ComponentReadCtx, limit?: number) => {
1700
+ return await ctx.runQuery(
1701
+ config.component.public.enterpriseWebhookDeliveryListReady,
1702
+ { now: Date.now(), limit },
1703
+ );
1704
+ },
1705
+ markDelivered: async (
1706
+ ctx: ComponentCtx,
1707
+ deliveryId: string,
1708
+ responseStatus?: number,
1709
+ ) => {
1710
+ await ctx.runMutation(
1711
+ config.component.public.enterpriseWebhookDeliveryPatch,
1712
+ {
1713
+ deliveryId,
1714
+ data: {
1715
+ status: "delivered",
1716
+ attemptCount: 1,
1717
+ lastAttemptAt: Date.now(),
1718
+ lastResponseStatus: responseStatus,
1719
+ },
1720
+ },
1721
+ );
1722
+ },
1723
+ markFailed: async (
1724
+ ctx: ComponentCtx,
1725
+ deliveryId: string,
1726
+ data: {
1727
+ attemptCount: number;
1728
+ responseStatus?: number;
1729
+ error?: string;
1730
+ retryAt?: number;
1731
+ },
1732
+ ) => {
1733
+ await ctx.runMutation(
1734
+ config.component.public.enterpriseWebhookDeliveryPatch,
1735
+ {
1736
+ deliveryId,
1737
+ data: {
1738
+ status: data.retryAt ? "pending" : "failed",
1739
+ attemptCount: data.attemptCount,
1740
+ lastAttemptAt: Date.now(),
1741
+ lastResponseStatus: data.responseStatus,
1742
+ lastError: data.error,
1743
+ nextAttemptAt: data.retryAt ?? Date.now(),
1744
+ },
1745
+ },
1746
+ );
1747
+ },
1748
+ },
1749
+ },
1750
+ };
1751
+ }