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

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 (310) hide show
  1. package/dist/authorization/index.d.ts +1 -1
  2. package/dist/authorization/index.js +1 -1
  3. package/dist/authorization/index.js.map +1 -1
  4. package/dist/client/index.d.ts +1 -2
  5. package/dist/client/index.d.ts.map +1 -1
  6. package/dist/client/index.js +36 -39
  7. package/dist/client/index.js.map +1 -1
  8. package/dist/component/client/index.d.ts +1 -2
  9. package/dist/component/convex.config.d.ts +2 -2
  10. package/dist/component/convex.config.d.ts.map +1 -1
  11. package/dist/component/model.d.ts +5 -5
  12. package/dist/component/model.d.ts.map +1 -1
  13. package/dist/component/public/enterprise/audit.d.ts.map +1 -1
  14. package/dist/component/public/enterprise/audit.js.map +1 -1
  15. package/dist/component/public/enterprise/core.d.ts.map +1 -1
  16. package/dist/component/public/enterprise/core.js.map +1 -1
  17. package/dist/component/public/enterprise/domains.d.ts.map +1 -1
  18. package/dist/component/public/enterprise/domains.js.map +1 -1
  19. package/dist/component/public/enterprise/scim.d.ts.map +1 -1
  20. package/dist/component/public/enterprise/scim.js.map +1 -1
  21. package/dist/component/public/enterprise/secrets.d.ts.map +1 -1
  22. package/dist/component/public/enterprise/secrets.js.map +1 -1
  23. package/dist/component/public/enterprise/webhooks.d.ts.map +1 -1
  24. package/dist/component/public/enterprise/webhooks.js.map +1 -1
  25. package/dist/component/public/factors/devices.d.ts.map +1 -1
  26. package/dist/component/public/factors/devices.js.map +1 -1
  27. package/dist/component/public/factors/passkeys.d.ts.map +1 -1
  28. package/dist/component/public/factors/passkeys.js.map +1 -1
  29. package/dist/component/public/factors/totp.d.ts.map +1 -1
  30. package/dist/component/public/factors/totp.js.map +1 -1
  31. package/dist/component/public/groups/core.js.map +1 -1
  32. package/dist/component/public/groups/invites.d.ts.map +1 -1
  33. package/dist/component/public/groups/invites.js.map +1 -1
  34. package/dist/component/public/groups/members.d.ts.map +1 -1
  35. package/dist/component/public/groups/members.js.map +1 -1
  36. package/dist/component/public/identity/accounts.d.ts.map +1 -1
  37. package/dist/component/public/identity/accounts.js.map +1 -1
  38. package/dist/component/public/identity/codes.d.ts.map +1 -1
  39. package/dist/component/public/identity/codes.js.map +1 -1
  40. package/dist/component/public/identity/sessions.d.ts.map +1 -1
  41. package/dist/component/public/identity/sessions.js.map +1 -1
  42. package/dist/component/public/identity/tokens.d.ts.map +1 -1
  43. package/dist/component/public/identity/tokens.js.map +1 -1
  44. package/dist/component/public/identity/users.d.ts.map +1 -1
  45. package/dist/component/public/identity/users.js.map +1 -1
  46. package/dist/component/public/identity/verifiers.d.ts.map +1 -1
  47. package/dist/component/public/identity/verifiers.js.map +1 -1
  48. package/dist/component/public/security/keys.d.ts.map +1 -1
  49. package/dist/component/public/security/keys.js.map +1 -1
  50. package/dist/component/public/security/limits.d.ts.map +1 -1
  51. package/dist/component/public/security/limits.js.map +1 -1
  52. package/dist/component/schema.d.ts +39 -39
  53. package/dist/component/server/auth.d.ts +95 -52
  54. package/dist/component/server/auth.d.ts.map +1 -1
  55. package/dist/component/server/auth.js +63 -43
  56. package/dist/component/server/auth.js.map +1 -1
  57. package/dist/component/server/core.js +116 -235
  58. package/dist/component/server/core.js.map +1 -1
  59. package/dist/component/server/crypto.js +25 -7
  60. package/dist/component/server/crypto.js.map +1 -1
  61. package/dist/component/server/device.js +58 -15
  62. package/dist/component/server/device.js.map +1 -1
  63. package/dist/component/server/enterprise/domain.js +148 -59
  64. package/dist/component/server/enterprise/domain.js.map +1 -1
  65. package/dist/component/server/enterprise/http.js +36 -15
  66. package/dist/component/server/enterprise/http.js.map +1 -1
  67. package/dist/component/server/enterprise/oidc.js +1 -1
  68. package/dist/component/server/http.js +26 -21
  69. package/dist/component/server/http.js.map +1 -1
  70. package/dist/component/server/identity.js +5 -2
  71. package/dist/component/server/identity.js.map +1 -1
  72. package/dist/component/server/limits.js +21 -30
  73. package/dist/component/server/limits.js.map +1 -1
  74. package/dist/component/server/mutations/account.js +12 -10
  75. package/dist/component/server/mutations/account.js.map +1 -1
  76. package/dist/component/server/mutations/code.js +5 -2
  77. package/dist/component/server/mutations/code.js.map +1 -1
  78. package/dist/component/server/mutations/invalidate.js +1 -1
  79. package/dist/component/server/mutations/invalidate.js.map +1 -1
  80. package/dist/component/server/mutations/oauth.js +10 -4
  81. package/dist/component/server/mutations/oauth.js.map +1 -1
  82. package/dist/component/server/mutations/refresh.js +2 -2
  83. package/dist/component/server/mutations/refresh.js.map +1 -1
  84. package/dist/component/server/mutations/register.js +46 -42
  85. package/dist/component/server/mutations/register.js.map +1 -1
  86. package/dist/component/server/mutations/retrieve.js +21 -25
  87. package/dist/component/server/mutations/retrieve.js.map +1 -1
  88. package/dist/component/server/mutations/signature.js +10 -4
  89. package/dist/component/server/mutations/signature.js.map +1 -1
  90. package/dist/component/server/mutations/signout.js.map +1 -1
  91. package/dist/component/server/mutations/store.js +9 -24
  92. package/dist/component/server/mutations/store.js.map +1 -1
  93. package/dist/component/server/mutations/verifier.js.map +1 -1
  94. package/dist/component/server/mutations/verify.js +1 -1
  95. package/dist/component/server/mutations/verify.js.map +1 -1
  96. package/dist/component/server/oauth.js +53 -16
  97. package/dist/component/server/oauth.js.map +1 -1
  98. package/dist/component/server/passkey.js +115 -31
  99. package/dist/component/server/passkey.js.map +1 -1
  100. package/dist/component/server/redirects.js +9 -3
  101. package/dist/component/server/redirects.js.map +1 -1
  102. package/dist/component/server/refresh.js +10 -7
  103. package/dist/component/server/refresh.js.map +1 -1
  104. package/dist/component/server/runtime.d.ts +3 -3
  105. package/dist/component/server/runtime.d.ts.map +1 -1
  106. package/dist/component/server/runtime.js +62 -20
  107. package/dist/component/server/runtime.js.map +1 -1
  108. package/dist/component/server/signin.js +34 -10
  109. package/dist/component/server/signin.js.map +1 -1
  110. package/dist/component/server/totp.js +79 -19
  111. package/dist/component/server/totp.js.map +1 -1
  112. package/dist/component/server/types.d.ts +12 -20
  113. package/dist/component/server/types.d.ts.map +1 -1
  114. package/dist/component/server/types.js.map +1 -1
  115. package/dist/component/server/users.js +6 -3
  116. package/dist/component/server/users.js.map +1 -1
  117. package/dist/component/server/utils.js +10 -4
  118. package/dist/component/server/utils.js.map +1 -1
  119. package/dist/core/types.d.ts +14 -22
  120. package/dist/core/types.d.ts.map +1 -1
  121. package/dist/factors/device.js +8 -9
  122. package/dist/factors/device.js.map +1 -1
  123. package/dist/factors/passkey.js +18 -21
  124. package/dist/factors/passkey.js.map +1 -1
  125. package/dist/providers/password.js +66 -81
  126. package/dist/providers/password.js.map +1 -1
  127. package/dist/runtime/invite.js +2 -8
  128. package/dist/runtime/invite.js.map +1 -1
  129. package/dist/server/auth.d.ts +95 -52
  130. package/dist/server/auth.d.ts.map +1 -1
  131. package/dist/server/auth.js +63 -43
  132. package/dist/server/auth.js.map +1 -1
  133. package/dist/server/core.d.ts +71 -159
  134. package/dist/server/core.d.ts.map +1 -1
  135. package/dist/server/core.js +116 -235
  136. package/dist/server/core.js.map +1 -1
  137. package/dist/server/crypto.d.ts.map +1 -1
  138. package/dist/server/crypto.js +25 -7
  139. package/dist/server/crypto.js.map +1 -1
  140. package/dist/server/device.js +58 -15
  141. package/dist/server/device.js.map +1 -1
  142. package/dist/server/enterprise/domain.d.ts +0 -8
  143. package/dist/server/enterprise/domain.d.ts.map +1 -1
  144. package/dist/server/enterprise/domain.js +148 -59
  145. package/dist/server/enterprise/domain.js.map +1 -1
  146. package/dist/server/enterprise/http.d.ts.map +1 -1
  147. package/dist/server/enterprise/http.js +35 -14
  148. package/dist/server/enterprise/http.js.map +1 -1
  149. package/dist/server/http.d.ts +2 -2
  150. package/dist/server/http.d.ts.map +1 -1
  151. package/dist/server/http.js +25 -20
  152. package/dist/server/http.js.map +1 -1
  153. package/dist/server/identity.js +5 -2
  154. package/dist/server/identity.js.map +1 -1
  155. package/dist/server/index.d.ts +2 -2
  156. package/dist/server/limits.js +21 -30
  157. package/dist/server/limits.js.map +1 -1
  158. package/dist/server/mounts.d.ts +26 -64
  159. package/dist/server/mounts.d.ts.map +1 -1
  160. package/dist/server/mounts.js +45 -106
  161. package/dist/server/mounts.js.map +1 -1
  162. package/dist/server/mutations/account.d.ts +8 -9
  163. package/dist/server/mutations/account.d.ts.map +1 -1
  164. package/dist/server/mutations/account.js +11 -9
  165. package/dist/server/mutations/account.js.map +1 -1
  166. package/dist/server/mutations/code.d.ts +13 -13
  167. package/dist/server/mutations/code.d.ts.map +1 -1
  168. package/dist/server/mutations/code.js +5 -2
  169. package/dist/server/mutations/code.js.map +1 -1
  170. package/dist/server/mutations/invalidate.d.ts +4 -4
  171. package/dist/server/mutations/invalidate.d.ts.map +1 -1
  172. package/dist/server/mutations/invalidate.js.map +1 -1
  173. package/dist/server/mutations/oauth.d.ts +12 -10
  174. package/dist/server/mutations/oauth.d.ts.map +1 -1
  175. package/dist/server/mutations/oauth.js +9 -3
  176. package/dist/server/mutations/oauth.js.map +1 -1
  177. package/dist/server/mutations/refresh.d.ts +3 -3
  178. package/dist/server/mutations/refresh.d.ts.map +1 -1
  179. package/dist/server/mutations/refresh.js +1 -1
  180. package/dist/server/mutations/refresh.js.map +1 -1
  181. package/dist/server/mutations/register.d.ts +11 -11
  182. package/dist/server/mutations/register.d.ts.map +1 -1
  183. package/dist/server/mutations/register.js +45 -41
  184. package/dist/server/mutations/register.js.map +1 -1
  185. package/dist/server/mutations/retrieve.d.ts +6 -6
  186. package/dist/server/mutations/retrieve.d.ts.map +1 -1
  187. package/dist/server/mutations/retrieve.js +20 -24
  188. package/dist/server/mutations/retrieve.js.map +1 -1
  189. package/dist/server/mutations/signature.d.ts +6 -7
  190. package/dist/server/mutations/signature.d.ts.map +1 -1
  191. package/dist/server/mutations/signature.js +9 -3
  192. package/dist/server/mutations/signature.js.map +1 -1
  193. package/dist/server/mutations/signin.d.ts +5 -5
  194. package/dist/server/mutations/signin.d.ts.map +1 -1
  195. package/dist/server/mutations/signout.js.map +1 -1
  196. package/dist/server/mutations/store.d.ts +97 -97
  197. package/dist/server/mutations/store.d.ts.map +1 -1
  198. package/dist/server/mutations/store.js +8 -23
  199. package/dist/server/mutations/store.js.map +1 -1
  200. package/dist/server/mutations/verifier.js.map +1 -1
  201. package/dist/server/mutations/verify.d.ts +10 -10
  202. package/dist/server/mutations/verify.d.ts.map +1 -1
  203. package/dist/server/mutations/verify.js.map +1 -1
  204. package/dist/server/oauth.js +53 -16
  205. package/dist/server/oauth.js.map +1 -1
  206. package/dist/server/passkey.d.ts +2 -2
  207. package/dist/server/passkey.d.ts.map +1 -1
  208. package/dist/server/passkey.js +114 -30
  209. package/dist/server/passkey.js.map +1 -1
  210. package/dist/server/redirects.js +9 -3
  211. package/dist/server/redirects.js.map +1 -1
  212. package/dist/server/refresh.js +10 -7
  213. package/dist/server/refresh.js.map +1 -1
  214. package/dist/server/runtime.d.ts +14 -14
  215. package/dist/server/runtime.d.ts.map +1 -1
  216. package/dist/server/runtime.js +61 -19
  217. package/dist/server/runtime.js.map +1 -1
  218. package/dist/server/signin.js +34 -10
  219. package/dist/server/signin.js.map +1 -1
  220. package/dist/server/ssr.d.ts.map +1 -1
  221. package/dist/server/ssr.js +175 -184
  222. package/dist/server/ssr.js.map +1 -1
  223. package/dist/server/totp.js +78 -18
  224. package/dist/server/totp.js.map +1 -1
  225. package/dist/server/types.d.ts +13 -21
  226. package/dist/server/types.d.ts.map +1 -1
  227. package/dist/server/types.js.map +1 -1
  228. package/dist/server/users.js +6 -3
  229. package/dist/server/users.js.map +1 -1
  230. package/dist/server/utils.js +10 -4
  231. package/dist/server/utils.js.map +1 -1
  232. package/package.json +2 -6
  233. package/src/authorization/index.ts +1 -1
  234. package/src/cli/index.ts +1 -1
  235. package/src/client/core/types.ts +14 -14
  236. package/src/client/factors/device.ts +10 -12
  237. package/src/client/factors/passkey.ts +23 -26
  238. package/src/client/index.ts +54 -64
  239. package/src/client/runtime/invite.ts +5 -7
  240. package/src/component/index.ts +1 -0
  241. package/src/component/public/enterprise/audit.ts +6 -1
  242. package/src/component/public/enterprise/core.ts +1 -0
  243. package/src/component/public/enterprise/domains.ts +5 -1
  244. package/src/component/public/enterprise/scim.ts +1 -0
  245. package/src/component/public/enterprise/secrets.ts +1 -0
  246. package/src/component/public/enterprise/webhooks.ts +1 -0
  247. package/src/component/public/factors/devices.ts +1 -0
  248. package/src/component/public/factors/passkeys.ts +1 -0
  249. package/src/component/public/factors/totp.ts +1 -0
  250. package/src/component/public/groups/core.ts +1 -1
  251. package/src/component/public/groups/invites.ts +7 -1
  252. package/src/component/public/groups/members.ts +1 -0
  253. package/src/component/public/identity/accounts.ts +1 -0
  254. package/src/component/public/identity/codes.ts +1 -0
  255. package/src/component/public/identity/sessions.ts +1 -0
  256. package/src/component/public/identity/tokens.ts +1 -0
  257. package/src/component/public/identity/users.ts +1 -0
  258. package/src/component/public/identity/verifiers.ts +1 -0
  259. package/src/component/public/security/keys.ts +1 -0
  260. package/src/component/public/security/limits.ts +1 -0
  261. package/src/providers/password.ts +89 -110
  262. package/src/server/auth.ts +177 -111
  263. package/src/server/core.ts +197 -233
  264. package/src/server/crypto.ts +31 -29
  265. package/src/server/device.ts +65 -32
  266. package/src/server/enterprise/domain.ts +158 -170
  267. package/src/server/enterprise/http.ts +46 -39
  268. package/src/server/http.ts +36 -30
  269. package/src/server/identity.ts +5 -5
  270. package/src/server/index.ts +2 -0
  271. package/src/server/limits.ts +53 -80
  272. package/src/server/mounts.ts +47 -74
  273. package/src/server/mutations/account.ts +22 -36
  274. package/src/server/mutations/code.ts +6 -6
  275. package/src/server/mutations/invalidate.ts +1 -1
  276. package/src/server/mutations/oauth.ts +14 -8
  277. package/src/server/mutations/refresh.ts +5 -4
  278. package/src/server/mutations/register.ts +87 -132
  279. package/src/server/mutations/retrieve.ts +44 -44
  280. package/src/server/mutations/signature.ts +13 -6
  281. package/src/server/mutations/signout.ts +1 -1
  282. package/src/server/mutations/store.ts +16 -31
  283. package/src/server/mutations/verifier.ts +1 -1
  284. package/src/server/mutations/verify.ts +3 -5
  285. package/src/server/oauth.ts +60 -69
  286. package/src/server/passkey.ts +567 -517
  287. package/src/server/redirects.ts +10 -6
  288. package/src/server/refresh.ts +14 -18
  289. package/src/server/runtime.ts +70 -55
  290. package/src/server/signin.ts +44 -37
  291. package/src/server/ssr.ts +390 -407
  292. package/src/server/totp.ts +85 -35
  293. package/src/server/types.ts +19 -22
  294. package/src/server/users.ts +7 -6
  295. package/src/server/utils.ts +10 -12
  296. package/dist/component/server/authError.js +0 -34
  297. package/dist/component/server/authError.js.map +0 -1
  298. package/dist/component/server/errors.d.ts +0 -1
  299. package/dist/component/server/errors.js +0 -137
  300. package/dist/component/server/errors.js.map +0 -1
  301. package/dist/server/authError.d.ts +0 -46
  302. package/dist/server/authError.d.ts.map +0 -1
  303. package/dist/server/authError.js +0 -34
  304. package/dist/server/authError.js.map +0 -1
  305. package/dist/server/errors.d.ts +0 -177
  306. package/dist/server/errors.d.ts.map +0 -1
  307. package/dist/server/errors.js +0 -212
  308. package/dist/server/errors.js.map +0 -1
  309. package/src/server/authError.ts +0 -44
  310. package/src/server/errors.ts +0 -290
