@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
@@ -1,9 +1,10 @@
1
- import { AuthError } from "./authError.js";
2
1
  import { generateRandomString, requireEnv, sha256 } from "./utils.js";
3
2
  import { userIdFromIdentitySubject } from "./identity.js";
4
3
  import { callSignIn } from "./mutations/signin.js";
5
4
  import { mutateDeviceAuthorize, mutateDeviceDelete, mutateDeviceInsert, mutateDeviceUpdateLastPolled, queryDeviceByCodeHash, queryDeviceByUserCode } from "./types.js";
5
+ import { Cv } from "@robelest/fx/convex";
6
6
  import { Fx } from "@robelest/fx";
7
+ import { ConvexError } from "convex/values";
7
8
 
8
9
  //#region src/server/device.ts
9
10
  /**
@@ -29,7 +30,10 @@ const handleDevice = (ctx, provider, args) => Fx.from({
29
30
  ok: async () => {
30
31
  const params = args.params ?? {};
31
32
  const flow = typeof params.flow === "string" ? params.flow : "create";
32
- if (!DEVICE_FLOWS.some((candidate) => candidate === flow)) throw new AuthError("DEVICE_MISSING_FLOW", "Missing `flow` parameter. Expected one of: create, poll, verify");
33
+ if (!DEVICE_FLOWS.some((candidate) => candidate === flow)) throw Cv.error({
34
+ code: "DEVICE_MISSING_FLOW",
35
+ message: "Missing `flow` parameter. Expected one of: create, poll, verify"
36
+ });
33
37
  if (flow === "create") {
34
38
  const deviceCode = generateRandomString(DEVICE_CODE_LENGTH, DEVICE_CODE_ALPHABET);
35
39
  const deviceCodeHash = await sha256(deviceCode);
@@ -55,21 +59,42 @@ const handleDevice = (ctx, provider, args) => Fx.from({
55
59
  };
56
60
  }
57
61
  if (flow === "poll") {
58
- if (typeof params.deviceCode !== "string") throw new AuthError("DEVICE_MISSING_FLOW", "Missing `deviceCode` parameter for poll flow.");
62
+ if (typeof params.deviceCode !== "string") throw Cv.error({
63
+ code: "DEVICE_MISSING_FLOW",
64
+ message: "Missing `deviceCode` parameter for poll flow."
65
+ });
59
66
  const doc$1 = await queryDeviceByCodeHash(ctx, await sha256(params.deviceCode));
60
- if (doc$1 === null) throw new AuthError("DEVICE_CODE_EXPIRED");
67
+ if (doc$1 === null) throw Cv.error({
68
+ code: "DEVICE_CODE_EXPIRED",
69
+ message: "The device code has expired. Please start a new authorization request."
70
+ });
61
71
  if (Date.now() > doc$1.expiresAt) {
62
72
  await mutateDeviceDelete(ctx, doc$1._id);
63
- throw new AuthError("DEVICE_CODE_EXPIRED");
73
+ throw Cv.error({
74
+ code: "DEVICE_CODE_EXPIRED",
75
+ message: "The device code has expired. Please start a new authorization request."
76
+ });
64
77
  }
65
- if (doc$1.lastPolledAt !== void 0 && (Date.now() - doc$1.lastPolledAt) / 1e3 < doc$1.interval) throw new AuthError("DEVICE_SLOW_DOWN");
78
+ if (doc$1.lastPolledAt !== void 0 && (Date.now() - doc$1.lastPolledAt) / 1e3 < doc$1.interval) throw Cv.error({
79
+ code: "DEVICE_SLOW_DOWN",
80
+ message: "Polling too frequently. Increase the interval between requests."
81
+ });
66
82
  await mutateDeviceUpdateLastPolled(ctx, doc$1._id, Date.now());
67
- if (doc$1.status === "pending") throw new AuthError("DEVICE_AUTHORIZATION_PENDING");
83
+ if (doc$1.status === "pending") throw Cv.error({
84
+ code: "DEVICE_AUTHORIZATION_PENDING",
85
+ message: "The user has not yet authorized this device."
86
+ });
68
87
  if (doc$1.status === "denied") {
69
88
  await mutateDeviceDelete(ctx, doc$1._id);
70
- throw new AuthError("DEVICE_CODE_DENIED");
89
+ throw Cv.error({
90
+ code: "DEVICE_CODE_DENIED",
91
+ message: "The authorization request was denied."
92
+ });
71
93
  }
72
- if (!doc$1.userId || !doc$1.sessionId) throw new AuthError("INTERNAL_ERROR", "Authorized device code missing userId or sessionId");
94
+ if (!doc$1.userId || !doc$1.sessionId) throw Cv.error({
95
+ code: "INTERNAL_ERROR",
96
+ message: "Authorized device code missing userId or sessionId"
97
+ });
73
98
  await mutateDeviceDelete(ctx, doc$1._id);
74
99
  return {
75
100
  kind: "signedIn",
@@ -80,17 +105,32 @@ const handleDevice = (ctx, provider, args) => Fx.from({
80
105
  })
81
106
  };
82
107
  }
83
- if (typeof params.userCode !== "string") throw new AuthError("DEVICE_INVALID_USER_CODE", "Missing `userCode` parameter for verify flow.");
108
+ if (typeof params.userCode !== "string") throw Cv.error({
109
+ code: "DEVICE_INVALID_USER_CODE",
110
+ message: "Missing `userCode` parameter for verify flow."
111
+ });
84
112
  const identity = await ctx.auth.getUserIdentity();
85
- if (identity === null) throw new AuthError("NOT_SIGNED_IN", "You must be signed in to authorize a device.");
113
+ if (identity === null) throw Cv.error({
114
+ code: "NOT_SIGNED_IN",
115
+ message: "You must be signed in to authorize a device."
116
+ });
86
117
  const userId = userIdFromIdentitySubject(identity.subject);
87
118
  const doc = await queryDeviceByUserCode(ctx, params.userCode);
88
- if (doc === null) throw new AuthError("DEVICE_INVALID_USER_CODE");
119
+ if (doc === null) throw Cv.error({
120
+ code: "DEVICE_INVALID_USER_CODE",
121
+ message: "Invalid or expired user code."
122
+ });
89
123
  if (Date.now() > doc.expiresAt) {
90
124
  await mutateDeviceDelete(ctx, doc._id);
91
- throw new AuthError("DEVICE_CODE_EXPIRED");
125
+ throw Cv.error({
126
+ code: "DEVICE_CODE_EXPIRED",
127
+ message: "The device code has expired. Please start a new authorization request."
128
+ });
92
129
  }
93
- if (doc.status !== "pending") throw new AuthError("DEVICE_ALREADY_AUTHORIZED");
130
+ if (doc.status !== "pending") throw Cv.error({
131
+ code: "DEVICE_ALREADY_AUTHORIZED",
132
+ message: "This device code has already been authorized."
133
+ });
94
134
  const signInResult = await callSignIn(ctx, {
95
135
  userId,
96
136
  generateTokens: false
@@ -101,7 +141,10 @@ const handleDevice = (ctx, provider, args) => Fx.from({
101
141
  signedIn: null
102
142
  };
103
143
  },
104
- err: (e) => e instanceof AuthError ? e : new AuthError("INTERNAL_ERROR", `Device flow failed: ${String(e)}`)
144
+ err: (e) => e instanceof ConvexError ? e : Cv.error({
145
+ code: "INTERNAL_ERROR",
146
+ message: `Device flow failed: ${String(e)}`
147
+ })
105
148
  });
106
149
 
107
150
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"device.js","names":["doc"],"sources":["../../../src/server/device.ts"],"sourcesContent":["/**\n * Server-side device authorization flow logic (RFC 8628).\n *\n * Handles the three phases of the device flow:\n * 1. (default) — Generate a device code + user code pair\n * 2. poll — Device checks whether the user has authorized yet\n * 3. verify — Authenticated user links a user code to their session\n *\n * Uses `@oslojs/crypto/random` for code generation and\n * `@oslojs/crypto/sha2` for hashing device codes before storage.\n */\n\nimport { Fx } from \"@robelest/fx\";\n\nimport { AuthError } from \"./authError\";\nimport { userIdFromIdentitySubject } from \"./identity\";\nimport { callSignIn } from \"./mutations/index\";\nimport { DeviceProviderConfig, GenericActionCtxWithAuthConfig } from \"./types\";\nimport {\n AuthDataModel,\n SessionInfo,\n mutateDeviceInsert,\n queryDeviceByCodeHash,\n queryDeviceByUserCode,\n mutateDeviceAuthorize,\n mutateDeviceUpdateLastPolled,\n mutateDeviceDelete,\n} from \"./types\";\nimport { generateRandomString, sha256 } from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\ntype EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEVICE_CODE_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\nconst DEVICE_CODE_LENGTH = 40;\nconst DEVICE_FLOWS = [\"create\", \"poll\", \"verify\"] as const;\n\n// ============================================================================\n// Create flow\n// ============================================================================\n\n// ============================================================================\n// Poll flow — pipeline of validations + status dispatch\n// ============================================================================\n\n// ============================================================================\n// Main dispatch\n// ============================================================================\n\ntype DeviceResult =\n | {\n kind: \"deviceCode\";\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n }\n | { kind: \"signedIn\"; signedIn: SessionInfo | null };\n\n/** @internal */\nexport const handleDevice = (\n ctx: EnrichedActionCtx,\n provider: DeviceProviderConfig,\n args: { params?: Record<string, any> },\n): Fx<DeviceResult, AuthError> =>\n Fx.from({\n ok: async () => {\n const params = (args.params ?? {}) as Record<string, unknown>;\n const flow = (typeof params.flow === \"string\" ? params.flow : \"create\") as\n | \"create\"\n | \"poll\"\n | \"verify\";\n\n if (!DEVICE_FLOWS.some((candidate) => candidate === flow)) {\n throw new AuthError(\n \"DEVICE_MISSING_FLOW\",\n \"Missing `flow` parameter. Expected one of: create, poll, verify\",\n );\n }\n\n if (flow === \"create\") {\n const deviceCode = generateRandomString(\n DEVICE_CODE_LENGTH,\n DEVICE_CODE_ALPHABET,\n );\n const deviceCodeHash = await sha256(deviceCode);\n\n const rawUserCode = generateRandomString(\n provider.userCodeLength,\n provider.charset,\n );\n const mid = Math.floor(rawUserCode.length / 2);\n const userCode =\n rawUserCode.slice(0, mid) + \"-\" + rawUserCode.slice(mid);\n\n const expiresAt = Date.now() + provider.expiresIn * 1000;\n await mutateDeviceInsert(ctx, {\n deviceCodeHash,\n userCode,\n expiresAt,\n interval: provider.interval,\n status: \"pending\",\n });\n\n const verificationUri =\n provider.verificationUri ??\n `${process.env.SITE_URL ?? requireEnv(\"SITE_URL\")}/device`;\n\n return {\n kind: \"deviceCode\" as const,\n deviceCode,\n userCode,\n verificationUri,\n verificationUriComplete: `${verificationUri}?user_code=${encodeURIComponent(userCode)}`,\n expiresIn: provider.expiresIn,\n interval: provider.interval,\n };\n }\n\n if (flow === \"poll\") {\n if (typeof params.deviceCode !== \"string\") {\n throw new AuthError(\n \"DEVICE_MISSING_FLOW\",\n \"Missing `deviceCode` parameter for poll flow.\",\n );\n }\n\n const hash = await sha256(params.deviceCode);\n const doc = await queryDeviceByCodeHash(ctx, hash);\n if (doc === null) {\n throw new AuthError(\"DEVICE_CODE_EXPIRED\");\n }\n if (Date.now() > doc.expiresAt) {\n await mutateDeviceDelete(ctx, doc._id);\n throw new AuthError(\"DEVICE_CODE_EXPIRED\");\n }\n if (\n doc.lastPolledAt !== undefined &&\n (Date.now() - doc.lastPolledAt) / 1000 < doc.interval\n ) {\n throw new AuthError(\"DEVICE_SLOW_DOWN\");\n }\n\n await mutateDeviceUpdateLastPolled(ctx, doc._id, Date.now());\n\n if (doc.status === \"pending\") {\n throw new AuthError(\"DEVICE_AUTHORIZATION_PENDING\");\n }\n if (doc.status === \"denied\") {\n await mutateDeviceDelete(ctx, doc._id);\n throw new AuthError(\"DEVICE_CODE_DENIED\");\n }\n\n if (!doc.userId || !doc.sessionId) {\n throw new AuthError(\n \"INTERNAL_ERROR\",\n \"Authorized device code missing userId or sessionId\",\n );\n }\n\n await mutateDeviceDelete(ctx, doc._id);\n const signInResult = await callSignIn(ctx, {\n userId: doc.userId,\n sessionId: doc.sessionId,\n generateTokens: true,\n });\n return { kind: \"signedIn\" as const, signedIn: signInResult };\n }\n\n if (typeof params.userCode !== \"string\") {\n throw new AuthError(\n \"DEVICE_INVALID_USER_CODE\",\n \"Missing `userCode` parameter for verify flow.\",\n );\n }\n\n const identity = await ctx.auth.getUserIdentity();\n if (identity === null) {\n throw new AuthError(\n \"NOT_SIGNED_IN\",\n \"You must be signed in to authorize a device.\",\n );\n }\n\n const userId = userIdFromIdentitySubject(identity.subject);\n const doc = await queryDeviceByUserCode(ctx, params.userCode);\n if (doc === null) {\n throw new AuthError(\"DEVICE_INVALID_USER_CODE\");\n }\n if (Date.now() > doc.expiresAt) {\n await mutateDeviceDelete(ctx, doc._id);\n throw new AuthError(\"DEVICE_CODE_EXPIRED\");\n }\n if (doc.status !== \"pending\") {\n throw new AuthError(\"DEVICE_ALREADY_AUTHORIZED\");\n }\n\n const signInResult = await callSignIn(ctx, {\n userId,\n generateTokens: false,\n });\n await mutateDeviceAuthorize(\n ctx,\n doc._id,\n signInResult.userId,\n signInResult.sessionId,\n );\n return { kind: \"signedIn\" as const, signedIn: null };\n },\n err: (e) =>\n e instanceof AuthError\n ? e\n : new AuthError(\"INTERNAL_ERROR\", `Device flow failed: ${String(e)}`),\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"device.js","names":["doc"],"sources":["../../../src/server/device.ts"],"sourcesContent":["/**\n * Server-side device authorization flow logic (RFC 8628).\n *\n * Handles the three phases of the device flow:\n * 1. (default) — Generate a device code + user code pair\n * 2. poll — Device checks whether the user has authorized yet\n * 3. verify — Authenticated user links a user code to their session\n *\n * Uses `@oslojs/crypto/random` for code generation and\n * `@oslojs/crypto/sha2` for hashing device codes before storage.\n */\n\nimport { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport { ConvexError } from \"convex/values\";\n\nimport { userIdFromIdentitySubject } from \"./identity\";\nimport { callSignIn } from \"./mutations/index\";\nimport { DeviceProviderConfig, GenericActionCtxWithAuthConfig } from \"./types\";\nimport {\n AuthDataModel,\n SessionInfo,\n mutateDeviceInsert,\n queryDeviceByCodeHash,\n queryDeviceByUserCode,\n mutateDeviceAuthorize,\n mutateDeviceUpdateLastPolled,\n mutateDeviceDelete,\n} from \"./types\";\nimport { generateRandomString, sha256 } from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\ntype EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEVICE_CODE_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\nconst DEVICE_CODE_LENGTH = 40;\nconst DEVICE_FLOWS = [\"create\", \"poll\", \"verify\"] as const;\n\n// ============================================================================\n// Create flow\n// ============================================================================\n\n// ============================================================================\n// Poll flow — pipeline of validations + status dispatch\n// ============================================================================\n\n// ============================================================================\n// Main dispatch\n// ============================================================================\n\ntype DeviceResult =\n | {\n kind: \"deviceCode\";\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n }\n | { kind: \"signedIn\"; signedIn: SessionInfo | null };\n\n/** @internal */\nexport const handleDevice = (\n ctx: EnrichedActionCtx,\n provider: DeviceProviderConfig,\n args: { params?: Record<string, any> },\n): Fx<DeviceResult, ConvexError<any>> =>\n Fx.from({\n ok: async () => {\n const params = (args.params ?? {}) as Record<string, unknown>;\n const flow = (typeof params.flow === \"string\" ? params.flow : \"create\") as\n | \"create\"\n | \"poll\"\n | \"verify\";\n\n if (!DEVICE_FLOWS.some((candidate) => candidate === flow)) {\n throw Cv.error({\n code: \"DEVICE_MISSING_FLOW\",\n message:\n \"Missing `flow` parameter. Expected one of: create, poll, verify\",\n });\n }\n\n if (flow === \"create\") {\n const deviceCode = generateRandomString(\n DEVICE_CODE_LENGTH,\n DEVICE_CODE_ALPHABET,\n );\n const deviceCodeHash = await sha256(deviceCode);\n\n const rawUserCode = generateRandomString(\n provider.userCodeLength,\n provider.charset,\n );\n const mid = Math.floor(rawUserCode.length / 2);\n const userCode =\n rawUserCode.slice(0, mid) + \"-\" + rawUserCode.slice(mid);\n\n const expiresAt = Date.now() + provider.expiresIn * 1000;\n await mutateDeviceInsert(ctx, {\n deviceCodeHash,\n userCode,\n expiresAt,\n interval: provider.interval,\n status: \"pending\",\n });\n\n const verificationUri =\n provider.verificationUri ??\n `${process.env.SITE_URL ?? requireEnv(\"SITE_URL\")}/device`;\n\n return {\n kind: \"deviceCode\" as const,\n deviceCode,\n userCode,\n verificationUri,\n verificationUriComplete: `${verificationUri}?user_code=${encodeURIComponent(userCode)}`,\n expiresIn: provider.expiresIn,\n interval: provider.interval,\n };\n }\n\n if (flow === \"poll\") {\n if (typeof params.deviceCode !== \"string\") {\n throw Cv.error({\n code: \"DEVICE_MISSING_FLOW\",\n message: \"Missing `deviceCode` parameter for poll flow.\",\n });\n }\n\n const hash = await sha256(params.deviceCode);\n const doc = await queryDeviceByCodeHash(ctx, hash);\n if (doc === null) {\n throw Cv.error({\n code: \"DEVICE_CODE_EXPIRED\",\n message:\n \"The device code has expired. Please start a new authorization request.\",\n });\n }\n if (Date.now() > doc.expiresAt) {\n await mutateDeviceDelete(ctx, doc._id);\n throw Cv.error({\n code: \"DEVICE_CODE_EXPIRED\",\n message:\n \"The device code has expired. Please start a new authorization request.\",\n });\n }\n if (\n doc.lastPolledAt !== undefined &&\n (Date.now() - doc.lastPolledAt) / 1000 < doc.interval\n ) {\n throw Cv.error({\n code: \"DEVICE_SLOW_DOWN\",\n message:\n \"Polling too frequently. Increase the interval between requests.\",\n });\n }\n\n await mutateDeviceUpdateLastPolled(ctx, doc._id, Date.now());\n\n if (doc.status === \"pending\") {\n throw Cv.error({\n code: \"DEVICE_AUTHORIZATION_PENDING\",\n message: \"The user has not yet authorized this device.\",\n });\n }\n if (doc.status === \"denied\") {\n await mutateDeviceDelete(ctx, doc._id);\n throw Cv.error({\n code: \"DEVICE_CODE_DENIED\",\n message: \"The authorization request was denied.\",\n });\n }\n\n if (!doc.userId || !doc.sessionId) {\n throw Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"Authorized device code missing userId or sessionId\",\n });\n }\n\n await mutateDeviceDelete(ctx, doc._id);\n const signInResult = await callSignIn(ctx, {\n userId: doc.userId,\n sessionId: doc.sessionId,\n generateTokens: true,\n });\n return { kind: \"signedIn\" as const, signedIn: signInResult };\n }\n\n if (typeof params.userCode !== \"string\") {\n throw Cv.error({\n code: \"DEVICE_INVALID_USER_CODE\",\n message: \"Missing `userCode` parameter for verify flow.\",\n });\n }\n\n const identity = await ctx.auth.getUserIdentity();\n if (identity === null) {\n throw Cv.error({\n code: \"NOT_SIGNED_IN\",\n message: \"You must be signed in to authorize a device.\",\n });\n }\n\n const userId = userIdFromIdentitySubject(identity.subject);\n const doc = await queryDeviceByUserCode(ctx, params.userCode);\n if (doc === null) {\n throw Cv.error({\n code: \"DEVICE_INVALID_USER_CODE\",\n message: \"Invalid or expired user code.\",\n });\n }\n if (Date.now() > doc.expiresAt) {\n await mutateDeviceDelete(ctx, doc._id);\n throw Cv.error({\n code: \"DEVICE_CODE_EXPIRED\",\n message:\n \"The device code has expired. Please start a new authorization request.\",\n });\n }\n if (doc.status !== \"pending\") {\n throw Cv.error({\n code: \"DEVICE_ALREADY_AUTHORIZED\",\n message: \"This device code has already been authorized.\",\n });\n }\n\n const signInResult = await callSignIn(ctx, {\n userId,\n generateTokens: false,\n });\n await mutateDeviceAuthorize(\n ctx,\n doc._id,\n signInResult.userId,\n signInResult.sessionId,\n );\n return { kind: \"signedIn\" as const, signedIn: null };\n },\n err: (e) =>\n e instanceof ConvexError\n ? e\n : Cv.error({\n code: \"INTERNAL_ERROR\",\n message: `Device flow failed: ${String(e)}`,\n }),\n });\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsCA,MAAM,uBACJ;AACF,MAAM,qBAAqB;AAC3B,MAAM,eAAe;CAAC;CAAU;CAAQ;CAAS;;AA2BjD,MAAa,gBACX,KACA,UACA,SAEA,GAAG,KAAK;CACN,IAAI,YAAY;EACd,MAAM,SAAU,KAAK,UAAU,EAAE;EACjC,MAAM,OAAQ,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAK9D,MAAI,CAAC,aAAa,MAAM,cAAc,cAAc,KAAK,CACvD,OAAM,GAAG,MAAM;GACb,MAAM;GACN,SACE;GACH,CAAC;AAGJ,MAAI,SAAS,UAAU;GACrB,MAAM,aAAa,qBACjB,oBACA,qBACD;GACD,MAAM,iBAAiB,MAAM,OAAO,WAAW;GAE/C,MAAM,cAAc,qBAClB,SAAS,gBACT,SAAS,QACV;GACD,MAAM,MAAM,KAAK,MAAM,YAAY,SAAS,EAAE;GAC9C,MAAM,WACJ,YAAY,MAAM,GAAG,IAAI,GAAG,MAAM,YAAY,MAAM,IAAI;AAG1D,SAAM,mBAAmB,KAAK;IAC5B;IACA;IACA,WAJgB,KAAK,KAAK,GAAG,SAAS,YAAY;IAKlD,UAAU,SAAS;IACnB,QAAQ;IACT,CAAC;GAEF,MAAM,kBACJ,SAAS,mBACT,GAAG,QAAQ,IAAI,YAAY,WAAW,WAAW,CAAC;AAEpD,UAAO;IACL,MAAM;IACN;IACA;IACA;IACA,yBAAyB,GAAG,gBAAgB,aAAa,mBAAmB,SAAS;IACrF,WAAW,SAAS;IACpB,UAAU,SAAS;IACpB;;AAGH,MAAI,SAAS,QAAQ;AACnB,OAAI,OAAO,OAAO,eAAe,SAC/B,OAAM,GAAG,MAAM;IACb,MAAM;IACN,SAAS;IACV,CAAC;GAIJ,MAAMA,QAAM,MAAM,sBAAsB,KAD3B,MAAM,OAAO,OAAO,WAAW,CACM;AAClD,OAAIA,UAAQ,KACV,OAAM,GAAG,MAAM;IACb,MAAM;IACN,SACE;IACH,CAAC;AAEJ,OAAI,KAAK,KAAK,GAAGA,MAAI,WAAW;AAC9B,UAAM,mBAAmB,KAAKA,MAAI,IAAI;AACtC,UAAM,GAAG,MAAM;KACb,MAAM;KACN,SACE;KACH,CAAC;;AAEJ,OACEA,MAAI,iBAAiB,WACpB,KAAK,KAAK,GAAGA,MAAI,gBAAgB,MAAOA,MAAI,SAE7C,OAAM,GAAG,MAAM;IACb,MAAM;IACN,SACE;IACH,CAAC;AAGJ,SAAM,6BAA6B,KAAKA,MAAI,KAAK,KAAK,KAAK,CAAC;AAE5D,OAAIA,MAAI,WAAW,UACjB,OAAM,GAAG,MAAM;IACb,MAAM;IACN,SAAS;IACV,CAAC;AAEJ,OAAIA,MAAI,WAAW,UAAU;AAC3B,UAAM,mBAAmB,KAAKA,MAAI,IAAI;AACtC,UAAM,GAAG,MAAM;KACb,MAAM;KACN,SAAS;KACV,CAAC;;AAGJ,OAAI,CAACA,MAAI,UAAU,CAACA,MAAI,UACtB,OAAM,GAAG,MAAM;IACb,MAAM;IACN,SAAS;IACV,CAAC;AAGJ,SAAM,mBAAmB,KAAKA,MAAI,IAAI;AAMtC,UAAO;IAAE,MAAM;IAAqB,UALf,MAAM,WAAW,KAAK;KACzC,QAAQA,MAAI;KACZ,WAAWA,MAAI;KACf,gBAAgB;KACjB,CAAC;IAC0D;;AAG9D,MAAI,OAAO,OAAO,aAAa,SAC7B,OAAM,GAAG,MAAM;GACb,MAAM;GACN,SAAS;GACV,CAAC;EAGJ,MAAM,WAAW,MAAM,IAAI,KAAK,iBAAiB;AACjD,MAAI,aAAa,KACf,OAAM,GAAG,MAAM;GACb,MAAM;GACN,SAAS;GACV,CAAC;EAGJ,MAAM,SAAS,0BAA0B,SAAS,QAAQ;EAC1D,MAAM,MAAM,MAAM,sBAAsB,KAAK,OAAO,SAAS;AAC7D,MAAI,QAAQ,KACV,OAAM,GAAG,MAAM;GACb,MAAM;GACN,SAAS;GACV,CAAC;AAEJ,MAAI,KAAK,KAAK,GAAG,IAAI,WAAW;AAC9B,SAAM,mBAAmB,KAAK,IAAI,IAAI;AACtC,SAAM,GAAG,MAAM;IACb,MAAM;IACN,SACE;IACH,CAAC;;AAEJ,MAAI,IAAI,WAAW,UACjB,OAAM,GAAG,MAAM;GACb,MAAM;GACN,SAAS;GACV,CAAC;EAGJ,MAAM,eAAe,MAAM,WAAW,KAAK;GACzC;GACA,gBAAgB;GACjB,CAAC;AACF,QAAM,sBACJ,KACA,IAAI,KACJ,aAAa,QACb,aAAa,UACd;AACD,SAAO;GAAE,MAAM;GAAqB,UAAU;GAAM;;CAEtD,MAAM,MACJ,aAAa,cACT,IACA,GAAG,MAAM;EACP,MAAM;EACN,SAAS,uBAAuB,OAAO,EAAE;EAC1C,CAAC;CACT,CAAC"}
@@ -1,4 +1,4 @@
1
- import { AuthError } from "../authError.js";
1
+ import { Cv } from "@robelest/fx/convex";
2
2
  import { Fx } from "@robelest/fx";
