@robelest/convex-auth 0.0.4-preview.18 → 0.0.4-preview.19

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 (541) hide show
  1. package/README.md +6 -3
  2. package/dist/authorization/index.d.ts +46 -0
  3. package/dist/authorization/index.d.ts.map +1 -1
  4. package/dist/authorization/index.js +46 -0
  5. package/dist/authorization/index.js.map +1 -1
  6. package/dist/bin.cjs +21 -13
  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 -16
  10. package/dist/client/index.d.ts.map +1 -1
  11. package/dist/client/index.js +67 -565
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/component/_generated/api.d.ts +40 -12
  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 +1306 -1344
  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 -2
  20. package/dist/component/model.d.ts +80 -80
  21. package/dist/component/model.d.ts.map +1 -1
  22. package/dist/component/model.js +5 -1
  23. package/dist/component/model.js.map +1 -1
  24. package/dist/component/providers/credentials.d.ts +3 -2
  25. package/dist/component/providers/credentials.d.ts.map +1 -1
  26. package/dist/component/providers/email.d.ts +30 -0
  27. package/dist/component/providers/email.d.ts.map +1 -1
  28. package/dist/component/providers/phone.d.ts +28 -0
  29. package/dist/component/providers/phone.d.ts.map +1 -1
  30. package/dist/component/public/enterprise/audit.d.ts +73 -0
  31. package/dist/component/public/enterprise/audit.d.ts.map +1 -0
  32. package/dist/component/public/enterprise/audit.js +108 -0
  33. package/dist/component/public/enterprise/audit.js.map +1 -0
  34. package/dist/component/public/enterprise/core.d.ts +176 -0
  35. package/dist/component/public/enterprise/core.d.ts.map +1 -0
  36. package/dist/component/public/enterprise/core.js +292 -0
  37. package/dist/component/public/enterprise/core.js.map +1 -0
  38. package/dist/component/public/enterprise/domains.d.ts +174 -0
  39. package/dist/component/public/enterprise/domains.d.ts.map +1 -0
  40. package/dist/component/public/enterprise/domains.js +271 -0
  41. package/dist/component/public/enterprise/domains.js.map +1 -0
  42. package/dist/component/public/enterprise/scim.d.ts +245 -0
  43. package/dist/component/public/enterprise/scim.d.ts.map +1 -0
  44. package/dist/component/public/enterprise/scim.js +344 -0
  45. package/dist/component/public/enterprise/scim.js.map +1 -0
  46. package/dist/component/public/enterprise/secrets.d.ts +78 -0
  47. package/dist/component/public/enterprise/secrets.d.ts.map +1 -0
  48. package/dist/component/public/enterprise/secrets.js +118 -0
  49. package/dist/component/public/enterprise/secrets.js.map +1 -0
  50. package/dist/component/public/enterprise/webhooks.d.ts +211 -0
  51. package/dist/component/public/enterprise/webhooks.d.ts.map +1 -0
  52. package/dist/component/public/enterprise/webhooks.js +300 -0
  53. package/dist/component/public/enterprise/webhooks.js.map +1 -0
  54. package/dist/component/public/factors/devices.d.ts +157 -0
  55. package/dist/component/public/factors/devices.d.ts.map +1 -0
  56. package/dist/component/public/factors/devices.js +216 -0
  57. package/dist/component/public/factors/devices.js.map +1 -0
  58. package/dist/component/public/factors/passkeys.d.ts +175 -0
  59. package/dist/component/public/factors/passkeys.d.ts.map +1 -0
  60. package/dist/component/public/factors/passkeys.js +238 -0
  61. package/dist/component/public/factors/passkeys.js.map +1 -0
  62. package/dist/component/public/factors/totp.d.ts +189 -0
  63. package/dist/component/public/factors/totp.d.ts.map +1 -0
  64. package/dist/component/public/factors/totp.js +254 -0
  65. package/dist/component/public/factors/totp.js.map +1 -0
  66. package/dist/component/public/groups/core.d.ts +137 -0
  67. package/dist/component/public/groups/core.d.ts.map +1 -0
  68. package/dist/component/public/groups/core.js +321 -0
  69. package/dist/component/public/groups/core.js.map +1 -0
  70. package/dist/component/public/groups/invites.d.ts +217 -0
  71. package/dist/component/public/groups/invites.d.ts.map +1 -0
  72. package/dist/component/public/groups/invites.js +457 -0
  73. package/dist/component/public/groups/invites.js.map +1 -0
  74. package/dist/component/public/groups/members.d.ts +204 -0
  75. package/dist/component/public/groups/members.d.ts.map +1 -0
  76. package/dist/component/public/groups/members.js +355 -0
  77. package/dist/component/public/groups/members.js.map +1 -0
  78. package/dist/component/public/identity/accounts.d.ts +147 -0
  79. package/dist/component/public/identity/accounts.d.ts.map +1 -0
  80. package/dist/component/public/identity/accounts.js +200 -0
  81. package/dist/component/public/identity/accounts.js.map +1 -0
  82. package/dist/component/public/identity/codes.d.ts +104 -0
  83. package/dist/component/public/identity/codes.d.ts.map +1 -0
  84. package/dist/component/public/identity/codes.js +140 -0
  85. package/dist/component/public/identity/codes.js.map +1 -0
  86. package/dist/component/public/identity/sessions.d.ts +128 -0
  87. package/dist/component/public/identity/sessions.d.ts.map +1 -0
  88. package/dist/component/public/identity/sessions.js +192 -0
  89. package/dist/component/public/identity/sessions.js.map +1 -0
  90. package/dist/component/public/identity/tokens.d.ts +169 -0
  91. package/dist/component/public/identity/tokens.d.ts.map +1 -0
  92. package/dist/component/public/identity/tokens.js +227 -0
  93. package/dist/component/public/identity/tokens.js.map +1 -0
  94. package/dist/component/public/identity/users.d.ts +212 -0
  95. package/dist/component/public/identity/users.d.ts.map +1 -0
  96. package/dist/component/public/identity/users.js +311 -0
  97. package/dist/component/public/identity/users.js.map +1 -0
  98. package/dist/component/public/identity/verifiers.d.ts +116 -0
  99. package/dist/component/public/identity/verifiers.d.ts.map +1 -0
  100. package/dist/component/public/identity/verifiers.js +154 -0
  101. package/dist/component/public/identity/verifiers.js.map +1 -0
  102. package/dist/component/public/security/keys.d.ts +209 -0
  103. package/dist/component/public/security/keys.d.ts.map +1 -0
  104. package/dist/component/public/security/keys.js +319 -0
  105. package/dist/component/public/security/keys.js.map +1 -0
  106. package/dist/component/public/security/limits.d.ts +114 -0
  107. package/dist/component/public/security/limits.d.ts.map +1 -0
  108. package/dist/component/public/security/limits.js +169 -0
  109. package/dist/component/public/security/limits.js.map +1 -0
  110. package/dist/component/public.d.ts +22 -7
  111. package/dist/component/public.js +21 -6
  112. package/dist/component/schema.d.ts +288 -288
  113. package/dist/component/server/auth.d.ts +212 -25
  114. package/dist/component/server/auth.d.ts.map +1 -1
  115. package/dist/component/server/auth.js +68 -4
  116. package/dist/component/server/auth.js.map +1 -1
  117. package/dist/component/server/authError.js +34 -0
  118. package/dist/component/server/authError.js.map +1 -0
  119. package/dist/component/server/{providers.js → config.js} +2 -2
  120. package/dist/component/server/config.js.map +1 -0
  121. package/dist/component/server/{domains/core.js → core.js} +107 -88
  122. package/dist/component/server/core.js.map +1 -0
  123. package/dist/component/server/{provider.js → crypto.js} +3 -3
  124. package/dist/component/server/crypto.js.map +1 -0
  125. package/dist/component/server/device.js +1 -1
  126. package/dist/component/server/device.js.map +1 -1
  127. package/dist/component/server/enterprise/config.js +46 -0
  128. package/dist/component/server/enterprise/config.js.map +1 -0
  129. package/dist/component/server/{domains/sso.js → enterprise/domain.js} +6 -5
  130. package/dist/component/server/enterprise/domain.js.map +1 -0
  131. package/dist/component/server/enterprise/http.js +766 -0
  132. package/dist/component/server/enterprise/http.js.map +1 -0
  133. package/dist/component/server/enterprise/oidc.js +248 -0
  134. package/dist/component/server/enterprise/oidc.js.map +1 -0
  135. package/dist/component/server/enterprise/policy.js +85 -0
  136. package/dist/component/server/enterprise/policy.js.map +1 -0
  137. package/dist/component/server/enterprise/saml.js +338 -0
  138. package/dist/component/server/enterprise/saml.js.map +1 -0
  139. package/dist/component/server/enterprise/scim.js +97 -0
  140. package/dist/component/server/enterprise/scim.js.map +1 -0
  141. package/dist/component/server/enterprise/shared.js +51 -0
  142. package/dist/component/server/enterprise/shared.js.map +1 -0
  143. package/dist/component/server/errors.js.map +1 -1
  144. package/dist/component/server/http.js +2 -1
  145. package/dist/component/server/http.js.map +1 -1
  146. package/dist/component/server/identity.js +1 -1
  147. package/dist/component/server/identity.js.map +1 -1
  148. package/dist/component/server/{ratelimit.js → limits.js} +3 -3
  149. package/dist/component/server/limits.js.map +1 -0
  150. package/dist/component/server/mutations/account.js +3 -3
  151. package/dist/component/server/mutations/account.js.map +1 -1
  152. package/dist/component/server/mutations/code.js +2 -2
  153. package/dist/component/server/mutations/code.js.map +1 -1
  154. package/dist/component/server/mutations/invalidate.js +1 -1
  155. package/dist/component/server/mutations/invalidate.js.map +1 -1
  156. package/dist/component/server/mutations/oauth.js +5 -3
  157. package/dist/component/server/mutations/oauth.js.map +1 -1
  158. package/dist/component/server/mutations/refresh.js +1 -1
  159. package/dist/component/server/mutations/refresh.js.map +1 -1
  160. package/dist/component/server/mutations/register.js +3 -3
  161. package/dist/component/server/mutations/register.js.map +1 -1
  162. package/dist/component/server/mutations/retrieve.js +4 -4
  163. package/dist/component/server/mutations/retrieve.js.map +1 -1
  164. package/dist/component/server/mutations/signature.js +2 -2
  165. package/dist/component/server/mutations/signature.js.map +1 -1
  166. package/dist/component/server/mutations/signin.js +1 -1
  167. package/dist/component/server/mutations/signin.js.map +1 -1
  168. package/dist/component/server/mutations/signout.js +1 -1
  169. package/dist/component/server/mutations/signout.js.map +1 -1
  170. package/dist/component/server/mutations/store/refs.js +15 -0
  171. package/dist/component/server/mutations/store/refs.js.map +1 -0
  172. package/dist/component/server/mutations/store.js +80 -10
  173. package/dist/component/server/mutations/store.js.map +1 -1
  174. package/dist/component/server/mutations/verifier.js +1 -1
  175. package/dist/component/server/mutations/verifier.js.map +1 -1
  176. package/dist/component/server/mutations/verify.js +4 -3
  177. package/dist/component/server/mutations/verify.js.map +1 -1
  178. package/dist/component/server/oauth.js +1 -1
  179. package/dist/component/server/oauth.js.map +1 -1
  180. package/dist/component/server/passkey.js +2 -1
  181. package/dist/component/server/passkey.js.map +1 -1
  182. package/dist/component/server/redirects.js +1 -1
  183. package/dist/component/server/redirects.js.map +1 -1
  184. package/dist/component/server/refresh.js +1 -1
  185. package/dist/component/server/refresh.js.map +1 -1
  186. package/dist/component/server/{factory.d.ts → runtime.d.ts} +2 -2
  187. package/dist/component/server/runtime.d.ts.map +1 -0
  188. package/dist/component/server/runtime.js +413 -0
  189. package/dist/component/server/runtime.js.map +1 -0
  190. package/dist/component/server/signin.js +2 -1
  191. package/dist/component/server/signin.js.map +1 -1
  192. package/dist/component/server/totp.js +2 -1
  193. package/dist/component/server/totp.js.map +1 -1
  194. package/dist/component/server/types.d.ts +225 -41
  195. package/dist/component/server/types.d.ts.map +1 -1
  196. package/dist/component/server/types.js.map +1 -1
  197. package/dist/component/server/users.js +1 -1
  198. package/dist/component/server/users.js.map +1 -1
  199. package/dist/component/server/utils.js +1 -1
  200. package/dist/component/server/utils.js.map +1 -1
  201. package/dist/core/types.d.ts +369 -0
  202. package/dist/core/types.d.ts.map +1 -0
  203. package/dist/factors/device.js +105 -0
  204. package/dist/factors/device.js.map +1 -0
  205. package/dist/factors/passkey.js +181 -0
  206. package/dist/factors/passkey.js.map +1 -0
  207. package/dist/factors/totp.js +122 -0
  208. package/dist/factors/totp.js.map +1 -0
  209. package/dist/providers/credentials.d.ts +5 -2
  210. package/dist/providers/credentials.d.ts.map +1 -1
  211. package/dist/providers/credentials.js +2 -0
  212. package/dist/providers/credentials.js.map +1 -1
  213. package/dist/providers/email.d.ts +30 -0
  214. package/dist/providers/email.d.ts.map +1 -1
  215. package/dist/providers/email.js +24 -0
  216. package/dist/providers/email.js.map +1 -1
  217. package/dist/providers/phone.d.ts +28 -0
  218. package/dist/providers/phone.d.ts.map +1 -1
  219. package/dist/providers/phone.js +22 -0
  220. package/dist/providers/phone.js.map +1 -1
  221. package/dist/runtime/browser.js +68 -0
  222. package/dist/runtime/browser.js.map +1 -0
  223. package/dist/runtime/invite.js +51 -0
  224. package/dist/runtime/invite.js.map +1 -0
  225. package/dist/runtime/proxy.js +70 -0
  226. package/dist/runtime/proxy.js.map +1 -0
  227. package/dist/runtime/storage.js +37 -0
  228. package/dist/runtime/storage.js.map +1 -0
  229. package/dist/server/auth.d.ts +218 -28
  230. package/dist/server/auth.d.ts.map +1 -1
  231. package/dist/server/auth.js +68 -4
  232. package/dist/server/auth.js.map +1 -1
  233. package/dist/server/{fx.d.ts → authError.d.ts} +25 -15
  234. package/dist/server/authError.d.ts.map +1 -0
  235. package/dist/server/authError.js +34 -0
  236. package/dist/server/authError.js.map +1 -0
  237. package/dist/server/{providers.js → config.js} +2 -2
  238. package/dist/server/config.js.map +1 -0
  239. package/dist/server/core.d.ts +1436 -0
  240. package/dist/server/core.d.ts.map +1 -0
  241. package/dist/server/{domains/core.js → core.js} +107 -88
  242. package/dist/server/core.js.map +1 -0
  243. package/dist/server/{provider.d.ts → crypto.d.ts} +2 -2
  244. package/dist/server/crypto.d.ts.map +1 -0
  245. package/dist/server/{provider.js → crypto.js} +3 -3
  246. package/dist/{component/server/provider.js.map → server/crypto.js.map} +1 -1
  247. package/dist/server/device.js +1 -1
  248. package/dist/server/device.js.map +1 -1
  249. package/dist/server/enterprise/config.js +46 -0
  250. package/dist/server/enterprise/config.js.map +1 -0
  251. package/dist/server/{domains/sso.d.ts → enterprise/domain.d.ts} +4 -4
  252. package/dist/server/enterprise/domain.d.ts.map +1 -0
  253. package/dist/server/{domains/sso.js → enterprise/domain.js} +6 -5
  254. package/dist/server/enterprise/domain.js.map +1 -0
  255. package/dist/server/enterprise/http.d.ts +26 -0
  256. package/dist/server/enterprise/http.d.ts.map +1 -0
  257. package/dist/server/enterprise/http.js +766 -0
  258. package/dist/server/enterprise/http.js.map +1 -0
  259. package/dist/server/enterprise/oidc.js +248 -0
  260. package/dist/server/enterprise/oidc.js.map +1 -0
  261. package/dist/server/enterprise/policy.js +85 -0
  262. package/dist/server/enterprise/policy.js.map +1 -0
  263. package/dist/server/enterprise/saml.d.ts +1 -0
  264. package/dist/server/enterprise/saml.js +338 -0
  265. package/dist/server/enterprise/saml.js.map +1 -0
  266. package/dist/server/enterprise/scim.d.ts +1 -0
  267. package/dist/server/enterprise/scim.js +97 -0
  268. package/dist/server/enterprise/scim.js.map +1 -0
  269. package/dist/server/enterprise/shared.d.ts +5 -0
  270. package/dist/server/enterprise/shared.d.ts.map +1 -0
  271. package/dist/server/enterprise/shared.js +51 -0
  272. package/dist/server/enterprise/shared.js.map +1 -0
  273. package/dist/server/enterprise/validators.d.ts +1 -0
  274. package/dist/server/{enterpriseValidators.js → enterprise/validators.js} +2 -2
  275. package/dist/server/enterprise/validators.js.map +1 -0
  276. package/dist/server/errors.d.ts +2 -0
  277. package/dist/server/errors.d.ts.map +1 -1
  278. package/dist/server/errors.js +2 -0
  279. package/dist/server/errors.js.map +1 -1
  280. package/dist/server/http.d.ts +2 -2
  281. package/dist/server/http.d.ts.map +1 -1
  282. package/dist/server/http.js +2 -1
  283. package/dist/server/http.js.map +1 -1
  284. package/dist/server/identity.js +1 -1
  285. package/dist/server/identity.js.map +1 -1
  286. package/dist/server/index.d.ts +4 -705
  287. package/dist/server/index.js +4 -1367
  288. package/dist/server/limits.d.ts +1 -0
  289. package/dist/server/{ratelimit.js → limits.js} +3 -3
  290. package/dist/server/limits.js.map +1 -0
  291. package/dist/server/mounts.d.ts +647 -0
  292. package/dist/server/mounts.d.ts.map +1 -0
  293. package/dist/server/mounts.js +643 -0
  294. package/dist/server/mounts.js.map +1 -0
  295. package/dist/server/mutations/account.d.ts +8 -8
  296. package/dist/server/mutations/account.js +3 -3
  297. package/dist/server/mutations/account.js.map +1 -1
  298. package/dist/server/mutations/code.d.ts +13 -13
  299. package/dist/server/mutations/code.js +2 -2
  300. package/dist/server/mutations/code.js.map +1 -1
  301. package/dist/server/mutations/index.d.ts +8 -312
  302. package/dist/server/mutations/index.js +14 -84
  303. package/dist/server/mutations/invalidate.d.ts +5 -5
  304. package/dist/server/mutations/invalidate.d.ts.map +1 -1
  305. package/dist/server/mutations/invalidate.js +1 -1
  306. package/dist/server/mutations/invalidate.js.map +1 -1
  307. package/dist/server/mutations/oauth.d.ts +9 -9
  308. package/dist/server/mutations/oauth.d.ts.map +1 -1
  309. package/dist/server/mutations/oauth.js +5 -3
  310. package/dist/server/mutations/oauth.js.map +1 -1
  311. package/dist/server/mutations/refresh.d.ts +4 -4
  312. package/dist/server/mutations/refresh.js +1 -1
  313. package/dist/server/mutations/refresh.js.map +1 -1
  314. package/dist/server/mutations/register.d.ts +10 -10
  315. package/dist/server/mutations/register.d.ts.map +1 -1
  316. package/dist/server/mutations/register.js +3 -3
  317. package/dist/server/mutations/register.js.map +1 -1
  318. package/dist/server/mutations/retrieve.d.ts +8 -10
  319. package/dist/server/mutations/retrieve.d.ts.map +1 -1
  320. package/dist/server/mutations/retrieve.js +5 -7
  321. package/dist/server/mutations/retrieve.js.map +1 -1
  322. package/dist/server/mutations/signature.d.ts +6 -6
  323. package/dist/server/mutations/signature.d.ts.map +1 -1
  324. package/dist/server/mutations/signature.js +2 -2
  325. package/dist/server/mutations/signature.js.map +1 -1
  326. package/dist/server/mutations/signin.d.ts +1 -1
  327. package/dist/server/mutations/signin.js +1 -1
  328. package/dist/server/mutations/signin.js.map +1 -1
  329. package/dist/server/mutations/signout.d.ts +1 -1
  330. package/dist/server/mutations/signout.js +1 -1
  331. package/dist/server/mutations/signout.js.map +1 -1
  332. package/dist/server/mutations/store/refs.d.ts +12 -0
  333. package/dist/server/mutations/store/refs.d.ts.map +1 -0
  334. package/dist/server/mutations/store/refs.js +15 -0
  335. package/dist/server/mutations/store/refs.js.map +1 -0
  336. package/dist/server/mutations/store.d.ts +303 -9
  337. package/dist/server/mutations/store.d.ts.map +1 -1
  338. package/dist/server/mutations/store.js +80 -10
  339. package/dist/server/mutations/store.js.map +1 -1
  340. package/dist/server/mutations/verifier.d.ts +1 -1
  341. package/dist/server/mutations/verifier.js +1 -1
  342. package/dist/server/mutations/verifier.js.map +1 -1
  343. package/dist/server/mutations/verify.d.ts +8 -8
  344. package/dist/server/mutations/verify.d.ts.map +1 -1
  345. package/dist/server/mutations/verify.js +4 -3
  346. package/dist/server/mutations/verify.js.map +1 -1
  347. package/dist/server/oauth.js +1 -1
  348. package/dist/server/oauth.js.map +1 -1
  349. package/dist/server/passkey.d.ts +2 -2
  350. package/dist/server/passkey.d.ts.map +1 -1
  351. package/dist/server/passkey.js +3 -2
  352. package/dist/server/passkey.js.map +1 -1
  353. package/dist/server/redirects.js +1 -1
  354. package/dist/server/redirects.js.map +1 -1
  355. package/dist/server/refresh.js +1 -1
  356. package/dist/server/refresh.js.map +1 -1
  357. package/dist/server/{factory.d.ts → runtime.d.ts} +16 -16
  358. package/dist/server/runtime.d.ts.map +1 -0
  359. package/dist/server/runtime.js +413 -0
  360. package/dist/server/runtime.js.map +1 -0
  361. package/dist/server/signin.js +3 -2
  362. package/dist/server/signin.js.map +1 -1
  363. package/dist/server/ssr.d.ts +226 -0
  364. package/dist/server/ssr.d.ts.map +1 -0
  365. package/dist/server/ssr.js +786 -0
  366. package/dist/server/ssr.js.map +1 -0
  367. package/dist/server/totp.js +2 -1
  368. package/dist/server/totp.js.map +1 -1
  369. package/dist/server/types.d.ts +242 -42
  370. package/dist/server/types.d.ts.map +1 -1
  371. package/dist/server/types.js +12 -1
  372. package/dist/server/types.js.map +1 -1
  373. package/dist/server/users.js +1 -1
  374. package/dist/server/users.js.map +1 -1
  375. package/dist/server/utils.js +1 -1
  376. package/dist/server/utils.js.map +1 -1
  377. package/package.json +3 -4
  378. package/src/authorization/index.ts +46 -0
  379. package/src/cli/index.ts +38 -20
  380. package/src/client/core/types.ts +437 -0
  381. package/src/client/factors/device.ts +160 -0
  382. package/src/client/factors/passkey.ts +282 -0
  383. package/src/client/factors/totp.ts +150 -0
  384. package/src/client/index.ts +133 -1267
  385. package/src/client/runtime/browser.ts +112 -0
  386. package/src/client/runtime/invite.ts +65 -0
  387. package/src/client/runtime/proxy.ts +111 -0
  388. package/src/client/runtime/storage.ts +79 -0
  389. package/src/component/_generated/api.ts +40 -12
  390. package/src/component/_generated/component.ts +1772 -1798
  391. package/src/component/model.ts +6 -0
  392. package/src/component/public/enterprise/audit.ts +120 -0
  393. package/src/component/public/enterprise/core.ts +354 -0
  394. package/src/component/public/enterprise/domains.ts +323 -0
  395. package/src/component/public/enterprise/scim.ts +396 -0
  396. package/src/component/public/enterprise/secrets.ts +132 -0
  397. package/src/component/public/enterprise/webhooks.ts +306 -0
  398. package/src/component/public/factors/devices.ts +223 -0
  399. package/src/component/public/factors/passkeys.ts +242 -0
  400. package/src/component/public/factors/totp.ts +258 -0
  401. package/src/component/public/groups/core.ts +481 -0
  402. package/src/component/public/groups/invites.ts +602 -0
  403. package/src/component/public/groups/members.ts +409 -0
  404. package/src/component/public/identity/accounts.ts +206 -0
  405. package/src/component/public/identity/codes.ts +148 -0
  406. package/src/component/public/identity/sessions.ts +209 -0
  407. package/src/component/public/identity/tokens.ts +250 -0
  408. package/src/component/public/identity/users.ts +354 -0
  409. package/src/component/public/identity/verifiers.ts +157 -0
  410. package/src/component/public/security/keys.ts +365 -0
  411. package/src/component/public/security/limits.ts +173 -0
  412. package/src/component/public.ts +27 -5
  413. package/src/providers/credentials.ts +4 -5
  414. package/src/providers/email.ts +30 -0
  415. package/src/providers/phone.ts +28 -0
  416. package/src/server/auth.ts +282 -28
  417. package/src/server/authError.ts +44 -0
  418. package/src/server/core.ts +2095 -0
  419. package/src/server/{provider.ts → crypto.ts} +1 -1
  420. package/src/server/device.ts +1 -1
  421. package/src/server/enterprise/config.ts +51 -0
  422. package/src/server/{domains/sso.ts → enterprise/domain.ts} +4 -2
  423. package/src/server/enterprise/http.ts +1324 -0
  424. package/src/server/enterprise/oidc.ts +500 -0
  425. package/src/server/enterprise/policy.ts +128 -0
  426. package/src/server/enterprise/saml.ts +578 -0
  427. package/src/server/enterprise/scim.ts +135 -0
  428. package/src/server/enterprise/shared.ts +134 -0
  429. package/src/server/errors.ts +2 -0
  430. package/src/server/http.ts +3 -1
  431. package/src/server/identity.ts +1 -1
  432. package/src/server/index.ts +32 -2605
  433. package/src/server/{ratelimit.ts → limits.ts} +1 -1
  434. package/src/server/mounts.ts +948 -0
  435. package/src/server/mutations/account.ts +4 -4
  436. package/src/server/mutations/code.ts +3 -3
  437. package/src/server/mutations/index.ts +8 -148
  438. package/src/server/mutations/invalidate.ts +2 -2
  439. package/src/server/mutations/oauth.ts +8 -6
  440. package/src/server/mutations/refresh.ts +3 -3
  441. package/src/server/mutations/register.ts +3 -3
  442. package/src/server/mutations/retrieve.ts +4 -8
  443. package/src/server/mutations/signature.ts +3 -3
  444. package/src/server/mutations/signin.ts +2 -2
  445. package/src/server/mutations/signout.ts +2 -2
  446. package/src/server/mutations/store/refs.ts +10 -0
  447. package/src/server/mutations/store.ts +137 -9
  448. package/src/server/mutations/verifier.ts +2 -2
  449. package/src/server/mutations/verify.ts +5 -5
  450. package/src/server/oauth.ts +1 -1
  451. package/src/server/passkey.ts +3 -4
  452. package/src/server/redirects.ts +1 -1
  453. package/src/server/refresh.ts +1 -1
  454. package/src/server/runtime.ts +880 -0
  455. package/src/server/signin.ts +3 -1
  456. package/src/server/ssr.ts +1764 -0
  457. package/src/server/totp.ts +3 -1
  458. package/src/server/types.ts +254 -43
  459. package/src/server/users.ts +1 -1
  460. package/src/server/utils.ts +1 -1
  461. package/src/test.ts +25 -0
  462. package/dist/component/public/enterprise.d.ts +0 -54
  463. package/dist/component/public/enterprise.d.ts.map +0 -1
  464. package/dist/component/public/enterprise.js +0 -515
  465. package/dist/component/public/enterprise.js.map +0 -1
  466. package/dist/component/public/factors.d.ts +0 -52
  467. package/dist/component/public/factors.d.ts.map +0 -1
  468. package/dist/component/public/factors.js +0 -285
  469. package/dist/component/public/factors.js.map +0 -1
  470. package/dist/component/public/groups.d.ts +0 -124
  471. package/dist/component/public/groups.d.ts.map +0 -1
  472. package/dist/component/public/groups.js +0 -680
  473. package/dist/component/public/groups.js.map +0 -1
  474. package/dist/component/public/identity.d.ts +0 -93
  475. package/dist/component/public/identity.d.ts.map +0 -1
  476. package/dist/component/public/identity.js +0 -426
  477. package/dist/component/public/identity.js.map +0 -1
  478. package/dist/component/public/keys.d.ts +0 -41
  479. package/dist/component/public/keys.d.ts.map +0 -1
  480. package/dist/component/public/keys.js +0 -157
  481. package/dist/component/public/keys.js.map +0 -1
  482. package/dist/component/public/shared.d.ts +0 -26
  483. package/dist/component/public/shared.d.ts.map +0 -1
  484. package/dist/component/public/shared.js +0 -32
  485. package/dist/component/public/shared.js.map +0 -1
  486. package/dist/component/server/domains/core.js.map +0 -1
  487. package/dist/component/server/domains/sso.js.map +0 -1
  488. package/dist/component/server/factory.d.ts.map +0 -1
  489. package/dist/component/server/factory.js +0 -1134
  490. package/dist/component/server/factory.js.map +0 -1
  491. package/dist/component/server/fx.js +0 -66
  492. package/dist/component/server/fx.js.map +0 -1
  493. package/dist/component/server/mutations/index.js +0 -85
  494. package/dist/component/server/mutations/index.js.map +0 -1
  495. package/dist/component/server/providers.js.map +0 -1
  496. package/dist/component/server/ratelimit.js.map +0 -1
  497. package/dist/component/server/sso.js +0 -830
  498. package/dist/component/server/sso.js.map +0 -1
  499. package/dist/server/domains/core.d.ts +0 -449
  500. package/dist/server/domains/core.d.ts.map +0 -1
  501. package/dist/server/domains/core.js.map +0 -1
  502. package/dist/server/domains/sso.d.ts.map +0 -1
  503. package/dist/server/domains/sso.js.map +0 -1
  504. package/dist/server/enterpriseValidators.js.map +0 -1
  505. package/dist/server/factory.d.ts.map +0 -1
  506. package/dist/server/factory.js +0 -1134
  507. package/dist/server/factory.js.map +0 -1
  508. package/dist/server/fx.d.ts.map +0 -1
  509. package/dist/server/fx.js +0 -66
  510. package/dist/server/fx.js.map +0 -1
  511. package/dist/server/index.d.ts.map +0 -1
  512. package/dist/server/index.js.map +0 -1
  513. package/dist/server/mutations/index.d.ts.map +0 -1
  514. package/dist/server/mutations/index.js.map +0 -1
  515. package/dist/server/provider.d.ts.map +0 -1
  516. package/dist/server/provider.js.map +0 -1
  517. package/dist/server/providers.js.map +0 -1
  518. package/dist/server/ratelimit.js.map +0 -1
  519. package/dist/server/sso.js +0 -830
  520. package/dist/server/sso.js.map +0 -1
  521. package/dist/server/version.d.ts +0 -5
  522. package/dist/server/version.d.ts.map +0 -1
  523. package/dist/server/version.js +0 -6
  524. package/dist/server/version.js.map +0 -1
  525. package/src/component/public/enterprise.ts +0 -753
  526. package/src/component/public/factors.ts +0 -333
  527. package/src/component/public/groups.ts +0 -1066
  528. package/src/component/public/identity.ts +0 -569
  529. package/src/component/public/keys.ts +0 -209
  530. package/src/component/public/shared.ts +0 -119
  531. package/src/server/domains/core.ts +0 -1096
  532. package/src/server/factory.ts +0 -2181
  533. package/src/server/fx.ts +0 -152
  534. package/src/server/sso.ts +0 -1516
  535. package/src/server/version.ts +0 -2
  536. /package/dist/server/{enterpriseValidators.d.ts → config.d.ts} +0 -0
  537. /package/dist/server/{providers.d.ts → enterprise/config.d.ts} +0 -0
  538. /package/dist/server/{ratelimit.d.ts → enterprise/oidc.d.ts} +0 -0
  539. /package/dist/server/{sso.d.ts → enterprise/policy.d.ts} +0 -0
  540. /package/src/server/{providers.ts → config.ts} +0 -0
  541. /package/src/server/{enterpriseValidators.ts → enterprise/validators.ts} +0 -0
