@robelest/convex-auth 0.0.4-preview.13 → 0.0.4-preview.16

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 (328) hide show
  1. package/README.md +140 -9
  2. package/dist/bin.cjs +5957 -5478
  3. package/dist/client/index.d.ts +3 -7
  4. package/dist/client/index.d.ts.map +1 -1
  5. package/dist/client/index.js +27 -26
  6. package/dist/client/index.js.map +1 -1
  7. package/dist/component/_generated/api.d.ts +14 -0
  8. package/dist/component/_generated/api.d.ts.map +1 -1
  9. package/dist/component/_generated/api.js.map +1 -1
  10. package/dist/component/_generated/component.d.ts +1672 -24
  11. package/dist/component/_generated/component.d.ts.map +1 -1
  12. package/dist/component/convex.config.d.ts +2 -2
  13. package/dist/component/convex.config.d.ts.map +1 -1
  14. package/dist/component/index.d.ts +1 -1
  15. package/dist/component/index.js +2 -2
  16. package/dist/component/model.d.ts +153 -0
  17. package/dist/component/model.d.ts.map +1 -0
  18. package/dist/component/model.js +343 -0
  19. package/dist/component/model.js.map +1 -0
  20. package/dist/component/providers/sso.d.ts +1 -1
  21. package/dist/component/public/enterprise.d.ts +54 -0
  22. package/dist/component/public/enterprise.d.ts.map +1 -0
  23. package/dist/component/public/enterprise.js +515 -0
  24. package/dist/component/public/enterprise.js.map +1 -0
  25. package/dist/component/public/factors.d.ts +52 -0
  26. package/dist/component/public/factors.d.ts.map +1 -0
  27. package/dist/component/public/factors.js +285 -0
  28. package/dist/component/public/factors.js.map +1 -0
  29. package/dist/component/public/groups.d.ts +116 -0
  30. package/dist/component/public/groups.d.ts.map +1 -0
  31. package/dist/component/public/groups.js +596 -0
  32. package/dist/component/public/groups.js.map +1 -0
  33. package/dist/component/public/identity.d.ts +93 -0
  34. package/dist/component/public/identity.d.ts.map +1 -0
  35. package/dist/component/public/identity.js +426 -0
  36. package/dist/component/public/identity.js.map +1 -0
  37. package/dist/component/public/keys.d.ts +41 -0
  38. package/dist/component/public/keys.d.ts.map +1 -0
  39. package/dist/component/public/keys.js +157 -0
  40. package/dist/component/public/keys.js.map +1 -0
  41. package/dist/component/public/shared.d.ts +26 -0
  42. package/dist/component/public/shared.d.ts.map +1 -0
  43. package/dist/component/public/shared.js +32 -0
  44. package/dist/component/public/shared.js.map +1 -0
  45. package/dist/component/public.d.ts +9 -321
  46. package/dist/component/public.d.ts.map +1 -1
  47. package/dist/component/public.js +6 -2145
  48. package/dist/component/schema.d.ts +406 -260
  49. package/dist/component/schema.js +37 -32
  50. package/dist/component/schema.js.map +1 -1
  51. package/dist/component/server/auth.d.ts +161 -15
  52. package/dist/component/server/auth.d.ts.map +1 -1
  53. package/dist/component/server/auth.js +100 -7
  54. package/dist/component/server/auth.js.map +1 -1
  55. package/dist/component/server/cookies.js +3 -0
  56. package/dist/component/server/cookies.js.map +1 -1
  57. package/dist/component/server/db.js +1 -0
  58. package/dist/component/server/db.js.map +1 -1
  59. package/dist/component/server/device.js +3 -1
  60. package/dist/component/server/device.js.map +1 -1
  61. package/dist/component/server/domains/core.js +629 -0
  62. package/dist/component/server/domains/core.js.map +1 -0
  63. package/dist/component/server/domains/sso.js +884 -0
  64. package/dist/component/server/domains/sso.js.map +1 -0
  65. package/dist/component/server/factory.d.ts +136 -0
  66. package/dist/component/server/factory.d.ts.map +1 -0
  67. package/dist/component/server/factory.js +1134 -0
  68. package/dist/component/server/factory.js.map +1 -0
  69. package/dist/component/server/fx.js +2 -1
  70. package/dist/component/server/fx.js.map +1 -1
  71. package/dist/component/server/http.js +287 -0
  72. package/dist/component/server/http.js.map +1 -0
  73. package/dist/component/server/identity.js +13 -0
  74. package/dist/component/server/identity.js.map +1 -0
  75. package/dist/component/server/keys.js +4 -0
  76. package/dist/component/server/keys.js.map +1 -1
  77. package/dist/component/server/mutations/account.js +1 -1
  78. package/dist/component/server/mutations/index.js +2 -2
  79. package/dist/component/server/mutations/index.js.map +1 -1
  80. package/dist/component/server/mutations/invalidate.js +1 -1
  81. package/dist/component/server/mutations/oauth.js +10 -7
  82. package/dist/component/server/mutations/oauth.js.map +1 -1
  83. package/dist/component/server/mutations/refresh.js +1 -1
  84. package/dist/component/server/mutations/register.js +1 -1
  85. package/dist/component/server/mutations/retrieve.js +1 -1
  86. package/dist/component/server/mutations/signature.js +1 -1
  87. package/dist/component/server/mutations/store.js +6 -3
  88. package/dist/component/server/mutations/store.js.map +1 -1
  89. package/dist/component/server/mutations/verify.js +1 -1
  90. package/dist/component/server/oauth.js +3 -0
  91. package/dist/component/server/oauth.js.map +1 -1
  92. package/dist/component/server/passkey.js +3 -2
  93. package/dist/component/server/passkey.js.map +1 -1
  94. package/dist/component/server/provider.js +2 -0
  95. package/dist/component/server/provider.js.map +1 -1
  96. package/dist/component/server/providers.js +10 -0
  97. package/dist/component/server/providers.js.map +1 -1
  98. package/dist/component/server/ratelimit.js +3 -0
  99. package/dist/component/server/ratelimit.js.map +1 -1
  100. package/dist/component/server/redirects.js +2 -0
  101. package/dist/component/server/redirects.js.map +1 -1
  102. package/dist/component/server/refresh.js +5 -0
  103. package/dist/component/server/refresh.js.map +1 -1
  104. package/dist/component/server/sessions.js +5 -0
  105. package/dist/component/server/sessions.js.map +1 -1
  106. package/dist/component/server/signin.js +2 -1
  107. package/dist/component/server/signin.js.map +1 -1
  108. package/dist/component/server/sso.js +166 -19
  109. package/dist/component/server/sso.js.map +1 -1
  110. package/dist/component/server/tokens.js +1 -0
  111. package/dist/component/server/tokens.js.map +1 -1
  112. package/dist/component/server/totp.js +4 -2
  113. package/dist/component/server/totp.js.map +1 -1
  114. package/dist/component/server/types.d.ts +106 -38
  115. package/dist/component/server/types.d.ts.map +1 -1
  116. package/dist/component/server/types.js.map +1 -1
  117. package/dist/component/server/users.js +1 -0
  118. package/dist/component/server/users.js.map +1 -1
  119. package/dist/component/server/utils.js +44 -2
  120. package/dist/component/server/utils.js.map +1 -1
  121. package/dist/providers/anonymous.d.ts +1 -1
  122. package/dist/providers/credentials.d.ts +1 -1
  123. package/dist/providers/password.d.ts +1 -1
  124. package/dist/providers/sso.d.ts +1 -1
  125. package/dist/providers/sso.js.map +1 -1
  126. package/dist/server/auth.d.ts +163 -17
  127. package/dist/server/auth.d.ts.map +1 -1
  128. package/dist/server/auth.js +100 -7
  129. package/dist/server/auth.js.map +1 -1
  130. package/dist/server/cookies.d.ts +1 -38
  131. package/dist/server/cookies.js +3 -0
  132. package/dist/server/cookies.js.map +1 -1
  133. package/dist/server/db.d.ts +1 -125
  134. package/dist/server/db.js +1 -0
  135. package/dist/server/db.js.map +1 -1
  136. package/dist/server/device.d.ts +1 -24
  137. package/dist/server/device.js +3 -1
  138. package/dist/server/device.js.map +1 -1
  139. package/dist/server/domains/core.d.ts +434 -0
  140. package/dist/server/domains/core.d.ts.map +1 -0
  141. package/dist/server/domains/core.js +629 -0
  142. package/dist/server/domains/core.js.map +1 -0
  143. package/dist/server/domains/sso.d.ts +409 -0
  144. package/dist/server/domains/sso.d.ts.map +1 -0
  145. package/dist/server/domains/sso.js +884 -0
  146. package/dist/server/domains/sso.js.map +1 -0
  147. package/dist/server/enterpriseValidators.d.ts +1 -0
  148. package/dist/server/enterpriseValidators.js +60 -0
  149. package/dist/server/enterpriseValidators.js.map +1 -0
  150. package/dist/server/factory.d.ts +136 -0
  151. package/dist/server/factory.d.ts.map +1 -0
  152. package/dist/server/factory.js +1134 -0
  153. package/dist/server/factory.js.map +1 -0
  154. package/dist/server/fx.d.ts +1 -16
  155. package/dist/server/fx.d.ts.map +1 -1
  156. package/dist/server/fx.js +1 -0
  157. package/dist/server/fx.js.map +1 -1
  158. package/dist/server/http.d.ts +59 -0
  159. package/dist/server/http.d.ts.map +1 -0
  160. package/dist/server/http.js +287 -0
  161. package/dist/server/http.js.map +1 -0
  162. package/dist/server/identity.d.ts +1 -0
  163. package/dist/server/identity.js +13 -0
  164. package/dist/server/identity.js.map +1 -0
  165. package/dist/server/index.d.ts +468 -1
  166. package/dist/server/index.d.ts.map +1 -1
  167. package/dist/server/index.js +530 -36
  168. package/dist/server/index.js.map +1 -1
  169. package/dist/server/keys.d.ts +1 -57
  170. package/dist/server/keys.js +4 -0
  171. package/dist/server/keys.js.map +1 -1
  172. package/dist/server/mutations/account.d.ts +7 -7
  173. package/dist/server/mutations/account.d.ts.map +1 -1
  174. package/dist/server/mutations/code.d.ts +13 -13
  175. package/dist/server/mutations/code.d.ts.map +1 -1
  176. package/dist/server/mutations/index.d.ts +107 -107
  177. package/dist/server/mutations/index.d.ts.map +1 -1
  178. package/dist/server/mutations/index.js +1 -1
  179. package/dist/server/mutations/index.js.map +1 -1
  180. package/dist/server/mutations/invalidate.d.ts +5 -5
  181. package/dist/server/mutations/invalidate.d.ts.map +1 -1
  182. package/dist/server/mutations/oauth.d.ts +10 -10
  183. package/dist/server/mutations/oauth.d.ts.map +1 -1
  184. package/dist/server/mutations/oauth.js +9 -6
  185. package/dist/server/mutations/oauth.js.map +1 -1
  186. package/dist/server/mutations/refresh.d.ts +4 -4
  187. package/dist/server/mutations/register.d.ts +12 -12
  188. package/dist/server/mutations/register.d.ts.map +1 -1
  189. package/dist/server/mutations/retrieve.d.ts +7 -7
  190. package/dist/server/mutations/signature.d.ts +5 -5
  191. package/dist/server/mutations/signin.d.ts +6 -6
  192. package/dist/server/mutations/signin.d.ts.map +1 -1
  193. package/dist/server/mutations/signout.d.ts +1 -1
  194. package/dist/server/mutations/store.d.ts +3 -2
  195. package/dist/server/mutations/store.d.ts.map +1 -1
  196. package/dist/server/mutations/store.js +6 -3
  197. package/dist/server/mutations/store.js.map +1 -1
  198. package/dist/server/mutations/verifier.d.ts +1 -1
  199. package/dist/server/mutations/verify.d.ts +11 -11
  200. package/dist/server/mutations/verify.d.ts.map +1 -1
  201. package/dist/server/oauth.d.ts +1 -59
  202. package/dist/server/oauth.js +3 -0
  203. package/dist/server/oauth.js.map +1 -1
  204. package/dist/server/passkey.d.ts.map +1 -1
  205. package/dist/server/passkey.js +3 -2
  206. package/dist/server/passkey.js.map +1 -1
  207. package/dist/server/provider.d.ts +1 -14
  208. package/dist/server/provider.d.ts.map +1 -1
  209. package/dist/server/provider.js +2 -0
  210. package/dist/server/provider.js.map +1 -1
  211. package/dist/server/providers.js +10 -0
  212. package/dist/server/providers.js.map +1 -1
  213. package/dist/server/ratelimit.d.ts +1 -22
  214. package/dist/server/ratelimit.js +3 -0
  215. package/dist/server/ratelimit.js.map +1 -1
  216. package/dist/server/redirects.d.ts +1 -10
  217. package/dist/server/redirects.js +2 -0
  218. package/dist/server/redirects.js.map +1 -1
  219. package/dist/server/refresh.d.ts +1 -37
  220. package/dist/server/refresh.js +5 -0
  221. package/dist/server/refresh.js.map +1 -1
  222. package/dist/server/sessions.d.ts +1 -28
  223. package/dist/server/sessions.js +5 -0
  224. package/dist/server/sessions.js.map +1 -1
  225. package/dist/server/signin.d.ts +1 -55
  226. package/dist/server/signin.js +2 -1
  227. package/dist/server/signin.js.map +1 -1
  228. package/dist/server/sso.d.ts +1 -348
  229. package/dist/server/sso.js +165 -18
  230. package/dist/server/sso.js.map +1 -1
  231. package/dist/server/templates.d.ts +1 -21
  232. package/dist/server/templates.js +1 -0
  233. package/dist/server/templates.js.map +1 -1
  234. package/dist/server/tokens.d.ts +1 -11
  235. package/dist/server/tokens.js +1 -0
  236. package/dist/server/tokens.js.map +1 -1
  237. package/dist/server/totp.d.ts +1 -23
  238. package/dist/server/totp.js +4 -2
  239. package/dist/server/totp.js.map +1 -1
  240. package/dist/server/types.d.ts +114 -77
  241. package/dist/server/types.d.ts.map +1 -1
  242. package/dist/server/types.js.map +1 -1
  243. package/dist/server/users.d.ts +1 -31
  244. package/dist/server/users.js +1 -0
  245. package/dist/server/users.js.map +1 -1
  246. package/dist/server/utils.d.ts +1 -27
  247. package/dist/server/utils.js +44 -2
  248. package/dist/server/utils.js.map +1 -1
  249. package/dist/server/version.d.ts +1 -1
  250. package/dist/server/version.js +1 -1
  251. package/dist/server/version.js.map +1 -1
  252. package/package.json +4 -5
  253. package/src/cli/bin.ts +5 -0
  254. package/src/cli/index.ts +22 -9
  255. package/src/cli/keys.ts +3 -0
  256. package/src/client/index.ts +36 -37
  257. package/src/component/_generated/api.ts +14 -0
  258. package/src/component/_generated/component.ts +2106 -9
  259. package/src/component/index.ts +3 -1
  260. package/src/component/model.ts +441 -0
  261. package/src/component/public/enterprise.ts +753 -0
  262. package/src/component/public/factors.ts +332 -0
  263. package/src/component/public/groups.ts +932 -0
  264. package/src/component/public/identity.ts +566 -0
  265. package/src/component/public/keys.ts +209 -0
  266. package/src/component/public/shared.ts +119 -0
  267. package/src/component/public.ts +5 -2965
  268. package/src/component/schema.ts +68 -63
  269. package/src/providers/sso.ts +1 -1
  270. package/src/server/auth.ts +413 -18
  271. package/src/server/cookies.ts +3 -0
  272. package/src/server/db.ts +3 -0
  273. package/src/server/device.ts +3 -1
  274. package/src/server/domains/core.ts +1071 -0
  275. package/src/server/domains/sso.ts +1749 -0
  276. package/src/server/enterpriseValidators.ts +93 -0
  277. package/src/server/factory.ts +2181 -0
  278. package/src/server/fx.ts +1 -0
  279. package/src/server/http.ts +529 -0
  280. package/src/server/identity.ts +18 -0
  281. package/src/server/index.ts +806 -40
  282. package/src/server/keys.ts +4 -0
  283. package/src/server/mutations/index.ts +1 -1
  284. package/src/server/mutations/oauth.ts +36 -8
  285. package/src/server/mutations/store.ts +6 -3
  286. package/src/server/oauth.ts +6 -0
  287. package/src/server/passkey.ts +3 -2
  288. package/src/server/provider.ts +2 -0
  289. package/src/server/providers.ts +20 -0
  290. package/src/server/ratelimit.ts +3 -0
  291. package/src/server/redirects.ts +2 -0
  292. package/src/server/refresh.ts +5 -0
  293. package/src/server/sessions.ts +5 -0
  294. package/src/server/signin.ts +1 -0
  295. package/src/server/sso.ts +259 -17
  296. package/src/server/templates.ts +1 -0
  297. package/src/server/tokens.ts +1 -0
  298. package/src/server/totp.ts +4 -2
  299. package/src/server/types.ts +178 -83
  300. package/src/server/users.ts +1 -0
  301. package/src/server/utils.ts +71 -1
  302. package/src/server/version.ts +1 -1
  303. package/dist/component/public.js.map +0 -1
  304. package/dist/component/server/implementation.d.ts +0 -1264
  305. package/dist/component/server/implementation.d.ts.map +0 -1
  306. package/dist/component/server/implementation.js +0 -2365
  307. package/dist/component/server/implementation.js.map +0 -1
  308. package/dist/server/cookies.d.ts.map +0 -1
  309. package/dist/server/db.d.ts.map +0 -1
  310. package/dist/server/device.d.ts.map +0 -1
  311. package/dist/server/implementation.d.ts +0 -1264
  312. package/dist/server/implementation.d.ts.map +0 -1
  313. package/dist/server/implementation.js +0 -2365
  314. package/dist/server/implementation.js.map +0 -1
  315. package/dist/server/keys.d.ts.map +0 -1
  316. package/dist/server/oauth.d.ts.map +0 -1
  317. package/dist/server/ratelimit.d.ts.map +0 -1
  318. package/dist/server/redirects.d.ts.map +0 -1
  319. package/dist/server/refresh.d.ts.map +0 -1
  320. package/dist/server/sessions.d.ts.map +0 -1
  321. package/dist/server/signin.d.ts.map +0 -1
  322. package/dist/server/sso.d.ts.map +0 -1
  323. package/dist/server/templates.d.ts.map +0 -1
  324. package/dist/server/tokens.d.ts.map +0 -1
  325. package/dist/server/totp.d.ts.map +0 -1
  326. package/dist/server/users.d.ts.map +0 -1
  327. package/dist/server/utils.d.ts.map +0 -1
  328. package/src/server/implementation.ts +0 -5336