3
3
 
4
4
  //#region src/server/enterprise/domain.ts
@@ -34,7 +34,6 @@ function createEnterpriseDomain(deps) {
34
34
  connection: {
35
35
  create: async (ctx, data) => {
36
36
  return {
37
- ok: true,
38
37
  enterpriseId: await ctx.runMutation(config.component.public.enterpriseCreate, {
39
38
  ...data,
40
39
  policy: normalizeEnterprisePolicy(data.policy)
@@ -65,21 +64,18 @@ function createEnterpriseDomain(deps) {
65
64
  enterpriseId,
66
65
  data
67
66
  });
68
- return {
69
- ok: true,
70
- enterpriseId
71
- };
67
+ return { enterpriseId };
72
68
  },
73
69
  delete: async (ctx, enterpriseId) => {
74
70
  await ctx.runMutation(config.component.public.enterpriseDelete, { enterpriseId });
75
- return {
76
- ok: true,
77
- enterpriseId
78
- };
71
+ return { enterpriseId };
79
72
  },
80
73
  status: async (ctx, enterpriseId) => {
81
74
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId });
82
- if (!enterprise) throw new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError).toConvexError();
75
+ if (!enterprise) throw Cv.error({
76
+ code: "INVALID_PARAMETERS",
77
+ message: enterpriseNotFoundError
78
+ });
83
79
  const policy = getPolicyFromEnterprise(enterprise);
84
80
  const protocols = enterprise.config?.protocols ?? {};
85
81
  const oidcConfig = protocols.oidc;
@@ -130,7 +126,10 @@ function createEnterpriseDomain(deps) {
130
126
  },
131
127
  validate: async (ctx, enterpriseId) => {
132
128
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId });
133
- if (enterprise === null) throw new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError).toConvexError();
129
+ if (enterprise === null) throw Cv.error({
130
+ code: "INVALID_PARAMETERS",
131
+ message: enterpriseNotFoundError
132
+ });
134
133
  const domains = await ctx.runQuery(config.component.public.enterpriseDomainList, { enterpriseId });