@@ -10,10 +10,10 @@
10
10
  import { encodeBase32LowerCaseNoPadding } from "@oslojs/encoding";
11
11
  import { verifyTOTPWithGracePeriod, createTOTPKeyURI } from "@oslojs/otp";
12
12
  import type { Fx as FxType } from "@robelest/fx";
13
-
14
13
  import { Fx } from "@robelest/fx";
14
+ import { Cv } from "@robelest/fx/convex";
15
+ import type { ConvexError } from "convex/values";
15
16
 
16
- import { AuthError } from "./authError";
17
17
  import { userIdFromIdentitySubject } from "./identity";
18
18
  import { callSignIn, callVerifier } from "./mutations/index";
19
19
  import { callVerifierSignature } from "./mutations/signature";
@@ -70,43 +70,48 @@ type TotpDispatch =
70
70
 
71
71
  const resolveTotpFlowFx = (
72
72
  params: Record<string, unknown>,
73
- ): FxType<TotpFlow, AuthError> => {
73
+ ): FxType<TotpFlow, ConvexError<any>> => {
74
74
  const flow = params.flow;
75
75
  return typeof flow === "string" && TOTP_FLOWS.includes(flow as never)
76
76
  ? Fx.succeed(flow as TotpFlow)
77
- : Fx.fail(
78
- new AuthError(
79
- "TOTP_MISSING_FLOW",
77
+ : Cv.fail({
78
+ code: "TOTP_MISSING_FLOW",
79
+ message:
80
80
  "Missing `flow` parameter. Expected one of: setup, confirm, verify",
81
- ),
82
- );
81
+ });
83
82
  };