@@ -1 +1 @@
1
- {"version":3,"file":"users.js","names":[],"sources":["../../../src/server/users.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { GenericId } from \"convex/values\";\n\nimport { authDb } from \"./db\";\nimport { AuthError } from \"./fx\";\nimport { Doc, MutationCtx } from \"./types\";\nimport { AuthProviderMaterializedConfig, ConvexAuthConfig } from \"./types\";\nimport { LOG_LEVELS, logWithLevel } from \"./utils\";\n\ntype CreateOrUpdateUserArgs = {\n type: \"oauth\" | \"credentials\" | \"email\" | \"phone\" | \"verification\";\n provider: AuthProviderMaterializedConfig;\n profile: Record<string, unknown> & {\n email?: string;\n phone?: string;\n emailVerified?: boolean;\n phoneVerified?: boolean;\n };\n accountExtend?: Record<string, unknown>;\n shouldLinkViaEmail?: boolean;\n shouldLinkViaPhone?: boolean;\n};\n\nfunction mergeExtend(\n existing: unknown,\n incoming: Record<string, unknown> | undefined,\n) {\n if (!incoming) {\n return undefined;\n }\n const existingRecord =\n typeof existing === \"object\" &&\n existing !== null &&\n !Array.isArray(existing)\n ? (existing as Record<string, unknown>)\n : undefined;\n return existingRecord ? { ...existingRecord, ...incoming } : incoming;\n}\n\nexport async function upsertUserAndAccount(\n ctx: MutationCtx,\n sessionId: GenericId<\"Session\"> | null,\n account:\n | { existingAccount: Doc<\"Account\"> }\n | {\n providerAccountId: string;\n secret?: string;\n },\n args: CreateOrUpdateUserArgs,\n config: ConvexAuthConfig,\n opts?: { existingUserId?: GenericId<\"User\"> },\n): Promise<{\n userId: GenericId<\"User\">;\n accountId: GenericId<\"Account\">;\n}> {\n const userId = await defaultCreateOrUpdateUser(\n ctx,\n sessionId,\n \"existingAccount\" in account ? account.existingAccount : null,\n args,\n config,\n opts?.existingUserId ?? null,\n );\n const accountId = await createOrUpdateAccount(\n ctx,\n userId,\n account,\n args,\n config,\n );\n return { userId, accountId };\n}\n\nasync function defaultCreateOrUpdateUser(\n ctx: MutationCtx,\n existingSessionId: GenericId<\"Session\"> | null,\n existingAccount: Doc<\"Account\"> | null,\n args: CreateOrUpdateUserArgs,\n config: ConvexAuthConfig,\n existingUserIdOverride: GenericId<\"User\"> | null,\n) {\n logWithLevel(LOG_LEVELS.DEBUG, \"defaultCreateOrUpdateUser args:\", {\n existingAccountId: existingAccount?._id,\n existingSessionId,\n args,\n });\n const existingUserId = existingAccount?.userId ?? null;\n const db = authDb(ctx, config);\n if (config.callbacks?.createOrUpdateUser !== undefined) {\n logWithLevel(LOG_LEVELS.DEBUG, \"Using custom createOrUpdateUser callback\");\n return await config.callbacks.createOrUpdateUser(ctx, {\n existingUserId,\n ...args,\n });\n }\n\n const {\n provider,\n profile: {\n id: _profileId,\n emailVerified: profileEmailVerified,\n phoneVerified: profilePhoneVerified,\n ...profile\n },\n } = args;\n const emailVerified =\n profileEmailVerified ??\n (provider.type === \"oauth\" && provider.accountLinking !== \"none\");\n const phoneVerified = profilePhoneVerified ?? false;\n const shouldLinkViaEmail =\n args.shouldLinkViaEmail || emailVerified || provider.type === \"email\";\n const shouldLinkViaPhone =\n args.shouldLinkViaPhone || phoneVerified || provider.type === \"phone\";\n\n let userId = existingUserId ?? existingUserIdOverride;\n if (existingUserId === null) {\n const existingUserWithVerifiedEmailId =\n typeof profile.email === \"string\" && shouldLinkViaEmail\n ? ((await uniqueUserWithVerifiedEmail(ctx, profile.email, config))\n ?._id ?? null)\n : null;\n\n const existingUserWithVerifiedPhoneId =\n typeof profile.phone === \"string\" && shouldLinkViaPhone\n ? ((await uniqueUserWithVerifiedPhone(ctx, profile.phone, config))\n ?._id ?? null)\n : null;\n const linkDispatch = {\n tag:\n existingUserWithVerifiedEmailId !== null &&\n existingUserWithVerifiedPhoneId !== null\n ? \"both\"\n : existingUserWithVerifiedEmailId !== null\n ? \"email\"\n : existingUserWithVerifiedPhoneId !== null\n ? \"phone\"\n : \"none\",\n existingUserWithVerifiedEmailId,\n existingUserWithVerifiedPhoneId,\n } as const;\n\n const linkHandlers = {\n both: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Found existing email and phone verified users, so not linking: email: ${linkDispatch.existingUserWithVerifiedEmailId}, phone: ${linkDispatch.existingUserWithVerifiedPhoneId}`,\n );\n return null;\n }),\n email: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Found existing email verified user, linking: ${linkDispatch.existingUserWithVerifiedEmailId}`,\n );\n return linkDispatch.existingUserWithVerifiedEmailId;\n }),\n phone: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Found existing phone verified user, linking: ${linkDispatch.existingUserWithVerifiedPhoneId}`,\n );\n return linkDispatch.existingUserWithVerifiedPhoneId;\n }),\n none: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"No existing verified users found, creating new user\",\n );\n return null;\n }),\n } as const;\n\n userId = await Fx.run(linkHandlers[linkDispatch.tag]());\n }\n const userData = {\n ...(emailVerified ? { emailVerificationTime: Date.now() } : null),\n ...(phoneVerified ? { phoneVerificationTime: Date.now() } : null),\n ...profile,\n };\n const existingOrLinkedUserId = userId;\n if (userId !== null) {\n await Fx.run(\n Fx.from({\n ok: () => db.users.patch(userId!, userData),\n err: (error) =>\n new AuthError(\n \"USER_UPDATE_FAILED\",\n `Could not update user document with ID \\`${userId}\\`, ` +\n `either the user has been deleted but their account has not, ` +\n `or the profile data doesn't match the \\`users\\` table schema: ` +\n `${(error as Error).message}`,\n ),\n }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),\n );\n } else {\n userId = (await db.users.insert(userData)) as GenericId<\"User\">;\n }\n const afterUserCreatedOrUpdated = config.callbacks?.afterUserCreatedOrUpdated;\n if (afterUserCreatedOrUpdated !== undefined) {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"Calling custom afterUserCreatedOrUpdated callback\",\n );\n await afterUserCreatedOrUpdated(ctx, {\n userId,\n existingUserId: existingOrLinkedUserId,\n ...args,\n });\n } else {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"No custom afterUserCreatedOrUpdated callback, skipping\",\n );\n }\n return userId;\n}\n\nasync function uniqueUserWithVerifiedEmail(\n ctx: MutationCtx,\n email: string,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n return (await db.users.findByVerifiedEmail(email)) as Doc<\"User\"> | null;\n}\n\nasync function uniqueUserWithVerifiedPhone(\n ctx: MutationCtx,\n phone: string,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n return (await db.users.findByVerifiedPhone(phone)) as Doc<\"User\"> | null;\n}\n\nasync function createOrUpdateAccount(\n ctx: MutationCtx,\n userId: GenericId<\"User\">,\n account:\n | { existingAccount: Doc<\"Account\"> }\n | {\n providerAccountId: string;\n secret?: string;\n },\n args: CreateOrUpdateUserArgs,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n const mergedExtend =\n \"existingAccount\" in account\n ? mergeExtend(account.existingAccount.extend, args.accountExtend)\n : args.accountExtend;\n const accountId =\n \"existingAccount\" in account\n ? account.existingAccount._id\n : ((await db.accounts.create({\n userId,\n provider: args.provider.id,\n providerAccountId: account.providerAccountId,\n secret: account.secret,\n extend: mergedExtend,\n })) as GenericId<\"Account\">);\n // This is never used with the default `createOrUpdateUser` implementation,\n // but it is used for manual linking via custom `createOrUpdateUser`:\n if (\n \"existingAccount\" in account &&\n account.existingAccount.userId !== userId\n ) {\n await db.accounts.patch(accountId, { userId });\n }\n const accountPatchData: Record<string, unknown> = {};\n if (mergedExtend) {\n accountPatchData.extend = mergedExtend;\n }\n if (args.profile.emailVerified) {\n accountPatchData.emailVerified = args.profile.email;\n }\n if (args.profile.phoneVerified) {\n accountPatchData.phoneVerified = args.profile.phone;\n }\n if (Object.keys(accountPatchData).length > 0) {\n await db.accounts.patch(accountId, accountPatchData);\n }\n return accountId;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"users.js","names":[],"sources":["../../../src/server/users.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { GenericId } from \"convex/values\";\n\nimport { authDb } from \"./db\";\nimport { AuthError } from \"./fx\";\nimport { Doc, MutationCtx } from \"./types\";\nimport { AuthProviderMaterializedConfig, ConvexAuthConfig } from \"./types\";\nimport { LOG_LEVELS, logWithLevel } from \"./utils\";\n\ntype CreateOrUpdateUserArgs = {\n type: \"oauth\" | \"credentials\" | \"email\" | \"phone\" | \"verification\";\n provider: AuthProviderMaterializedConfig;\n profile: Record<string, unknown> & {\n email?: string;\n phone?: string;\n emailVerified?: boolean;\n phoneVerified?: boolean;\n };\n accountExtend?: Record<string, unknown>;\n shouldLinkViaEmail?: boolean;\n shouldLinkViaPhone?: boolean;\n};\n\nfunction mergeExtend(\n existing: unknown,\n incoming: Record<string, unknown> | undefined,\n) {\n if (!incoming) {\n return undefined;\n }\n const existingRecord =\n typeof existing === \"object\" &&\n existing !== null &&\n !Array.isArray(existing)\n ? (existing as Record<string, unknown>)\n : undefined;\n return existingRecord ? { ...existingRecord, ...incoming } : incoming;\n}\n\n/** @internal */\nexport async function upsertUserAndAccount(\n ctx: MutationCtx,\n sessionId: GenericId<\"Session\"> | null,\n account:\n | { existingAccount: Doc<\"Account\"> }\n | {\n providerAccountId: string;\n secret?: string;\n },\n args: CreateOrUpdateUserArgs,\n config: ConvexAuthConfig,\n opts?: { existingUserId?: GenericId<\"User\"> },\n): Promise<{\n userId: GenericId<\"User\">;\n accountId: GenericId<\"Account\">;\n}> {\n const userId = await defaultCreateOrUpdateUser(\n ctx,\n sessionId,\n \"existingAccount\" in account ? account.existingAccount : null,\n args,\n config,\n opts?.existingUserId ?? null,\n );\n const accountId = await createOrUpdateAccount(\n ctx,\n userId,\n account,\n args,\n config,\n );\n return { userId, accountId };\n}\n\nasync function defaultCreateOrUpdateUser(\n ctx: MutationCtx,\n existingSessionId: GenericId<\"Session\"> | null,\n existingAccount: Doc<\"Account\"> | null,\n args: CreateOrUpdateUserArgs,\n config: ConvexAuthConfig,\n existingUserIdOverride: GenericId<\"User\"> | null,\n) {\n logWithLevel(LOG_LEVELS.DEBUG, \"defaultCreateOrUpdateUser args:\", {\n existingAccountId: existingAccount?._id,\n existingSessionId,\n args,\n });\n const existingUserId = existingAccount?.userId ?? null;\n const db = authDb(ctx, config);\n if (config.callbacks?.createOrUpdateUser !== undefined) {\n logWithLevel(LOG_LEVELS.DEBUG, \"Using custom createOrUpdateUser callback\");\n return await config.callbacks.createOrUpdateUser(ctx, {\n existingUserId,\n ...args,\n });\n }\n\n const {\n provider,\n profile: {\n id: _profileId,\n emailVerified: profileEmailVerified,\n phoneVerified: profilePhoneVerified,\n ...profile\n },\n } = args;\n const emailVerified =\n profileEmailVerified ??\n (provider.type === \"oauth\" && provider.accountLinking !== \"none\");\n const phoneVerified = profilePhoneVerified ?? false;\n const shouldLinkViaEmail =\n args.shouldLinkViaEmail || emailVerified || provider.type === \"email\";\n const shouldLinkViaPhone =\n args.shouldLinkViaPhone || phoneVerified || provider.type === \"phone\";\n\n let userId = existingUserId ?? existingUserIdOverride;\n if (existingUserId === null) {\n const existingUserWithVerifiedEmailId =\n typeof profile.email === \"string\" && shouldLinkViaEmail\n ? ((await uniqueUserWithVerifiedEmail(ctx, profile.email, config))\n ?._id ?? null)\n : null;\n\n const existingUserWithVerifiedPhoneId =\n typeof profile.phone === \"string\" && shouldLinkViaPhone\n ? ((await uniqueUserWithVerifiedPhone(ctx, profile.phone, config))\n ?._id ?? null)\n : null;\n const linkDispatch = {\n tag:\n existingUserWithVerifiedEmailId !== null &&\n existingUserWithVerifiedPhoneId !== null\n ? \"both\"\n : existingUserWithVerifiedEmailId !== null\n ? \"email\"\n : existingUserWithVerifiedPhoneId !== null\n ? \"phone\"\n : \"none\",\n existingUserWithVerifiedEmailId,\n existingUserWithVerifiedPhoneId,\n } as const;\n\n const linkHandlers = {\n both: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Found existing email and phone verified users, so not linking: email: ${linkDispatch.existingUserWithVerifiedEmailId}, phone: ${linkDispatch.existingUserWithVerifiedPhoneId}`,\n );\n return null;\n }),\n email: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Found existing email verified user, linking: ${linkDispatch.existingUserWithVerifiedEmailId}`,\n );\n return linkDispatch.existingUserWithVerifiedEmailId;\n }),\n phone: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Found existing phone verified user, linking: ${linkDispatch.existingUserWithVerifiedPhoneId}`,\n );\n return linkDispatch.existingUserWithVerifiedPhoneId;\n }),\n none: () =>\n Fx.sync(() => {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"No existing verified users found, creating new user\",\n );\n return null;\n }),\n } as const;\n\n userId = await Fx.run(linkHandlers[linkDispatch.tag]());\n }\n const userData = {\n ...(emailVerified ? { emailVerificationTime: Date.now() } : null),\n ...(phoneVerified ? { phoneVerificationTime: Date.now() } : null),\n ...profile,\n };\n const existingOrLinkedUserId = userId;\n if (userId !== null) {\n await Fx.run(\n Fx.from({\n ok: () => db.users.patch(userId!, userData),\n err: (error) =>\n new AuthError(\n \"USER_UPDATE_FAILED\",\n `Could not update user document with ID \\`${userId}\\`, ` +\n `either the user has been deleted but their account has not, ` +\n `or the profile data doesn't match the \\`users\\` table schema: ` +\n `${(error as Error).message}`,\n ),\n }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),\n );\n } else {\n userId = (await db.users.insert(userData)) as GenericId<\"User\">;\n }\n const afterUserCreatedOrUpdated = config.callbacks?.afterUserCreatedOrUpdated;\n if (afterUserCreatedOrUpdated !== undefined) {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"Calling custom afterUserCreatedOrUpdated callback\",\n );\n await afterUserCreatedOrUpdated(ctx, {\n userId,\n existingUserId: existingOrLinkedUserId,\n ...args,\n });\n } else {\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"No custom afterUserCreatedOrUpdated callback, skipping\",\n );\n }\n return userId;\n}\n\nasync function uniqueUserWithVerifiedEmail(\n ctx: MutationCtx,\n email: string,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n return (await db.users.findByVerifiedEmail(email)) as Doc<\"User\"> | null;\n}\n\nasync function uniqueUserWithVerifiedPhone(\n ctx: MutationCtx,\n phone: string,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n return (await db.users.findByVerifiedPhone(phone)) as Doc<\"User\"> | null;\n}\n\nasync function createOrUpdateAccount(\n ctx: MutationCtx,\n userId: GenericId<\"User\">,\n account:\n | { existingAccount: Doc<\"Account\"> }\n | {\n providerAccountId: string;\n secret?: string;\n },\n args: CreateOrUpdateUserArgs,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n const mergedExtend =\n \"existingAccount\" in account\n ? mergeExtend(account.existingAccount.extend, args.accountExtend)\n : args.accountExtend;\n const accountId =\n \"existingAccount\" in account\n ? account.existingAccount._id\n : ((await db.accounts.create({\n userId,\n provider: args.provider.id,\n providerAccountId: account.providerAccountId,\n secret: account.secret,\n extend: mergedExtend,\n })) as GenericId<\"Account\">);\n // This is never used with the default `createOrUpdateUser` implementation,\n // but it is used for manual linking via custom `createOrUpdateUser`:\n if (\n \"existingAccount\" in account &&\n account.existingAccount.userId !== userId\n ) {\n await db.accounts.patch(accountId, { userId });\n }\n const accountPatchData: Record<string, unknown> = {};\n if (mergedExtend) {\n accountPatchData.extend = mergedExtend;\n }\n if (args.profile.emailVerified) {\n accountPatchData.emailVerified = args.profile.email;\n }\n if (args.profile.phoneVerified) {\n accountPatchData.phoneVerified = args.profile.phone;\n }\n if (Object.keys(accountPatchData).length > 0) {\n await db.accounts.patch(accountId, accountPatchData);\n }\n return accountId;\n}\n"],"mappings":";;;;;;AAuBA,SAAS,YACP,UACA,UACA;AACA,KAAI,CAAC,SACH;CAEF,MAAM,iBACJ,OAAO,aAAa,YACpB,aAAa,QACb,CAAC,MAAM,QAAQ,SAAS,GACnB,WACD;AACN,QAAO,iBAAiB;EAAE,GAAG;EAAgB,GAAG;EAAU,GAAG;;;AAI/D,eAAsB,qBACpB,KACA,WACA,SAMA,MACA,QACA,MAIC;CACD,MAAM,SAAS,MAAM,0BACnB,KACA,WACA,qBAAqB,UAAU,QAAQ,kBAAkB,MACzD,MACA,QACA,MAAM,kBAAkB,KACzB;AAQD,QAAO;EAAE;EAAQ,WAPC,MAAM,sBACtB,KACA,QACA,SACA,MACA,OACD;EAC2B;;AAG9B,eAAe,0BACb,KACA,mBACA,iBACA,MACA,QACA,wBACA;AACA,cAAa,WAAW,OAAO,mCAAmC;EAChE,mBAAmB,iBAAiB;EACpC;EACA;EACD,CAAC;CACF,MAAM,iBAAiB,iBAAiB,UAAU;CAClD,MAAM,KAAK,OAAO,KAAK,OAAO;AAC9B,KAAI,OAAO,WAAW,uBAAuB,QAAW;AACtD,eAAa,WAAW,OAAO,2CAA2C;AAC1E,SAAO,MAAM,OAAO,UAAU,mBAAmB,KAAK;GACpD;GACA,GAAG;GACJ,CAAC;;CAGJ,MAAM,EACJ,UACA,SAAS,EACP,IAAI,YACJ,eAAe,sBACf,eAAe,sBACf,GAAG,cAEH;CACJ,MAAM,gBACJ,yBACC,SAAS,SAAS,WAAW,SAAS,mBAAmB;CAC5D,MAAM,gBAAgB,wBAAwB;CAC9C,MAAM,qBACJ,KAAK,sBAAsB,iBAAiB,SAAS,SAAS;CAChE,MAAM,qBACJ,KAAK,sBAAsB,iBAAiB,SAAS,SAAS;CAEhE,IAAI,SAAS,kBAAkB;AAC/B,KAAI,mBAAmB,MAAM;EAC3B,MAAM,kCACJ,OAAO,QAAQ,UAAU,YAAY,sBAC/B,MAAM,4BAA4B,KAAK,QAAQ,OAAO,OAAO,GAC3D,OAAO,OACX;EAEN,MAAM,kCACJ,OAAO,QAAQ,UAAU,YAAY,sBAC/B,MAAM,4BAA4B,KAAK,QAAQ,OAAO,OAAO,GAC3D,OAAO,OACX;EACN,MAAM,eAAe;GACnB,KACE,oCAAoC,QACpC,oCAAoC,OAChC,SACA,oCAAoC,OAClC,UACA,oCAAoC,OAClC,UACA;GACV;GACA;GACD;AAqCD,WAAS,MAAM,GAAG,IAnCG;GACnB,YACE,GAAG,WAAW;AACZ,iBACE,WAAW,OACX,yEAAyE,aAAa,gCAAgC,WAAW,aAAa,kCAC/I;AACD,WAAO;KACP;GACJ,aACE,GAAG,WAAW;AACZ,iBACE,WAAW,OACX,gDAAgD,aAAa,kCAC9D;AACD,WAAO,aAAa;KACpB;GACJ,aACE,GAAG,WAAW;AACZ,iBACE,WAAW,OACX,gDAAgD,aAAa,kCAC9D;AACD,WAAO,aAAa;KACpB;GACJ,YACE,GAAG,WAAW;AACZ,iBACE,WAAW,OACX,sDACD;AACD,WAAO;KACP;GACL,CAEkC,aAAa,MAAM,CAAC;;CAEzD,MAAM,WAAW;EACf,GAAI,gBAAgB,EAAE,uBAAuB,KAAK,KAAK,EAAE,GAAG;EAC5D,GAAI,gBAAgB,EAAE,uBAAuB,KAAK,KAAK,EAAE,GAAG;EAC5D,GAAG;EACJ;CACD,MAAM,yBAAyB;AAC/B,KAAI,WAAW,KACb,OAAM,GAAG,IACP,GAAG,KAAK;EACN,UAAU,GAAG,MAAM,MAAM,QAAS,SAAS;EAC3C,MAAM,UACJ,IAAI,UACF,sBACA,4CAA4C,OAAO,gIAG7C,MAAgB,UACvB;EACJ,CAAC,CAAC,KAAK,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CACxD;KAED,UAAU,MAAM,GAAG,MAAM,OAAO,SAAS;CAE3C,MAAM,4BAA4B,OAAO,WAAW;AACpD,KAAI,8BAA8B,QAAW;AAC3C,eACE,WAAW,OACX,oDACD;AACD,QAAM,0BAA0B,KAAK;GACnC;GACA,gBAAgB;GAChB,GAAG;GACJ,CAAC;OAEF,cACE,WAAW,OACX,yDACD;AAEH,QAAO;;AAGT,eAAe,4BACb,KACA,OACA,QACA;AAEA,QAAQ,MADG,OAAO,KAAK,OAAO,CACb,MAAM,oBAAoB,MAAM;;AAGnD,eAAe,4BACb,KACA,OACA,QACA;AAEA,QAAQ,MADG,OAAO,KAAK,OAAO,CACb,MAAM,oBAAoB,MAAM;;AAGnD,eAAe,sBACb,KACA,QACA,SAMA,MACA,QACA;CACA,MAAM,KAAK,OAAO,KAAK,OAAO;CAC9B,MAAM,eACJ,qBAAqB,UACjB,YAAY,QAAQ,gBAAgB,QAAQ,KAAK,cAAc,GAC/D,KAAK;CACX,MAAM,YACJ,qBAAqB,UACjB,QAAQ,gBAAgB,MACtB,MAAM,GAAG,SAAS,OAAO;EACzB;EACA,UAAU,KAAK,SAAS;EACxB,mBAAmB,QAAQ;EAC3B,QAAQ,QAAQ;EAChB,QAAQ;EACT,CAAC;AAGR,KACE,qBAAqB,WACrB,QAAQ,gBAAgB,WAAW,OAEnC,OAAM,GAAG,SAAS,MAAM,WAAW,EAAE,QAAQ,CAAC;CAEhD,MAAM,mBAA4C,EAAE;AACpD,KAAI,aACF,kBAAiB,SAAS;AAE5B,KAAI,KAAK,QAAQ,cACf,kBAAiB,gBAAgB,KAAK,QAAQ;AAEhD,KAAI,KAAK,QAAQ,cACf,kBAAiB,gBAAgB,KAAK,QAAQ;AAEhD,KAAI,OAAO,KAAK,iBAAiB,CAAC,SAAS,EACzC,OAAM,GAAG,SAAS,MAAM,WAAW,iBAAiB;AAEtD,QAAO"}
@@ -1,7 +1,7 @@
1
1
  import { AuthError } from "./fx.js";