135
134
  const primaryDomains = domains.filter((domain) => domain.isPrimary);
136
135
  const verifiedDomains = domains.filter((domain) => domain.verifiedAt !== void 0);
@@ -159,7 +158,10 @@ function createEnterpriseDomain(deps) {
159
158
  const enterprise = await loadEnterpriseOrThrow(ctx, args.enterpriseId);
160
159
  const normalizedDomain = normalizeDomain(args.domain);
161
160
  const domain = (await ctx.runQuery(config.component.public.enterpriseDomainList, { enterpriseId: enterprise._id })).find((entry) => entry.domain === normalizedDomain);
162
- if (!domain) throw new AuthError("INVALID_PARAMETERS", "Domain is not attached to this enterprise.").toConvexError();
161
+ if (!domain) throw Cv.error({
162
+ code: "INVALID_PARAMETERS",
163
+ message: "Domain is not attached to this enterprise."
164
+ });
163
165
  const requestedAt = Date.now();
164
166
  const expiresAt = requestedAt + ENTERPRISE_DOMAIN_VERIFICATION_TTL_MS;
165
167
  const token = generateRandomString(32, INVITE_TOKEN_ALPHABET);
@@ -191,7 +193,6 @@ function createEnterpriseDomain(deps) {
191
193
  }
192
194
  });