84
83
 
85
84
  const requireTotpVerifierFx = (
86
85
  verifier: string | undefined,
87
- ): FxType<string, AuthError> =>
86
+ ): FxType<string, ConvexError<any>> =>
88
87
  verifier != null
89
88
  ? Fx.succeed(verifier)
90
- : Fx.fail(new AuthError("TOTP_MISSING_VERIFIER"));
89
+ : Cv.fail({
90
+ code: "TOTP_MISSING_VERIFIER",
91
+ message: "Missing verifier for TOTP operation.",
92
+ });
91
93
 
92
94
  const requireTotpCodeFx = (
93
95
  params: Record<string, unknown>,
94
- ): FxType<string, AuthError> =>
96
+ ): FxType<string, ConvexError<any>> =>
95
97
  typeof params.code === "string"
96
98
  ? Fx.succeed(params.code)
97
- : Fx.fail(new AuthError("TOTP_MISSING_CODE"));
99
+ : Cv.fail({ code: "TOTP_MISSING_CODE", message: "Missing TOTP code." });
98
100
 
99
101
  const requireTotpIdFx = (
100
102
  params: Record<string, unknown>,
101
- ): FxType<string, AuthError> =>
103
+ ): FxType<string, ConvexError<any>> =>
102
104
  typeof params.totpId === "string"