2
2
  import { generateRandomString } from "@oslojs/crypto/random";
3
3
  import { sha256 } from "@oslojs/crypto/sha2";
4
- import { encodeHexLowerCase } from "@oslojs/encoding";
4
+ import { decodeBase64urlIgnorePadding, encodeBase64urlNoPadding, encodeHexLowerCase } from "@oslojs/encoding";
5
5
 
6
6
  //#region src/server/utils.ts
7
7
  /**
@@ -10,11 +10,13 @@ import { encodeHexLowerCase } from "@oslojs/encoding";
10
10
  * Uses `AuthError.toConvexError()` directly since this is a synchronous guard
11
11
  * called inline in many expressions — not suitable for Fx pipeline wrapping.
12
12
  */
13
+ /** @internal */
13
14
  function requireEnv(name) {
14
15
  const value = process.env[name];
15
16
  if (value === void 0) throw new AuthError("MISSING_ENV_VAR", `Missing environment variable \`${name}\``, { variable: name }).toConvexError();
16
17
  return value;
17
18
  }
19
+ /** @internal */
18
20
  function isLocalHost(host) {
19
21
  if (host === void 0) return false;
20
22
  const raw = host.includes("://") ? host : `http://${host}`;
@@ -26,28 +28,36 @@ function isLocalHost(host) {
26
28
  }
27
29
  return url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1";
28
30
  }