193
195
  return {
194
- ok: true,
195
196
  enterpriseId: enterprise._id,
196
197
  domain: normalizedDomain,
197
198
  requestedAt,
@@ -207,7 +208,10 @@ function createEnterpriseDomain(deps) {
207
208
  const enterprise = await loadEnterpriseOrThrow(ctx, args.enterpriseId);
208
209
  const normalizedDomain = normalizeDomain(args.domain);
209
210
  const domain = (await ctx.runQuery(config.component.public.enterpriseDomainList, { enterpriseId: enterprise._id })).find((entry) => entry.domain === normalizedDomain);
210
- if (!domain) throw new AuthError("INVALID_PARAMETERS", "Domain is not attached to this enterprise.").toConvexError();
211
+ if (!domain) throw Cv.error({
212
+ code: "INVALID_PARAMETERS",
213
+ message: "Domain is not attached to this enterprise."
214
+ });
211
215
  if (domain.verifiedAt !== void 0) return {
212
216
  ok: true,
213
217
  enterpriseId: enterprise._id,
@@ -260,7 +264,10 @@ function createEnterpriseDomain(deps) {
260
264
  try {
261
265
  txtValues = await resolveTxtValues(verification.recordName);
262
266
  } catch (error) {
263
- throw new AuthError("INTERNAL_ERROR", error instanceof Error ? error.message : "Failed to resolve DNS TXT records.").toConvexError();
267
+ throw Cv.error({
268
+ code: "INTERNAL_ERROR",
269
+ message: error instanceof Error ? error.message : "Failed to resolve DNS TXT records."
270
+ });
264
271
  }
265
272
  checks.push({
266
273
  name: "dns_record_present",
@@ -312,19 +319,37 @@ function createEnterpriseDomain(deps) {
312
319
  return await Fx.run(Fx.gen(function* () {
313
320
  const enterprise = yield* Fx.from({
314
321
  ok: () => ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: data.enterpriseId }),
315
- err: () => new AuthError("INTERNAL_ERROR", "Failed to load enterprise.")
316
- }).pipe(Fx.chain((ent) => ent === null ? Fx.fail(new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError)) : Fx.succeed(ent)));
322
+ err: () => Cv.error({
323
+ code: "INTERNAL_ERROR",
324
+ message: "Failed to load enterprise."
325
+ })
326
+ }).pipe(Fx.chain((ent) => ent === null ? Cv.fail({
327
+ code: "INVALID_PARAMETERS",
328
+ message: enterpriseNotFoundError
329
+ }) : Fx.succeed(ent)));
317
330
  const metadataXml = yield* data.metadataXml ? Fx.succeed(data.metadataXml) : data.metadataUrl ? Fx.defer(() => Fx.from({
318
331
  ok: async () => {
319
332
  const response = await fetch(data.metadataUrl);
320
333
  if (!response.ok) throw new Error(`Failed to fetch SAML metadata: ${response.status}`);
321
334
  return await response.text();
322
335
  },
323
- err: (error) => new AuthError("INVALID_PARAMETERS", error instanceof Error ? error.message : "Failed to fetch SAML metadata")
324
- })).pipe(Fx.timeout(1e4), Fx.retry(Fx.retry.compose(Fx.retry.jittered(Fx.retry.exponential(200)), Fx.retry.recurs(2))), Fx.recover((error) => Fx.fail(new AuthError("INVALID_PARAMETERS", error instanceof Error ? error.message : "Failed to fetch SAML metadata")))) : Fx.fail(new AuthError("INVALID_PARAMETERS", "SAML registration requires metadataXml or metadataUrl."));
336
+ err: (error) => Cv.error({
337
+ code: "INVALID_PARAMETERS",
338
+ message: error instanceof Error ? error.message : "Failed to fetch SAML metadata"
339
+ })
340
+ })).pipe(Fx.timeout(1e4), Fx.retry(Fx.retry.compose(Fx.retry.jittered(Fx.retry.exponential(200)), Fx.retry.recurs(2))), Fx.recover((error) => Cv.fail({
341
+ code: "INVALID_PARAMETERS",
342
+ message: error instanceof Error ? error.message : "Failed to fetch SAML metadata"
343
+ }))) : Cv.fail({
344
+ code: "INVALID_PARAMETERS",
345
+ message: "SAML registration requires metadataXml or metadataUrl."
346
+ });
325
347
  const parsed = yield* Fx.from({
326
348
  ok: () => parseSamlIdpMetadata(metadataXml),
327
- err: () => new AuthError("INVALID_PARAMETERS", "Failed to parse SAML metadata.")
349
+ err: () => Cv.error({
350
+ code: "INVALID_PARAMETERS",
351
+ message: "Failed to parse SAML metadata."
352
+ })
328
353
  });
329
354
  const baseConfig = upsertProtocolConfig(enterprise.config, "saml", {
330
355
  enabled: true,
@@ -349,7 +374,10 @@ function createEnterpriseDomain(deps) {
349
374
  config: nextConfig
350
375
  }
351
376
  }),
352
- err: () => new AuthError("INTERNAL_ERROR", "Failed to persist SAML registration.")
377
+ err: () => Cv.error({
378
+ code: "INTERNAL_ERROR",
379
+ message: "Failed to persist SAML registration."
380
+ })
353
381
  });