103
105
  ? Fx.succeed(params.totpId)
104
- : Fx.fail(new AuthError("TOTP_MISSING_ID"));
106
+ : Cv.fail({
107
+ code: "TOTP_MISSING_ID",
108
+ message: "Missing TOTP enrollment ID.",
109
+ });
105
110
 
106
111
  const resolveTotpDispatchFx = (
107
112
  params: Record<string, unknown>,
108
113
  verifier: string | undefined,
109
- ): FxType<TotpDispatch, AuthError> =>
114
+ ): FxType<TotpDispatch, ConvexError<any>> =>
110
115
  resolveTotpFlowFx(params).pipe(
111
116
  Fx.chain((flow) =>
112
117
  Fx.match({ flow }).on("flow", {
@@ -142,7 +147,7 @@ export const handleTotp = (
142
147
  ctx: EnrichedActionCtx,
143
148
  provider: TotpProviderConfig,
144
149
  args: { params?: Record<string, any>; verifier?: string },
145
- ): FxType<TotpResult, AuthError> => {
150
+ ): FxType<TotpResult, ConvexError<any>> => {
146
151
  const params = (args.params ?? {}) as Record<string, unknown>;
147
152
 
148
153
  return resolveTotpDispatchFx(params, args.verifier).pipe(
@@ -151,11 +156,16 @@ export const handleTotp = (
151
156
  setup: ({ params }) =>
152
157
  Fx.from({
153
158
  ok: () => ctx.auth.getUserIdentity(),
154
- err: (e) => new AuthError("INTERNAL_ERROR", String(e)),
159
+ err: (e) =>
160
+ Cv.error({ code: "INTERNAL_ERROR", message: String(e) }),
155
161
  }).pipe(
156
162
  Fx.chain((identity) =>
157
163
  identity === null
158
- ? Fx.fail(new AuthError("TOTP_AUTH_REQUIRED"))
164
+ ? Cv.fail({
165
+ code: "TOTP_AUTH_REQUIRED",
166
+ message:
167
+ "Sign in first, then set up two-factor authentication.",
168
+ })
159
169
  : Fx.succeed(userIdFromIdentitySubject(identity.subject)),
160
170
  ),
161
171
  Fx.chain((userId) =>
@@ -213,37 +223,52 @@ export const handleTotp = (
213
223
  };
214
224
  },
215
225
  err: (e) =>
216
- new AuthError(
217
- "INTERNAL_ERROR",
218
- `TOTP setup failed: ${String(e)}`,
219
- ),
226
+ Cv.error({
227
+ code: "INTERNAL_ERROR",
228
+ message: `TOTP setup failed: ${String(e)}`,
229
+ }),
220
230
  }),
221
231
  ),
222
232
  ),
223
233
  confirm: ({ code, totpId, verifier }) =>
224
234
  Fx.from({
225
235
  ok: () => ctx.auth.getUserIdentity(),
226
- err: (e) => new AuthError("INTERNAL_ERROR", String(e)),
236
+ err: (e) =>
237
+ Cv.error({ code: "INTERNAL_ERROR", message: String(e) }),
227
238
  }).pipe(
228
239
  Fx.chain((identity) =>
229
240
  identity === null
230
- ? Fx.fail(new AuthError("TOTP_AUTH_REQUIRED"))
241
+ ? Cv.fail({
242
+ code: "TOTP_AUTH_REQUIRED",
243
+ message:
244
+ "Sign in first, then set up two-factor authentication.",
245
+ })
231
246
  : Fx.succeed(userIdFromIdentitySubject(identity.subject)),
232
247
  ),
233
248
  Fx.chain((userId) =>
234
249
  Fx.from({
235
250
  ok: () => queryTotpById(ctx, totpId),
236
- err: () => new AuthError("TOTP_NOT_FOUND"),
251
+ err: () =>
252
+ Cv.error({
253
+ code: "TOTP_NOT_FOUND",
254
+ message: "TOTP enrollment not found.",
255
+ }),
237
256
  })
238
257
  .pipe(
239
258
  Fx.chain((doc) =>
240
259
  doc === null
241
- ? Fx.fail(new AuthError("TOTP_NOT_FOUND"))
260
+ ? Cv.fail({
261
+ code: "TOTP_NOT_FOUND",
262
+ message: "TOTP enrollment not found.",
263
+ })
242
264
  : Fx.succeed(doc),
243
265
  ),
244
266
  Fx.chain((totpDoc) =>
245
267
  totpDoc.verified
246
- ? Fx.fail(new AuthError("TOTP_ALREADY_VERIFIED"))
268
+ ? Cv.fail({
269
+ code: "TOTP_ALREADY_VERIFIED",
270
+ message: "TOTP enrollment is already verified.",
271
+ })
247
272
  : Fx.succeed(totpDoc),
248
273
  ),
249
274
  )
@@ -257,7 +282,10 @@ export const handleTotp = (
257
282
  30,
258
283
  )
259
284
  ? Fx.succeed(totpDoc)
260
- : Fx.fail(new AuthError("TOTP_INVALID_CODE")),
285
+ : Cv.fail({
286
+ code: "TOTP_INVALID_CODE",
287
+ message: "Invalid TOTP code.",
288
+ }),
261
289
  ),
262
290
  )
263
291
  .pipe(
@@ -271,7 +299,11 @@ export const handleTotp = (
271
299
  generateTokens: true,
272
300
  });
273
301
  },
274
- err: (e) => new AuthError("INTERNAL_ERROR", String(e)),
302
+ err: (e) =>
303
+ Cv.error({
304
+ code: "INTERNAL_ERROR",
305
+ message: String(e),
306
+ }),
275
307
  }),
276
308
  ),