31
+ /** @internal */
29
32
  const TOKEN_SUB_CLAIM_DIVIDER = "|";
33
+ /** @internal */
30
34
  const REFRESH_TOKEN_DIVIDER = "|";
35
+ /** @internal */
31
36
  async function sha256$1(input) {
32
37
  return encodeHexLowerCase(sha256(new TextEncoder().encode(input)));
33
38
  }
39
+ /** @internal */
34
40
  function generateRandomString$1(length, alphabet) {
35
41
  return generateRandomString({ read(bytes) {
36
42
  crypto.getRandomValues(bytes);
37
43
  } }, alphabet, length);
38
44
  }
45
+ /** @internal */
39
46
  function errorMessage(error) {
40
47
  return error instanceof Error ? error.message : String(error);
41
48
  }
49
+ /** @internal */
42
50
  function logError(error) {
43
51
  logWithLevel(LOG_LEVELS.ERROR, error instanceof Error ? error.message + "\n" + error.stack?.replace("\\n", "\n") : error);
44
52
  }
53
+ /** @internal */
45
54
  const LOG_LEVELS = {
46
55
  ERROR: "ERROR",
47
56
  WARN: "WARN",
48
57
  INFO: "INFO",
49
58
  DEBUG: "DEBUG"
50
59
  };