354
382
  if (normalizedDomains) for (const [index, domain] of normalizedDomains.entries()) yield* Fx.from({
355
383
  ok: () => ctx.runMutation(config.component.public.enterpriseDomainAdd, {
@@ -358,7 +386,10 @@ function createEnterpriseDomain(deps) {
358
386
  domain,
359
387
  isPrimary: index === 0
360
388
  }),
361
- err: () => new AuthError("INTERNAL_ERROR", "Failed to persist enterprise domain.")
389
+ err: () => Cv.error({
390
+ code: "INTERNAL_ERROR",
391
+ message: "Failed to persist enterprise domain."
392
+ })
362
393
  });
363
394
  yield* Fx.from({
364
395
  ok: () => recordEnterpriseAuditEvent(ctx, {
@@ -374,18 +405,23 @@ function createEnterpriseDomain(deps) {
374
405
  domains: normalizedDomains
375
406
  }
376
407
  }),
377
- err: () => new AuthError("INTERNAL_ERROR", "Failed to record SAML registration audit event.")
408
+ err: () => Cv.error({
409
+ code: "INTERNAL_ERROR",
410
+ message: "Failed to record SAML registration audit event."
411
+ })
378
412
  });
379
413
  return {
380
- ok: true,
381
414
  enterpriseId: enterprise._id,
382
415
  groupId: enterprise.groupId
383
416
  };
384
- }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))));
417
+ }).pipe(Fx.recover((e) => Fx.fatal(e))));
385
418
  },