277
309
  )
@@ -286,11 +318,18 @@ export const handleTotp = (
286
318
  verify: ({ code, verifier }) =>
287
319
  Fx.from({
288
320
  ok: () => queryVerifierById(ctx, verifier),
289
- err: () => new AuthError("TOTP_INVALID_VERIFIER"),
321
+ err: () =>
322
+ Cv.error({
323
+ code: "TOTP_INVALID_VERIFIER",
324
+ message: "Invalid or expired TOTP verifier.",
325
+ }),
290
326
  }).pipe(
291
327
  Fx.chain((doc) =>
292
328
  doc === null
293
- ? Fx.fail(new AuthError("TOTP_INVALID_VERIFIER"))
329
+ ? Cv.fail({
330
+ code: "TOTP_INVALID_VERIFIER",
331
+ message: "Invalid or expired TOTP verifier.",
332
+ })
294
333
  : Fx.succeed(doc),
295
334
  ),
296
335
  Fx.map((doc) => {
@@ -300,11 +339,18 @@ export const handleTotp = (
300
339
  Fx.chain(({ userId, code, verifier }) =>
301
340
  Fx.from({
302
341
  ok: () => queryTotpVerifiedByUserId(ctx, userId),
303
- err: () => new AuthError("TOTP_NO_ENROLLMENT"),
342
+ err: () =>
343
+ Cv.error({
344
+ code: "TOTP_NO_ENROLLMENT",
345
+ message: "No verified TOTP enrollment found.",
346
+ }),
304
347
  }).pipe(
305
348
  Fx.chain((totpDoc) =>
306
349
  totpDoc === null
307
- ? Fx.fail(new AuthError("TOTP_NO_ENROLLMENT"))
350
+ ? Cv.fail({
351
+ code: "TOTP_NO_ENROLLMENT",
352
+ message: "No verified TOTP enrollment found.",
353
+ })
308
354
  : Fx.succeed(totpDoc),
309
355
  ),
310
356
  Fx.chain((totpDoc) =>
@@ -316,7 +362,10 @@ export const handleTotp = (
316
362
  30,
317
363
  )
318
364
  ? Fx.succeed(totpDoc)
319
- : Fx.fail(new AuthError("TOTP_INVALID_CODE")),
365
+ : Cv.fail({
366
+ code: "TOTP_INVALID_CODE",
367
+ message: "Invalid TOTP code.",
368
+ }),
320
369
  ),
321
370
  Fx.chain((totpDoc) =>
322
371
  Fx.from({
@@ -329,7 +378,8 @@ export const handleTotp = (
329
378
  await mutateVerifierDelete(ctx, verifier);
330
379
  return callSignIn(ctx, { userId, generateTokens: true });
331
380
  },
332
- err: (e) => new AuthError("INTERNAL_ERROR", String(e)),
381
+ err: (e) =>
382
+ Cv.error({ code: "INTERNAL_ERROR", message: String(e) }),
333
383
  }),
334
384
  ),
335
385
  Fx.map((signInResult) => ({
@@ -795,30 +795,25 @@ export type AuthProviderSignInResult = {
795
795
  sessionId: GenericId<"Session">;
796
796
  } | null;
797
797
 
798
- /** Arguments for `auth.member.resolve()`. */
799
- export type AuthMemberResolveArgs = {
798
+ /** Arguments for `auth.member.inspect()`. */
799
+ export type AuthMemberInspectArgs = {
800
800
  userId: GenericId<"User">;
801
801
  groupId: GenericId<"Group">;
802
802
  ancestry?: boolean;
803
- roleIds?: string[];
804
- grants?: string[];
805
803
  maxDepth?: number;
806
804
  };
807
805
 
808
- /** Result of `auth.member.resolve()` — membership check with role and grant details. */
809
- export type AuthMemberResolveResult = {
810
- ok: boolean;
806
+ /** Result of `auth.member.inspect()` — membership state and derived access details. */
807
+ export type AuthMemberInspectResult = {
811
808
  membership: GenericDoc<GenericDataModel, "GroupMember"> | null;
812
- matchedGroupId: GenericId<"Group"> | null;
813
809
  roleIds: string[];
814
810
  grants: string[];
815
- missingGrants: string[];
816
- depth: number | null;
817
- isDirect: boolean;
818
- isInherited: boolean;
819
- traversedGroupIds: GenericId<"Group">[];
820
- code?: "INVALID_ROLE_IDS";
821
- invalidRoleIds?: string[];
811
+ };
812
+
813
+ /** Arguments for `auth.member.require()`. */
814
+ export type AuthMemberRequireArgs = AuthMemberInspectArgs & {
815
+ roleIds?: string[];
816
+ grants?: string[];
822
817
  };
823
818
 
824
819
  /**
@@ -846,7 +841,6 @@ export type AuthServerHelpers = {
846
841
  ctx: GenericActionCtx<any>,
847
842
  args: AuthCreateAccountArgs,
848
843
  ) => Promise<{
849
- ok: true;
850
844
  account: GenericDoc<GenericDataModel, "Account">;
851
845
  user: GenericDoc<GenericDataModel, "User">;
852
846
  }>;
@@ -860,7 +854,7 @@ export type AuthServerHelpers = {
860
854
  update: (
861
855
  ctx: GenericActionCtx<any>,
862
856
  args: AuthUpdateAccountArgs,
863
- ) => Promise<{ ok: true; accountId: GenericId<"Account"> }>;
857
+ ) => Promise<{ accountId: GenericId<"Account"> }>;
864
858
  };
865
859
  session: {
866
860
  current: (ctx: {
@@ -870,16 +864,19 @@ export type AuthServerHelpers = {
870
864
  ctx: GenericActionCtx<any>,
871
865
  args: AuthInvalidateSessionsArgs,
872
866
  ) => Promise<{
873
- ok: true;
874
867
  userId: GenericId<"User">;
875
868
  except: GenericId<"Session">[];
876
869
  }>;
877
870
  };
878
871
  member: {
879
- resolve: (
872
+ inspect: (
873
+ ctx: GenericActionCtx<any>,
874
+ args: AuthMemberInspectArgs,
875
+ ) => Promise<AuthMemberInspectResult>;
876
+ require: (
880
877
  ctx: GenericActionCtx<any>,
881
- args: AuthMemberResolveArgs,
882
- ) => Promise<AuthMemberResolveResult>;
878
+ args: AuthMemberRequireArgs,
879
+ ) => Promise<AuthMemberInspectResult>;
883
880
  };
884
881
  provider: {
885
882
  signIn: (
@@ -939,7 +936,7 @@ export interface SAMLAttributeMapping {
939
936
  * Materialized OAuth provider config (Arctic-based).
940
937
  *
941
938
  * Carries the Arctic provider instance along with scopes and profile config.
942
- * Produced by materializing an `OAuthProviderInstance` during `configDefaults`.
939
+ * Produced by materializing an `OAuthProviderInstance` during `configDefaults`.
943
940
  */
944
941
  export interface OAuthMaterializedConfig {
945
942
  /**
@@ -1,8 +1,8 @@
1
1
  import { Fx } from "@robelest/fx";
2
+ import { Cv } from "@robelest/fx/convex";
2
3
  import { GenericId } from "convex/values";
3
4
 
4
5
  import { authDb } from "./db";
5
- import { AuthError } from "./authError";
6
6
  import { Doc, MutationCtx } from "./types";
7
7
  import { AuthProviderMaterializedConfig, ConvexAuthConfig } from "./types";
8
8
  import { LOG_LEVELS, logWithLevel } from "./utils";
@@ -188,14 +188,15 @@ async function defaultCreateOrUpdateUser(
188
188
  Fx.from({
189
189
  ok: () => db.users.patch(userId!, userData),
190
190
  err: (error) =>
191
- new AuthError(
192
- "USER_UPDATE_FAILED",
193
- `Could not update user document with ID \`${userId}\`, ` +
191
+ Cv.error({
192
+ code: "USER_UPDATE_FAILED",
193
+ message:
194
+ `Could not update user document with ID \`${userId}\`, ` +
194
195
  `either the user has been deleted but their account has not, ` +
195
196
  `or the profile data doesn't match the \`users\` table schema: ` +
196
197
  `${(error as Error).message}`,
197
- ),
198
- }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),
198
+ }),
199
+ }).pipe(Fx.recover((e) => Fx.fatal(e))),
199
200
  );
200
201
  } else {
201
202
  userId = (await db.users.insert(userData)) as GenericId<"User">;
@@ -8,24 +8,22 @@ import {
8
8
  encodeBase64urlNoPadding,
9
9
  encodeHexLowerCase,
10
10
  } from "@oslojs/encoding";
11
-
12
- import { AuthError } from "./authError";
11
+ import { Cv } from "@robelest/fx/convex";
13
12
 
14
13
  /**
15
14
  * Require an environment variable to be set, throwing at config time if missing.
16
15
  *
17
- * Uses `AuthError.toConvexError()` directly since this is a synchronous guard
16
+ * Uses `Cv.error()` directly since this is a synchronous guard
18
17
  * called inline in many expressions — not suitable for Fx pipeline wrapping.
19
18
  */
20
19
  /** @internal */
21
20
  export function requireEnv(name: string) {
22
21
  const value = process.env[name];
23
22
  if (value === undefined) {
24
- throw new AuthError(
25
- "MISSING_ENV_VAR",
26
- `Missing environment variable \`${name}\``,
27
- { variable: name },
28
- ).toConvexError();
23
+ throw Cv.error({
24
+ code: "MISSING_ENV_VAR",
25
+ message: `Missing environment variable \`${name}\``,
26
+ });
29
27
  }
30
28
  return value;
31
29
  }
@@ -183,10 +181,10 @@ export async function encryptSecret(value: string) {
183
181
  export async function decryptSecret(ciphertext: string) {
184
182
  const [ivEncoded, payloadEncoded] = ciphertext.split(".");
185
183
  if (!ivEncoded || !payloadEncoded) {
186
- throw new AuthError(
187
- "INVALID_PARAMETERS",
188
- "Stored enterprise secret is malformed.",
189
- ).toConvexError();
184
+ throw Cv.error({
185
+ code: "INVALID_PARAMETERS",
186
+ message: "Stored enterprise secret is malformed.",
187
+ });
190
188
  }
191
189
  const key = await getSecretCryptoKey();
192
190
  const decrypted = await crypto.subtle.decrypt(
@@ -1,34 +0,0 @@
1
- import { AUTH_ERRORS } from "./errors.js";
2
- import { Cv } from "@robelest/fx/convex";
3
-
4
- //#region src/server/authError.ts
5
- /**
6
- * Typed error for the Fx error channel.
7
- *
8
- * Use with `Fx.fail(new AuthError("CODE"))` in pipelines.
9
- * At Convex boundaries, {@link toConvexError} converts these to `ConvexError`.
10
- */
11
- var AuthError = class extends Error {
12
- /**
13
- * Discriminant tag for error channel matching.
14
- * @readonly
15
- */
16
- _tag = "AuthError";
17
- constructor(code, message, context) {
18
- super(message ?? AUTH_ERRORS[code]);
19
- this.code = code;
20
- this.context = context;
21
- }
22
- /** Convert to the `ConvexError` shape the Convex runtime expects. */
23
- toConvexError() {
24
- return Cv.error({
25
- code: this.code,
26
- message: this.message,
27
- ...this.context
28
- });
29
- }
30
- };
31
-
32
- //#endregion
33
- export { AuthError };
34
- //# sourceMappingURL=authError.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"authError.js","names":[],"sources":["../../../src/server/authError.ts"],"sourcesContent":["import { Cv } from \"@robelest/fx/convex\";\nimport type { ConvexError } from \"convex/values\";\n\nimport { AUTH_ERRORS } from \"./errors\";\nimport type { AuthErrorCode } from \"./errors\";\n\n/**\n * Typed error for the Fx error channel.\n *\n * Use with `Fx.fail(new AuthError(\"CODE\"))` in pipelines.\n * At Convex boundaries, {@link toConvexError} converts these to `ConvexError`.\n */\nexport class AuthError extends Error {\n /**\n * Discriminant tag for error channel matching.\n * @readonly\n */\n readonly _tag = \"AuthError\" as const;\n\n constructor(\n /**\n * Machine-readable error code.\n * @readonly\n */\n readonly code: AuthErrorCode,\n message?: string,\n /**\n * Optional structured context for diagnostics.\n * @readonly\n */\n readonly context?: Record<string, unknown>,\n ) {\n super(message ?? AUTH_ERRORS[code]);\n }\n\n /** Convert to the `ConvexError` shape the Convex runtime expects. */\n toConvexError(): ConvexError<{ code: AuthErrorCode; message: string }> {\n return Cv.error({\n code: this.code,\n message: this.message,\n ...this.context,\n });\n }\n}\n"],"mappings":";;;;;;;;;;AAYA,IAAa,YAAb,cAA+B,MAAM;;;;;CAKnC,AAAS,OAAO;CAEhB,YAKE,AAAS,MACT,SAKA,AAAS,SACT;AACA,QAAM,WAAW,YAAY,MAAM;EAR1B;EAMA;;;CAMX,gBAAuE;AACrE,SAAO,GAAG,MAAM;GACd,MAAM,KAAK;GACX,SAAS,KAAK;GACd,GAAG,KAAK;GACT,CAAC"}
@@ -1 +0,0 @@
1
- import { ConvexError } from "convex/values";
@@ -1,137 +0,0 @@
1
- import { ConvexError } from "convex/values";
2
-
3
- //#region src/server/errors.ts
4
- /**
5
- * Structured error handling for Convex Auth.
6
- *
7
- * Every error thrown by the auth system uses `ConvexError` with a
8
- * `{ code, message }` payload so clients can distinguish error types
9
- * and display user-friendly messages.
10
- *
11
- * **Consumer API:** Use {@link throwAuthError} to throw structured errors
12
- * from your own Convex functions (e.g. custom authorization checks).
13
- *
14
- * **Internal pattern:** The library itself uses `new AuthError(code)` with
15
- * the `@robelest/fx` effect system (`Fx.fail(new AuthError(code))`).
16
- * You do not need to use `AuthError` directly — it is an implementation detail.
17
- *
18
- * @module
19
- */
20
- /**
21
- * Map of every auth error code to its default human-readable message.
22
- *
23
- * Use the keys as the `code` argument to {@link throwAuthError}.
24
- * Clients can match on these codes for conditional error handling.
25
- *
26
- * @example
27
- * ```ts
28
- * throwAuthError("NOT_SIGNED_IN");
29
- * // ConvexError { data: { code: "NOT_SIGNED_IN", message: "You must be signed in..." } }
30
- * ```
31
- */
32
- const AUTH_ERRORS = {
33
- PROVIDER_NOT_CONFIGURED: "This sign-in method is not available.",
34
- EMAIL_CONFIG_REQUIRED: "Email transport is not configured. Configure email in createAuth(...).",
35
- MISSING_ENV_VAR: "A required server environment variable is missing.",
36
- MISSING_ACTION_CONTEXT: "Action context is required for this operation.",
37
- INVALID_PARAMETERS: "The provided parameters are invalid.",
38
- NOT_SIGNED_IN: "You must be signed in to perform this action.",
39
- INVALID_VERIFICATION_CODE: "Invalid or expired verification code.",
40
- INVALID_REFRESH_TOKEN: "Your session has expired. Please sign in again.",
41
- AUTH_HANDSHAKE_TIMEOUT: "Sign-in succeeded but authentication confirmation timed out.",
42
- AUTH_HANDSHAKE_REJECTED: "Authentication was rejected while confirming the session.",
43
- SIGN_IN_MISSING_PARAMS: "Cannot sign in: missing provider, code, or refresh token.",
44
- UNSUPPORTED_PROVIDER_TYPE: "This provider type is not supported.",
45
- INVALID_REDIRECT: "Invalid redirect URL.",
46
- EMAIL_SEND_FAILED: "Failed to send verification email. Please try again.",
47
- INVALID_API_KEY: "Invalid API key.",
48
- API_KEY_REVOKED: "This API key has been revoked.",
49
- API_KEY_EXPIRED: "This API key has expired.",
50
- API_KEY_RATE_LIMITED: "API key rate limit exceeded. Please try again later.",
51
- API_KEY_INVALID_SCOPE: "Invalid scope requested for API key.",
52
- KEY_NOT_FOUND: "API key not found.",
53
- MISSING_BEARER_TOKEN: "Missing or malformed Authorization: Bearer header.",
54
- SCOPE_CHECK_FAILED: "This API key does not have the required permissions.",
55
- OAUTH_MISSING_PROVIDER: "Missing OAuth provider ID.",
56
- OAUTH_MISSING_VERIFIER: "Missing sign-in verifier.",
57
- OAUTH_INVALID_STATE: "Invalid OAuth state. Please try signing in again.",
58
- OAUTH_PROVIDER_ERROR: "The sign-in provider returned an error.",
59
- OAUTH_MISSING_ID_TOKEN: "ID token claims are missing from the provider response.",
60
- OAUTH_INVALID_PROFILE: "The sign-in provider returned an invalid profile.",
61
- OAUTH_UNSUPPORTED_AUTH_METHOD: "Unsupported OAuth client authentication method.",
62
- OAUTH_NO_USERINFO: "No userinfo endpoint configured for this provider.",
63
- ACCOUNT_ALREADY_EXISTS: "An account with these credentials already exists.",
64
- ACCOUNT_NOT_FOUND: "Account not found.",
65
- INVALID_CREDENTIALS_PROVIDER: "This provider does not support credential operations.",
66
- MISSING_CRYPTO_FUNCTION: "This provider is missing a required cryptographic function.",
67
- USER_UPDATE_FAILED: "Could not update the user record.",
68
- INVALID_VERIFIER: "Invalid or expired verifier.",
69
- PASSKEY_MISSING_CONFIG: "Passkey provider requires SITE_URL or explicit rpId configuration.",
70
- PASSKEY_AUTH_REQUIRED: "Sign in first, then add a passkey to your account.",
71
- PASSKEY_MISSING_VERIFIER: "Missing verifier for passkey operation.",
72
- PASSKEY_INVALID_CLIENT_DATA: "Invalid passkey client data.",
73
- PASSKEY_INVALID_ORIGIN: "Passkey origin does not match the expected value.",
74
- PASSKEY_INVALID_CHALLENGE: "Invalid or expired passkey challenge.",
75
- PASSKEY_RP_MISMATCH: "Relying party ID mismatch.",
76
- PASSKEY_USER_PRESENCE: "User presence flag not set.",
77
- PASSKEY_USER_VERIFICATION: "User verification required but not performed.",
78
- PASSKEY_NO_CREDENTIAL: "No credential in attestation.",
79
- PASSKEY_UNSUPPORTED_ALGORITHM: "Unsupported passkey algorithm.",
80
- PASSKEY_INVALID_SIGNATURE: "Invalid passkey signature.",
81
- PASSKEY_UNKNOWN_CREDENTIAL: "Unknown passkey credential.",
82
- PASSKEY_COUNTER_ERROR: "Authenticator counter did not increase — possible credential cloning detected.",
83
- PASSKEY_MISSING_FLOW: "Missing passkey flow parameter.",
84
- PASSKEY_UNKNOWN_FLOW: "Unknown passkey flow.",
85
- TOTP_AUTH_REQUIRED: "Sign in first, then set up two-factor authentication.",
86
- TOTP_MISSING_VERIFIER: "Missing verifier for TOTP operation.",
87
- TOTP_MISSING_CODE: "Missing TOTP code.",
88
- TOTP_MISSING_ID: "Missing TOTP enrollment ID.",
89
- TOTP_NOT_FOUND: "TOTP enrollment not found.",
90
- TOTP_ALREADY_VERIFIED: "TOTP enrollment is already verified.",
91
- TOTP_INVALID_CODE: "Invalid TOTP code.",
92
- TOTP_INVALID_VERIFIER: "Invalid or expired TOTP verifier.",
93
- TOTP_NO_ENROLLMENT: "No verified TOTP enrollment found.",
94
- TOTP_MISSING_FLOW: "Missing TOTP flow parameter.",
95
- TOTP_UNKNOWN_FLOW: "Unknown TOTP flow.",
96
- DEVICE_CODE_EXPIRED: "The device code has expired. Please start a new authorization request.",
97
- DEVICE_CODE_DENIED: "The authorization request was denied.",
98
- DEVICE_AUTHORIZATION_PENDING: "The user has not yet authorized this device.",
99
- DEVICE_SLOW_DOWN: "Polling too frequently. Increase the interval between requests.",
100
- DEVICE_INVALID_USER_CODE: "Invalid or expired user code.",
101
- DEVICE_ALREADY_AUTHORIZED: "This device code has already been authorized.",
102
- DEVICE_MISSING_FLOW: "Missing device flow parameter.",
103
- DEVICE_UNKNOWN_FLOW: "Unknown device flow.",
104
- INVITE_EXPIRED: "This invitation has expired.",
105
- INVITE_EMAIL_MISMATCH: "This invitation is for a different email.",
106
- INVITE_ALREADY_ACCEPTED: "This invitation has already been accepted.",
107
- DUPLICATE_INVITE: "A pending invite already exists for this email in this group.",
108
- INVITE_NOT_FOUND: "Invite not found.",
109
- INVITE_NOT_PENDING: "Cannot accept or revoke invite that is not pending.",
110
- FORBIDDEN: "Access denied.",
111
- NO_ACTIVE_GROUP: "User has no active group set.",
112
- DUPLICATE_MEMBERSHIP: "User is already a member of this group.",
113
- ENTERPRISE_ALREADY_EXISTS: "An enterprise record already exists for this group.",
114
- ENTERPRISE_DOMAIN_TAKEN: "That domain is already attached to another enterprise.",
115
- INTERNAL_ERROR: "An unexpected error occurred."
116
- };
117
- /**
118
- * Type guard: check whether a caught value is a structured auth `ConvexError`.
119
- *
120
- * @param error - The caught value (typically from a `catch` block).
121
- * @returns `true` when `error` is a `ConvexError` with `{ code, message }` data.
122
- *
123
- * @example
124
- * ```ts
125
- * try { await auth.signIn('email', { email }); }
126
- * catch (e) {
127
- * if (isAuthError(e)) console.log(e.data.code); // "EMAIL_SEND_FAILED"
128
- * }
129
- * ```
130
- */
131
- function isAuthError(error) {
132
- return error instanceof ConvexError && typeof error.data === "object" && error.data !== null && "code" in error.data && "message" in error.data;
133
- }
134
-
135
- //#endregion
136
- export { AUTH_ERRORS, isAuthError };
137
- //# sourceMappingURL=errors.js.map
@@ -1 +0,0 @@
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"}