60
+ /** @internal */
51
61
  function logWithLevel(level, ...args) {
52
62
  const configuredLogLevel = LOG_LEVELS[process.env.AUTH_LOG_LEVEL ?? "INFO"] ?? "INFO";
53
63
  switch (level) {
@@ -66,6 +76,7 @@ function logWithLevel(level, ...args) {
66
76
  }
67
77
  }
68
78
  const UNREDACTED_LENGTH = 5;
79
+ /** @internal */
69
80
  function maybeRedact(value) {
70
81
  if (value === "") return "";
71
82
  if (process.env.AUTH_LOG_SECRETS !== "true") {
@@ -73,7 +84,38 @@ function maybeRedact(value) {
73
84
  return value.substring(0, UNREDACTED_LENGTH) + "<redacted>" + value.substring(value.length - UNREDACTED_LENGTH);
74
85
  } else return value;
75
86
  }
87
+ const SECRET_KEY_ENV = "AUTH_SECRET_ENCRYPTION_KEY";
88
+ const SECRET_IV_LENGTH = 12;
89
+ function toArrayBuffer(bytes) {
90
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
91
+ }
92
+ async function getSecretCryptoKey() {
93
+ const material = requireEnv(SECRET_KEY_ENV);
94
+ const rawKey = sha256(new TextEncoder().encode(material));
95
+ return await crypto.subtle.importKey("raw", toArrayBuffer(rawKey), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
96
+ }
97
+ /** @internal */
98
+ async function encryptSecret(value) {
99
+ const key = await getSecretCryptoKey();
100
+ const iv = crypto.getRandomValues(new Uint8Array(SECRET_IV_LENGTH));
101
+ const encrypted = await crypto.subtle.encrypt({
102
+ name: "AES-GCM",
103
+ iv: toArrayBuffer(iv)
104
+ }, key, toArrayBuffer(new TextEncoder().encode(value)));
105
+ return `${encodeBase64urlNoPadding(iv)}.${encodeBase64urlNoPadding(new Uint8Array(encrypted))}`;
106
+ }
107
+ /** @internal */
108
+ async function decryptSecret(ciphertext) {
109
+ const [ivEncoded, payloadEncoded] = ciphertext.split(".");
110
+ if (!ivEncoded || !payloadEncoded) throw new AuthError("INVALID_PARAMETERS", "Stored enterprise secret is malformed.").toConvexError();
111
+ const key = await getSecretCryptoKey();
112
+ const decrypted = await crypto.subtle.decrypt({
113
+ name: "AES-GCM",
114
+ iv: toArrayBuffer(decodeBase64urlIgnorePadding(ivEncoded))
115
+ }, key, toArrayBuffer(decodeBase64urlIgnorePadding(payloadEncoded)));
116
+ return new TextDecoder().decode(decrypted);
117
+ }
76
118
 
77
119
  //#endregion
78
- export { LOG_LEVELS, REFRESH_TOKEN_DIVIDER, TOKEN_SUB_CLAIM_DIVIDER, errorMessage, generateRandomString$1 as generateRandomString, isLocalHost, logError, logWithLevel, maybeRedact, requireEnv, sha256$1 as sha256 };
120
+ export { LOG_LEVELS, REFRESH_TOKEN_DIVIDER, TOKEN_SUB_CLAIM_DIVIDER, decryptSecret, encryptSecret, errorMessage, generateRandomString$1 as generateRandomString, isLocalHost, logError, logWithLevel, maybeRedact, requireEnv, sha256$1 as sha256 };
79
121
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["sha256","rawSha256","generateRandomString","osloGenerateRandomString"],"sources":["../../../src/server/utils.ts"],"sourcesContent":["import {\n RandomReader,\n generateRandomString as osloGenerateRandomString,\n} from \"@oslojs/crypto/random\";\nimport { sha256 as rawSha256 } from \"@oslojs/crypto/sha2\";\nimport { encodeHexLowerCase } from \"@oslojs/encoding\";\n\nimport { AuthError } from \"./fx\";\n\n/**\n * Require an environment variable to be set, throwing at config time if missing.\n *\n * Uses `AuthError.toConvexError()` directly since this is a synchronous guard\n * called inline in many expressions — not suitable for Fx pipeline wrapping.\n */\nexport function requireEnv(name: string) {\n const value = process.env[name];\n if (value === undefined) {\n throw new AuthError(\n \"MISSING_ENV_VAR\",\n `Missing environment variable \\`${name}\\``,\n { variable: name },\n ).toConvexError();\n }\n return value;\n}\n\nexport function isLocalHost(host?: string) {\n if (host === undefined) {\n return false;\n }\n const raw = host.includes(\"://\") ? host : `http://${host}`;\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return false;\n }\n return (\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\" ||\n url.hostname === \"::1\"\n );\n}\n\n// Internal server utilities (merged from former internalUtils.ts)\n\nexport const TOKEN_SUB_CLAIM_DIVIDER = \"|\";\nexport const REFRESH_TOKEN_DIVIDER = \"|\";\n\nexport async function sha256(input: string) {\n return encodeHexLowerCase(rawSha256(new TextEncoder().encode(input)));\n}\n\nexport function generateRandomString(length: number, alphabet: string) {\n const random: RandomReader = {\n read(bytes) {\n crypto.getRandomValues(bytes as Uint8Array<ArrayBuffer>);\n },\n };\n\n return osloGenerateRandomString(random, alphabet, length);\n}\n\nexport function errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function logError(error: unknown) {\n logWithLevel(\n LOG_LEVELS.ERROR,\n error instanceof Error\n ? error.message + \"\\n\" + error.stack?.replace(\"\\\\n\", \"\\n\")\n : error,\n );\n}\n\nexport const LOG_LEVELS = {\n ERROR: \"ERROR\",\n WARN: \"WARN\",\n INFO: \"INFO\",\n DEBUG: \"DEBUG\",\n} as const;\ntype LogLevel = keyof typeof LOG_LEVELS;\n\nexport function logWithLevel(level: LogLevel, ...args: unknown[]) {\n const configuredLogLevel =\n LOG_LEVELS[\n (process.env.AUTH_LOG_LEVEL as LogLevel | undefined) ?? \"INFO\"\n ] ?? \"INFO\";\n switch (level) {\n case \"ERROR\":\n console.error(...args);\n break;\n case \"WARN\":\n if (configuredLogLevel !== \"ERROR\") {\n console.warn(...args);\n }\n break;\n case \"INFO\":\n if (configuredLogLevel === \"INFO\" || configuredLogLevel === \"DEBUG\") {\n console.info(...args);\n }\n break;\n case \"DEBUG\":\n if (configuredLogLevel === \"DEBUG\") {\n console.debug(...args);\n }\n break;\n }\n}\n\nconst UNREDACTED_LENGTH = 5;\nexport function maybeRedact(value: string) {\n if (value === \"\") {\n return \"\";\n }\n const shouldRedact = process.env.AUTH_LOG_SECRETS !== \"true\";\n if (shouldRedact) {\n if (value.length < UNREDACTED_LENGTH * 2) {\n return \"<redacted>\";\n }\n return (\n value.substring(0, UNREDACTED_LENGTH) +\n \"<redacted>\" +\n value.substring(value.length - UNREDACTED_LENGTH)\n );\n } else {\n return value;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,WAAW,MAAc;CACvC,MAAM,QAAQ,QAAQ,IAAI;AAC1B,KAAI,UAAU,OACZ,OAAM,IAAI,UACR,mBACA,kCAAkC,KAAK,KACvC,EAAE,UAAU,MAAM,CACnB,CAAC,eAAe;AAEnB,QAAO;;AAGT,SAAgB,YAAY,MAAe;AACzC,KAAI,SAAS,OACX,QAAO;CAET,MAAM,MAAM,KAAK,SAAS,MAAM,GAAG,OAAO,UAAU;CACpD,IAAI;AACJ,KAAI;AACF,QAAM,IAAI,IAAI,IAAI;SACZ;AACN,SAAO;;AAET,QACE,IAAI,aAAa,eACjB,IAAI,aAAa,eACjB,IAAI,aAAa;;AAMrB,MAAa,0BAA0B;AACvC,MAAa,wBAAwB;AAErC,eAAsBA,SAAO,OAAe;AAC1C,QAAO,mBAAmBC,OAAU,IAAI,aAAa,CAAC,OAAO,MAAM,CAAC,CAAC;;AAGvE,SAAgBC,uBAAqB,QAAgB,UAAkB;AAOrE,QAAOC,qBANsB,EAC3B,KAAK,OAAO;AACV,SAAO,gBAAgB,MAAiC;IAE3D,EAEuC,UAAU,OAAO;;AAG3D,SAAgB,aAAa,OAAgB;AAC3C,QAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;AAG/D,SAAgB,SAAS,OAAgB;AACvC,cACE,WAAW,OACX,iBAAiB,QACb,MAAM,UAAU,OAAO,MAAM,OAAO,QAAQ,OAAO,KAAK,GACxD,MACL;;AAGH,MAAa,aAAa;CACxB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;AAGD,SAAgB,aAAa,OAAiB,GAAG,MAAiB;CAChE,MAAM,qBACJ,WACG,QAAQ,IAAI,kBAA2C,WACrD;AACP,SAAQ,OAAR;EACE,KAAK;AACH,WAAQ,MAAM,GAAG,KAAK;AACtB;EACF,KAAK;AACH,OAAI,uBAAuB,QACzB,SAAQ,KAAK,GAAG,KAAK;AAEvB;EACF,KAAK;AACH,OAAI,uBAAuB,UAAU,uBAAuB,QAC1D,SAAQ,KAAK,GAAG,KAAK;AAEvB;EACF,KAAK;AACH,OAAI,uBAAuB,QACzB,SAAQ,MAAM,GAAG,KAAK;AAExB;;;AAIN,MAAM,oBAAoB;AAC1B,SAAgB,YAAY,OAAe;AACzC,KAAI,UAAU,GACZ,QAAO;AAGT,KADqB,QAAQ,IAAI,qBAAqB,QACpC;AAChB,MAAI,MAAM,SAAS,oBAAoB,EACrC,QAAO;AAET,SACE,MAAM,UAAU,GAAG,kBAAkB,GACrC,eACA,MAAM,UAAU,MAAM,SAAS,kBAAkB;OAGnD,QAAO"}
1
+ {"version":3,"file":"utils.js","names":["sha256","rawSha256","generateRandomString","osloGenerateRandomString"],"sources":["../../../src/server/utils.ts"],"sourcesContent":["import {\n RandomReader,\n generateRandomString as osloGenerateRandomString,\n} from \"@oslojs/crypto/random\";\nimport { sha256 as rawSha256 } from \"@oslojs/crypto/sha2\";\nimport {\n decodeBase64urlIgnorePadding,\n encodeBase64urlNoPadding,\n encodeHexLowerCase,\n} from \"@oslojs/encoding\";\n\nimport { AuthError } from \"./fx\";\n\n/**\n * Require an environment variable to be set, throwing at config time if missing.\n *\n * Uses `AuthError.toConvexError()` directly since this is a synchronous guard\n * called inline in many expressions — not suitable for Fx pipeline wrapping.\n */\n/** @internal */\nexport function requireEnv(name: string) {\n const value = process.env[name];\n if (value === undefined) {\n throw new AuthError(\n \"MISSING_ENV_VAR\",\n `Missing environment variable \\`${name}\\``,\n { variable: name },\n ).toConvexError();\n }\n return value;\n}\n\n/** @internal */\nexport function isLocalHost(host?: string) {\n if (host === undefined) {\n return false;\n }\n const raw = host.includes(\"://\") ? host : `http://${host}`;\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return false;\n }\n return (\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\" ||\n url.hostname === \"::1\"\n );\n}\n\n// Internal server utilities (merged from former internalUtils.ts)\n\n/** @internal */\nexport const TOKEN_SUB_CLAIM_DIVIDER = \"|\";\n/** @internal */\nexport const REFRESH_TOKEN_DIVIDER = \"|\";\n\n/** @internal */\nexport async function sha256(input: string) {\n return encodeHexLowerCase(rawSha256(new TextEncoder().encode(input)));\n}\n\n/** @internal */\nexport function generateRandomString(length: number, alphabet: string) {\n const random: RandomReader = {\n read(bytes) {\n crypto.getRandomValues(bytes as Uint8Array<ArrayBuffer>);\n },\n };\n\n return osloGenerateRandomString(random, alphabet, length);\n}\n\n/** @internal */\nexport function errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** @internal */\nexport function logError(error: unknown) {\n logWithLevel(\n LOG_LEVELS.ERROR,\n error instanceof Error\n ? error.message + \"\\n\" + error.stack?.replace(\"\\\\n\", \"\\n\")\n : error,\n );\n}\n\n/** @internal */\nexport const LOG_LEVELS = {\n ERROR: \"ERROR\",\n WARN: \"WARN\",\n INFO: \"INFO\",\n DEBUG: \"DEBUG\",\n} as const;\ntype LogLevel = keyof typeof LOG_LEVELS;\n\n/** @internal */\nexport function logWithLevel(level: LogLevel, ...args: unknown[]) {\n const configuredLogLevel =\n LOG_LEVELS[\n (process.env.AUTH_LOG_LEVEL as LogLevel | undefined) ?? \"INFO\"\n ] ?? \"INFO\";\n switch (level) {\n case \"ERROR\":\n console.error(...args);\n break;\n case \"WARN\":\n if (configuredLogLevel !== \"ERROR\") {\n console.warn(...args);\n }\n break;\n case \"INFO\":\n if (configuredLogLevel === \"INFO\" || configuredLogLevel === \"DEBUG\") {\n console.info(...args);\n }\n break;\n case \"DEBUG\":\n if (configuredLogLevel === \"DEBUG\") {\n console.debug(...args);\n }\n break;\n }\n}\n\nconst UNREDACTED_LENGTH = 5;\n/** @internal */\nexport function maybeRedact(value: string) {\n if (value === \"\") {\n return \"\";\n }\n const shouldRedact = process.env.AUTH_LOG_SECRETS !== \"true\";\n if (shouldRedact) {\n if (value.length < UNREDACTED_LENGTH * 2) {\n return \"<redacted>\";\n }\n return (\n value.substring(0, UNREDACTED_LENGTH) +\n \"<redacted>\" +\n value.substring(value.length - UNREDACTED_LENGTH)\n );\n } else {\n return value;\n }\n}\n\nconst SECRET_KEY_ENV = \"AUTH_SECRET_ENCRYPTION_KEY\";\nconst SECRET_IV_LENGTH = 12;\n\nfunction toArrayBuffer(bytes: Uint8Array) {\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength,\n ) as ArrayBuffer;\n}\n\nasync function getSecretCryptoKey() {\n const material = requireEnv(SECRET_KEY_ENV);\n const rawKey = rawSha256(new TextEncoder().encode(material));\n return await crypto.subtle.importKey(\n \"raw\",\n toArrayBuffer(rawKey),\n { name: \"AES-GCM\" },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n}\n\n/** @internal */\nexport async function encryptSecret(value: string) {\n const key = await getSecretCryptoKey();\n const iv = crypto.getRandomValues(new Uint8Array(SECRET_IV_LENGTH));\n const encrypted = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv: toArrayBuffer(iv) },\n key,\n toArrayBuffer(new TextEncoder().encode(value)),\n );\n return `${encodeBase64urlNoPadding(iv)}.${encodeBase64urlNoPadding(new Uint8Array(encrypted))}`;\n}\n\n/** @internal */\nexport async function decryptSecret(ciphertext: string) {\n const [ivEncoded, payloadEncoded] = ciphertext.split(\".\");\n if (!ivEncoded || !payloadEncoded) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Stored enterprise secret is malformed.\",\n ).toConvexError();\n }\n const key = await getSecretCryptoKey();\n const decrypted = await crypto.subtle.decrypt(\n {\n name: \"AES-GCM\",\n iv: toArrayBuffer(decodeBase64urlIgnorePadding(ivEncoded)),\n },\n key,\n toArrayBuffer(decodeBase64urlIgnorePadding(payloadEncoded)),\n );\n return new TextDecoder().decode(decrypted);\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { GenericActionCtxWithAuthConfig } from "../server/types.js";
2
- import { Value } from "convex/values";
3
2
  import { DocumentByName, GenericDataModel, WithoutSystemFields } from "convex/server";
3
+ import { Value } from "convex/values";
4
4
 
5
5
  //#region src/providers/anonymous.d.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { AuthProviderConfig, GenericActionCtxWithAuthConfig } from "../server/types.js";
2
- import { GenericId, Value } from "convex/values";
3
2
  import { GenericDataModel } from "convex/server";
3
+ import { GenericId, Value } from "convex/values";
4
4
 
5
5
  //#region src/providers/credentials.d.ts
6
6
  /**
@@ -1,7 +1,7 @@
1
1
  import { CredentialsConfig } from "./credentials.js";
2
2
  import { EmailConfig, GenericActionCtxWithAuthConfig } from "../server/types.js";
3
- import { Value } from "convex/values";
4
3
  import { DocumentByName, GenericDataModel, WithoutSystemFields } from "convex/server";
4
+ import { Value } from "convex/values";
5
5
 
6
6
  //#region src/providers/password.d.ts
7
7
  /**
@@ -15,7 +15,7 @@
15
15
  * });
16
16
  *
17
17
  * // auth.sso is now available
18
- * await auth.sso.oidc.configure(ctx, { enterpriseId, clientId, ... });
18
+ * await auth.sso.admin.oidc.configure(ctx, { enterpriseId, clientId, ... });
19
19
  * ```
20
20
  *
21
21
  * Without `new SSO()` in the providers list, `auth.sso` is not
@@ -1 +1 @@
1
- {"version":3,"file":"sso.js","names":[],"sources":["../../src/providers/sso.ts"],"sourcesContent":["/**\n * Enterprise SSO provider (OIDC + SAML + SCIM).\n *\n * Adding `new SSO()` to your providers list enables enterprise SSO\n * sign-in flows and registers the OIDC, SAML, and SCIM runtime HTTP\n * routes. It also makes `auth.sso.*` available on the auth\n * object returned by `createAuth`.\n *\n * ```ts\n * import { SSO } from \"@robelest/convex-auth/providers\";\n *\n * const auth = createAuth(components.auth, {\n * providers: [new SSO(), new Password()],\n * });\n *\n * // auth.sso is now available\n * await auth.sso.oidc.configure(ctx, { enterpriseId, clientId, ... });\n * ```\n *\n * Without `new SSO()` in the providers list, `auth.sso` is not\n * present on the returned object and accessing it is a TypeScript error.\n *\n * @module\n */\n\nimport type { SSOProviderConfig } from \"../server/types\";\n\n/**\n * Enterprise SSO provider.\n *\n * Zero-configuration — sensible defaults are applied for all enterprise\n * protocols (OIDC, SAML, SCIM). Per-tenant configuration is done at\n * runtime via `auth.sso.*` helpers.\n *\n * @example\n * ```ts\n * import { createAuth } from \"@robelest/convex-auth/component\";\n * import { SSO, Password } from \"@robelest/convex-auth/providers\";\n * import { components } from \"./_generated/api\";\n *\n * export const auth = createAuth(components.auth, {\n * providers: [new SSO(), new Password()],\n * });\n * ```\n */\nexport class SSO {\n readonly id = \"enterprise-sso\";\n readonly type = \"sso\" as const;\n\n /** @internal Convert to the internal materialized config shape. */\n _toMaterialized(): SSOProviderConfig {\n return { id: this.id, type: \"sso\" };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA6CA,IAAa,MAAb,MAAiB;CACf,AAAS,KAAK;CACd,AAAS,OAAO;;CAGhB,kBAAqC;AACnC,SAAO;GAAE,IAAI,KAAK;GAAI,MAAM;GAAO"}
1
+ {"version":3,"file":"sso.js","names":[],"sources":["../../src/providers/sso.ts"],"sourcesContent":["/**\n * Enterprise SSO provider (OIDC + SAML + SCIM).\n *\n * Adding `new SSO()` to your providers list enables enterprise SSO\n * sign-in flows and registers the OIDC, SAML, and SCIM runtime HTTP\n * routes. It also makes `auth.sso.*` available on the auth\n * object returned by `createAuth`.\n *\n * ```ts\n * import { SSO } from \"@robelest/convex-auth/providers\";\n *\n * const auth = createAuth(components.auth, {\n * providers: [new SSO(), new Password()],\n * });\n *\n * // auth.sso is now available\n * await auth.sso.admin.oidc.configure(ctx, { enterpriseId, clientId, ... });\n * ```\n *\n * Without `new SSO()` in the providers list, `auth.sso` is not\n * present on the returned object and accessing it is a TypeScript error.\n *\n * @module\n */\n\nimport type { SSOProviderConfig } from \"../server/types\";\n\n/**\n * Enterprise SSO provider.\n *\n * Zero-configuration — sensible defaults are applied for all enterprise\n * protocols (OIDC, SAML, SCIM). Per-tenant configuration is done at\n * runtime via `auth.sso.*` helpers.\n *\n * @example\n * ```ts\n * import { createAuth } from \"@robelest/convex-auth/component\";\n * import { SSO, Password } from \"@robelest/convex-auth/providers\";\n * import { components } from \"./_generated/api\";\n *\n * export const auth = createAuth(components.auth, {\n * providers: [new SSO(), new Password()],\n * });\n * ```\n */\nexport class SSO {\n readonly id = \"enterprise-sso\";\n readonly type = \"sso\" as const;\n\n /** @internal Convert to the internal materialized config shape. */\n _toMaterialized(): SSOProviderConfig {\n return { id: this.id, type: \"sso\" };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA6CA,IAAa,MAAb,MAAiB;CACf,AAAS,KAAK;CACd,AAAS,OAAO;;CAGhB,kBAAqC;AACnC,SAAO;GAAE,IAAI,KAAK;GAAI,MAAM;GAAO"}
@@ -1,8 +1,8 @@
1
- import { AuthProviderConfig, ConvexAuthConfig, Doc, HasDeviceProvider, HasPasskeyProvider, HasSSO, HasTotpProvider } from "./types.js";
1
+ import { AuthAuthorizationConfig, AuthGrant, AuthProviderConfig, AuthRoleId, ConvexAuthConfig, Doc, HasDeviceProvider, HasPasskeyProvider, HasSSO, HasTotpProvider } from "./types.js";
2
2
  import { AuthApiRefs } from "../client/index.js";
3
- import { Auth as Auth$1 } from "./implementation.js";
4
- import { GenericId } from "convex/values";
3
+ import { Auth as Auth$1 } from "./factory.js";
5
4
  import { UserIdentity } from "convex/server";
5
+ import { GenericId } from "convex/values";
6
6
 
7
7
  //#region src/server/auth.d.ts
8
8
  /**
@@ -10,8 +10,66 @@ import { UserIdentity } from "convex/server";
10
10
  * minus `component` (which is passed as the first constructor argument).
11
11
  */
12
12
  type AuthConfig = Omit<ConvexAuthConfig, "component">;
13
+ type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig | undefined> = Omit<ReturnType<typeof Auth$1>["auth"]["member"], "create" | "list" | "update" | "inherit" | "require"> & {
14
+ create: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["create"]>[0], data: {
15
+ groupId: string;
16
+ userId: string;
17
+ roleIds?: AuthRoleId<TAuthorization>[];
18
+ status?: string;
19
+ extend?: Record<string, unknown>;
20
+ }) => Promise<{
21
+ ok: true;
22
+ memberId: string;
23
+ }>;
24
+ list: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["list"]>[0], opts?: {
25
+ where?: {
26
+ groupId?: string;
27
+ userId?: string;
28
+ roleId?: AuthRoleId<TAuthorization>;
29
+ status?: string;
30
+ };
31
+ limit?: number;
32
+ cursor?: string | null;
33
+ orderBy?: "_creationTime" | "status";
34
+ order?: "asc" | "desc";
35
+ }) => ReturnType<ReturnType<typeof Auth$1>["auth"]["member"]["list"]>;
36
+ update: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["update"]>[0], memberId: string, data: Record<string, unknown> & {
37
+ roleIds?: AuthRoleId<TAuthorization>[];
38
+ }) => Promise<{
39
+ ok: true;
40
+ memberId: string;
41
+ }>;
42
+ inherit: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["inherit"]>[0], opts: {
43
+ userId: string;
44
+ groupId: string;
45
+ roleIds?: AuthRoleId<TAuthorization>[];
46
+ grants?: AuthGrant<TAuthorization>[];
47
+ maxDepth?: number;
48
+ }) => ReturnType<ReturnType<typeof Auth$1>["auth"]["member"]["inherit"]>;
49
+ require: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["require"]>[0], opts: {
50
+ userId: string;
51
+ groupId: string;
52
+ roleIds?: AuthRoleId<TAuthorization>[];
53
+ grants?: AuthGrant<TAuthorization>[];
54
+ maxDepth?: number;
55
+ }) => ReturnType<ReturnType<typeof Auth$1>["auth"]["member"]["require"]>;
56
+ };
57
+ type AccessApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig | undefined> = {
58
+ check: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["access"]["check"]>[0], opts: {
59
+ userId: string;
60
+ groupId: string;
61
+ grants: AuthGrant<TAuthorization>[];
62
+ maxDepth?: number;
63
+ }) => ReturnType<ReturnType<typeof Auth$1>["auth"]["access"]["check"]>;
64
+ require: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["access"]["require"]>[0], opts: {
65
+ userId: string;
66
+ groupId: string;
67
+ grants: AuthGrant<TAuthorization>[];
68
+ maxDepth?: number;
69
+ }) => ReturnType<ReturnType<typeof Auth$1>["auth"]["access"]["require"]>;
70
+ };
13
71
  /** The base auth API surface, without conditional namespaces. */