386
419
  metadata: async (ctx, opts) => {
387
420
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: opts.enterpriseId });
388
- if (!enterprise) throw new AuthError("INVALID_PARAMETERS", "Enterprise not found.").toConvexError();
421
+ if (!enterprise) throw Cv.error({
422
+ code: "INVALID_PARAMETERS",
423
+ message: "Enterprise not found."
424
+ });
389
425
  return createServiceProviderMetadata(getSamlServiceProviderOptions({
390
426
  rootUrl: requireEnv("CONVEX_SITE_URL"),
391
427
  source: {
@@ -507,11 +543,20 @@ function createEnterpriseDomain(deps) {
507
543
  oidc: {
508
544
  configure: async (ctx, data) => {
509
545
  return await Fx.run(Fx.gen(function* () {
510
- yield* Fx.guard(data.issuer === void 0 && data.discoveryUrl === void 0, Fx.fail(new AuthError("INVALID_PARAMETERS", "OIDC registration requires issuer or discoveryUrl.")));
546
+ yield* Fx.guard(data.issuer === void 0 && data.discoveryUrl === void 0, Cv.fail({
547
+ code: "INVALID_PARAMETERS",
548
+ message: "OIDC registration requires issuer or discoveryUrl."
549
+ }));
511
550
  const enterprise = yield* Fx.from({
512
551
  ok: () => ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: data.enterpriseId }),
513
- err: () => new AuthError("INTERNAL_ERROR", "Failed to load enterprise.")
514
- }).pipe(Fx.chain((ent) => ent === null ? Fx.fail(new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError)) : Fx.succeed(ent)));
552
+ err: () => Cv.error({
553
+ code: "INTERNAL_ERROR",
554
+ message: "Failed to load enterprise."
555
+ })
556
+ }).pipe(Fx.chain((ent) => ent === null ? Cv.fail({
557
+ code: "INVALID_PARAMETERS",
558
+ message: enterpriseNotFoundError
559
+ }) : Fx.succeed(ent)));
515
560
  const nextConfig = upsertProtocolConfig(enterprise.config, "oidc", {
516
561
  enabled: true,
517
562
  issuer: data.issuer,
@@ -532,12 +577,18 @@ function createEnterpriseDomain(deps) {
532
577
  enterpriseId: data.enterpriseId,
533
578
  data: { config: nextConfig }
534
579
  }),
535
- err: () => new AuthError("INTERNAL_ERROR", "Failed to persist OIDC registration.")
580
+ err: () => Cv.error({
581
+ code: "INTERNAL_ERROR",
582
+ message: "Failed to persist OIDC registration."
583
+ })
536
584
  });
537
585
  if (data.clientSecret !== void 0) {
538
586
  const ciphertext = yield* Fx.from({
539
587
  ok: () => encryptSecret(data.clientSecret),
540
- err: () => new AuthError("INTERNAL_ERROR", "Failed to encrypt OIDC client secret.")
588
+ err: () => Cv.error({
589
+ code: "INTERNAL_ERROR",
590
+ message: "Failed to encrypt OIDC client secret."
591
+ })
541
592
  });
542
593
  yield* Fx.from({
543
594
  ok: () => ctx.runMutation(config.component.public.enterpriseSecretUpsert, {
@@ -547,7 +598,10 @@ function createEnterpriseDomain(deps) {
547
598
  ciphertext,
548
599
  updatedAt: Date.now()
549
600
  }),
550
- err: () => new AuthError("INTERNAL_ERROR", "Failed to persist OIDC client secret.")
601
+ err: () => Cv.error({
602
+ code: "INTERNAL_ERROR",
603
+ message: "Failed to persist OIDC client secret."
604
+ })
551
605
  });
552
606
  }
553
607
  yield* Fx.from({
@@ -564,39 +618,75 @@ function createEnterpriseDomain(deps) {
564
618
  discoveryUrl: data.discoveryUrl
565
619
  }
566
620
  }),
567
- err: () => new AuthError("INTERNAL_ERROR", "Failed to record OIDC registration audit event.")
621
+ err: () => Cv.error({
622
+ code: "INTERNAL_ERROR",
623
+ message: "Failed to record OIDC registration audit event."
624
+ })
568
625
  });
569
626
  const secret = yield* Fx.from({
570
627
  ok: () => getEnterpriseSecret(ctx, data.enterpriseId, ENTERPRISE_OIDC_CLIENT_SECRET_KIND),
571
- err: () => new AuthError("INTERNAL_ERROR", "Failed to load OIDC secret metadata.")
628
+ err: () => Cv.error({
629
+ code: "INTERNAL_ERROR",
630
+ message: "Failed to load OIDC secret metadata."
631
+ })
572
632
  });
573
633
  return withOidcSecretState(getPublicOidcConfig(nextConfig), secret !== null);
574
- }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))));
634
+ }).pipe(Fx.recover((e) => Fx.fatal(e))));
575
635
  },