@@ -0,0 +1,338 @@
1
+ import { asRecord, getEnterpriseSamlUrls } from "./shared.js";
2
+ import { getSamlConfig } from "./config.js";
3
+ import { decodeBase64urlIgnorePadding, encodeBase64urlNoPadding } from "@oslojs/encoding";
4
+ import { Constants, IdentityProvider, ServiceProvider, setSchemaValidator } from "@robelest/samlify";
5
+
6
+ //#region src/server/enterprise/saml.ts
7
+ const _samlifyPermissiveValidator = { validate: (_xml) => Promise.resolve("OK") };
8
+ function ensureSamlifyValidator() {
9
+ setSchemaValidator(_samlifyPermissiveValidator);
10
+ }
11
+ /** @internal */
12
+ function createSamlPostBindingResponse(opts) {
13
+ const fields = [`<input type="hidden" name="${opts.parameter}" value="${opts.value.replace(/"/g, "&quot;")}" />`, opts.relayState ? `<input type="hidden" name="RelayState" value="${opts.relayState.replace(/"/g, "&quot;")}" />` : ""].join("");
14
+ return new Response(`<!doctype html><html><body><form method="POST" action="${opts.endpoint}">${fields}</form><script>document.forms[0].submit();<\/script></body></html>`, {
15
+ status: 200,
16
+ headers: { "Content-Type": "text/html; charset=utf-8" }
17
+ });
18
+ }
19
+ /** @internal */
20
+ function decodeRelayState(value) {
21
+ if (!value) return {};
22
+ try {
23
+ return JSON.parse(new TextDecoder().decode(decodeBase64urlIgnorePadding(value)));
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+ /** @internal */
29
+ function encodeEnterpriseSamlRelayState(value) {
30
+ return encodeBase64urlNoPadding(new TextEncoder().encode(JSON.stringify({
31
+ source: `${value.source.kind}:${value.source.id}`,
32
+ signature: value.signature,
33
+ requestId: value.requestId,
34
+ state: value.state,
35
+ redirectTo: value.redirectTo
36
+ })));
37
+ }
38
+ /** @internal */
39
+ function decodeEnterpriseSamlRelayStateOrThrow(value) {
40
+ if (!value) throw new Error("Missing SAML RelayState.");
41
+ const decoded = decodeRelayState(value);
42
+ if (typeof decoded.source !== "string" || typeof decoded.signature !== "string" || typeof decoded.requestId !== "string" || typeof decoded.state !== "string") throw new Error("Invalid SAML RelayState.");
43
+ const [kind, ...rest] = decoded.source.split(":");
44
+ const id = rest.join(":");
45
+ if (kind !== "enterprise" || id.length === 0) throw new Error("Invalid enterprise SAML source.");
46
+ return {
47
+ source: {
48
+ kind,
49
+ id
50
+ },
51
+ signature: decoded.signature,
52
+ requestId: decoded.requestId,
53
+ state: decoded.state,
54
+ redirectTo: typeof decoded.redirectTo === "string" ? decoded.redirectTo : void 0
55
+ };
56
+ }
57
+ /** @internal */
58
+ async function readRequestBody(request) {
59
+ const contentType = request.headers.get("Content-Type") ?? "";
60
+ if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
61
+ const form = await request.formData();
62
+ const body = {};
63
+ form.forEach((value, key) => {
64
+ body[key] = typeof value === "string" ? value : value.name;
65
+ });
66
+ return body;
67
+ }
68
+ return {};
69
+ }
70
+ /** @internal */
71
+ async function readEnterpriseSamlHttpRequest(request) {
72
+ const url = new URL(request.url);
73
+ const body = await readRequestBody(request);
74
+ return {
75
+ url,
76
+ body,
77
+ query: Object.fromEntries(url.searchParams),
78
+ binding: request.method === "GET" ? "redirect" : body.SAMLResponse || body.SAMLRequest ? "post" : "redirect",
79
+ relayState: body.RelayState ?? url.searchParams.get("RelayState") ?? void 0,
80
+ hasSamlRequest: Boolean(body.SAMLRequest ?? url.searchParams.get("SAMLRequest")),
81
+ hasSamlResponse: Boolean(body.SAMLResponse ?? url.searchParams.get("SAMLResponse"))
82
+ };
83
+ }
84
+ /** @internal */
85
+ function parseSamlIdpMetadata(metadata) {
86
+ const entityMeta = IdentityProvider({ metadata }).entityMeta;
87
+ const normalizeService = (value) => {
88
+ return typeof value === "string" && value.length > 0 ? value : void 0;
89
+ };
90
+ return {
91
+ issuer: entityMeta.getEntityID(),
92
+ sso: {
93
+ redirect: normalizeService(entityMeta.getSingleSignOnService("redirect")),
94
+ post: normalizeService(entityMeta.getSingleSignOnService("post"))
95
+ },
96
+ slo: {
97
+ redirect: normalizeService(entityMeta.getSingleLogoutService("redirect")),
98
+ post: normalizeService(entityMeta.getSingleLogoutService("post"))
99
+ },
100
+ signingCert: entityMeta.getX509Certificate("signing"),
101
+ encryptionCert: entityMeta.getX509Certificate("encrypt"),
102
+ nameIdFormats: (() => {
103
+ const nameIdFormat = entityMeta.getNameIDFormat();
104
+ return Array.isArray(nameIdFormat) ? nameIdFormat : [];
105
+ })(),
106
+ wantsSignedAuthnRequests: entityMeta.isWantAuthnRequestsSigned()
107
+ };
108
+ }
109
+ /** @internal */
110
+ function createServiceProviderMetadata(opts) {
111
+ const binding = Constants.namespace.binding;
112
+ return ServiceProvider({
113
+ entityID: opts.entityId,
114
+ authnRequestsSigned: opts.authnRequestsSigned ?? false,
115
+ privateKey: opts.privateKey,
116
+ privateKeyPass: opts.privateKeyPass,
117
+ signingCert: opts.signingCert,
118
+ encryptCert: opts.encryptCert,
119
+ encPrivateKey: opts.encPrivateKey,
120
+ encPrivateKeyPass: opts.encPrivateKeyPass,
121
+ assertionConsumerService: [{
122
+ Binding: binding.post,
123
+ Location: opts.acsUrl
124
+ }],
125
+ singleLogoutService: opts.sloUrl ? [{
126
+ Binding: binding.redirect,
127
+ Location: opts.sloUrl
128
+ }, {
129
+ Binding: binding.post,
130
+ Location: opts.sloUrl
131
+ }] : void 0
132
+ }).getMetadata();
133
+ }
134
+ /** @internal */
135
+ function createEnterpriseSamlMetadataXml(opts) {
136
+ return createServiceProviderMetadata(getSamlServiceProviderOptions({
137
+ rootUrl: opts.rootUrl,
138
+ source: opts.source,
139
+ config: opts.config
140
+ }));
141
+ }
142
+ /** @internal */
143
+ function getSamlServiceProviderOptions(opts) {
144
+ const saml = getSamlConfig(opts.config);
145
+ const sp = asRecord(saml.sp) ?? {};
146
+ const urls = getEnterpriseSamlUrls({
147
+ rootUrl: opts.rootUrl,
148
+ source: opts.source
149
+ });
150
+ return {
151
+ entityId: opts.overrides?.entityId ?? sp.entityId ?? urls.metadataUrl,
152
+ acsUrl: opts.overrides?.acsUrl ?? sp.acsUrl ?? urls.acsUrl,
153
+ sloUrl: opts.overrides?.sloUrl ?? sp.sloUrl ?? urls.sloUrl,
154
+ relayState: opts.relayState,
155
+ authnRequestsSigned: saml.signAuthnRequests,
156
+ signingCert: sp.signingCert,
157
+ encryptCert: sp.encryptCert,
158
+ privateKey: sp.privateKey,
159
+ privateKeyPass: sp.privateKeyPass,
160
+ encPrivateKey: sp.encPrivateKey,
161
+ encPrivateKeyPass: sp.encPrivateKeyPass
162
+ };
163
+ }
164
+ /** @internal */
165
+ function createSamlServiceProvider(opts) {
166
+ const binding = Constants.namespace.binding;
167
+ return ServiceProvider({
168
+ entityID: opts.entityId,
169
+ relayState: opts.relayState ?? "",
170
+ authnRequestsSigned: opts.authnRequestsSigned ?? false,
171
+ privateKey: opts.privateKey,
172
+ privateKeyPass: opts.privateKeyPass,
173
+ signingCert: opts.signingCert,
174
+ encryptCert: opts.encryptCert,
175
+ encPrivateKey: opts.encPrivateKey,
176
+ encPrivateKeyPass: opts.encPrivateKeyPass,
177
+ assertionConsumerService: [{
178
+ Binding: binding.post,
179
+ Location: opts.acsUrl
180
+ }],
181
+ singleLogoutService: opts.sloUrl ? [{
182
+ Binding: binding.redirect,
183
+ Location: opts.sloUrl
184
+ }, {
185
+ Binding: binding.post,
186
+ Location: opts.sloUrl
187
+ }] : void 0
188
+ });
189
+ }
190
+ /** @internal */
191
+ function createEnterpriseSamlRuntime(opts) {
192
+ const saml = getSamlConfig(opts.config);
193
+ const spOptions = getSamlServiceProviderOptions({
194
+ rootUrl: opts.rootUrl,
195
+ source: opts.source,
196
+ config: opts.config,
197
+ relayState: opts.relayState,
198
+ overrides: opts.overrides
199
+ });
200
+ if (typeof saml.idp?.metadataXml !== "string") throw new Error("SAML IdP metadata is missing.");
201
+ return {
202
+ saml,
203
+ sp: createSamlServiceProvider(spOptions),
204
+ idp: IdentityProvider({ metadata: saml.idp.metadataXml }),
205
+ urls: getEnterpriseSamlUrls({
206
+ rootUrl: opts.rootUrl,
207
+ source: opts.source
208
+ })
209
+ };
210
+ }
211
+ /** @internal */
212
+ function createEnterpriseSamlSignInRequest(opts) {
213
+ const runtime = createEnterpriseSamlRuntime({
214
+ rootUrl: opts.rootUrl,
215
+ source: opts.source,
216
+ config: opts.config
217
+ });
218
+ const binding = runtime.saml.idp.sso?.redirect ? "redirect" : "post";
219
+ const loginRequest = runtime.sp.createLoginRequest(runtime.idp, binding);
220
+ const relayState = encodeEnterpriseSamlRelayState({
221
+ source: opts.source,
222
+ signature: opts.signature,
223
+ requestId: loginRequest.id,
224
+ state: opts.state,
225
+ redirectTo: opts.redirectTo
226
+ });
227
+ return {
228
+ requestId: loginRequest.id,
229
+ binding,
230
+ relayState,
231
+ redirectUrl: binding === "redirect" ? (() => {
232
+ const redirectUrl = new URL(loginRequest.context);
233
+ redirectUrl.searchParams.set("RelayState", relayState);
234
+ return redirectUrl.toString();
235
+ })() : void 0,
236
+ post: binding === "post" ? {
237
+ endpoint: loginRequest.entityEndpoint,
238
+ value: loginRequest.context
239
+ } : void 0
240
+ };
241
+ }
242
+ /** @internal */
243
+ async function parseEnterpriseSamlLoginResponse(opts) {
244
+ ensureSamlifyValidator();
245
+ const httpRequest = await readEnterpriseSamlHttpRequest(opts.request);
246
+ const runtime = createEnterpriseSamlRuntime({
247
+ rootUrl: opts.rootUrl,
248
+ source: opts.source,
249
+ config: opts.config
250
+ });
251
+ const parsed = await runtime.sp.parseLoginResponse(runtime.idp, httpRequest.binding, {
252
+ query: httpRequest.query,
253
+ body: httpRequest.body
254
+ });
255
+ warnWeakSamlAlgorithms(parsed);
256
+ return {
257
+ ...httpRequest,
258
+ runtime,
259
+ parsed,
260
+ relayState: decodeEnterpriseSamlRelayStateOrThrow(httpRequest.relayState ?? null)
261
+ };
262
+ }
263
+ const WEAK_SAML_ALGORITHMS = new Set([
264
+ "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
265
+ "http://www.w3.org/2000/09/xmldsig#dsa-sha1",
266
+ "http://www.w3.org/2000/09/xmldsig#sha1",
267
+ "http://www.w3.org/2001/04/xmlenc#rsa-1_5",
268
+ "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
269
+ ]);
270
+ /**
271
+ * Warn when the SAML response uses weak cryptographic algorithms
272
+ * such as SHA-1, RSA 1.5, or 3DES.
273
+ */
274
+ function warnWeakSamlAlgorithms(parsed) {
275
+ try {
276
+ const sigAlg = parsed?.extract?.signature?.signatureAlgorithm ?? parsed?.extract?.response?.signatureAlgorithm;
277
+ const digestAlg = parsed?.extract?.signature?.digestAlgorithm;
278
+ if (sigAlg && WEAK_SAML_ALGORITHMS.has(sigAlg)) console.warn(`[convex-auth] SAML response uses weak signature algorithm: ${sigAlg}. Consider upgrading your IdP to use RSA-SHA256 or stronger.`);
279
+ if (digestAlg && WEAK_SAML_ALGORITHMS.has(digestAlg)) console.warn(`[convex-auth] SAML response uses weak digest algorithm: ${digestAlg}. Consider upgrading your IdP to use SHA-256 or stronger.`);
280
+ } catch {}
281
+ }
282
+ /** @internal */
283
+ function validateEnterpriseSamlLoginRelayState(opts) {
284
+ if (opts.relayState.source.kind !== opts.source.kind || opts.relayState.source.id !== opts.source.id || opts.relayState.requestId !== opts.inResponseTo) throw new Error("SAML RelayState did not match the pending login request.");
285
+ }
286
+ /** @internal */
287
+ async function parseEnterpriseSamlLogoutMessage(opts) {
288
+ ensureSamlifyValidator();
289
+ const httpRequest = await readEnterpriseSamlHttpRequest(opts.request);
290
+ const runtime = createEnterpriseSamlRuntime({
291
+ rootUrl: opts.rootUrl,
292
+ source: opts.source,
293
+ config: opts.config,
294
+ relayState: httpRequest.relayState
295
+ });
296
+ const parsedRequest = httpRequest.hasSamlRequest ? await runtime.sp.parseLogoutRequest(runtime.idp, httpRequest.binding, {
297
+ query: httpRequest.query,
298
+ body: httpRequest.body
299
+ }) : void 0;
300
+ return {
301
+ ...httpRequest,
302
+ runtime,
303
+ parsedRequest
304
+ };
305
+ }
306
+ /** @internal */
307
+ function profileFromSamlExtract(extract, mapping) {
308
+ const attributes = typeof extract?.attributes === "object" && extract.attributes !== null ? extract.attributes : {};
309
+ const resolveFirst = (...keys) => {
310
+ for (const key of keys) {
311
+ if (!key) continue;
312
+ const attribute = attributes[key];
313
+ const value = Array.isArray(attribute) ? attribute[0] : attribute;
314
+ if (value !== void 0) return value;
315
+ }
316
+ };
317
+ const fieldResolvers = {
318
+ email: () => resolveFirst(mapping?.email),
319
+ name: () => resolveFirst(mapping?.name) ?? ([resolveFirst(mapping?.firstName), resolveFirst(mapping?.lastName)].filter(Boolean).join(" ") || void 0),
320
+ subject: () => resolveFirst(mapping?.subject) ?? extract?.nameID
321
+ };
322
+ const subject = fieldResolvers.subject();
323
+ if (subject === void 0) throw new Error("SAML profile is missing a subject. Configure `attributeMapping.subject` or ensure the assertion includes a NameID.");
324
+ const email = fieldResolvers.email();
325
+ const name = fieldResolvers.name();
326
+ return {
327
+ id: subject,
328
+ email,
329
+ emailVerified: typeof email === "string" ? true : void 0,
330
+ name,
331
+ samlAttributes: attributes,
332
+ samlSessionIndex: extract?.sessionIndex?.SessionIndex
333
+ };
334
+ }
335
+
336
+ //#endregion
337
+ export { createEnterpriseSamlMetadataXml, createEnterpriseSamlSignInRequest, createSamlPostBindingResponse, createServiceProviderMetadata, encodeEnterpriseSamlRelayState, getSamlServiceProviderOptions, parseEnterpriseSamlLoginResponse, parseEnterpriseSamlLogoutMessage, parseSamlIdpMetadata, profileFromSamlExtract, validateEnterpriseSamlLoginRelayState };
338
+ //# sourceMappingURL=saml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saml.js","names":[],"sources":["../../../../src/server/enterprise/saml.ts"],"sourcesContent":["import {\n decodeBase64urlIgnorePadding,\n encodeBase64urlNoPadding,\n} from \"@oslojs/encoding\";\nimport {\n Constants,\n IdentityProvider,\n ServiceProvider,\n setSchemaValidator,\n} from \"@robelest/samlify\";\n\nimport type { SAMLAttributeMapping } from \"../types\";\nimport { getSamlConfig } from \"./config\";\nimport type {\n EnterpriseSamlHttpRequest,\n EnterpriseSamlRelayState,\n EnterpriseSamlSource,\n ParsedSamlMetadata,\n} from \"./shared\";\nimport { asRecord, getEnterpriseSamlUrls } from \"./shared\";\n\n// Samlify requires a schema validator to be registered before parsing any SAML\n// response. We use a permissive validator that always resolves because Convex's\n// edge runtime has no file-system access for XML schema files, and structural\n// correctness is already ensured by the XML parser. This is called directly\n// before each parse operation since Convex can restart the V8 isolate between\n// requests, resetting module-level state.\nconst _samlifyPermissiveValidator = {\n validate: (_xml: string) => Promise.resolve(\"OK\"),\n};\nfunction ensureSamlifyValidator() {\n setSchemaValidator(_samlifyPermissiveValidator);\n}\n\n/** @internal */\nexport function createSamlPostBindingResponse(opts: {\n endpoint: string;\n parameter: \"SAMLRequest\" | \"SAMLResponse\";\n value: string;\n relayState?: string;\n}) {\n const fields = [\n `<input type=\"hidden\" name=\"${opts.parameter}\" value=\"${opts.value.replace(/\"/g, \"&quot;\")}\" />`,\n opts.relayState\n ? `<input type=\"hidden\" name=\"RelayState\" value=\"${opts.relayState.replace(/\"/g, \"&quot;\")}\" />`\n : \"\",\n ].join(\"\");\n return new Response(\n `<!doctype html><html><body><form method=\"POST\" action=\"${opts.endpoint}\">${fields}</form><script>document.forms[0].submit();</script></body></html>`,\n { status: 200, headers: { \"Content-Type\": \"text/html; charset=utf-8\" } },\n );\n}\n\n/** @internal */\nexport function decodeRelayState(\n value: string | null,\n): Record<string, unknown> {\n if (!value) {\n return {};\n }\n try {\n return JSON.parse(\n new TextDecoder().decode(decodeBase64urlIgnorePadding(value)),\n );\n } catch {\n return {};\n }\n}\n\n/** @internal */\nexport function encodeEnterpriseSamlRelayState(\n value: EnterpriseSamlRelayState,\n) {\n return encodeBase64urlNoPadding(\n new TextEncoder().encode(\n JSON.stringify({\n source: `${value.source.kind}:${value.source.id}`,\n signature: value.signature,\n requestId: value.requestId,\n state: value.state,\n redirectTo: value.redirectTo,\n }),\n ),\n );\n}\n\n/** @internal */\nexport function decodeEnterpriseSamlRelayStateOrThrow(\n value: string | null,\n): EnterpriseSamlRelayState {\n if (!value) {\n throw new Error(\"Missing SAML RelayState.\");\n }\n const decoded = decodeRelayState(value);\n if (\n typeof decoded.source !== \"string\" ||\n typeof decoded.signature !== \"string\" ||\n typeof decoded.requestId !== \"string\" ||\n typeof decoded.state !== \"string\"\n ) {\n throw new Error(\"Invalid SAML RelayState.\");\n }\n const [kind, ...rest] = decoded.source.split(\":\");\n const id = rest.join(\":\");\n if (kind !== \"enterprise\" || id.length === 0) {\n throw new Error(\"Invalid enterprise SAML source.\");\n }\n return {\n source: { kind, id } as EnterpriseSamlSource,\n signature: decoded.signature,\n requestId: decoded.requestId,\n state: decoded.state,\n redirectTo:\n typeof decoded.redirectTo === \"string\" ? decoded.redirectTo : undefined,\n };\n}\n\n/** @internal */\nexport async function readRequestBody(\n request: Request,\n): Promise<Record<string, string>> {\n const contentType = request.headers.get(\"Content-Type\") ?? \"\";\n if (\n contentType.includes(\"application/x-www-form-urlencoded\") ||\n contentType.includes(\"multipart/form-data\")\n ) {\n const form = await request.formData();\n const body: Record<string, string> = {};\n form.forEach((value, key) => {\n body[key] = typeof value === \"string\" ? value : value.name;\n });\n return body;\n }\n return {};\n}\n\n/** @internal */\nexport async function readEnterpriseSamlHttpRequest(\n request: Request,\n): Promise<EnterpriseSamlHttpRequest> {\n const url = new URL(request.url);\n const body = await readRequestBody(request);\n const query = Object.fromEntries(url.searchParams);\n const binding =\n request.method === \"GET\"\n ? \"redirect\"\n : body.SAMLResponse || body.SAMLRequest\n ? \"post\"\n : \"redirect\";\n return {\n url,\n body,\n query,\n binding,\n relayState:\n body.RelayState ?? url.searchParams.get(\"RelayState\") ?? undefined,\n hasSamlRequest: Boolean(\n body.SAMLRequest ?? url.searchParams.get(\"SAMLRequest\"),\n ),\n hasSamlResponse: Boolean(\n body.SAMLResponse ?? url.searchParams.get(\"SAMLResponse\"),\n ),\n };\n}\n\n/** @internal */\nexport function parseSamlIdpMetadata(metadata: string): ParsedSamlMetadata {\n const idp = IdentityProvider({ metadata });\n const entityMeta = idp.entityMeta;\n\n const normalizeService = (value: unknown): string | undefined => {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n };\n\n return {\n issuer: entityMeta.getEntityID(),\n sso: {\n redirect: normalizeService(entityMeta.getSingleSignOnService(\"redirect\")),\n post: normalizeService(entityMeta.getSingleSignOnService(\"post\")),\n },\n slo: {\n redirect: normalizeService(entityMeta.getSingleLogoutService(\"redirect\")),\n post: normalizeService(entityMeta.getSingleLogoutService(\"post\")),\n },\n signingCert: entityMeta.getX509Certificate(\"signing\"),\n encryptionCert: entityMeta.getX509Certificate(\"encrypt\"),\n nameIdFormats: (() => {\n const nameIdFormat = entityMeta.getNameIDFormat();\n return Array.isArray(nameIdFormat) ? nameIdFormat : [];\n })(),\n wantsSignedAuthnRequests: entityMeta.isWantAuthnRequestsSigned(),\n };\n}\n\n/** @internal */\nexport function createServiceProviderMetadata(opts: {\n entityId: string;\n acsUrl: string;\n sloUrl?: string;\n authnRequestsSigned?: boolean;\n signingCert?: string | string[];\n encryptCert?: string | string[];\n privateKey?: string;\n privateKeyPass?: string;\n encPrivateKey?: string;\n encPrivateKeyPass?: string;\n}) {\n const binding = Constants.namespace.binding;\n const sp = ServiceProvider({\n entityID: opts.entityId,\n authnRequestsSigned: opts.authnRequestsSigned ?? false,\n privateKey: opts.privateKey,\n privateKeyPass: opts.privateKeyPass,\n signingCert: opts.signingCert,\n encryptCert: opts.encryptCert,\n encPrivateKey: opts.encPrivateKey,\n encPrivateKeyPass: opts.encPrivateKeyPass,\n assertionConsumerService: [\n {\n Binding: binding.post,\n Location: opts.acsUrl,\n },\n ],\n singleLogoutService: opts.sloUrl\n ? [\n {\n Binding: binding.redirect,\n Location: opts.sloUrl,\n },\n {\n Binding: binding.post,\n Location: opts.sloUrl,\n },\n ]\n : undefined,\n });\n return sp.getMetadata();\n}\n\n/** @internal */\nexport function createEnterpriseSamlMetadataXml(opts: {\n rootUrl: string;\n source: EnterpriseSamlSource;\n config: unknown;\n}) {\n return createServiceProviderMetadata(\n getSamlServiceProviderOptions({\n rootUrl: opts.rootUrl,\n source: opts.source,\n config: opts.config,\n }),\n );\n}\n\n/** @internal */\nexport function getSamlServiceProviderOptions(opts: {\n rootUrl: string;\n source: EnterpriseSamlSource;\n config: unknown;\n overrides?: {\n entityId?: string;\n acsUrl?: string;\n sloUrl?: string;\n };\n relayState?: string;\n}) {\n const saml = getSamlConfig(opts.config);\n const sp = asRecord(saml.sp) ?? {};\n const urls = getEnterpriseSamlUrls({\n rootUrl: opts.rootUrl,\n source: opts.source,\n });\n return {\n entityId: opts.overrides?.entityId ?? sp.entityId ?? urls.metadataUrl,\n acsUrl: opts.overrides?.acsUrl ?? sp.acsUrl ?? urls.acsUrl,\n sloUrl: opts.overrides?.sloUrl ?? sp.sloUrl ?? urls.sloUrl,\n relayState: opts.relayState,\n authnRequestsSigned: saml.signAuthnRequests,\n signingCert: sp.signingCert,\n encryptCert: sp.encryptCert,\n privateKey: sp.privateKey,\n privateKeyPass: sp.privateKeyPass,\n encPrivateKey: sp.encPrivateKey,\n encPrivateKeyPass: sp.encPrivateKeyPass,\n };\n}\n\n/** @internal */\nexport function createSamlServiceProvider(opts: {\n entityId: string;\n acsUrl: string;\n sloUrl?: string;\n relayState?: string;\n authnRequestsSigned?: boolean;\n signingCert?: string | string[];\n encryptCert?: string | string[];\n privateKey?: string;\n privateKeyPass?: string;\n encPrivateKey?: string;\n encPrivateKeyPass?: string;\n}) {\n const binding = Constants.namespace.binding;\n return ServiceProvider({\n entityID: opts.entityId,\n relayState: opts.relayState ?? \"\",\n authnRequestsSigned: opts.authnRequestsSigned ?? false,\n privateKey: opts.privateKey,\n privateKeyPass: opts.privateKeyPass,\n signingCert: opts.signingCert,\n encryptCert: opts.encryptCert,\n encPrivateKey: opts.encPrivateKey,\n encPrivateKeyPass: opts.encPrivateKeyPass,\n assertionConsumerService: [\n {\n Binding: binding.post,\n Location: opts.acsUrl,\n },\n ],\n singleLogoutService: opts.sloUrl\n ? [\n { Binding: binding.redirect, Location: opts.sloUrl },\n { Binding: binding.post, Location: opts.sloUrl },\n ]\n : undefined,\n });\n}\n\n/** @internal */\nexport function createEnterpriseSamlRuntime(opts: {\n rootUrl: string;\n source: EnterpriseSamlSource;\n config: unknown;\n relayState?: string;\n overrides?: {\n entityId?: string;\n acsUrl?: string;\n sloUrl?: string;\n };\n}) {\n const saml = getSamlConfig(opts.config);\n const spOptions = getSamlServiceProviderOptions({\n rootUrl: opts.rootUrl,\n source: opts.source,\n config: opts.config,\n relayState: opts.relayState,\n overrides: opts.overrides,\n });\n if (typeof saml.idp?.metadataXml !== \"string\") {\n throw new Error(\"SAML IdP metadata is missing.\");\n }\n return {\n saml,\n sp: createSamlServiceProvider(spOptions),\n idp: IdentityProvider({ metadata: saml.idp.metadataXml }),\n urls: getEnterpriseSamlUrls({ rootUrl: opts.rootUrl, source: opts.source }),\n };\n}\n\n/** @internal */\nexport function createEnterpriseSamlSignInRequest(opts: {\n rootUrl: string;\n source: EnterpriseSamlSource;\n config: unknown;\n state: string;\n signature: string;\n redirectTo?: string;\n}) {\n const runtime = createEnterpriseSamlRuntime({\n rootUrl: opts.rootUrl,\n source: opts.source,\n config: opts.config,\n });\n const binding = runtime.saml.idp.sso?.redirect ? \"redirect\" : \"post\";\n const loginRequest = runtime.sp.createLoginRequest(\n runtime.idp,\n binding as any,\n ) as any;\n const relayState = encodeEnterpriseSamlRelayState({\n source: opts.source,\n signature: opts.signature,\n requestId: loginRequest.id,\n state: opts.state,\n redirectTo: opts.redirectTo,\n });\n return {\n requestId: loginRequest.id as string,\n binding,\n relayState,\n redirectUrl:\n binding === \"redirect\"\n ? (() => {\n const redirectUrl = new URL(loginRequest.context);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n return redirectUrl.toString();\n })()\n : undefined,\n post:\n binding === \"post\"\n ? {\n endpoint: loginRequest.entityEndpoint as string,\n value: loginRequest.context as string,\n }\n : undefined,\n };\n}\n\n/** @internal */\nexport async function parseEnterpriseSamlLoginResponse(opts: {\n request: Request;\n rootUrl: string;\n source: EnterpriseSamlSource;\n config: unknown;\n}) {\n ensureSamlifyValidator();\n const httpRequest = await readEnterpriseSamlHttpRequest(opts.request);\n const runtime = createEnterpriseSamlRuntime({\n rootUrl: opts.rootUrl,\n source: opts.source,\n config: opts.config,\n });\n const parsed = (await runtime.sp.parseLoginResponse(\n runtime.idp as any,\n httpRequest.binding as any,\n {\n query: httpRequest.query,\n body: httpRequest.body,\n },\n )) as any;\n // Check for weak SAML algorithms and warn.\n warnWeakSamlAlgorithms(parsed);\n\n return {\n ...httpRequest,\n runtime,\n parsed,\n relayState: decodeEnterpriseSamlRelayStateOrThrow(\n httpRequest.relayState ?? null,\n ),\n };\n}\n\nconst WEAK_SAML_ALGORITHMS = new Set([\n // Signature algorithms\n \"http://www.w3.org/2000/09/xmldsig#rsa-sha1\",\n \"http://www.w3.org/2000/09/xmldsig#dsa-sha1\",\n // Digest algorithms\n \"http://www.w3.org/2000/09/xmldsig#sha1\",\n // Key encryption\n \"http://www.w3.org/2001/04/xmlenc#rsa-1_5\",\n // Data encryption\n \"http://www.w3.org/2001/04/xmlenc#tripledes-cbc\",\n]);\n\n/**\n * Warn when the SAML response uses weak cryptographic algorithms\n * such as SHA-1, RSA 1.5, or 3DES.\n */\nfunction warnWeakSamlAlgorithms(parsed: any) {\n try {\n const sigAlg =\n parsed?.extract?.signature?.signatureAlgorithm ??\n parsed?.extract?.response?.signatureAlgorithm;\n const digestAlg = parsed?.extract?.signature?.digestAlgorithm;\n\n if (sigAlg && WEAK_SAML_ALGORITHMS.has(sigAlg)) {\n console.warn(\n `[convex-auth] SAML response uses weak signature algorithm: ${sigAlg}. ` +\n `Consider upgrading your IdP to use RSA-SHA256 or stronger.`,\n );\n }\n if (digestAlg && WEAK_SAML_ALGORITHMS.has(digestAlg)) {\n console.warn(\n `[convex-auth] SAML response uses weak digest algorithm: ${digestAlg}. ` +\n `Consider upgrading your IdP to use SHA-256 or stronger.`,\n );\n }\n } catch {\n // Non-critical — don't break auth flow for algorithm check failures\n }\n}\n\n/** @internal */\nexport function validateEnterpriseSamlLoginRelayState(opts: {\n relayState: EnterpriseSamlRelayState;\n source: EnterpriseSamlSource;\n inResponseTo?: string;\n}) {\n if (\n opts.relayState.source.kind !== opts.source.kind ||\n opts.relayState.source.id !== opts.source.id ||\n opts.relayState.requestId !== opts.inResponseTo\n ) {\n throw new Error(\"SAML RelayState did not match the pending login request.\");\n }\n}\n\n/** @internal */\nexport async function parseEnterpriseSamlLogoutMessage(opts: {\n request: Request;\n rootUrl: string;\n source: EnterpriseSamlSource;\n config: unknown;\n}) {\n ensureSamlifyValidator();\n const httpRequest = await readEnterpriseSamlHttpRequest(opts.request);\n const runtime = createEnterpriseSamlRuntime({\n rootUrl: opts.rootUrl,\n source: opts.source,\n config: opts.config,\n relayState: httpRequest.relayState,\n });\n const parsedRequest = httpRequest.hasSamlRequest\n ? ((await runtime.sp.parseLogoutRequest(\n runtime.idp as any,\n httpRequest.binding as any,\n {\n query: httpRequest.query,\n body: httpRequest.body,\n },\n )) as any)\n : undefined;\n return {\n ...httpRequest,\n runtime,\n parsedRequest,\n };\n}\n\n/** @internal */\nexport function profileFromSamlExtract(\n extract: any,\n mapping?: SAMLAttributeMapping,\n) {\n const attributes =\n typeof extract?.attributes === \"object\" && extract.attributes !== null\n ? (extract.attributes as Record<string, unknown>)\n : {};\n const resolveFirst = (...keys: Array<string | undefined>) => {\n for (const key of keys) {\n if (!key) {\n continue;\n }\n const attribute = attributes[key];\n const value = Array.isArray(attribute) ? attribute[0] : attribute;\n if (value !== undefined) {\n return value;\n }\n }\n return undefined;\n };\n const fieldResolvers = {\n email: () => resolveFirst(mapping?.email),\n name: () =>\n resolveFirst(mapping?.name) ??\n ([resolveFirst(mapping?.firstName), resolveFirst(mapping?.lastName)]\n .filter(Boolean)\n .join(\" \") ||\n undefined),\n subject: () =>\n resolveFirst(mapping?.subject) ?? (extract?.nameID as string | undefined),\n } as const;\n const subject = fieldResolvers.subject() as string | undefined;\n if (subject === undefined) {\n throw new Error(\n \"SAML profile is missing a subject. Configure `attributeMapping.subject` or ensure the assertion includes a NameID.\",\n );\n }\n const email = fieldResolvers.email() as string | undefined;\n const name = fieldResolvers.name() as string | undefined;\n return {\n id: subject,\n email,\n emailVerified: typeof email === \"string\" ? true : undefined,\n name,\n samlAttributes: attributes,\n samlSessionIndex: extract?.sessionIndex?.SessionIndex as string | undefined,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import { SCIM_GROUP_SCHEMA_ID, SCIM_USER_SCHEMA_ID } from "./shared.js";
2
+
3
+ //#region src/server/enterprise/scim.ts
4
+ /** @internal */
5
+ function parseScimPath(pathname) {
6
+ const [api, auth, sso, enterpriseId, protocol, version, ...rest] = pathname.split("/").filter(Boolean);
7
+ if (api !== "api" || auth !== "auth" || sso !== "sso" || !enterpriseId || enterpriseId === "setup" || protocol !== "scim" || version !== "v2") return {
8
+ enterpriseId: "",
9
+ resource: "",
10
+ resourceId: void 0
11
+ };
12
+ return {
13
+ enterpriseId,
14
+ resource: rest[0] ?? "",
15
+ resourceId: rest[1]
16
+ };
17
+ }
18
+ /** @internal */
19
+ function parseScimListRequest(url) {
20
+ const startIndex = Math.max(1, Number(url.searchParams.get("startIndex") ?? "1"));
21
+ const count = Math.min(100, Math.max(1, Number(url.searchParams.get("count") ?? "100")));
22
+ const filterParam = url.searchParams.get("filter");
23
+ return {
24
+ startIndex,
25
+ count,
26
+ filter: filterParam ? (() => {
27
+ const match = filterParam.match(/^([A-Za-z0-9_.]+)\s+eq\s+"([^"]+)"$/);
28
+ if (!match) throw new Error("Unsupported SCIM filter.");
29
+ return {
30
+ attribute: match[1],
31
+ value: match[2]
32
+ };
33
+ })() : void 0
34
+ };
35
+ }
36
+ /** @internal */
37
+ function scimJson(data, status = 200, headers) {
38
+ const responseHeaders = new Headers({ "Content-Type": "application/scim+json" });
39
+ if (headers) new Headers(headers).forEach((value, key) => {
40
+ responseHeaders.set(key, value);
41
+ });
42
+ return new Response(JSON.stringify(data), {
43
+ status,
44
+ headers: responseHeaders
45
+ });
46
+ }
47
+ /** @internal */
48
+ function scimError(status, scimType, detail) {
49
+ return scimJson({
50
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
51
+ status: String(status),
52
+ scimType,
53
+ detail
54
+ }, status);
55
+ }
56
+ /** @internal */
57
+ function serializeScimUser(args) {
58
+ return {
59
+ schemas: [SCIM_USER_SCHEMA_ID],
60
+ id: args.id,
61
+ externalId: args.externalId,
62
+ meta: {
63
+ resourceType: "User",
64
+ location: args.location
65
+ },
66
+ userName: args.user.email ?? args.user.phone ?? args.user.name ?? args.id,
67
+ active: args.active ?? true,
68
+ name: args.user.name !== void 0 ? { formatted: args.user.name } : void 0,
69
+ emails: typeof args.user.email === "string" ? [{
70
+ value: args.user.email,
71
+ primary: true
72
+ }] : void 0,
73
+ phoneNumbers: typeof args.user.phone === "string" ? [{
74
+ value: args.user.phone,
75
+ primary: true
76
+ }] : void 0,
77
+ displayName: args.user.name
78
+ };
79
+ }
80
+ /** @internal */
81
+ function serializeScimGroup(args) {
82
+ return {
83
+ schemas: [SCIM_GROUP_SCHEMA_ID],
84
+ id: args.id,
85
+ externalId: args.externalId,
86
+ meta: {
87
+ resourceType: "Group",
88
+ location: args.location
89
+ },
90
+ displayName: args.group.name ?? args.id,
91
+ members: args.members ?? []
92
+ };
93
+ }
94
+
95
+ //#endregion
96
+ export { parseScimListRequest, parseScimPath, scimError, scimJson, serializeScimGroup, serializeScimUser };
97
+ //# sourceMappingURL=scim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scim.js","names":[],"sources":["../../../../src/server/enterprise/scim.ts"],"sourcesContent":["import type { ScimListRequest } from \"./shared\";\nimport { SCIM_GROUP_SCHEMA_ID, SCIM_USER_SCHEMA_ID } from \"./shared\";\n\n/** @internal */\nexport function parseScimPath(pathname: string) {\n const parts = pathname.split(\"/\").filter(Boolean);\n const [api, auth, sso, enterpriseId, protocol, version, ...rest] = parts;\n\n if (\n api !== \"api\" ||\n auth !== \"auth\" ||\n sso !== \"sso\" ||\n !enterpriseId ||\n enterpriseId === \"setup\" ||\n protocol !== \"scim\" ||\n version !== \"v2\"\n ) {\n return {\n enterpriseId: \"\",\n resource: \"\",\n resourceId: undefined,\n };\n }\n\n return {\n enterpriseId,\n resource: rest[0] ?? \"\",\n resourceId: rest[1],\n };\n}\n\n/** @internal */\nexport function parseScimListRequest(url: URL): ScimListRequest {\n const startIndex = Math.max(\n 1,\n Number(url.searchParams.get(\"startIndex\") ?? \"1\"),\n );\n const count = Math.min(\n 100,\n Math.max(1, Number(url.searchParams.get(\"count\") ?? \"100\")),\n );\n const filterParam = url.searchParams.get(\"filter\");\n const filter = filterParam\n ? (() => {\n const match = filterParam.match(/^([A-Za-z0-9_.]+)\\s+eq\\s+\"([^\"]+)\"$/);\n if (!match) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n return { attribute: match[1]!, value: match[2]! };\n })()\n : undefined;\n return { startIndex, count, filter };\n}\n\n/** @internal */\nexport function scimJson(data: unknown, status = 200, headers?: HeadersInit) {\n const responseHeaders = new Headers({\n \"Content-Type\": \"application/scim+json\",\n });\n if (headers) {\n new Headers(headers).forEach((value, key) => {\n responseHeaders.set(key, value);\n });\n }\n return new Response(JSON.stringify(data), {\n status,\n headers: responseHeaders,\n });\n}\n\n/** @internal */\nexport function scimError(status: number, scimType: string, detail: string) {\n return scimJson(\n {\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:Error\"],\n status: String(status),\n scimType,\n detail,\n },\n status,\n );\n}\n\n/** @internal */\nexport function serializeScimUser(args: {\n id: string;\n user: Record<string, any>;\n externalId?: string;\n active?: boolean;\n location?: string;\n}) {\n return {\n schemas: [SCIM_USER_SCHEMA_ID],\n id: args.id,\n externalId: args.externalId,\n meta: {\n resourceType: \"User\",\n location: args.location,\n },\n userName: args.user.email ?? args.user.phone ?? args.user.name ?? args.id,\n active: args.active ?? true,\n name:\n args.user.name !== undefined ? { formatted: args.user.name } : undefined,\n emails:\n typeof args.user.email === \"string\"\n ? [{ value: args.user.email, primary: true }]\n : undefined,\n phoneNumbers:\n typeof args.user.phone === \"string\"\n ? [{ value: args.user.phone, primary: true }]\n : undefined,\n displayName: args.user.name,\n };\n}\n\n/** @internal */\nexport function serializeScimGroup(args: {\n id: string;\n group: Record<string, any>;\n externalId?: string;\n members?: Array<{ value: string; display?: string }>;\n location?: string;\n}) {\n return {\n schemas: [SCIM_GROUP_SCHEMA_ID],\n id: args.id,\n externalId: args.externalId,\n meta: {\n resourceType: \"Group\",\n location: args.location,\n },\n displayName: args.group.name ?? args.id,\n members: args.members ?? [],\n };\n}\n"],"mappings":";;;;AAIA,SAAgB,cAAc,UAAkB;CAE9C,MAAM,CAAC,KAAK,MAAM,KAAK,cAAc,UAAU,SAAS,GAAG,QAD7C,SAAS,MAAM,IAAI,CAAC,OAAO,QAAQ;AAGjD,KACE,QAAQ,SACR,SAAS,UACT,QAAQ,SACR,CAAC,gBACD,iBAAiB,WACjB,aAAa,UACb,YAAY,KAEZ,QAAO;EACL,cAAc;EACd,UAAU;EACV,YAAY;EACb;AAGH,QAAO;EACL;EACA,UAAU,KAAK,MAAM;EACrB,YAAY,KAAK;EAClB;;;AAIH,SAAgB,qBAAqB,KAA2B;CAC9D,MAAM,aAAa,KAAK,IACtB,GACA,OAAO,IAAI,aAAa,IAAI,aAAa,IAAI,IAAI,CAClD;CACD,MAAM,QAAQ,KAAK,IACjB,KACA,KAAK,IAAI,GAAG,OAAO,IAAI,aAAa,IAAI,QAAQ,IAAI,MAAM,CAAC,CAC5D;CACD,MAAM,cAAc,IAAI,aAAa,IAAI,SAAS;AAUlD,QAAO;EAAE;EAAY;EAAO,QATb,qBACJ;GACL,MAAM,QAAQ,YAAY,MAAM,sCAAsC;AACtE,OAAI,CAAC,MACH,OAAM,IAAI,MAAM,2BAA2B;AAE7C,UAAO;IAAE,WAAW,MAAM;IAAK,OAAO,MAAM;IAAK;MAC/C,GACJ;EACgC;;;AAItC,SAAgB,SAAS,MAAe,SAAS,KAAK,SAAuB;CAC3E,MAAM,kBAAkB,IAAI,QAAQ,EAClC,gBAAgB,yBACjB,CAAC;AACF,KAAI,QACF,KAAI,QAAQ,QAAQ,CAAC,SAAS,OAAO,QAAQ;AAC3C,kBAAgB,IAAI,KAAK,MAAM;GAC/B;AAEJ,QAAO,IAAI,SAAS,KAAK,UAAU,KAAK,EAAE;EACxC;EACA,SAAS;EACV,CAAC;;;AAIJ,SAAgB,UAAU,QAAgB,UAAkB,QAAgB;AAC1E,QAAO,SACL;EACE,SAAS,CAAC,8CAA8C;EACxD,QAAQ,OAAO,OAAO;EACtB;EACA;EACD,EACD,OACD;;;AAIH,SAAgB,kBAAkB,MAM/B;AACD,QAAO;EACL,SAAS,CAAC,oBAAoB;EAC9B,IAAI,KAAK;EACT,YAAY,KAAK;EACjB,MAAM;GACJ,cAAc;GACd,UAAU,KAAK;GAChB;EACD,UAAU,KAAK,KAAK,SAAS,KAAK,KAAK,SAAS,KAAK,KAAK,QAAQ,KAAK;EACvE,QAAQ,KAAK,UAAU;EACvB,MACE,KAAK,KAAK,SAAS,SAAY,EAAE,WAAW,KAAK,KAAK,MAAM,GAAG;EACjE,QACE,OAAO,KAAK,KAAK,UAAU,WACvB,CAAC;GAAE,OAAO,KAAK,KAAK;GAAO,SAAS;GAAM,CAAC,GAC3C;EACN,cACE,OAAO,KAAK,KAAK,UAAU,WACvB,CAAC;GAAE,OAAO,KAAK,KAAK;GAAO,SAAS;GAAM,CAAC,GAC3C;EACN,aAAa,KAAK,KAAK;EACxB;;;AAIH,SAAgB,mBAAmB,MAMhC;AACD,QAAO;EACL,SAAS,CAAC,qBAAqB;EAC/B,IAAI,KAAK;EACT,YAAY,KAAK;EACjB,MAAM;GACJ,cAAc;GACd,UAAU,KAAK;GAChB;EACD,aAAa,KAAK,MAAM,QAAQ,KAAK;EACrC,SAAS,KAAK,WAAW,EAAE;EAC5B"}
@@ -0,0 +1,51 @@
1
+ //#region src/server/enterprise/shared.ts
2
+ /** @internal */
3
+ const SCIM_USER_SCHEMA_ID = "urn:ietf:params:scim:schemas:core:2.0:User";
4
+ /** @internal */
5
+ const SCIM_GROUP_SCHEMA_ID = "urn:ietf:params:scim:schemas:core:2.0:Group";
6
+ /** @internal */
7
+ const ENTERPRISE_OIDC_PROVIDER_PREFIX = "enterprise:oidc:";
8
+ /** @internal */
9
+ const ENTERPRISE_SAML_PROVIDER_PREFIX = "enterprise:saml:";
10
+ /** @internal */
11
+ function normalizeDomain(domain) {
12
+ return domain.trim().toLowerCase().replace(/^@+/, "");
13
+ }
14
+ /** @internal */
15
+ function enterpriseOidcProviderId(enterpriseId) {
16
+ return `${ENTERPRISE_OIDC_PROVIDER_PREFIX}${enterpriseId}`;
17
+ }
18
+ /** @internal */
19
+ function enterpriseSamlProviderId(enterpriseId) {
20
+ return `${ENTERPRISE_SAML_PROVIDER_PREFIX}${enterpriseId}`;
21
+ }
22
+ /** @internal */
23
+ function getEnterpriseSamlUrls(opts) {
24
+ const root = opts.rootUrl.replace(/\/$/, "");
25
+ return {
26
+ metadataUrl: `${root}/api/auth/sso/${opts.source.id}/saml/metadata`,
27
+ acsUrl: `${root}/api/auth/sso/${opts.source.id}/saml/acs`,
28
+ sloUrl: `${root}/api/auth/sso/${opts.source.id}/saml/slo`
29
+ };
30
+ }
31
+ /** @internal */
32
+ function getEnterpriseOidcUrls(opts) {
33
+ const root = opts.rootUrl.replace(/\/$/, "");
34
+ return {
35
+ signInUrl: `${root}/api/auth/sso/${opts.enterpriseId}/oidc/signin`,
36
+ callbackUrl: `${root}/api/auth/sso/${opts.enterpriseId}/oidc/callback`
37
+ };
38
+ }
39
+ /** @internal */
40
+ function isEnterpriseSamlSourceActive(source) {
41
+ return source.status === "active";
42
+ }
43
+ /** @internal */
44
+ function isEnterpriseProviderId(providerId) {
45
+ return providerId.startsWith(ENTERPRISE_OIDC_PROVIDER_PREFIX) || providerId.startsWith(ENTERPRISE_SAML_PROVIDER_PREFIX);
46
+ }
47
+ const asRecord = (value) => typeof value === "object" && value !== null ? value : null;
48
+
49
+ //#endregion
50
+ export { ENTERPRISE_OIDC_PROVIDER_PREFIX, ENTERPRISE_SAML_PROVIDER_PREFIX, SCIM_GROUP_SCHEMA_ID, SCIM_USER_SCHEMA_ID, asRecord, enterpriseOidcProviderId, enterpriseSamlProviderId, getEnterpriseOidcUrls, getEnterpriseSamlUrls, isEnterpriseProviderId, isEnterpriseSamlSourceActive, normalizeDomain };
51
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","names":[],"sources":["../../../../src/server/enterprise/shared.ts"],"sourcesContent":["/** @internal */\nexport type ParsedSamlMetadata = {\n issuer: string;\n sso: {\n redirect?: string;\n post?: string;\n };\n slo: {\n redirect?: string;\n post?: string;\n };\n signingCert: string | string[] | null;\n encryptionCert: string | string[] | null;\n nameIdFormats: string[];\n wantsSignedAuthnRequests: boolean;\n};\n\n/** @internal */\nexport type EnterpriseSamlSource = { kind: \"enterprise\"; id: string };\n\n/** @internal */\nexport type EnterpriseSamlRelayState = {\n source: EnterpriseSamlSource;\n signature: string;\n requestId: string;\n state: string;\n redirectTo?: string;\n};\n\n/** @internal */\nexport type EnterpriseSamlUrls = {\n metadataUrl: string;\n acsUrl: string;\n sloUrl?: string;\n};\n\n/** @internal */\nexport type EnterpriseSamlLoadedSource = {\n source: EnterpriseSamlSource;\n config: unknown;\n status?: string;\n};\n\n/** @internal */\nexport type EnterpriseSamlHttpRequest = {\n url: URL;\n body: Record<string, string>;\n query: Record<string, string>;\n binding: \"redirect\" | \"post\";\n relayState?: string;\n hasSamlRequest: boolean;\n hasSamlResponse: boolean;\n};\n\n/** @internal */\nexport type ScimListRequest = {\n startIndex: number;\n count: number;\n filter?: { attribute: string; value: string };\n};\n\n/** @internal */\nexport const SCIM_USER_SCHEMA_ID = \"urn:ietf:params:scim:schemas:core:2.0:User\";\n/** @internal */\nexport const SCIM_GROUP_SCHEMA_ID =\n \"urn:ietf:params:scim:schemas:core:2.0:Group\";\n\n/** @internal */\nexport const ENTERPRISE_OIDC_PROVIDER_PREFIX = \"enterprise:oidc:\";\n/** @internal */\nexport const ENTERPRISE_SAML_PROVIDER_PREFIX = \"enterprise:saml:\";\n\n/** @internal */\nexport function normalizeDomain(domain: string): string {\n return domain.trim().toLowerCase().replace(/^@+/, \"\");\n}\n\n/** @internal */\nexport function enterpriseOidcProviderId(enterpriseId: string): string {\n return `${ENTERPRISE_OIDC_PROVIDER_PREFIX}${enterpriseId}`;\n}\n\n/** @internal */\nexport function enterpriseSamlProviderId(enterpriseId: string): string {\n return `${ENTERPRISE_SAML_PROVIDER_PREFIX}${enterpriseId}`;\n}\n\n/** @internal */\nexport function getEnterpriseSamlUrls(opts: {\n rootUrl: string;\n source: EnterpriseSamlSource;\n}): EnterpriseSamlUrls {\n const root = opts.rootUrl.replace(/\\/$/, \"\");\n const metadataBase = `${root}/api/auth/sso/${opts.source.id}/saml/metadata`;\n const acsBase = `${root}/api/auth/sso/${opts.source.id}/saml/acs`;\n const sloBase = `${root}/api/auth/sso/${opts.source.id}/saml/slo`;\n return {\n metadataUrl: metadataBase,\n acsUrl: acsBase,\n sloUrl: sloBase,\n };\n}\n\n/** @internal */\nexport function getEnterpriseOidcUrls(opts: {\n rootUrl: string;\n enterpriseId: string;\n}) {\n const root = opts.rootUrl.replace(/\\/$/, \"\");\n return {\n signInUrl: `${root}/api/auth/sso/${opts.enterpriseId}/oidc/signin`,\n callbackUrl: `${root}/api/auth/sso/${opts.enterpriseId}/oidc/callback`,\n };\n}\n\n/** @internal */\nexport function isEnterpriseSamlSourceActive(\n source: EnterpriseSamlLoadedSource,\n) {\n return source.status === \"active\";\n}\n\n/** @internal */\nexport function isEnterpriseProviderId(providerId: string): boolean {\n return (\n providerId.startsWith(ENTERPRISE_OIDC_PROVIDER_PREFIX) ||\n providerId.startsWith(ENTERPRISE_SAML_PROVIDER_PREFIX)\n );\n}\n\nexport const asRecord = (value: unknown) =>\n typeof value === \"object\" && value !== null\n ? (value as Record<string, any>)\n : null;\n"],"mappings":";;AA8DA,MAAa,sBAAsB;;AAEnC,MAAa,uBACX;;AAGF,MAAa,kCAAkC;;AAE/C,MAAa,kCAAkC;;AAG/C,SAAgB,gBAAgB,QAAwB;AACtD,QAAO,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,OAAO,GAAG;;;AAIvD,SAAgB,yBAAyB,cAA8B;AACrE,QAAO,GAAG,kCAAkC;;;AAI9C,SAAgB,yBAAyB,cAA8B;AACrE,QAAO,GAAG,kCAAkC;;;AAI9C,SAAgB,sBAAsB,MAGf;CACrB,MAAM,OAAO,KAAK,QAAQ,QAAQ,OAAO,GAAG;AAI5C,QAAO;EACL,aAJmB,GAAG,KAAK,gBAAgB,KAAK,OAAO,GAAG;EAK1D,QAJc,GAAG,KAAK,gBAAgB,KAAK,OAAO,GAAG;EAKrD,QAJc,GAAG,KAAK,gBAAgB,KAAK,OAAO,GAAG;EAKtD;;;AAIH,SAAgB,sBAAsB,MAGnC;CACD,MAAM,OAAO,KAAK,QAAQ,QAAQ,OAAO,GAAG;AAC5C,QAAO;EACL,WAAW,GAAG,KAAK,gBAAgB,KAAK,aAAa;EACrD,aAAa,GAAG,KAAK,gBAAgB,KAAK,aAAa;EACxD;;;AAIH,SAAgB,6BACd,QACA;AACA,QAAO,OAAO,WAAW;;;AAI3B,SAAgB,uBAAuB,YAA6B;AAClE,QACE,WAAW,WAAW,gCAAgC,IACtD,WAAW,WAAW,gCAAgC;;AAI1D,MAAa,YAAY,UACvB,OAAO,UAAU,YAAY,UAAU,OAClC,QACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../../../src/server/errors.ts"],"sourcesContent":["/**\n * Structured error handling for Convex Auth.\n *\n * Every error thrown by the auth system uses `ConvexError` with a\n * `{ code, message }` payload so clients can distinguish error types\n * and display user-friendly messages.\n *\n * **Consumer API:** Use {@link throwAuthError} to throw structured errors\n * from your own Convex functions (e.g. custom authorization checks).\n *\n * **Internal pattern:** The library itself uses `new AuthError(code)` with\n * the `@robelest/fx` effect system (`Fx.fail(new AuthError(code))`).\n * You do not need to use `AuthError` directly — it is an implementation detail.\n *\n * @module\n */\n\nimport { ConvexError } from \"convex/values\";\n\n// ============================================================================\n// Error code → default message map (single source of truth)\n// ============================================================================\n\n/**\n * Map of every auth error code to its default human-readable message.\n *\n * Use the keys as the `code` argument to {@link throwAuthError}.\n * Clients can match on these codes for conditional error handling.\n *\n * @example\n * ```ts\n * throwAuthError(\"NOT_SIGNED_IN\");\n * // ConvexError { data: { code: \"NOT_SIGNED_IN\", message: \"You must be signed in...\" } }\n * ```\n */\nexport const AUTH_ERRORS = {\n // ---- Configuration ----\n PROVIDER_NOT_CONFIGURED: \"This sign-in method is not available.\",\n EMAIL_CONFIG_REQUIRED:\n \"Email transport is not configured. Configure email in createAuth(...).\",\n MISSING_ENV_VAR: \"A required server environment variable is missing.\",\n MISSING_ACTION_CONTEXT: \"Action context is required for this operation.\",\n INVALID_PARAMETERS: \"The provided parameters are invalid.\",\n\n // ---- Authentication ----\n NOT_SIGNED_IN: \"You must be signed in to perform this action.\",\n INVALID_VERIFICATION_CODE: \"Invalid or expired verification code.\",\n INVALID_REFRESH_TOKEN: \"Your session has expired. Please sign in again.\",\n AUTH_HANDSHAKE_TIMEOUT:\n \"Sign-in succeeded but authentication confirmation timed out.\",\n AUTH_HANDSHAKE_REJECTED:\n \"Authentication was rejected while confirming the session.\",\n SIGN_IN_MISSING_PARAMS:\n \"Cannot sign in: missing provider, code, or refresh token.\",\n UNSUPPORTED_PROVIDER_TYPE: \"This provider type is not supported.\",\n INVALID_REDIRECT: \"Invalid redirect URL.\",\n\n // ---- Email / Phone ----\n EMAIL_SEND_FAILED: \"Failed to send verification email. Please try again.\",\n\n // ---- API Keys ----\n INVALID_API_KEY: \"Invalid API key.\",\n API_KEY_REVOKED: \"This API key has been revoked.\",\n API_KEY_EXPIRED: \"This API key has expired.\",\n API_KEY_RATE_LIMITED: \"API key rate limit exceeded. Please try again later.\",\n API_KEY_INVALID_SCOPE: \"Invalid scope requested for API key.\",\n KEY_NOT_FOUND: \"API key not found.\",\n\n // ---- HTTP Bearer Auth ----\n MISSING_BEARER_TOKEN: \"Missing or malformed Authorization: Bearer header.\",\n SCOPE_CHECK_FAILED: \"This API key does not have the required permissions.\",\n\n // ---- OAuth ----\n OAUTH_MISSING_PROVIDER: \"Missing OAuth provider ID.\",\n OAUTH_MISSING_VERIFIER: \"Missing sign-in verifier.\",\n OAUTH_INVALID_STATE: \"Invalid OAuth state. Please try signing in again.\",\n OAUTH_PROVIDER_ERROR: \"The sign-in provider returned an error.\",\n OAUTH_MISSING_ID_TOKEN:\n \"ID token claims are missing from the provider response.\",\n OAUTH_INVALID_PROFILE: \"The sign-in provider returned an invalid profile.\",\n OAUTH_UNSUPPORTED_AUTH_METHOD:\n \"Unsupported OAuth client authentication method.\",\n OAUTH_NO_USERINFO: \"No userinfo endpoint configured for this provider.\",\n\n // ---- Credentials ----\n ACCOUNT_ALREADY_EXISTS: \"An account with these credentials already exists.\",\n ACCOUNT_NOT_FOUND: \"Account not found.\",\n INVALID_CREDENTIALS_PROVIDER:\n \"This provider does not support credential operations.\",\n MISSING_CRYPTO_FUNCTION:\n \"This provider is missing a required cryptographic function.\",\n USER_UPDATE_FAILED: \"Could not update the user record.\",\n\n // ---- Verifier ----\n INVALID_VERIFIER: \"Invalid or expired verifier.\",\n\n // ---- Passkey ----\n PASSKEY_MISSING_CONFIG:\n \"Passkey provider requires SITE_URL or explicit rpId configuration.\",\n PASSKEY_AUTH_REQUIRED: \"Sign in first, then add a passkey to your account.\",\n PASSKEY_MISSING_VERIFIER: \"Missing verifier for passkey operation.\",\n PASSKEY_INVALID_CLIENT_DATA: \"Invalid passkey client data.\",\n PASSKEY_INVALID_ORIGIN: \"Passkey origin does not match the expected value.\",\n PASSKEY_INVALID_CHALLENGE: \"Invalid or expired passkey challenge.\",\n PASSKEY_RP_MISMATCH: \"Relying party ID mismatch.\",\n PASSKEY_USER_PRESENCE: \"User presence flag not set.\",\n PASSKEY_USER_VERIFICATION: \"User verification required but not performed.\",\n PASSKEY_NO_CREDENTIAL: \"No credential in attestation.\",\n PASSKEY_UNSUPPORTED_ALGORITHM: \"Unsupported passkey algorithm.\",\n PASSKEY_INVALID_SIGNATURE: \"Invalid passkey signature.\",\n PASSKEY_UNKNOWN_CREDENTIAL: \"Unknown passkey credential.\",\n PASSKEY_COUNTER_ERROR:\n \"Authenticator counter did not increase — possible credential cloning detected.\",\n PASSKEY_MISSING_FLOW: \"Missing passkey flow parameter.\",\n PASSKEY_UNKNOWN_FLOW: \"Unknown passkey flow.\",\n\n // ---- TOTP ----\n TOTP_AUTH_REQUIRED: \"Sign in first, then set up two-factor authentication.\",\n TOTP_MISSING_VERIFIER: \"Missing verifier for TOTP operation.\",\n TOTP_MISSING_CODE: \"Missing TOTP code.\",\n TOTP_MISSING_ID: \"Missing TOTP enrollment ID.\",\n TOTP_NOT_FOUND: \"TOTP enrollment not found.\",\n TOTP_ALREADY_VERIFIED: \"TOTP enrollment is already verified.\",\n TOTP_INVALID_CODE: \"Invalid TOTP code.\",\n TOTP_INVALID_VERIFIER: \"Invalid or expired TOTP verifier.\",\n TOTP_NO_ENROLLMENT: \"No verified TOTP enrollment found.\",\n TOTP_MISSING_FLOW: \"Missing TOTP flow parameter.\",\n TOTP_UNKNOWN_FLOW: \"Unknown TOTP flow.\",\n\n // ---- Device Authorization (RFC 8628) ----\n DEVICE_CODE_EXPIRED:\n \"The device code has expired. Please start a new authorization request.\",\n DEVICE_CODE_DENIED: \"The authorization request was denied.\",\n DEVICE_AUTHORIZATION_PENDING: \"The user has not yet authorized this device.\",\n DEVICE_SLOW_DOWN:\n \"Polling too frequently. Increase the interval between requests.\",\n DEVICE_INVALID_USER_CODE: \"Invalid or expired user code.\",\n DEVICE_ALREADY_AUTHORIZED: \"This device code has already been authorized.\",\n DEVICE_MISSING_FLOW: \"Missing device flow parameter.\",\n DEVICE_UNKNOWN_FLOW: \"Unknown device flow.\",\n\n // ---- Invites ----\n INVITE_EXPIRED: \"This invitation has expired.\",\n INVITE_EMAIL_MISMATCH: \"This invitation is for a different email.\",\n INVITE_ALREADY_ACCEPTED: \"This invitation has already been accepted.\",\n DUPLICATE_INVITE:\n \"A pending invite already exists for this email in this group.\",\n INVITE_NOT_FOUND: \"Invite not found.\",\n INVITE_NOT_PENDING: \"Cannot accept or revoke invite that is not pending.\",\n\n // ---- Groups / Members ----\n FORBIDDEN: \"Access denied.\",\n NO_ACTIVE_GROUP: \"User has no active group set.\",\n DUPLICATE_MEMBERSHIP: \"User is already a member of this group.\",\n\n // ---- Enterprise ----\n ENTERPRISE_ALREADY_EXISTS:\n \"An enterprise record already exists for this group.\",\n ENTERPRISE_DOMAIN_TAKEN:\n \"That domain is already attached to another enterprise.\",\n\n // ---- Internal (should never reach user) ----\n INTERNAL_ERROR: \"An unexpected error occurred.\",\n} as const satisfies Record<string, string>;\n\n/** Union of all recognized auth error code strings (keys of {@link AUTH_ERRORS}). */\nexport type AuthErrorCode = keyof typeof AUTH_ERRORS;\n\n// ============================================================================\n// Error helpers\n// ============================================================================\n\n/**\n * Throw a structured `ConvexError` with `{ code, message }`.\n *\n * Use this in your own Convex functions (queries, mutations, actions)\n * to throw auth-domain errors that clients can match on by `code`.\n * The library itself uses `AuthError` internally, but consumers\n * should prefer this helper for simplicity.\n *\n * @param code Machine-readable error code from `AUTH_ERRORS`.\n * @param message Optional override for the default human-readable message.\n * @param context Optional extra fields merged into the error payload.\n *\n * @example\n * ```ts\n * import { throwAuthError } from \"@robelest/convex-auth/server\";\n *\n * // In a custom mutation:\n * if (!isAdmin) {\n * throwAuthError(\"FORBIDDEN\");\n * }\n * ```\n */\nexport function throwAuthError(\n code: AuthErrorCode,\n message?: string,\n context?: Record<string, unknown>,\n): never {\n throw new ConvexError({\n code,\n message: message ?? AUTH_ERRORS[code],\n ...context,\n });\n}\n\n/**\n * Type guard: check whether a caught value is a structured auth `ConvexError`.\n *\n * @param error - The caught value (typically from a `catch` block).\n * @returns `true` when `error` is a `ConvexError` with `{ code, message }` data.\n *\n * @example\n * ```ts\n * try { await auth.signIn('email', { email }); }\n * catch (e) {\n * if (isAuthError(e)) console.log(e.data.code); // \"EMAIL_SEND_FAILED\"\n * }\n * ```\n */\nexport function isAuthError(\n error: unknown,\n): error is ConvexError<{ code: AuthErrorCode; message: string }> {\n return (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n );\n}\n\n/**\n * Extract `{ code, message }` from a caught error.\n *\n * Works for `ConvexError` (from Convex actions), plain `Error`\n * instances, and structured auth errors. Returns `null` when the\n * value is not an error object.\n *\n * @param error - The caught value to parse.\n * @returns `{ code, message }` when extractable, or `null`.\n * When `code` is `null`, the error is not a structured auth error\n * but `message` still contains the error text.\n *\n * @example\n * ```ts\n * try {\n * await auth.signIn(\"email\", { email });\n * } catch (e) {\n * const err = parseAuthError(e);\n * if (err?.code === \"EMAIL_SEND_FAILED\") { ... }\n * }\n * ```\n */\nexport function parseAuthError(\n error: unknown,\n):\n | { code: AuthErrorCode; message: string }\n | { code: null; message: string }\n | null {\n if (isAuthError(error)) {\n const { code, message } = error.data as {\n code: AuthErrorCode;\n message: string;\n };\n return { code, message };\n }\n // Recognize the Fx-native AuthError class (has _tag + code)\n if (\n error instanceof Error &&\n \"_tag\" in error &&\n (error as any)._tag === \"AuthError\" &&\n \"code\" in error &&\n typeof (error as any).code === \"string\"\n ) {\n return {\n code: (error as any).code as AuthErrorCode,\n message: error.message,\n };\n }\n if (error instanceof ConvexError && typeof error.data === \"string\") {\n return { code: null, message: error.data };\n }\n if (error instanceof Error) {\n return { code: null, message: error.message };\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAa,cAAc;CAEzB,yBAAyB;CACzB,uBACE;CACF,iBAAiB;CACjB,wBAAwB;CACxB,oBAAoB;CAGpB,eAAe;CACf,2BAA2B;CAC3B,uBAAuB;CACvB,wBACE;CACF,yBACE;CACF,wBACE;CACF,2BAA2B;CAC3B,kBAAkB;CAGlB,mBAAmB;CAGnB,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,sBAAsB;CACtB,uBAAuB;CACvB,eAAe;CAGf,sBAAsB;CACtB,oBAAoB;CAGpB,wBAAwB;CACxB,wBAAwB;CACxB,qBAAqB;CACrB,sBAAsB;CACtB,wBACE;CACF,uBAAuB;CACvB,+BACE;CACF,mBAAmB;CAGnB,wBAAwB;CACxB,mBAAmB;CACnB,8BACE;CACF,yBACE;CACF,oBAAoB;CAGpB,kBAAkB;CAGlB,wBACE;CACF,uBAAuB;CACvB,0BAA0B;CAC1B,6BAA6B;CAC7B,wBAAwB;CACxB,2BAA2B;CAC3B,qBAAqB;CACrB,uBAAuB;CACvB,2BAA2B;CAC3B,uBAAuB;CACvB,+BAA+B;CAC/B,2BAA2B;CAC3B,4BAA4B;CAC5B,uBACE;CACF,sBAAsB;CACtB,sBAAsB;CAGtB,oBAAoB;CACpB,uBAAuB;CACvB,mBAAmB;CACnB,iBAAiB;CACjB,gBAAgB;CAChB,uBAAuB;CACvB,mBAAmB;CACnB,uBAAuB;CACvB,oBAAoB;CACpB,mBAAmB;CACnB,mBAAmB;CAGnB,qBACE;CACF,oBAAoB;CACpB,8BAA8B;CAC9B,kBACE;CACF,0BAA0B;CAC1B,2BAA2B;CAC3B,qBAAqB;CACrB,qBAAqB;CAGrB,gBAAgB;CAChB,uBAAuB;CACvB,yBAAyB;CACzB,kBACE;CACF,kBAAkB;CAClB,oBAAoB;CAGpB,WAAW;CACX,iBAAiB;CACjB,sBAAsB;CAGtB,2BACE;CACF,yBACE;CAGF,gBAAgB;CACjB;;;;;;;;;;;;;;;AAyDD,SAAgB,YACd,OACgE;AAChE,QACE,iBAAiB,eACjB,OAAO,MAAM,SAAS,YACtB,MAAM,SAAS,QACf,UAAU,MAAM,QAChB,aAAa,MAAM"}
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../../../src/server/errors.ts"],"sourcesContent":["/**\n * Structured error handling for Convex Auth.\n *\n * Every error thrown by the auth system uses `ConvexError` with a\n * `{ code, message }` payload so clients can distinguish error types\n * and display user-friendly messages.\n *\n * **Consumer API:** Use {@link throwAuthError} to throw structured errors\n * from your own Convex functions (e.g. custom authorization checks).\n *\n * **Internal pattern:** The library itself uses `new AuthError(code)` with\n * the `@robelest/fx` effect system (`Fx.fail(new AuthError(code))`).\n * You do not need to use `AuthError` directly — it is an implementation detail.\n *\n * @module\n */\n\nimport { ConvexError } from \"convex/values\";\n\n// ============================================================================\n// Error code → default message map (single source of truth)\n// ============================================================================\n\n/**\n * Map of every auth error code to its default human-readable message.\n *\n * Use the keys as the `code` argument to {@link throwAuthError}.\n * Clients can match on these codes for conditional error handling.\n *\n * @example\n * ```ts\n * throwAuthError(\"NOT_SIGNED_IN\");\n * // ConvexError { data: { code: \"NOT_SIGNED_IN\", message: \"You must be signed in...\" } }\n * ```\n */\nexport const AUTH_ERRORS = {\n // ---- Configuration ----\n PROVIDER_NOT_CONFIGURED: \"This sign-in method is not available.\",\n EMAIL_CONFIG_REQUIRED:\n \"Email transport is not configured. Configure email in createAuth(...).\",\n MISSING_ENV_VAR: \"A required server environment variable is missing.\",\n MISSING_ACTION_CONTEXT: \"Action context is required for this operation.\",\n INVALID_PARAMETERS: \"The provided parameters are invalid.\",\n\n // ---- Authentication ----\n NOT_SIGNED_IN: \"You must be signed in to perform this action.\",\n INVALID_VERIFICATION_CODE: \"Invalid or expired verification code.\",\n INVALID_REFRESH_TOKEN: \"Your session has expired. Please sign in again.\",\n AUTH_HANDSHAKE_TIMEOUT:\n \"Sign-in succeeded but authentication confirmation timed out.\",\n AUTH_HANDSHAKE_REJECTED:\n \"Authentication was rejected while confirming the session.\",\n SIGN_IN_MISSING_PARAMS:\n \"Cannot sign in: missing provider, code, or refresh token.\",\n UNSUPPORTED_PROVIDER_TYPE: \"This provider type is not supported.\",\n INVALID_REDIRECT: \"Invalid redirect URL.\",\n\n // ---- Email / Phone ----\n EMAIL_SEND_FAILED: \"Failed to send verification email. Please try again.\",\n\n // ---- API Keys ----\n INVALID_API_KEY: \"Invalid API key.\",\n API_KEY_REVOKED: \"This API key has been revoked.\",\n API_KEY_EXPIRED: \"This API key has expired.\",\n API_KEY_RATE_LIMITED: \"API key rate limit exceeded. Please try again later.\",\n API_KEY_INVALID_SCOPE: \"Invalid scope requested for API key.\",\n KEY_NOT_FOUND: \"API key not found.\",\n\n // ---- HTTP Bearer Auth ----\n MISSING_BEARER_TOKEN: \"Missing or malformed Authorization: Bearer header.\",\n SCOPE_CHECK_FAILED: \"This API key does not have the required permissions.\",\n\n // ---- OAuth ----\n OAUTH_MISSING_PROVIDER: \"Missing OAuth provider ID.\",\n OAUTH_MISSING_VERIFIER: \"Missing sign-in verifier.\",\n OAUTH_INVALID_STATE: \"Invalid OAuth state. Please try signing in again.\",\n OAUTH_PROVIDER_ERROR: \"The sign-in provider returned an error.\",\n OAUTH_MISSING_ID_TOKEN:\n \"ID token claims are missing from the provider response.\",\n OAUTH_INVALID_PROFILE: \"The sign-in provider returned an invalid profile.\",\n OAUTH_UNSUPPORTED_AUTH_METHOD:\n \"Unsupported OAuth client authentication method.\",\n OAUTH_NO_USERINFO: \"No userinfo endpoint configured for this provider.\",\n\n // ---- Credentials ----\n ACCOUNT_ALREADY_EXISTS: \"An account with these credentials already exists.\",\n ACCOUNT_NOT_FOUND: \"Account not found.\",\n INVALID_CREDENTIALS_PROVIDER:\n \"This provider does not support credential operations.\",\n MISSING_CRYPTO_FUNCTION:\n \"This provider is missing a required cryptographic function.\",\n USER_UPDATE_FAILED: \"Could not update the user record.\",\n\n // ---- Verifier ----\n INVALID_VERIFIER: \"Invalid or expired verifier.\",\n\n // ---- Passkey ----\n PASSKEY_MISSING_CONFIG:\n \"Passkey provider requires SITE_URL or explicit rpId configuration.\",\n PASSKEY_AUTH_REQUIRED: \"Sign in first, then add a passkey to your account.\",\n PASSKEY_MISSING_VERIFIER: \"Missing verifier for passkey operation.\",\n PASSKEY_INVALID_CLIENT_DATA: \"Invalid passkey client data.\",\n PASSKEY_INVALID_ORIGIN: \"Passkey origin does not match the expected value.\",\n PASSKEY_INVALID_CHALLENGE: \"Invalid or expired passkey challenge.\",\n PASSKEY_RP_MISMATCH: \"Relying party ID mismatch.\",\n PASSKEY_USER_PRESENCE: \"User presence flag not set.\",\n PASSKEY_USER_VERIFICATION: \"User verification required but not performed.\",\n PASSKEY_NO_CREDENTIAL: \"No credential in attestation.\",\n PASSKEY_UNSUPPORTED_ALGORITHM: \"Unsupported passkey algorithm.\",\n PASSKEY_INVALID_SIGNATURE: \"Invalid passkey signature.\",\n PASSKEY_UNKNOWN_CREDENTIAL: \"Unknown passkey credential.\",\n PASSKEY_COUNTER_ERROR:\n \"Authenticator counter did not increase — possible credential cloning detected.\",\n PASSKEY_MISSING_FLOW: \"Missing passkey flow parameter.\",\n PASSKEY_UNKNOWN_FLOW: \"Unknown passkey flow.\",\n\n // ---- TOTP ----\n TOTP_AUTH_REQUIRED: \"Sign in first, then set up two-factor authentication.\",\n TOTP_MISSING_VERIFIER: \"Missing verifier for TOTP operation.\",\n TOTP_MISSING_CODE: \"Missing TOTP code.\",\n TOTP_MISSING_ID: \"Missing TOTP enrollment ID.\",\n TOTP_NOT_FOUND: \"TOTP enrollment not found.\",\n TOTP_ALREADY_VERIFIED: \"TOTP enrollment is already verified.\",\n TOTP_INVALID_CODE: \"Invalid TOTP code.\",\n TOTP_INVALID_VERIFIER: \"Invalid or expired TOTP verifier.\",\n TOTP_NO_ENROLLMENT: \"No verified TOTP enrollment found.\",\n TOTP_MISSING_FLOW: \"Missing TOTP flow parameter.\",\n TOTP_UNKNOWN_FLOW: \"Unknown TOTP flow.\",\n\n // ---- Device Authorization (RFC 8628) ----\n DEVICE_CODE_EXPIRED:\n \"The device code has expired. Please start a new authorization request.\",\n DEVICE_CODE_DENIED: \"The authorization request was denied.\",\n DEVICE_AUTHORIZATION_PENDING: \"The user has not yet authorized this device.\",\n DEVICE_SLOW_DOWN:\n \"Polling too frequently. Increase the interval between requests.\",\n DEVICE_INVALID_USER_CODE: \"Invalid or expired user code.\",\n DEVICE_ALREADY_AUTHORIZED: \"This device code has already been authorized.\",\n DEVICE_MISSING_FLOW: \"Missing device flow parameter.\",\n DEVICE_UNKNOWN_FLOW: \"Unknown device flow.\",\n\n // ---- Invites ----\n INVITE_EXPIRED: \"This invitation has expired.\",\n INVITE_EMAIL_MISMATCH: \"This invitation is for a different email.\",\n INVITE_ALREADY_ACCEPTED: \"This invitation has already been accepted.\",\n DUPLICATE_INVITE:\n \"A pending invite already exists for this email in this group.\",\n INVITE_NOT_FOUND: \"Invite not found.\",\n INVITE_NOT_PENDING: \"Cannot accept or revoke invite that is not pending.\",\n\n // ---- Groups / Members ----\n FORBIDDEN: \"Access denied.\",\n NO_ACTIVE_GROUP: \"User has no active group set.\",\n DUPLICATE_MEMBERSHIP: \"User is already a member of this group.\",\n\n // ---- Enterprise ----\n ENTERPRISE_ALREADY_EXISTS:\n \"An enterprise record already exists for this group.\",\n ENTERPRISE_DOMAIN_TAKEN:\n \"That domain is already attached to another enterprise.\",\n\n // ---- Internal (should never reach user) ----\n INTERNAL_ERROR: \"An unexpected error occurred.\",\n} as const satisfies Record<string, string>;\n\n/** Union of all recognized auth error code strings (keys of {@link AUTH_ERRORS}). */\nexport type AuthErrorCode = keyof typeof AUTH_ERRORS;\n\n// ============================================================================\n// Error helpers\n// ============================================================================\n\n/**\n * Throw a structured `ConvexError` with `{ code, message }`.\n *\n * Use this in your own Convex functions (queries, mutations, actions)\n * to throw auth-domain errors that clients can match on by `code`.\n * The library itself uses `AuthError` internally, but consumers\n * should prefer this helper for simplicity.\n *\n * @param code Machine-readable error code from `AUTH_ERRORS`.\n * @param message Optional override for the default human-readable message.\n * @param context Optional extra fields merged into the error payload.\n *\n * @example\n * ```ts\n * import { throwAuthError } from \"@robelest/convex-auth/server\";\n *\n * // In a custom mutation:\n * if (!isAdmin) {\n * throwAuthError(\"FORBIDDEN\");\n * }\n * ```\n *\n * @throws {ConvexError} Always — throws a `ConvexError` with `{ code, message }` payload.\n */\nexport function throwAuthError(\n code: AuthErrorCode,\n message?: string,\n context?: Record<string, unknown>,\n): never {\n throw new ConvexError({\n code,\n message: message ?? AUTH_ERRORS[code],\n ...context,\n });\n}\n\n/**\n * Type guard: check whether a caught value is a structured auth `ConvexError`.\n *\n * @param error - The caught value (typically from a `catch` block).\n * @returns `true` when `error` is a `ConvexError` with `{ code, message }` data.\n *\n * @example\n * ```ts\n * try { await auth.signIn('email', { email }); }\n * catch (e) {\n * if (isAuthError(e)) console.log(e.data.code); // \"EMAIL_SEND_FAILED\"\n * }\n * ```\n */\nexport function isAuthError(\n error: unknown,\n): error is ConvexError<{ code: AuthErrorCode; message: string }> {\n return (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n );\n}\n\n/**\n * Extract `{ code, message }` from a caught error.\n *\n * Works for `ConvexError` (from Convex actions), plain `Error`\n * instances, and structured auth errors. Returns `null` when the\n * value is not an error object.\n *\n * @param error - The caught value to parse.\n * @returns `{ code, message }` when extractable, or `null`.\n * When `code` is `null`, the error is not a structured auth error\n * but `message` still contains the error text.\n *\n * @example\n * ```ts\n * try {\n * await auth.signIn(\"email\", { email });\n * } catch (e) {\n * const err = parseAuthError(e);\n * if (err?.code === \"EMAIL_SEND_FAILED\") { ... }\n * }\n * ```\n */\nexport function parseAuthError(\n error: unknown,\n):\n | { code: AuthErrorCode; message: string }\n | { code: null; message: string }\n | null {\n if (isAuthError(error)) {\n const { code, message } = error.data as {\n code: AuthErrorCode;\n message: string;\n };\n return { code, message };\n }\n // Recognize the Fx-native AuthError class (has _tag + code)\n if (\n error instanceof Error &&\n \"_tag\" in error &&\n (error as any)._tag === \"AuthError\" &&\n \"code\" in error &&\n typeof (error as any).code === \"string\"\n ) {\n return {\n code: (error as any).code as AuthErrorCode,\n message: error.message,\n };\n }\n if (error instanceof ConvexError && typeof error.data === \"string\") {\n return { code: null, message: error.data };\n }\n if (error instanceof Error) {\n return { code: null, message: error.message };\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAa,cAAc;CAEzB,yBAAyB;CACzB,uBACE;CACF,iBAAiB;CACjB,wBAAwB;CACxB,oBAAoB;CAGpB,eAAe;CACf,2BAA2B;CAC3B,uBAAuB;CACvB,wBACE;CACF,yBACE;CACF,wBACE;CACF,2BAA2B;CAC3B,kBAAkB;CAGlB,mBAAmB;CAGnB,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,sBAAsB;CACtB,uBAAuB;CACvB,eAAe;CAGf,sBAAsB;CACtB,oBAAoB;CAGpB,wBAAwB;CACxB,wBAAwB;CACxB,qBAAqB;CACrB,sBAAsB;CACtB,wBACE;CACF,uBAAuB;CACvB,+BACE;CACF,mBAAmB;CAGnB,wBAAwB;CACxB,mBAAmB;CACnB,8BACE;CACF,yBACE;CACF,oBAAoB;CAGpB,kBAAkB;CAGlB,wBACE;CACF,uBAAuB;CACvB,0BAA0B;CAC1B,6BAA6B;CAC7B,wBAAwB;CACxB,2BAA2B;CAC3B,qBAAqB;CACrB,uBAAuB;CACvB,2BAA2B;CAC3B,uBAAuB;CACvB,+BAA+B;CAC/B,2BAA2B;CAC3B,4BAA4B;CAC5B,uBACE;CACF,sBAAsB;CACtB,sBAAsB;CAGtB,oBAAoB;CACpB,uBAAuB;CACvB,mBAAmB;CACnB,iBAAiB;CACjB,gBAAgB;CAChB,uBAAuB;CACvB,mBAAmB;CACnB,uBAAuB;CACvB,oBAAoB;CACpB,mBAAmB;CACnB,mBAAmB;CAGnB,qBACE;CACF,oBAAoB;CACpB,8BAA8B;CAC9B,kBACE;CACF,0BAA0B;CAC1B,2BAA2B;CAC3B,qBAAqB;CACrB,qBAAqB;CAGrB,gBAAgB;CAChB,uBAAuB;CACvB,yBAAyB;CACzB,kBACE;CACF,kBAAkB;CAClB,oBAAoB;CAGpB,WAAW;CACX,iBAAiB;CACjB,sBAAsB;CAGtB,2BACE;CACF,yBACE;CAGF,gBAAgB;CACjB;;;;;;;;;;;;;;;AA2DD,SAAgB,YACd,OACgE;AAChE,QACE,iBAAiB,eACjB,OAAO,MAAM,SAAS,YACtB,MAAM,SAAS,QACf,UAAU,MAAM,QAChB,aAAa,MAAM"}
@@ -1,9 +1,10 @@
1
1
  import { isAuthError } from "./errors.js";
2
- import { AuthError, Fx } from "./fx.js";
2
+ import { AuthError } from "./authError.js";
3
3
  import { logError } from "./utils.js";
4
4
  import { httpActionGeneric } from "convex/server";
5
5
  import { ConvexError } from "convex/values";
6
6
  import { parse } from "cookie";
7
+ import { Fx } from "@robelest/fx";
7
8
 
8
9
  //#region src/server/http.ts
9
10
  function createHttpAction(auth) {