@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,13 +1,14 @@
1
+ import { Cv } from "@robelest/fx/convex";
1
2
  import { Auth, GenericActionCtx, GenericDataModel } from "convex/server";
2
3
  import { GenericId } from "convex/values";
3
4
 
5
+ import { materializeProvider } from "./config";
4
6
  import {
5
7
  buildScopeChecker,
6
8
  checkKeyRateLimit,
7
9
  generateApiKey,
8
10
  hashApiKey,
9
11
  } from "./keys";
10
- import { materializeProvider } from "./config";
11
12
  import { signInImpl } from "./signin";
12
13
  import type {
13
14
  AuthProviderConfig,
@@ -17,11 +18,7 @@ import type {
17
18
  UserOrderBy,
18
19
  UserWhere,
19
20
  } from "./types";
20
- import {
21
- generateRandomString,
22
- sha256,
23
- TOKEN_SUB_CLAIM_DIVIDER,
24
- } from "./utils";
21
+ import { generateRandomString, sha256, TOKEN_SUB_CLAIM_DIVIDER } from "./utils";
25
22
 
26
23
  type ComponentCtx = Pick<
27
24
  GenericActionCtx<GenericDataModel>,
@@ -104,17 +101,17 @@ export function createCoreDomains(deps: CoreDeps) {
104
101
  return roleDefinitions[roleId] ?? null;
105
102
  };
106
103
 
107
- const normalizeRoleIds = (
108
- roleIds?: string[],
109
- ):
110
- | { ok: true; roleIds: string[] }
111
- | { ok: false; invalidRoleIds: string[] } => {
104
+ const normalizeRoleIds = (roleIds?: string[]): string[] => {
112
105
  const normalized = Array.from(new Set(roleIds ?? []));
113
106
  const invalid = normalized.filter((id) => getRoleDefinition(id) === null);
114
107
  if (invalid.length > 0) {
115
- return { ok: false, invalidRoleIds: invalid };
108
+ throw Cv.error({
109
+ code: "INVALID_ROLE_IDS",
110
+ message: "One or more role IDs are invalid.",
111
+ invalidRoleIds: invalid,
112
+ });
116
113
  }
117
- return { ok: true, roleIds: normalized };
114
+ return normalized;
118
115
  };
119
116
 
120
117
  const listAllKeysByUser = async (ctx: ComponentCtx, userId: string) => {
@@ -225,14 +222,15 @@ export function createCoreDomains(deps: CoreDeps) {
225
222
  const authHeader = request.headers.get("Authorization");
226
223
  if (authHeader?.startsWith("Bearer sk_")) {
227
224
  const rawKey = authHeader.slice(7);
228
- const result = await getAuth().key.verify(
229
- ctx as ComponentCtx,
230
- rawKey,
231
- );
232
- if (result.ok) {
225
+ try {
226
+ const result = await getAuth().key.verify(
227
+ ctx as ComponentCtx,
228
+ rawKey,
229
+ );
233
230
  return result.userId;
231
+ } catch {
232
+ return null;
234
233
  }
235
- return null;
236
234
  }
237
235
  }
238
236
  return null;
@@ -325,7 +323,7 @@ export function createCoreDomains(deps: CoreDeps) {
325
323
  * @param ctx - Convex mutation context.
326
324
  * @param userId - The user's document ID.
327
325
  * @param data - Fields to merge into the user document.
328
- * @returns `{ ok: true, userId }`.
326
+ * @returns `{ userId }`.
329
327
  *
330
328
  * @example
331
329
  * ```ts
@@ -344,7 +342,7 @@ export function createCoreDomains(deps: CoreDeps) {
344
342
  userId,
345
343
  data,
346
344
  });
347
- return { ok: true as const, userId };
345
+ return { userId };
348
346
  },
349
347
  /**
350
348
  * Set the user's active group. Stored in `user.extend.lastActiveGroup`.
@@ -354,7 +352,7 @@ export function createCoreDomains(deps: CoreDeps) {
354
352
  * @param ctx - Convex mutation context.
355
353
  * @param opts.userId - The user's document ID.
356
354
  * @param opts.groupId - Group ID to set as active, or `null` to clear.
357
- * @returns `{ ok: true, userId, groupId }` confirming the active group was set (or cleared).
355
+ * @returns `{ userId, groupId }` confirming the active group was set (or cleared).
358
356
  *
359
357
  * @example
360
358
  * ```ts
@@ -380,12 +378,12 @@ export function createCoreDomains(deps: CoreDeps) {
380
378
  if (opts.groupId === null) {
381
379
  const { lastActiveGroup: _omit, ...rest } = existingExtend;
382
380
  await user.update(ctx, opts.userId, { extend: rest });
383
- return { ok: true as const, userId: opts.userId, groupId: null };
381
+ return { userId: opts.userId, groupId: null };
384
382
  }
385
383
  await user.update(ctx, opts.userId, {
386
384
  extend: { ...existingExtend, lastActiveGroup: opts.groupId },
387
385
  });
388
- return { ok: true as const, userId: opts.userId, groupId: opts.groupId };
386
+ return { userId: opts.userId, groupId: opts.groupId };
389
387
  },
390
388
  /**
391
389
  * Read the user's active group ID from `user.extend.lastActiveGroup`.
@@ -429,7 +427,8 @@ export function createCoreDomains(deps: CoreDeps) {
429
427
  * @param ctx - Convex mutation context.
430
428
  * @param userId - The user's document ID.
431
429
  * @param opts.cascade - Whether to delete related records (default `true`).
432
- * @returns `{ ok: true, userId }`.
430
+ * @returns `{ userId }`.
431
+ * @throws `INVALID_PARAMETERS` if `cascade` is `false` but the user has linked data.
433
432
  */
434
433
  delete: async (
435
434
  ctx: ComponentCtx,
@@ -462,7 +461,10 @@ export function createCoreDomains(deps: CoreDeps) {
462
461
  passkeys.length +
463
462
  totps.length;
464
463
  if (!cascade && totalLinked > 0) {
465
- return { ok: false as const, code: "INVALID_PARAMETERS" as const };
464
+ throw Cv.error({
465
+ code: "INVALID_PARAMETERS",
466
+ message: "The provided parameters are invalid.",
467
+ });
466
468
  }
467
469
  const deletions: Promise<unknown>[] = [];
468
470
  for (const s of sessions)
@@ -501,7 +503,7 @@ export function createCoreDomains(deps: CoreDeps) {
501
503
  );
502
504
  await Promise.all(deletions);
503
505
  await ctx.runMutation(config.component.public.userDelete, { userId });
504
- return { ok: true as const, userId };
506
+ return { userId };
505
507
  },
506
508
  };
507
509
 
@@ -547,7 +549,7 @@ export function createCoreDomains(deps: CoreDeps) {
547
549
  * @param ctx - Convex action context.
548
550
  * @param args.userId - The user whose sessions should be invalidated.
549
551
  * @param args.except - Optional array of session IDs to keep valid.
550
- * @returns `{ ok: true, userId, except }` confirming the operation.
552
+ * @returns `{ userId, except }` confirming the operation.
551
553
  *
552
554
  * @example Sign out everywhere except the current session
553
555
  * ```ts
@@ -564,7 +566,6 @@ export function createCoreDomains(deps: CoreDeps) {
564
566
  ) => {
565
567
  await callInvalidateSessions(ctx, args);
566
568
  return {
567
- ok: true as const,
568
569
  userId: args.userId,
569
570
  except: args.except ?? [],
570
571
  };
@@ -635,7 +636,7 @@ export function createCoreDomains(deps: CoreDeps) {
635
636
  * @param args.profile - Profile data used to create or update the user document.
636
637
  * @param args.shouldLinkViaEmail - If `true`, link to an existing user by email match.
637
638
  * @param args.shouldLinkViaPhone - If `true`, link to an existing user by phone match.
638
- * @returns `{ ok: true, ...created }` with the created account and user information.
639
+ * @returns The created account and user information.
639
640
  *
640
641
  * @example
641
642
  * ```ts
@@ -651,7 +652,7 @@ export function createCoreDomains(deps: CoreDeps) {
651
652
  args: CreateAccountArgs,
652
653
  ) => {
653
654
  const created = await callCreateAccountFromCredentials(ctx, args);
654
- return { ok: true as const, ...created };
655
+ return { ...created };
655
656
  },
656
657
  /**
657
658
  * Retrieve an auth account by provider and credentials.
@@ -700,7 +701,7 @@ export function createCoreDomains(deps: CoreDeps) {
700
701
  * @param args.provider - The provider ID (e.g. `"password"`).
701
702
  * @param args.account.id - Provider-specific account identifier.
702
703
  * @param args.account.secret - The new credential secret to store.
703
- * @returns `{ ok: true, accountId }` confirming the update.
704
+ * @returns `{ accountId }` confirming the update.
704
705
  *
705
706
  * @example Password reset
706
707
  * ```ts
@@ -715,7 +716,7 @@ export function createCoreDomains(deps: CoreDeps) {
715
716
  args: UpdateAccountCredentialsArgs,
716
717
  ) => {
717
718
  await callModifyAccount(ctx, args);
718
- return { ok: true as const, accountId: args.account.id };
719
+ return { accountId: args.account.id };
719
720
  },
720
721
  /**
721
722
  * Delete an auth account by ID.
@@ -727,16 +728,13 @@ export function createCoreDomains(deps: CoreDeps) {
727
728
  *
728
729
  * @param ctx - Convex mutation context.
729
730
  * @param accountId - The account's document ID.
730
- * @returns `{ ok: true, accountId }` on success, or
731
- * `{ ok: false, code: "ACCOUNT_NOT_FOUND" }` if the account does not exist, or
732
- * `{ ok: false, code: "INVALID_PARAMETERS" }` if it is the user's last account.
731
+ * @returns `{ accountId }` on success.
732
+ * @throws `ACCOUNT_NOT_FOUND` if the account does not exist.
733
+ * @throws `INVALID_PARAMETERS` if it is the user's last account.
733
734
  *
734
735
  * @example
735
736
  * ```ts
736
- * const result = await auth.account.delete(ctx, accountId);
737
- * if (!result.ok) {
738
- * console.error("Cannot delete account:", result.code);
739
- * }
737
+ * await auth.account.delete(ctx, accountId);
740
738
  * ```
741
739
  */
742
740
  delete: async (ctx: ComponentCtx, accountId: string) => {
@@ -744,19 +742,25 @@ export function createCoreDomains(deps: CoreDeps) {
744
742
  accountId,
745
743
  });
746
744
  if (doc === null) {
747
- return { ok: false as const, code: "ACCOUNT_NOT_FOUND" as const };
745
+ throw Cv.error({
746
+ code: "ACCOUNT_NOT_FOUND",
747
+ message: "Account not found.",
748
+ });
748
749
  }
749
750
  const allAccounts = (await ctx.runQuery(
750
751
  config.component.public.accountListByUser,
751
752
  { userId: (doc as any).userId },
752
753
  )) as Array<{ _id: string }>;
753
754
  if (allAccounts.length <= 1) {
754
- return { ok: false as const, code: "INVALID_PARAMETERS" as const };
755
+ throw Cv.error({
756
+ code: "INVALID_PARAMETERS",
757
+ message: "The provided parameters are invalid.",
758
+ });
755
759
  }
756
760
  await ctx.runMutation(config.component.public.accountDelete, {
757
761
  accountId,
758
762
  });
759
- return { ok: true as const, accountId };
763
+ return { accountId };
760
764
  },
761
765
  /**
762
766
  * List all passkey credentials registered for a user.
@@ -794,7 +798,7 @@ export function createCoreDomains(deps: CoreDeps) {
794
798
  * @param ctx - Convex mutation context.
795
799
  * @param passkeyId - The passkey credential's document ID.
796
800
  * @param name - The new display name for the passkey.
797
- * @returns `{ ok: true, passkeyId }` confirming the rename.
801
+ * @returns `{ passkeyId }` confirming the rename.
798
802
  *
799
803
  * @example
800
804
  * ```ts
@@ -810,7 +814,7 @@ export function createCoreDomains(deps: CoreDeps) {
810
814
  passkeyId,
811
815
  data: { name },
812
816
  });
813
- return { ok: true as const, passkeyId };
817
+ return { passkeyId };
814
818
  },
815
819
  /**
816
820
  * Delete a passkey credential.
@@ -821,7 +825,7 @@ export function createCoreDomains(deps: CoreDeps) {
821
825
  *
822
826
  * @param ctx - Convex mutation context.
823
827
  * @param passkeyId - The passkey credential's document ID.
824
- * @returns `{ ok: true, passkeyId }` confirming the deletion.
828
+ * @returns `{ passkeyId }` confirming the deletion.
825
829
  *
826
830
  * @example
827
831
  * ```ts
@@ -832,7 +836,7 @@ export function createCoreDomains(deps: CoreDeps) {
832
836
  await ctx.runMutation(config.component.public.passkeyDelete, {
833
837
  passkeyId,
834
838
  });
835
- return { ok: true as const, passkeyId };
839
+ return { passkeyId };
836
840
  },
837
841
  /**
838
842
  * List all TOTP (time-based one-time password) factors for a user.
@@ -863,7 +867,7 @@ export function createCoreDomains(deps: CoreDeps) {
863
867
  *
864
868
  * @param ctx - Convex mutation context.
865
869
  * @param totpId - The TOTP factor's document ID.
866
- * @returns `{ ok: true, totpId }` confirming the deletion.
870
+ * @returns `{ totpId }` confirming the deletion.
867
871
  *
868
872
  * @example
869
873
  * ```ts
@@ -872,7 +876,7 @@ export function createCoreDomains(deps: CoreDeps) {
872
876
  */
873
877
  deleteTotp: async (ctx: ComponentCtx, totpId: string) => {
874
878
  await ctx.runMutation(config.component.public.totpDelete, { totpId });
875
- return { ok: true as const, totpId };
879
+ return { totpId };
876
880
  },
877
881
  };
878
882
 
@@ -954,7 +958,7 @@ export function createCoreDomains(deps: CoreDeps) {
954
958
  * @param data.parentGroupId - Nest under this group. Omit for a root group.
955
959
  * @param data.tags - Faceted classification tags (normalized at write time).
956
960
  * @param data.extend - Arbitrary app-specific metadata.
957
- * @returns `{ ok: true, groupId }`.
961
+ * @returns `{ groupId }`.
958
962
  *
959
963
  * @example Root group
960
964
  * ```ts
@@ -980,12 +984,12 @@ export function createCoreDomains(deps: CoreDeps) {
980
984
  tags?: Array<{ key: string; value: string }>;
981
985
  extend?: Record<string, unknown>;
982
986
  },
983
- ): Promise<{ ok: true; groupId: string }> => {
987
+ ): Promise<{ groupId: string }> => {
984
988
  const groupId = (await ctx.runMutation(
985
989
  config.component.public.groupCreate,
986
990
  data,
987
991
  )) as string;
988
- return { ok: true, groupId };
992
+ return { groupId };
989
993
  },
990
994
  /**
991
995
  * Fetch a group document by ID.
@@ -1074,7 +1078,7 @@ export function createCoreDomains(deps: CoreDeps) {
1074
1078
  * @param ctx - Convex mutation context.
1075
1079
  * @param groupId - The group's document ID.
1076
1080
  * @param data - Fields to merge (e.g. `name`, `slug`, `tags`, `parentGroupId`).
1077
- * @returns `{ ok: true, groupId }`.
1081
+ * @returns `{ groupId }`.
1078
1082
  *
1079
1083
  * @example
1080
1084
  * ```ts
@@ -1093,7 +1097,7 @@ export function createCoreDomains(deps: CoreDeps) {
1093
1097
  groupId,
1094
1098
  data,
1095
1099
  });
1096
- return { ok: true as const, groupId };
1100
+ return { groupId };
1097
1101
  },
1098
1102
  /**
1099
1103
  * Delete a group and recursively cascade to all descendant groups,
@@ -1101,7 +1105,7 @@ export function createCoreDomains(deps: CoreDeps) {
1101
1105
  *
1102
1106
  * @param ctx - Convex mutation context.
1103
1107
  * @param groupId - The group's document ID.
1104
- * @returns `{ ok: true, groupId }`.
1108
+ * @returns `{ groupId }`.
1105
1109
  *
1106
1110
  * @example
1107
1111
  * ```ts
@@ -1110,7 +1114,7 @@ export function createCoreDomains(deps: CoreDeps) {
1110
1114
  */
1111
1115
  delete: async (ctx: ComponentCtx, groupId: string) => {
1112
1116
  await ctx.runMutation(config.component.public.groupDelete, { groupId });
1113
- return { ok: true as const, groupId };
1117
+ return { groupId };
1114
1118
  },
1115
1119
  /**
1116
1120
  * Walk up the group hierarchy from `groupId` and return all ancestor
@@ -1176,7 +1180,7 @@ export function createCoreDomains(deps: CoreDeps) {
1176
1180
  * Add a user to a group with optional role IDs.
1177
1181
  *
1178
1182
  * Role IDs are validated against the roles defined in `defineRoles()` —
1179
- * invalid IDs return `{ ok: false, code: "INVALID_ROLE_IDS" }`.
1183
+ * invalid IDs throw `INVALID_ROLE_IDS`.
1180
1184
  * Throws `DUPLICATE_MEMBERSHIP` if the user is already a member.
1181
1185
  *
1182
1186
  * @param ctx - Convex mutation context.
@@ -1185,7 +1189,8 @@ export function createCoreDomains(deps: CoreDeps) {
1185
1189
  * @param data.roleIds - Role IDs from `defineRoles()` (optional).
1186
1190
  * @param data.status - Membership status string (optional, app-defined).
1187
1191
  * @param data.extend - Arbitrary app-specific metadata.
1188
- * @returns `{ ok: true, memberId }` or `{ ok: false, code, invalidRoleIds }`.
1192
+ * @returns `{ memberId }`.
1193
+ * @throws `INVALID_ROLE_IDS` if any supplied role IDs are not defined.
1189
1194
  *
1190
1195
  * @example
1191
1196
  * ```ts
@@ -1206,18 +1211,12 @@ export function createCoreDomains(deps: CoreDeps) {
1206
1211
  extend?: Record<string, unknown>;
1207
1212
  },
1208
1213
  ) => {
1209
- const normalized = normalizeRoleIds(data.roleIds);
1210
- if (!normalized.ok)
1211
- return {
1212
- ok: false as const,
1213
- code: "INVALID_ROLE_IDS" as const,
1214
- invalidRoleIds: normalized.invalidRoleIds,
1215
- };
1214
+ const roleIds = normalizeRoleIds(data.roleIds);
1216
1215
  const memberId = (await ctx.runMutation(
1217
1216
  config.component.public.memberAdd,
1218
- { ...data, roleIds: normalized.roleIds },
1217
+ { ...data, roleIds },
1219
1218
  )) as string;
1220
- return { ok: true as const, memberId };
1219
+ return { memberId };
1221
1220
  },
1222
1221
  /**
1223
1222
  * Fetch a membership document by its document ID.
@@ -1291,7 +1290,7 @@ export function createCoreDomains(deps: CoreDeps) {
1291
1290
  *
1292
1291
  * @param ctx - Convex mutation context.
1293
1292
  * @param memberId - The membership document ID.
1294
- * @returns `{ ok: true, memberId }`.
1293
+ * @returns `{ memberId }`.
1295
1294
  *
1296
1295
  * @example
1297
1296
  * ```ts
@@ -1300,7 +1299,7 @@ export function createCoreDomains(deps: CoreDeps) {
1300
1299
  */
1301
1300
  delete: async (ctx: ComponentCtx, memberId: string) => {
1302
1301
  await ctx.runMutation(config.component.public.memberRemove, { memberId });
1303
- return { ok: true as const, memberId };
1302
+ return { memberId };
1304
1303
  },
1305
1304
  /**
1306
1305
  * Patch a membership's `roleIds`, `status`, or `extend` fields.
@@ -1309,7 +1308,8 @@ export function createCoreDomains(deps: CoreDeps) {
1309
1308
  * @param ctx - Convex mutation context.
1310
1309
  * @param memberId - The membership document ID.
1311
1310
  * @param data - Fields to merge. `roleIds` are validated.
1312
- * @returns `{ ok: true, memberId }` or `{ ok: false, code: "INVALID_ROLE_IDS" }`.
1311
+ * @returns `{ memberId }`.
1312
+ * @throws `INVALID_ROLE_IDS` if any supplied role IDs are not defined.
1313
1313
  *
1314
1314
  * @example
1315
1315
  * ```ts
@@ -1326,24 +1326,17 @@ export function createCoreDomains(deps: CoreDeps) {
1326
1326
  ) => {
1327
1327
  const nextData = { ...data };
1328
1328
  if ("roleIds" in nextData) {
1329
- const normalized = normalizeRoleIds(
1329
+ nextData.roleIds = normalizeRoleIds(
1330
1330
  Array.isArray(nextData.roleIds)
1331
1331
  ? (nextData.roleIds as string[])
1332
1332
  : undefined,
1333
1333
  );
1334
- if (!normalized.ok)
1335
- return {
1336
- ok: false as const,
1337
- code: "INVALID_ROLE_IDS" as const,
1338
- invalidRoleIds: normalized.invalidRoleIds,
1339
- };
1340
- nextData.roleIds = normalized.roleIds;
1341
1334
  }
1342
1335
  await ctx.runMutation(config.component.public.memberUpdate, {
1343
1336
  memberId,
1344
1337
  data: nextData,
1345
1338
  });
1346
- return { ok: true as const, memberId };
1339
+ return { memberId };
1347
1340
  },
1348
1341
  /**
1349
1342
  * Resolve a user's membership in a group, optionally walking the
@@ -1364,72 +1357,42 @@ export function createCoreDomains(deps: CoreDeps) {
1364
1357
  * @param opts.userId - The user's document ID.
1365
1358
  * @param opts.groupId - The group to check membership in.
1366
1359
  * @param opts.ancestry - Walk the hierarchy (default `false`).
1367
- * @param opts.grants - Grant strings to check (optional).
1368
- * @param opts.roleIds - Role IDs to filter by (optional).
1369
1360
  * @param opts.maxDepth - Max hierarchy levels (default 32, only with ancestry).
1370
- * @returns `{ ok, membership, roleIds, grants, missingGrants, ... }`.
1371
- * `ok` is `true` when membership exists and all requested grants are satisfied.
1361
+ * @returns `{ membership, roleIds, grants }`.
1372
1362
  *
1373
1363
  * @example Direct lookup
1374
1364
  * ```ts
1375
- * const result = await auth.member.resolve(ctx, { userId, groupId });
1376
- * if (!result.membership) return { ok: false, code: "NOT_A_MEMBER" };
1365
+ * const result = await auth.member.inspect(ctx, { userId, groupId });
1366
+ * if (!result.membership) return null;
1377
1367
  * ```
1378
1368
  *
1379
- * @example Check grants (no hierarchy walk)
1369
+ * @example Check grants after inspection
1380
1370
  * ```ts
1381
- * const result = await auth.member.resolve(ctx, {
1382
- * userId, groupId, grants: ["issues.create"],
1371
+ * const result = await auth.member.inspect(ctx, {
1372
+ * userId, groupId,
1383
1373
  * });
1384
- * if (!result.ok) return { ok: false, code: "FORBIDDEN" };
1374
+ * const canCreate = result.grants.includes("issues.create");
1385
1375
  * ```
1386
1376
  *
1387
1377
  * @example Walk hierarchy + check grants
1388
1378
  * ```ts
1389
- * const result = await auth.member.resolve(ctx, {
1390
- * userId, groupId: teamId, ancestry: true, grants: ["issues.create"],
1379
+ * const result = await auth.member.inspect(ctx, {
1380
+ * userId, groupId: teamId, ancestry: true,
1391
1381
  * });
1392
1382
  * ```
1393
1383
  */
1394
- resolve: async (
1384
+ inspect: async (
1395
1385
  ctx: ComponentReadCtx,
1396
1386
  opts: {
1397
1387
  userId: string;
1398
1388
  groupId: string;
1399
1389
  ancestry?: boolean;
1400
- roleIds?: string[];
1401
- grants?: string[];
1402
1390
  maxDepth?: number;
1403
1391
  },
1404
1392
  ) => {
1405
- const normalized = normalizeRoleIds(opts.roleIds);
1406
- if (!normalized.ok)
1407
- return {
1408
- ok: false as const,
1409
- membership: null,
1410
- matchedGroupId: null,
1411
- roleIds: [] as string[],
1412
- grants: [] as string[],
1413
- missingGrants: Array.from(new Set(opts.grants ?? [])),
1414
- depth: null,
1415
- isDirect: false,
1416
- isInherited: false,
1417
- traversedGroupIds: [] as string[],
1418
- code: "INVALID_ROLE_IDS" as const,
1419
- invalidRoleIds: normalized.invalidRoleIds,
1420
- };
1421
- const requestedRoleIds = normalized.roleIds;
1422
- const roleFilter =
1423
- requestedRoleIds.length > 0 ? new Set(requestedRoleIds) : null;
1424
- const requiredGrants = Array.from(new Set(opts.grants ?? []));
1425
1393
  const useAncestry = opts.ancestry === true;
1426
1394
 
1427
1395
  let membership: any = null;
1428
- let matchedGroupId: string | null = null;
1429
- let depth: number | null = null;
1430
- let isDirect = false;
1431
- let isInherited = false;
1432
- let traversedGroupIds: string[] = [];
1433
1396
 
1434
1397
  if (useAncestry) {
1435
1398
  // Hierarchy walk — single component RPC
@@ -1444,11 +1407,6 @@ export function createCoreDomains(deps: CoreDeps) {
1444
1407
  },
1445
1408
  );
1446
1409
  membership = result.membership;
1447
- matchedGroupId = result.matchedGroupId;
1448
- depth = result.depth;
1449
- isDirect = result.isDirect;
1450
- isInherited = result.isInherited;
1451
- traversedGroupIds = result.traversedGroupIds ?? [];
1452
1410
  } else {
1453
1411
  // Fast path — direct lookup, 1 read
1454
1412
  const doc = await ctx.runQuery(
@@ -1456,64 +1414,75 @@ export function createCoreDomains(deps: CoreDeps) {
1456
1414
  { userId: opts.userId, groupId: opts.groupId },
1457
1415
  );
1458
1416
  membership = doc;
1459
- matchedGroupId = doc ? opts.groupId : null;
1460
- depth = doc ? 0 : null;
1461
- isDirect = doc !== null;
1462
1417
  }
1463
1418
 
1464
1419
  if (membership === null) {
1465
1420
  return {
1466
- ok: false as const,
1467
1421
  membership: null,
1468
- matchedGroupId: null,
1469
1422
  roleIds: [] as string[],
1470
1423
  grants: [] as string[],
1471
- missingGrants: requiredGrants,
1472
- depth: null,
1473
- isDirect: false,
1474
- isInherited: false,
1475
- traversedGroupIds,
1476
1424
  };
1477
1425
  }
1478
1426
 
1479
1427
  const membershipRoleIds = membership.roleIds ?? [];
1480
1428
  const membershipGrants = resolveGrantedPermissions(membershipRoleIds);
1481
1429
 
1482
- // Check role filter
1430
+ return {
1431
+ membership,
1432
+ roleIds: membershipRoleIds,
1433
+ grants: membershipGrants,
1434
+ };
1435
+ },
1436
+ require: async (
1437
+ ctx: ComponentReadCtx,
1438
+ opts: {
1439
+ userId: string;
1440
+ groupId: string;
1441
+ ancestry?: boolean;
1442
+ roleIds?: string[];
1443
+ grants?: string[];
1444
+ maxDepth?: number;
1445
+ },
1446
+ ) => {
1447
+ const validatedRoleIds = normalizeRoleIds(opts.roleIds);
1448
+ const requiredGrants = Array.from(new Set(opts.grants ?? []));
1449
+ const roleFilter =
1450
+ validatedRoleIds.length > 0 ? new Set(validatedRoleIds) : null;
1451
+ const result = await member.inspect(ctx, {
1452
+ userId: opts.userId,
1453
+ groupId: opts.groupId,
1454
+ ancestry: opts.ancestry,
1455
+ maxDepth: opts.maxDepth,
1456
+ });
1457
+ if (result.membership === null) {
1458
+ throw Cv.error({
1459
+ code: "NOT_A_MEMBER",
1460
+ message: "User is not a member of this group.",
1461
+ groupId: opts.groupId,
1462
+ });
1463
+ }
1483
1464
  if (
1484
1465
  roleFilter !== null &&
1485
- !membershipRoleIds.some((roleId: string) => roleFilter.has(roleId))
1466
+ !result.roleIds.some((roleId: string) => roleFilter.has(roleId))
1486
1467
  ) {
1487
- return {
1488
- ok: false as const,
1489
- membership: null,
1490
- matchedGroupId: null,
1491
- roleIds: [] as string[],
1492
- grants: [] as string[],
1493
- missingGrants: requiredGrants,
1494
- depth: null,
1495
- isDirect: false,
1496
- isInherited: false,
1497
- traversedGroupIds,
1498
- };
1468
+ throw Cv.error({
1469
+ code: "NOT_A_MEMBER",
1470
+ message: "User is not a member of this group.",
1471
+ groupId: opts.groupId,
1472
+ });
1499
1473
  }
1500
-
1501
1474
  const missingGrants = requiredGrants.filter(
1502
- (grant) => !membershipGrants.includes(grant),
1475
+ (grant) => !result.grants.includes(grant),
1503
1476
  );
1504
-
1505
- return {
1506
- ok: missingGrants.length === 0,
1507
- membership,
1508
- matchedGroupId,
1509
- roleIds: membershipRoleIds,
1510
- grants: membershipGrants,
1511
- missingGrants,
1512
- depth,
1513
- isDirect,
1514
- isInherited,
1515
- traversedGroupIds,
1516
- };
1477
+ if (missingGrants.length > 0) {
1478
+ throw Cv.error({
1479
+ code: "MISSING_GRANTS",
1480
+ message: "User is missing required grants.",
1481
+ groupId: opts.groupId,
1482
+ missingGrants,
1483
+ });
1484
+ }
1485
+ return result;
1517
1486
  },
1518
1487
  };
1519
1488
 
@@ -1529,7 +1498,8 @@ export function createCoreDomains(deps: CoreDeps) {
1529
1498
  * @param data.roleIds - Role IDs from `defineRoles()` to assign on acceptance (optional).
1530
1499
  * @param data.expiresTime - Expiration timestamp in ms since epoch (optional).
1531
1500
  * @param data.extend - Arbitrary app-specific metadata (optional).
1532
- * @returns `{ ok: true, inviteId, token }` or `{ ok: false, code: "INVALID_ROLE_IDS" }`.
1501
+ * @returns `{ inviteId, token }`.
1502
+ * @throws `INVALID_ROLE_IDS` if any supplied role IDs are not defined.
1533
1503
  *
1534
1504
  * @example
1535
1505
  * ```ts
@@ -1549,13 +1519,7 @@ export function createCoreDomains(deps: CoreDeps) {
1549
1519
  extend?: Record<string, unknown>;
1550
1520
  },
1551
1521
  ) => {
1552
- const normalized = normalizeRoleIds(data.roleIds);
1553
- if (!normalized.ok)
1554
- return {
1555
- ok: false as const,
1556
- code: "INVALID_ROLE_IDS" as const,
1557
- invalidRoleIds: normalized.invalidRoleIds,
1558
- };
1522
+ const roleIds = normalizeRoleIds(data.roleIds);
1559
1523
  const token = generateRandomString(
1560
1524
  inviteTokenLength,
1561
1525
  inviteTokenAlphabet,
@@ -1563,9 +1527,9 @@ export function createCoreDomains(deps: CoreDeps) {
1563
1527
  const tokenHash = await sha256(token);
1564
1528
  const inviteId = (await ctx.runMutation(
1565
1529
  config.component.public.inviteCreate,
1566
- { ...data, roleIds: normalized.roleIds, tokenHash, status: "pending" },
1530
+ { ...data, roleIds, tokenHash, status: "pending" },
1567
1531
  )) as string;
1568
- return { ok: true as const, inviteId, token };
1532
+ return { inviteId, token };
1569
1533
  },
1570
1534
  /**
1571
1535
  * Fetch an invite document by ID.
@@ -1628,7 +1592,7 @@ export function createCoreDomains(deps: CoreDeps) {
1628
1592
  * @param ctx - Convex mutation context.
1629
1593
  * @param args.token - The raw invite token string.
1630
1594
  * @param args.acceptedByUserId - The user accepting the invite.
1631
- * @returns `{ ok: true, ...result }` with the created membership details.
1595
+ * @returns The created membership details.
1632
1596
  *
1633
1597
  * @example
1634
1598
  * ```ts
@@ -1647,7 +1611,7 @@ export function createCoreDomains(deps: CoreDeps) {
1647
1611
  config.component.public.inviteAcceptByToken,
1648
1612
  { tokenHash, acceptedByUserId: args.acceptedByUserId },
1649
1613
  );
1650
- return { ok: true as const, ...result };
1614
+ return { ...result };
1651
1615
  },
1652
1616
  },
1653
1617
  /**
@@ -1715,7 +1679,7 @@ export function createCoreDomains(deps: CoreDeps) {
1715
1679
  * @param ctx - Convex mutation context.
1716
1680
  * @param inviteId - The invite's document ID.
1717
1681
  * @param acceptedByUserId - The user who accepted the invite (optional).
1718
- * @returns `{ ok: true, inviteId, acceptedByUserId }`.
1682
+ * @returns `{ inviteId, acceptedByUserId }`.
1719
1683
  *
1720
1684
  * @example
1721
1685
  * ```ts
@@ -1732,7 +1696,6 @@ export function createCoreDomains(deps: CoreDeps) {
1732
1696
  ...(acceptedByUserId ? { acceptedByUserId } : {}),
1733
1697
  });
1734
1698
  return {
1735
- ok: true as const,
1736
1699
  inviteId,
1737
1700
  acceptedByUserId: acceptedByUserId ?? null,
1738
1701
  };
@@ -1745,7 +1708,7 @@ export function createCoreDomains(deps: CoreDeps) {
1745
1708
  *
1746
1709
  * @param ctx - Convex mutation context.
1747
1710
  * @param inviteId - The invite's document ID.
1748
- * @returns `{ ok: true, inviteId }`.
1711
+ * @returns `{ inviteId }`.
1749
1712
  *
1750
1713
  * @example
1751
1714
  * ```ts
@@ -1754,7 +1717,7 @@ export function createCoreDomains(deps: CoreDeps) {
1754
1717
  */
1755
1718
  revoke: async (ctx: ComponentCtx, inviteId: string) => {
1756
1719
  await ctx.runMutation(config.component.public.inviteRevoke, { inviteId });
1757
- return { ok: true as const, inviteId };
1720
+ return { inviteId };
1758
1721
  },
1759
1722
  };
1760
1723
 
@@ -1770,7 +1733,7 @@ export function createCoreDomains(deps: CoreDeps) {
1770
1733
  * @param opts.rateLimit - Optional per-key rate limit `{ maxRequests, windowMs }`.
1771
1734
  * @param opts.expiresAt - Optional expiration timestamp (ms since epoch).
1772
1735
  * @param opts.metadata - Arbitrary app-specific metadata.
1773
- * @returns `{ ok: true, keyId, secret }`. Store `secret` securely — it cannot be retrieved later.
1736
+ * @returns `{ keyId, secret }`. Store `secret` securely — it cannot be retrieved later.
1774
1737
  *
1775
1738
  * @example
1776
1739
  * ```ts
@@ -1791,7 +1754,7 @@ export function createCoreDomains(deps: CoreDeps) {
1791
1754
  expiresAt?: number;
1792
1755
  metadata?: Record<string, unknown>;
1793
1756
  },
1794
- ): Promise<{ ok: true; keyId: string; secret: string }> => {
1757
+ ): Promise<{ keyId: string; secret: string }> => {
1795
1758
  const { raw, hashedKey, displayPrefix } = await generateApiKey("sk_");
1796
1759
  const keyId = (await ctx.runMutation(config.component.public.keyInsert, {
1797
1760
  userId: opts.userId,
@@ -1803,7 +1766,7 @@ export function createCoreDomains(deps: CoreDeps) {
1803
1766
  expiresAt: opts.expiresAt,
1804
1767
  metadata: opts.metadata,
1805
1768
  })) as string;
1806
- return { ok: true, keyId, secret: raw };
1769
+ return { keyId, secret: raw };
1807
1770
  },
1808
1771
  /**
1809
1772
  * Verify an API key and return the owner's identity and scopes.
@@ -1813,48 +1776,45 @@ export function createCoreDomains(deps: CoreDeps) {
1813
1776
  *
1814
1777
  * @param ctx - Convex mutation context (updates `lastUsedAt` and rate limit state).
1815
1778
  * @param rawKey - The raw `sk_*` key string.
1816
- * @returns On success: `{ ok: true, userId, keyId, scopes }` where `scopes.can(resource, action)` checks permissions.
1817
- * On failure: `{ ok: false, code }` with one of:
1818
- * - `"INVALID_API_KEY"` key not found.
1819
- * - `"API_KEY_REVOKED"` key was revoked.
1820
- * - `"API_KEY_EXPIRED"` key past its `expiresAt`.
1821
- * - `"API_KEY_RATE_LIMITED"` — rate limit exceeded.
1779
+ * @returns `{ userId, keyId, scopes }` where `scopes.can(resource, action)` checks permissions.
1780
+ * @throws `INVALID_API_KEY` if the key is not found.
1781
+ * @throws `API_KEY_REVOKED` if the key was revoked.
1782
+ * @throws `API_KEY_EXPIRED` if the key is past its `expiresAt`.
1783
+ * @throws `API_KEY_RATE_LIMITED` if the rate limit is exceeded.
1822
1784
  *
1823
1785
  * @example
1824
1786
  * ```ts
1825
- * const result = await auth.key.verify(ctx, rawKey);
1826
- * if (!result.ok) return { ok: false, code: result.code };
1827
- * const canRead = result.scopes.can("data", "read");
1787
+ * const { userId, scopes } = await auth.key.verify(ctx, rawKey);
1788
+ * const canRead = scopes.can("data", "read");
1828
1789
  * ```
1829
1790
  */
1830
1791
  verify: async (
1831
1792
  ctx: ComponentCtx,
1832
1793
  rawKey: string,
1833
- ): Promise<
1834
- | { ok: true; userId: string; keyId: string; scopes: ScopeChecker }
1835
- | {
1836
- ok: false;
1837
- code:
1838
- | "INVALID_API_KEY"
1839
- | "API_KEY_REVOKED"
1840
- | "API_KEY_EXPIRED"
1841
- | "API_KEY_RATE_LIMITED";
1842
- }
1843
- > => {
1794
+ ): Promise<{ userId: string; keyId: string; scopes: ScopeChecker }> => {
1844
1795
  const hashedKey = await hashApiKey(rawKey);
1845
1796
  const doc = (await ctx.runQuery(
1846
1797
  config.component.public.keyGetByHashedKey,
1847
1798
  { hashedKey },
1848
1799
  )) as KeyDoc | null;
1849
1800
  if (!doc) {
1850
- return { ok: false as const, code: "INVALID_API_KEY" as const };
1801
+ throw Cv.error({
1802
+ code: "INVALID_API_KEY",
1803
+ message: "Invalid API key.",
1804
+ });
1851
1805
  }
1852
1806
  const k = doc;
1853
1807
  if (k.revoked) {
1854
- return { ok: false as const, code: "API_KEY_REVOKED" as const };
1808
+ throw Cv.error({
1809
+ code: "API_KEY_REVOKED",
1810
+ message: "This API key has been revoked.",
1811
+ });
1855
1812
  }
1856
1813
  if (k.expiresAt && k.expiresAt < Date.now()) {
1857
- return { ok: false as const, code: "API_KEY_EXPIRED" as const };
1814
+ throw Cv.error({
1815
+ code: "API_KEY_EXPIRED",
1816
+ message: "This API key has expired.",
1817
+ });
1858
1818
  }
1859
1819
  const patchData: Record<string, unknown> = { lastUsedAt: Date.now() };
1860
1820
  if (k.rateLimit) {
@@ -1863,7 +1823,10 @@ export function createCoreDomains(deps: CoreDeps) {
1863
1823
  k.rateLimitState ?? undefined,
1864
1824
  );
1865
1825
  if (limited) {
1866
- return { ok: false as const, code: "API_KEY_RATE_LIMITED" as const };
1826
+ throw Cv.error({
1827
+ code: "API_KEY_RATE_LIMITED",
1828
+ message: "API key rate limit exceeded. Please try again later.",
1829
+ });
1867
1830
  }
1868
1831
  patchData.rateLimitState = newState;
1869
1832
  }
@@ -1872,7 +1835,6 @@ export function createCoreDomains(deps: CoreDeps) {
1872
1835
  data: patchData,
1873
1836
  });
1874
1837
  return {
1875
- ok: true as const,
1876
1838
  userId: k.userId,
1877
1839
  keyId: k._id,
1878
1840
  scopes: buildScopeChecker(k.scopes),
@@ -1936,24 +1898,23 @@ export function createCoreDomains(deps: CoreDeps) {
1936
1898
  *
1937
1899
  * @param ctx - Convex query or mutation context.
1938
1900
  * @param keyId - The API key's document ID.
1939
- * @returns `{ ok: true, key }` with the key document, or `{ ok: false }` if not found.
1901
+ * @returns The key document, or `null` if not found.
1940
1902
  *
1941
1903
  * @example
1942
1904
  * ```ts
1943
- * const result = await auth.key.get(ctx, keyId);
1944
- * if (!result.ok) throw new Error("Key not found");
1945
- * console.log(result.key.name, result.key.prefix);
1905
+ * const key = await auth.key.get(ctx, keyId);
1906
+ * if (!key) throw new Error("Key not found");
1907
+ * console.log(key.name, key.prefix);
1946
1908
  * ```
1947
1909
  */
1948
1910
  get: async (
1949
1911
  ctx: ComponentReadCtx,
1950
1912
  keyId: string,
1951
- ): Promise<{ ok: true; key: KeyDoc } | { ok: false }> => {
1913
+ ): Promise<KeyDoc | null> => {
1952
1914
  const doc = (await ctx.runQuery(config.component.public.keyGetById, {
1953
1915
  keyId,
1954
1916
  })) as KeyDoc | null;
1955
- if (!doc) return { ok: false as const };
1956
- return { ok: true as const, key: doc };
1917
+ return doc ?? null;
1957
1918
  },
1958
1919
  /**
1959
1920
  * Update a key's name, scopes, or rate limit.
@@ -1964,7 +1925,7 @@ export function createCoreDomains(deps: CoreDeps) {
1964
1925
  * @param ctx - Convex mutation context.
1965
1926
  * @param keyId - The API key's document ID.
1966
1927
  * @param data - Fields to merge into the key document.
1967
- * @returns `{ ok: true, keyId }`.
1928
+ * @returns `{ keyId }`.
1968
1929
  *
1969
1930
  * @example
1970
1931
  * ```ts
@@ -1984,18 +1945,18 @@ export function createCoreDomains(deps: CoreDeps) {
1984
1945
  },
1985
1946
  ) => {
1986
1947
  await ctx.runMutation(config.component.public.keyPatch, { keyId, data });
1987
- return { ok: true as const, keyId };
1948
+ return { keyId };
1988
1949
  },
1989
1950
  /**
1990
1951
  * Soft-delete: set `revoked: true`. The key can no longer be verified.
1991
1952
  *
1992
1953
  * After revocation, any subsequent calls to `auth.key.verify` with
1993
- * this key will return `{ ok: false, code: "API_KEY_REVOKED" }`.
1954
+ * this key will throw `API_KEY_REVOKED`.
1994
1955
  * The key record is preserved for audit purposes.
1995
1956
  *
1996
1957
  * @param ctx - Convex mutation context.
1997
1958
  * @param keyId - The API key's document ID.
1998
- * @returns `{ ok: true, keyId }`.
1959
+ * @returns `{ keyId }`.
1999
1960
  *
2000
1961
  * @example
2001
1962
  * ```ts
@@ -2007,7 +1968,7 @@ export function createCoreDomains(deps: CoreDeps) {
2007
1968
  keyId,
2008
1969
  data: { revoked: true },
2009
1970
  });
2010
- return { ok: true as const, keyId };
1971
+ return { keyId };
2011
1972
  },
2012
1973
  /**
2013
1974
  * Hard-delete: permanently remove the key record.
@@ -2018,7 +1979,7 @@ export function createCoreDomains(deps: CoreDeps) {
2018
1979
  *
2019
1980
  * @param ctx - Convex mutation context.
2020
1981
  * @param keyId - The API key's document ID.
2021
- * @returns `{ ok: true, keyId }`.
1982
+ * @returns `{ keyId }`.
2022
1983
  *
2023
1984
  * @example
2024
1985
  * ```ts
@@ -2027,45 +1988,48 @@ export function createCoreDomains(deps: CoreDeps) {
2027
1988
  */
2028
1989
  delete: async (ctx: ComponentCtx, keyId: string) => {
2029
1990
  await ctx.runMutation(config.component.public.keyDelete, { keyId });
2030
- return { ok: true as const, keyId };
1991
+ return { keyId };
2031
1992
  },
2032
1993
  /**
2033
1994
  * Rotate a key: revokes the old key and creates a new one with the
2034
1995
  * same user, scopes, and rate limit. Returns the new `keyId` and `secret`.
2035
- * Fails with `{ ok: false }` if the key is already revoked.
1996
+ * Throws if the key does not exist or is already revoked.
2036
1997
  *
2037
1998
  * @param ctx - Convex mutation context.
2038
1999
  * @param keyId - The existing API key's document ID to rotate.
2039
2000
  * @param opts.name - Optional new name for the rotated key (defaults to the old name).
2040
2001
  * @param opts.expiresAt - Optional new expiration timestamp in ms since epoch.
2041
- * @returns `{ ok: true, keyId, secret }` with the new key, or `{ ok: false, code }` on failure.
2002
+ * @returns `{ keyId, secret }` with the new key.
2003
+ * @throws `INVALID_PARAMETERS` if the key does not exist.
2004
+ * @throws `API_KEY_REVOKED` if the key is already revoked.
2042
2005
  *
2043
2006
  * @example
2044
2007
  * ```ts
2045
- * const result = await auth.key.rotate(ctx, oldKeyId, {
2008
+ * const { keyId, secret } = await auth.key.rotate(ctx, oldKeyId, {
2046
2009
  * expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days
2047
2010
  * });
2048
- * if (result.ok) {
2049
- * // Store result.secret securely — shown only once
2050
- * }
2011
+ * // Store secret securely — shown only once
2051
2012
  * ```
2052
2013
  */
2053
2014
  rotate: async (
2054
2015
  ctx: ComponentCtx,
2055
2016
  keyId: string,
2056
2017
  opts?: { name?: string; expiresAt?: number },
2057
- ): Promise<
2058
- | { ok: true; keyId: string; secret: string }
2059
- | { ok: false; code: "INVALID_PARAMETERS" | "API_KEY_REVOKED" }
2060
- > => {
2018
+ ): Promise<{ keyId: string; secret: string }> => {
2061
2019
  const existing = await ctx.runQuery(config.component.public.keyGetById, {
2062
2020
  keyId,
2063
2021
  });
2064
2022
  if (!existing) {
2065
- return { ok: false as const, code: "INVALID_PARAMETERS" as const };
2023
+ throw Cv.error({
2024
+ code: "INVALID_PARAMETERS",
2025
+ message: "The provided parameters are invalid.",
2026
+ });
2066
2027
  }
2067
2028
  if ((existing as any).revoked === true) {
2068
- return { ok: false as const, code: "API_KEY_REVOKED" as const };
2029
+ throw Cv.error({
2030
+ code: "API_KEY_REVOKED",
2031
+ message: "This API key has been revoked.",
2032
+ });
2069
2033
  }
2070
2034
  await ctx.runMutation(config.component.public.keyPatch, {
2071
2035
  keyId,