576
636
  get: async (ctx, enterpriseId) => {
577
637
  return await Fx.run(Fx.from({
578
638
  ok: () => ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId }),
579
- err: () => new AuthError("INTERNAL_ERROR", "Failed to load enterprise.")
580
- }).pipe(Fx.chain((ent) => ent === null ? Fx.fail(new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError)) : Fx.succeed(ent)), Fx.chain((enterprise) => Fx.from({
639
+ err: () => Cv.error({
640
+ code: "INTERNAL_ERROR",
641
+ message: "Failed to load enterprise."
642
+ })
643
+ }).pipe(Fx.chain((ent) => ent === null ? Cv.fail({
644
+ code: "INVALID_PARAMETERS",
645
+ message: enterpriseNotFoundError
646
+ }) : Fx.succeed(ent)), Fx.chain((enterprise) => Fx.from({
581
647
  ok: async () => {
582
648
  const secret = await getEnterpriseSecret(ctx, enterprise._id, ENTERPRISE_OIDC_CLIENT_SECRET_KIND);
583
649
  return withOidcSecretState(getPublicOidcConfig(enterprise.config), secret !== null);
584
650
  },
585
- err: () => new AuthError("INTERNAL_ERROR", "Failed to load OIDC secret metadata.")
586
- })), Fx.recover((e) => Fx.fatal(e.toConvexError()))));
651
+ err: () => Cv.error({
652
+ code: "INTERNAL_ERROR",
653
+ message: "Failed to load OIDC secret metadata."
654
+ })
655
+ })), Fx.recover((e) => Fx.fatal(e))));
587
656
  },