14
- type AuthApiBase = {
72
+ type AuthApiBase<TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = {
15
73
  signIn: ReturnType<typeof Auth$1>["signIn"];
16
74
  signOut: ReturnType<typeof Auth$1>["signOut"];
17
75
  store: ReturnType<typeof Auth$1>["store"];
@@ -20,21 +78,100 @@ type AuthApiBase = {
20
78
  provider: ReturnType<typeof Auth$1>["auth"]["provider"];
21
79
  account: ReturnType<typeof Auth$1>["auth"]["account"];
22
80
  group: ReturnType<typeof Auth$1>["auth"]["group"];
23
- member: ReturnType<typeof Auth$1>["auth"]["member"];
81
+ member: MemberApiWithAuthorization<TAuthorization>;
82
+ access: AccessApiWithAuthorization<TAuthorization>;
24
83
  invite: ReturnType<typeof Auth$1>["auth"]["invite"];
25
84
  key: ReturnType<typeof Auth$1>["auth"]["key"];
26
85
  http: ReturnType<typeof Auth$1>["auth"]["http"];
27
86
  };
28
- /** Auth API with SSO namespace — present only when `new SSO()` is in providers. */
29
- type AuthApi = AuthApiBase & {
30
- sso: ReturnType<typeof Auth$1>["auth"]["sso"];
87
+ type InternalSsoApi = ReturnType<typeof Auth$1>["auth"]["sso"];
88
+ type PublicSsoAdminApi = {
89
+ connection: InternalSsoApi["connection"] & {
90
+ domain: {
91
+ list: InternalSsoApi["domain"]["list"];
92
+ validate: InternalSsoApi["domain"]["validate"];
93
+ set: (ctx: Parameters<InternalSsoApi["connection"]["create"]>[0], enterpriseId: string, domains: Array<{
94
+ domain: string;
95
+ isPrimary?: boolean;
96
+ }>) => Promise<{
97
+ ok: true;
98
+ enterpriseId: string;
99
+ domains: Array<{
100
+ domainId: string;
101
+ domain: string;
102
+ isPrimary: boolean;
103
+ verified: boolean;
104
+ verifiedAt: number | null;
105
+ }>;
106
+ }>;
107
+ verification: {
108
+ request: (ctx: Parameters<InternalSsoApi["connection"]["create"]>[0], args: {
109
+ enterpriseId: string;
110
+ domain: string;
111
+ }) => Promise<{
112
+ ok: true;
113
+ enterpriseId: string;
114
+ domain: string;
115
+ requestedAt: number;
116
+ expiresAt: number;
117
+ challenge: {
118
+ recordType: "TXT";
119
+ recordName: string;
120
+ recordValue: string;
121
+ };
122
+ }>;
123
+ confirm: (ctx: Parameters<InternalSsoApi["connection"]["create"]>[0], args: {
124
+ enterpriseId: string;
125
+ domain: string;
126
+ }) => Promise<{
127
+ ok: boolean;
128
+ enterpriseId: string;
129
+ domain: string;
130
+ verifiedAt?: number;
131
+ checks: Array<{
132
+ name: string;
133
+ ok: boolean;
134
+ message?: string;
135
+ }>;
136
+ }>;
137
+ };
138
+ };
139
+ };
140
+ oidc: Omit<InternalSsoApi["oidc"], "signIn">;
141
+ saml: Omit<InternalSsoApi["saml"], "metadata">;
142
+ policy: InternalSsoApi["policy"];
143
+ audit: {
144
+ list: InternalSsoApi["audit"]["list"];
145
+ };
146
+ webhook: {
147
+ endpoint: InternalSsoApi["webhook"]["endpoint"];
148
+ delivery: {
149
+ list: InternalSsoApi["webhook"]["delivery"]["list"];
150
+ };
151
+ };
152
+ };
153
+ type PublicSsoClientApi = {
154
+ signIn: InternalSsoApi["oidc"]["signIn"];
155
+ metadata: InternalSsoApi["saml"]["metadata"];
156
+ };
157
+ type PublicSsoApi = {
158
+ admin: PublicSsoAdminApi;
159
+ client: PublicSsoClientApi;
160
+ };
161
+ type PublicScimApi = {
162
+ admin: Omit<InternalSsoApi["scim"], "getConfigByToken" | "identity">;
163
+ };
164
+ /** Auth API with enterprise namespaces — present only when `new SSO()` is in providers. */
165
+ type AuthApi<TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = AuthApiBase<TAuthorization> & {
166
+ sso: PublicSsoApi;
167
+ scim: PublicScimApi;
31
168
  };
32
169
  /**
33
170
  * The return type of `createAuth`. Conditional namespaces:
34
- * - `auth.sso` — only when `new SSO()` is in providers
171
+ * - `auth.sso` and `auth.scim` — only when `new SSO()` is in providers
35
172
  * - `auth.clientApi` — typed API refs for the client SDK with capabilities
36
173
  */
37
- type ConvexAuthResult<P extends AuthProviderConfig[]> = HasSSO<P> extends true ? AuthApi : AuthApiBase;
174
+ type ConvexAuthResult<P extends AuthProviderConfig[], TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = HasSSO<P> extends true ? AuthApi<TAuthorization> : AuthApiBase<TAuthorization>;
38
175
  /**
39
176
  * Infer the typed `AuthApiRefs` for the client SDK from a `createAuth` call.
40
177
  *
@@ -47,20 +184,29 @@ type ConvexAuthResult<P extends AuthProviderConfig[]> = HasSSO<P> extends true ?
47
184
  * // Frontend
48
185
  * import type { auth } from "../convex/auth";
49
186
  * import type { InferClientApi } from "@robelest/convex-auth/component";
50
- * const c = client<InferClientApi<typeof auth>>({ convex, api: { ... } });
187
+ * const c = client<InferClientApi<typeof auth>>({ convex, api: api.auth });
51
188
  * ```
52
189
  */
53
190
  type InferClientApi<T> = T extends ConvexAuthResult<infer P> ? AuthApiRefs<HasPasskeyProvider<P>, HasTotpProvider<P>, HasDeviceProvider<P>> : AuthApiRefs;
54
191
  /**
55
192
  * Create an auth API object.
56
193
  *
57
- * When `new SSO()` is included in providers, `auth.sso` is available
58
- * on the returned object. Without it, `auth.sso` is absent and
59
- * accessing it is a TypeScript compile error.
194
+ * When `new SSO()` is included in providers, `auth.sso` and `auth.scim`
195
+ * are available on the returned object. Without it, those namespaces are
196
+ * absent and accessing them is a TypeScript compile error.
60
197
  */
61
- declare function createAuth<P extends AuthProviderConfig[]>(component: ConvexAuthConfig["component"], config: Omit<AuthConfig, "providers"> & {
198
+ declare function createAuth<P extends AuthProviderConfig[], TAuthorization extends AuthAuthorizationConfig | undefined = undefined>(component: ConvexAuthConfig["component"], config: Omit<AuthConfig, "providers" | "authorization"> & {
62
199
  providers: P;
63
- }): ConvexAuthResult<P>;
200
+ authorization?: TAuthorization;
201
+ }): ConvexAuthResult<P, TAuthorization>;
202
+ declare function defineRoles<const TRoles extends Record<string, {
203
+ label?: string;
204
+ grants: readonly string[];
205
+ }>>(roles: TRoles): { [K in keyof TRoles]: {
206
+ id: K & string;
207
+ label?: TRoles[K]["label"];
208
+ grants: Array<TRoles[K]["grants"][number] & string>;
209
+ } };
64
210
  type UserDoc = Doc<"User">;
65
211
  type AuthCtxConfig<TResolve extends Record<string, unknown> = Record<string, never>> = {
66
212
  optional?: boolean;
@@ -104,5 +250,5 @@ type InferAuth<T extends {
104
250
  }>;
105
251
  }> = Awaited<ReturnType<T["input"]>>["ctx"]["auth"];
106
252
  //#endregion
107
- export { AuthApi, AuthApiBase, AuthConfig, AuthCtx, AuthCtxConfig, ConvexAuthResult, InferAuth, InferClientApi, UserDoc, createAuth };
253
+ export { AuthApi, AuthApiBase, AuthConfig, AuthCtx, AuthCtxConfig, ConvexAuthResult, InferAuth, InferClientApi, UserDoc, createAuth, defineRoles };
108
254
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/server/auth.ts"],"mappings":";;;;;;;;AAkCA;;;KAHY,UAAA,GAAa,IAAA,CAAK,gBAAA;;KAGlB,WAAA;EACV,MAAA,EAAQ,UAAA,QAAkB,MAAA;EAC1B,OAAA,EAAS,UAAA,QAAkB,MAAA;EAC3B,KAAA,EAAO,UAAA,QAAkB,MAAA;EACzB,IAAA,EAAM,UAAA,QAAkB,MAAA;EACxB,OAAA,EAAS,UAAA,QAAkB,MAAA;EAC3B,QAAA,EAAU,UAAA,QAAkB,MAAA;EAC5B,OAAA,EAAS,UAAA,QAAkB,MAAA;EAC3B,KAAA,EAAO,UAAA,QAAkB,MAAA;EACzB,MAAA,EAAQ,UAAA,QAAkB,MAAA;EAC1B,MAAA,EAAQ,UAAA,QAAkB,MAAA;EAC1B,GAAA,EAAK,UAAA,QAAkB,MAAA;EACvB,IAAA,EAAM,UAAA,QAAkB,MAAA;AAAA;;KAId,OAAA,GAAU,WAAA;EACpB,GAAA,EAAK,UAAA,QAAkB,MAAA;AAAA;;;;;;KAQb,gBAAA,WAA2B,kBAAA,MACrC,MAAA,CAAO,CAAA,iBAAkB,OAAA,GAAU,WAAA;;;;;;;;;;;;;;;;KAiBzB,cAAA,MACV,CAAA,SAAU,gBAAA,YACN,WAAA,CACE,kBAAA,CAAmB,CAAA,GACnB,eAAA,CAAgB,CAAA,GAChB,iBAAA,CAAkB,CAAA,KAEpB,WAAA;;;;;;;;iBAgBU,UAAA,WAAqB,kBAAA,GAAA,CACnC,SAAA,EAAW,gBAAA,eACX,MAAA,EAAQ,IAAA,CAAK,UAAA;EAA6B,SAAA,EAAW,CAAA;AAAA,IACpD,gBAAA,CAAiB,CAAA;AAAA,KA4BR,OAAA,GAAU,GAAA;AAAA,KAEV,aAAA,kBACO,MAAA,oBAA0B,MAAA;EAE3C,QAAA;EACA,OAAA,IAAW,GAAA,OAAU,IAAA,EAAM,OAAA,KAAY,OAAA,CAAQ,QAAA,IAAY,QAAA;AAAA;;iBAI7C,OAAA,kBACG,MAAA,oBAA0B,MAAA,gBAAA,CAE3C,IAAA,EAAM,QAAA,EACN,MAAA,EAAQ,aAAA,CAAc,QAAA;EAAc,QAAA;AAAA;EAEpC,IAAA;EACA,KAAA,GACE,GAAA,OACA,KAAA,OACA,MAAA,WACG,OAAA;IACH,GAAA;MACE,IAAA;QACE,eAAA,QAAuB,OAAA,CAAQ,YAAA;QAC/B,MAAA,EAAQ,SAAA;QACR,IAAA,EAAM,OAAA;MAAA,IACJ,QAAA;IAAA;IAEN,IAAA;EAAA;AAAA;;iBAIY,OAAA,kBACG,MAAA,oBAA0B,MAAA,gBAAA,CAE3C,IAAA,EAAM,QAAA,EACN,MAAA,GAAS,aAAA,CAAc,QAAA;EAEvB,IAAA;EACA,KAAA,GACE,GAAA,OACA,KAAA,OACA,MAAA,WACG,OAAA;IACH,GAAA;MACE,IAAA;QACE,eAAA,QAAuB,OAAA,CAAQ,YAAA;QAC/B,MAAA,EAAQ,SAAA;QACR,IAAA,EAAM,OAAA;MAAA,IACJ,QAAA;IAAA;IAEN,IAAA;EAAA;AAAA;AAAA,KAgEQ,SAAA;EACE,KAAA,MAAW,IAAA,YAAgB,OAAA;IAAU,GAAA;MAAO,IAAA;IAAA;EAAA;AAAA,KACtD,OAAA,CAAQ,UAAA,CAAW,CAAA"}
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/server/auth.ts"],"mappings":"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"}
@@ -1,13 +1,13 @@
1
- import { Fx } from "./fx.js";
2
- import { Auth } from "./implementation.js";
1
+ import { AuthError, Fx } from "./fx.js";
2
+ import { Auth } from "./factory.js";
3
3
 
4
4
  //#region src/server/auth.ts
5
5
  /**
6
6
  * Create an auth API object.
7
7
  *
8
- * When `new SSO()` is included in providers, `auth.sso` is available
9
- * on the returned object. Without it, `auth.sso` is absent and
10
- * accessing it is a TypeScript compile error.
8
+ * When `new SSO()` is included in providers, `auth.sso` and `auth.scim`
9
+ * are available on the returned object. Without it, those namespaces are
10
+ * absent and accessing them is a TypeScript compile error.
11
11
  */
12
12
  function createAuth(component, config) {
13
13
  const authResult = Auth({
@@ -15,6 +15,86 @@ function createAuth(component, config) {
15
15
  component,
16
16
  providers: [...config.providers]
17
17
  });
18
+ const { domain: domainApi, scim: scimApi, connection: connectionApi, audit: auditApi, webhook: webhookApi, oidc: oidcApi, saml: samlApi, ...restSso } = authResult.auth.sso;
19
+ const setEnterpriseDomains = async (ctx, enterpriseId, domains) => {
20
+ const enterprise = await connectionApi.get(ctx, enterpriseId);
21
+ if (enterprise === null) throw new AuthError("INVALID_PARAMETERS", "Enterprise not found.").toConvexError();
22
+ const normalized = domains.map((entry) => ({
23
+ ...entry,
24
+ domain: entry.domain.trim().toLowerCase()
25
+ }));
26
+ const deduped = /* @__PURE__ */ new Map();
27
+ for (const entry of normalized) {
28
+ if (entry.domain.length === 0) throw new AuthError("INVALID_PARAMETERS", "Domain must not be empty.").toConvexError();
29
+ if (deduped.has(entry.domain)) throw new AuthError("INVALID_PARAMETERS", `Duplicate domain: ${entry.domain}`).toConvexError();
30
+ deduped.set(entry.domain, entry);
31
+ }
32
+ const nextDomains = [...deduped.values()];
33
+ const primaryCount = nextDomains.filter((entry) => entry.isPrimary).length;
34
+ if (primaryCount > 1) throw new AuthError("INVALID_PARAMETERS", "Only one primary domain may be set.").toConvexError();
35
+ if (nextDomains.length > 0 && primaryCount === 0) nextDomains[0] = {
36
+ ...nextDomains[0],
37
+ isPrimary: true
38
+ };
39
+ const currentDomains = await domainApi.list(ctx, enterpriseId);
40
+ const currentByDomain = new Map(currentDomains.map((entry) => [entry.domain.toLowerCase(), entry]));
41
+ for (const existing of currentDomains) if (!deduped.has(existing.domain.toLowerCase())) await domainApi.remove(ctx, existing._id);
42
+ for (const nextDomain of nextDomains) {
43
+ const current = currentByDomain.get(nextDomain.domain);
44
+ if (current && current.isPrimary === Boolean(nextDomain.isPrimary)) continue;
45
+ if (current) await domainApi.remove(ctx, current._id);
46
+ const domainId = await domainApi.add(ctx, {
47
+ enterpriseId: enterprise._id,
48
+ groupId: enterprise.groupId,
49
+ domain: nextDomain.domain,
50
+ isPrimary: nextDomain.isPrimary
51
+ });
52
+ if (current?.verifiedAt !== void 0) await ctx.runMutation(component.public.enterpriseDomainVerify, {
53
+ domainId,
54
+ verifiedAt: current.verifiedAt
55
+ });
56
+ }
57
+ return {
58
+ ok: true,
59
+ enterpriseId,
60
+ domains: (await domainApi.list(ctx, enterpriseId)).map((domain) => ({
61
+ domainId: domain._id,
62
+ domain: domain.domain,
63
+ isPrimary: domain.isPrimary,
64
+ verified: domain.verifiedAt !== void 0,
65
+ verifiedAt: domain.verifiedAt ?? null
66
+ }))
67
+ };
68
+ };
69
+ const publicSso = {
70
+ admin: {
71
+ ...restSso,
72
+ oidc: { ...oidcApi },
73
+ saml: { ...samlApi },
74
+ connection: {
75
+ ...connectionApi,
76
+ domain: {
77
+ list: domainApi.list,
78
+ validate: domainApi.validate,
79
+ set: setEnterpriseDomains,
80
+ verification: {
81
+ request: domainApi.verification.request,
82
+ confirm: domainApi.verification.confirm
83
+ }
84
+ }
85
+ },
86
+ policy: restSso.policy,
87
+ audit: { list: auditApi.list },
88
+ webhook: {
89
+ endpoint: webhookApi.endpoint,
90
+ delivery: { list: webhookApi.delivery.list }
91
+ }
92
+ },
93
+ client: {
94
+ signIn: oidcApi.signIn,
95
+ metadata: samlApi.metadata
96
+ }
97
+ };
18
98
  return {
19
99
  signIn: authResult.signIn,
20
100
  signOut: authResult.signOut,
@@ -25,12 +105,25 @@ function createAuth(component, config) {
25
105
  account: authResult.auth.account,
26
106
  group: authResult.auth.group,
27
107
  member: authResult.auth.member,
108
+ access: authResult.auth.access,
28
109
  invite: authResult.auth.invite,
29
110
  key: authResult.auth.key,
30
- sso: authResult.auth.sso,
111
+ sso: publicSso,
112
+ scim: { admin: {
113
+ configure: scimApi.configure,
114
+ get: scimApi.get,
115
+ validate: scimApi.validate
116
+ } },
31
117
  http: authResult.auth.http
32
118
  };
33
119
  }
120
+ function defineRoles(roles) {
121
+ return Object.fromEntries(Object.entries(roles).map(([id, role]) => [id, {
122
+ id,
123
+ ...role.label ? { label: role.label } : {},
124
+ grants: [...role.grants]
125
+ }]));
126
+ }
34
127
  function AuthCtx(auth, config) {
35
128
  return {
36
129
  args: {},
@@ -77,5 +170,5 @@ function AuthCtx(auth, config) {
77
170
  }
78
171
 
79
172
  //#endregion
80
- export { AuthCtx, createAuth };
173
+ export { AuthCtx, createAuth, defineRoles };
81
174
  //# sourceMappingURL=auth.js.map