588
657
  signIn: async (ctx, data) => {
589
658
  return await Fx.run(Fx.gen(function* () {
590
659
  const enterprise = data.enterpriseId !== void 0 ? yield* Fx.from({
591
660
  ok: () => ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: data.enterpriseId }),
592
- err: () => new AuthError("INTERNAL_ERROR", "Failed to load enterprise.")
593
- }).pipe(Fx.chain((ent) => ent === null ? Fx.fail(new AuthError("INVALID_PARAMETERS", enterpriseNotFoundError)) : Fx.succeed(ent))) : data.domain !== void 0 || data.email !== void 0 ? yield* Fx.from({
594
- ok: () => ctx.runQuery(config.component.public.enterpriseGetByDomain, { domain: normalizeDomain(data.domain ?? String(data.email).split("@").at(-1) ?? "") }),
595
- err: () => new AuthError("INTERNAL_ERROR", "Failed to resolve enterprise by domain.")
596
- }).pipe(Fx.chain((result) => result?.enterprise && result.domain?.verifiedAt !== void 0 ? Fx.succeed(result.enterprise) : Fx.fail(new AuthError("INVALID_PARAMETERS", "No enterprise OIDC connection matched the provided input.")))) : yield* Fx.fail(new AuthError("INVALID_PARAMETERS", "No enterprise OIDC connection matched the provided input."));
597
- yield* Fx.guard(enterprise.status !== "active", Fx.fail(new AuthError("INVALID_PARAMETERS", "Enterprise connection is not active.")));
661
+ err: () => Cv.error({
662
+ code: "INTERNAL_ERROR",
663
+ message: "Failed to load enterprise."
664
+ })
665
+ }).pipe(Fx.chain((ent) => ent === null ? Cv.fail({
666
+ code: "INVALID_PARAMETERS",
667
+ message: enterpriseNotFoundError
668
+ }) : Fx.succeed(ent))) : data.domain !== void 0 || data.email !== void 0 ? yield* Fx.from({
669
+ ok: () => ctx.runQuery(config.component.public.enterpriseGetByDomain, { domain: normalizeDomain(data.domain ?? String(data.email).split("@").pop() ?? "") }),
670
+ err: () => Cv.error({
671
+ code: "INTERNAL_ERROR",
672
+ message: "Failed to resolve enterprise by domain."
673
+ })
674
+ }).pipe(Fx.chain((result) => result?.enterprise && result.domain?.verifiedAt !== void 0 ? Fx.succeed(result.enterprise) : Cv.fail({
675
+ code: "INVALID_PARAMETERS",
676
+ message: "No enterprise OIDC connection matched the provided input."
677
+ }))) : yield* Cv.fail({
678
+ code: "INVALID_PARAMETERS",
679
+ message: "No enterprise OIDC connection matched the provided input."
680
+ });
681
+ yield* Fx.guard(enterprise.status !== "active", Cv.fail({
682
+ code: "INVALID_PARAMETERS",
683
+ message: "Enterprise connection is not active."
684
+ }));
598
685
  const oidc = getOidcConfig(enterprise.config);
599
- yield* Fx.guard(oidc.enabled !== true, Fx.fail(new AuthError("PROVIDER_NOT_CONFIGURED", "OIDC is not configured for this enterprise.")));
686
+ yield* Fx.guard(oidc.enabled !== true, Cv.fail({
687
+ code: "PROVIDER_NOT_CONFIGURED",
688
+ message: "OIDC is not configured for this enterprise."
689
+ }));
600
690
  const urls = getEnterpriseOidcUrls({
601
691
  rootUrl: requireEnv("CONVEX_SITE_URL"),
602
692
  enterpriseId: enterprise._id
@@ -608,7 +698,7 @@ function createEnterpriseDomain(deps) {
608
698
  callbackPath: urls.callbackUrl,
609
699
  redirectTo: data.redirectTo
610
700
  };
611
- }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))));
701
+ }).pipe(Fx.recover((e) => Fx.fatal(e))));
612
702
  },
613
703
  validate: async (ctx, enterpriseId) => {
614
704
  const checks = [];
@@ -683,7 +773,10 @@ function createEnterpriseDomain(deps) {
683
773
  scim: {
684
774
  configure: async (ctx, data) => {
685
775
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: data.enterpriseId });
686
- if (enterprise === null) throw new AuthError("INVALID_PARAMETERS", "Enterprise not found.").toConvexError();
776
+ if (enterprise === null) throw Cv.error({
777
+ code: "INVALID_PARAMETERS",
778
+ message: "Enterprise not found."
779
+ });
687
780
  const rawToken = generateRandomString(48, INVITE_TOKEN_ALPHABET);
688
781
  const tokenHash = await sha256(rawToken);
689
782
  const configId = await ctx.runMutation(config.component.public.enterpriseScimConfigUpsert, {
@@ -713,7 +806,6 @@ function createEnterpriseDomain(deps) {
713
806
  }
714
807
  });
715
808
  return {
716
- ok: true,
717
809
  enterpriseId: enterprise._id,
718
810
  configId,
719
811
  basePath: data.basePath ?? `${requireEnv("CONVEX_SITE_URL")}/api/auth/sso/${enterprise._id}/scim/v2`,
@@ -799,7 +891,10 @@ function createEnterpriseDomain(deps) {
799
891
  },
800
892
  create: async (ctx, data) => {
801
893
  const enterprise = await ctx.runQuery(config.component.public.enterpriseGet, { enterpriseId: data.enterpriseId });
802
- if (enterprise === null) throw new AuthError("INVALID_PARAMETERS", "Enterprise not found.").toConvexError();
894
+ if (enterprise === null) throw Cv.error({
895
+ code: "INVALID_PARAMETERS",
896
+ message: "Enterprise not found."
897
+ });
803
898
  const secretHash = await sha256(data.secret);
804
899
  const endpointId = await ctx.runMutation(config.component.public.enterpriseWebhookEndpointCreate, {
805
900
  enterpriseId: enterprise._id,
@@ -819,10 +914,7 @@ function createEnterpriseDomain(deps) {
819
914
  subjectId: endpointId,
820
915
  ok: true
821
916
  });
822
- return {
823
- ok: true,
824
- endpointId
825
- };
917
+ return { endpointId };
826
918
  },
827
919
  list: async (ctx, enterpriseId) => {
828
920
  return await ctx.runQuery(config.component.public.enterpriseWebhookEndpointList, { enterpriseId });
@@ -832,10 +924,7 @@ function createEnterpriseDomain(deps) {
832
924
  endpointId,
833
925
  data: { status: "disabled" }
834
926
  });
835
- return {
836
- ok: true,
837
- endpointId
838
- };
927
+ return { endpointId };
839
928
  }
840
929
  },
841
930
  emit: async (ctx, data) => {