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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/README.md +140 -9
  2. package/dist/bin.cjs +5957 -5478
  3. package/dist/client/index.d.ts +3 -7
  4. package/dist/client/index.d.ts.map +1 -1
  5. package/dist/client/index.js +27 -26
  6. package/dist/client/index.js.map +1 -1
  7. package/dist/component/_generated/api.d.ts +14 -0
  8. package/dist/component/_generated/api.d.ts.map +1 -1
  9. package/dist/component/_generated/api.js.map +1 -1
  10. package/dist/component/_generated/component.d.ts +1672 -24
  11. package/dist/component/_generated/component.d.ts.map +1 -1
  12. package/dist/component/convex.config.d.ts +2 -2
  13. package/dist/component/convex.config.d.ts.map +1 -1
  14. package/dist/component/index.d.ts +1 -1
  15. package/dist/component/index.js +2 -2
  16. package/dist/component/model.d.ts +153 -0
  17. package/dist/component/model.d.ts.map +1 -0
  18. package/dist/component/model.js +343 -0
  19. package/dist/component/model.js.map +1 -0
  20. package/dist/component/providers/sso.d.ts +1 -1
  21. package/dist/component/public/enterprise.d.ts +54 -0
  22. package/dist/component/public/enterprise.d.ts.map +1 -0
  23. package/dist/component/public/enterprise.js +515 -0
  24. package/dist/component/public/enterprise.js.map +1 -0
  25. package/dist/component/public/factors.d.ts +52 -0
  26. package/dist/component/public/factors.d.ts.map +1 -0
  27. package/dist/component/public/factors.js +285 -0
  28. package/dist/component/public/factors.js.map +1 -0
  29. package/dist/component/public/groups.d.ts +116 -0
  30. package/dist/component/public/groups.d.ts.map +1 -0
  31. package/dist/component/public/groups.js +596 -0
  32. package/dist/component/public/groups.js.map +1 -0
  33. package/dist/component/public/identity.d.ts +93 -0
  34. package/dist/component/public/identity.d.ts.map +1 -0
  35. package/dist/component/public/identity.js +426 -0
  36. package/dist/component/public/identity.js.map +1 -0
  37. package/dist/component/public/keys.d.ts +41 -0
  38. package/dist/component/public/keys.d.ts.map +1 -0
  39. package/dist/component/public/keys.js +157 -0
  40. package/dist/component/public/keys.js.map +1 -0
  41. package/dist/component/public/shared.d.ts +26 -0
  42. package/dist/component/public/shared.d.ts.map +1 -0
  43. package/dist/component/public/shared.js +32 -0
  44. package/dist/component/public/shared.js.map +1 -0
  45. package/dist/component/public.d.ts +9 -321
  46. package/dist/component/public.d.ts.map +1 -1
  47. package/dist/component/public.js +6 -2145
  48. package/dist/component/schema.d.ts +406 -260
  49. package/dist/component/schema.js +37 -32
  50. package/dist/component/schema.js.map +1 -1
  51. package/dist/component/server/auth.d.ts +161 -15
  52. package/dist/component/server/auth.d.ts.map +1 -1
  53. package/dist/component/server/auth.js +100 -7
  54. package/dist/component/server/auth.js.map +1 -1
  55. package/dist/component/server/cookies.js +3 -0
  56. package/dist/component/server/cookies.js.map +1 -1
  57. package/dist/component/server/db.js +1 -0
  58. package/dist/component/server/db.js.map +1 -1
  59. package/dist/component/server/device.js +3 -1
  60. package/dist/component/server/device.js.map +1 -1
  61. package/dist/component/server/domains/core.js +629 -0
  62. package/dist/component/server/domains/core.js.map +1 -0
  63. package/dist/component/server/domains/sso.js +884 -0
  64. package/dist/component/server/domains/sso.js.map +1 -0
  65. package/dist/component/server/factory.d.ts +136 -0
  66. package/dist/component/server/factory.d.ts.map +1 -0
  67. package/dist/component/server/factory.js +1134 -0
  68. package/dist/component/server/factory.js.map +1 -0
  69. package/dist/component/server/fx.js +2 -1
  70. package/dist/component/server/fx.js.map +1 -1
  71. package/dist/component/server/http.js +287 -0
  72. package/dist/component/server/http.js.map +1 -0
  73. package/dist/component/server/identity.js +13 -0
  74. package/dist/component/server/identity.js.map +1 -0
  75. package/dist/component/server/keys.js +4 -0
  76. package/dist/component/server/keys.js.map +1 -1
  77. package/dist/component/server/mutations/account.js +1 -1
  78. package/dist/component/server/mutations/index.js +2 -2
  79. package/dist/component/server/mutations/index.js.map +1 -1
  80. package/dist/component/server/mutations/invalidate.js +1 -1
  81. package/dist/component/server/mutations/oauth.js +10 -7
  82. package/dist/component/server/mutations/oauth.js.map +1 -1
  83. package/dist/component/server/mutations/refresh.js +1 -1
  84. package/dist/component/server/mutations/register.js +1 -1
  85. package/dist/component/server/mutations/retrieve.js +1 -1
  86. package/dist/component/server/mutations/signature.js +1 -1
  87. package/dist/component/server/mutations/store.js +6 -3
  88. package/dist/component/server/mutations/store.js.map +1 -1
  89. package/dist/component/server/mutations/verify.js +1 -1
  90. package/dist/component/server/oauth.js +3 -0
  91. package/dist/component/server/oauth.js.map +1 -1
  92. package/dist/component/server/passkey.js +3 -2
  93. package/dist/component/server/passkey.js.map +1 -1
  94. package/dist/component/server/provider.js +2 -0
  95. package/dist/component/server/provider.js.map +1 -1
  96. package/dist/component/server/providers.js +10 -0
  97. package/dist/component/server/providers.js.map +1 -1
  98. package/dist/component/server/ratelimit.js +3 -0
  99. package/dist/component/server/ratelimit.js.map +1 -1
  100. package/dist/component/server/redirects.js +2 -0
  101. package/dist/component/server/redirects.js.map +1 -1
  102. package/dist/component/server/refresh.js +5 -0
  103. package/dist/component/server/refresh.js.map +1 -1
  104. package/dist/component/server/sessions.js +5 -0
  105. package/dist/component/server/sessions.js.map +1 -1
  106. package/dist/component/server/signin.js +2 -1
  107. package/dist/component/server/signin.js.map +1 -1
  108. package/dist/component/server/sso.js +166 -19
  109. package/dist/component/server/sso.js.map +1 -1
  110. package/dist/component/server/tokens.js +1 -0
  111. package/dist/component/server/tokens.js.map +1 -1
  112. package/dist/component/server/totp.js +4 -2
  113. package/dist/component/server/totp.js.map +1 -1
  114. package/dist/component/server/types.d.ts +106 -38
  115. package/dist/component/server/types.d.ts.map +1 -1
  116. package/dist/component/server/types.js.map +1 -1
  117. package/dist/component/server/users.js +1 -0
  118. package/dist/component/server/users.js.map +1 -1
  119. package/dist/component/server/utils.js +44 -2
  120. package/dist/component/server/utils.js.map +1 -1
  121. package/dist/providers/anonymous.d.ts +1 -1
  122. package/dist/providers/credentials.d.ts +1 -1
  123. package/dist/providers/password.d.ts +1 -1
  124. package/dist/providers/sso.d.ts +1 -1
  125. package/dist/providers/sso.js.map +1 -1
  126. package/dist/server/auth.d.ts +163 -17
  127. package/dist/server/auth.d.ts.map +1 -1
  128. package/dist/server/auth.js +100 -7
  129. package/dist/server/auth.js.map +1 -1
  130. package/dist/server/cookies.d.ts +1 -38
  131. package/dist/server/cookies.js +3 -0
  132. package/dist/server/cookies.js.map +1 -1
  133. package/dist/server/db.d.ts +1 -125
  134. package/dist/server/db.js +1 -0
  135. package/dist/server/db.js.map +1 -1
  136. package/dist/server/device.d.ts +1 -24
  137. package/dist/server/device.js +3 -1
  138. package/dist/server/device.js.map +1 -1
  139. package/dist/server/domains/core.d.ts +434 -0
  140. package/dist/server/domains/core.d.ts.map +1 -0
  141. package/dist/server/domains/core.js +629 -0
  142. package/dist/server/domains/core.js.map +1 -0
  143. package/dist/server/domains/sso.d.ts +409 -0
  144. package/dist/server/domains/sso.d.ts.map +1 -0
  145. package/dist/server/domains/sso.js +884 -0
  146. package/dist/server/domains/sso.js.map +1 -0
  147. package/dist/server/enterpriseValidators.d.ts +1 -0
  148. package/dist/server/enterpriseValidators.js +60 -0
  149. package/dist/server/enterpriseValidators.js.map +1 -0
  150. package/dist/server/factory.d.ts +136 -0
  151. package/dist/server/factory.d.ts.map +1 -0
  152. package/dist/server/factory.js +1134 -0
  153. package/dist/server/factory.js.map +1 -0
  154. package/dist/server/fx.d.ts +1 -16
  155. package/dist/server/fx.d.ts.map +1 -1
  156. package/dist/server/fx.js +1 -0
  157. package/dist/server/fx.js.map +1 -1
  158. package/dist/server/http.d.ts +59 -0
  159. package/dist/server/http.d.ts.map +1 -0
  160. package/dist/server/http.js +287 -0
  161. package/dist/server/http.js.map +1 -0
  162. package/dist/server/identity.d.ts +1 -0
  163. package/dist/server/identity.js +13 -0
  164. package/dist/server/identity.js.map +1 -0
  165. package/dist/server/index.d.ts +468 -1
  166. package/dist/server/index.d.ts.map +1 -1
  167. package/dist/server/index.js +530 -36
  168. package/dist/server/index.js.map +1 -1
  169. package/dist/server/keys.d.ts +1 -57
  170. package/dist/server/keys.js +4 -0
  171. package/dist/server/keys.js.map +1 -1
  172. package/dist/server/mutations/account.d.ts +7 -7
  173. package/dist/server/mutations/account.d.ts.map +1 -1
  174. package/dist/server/mutations/code.d.ts +13 -13
  175. package/dist/server/mutations/code.d.ts.map +1 -1
  176. package/dist/server/mutations/index.d.ts +107 -107
  177. package/dist/server/mutations/index.d.ts.map +1 -1
  178. package/dist/server/mutations/index.js +1 -1
  179. package/dist/server/mutations/index.js.map +1 -1
  180. package/dist/server/mutations/invalidate.d.ts +5 -5
  181. package/dist/server/mutations/invalidate.d.ts.map +1 -1
  182. package/dist/server/mutations/oauth.d.ts +10 -10
  183. package/dist/server/mutations/oauth.d.ts.map +1 -1
  184. package/dist/server/mutations/oauth.js +9 -6
  185. package/dist/server/mutations/oauth.js.map +1 -1
  186. package/dist/server/mutations/refresh.d.ts +4 -4
  187. package/dist/server/mutations/register.d.ts +12 -12
  188. package/dist/server/mutations/register.d.ts.map +1 -1
  189. package/dist/server/mutations/retrieve.d.ts +7 -7
  190. package/dist/server/mutations/signature.d.ts +5 -5
  191. package/dist/server/mutations/signin.d.ts +6 -6
  192. package/dist/server/mutations/signin.d.ts.map +1 -1
  193. package/dist/server/mutations/signout.d.ts +1 -1
  194. package/dist/server/mutations/store.d.ts +3 -2
  195. package/dist/server/mutations/store.d.ts.map +1 -1
  196. package/dist/server/mutations/store.js +6 -3
  197. package/dist/server/mutations/store.js.map +1 -1
  198. package/dist/server/mutations/verifier.d.ts +1 -1
  199. package/dist/server/mutations/verify.d.ts +11 -11
  200. package/dist/server/mutations/verify.d.ts.map +1 -1
  201. package/dist/server/oauth.d.ts +1 -59
  202. package/dist/server/oauth.js +3 -0
  203. package/dist/server/oauth.js.map +1 -1
  204. package/dist/server/passkey.d.ts.map +1 -1
  205. package/dist/server/passkey.js +3 -2
  206. package/dist/server/passkey.js.map +1 -1
  207. package/dist/server/provider.d.ts +1 -14
  208. package/dist/server/provider.d.ts.map +1 -1
  209. package/dist/server/provider.js +2 -0
  210. package/dist/server/provider.js.map +1 -1
  211. package/dist/server/providers.js +10 -0
  212. package/dist/server/providers.js.map +1 -1
  213. package/dist/server/ratelimit.d.ts +1 -22
  214. package/dist/server/ratelimit.js +3 -0
  215. package/dist/server/ratelimit.js.map +1 -1
  216. package/dist/server/redirects.d.ts +1 -10
  217. package/dist/server/redirects.js +2 -0
  218. package/dist/server/redirects.js.map +1 -1
  219. package/dist/server/refresh.d.ts +1 -37
  220. package/dist/server/refresh.js +5 -0
  221. package/dist/server/refresh.js.map +1 -1
  222. package/dist/server/sessions.d.ts +1 -28
  223. package/dist/server/sessions.js +5 -0
  224. package/dist/server/sessions.js.map +1 -1
  225. package/dist/server/signin.d.ts +1 -55
  226. package/dist/server/signin.js +2 -1
  227. package/dist/server/signin.js.map +1 -1
  228. package/dist/server/sso.d.ts +1 -348
  229. package/dist/server/sso.js +165 -18
  230. package/dist/server/sso.js.map +1 -1
  231. package/dist/server/templates.d.ts +1 -21
  232. package/dist/server/templates.js +1 -0
  233. package/dist/server/templates.js.map +1 -1
  234. package/dist/server/tokens.d.ts +1 -11
  235. package/dist/server/tokens.js +1 -0
  236. package/dist/server/tokens.js.map +1 -1
  237. package/dist/server/totp.d.ts +1 -23
  238. package/dist/server/totp.js +4 -2
  239. package/dist/server/totp.js.map +1 -1
  240. package/dist/server/types.d.ts +114 -77
  241. package/dist/server/types.d.ts.map +1 -1
  242. package/dist/server/types.js.map +1 -1
  243. package/dist/server/users.d.ts +1 -31
  244. package/dist/server/users.js +1 -0
  245. package/dist/server/users.js.map +1 -1
  246. package/dist/server/utils.d.ts +1 -27
  247. package/dist/server/utils.js +44 -2
  248. package/dist/server/utils.js.map +1 -1
  249. package/dist/server/version.d.ts +1 -1
  250. package/dist/server/version.js +1 -1
  251. package/dist/server/version.js.map +1 -1
  252. package/package.json +4 -5
  253. package/src/cli/bin.ts +5 -0
  254. package/src/cli/index.ts +22 -9
  255. package/src/cli/keys.ts +3 -0
  256. package/src/client/index.ts +36 -37
  257. package/src/component/_generated/api.ts +14 -0
  258. package/src/component/_generated/component.ts +2106 -9
  259. package/src/component/index.ts +3 -1
  260. package/src/component/model.ts +441 -0
  261. package/src/component/public/enterprise.ts +753 -0
  262. package/src/component/public/factors.ts +332 -0
  263. package/src/component/public/groups.ts +932 -0
  264. package/src/component/public/identity.ts +566 -0
  265. package/src/component/public/keys.ts +209 -0
  266. package/src/component/public/shared.ts +119 -0
  267. package/src/component/public.ts +5 -2965
  268. package/src/component/schema.ts +68 -63
  269. package/src/providers/sso.ts +1 -1
  270. package/src/server/auth.ts +413 -18
  271. package/src/server/cookies.ts +3 -0
  272. package/src/server/db.ts +3 -0
  273. package/src/server/device.ts +3 -1
  274. package/src/server/domains/core.ts +1071 -0
  275. package/src/server/domains/sso.ts +1749 -0
  276. package/src/server/enterpriseValidators.ts +93 -0
  277. package/src/server/factory.ts +2181 -0
  278. package/src/server/fx.ts +1 -0
  279. package/src/server/http.ts +529 -0
  280. package/src/server/identity.ts +18 -0
  281. package/src/server/index.ts +806 -40
  282. package/src/server/keys.ts +4 -0
  283. package/src/server/mutations/index.ts +1 -1
  284. package/src/server/mutations/oauth.ts +36 -8
  285. package/src/server/mutations/store.ts +6 -3
  286. package/src/server/oauth.ts +6 -0
  287. package/src/server/passkey.ts +3 -2
  288. package/src/server/provider.ts +2 -0
  289. package/src/server/providers.ts +20 -0
  290. package/src/server/ratelimit.ts +3 -0
  291. package/src/server/redirects.ts +2 -0
  292. package/src/server/refresh.ts +5 -0
  293. package/src/server/sessions.ts +5 -0
  294. package/src/server/signin.ts +1 -0
  295. package/src/server/sso.ts +259 -17
  296. package/src/server/templates.ts +1 -0
  297. package/src/server/tokens.ts +1 -0
  298. package/src/server/totp.ts +4 -2
  299. package/src/server/types.ts +178 -83
  300. package/src/server/users.ts +1 -0
  301. package/src/server/utils.ts +71 -1
  302. package/src/server/version.ts +1 -1
  303. package/dist/component/public.js.map +0 -1
  304. package/dist/component/server/implementation.d.ts +0 -1264
  305. package/dist/component/server/implementation.d.ts.map +0 -1
  306. package/dist/component/server/implementation.js +0 -2365
  307. package/dist/component/server/implementation.js.map +0 -1
  308. package/dist/server/cookies.d.ts.map +0 -1
  309. package/dist/server/db.d.ts.map +0 -1
  310. package/dist/server/device.d.ts.map +0 -1
  311. package/dist/server/implementation.d.ts +0 -1264
  312. package/dist/server/implementation.d.ts.map +0 -1
  313. package/dist/server/implementation.js +0 -2365
  314. package/dist/server/implementation.js.map +0 -1
  315. package/dist/server/keys.d.ts.map +0 -1
  316. package/dist/server/oauth.d.ts.map +0 -1
  317. package/dist/server/ratelimit.d.ts.map +0 -1
  318. package/dist/server/redirects.d.ts.map +0 -1
  319. package/dist/server/refresh.d.ts.map +0 -1
  320. package/dist/server/sessions.d.ts.map +0 -1
  321. package/dist/server/signin.d.ts.map +0 -1
  322. package/dist/server/sso.d.ts.map +0 -1
  323. package/dist/server/templates.d.ts.map +0 -1
  324. package/dist/server/tokens.d.ts.map +0 -1
  325. package/dist/server/totp.d.ts.map +0 -1
  326. package/dist/server/users.d.ts.map +0 -1
  327. package/dist/server/utils.d.ts.map +0 -1
  328. package/src/server/implementation.ts +0 -5336
@@ -0,0 +1,753 @@
1
+ import {
2
+ ConvexError,
3
+ mutation,
4
+ query,
5
+ v,
6
+ vAuditActorType,
7
+ vAuditStatus,
8
+ vEnterpriseAuditEventDoc,
9
+ vEnterpriseDoc,
10
+ vEnterpriseDomainDoc,
11
+ vEnterpriseDomainVerificationDoc,
12
+ vEnterprisePolicy,
13
+ vEnterpriseScimConfigDoc,
14
+ vEnterpriseScimIdentityDoc,
15
+ vEnterpriseSecretDoc,
16
+ vEnterpriseSecretKind,
17
+ vEnterpriseStatus,
18
+ vEnterpriseWebhookDeliveryDoc,
19
+ vEnterpriseWebhookEndpointDoc,
20
+ vPaginated,
21
+ vScimResourceType,
22
+ vScimStatus,
23
+ vWebhookEndpointStatus,
24
+ } from "./shared";
25
+
26
+ // ============================================================================
27
+ // Enterprise
28
+ // ============================================================================
29
+
30
+ /** Create an enterprise record attached to a root group. */
31
+ export const enterpriseCreate = mutation({
32
+ args: {
33
+ groupId: v.id("Group"),
34
+ slug: v.optional(v.string()),
35
+ name: v.optional(v.string()),
36
+ status: v.optional(vEnterpriseStatus),
37
+ policy: v.optional(vEnterprisePolicy),
38
+ config: v.optional(v.any()),
39
+ extend: v.optional(v.any()),
40
+ },
41
+ returns: v.id("Enterprise"),
42
+ handler: async (ctx, args) => {
43
+ const existing = await ctx.db
44
+ .query("Enterprise")
45
+ .withIndex("group_id", (idx) => idx.eq("groupId", args.groupId))
46
+ .first();
47
+ if (existing) {
48
+ throw new ConvexError({
49
+ code: "ENTERPRISE_ALREADY_EXISTS",
50
+ message: "An enterprise record already exists for this group.",
51
+ });
52
+ }
53
+ return await ctx.db.insert("Enterprise", {
54
+ ...args,
55
+ status: args.status ?? "draft",
56
+ });
57
+ },
58
+ });
59
+
60
+ /** Retrieve an enterprise record by ID. */
61
+ export const enterpriseGet = query({
62
+ args: { enterpriseId: v.id("Enterprise") },
63
+ returns: v.union(vEnterpriseDoc, v.null()),
64
+ handler: async (ctx, { enterpriseId }) => {
65
+ return await ctx.db.get("Enterprise", enterpriseId);
66
+ },
67
+ });
68
+
69
+ /** Retrieve an enterprise record by group ID. */
70
+ export const enterpriseGetByGroup = query({
71
+ args: { groupId: v.id("Group") },
72
+ returns: v.union(vEnterpriseDoc, v.null()),
73
+ handler: async (ctx, { groupId }) => {
74
+ return await ctx.db
75
+ .query("Enterprise")
76
+ .withIndex("group_id", (idx) => idx.eq("groupId", groupId))
77
+ .first();
78
+ },
79
+ });
80
+
81
+ /** Retrieve an enterprise record by a linked domain. */
82
+ export const enterpriseGetByDomain = query({
83
+ args: { domain: v.string() },
84
+ returns: v.union(
85
+ v.object({
86
+ enterprise: vEnterpriseDoc,
87
+ domain: vEnterpriseDomainDoc,
88
+ }),
89
+ v.null(),
90
+ ),
91
+ handler: async (ctx, { domain }) => {
92
+ const domainRow = await ctx.db
93
+ .query("EnterpriseDomain")
94
+ .withIndex("domain", (idx) => idx.eq("domain", domain))
95
+ .first();
96
+ if (!domainRow) {
97
+ return null;
98
+ }
99
+ const enterprise = await ctx.db.get("Enterprise", domainRow.enterpriseId);
100
+ if (!enterprise) {
101
+ return null;
102
+ }
103
+ return { enterprise, domain: domainRow };
104
+ },
105
+ });
106
+
107
+ /** List enterprises with lightweight filtering and cursor pagination. */
108
+ export const enterpriseList = query({
109
+ args: {
110
+ where: v.optional(
111
+ v.object({
112
+ groupId: v.optional(v.id("Group")),
113
+ slug: v.optional(v.string()),
114
+ status: v.optional(vEnterpriseStatus),
115
+ }),
116
+ ),
117
+ limit: v.optional(v.number()),
118
+ cursor: v.optional(v.union(v.string(), v.null())),
119
+ orderBy: v.optional(
120
+ v.union(
121
+ v.literal("_creationTime"),
122
+ v.literal("name"),
123
+ v.literal("slug"),
124
+ v.literal("status"),
125
+ ),
126
+ ),
127
+ order: v.optional(v.union(v.literal("asc"), v.literal("desc"))),
128
+ },
129
+ returns: vPaginated(vEnterpriseDoc),
130
+ handler: async (ctx, args) => {
131
+ const where = args.where ?? {};
132
+ const limit = Math.min(Math.max(args.limit ?? 50, 1), 100);
133
+ const order = args.order ?? "desc";
134
+
135
+ let q;
136
+ if (where.groupId !== undefined) {
137
+ q = ctx.db
138
+ .query("Enterprise")
139
+ .withIndex("group_id", (idx) => idx.eq("groupId", where.groupId!));
140
+ } else if (where.slug !== undefined) {
141
+ q = ctx.db
142
+ .query("Enterprise")
143
+ .withIndex("slug", (idx) => idx.eq("slug", where.slug!));
144
+ } else if (where.status !== undefined) {
145
+ q = ctx.db
146
+ .query("Enterprise")
147
+ .withIndex("status", (idx) => idx.eq("status", where.status!));
148
+ } else {
149
+ q = ctx.db.query("Enterprise");
150
+ }
151
+
152
+ if (where.groupId !== undefined && where.slug !== undefined) {
153
+ q = q.filter((f) => f.eq(f.field("slug"), where.slug!));
154
+ }
155
+ if (where.status !== undefined && where.groupId === undefined) {
156
+ // already handled by index in the dedicated branch
157
+ } else if (where.status !== undefined) {
158
+ q = q.filter((f) => f.eq(f.field("status"), where.status!));
159
+ }
160
+
161
+ q = q.order(order);
162
+ const all = await q.collect();
163
+ let startIdx = 0;
164
+ if (args.cursor) {
165
+ const cursorIdx = all.findIndex((doc) => doc._id === args.cursor);
166
+ if (cursorIdx !== -1) {
167
+ startIdx = cursorIdx + 1;
168
+ }
169
+ }
170
+ const page = all.slice(startIdx, startIdx + limit + 1);
171
+ const hasMore = page.length > limit;
172
+ const items = hasMore ? page.slice(0, limit) : page;
173
+ const nextCursor = hasMore ? items[items.length - 1]._id : null;
174
+ return { items, nextCursor };
175
+ },
176
+ });
177
+
178
+ /** Patch an enterprise record. */
179
+ export const enterpriseUpdate = mutation({
180
+ args: { enterpriseId: v.id("Enterprise"), data: v.any() },
181
+ returns: v.null(),
182
+ handler: async (ctx, { enterpriseId, data }) => {
183
+ await ctx.db.patch(enterpriseId, data);
184
+ return null;
185
+ },
186
+ });
187
+
188
+ /** Delete an enterprise record. */
189
+ export const enterpriseDelete = mutation({
190
+ args: { enterpriseId: v.id("Enterprise") },
191
+ returns: v.null(),
192
+ handler: async (ctx, { enterpriseId }) => {
193
+ const domains = await ctx.db
194
+ .query("EnterpriseDomain")
195
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
196
+ .collect();
197
+ for (const domain of domains) {
198
+ const verification = await ctx.db
199
+ .query("EnterpriseDomainVerification")
200
+ .withIndex("domain_id", (idx) => idx.eq("domainId", domain._id))
201
+ .first();
202
+ if (verification) {
203
+ await ctx.db.delete(verification._id);
204
+ }
205
+ await ctx.db.delete(domain._id);
206
+ }
207
+ const secrets = await ctx.db
208
+ .query("EnterpriseSecret")
209
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
210
+ .collect();
211
+ for (const secret of secrets) {
212
+ await ctx.db.delete(secret._id);
213
+ }
214
+ await ctx.db.delete(enterpriseId);
215
+ return null;
216
+ },
217
+ });
218
+
219
+ /** Link a domain to an enterprise record. */
220
+ export const enterpriseDomainAdd = mutation({
221
+ args: {
222
+ enterpriseId: v.id("Enterprise"),
223
+ groupId: v.id("Group"),
224
+ domain: v.string(),
225
+ isPrimary: v.optional(v.boolean()),
226
+ },
227
+ returns: v.id("EnterpriseDomain"),
228
+ handler: async (ctx, args) => {
229
+ const existingByDomain = await ctx.db
230
+ .query("EnterpriseDomain")
231
+ .withIndex("domain", (idx) => idx.eq("domain", args.domain))
232
+ .first();
233
+ if (
234
+ existingByDomain &&
235
+ existingByDomain.enterpriseId !== args.enterpriseId
236
+ ) {
237
+ throw new ConvexError({
238
+ code: "ENTERPRISE_DOMAIN_TAKEN",
239
+ message: "That domain is already attached to another enterprise.",
240
+ });
241
+ }
242
+
243
+ const existingForEnterprise = await ctx.db
244
+ .query("EnterpriseDomain")
245
+ .withIndex("enterprise_id", (idx) =>
246
+ idx.eq("enterpriseId", args.enterpriseId),
247
+ )
248
+ .collect();
249
+
250
+ for (const row of existingForEnterprise) {
251
+ if (row.domain === args.domain) {
252
+ await ctx.db.patch(row._id, {
253
+ isPrimary: args.isPrimary ?? row.isPrimary,
254
+ });
255
+ return row._id;
256
+ }
257
+ }
258
+
259
+ if (args.isPrimary === true) {
260
+ for (const row of existingForEnterprise) {
261
+ if (row.isPrimary) {
262
+ await ctx.db.patch(row._id, { isPrimary: false });
263
+ }
264
+ }
265
+ }
266
+
267
+ return await ctx.db.insert("EnterpriseDomain", {
268
+ ...args,
269
+ isPrimary: args.isPrimary ?? existingForEnterprise.length === 0,
270
+ });
271
+ },
272
+ });
273
+
274
+ /** List domains linked to an enterprise. */
275
+ export const enterpriseDomainList = query({
276
+ args: { enterpriseId: v.id("Enterprise") },
277
+ returns: v.array(vEnterpriseDomainDoc),
278
+ handler: async (ctx, { enterpriseId }) => {
279
+ return await ctx.db
280
+ .query("EnterpriseDomain")
281
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
282
+ .collect();
283
+ },
284
+ });
285
+
286
+ /** Remove a linked enterprise domain. */
287
+ export const enterpriseDomainDelete = mutation({
288
+ args: { domainId: v.id("EnterpriseDomain") },
289
+ returns: v.null(),
290
+ handler: async (ctx, { domainId }) => {
291
+ const verification = await ctx.db
292
+ .query("EnterpriseDomainVerification")
293
+ .withIndex("domain_id", (idx) => idx.eq("domainId", domainId))
294
+ .first();
295
+ if (verification) {
296
+ await ctx.db.delete(verification._id);
297
+ }
298
+ await ctx.db.delete(domainId);
299
+ return null;
300
+ },
301
+ });
302
+
303
+ export const enterpriseDomainVerificationGet = query({
304
+ args: { domainId: v.id("EnterpriseDomain") },
305
+ returns: v.union(vEnterpriseDomainVerificationDoc, v.null()),
306
+ handler: async (ctx, { domainId }) => {
307
+ return await ctx.db
308
+ .query("EnterpriseDomainVerification")
309
+ .withIndex("domain_id", (idx) => idx.eq("domainId", domainId))
310
+ .first();
311
+ },
312
+ });
313
+
314
+ export const enterpriseDomainVerificationUpsert = mutation({
315
+ args: {
316
+ enterpriseId: v.id("Enterprise"),
317
+ groupId: v.id("Group"),
318
+ domainId: v.id("EnterpriseDomain"),
319
+ domain: v.string(),
320
+ recordName: v.string(),
321
+ token: v.string(),
322
+ tokenHash: v.string(),
323
+ requestedAt: v.number(),
324
+ expiresAt: v.number(),
325
+ },
326
+ returns: v.id("EnterpriseDomainVerification"),
327
+ handler: async (ctx, args) => {
328
+ const existing = await ctx.db
329
+ .query("EnterpriseDomainVerification")
330
+ .withIndex("domain_id", (idx) => idx.eq("domainId", args.domainId))
331
+ .first();
332
+ if (existing) {
333
+ await ctx.db.patch(existing._id, args);
334
+ return existing._id;
335
+ }
336
+ return await ctx.db.insert("EnterpriseDomainVerification", args);
337
+ },
338
+ });
339
+
340
+ export const enterpriseDomainVerificationDelete = mutation({
341
+ args: { domainId: v.id("EnterpriseDomain") },
342
+ returns: v.null(),
343
+ handler: async (ctx, { domainId }) => {
344
+ const existing = await ctx.db
345
+ .query("EnterpriseDomainVerification")
346
+ .withIndex("domain_id", (idx) => idx.eq("domainId", domainId))
347
+ .first();
348
+ if (existing) {
349
+ await ctx.db.delete(existing._id);
350
+ }
351
+ return null;
352
+ },
353
+ });
354
+
355
+ export const enterpriseDomainVerify = mutation({
356
+ args: {
357
+ domainId: v.id("EnterpriseDomain"),
358
+ verifiedAt: v.number(),
359
+ },
360
+ returns: vEnterpriseDomainDoc,
361
+ handler: async (ctx, { domainId, verifiedAt }) => {
362
+ await ctx.db.patch(domainId, { verifiedAt });
363
+ const domain = await ctx.db.get("EnterpriseDomain", domainId);
364
+ if (!domain) {
365
+ throw new ConvexError({
366
+ code: "INVALID_PARAMETERS",
367
+ message: "Enterprise domain not found.",
368
+ });
369
+ }
370
+ const verification = await ctx.db
371
+ .query("EnterpriseDomainVerification")
372
+ .withIndex("domain_id", (idx) => idx.eq("domainId", domainId))
373
+ .first();
374
+ if (verification) {
375
+ await ctx.db.delete(verification._id);
376
+ }
377
+ return domain;
378
+ },
379
+ });
380
+
381
+ export const enterpriseSecretUpsert = mutation({
382
+ args: {
383
+ enterpriseId: v.id("Enterprise"),
384
+ groupId: v.id("Group"),
385
+ kind: vEnterpriseSecretKind,
386
+ ciphertext: v.string(),
387
+ updatedAt: v.number(),
388
+ },
389
+ returns: v.id("EnterpriseSecret"),
390
+ handler: async (ctx, args) => {
391
+ const existing = await ctx.db
392
+ .query("EnterpriseSecret")
393
+ .withIndex("enterprise_id_kind", (idx) =>
394
+ idx.eq("enterpriseId", args.enterpriseId).eq("kind", args.kind),
395
+ )
396
+ .first();
397
+ if (existing) {
398
+ await ctx.db.patch(existing._id, args);
399
+ return existing._id;
400
+ }
401
+ return await ctx.db.insert("EnterpriseSecret", args);
402
+ },
403
+ });
404
+
405
+ export const enterpriseSecretGet = query({
406
+ args: {
407
+ enterpriseId: v.id("Enterprise"),
408
+ kind: vEnterpriseSecretKind,
409
+ },
410
+ returns: v.union(vEnterpriseSecretDoc, v.null()),
411
+ handler: async (ctx, { enterpriseId, kind }) => {
412
+ return await ctx.db
413
+ .query("EnterpriseSecret")
414
+ .withIndex("enterprise_id_kind", (idx) =>
415
+ idx.eq("enterpriseId", enterpriseId).eq("kind", kind),
416
+ )
417
+ .first();
418
+ },
419
+ });
420
+
421
+ export const enterpriseSecretDelete = mutation({
422
+ args: {
423
+ enterpriseId: v.id("Enterprise"),
424
+ kind: vEnterpriseSecretKind,
425
+ },
426
+ returns: v.null(),
427
+ handler: async (ctx, { enterpriseId, kind }) => {
428
+ const existing = await ctx.db
429
+ .query("EnterpriseSecret")
430
+ .withIndex("enterprise_id_kind", (idx) =>
431
+ idx.eq("enterpriseId", enterpriseId).eq("kind", kind),
432
+ )
433
+ .first();
434
+ if (existing) {
435
+ await ctx.db.delete(existing._id);
436
+ }
437
+ return null;
438
+ },
439
+ });
440
+
441
+ /** Create or rotate SCIM configuration for an enterprise. */
442
+ export const enterpriseScimConfigUpsert = mutation({
443
+ args: {
444
+ enterpriseId: v.id("Enterprise"),
445
+ groupId: v.id("Group"),
446
+ status: vScimStatus,
447
+ basePath: v.string(),
448
+ tokenHash: v.string(),
449
+ lastRotatedAt: v.optional(v.number()),
450
+ extend: v.optional(v.any()),
451
+ },
452
+ returns: v.id("EnterpriseScimConfig"),
453
+ handler: async (ctx, args) => {
454
+ const existing = await ctx.db
455
+ .query("EnterpriseScimConfig")
456
+ .withIndex("enterprise_id", (idx) =>
457
+ idx.eq("enterpriseId", args.enterpriseId),
458
+ )
459
+ .first();
460
+ if (existing) {
461
+ await ctx.db.patch(existing._id, args);
462
+ return existing._id;
463
+ }
464
+ return await ctx.db.insert("EnterpriseScimConfig", args);
465
+ },
466
+ });
467
+
468
+ export const enterpriseScimConfigGetByEnterprise = query({
469
+ args: { enterpriseId: v.id("Enterprise") },
470
+ returns: v.union(vEnterpriseScimConfigDoc, v.null()),
471
+ handler: async (ctx, { enterpriseId }) => {
472
+ return await ctx.db
473
+ .query("EnterpriseScimConfig")
474
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
475
+ .first();
476
+ },
477
+ });
478
+
479
+ export const enterpriseScimConfigGetByTokenHash = query({
480
+ args: { tokenHash: v.string() },
481
+ returns: v.union(vEnterpriseScimConfigDoc, v.null()),
482
+ handler: async (ctx, { tokenHash }) => {
483
+ return await ctx.db
484
+ .query("EnterpriseScimConfig")
485
+ .withIndex("token_hash", (idx) => idx.eq("tokenHash", tokenHash))
486
+ .first();
487
+ },
488
+ });
489
+
490
+ export const enterpriseScimIdentityGet = query({
491
+ args: {
492
+ enterpriseId: v.id("Enterprise"),
493
+ resourceType: vScimResourceType,
494
+ externalId: v.string(),
495
+ },
496
+ returns: v.union(vEnterpriseScimIdentityDoc, v.null()),
497
+ handler: async (ctx, args) => {
498
+ return await ctx.db
499
+ .query("EnterpriseScimIdentity")
500
+ .withIndex("enterprise_id_resource_type_external_id", (idx) =>
501
+ idx
502
+ .eq("enterpriseId", args.enterpriseId)
503
+ .eq("resourceType", args.resourceType)
504
+ .eq("externalId", args.externalId),
505
+ )
506
+ .first();
507
+ },
508
+ });
509
+
510
+ export const enterpriseScimIdentityGetByUser = query({
511
+ args: { userId: v.id("User") },
512
+ returns: v.union(vEnterpriseScimIdentityDoc, v.null()),
513
+ handler: async (ctx, { userId }) => {
514
+ return await ctx.db
515
+ .query("EnterpriseScimIdentity")
516
+ .withIndex("user_id", (idx) => idx.eq("userId", userId))
517
+ .first();
518
+ },
519
+ });
520
+
521
+ export const enterpriseScimIdentityGetByEnterpriseAndUser = query({
522
+ args: {
523
+ enterpriseId: v.id("Enterprise"),
524
+ userId: v.id("User"),
525
+ },
526
+ returns: v.union(vEnterpriseScimIdentityDoc, v.null()),
527
+ handler: async (ctx, { enterpriseId, userId }) => {
528
+ return await ctx.db
529
+ .query("EnterpriseScimIdentity")
530
+ .withIndex("enterprise_id_user_id", (idx) =>
531
+ idx.eq("enterpriseId", enterpriseId).eq("userId", userId),
532
+ )
533
+ .first();
534
+ },
535
+ });
536
+
537
+ export const enterpriseScimIdentityGetByMappedGroup = query({
538
+ args: { mappedGroupId: v.id("Group") },
539
+ returns: v.union(vEnterpriseScimIdentityDoc, v.null()),
540
+ handler: async (ctx, { mappedGroupId }) => {
541
+ return await ctx.db
542
+ .query("EnterpriseScimIdentity")
543
+ .withIndex("mapped_group_id", (idx) =>
544
+ idx.eq("mappedGroupId", mappedGroupId),
545
+ )
546
+ .first();
547
+ },
548
+ });
549
+
550
+ export const enterpriseScimIdentityListByEnterprise = query({
551
+ args: { enterpriseId: v.id("Enterprise") },
552
+ returns: v.array(vEnterpriseScimIdentityDoc),
553
+ handler: async (ctx, { enterpriseId }) => {
554
+ return await ctx.db
555
+ .query("EnterpriseScimIdentity")
556
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
557
+ .collect();
558
+ },
559
+ });
560
+
561
+ export const enterpriseScimIdentityUpsert = mutation({
562
+ args: {
563
+ enterpriseId: v.id("Enterprise"),
564
+ groupId: v.id("Group"),
565
+ resourceType: vScimResourceType,
566
+ externalId: v.string(),
567
+ userId: v.optional(v.id("User")),
568
+ mappedGroupId: v.optional(v.id("Group")),
569
+ lastProvisionedAt: v.optional(v.number()),
570
+ active: v.optional(v.boolean()),
571
+ raw: v.optional(v.any()),
572
+ },
573
+ returns: v.id("EnterpriseScimIdentity"),
574
+ handler: async (ctx, args) => {
575
+ const existing = await ctx.db
576
+ .query("EnterpriseScimIdentity")
577
+ .withIndex("enterprise_id_resource_type_external_id", (idx) =>
578
+ idx
579
+ .eq("enterpriseId", args.enterpriseId)
580
+ .eq("resourceType", args.resourceType)
581
+ .eq("externalId", args.externalId),
582
+ )
583
+ .first();
584
+ if (existing) {
585
+ await ctx.db.patch(existing._id, args);
586
+ return existing._id;
587
+ }
588
+ return await ctx.db.insert("EnterpriseScimIdentity", args);
589
+ },
590
+ });
591
+
592
+ export const enterpriseScimIdentityDelete = mutation({
593
+ args: { identityId: v.id("EnterpriseScimIdentity") },
594
+ returns: v.null(),
595
+ handler: async (ctx, { identityId }) => {
596
+ await ctx.db.delete(identityId);
597
+ return null;
598
+ },
599
+ });
600
+
601
+ export const enterpriseAuditEventCreate = mutation({
602
+ args: {
603
+ enterpriseId: v.id("Enterprise"),
604
+ groupId: v.id("Group"),
605
+ eventType: v.string(),
606
+ actorType: vAuditActorType,
607
+ actorId: v.optional(v.string()),
608
+ subjectType: v.string(),
609
+ subjectId: v.optional(v.string()),
610
+ status: vAuditStatus,
611
+ occurredAt: v.number(),
612
+ requestId: v.optional(v.string()),
613
+ ip: v.optional(v.string()),
614
+ metadata: v.optional(v.any()),
615
+ },
616
+ returns: v.id("EnterpriseAuditEvent"),
617
+ handler: async (ctx, args) => {
618
+ return await ctx.db.insert("EnterpriseAuditEvent", args);
619
+ },
620
+ });
621
+
622
+ export const enterpriseAuditEventList = query({
623
+ args: {
624
+ enterpriseId: v.optional(v.id("Enterprise")),
625
+ groupId: v.optional(v.id("Group")),
626
+ limit: v.optional(v.number()),
627
+ },
628
+ returns: v.array(vEnterpriseAuditEventDoc),
629
+ handler: async (ctx, args) => {
630
+ const limit = Math.min(Math.max(args.limit ?? 50, 1), 100);
631
+ if (args.enterpriseId !== undefined) {
632
+ return await ctx.db
633
+ .query("EnterpriseAuditEvent")
634
+ .withIndex("enterprise_id_occurred_at", (idx) =>
635
+ idx.eq("enterpriseId", args.enterpriseId!),
636
+ )
637
+ .order("desc")
638
+ .take(limit);
639
+ }
640
+ if (args.groupId !== undefined) {
641
+ return await ctx.db
642
+ .query("EnterpriseAuditEvent")
643
+ .withIndex("group_id_occurred_at", (idx) =>
644
+ idx.eq("groupId", args.groupId!),
645
+ )
646
+ .order("desc")
647
+ .take(limit);
648
+ }
649
+ return await ctx.db.query("EnterpriseAuditEvent").order("desc").take(limit);
650
+ },
651
+ });
652
+
653
+ export const enterpriseWebhookEndpointCreate = mutation({
654
+ args: {
655
+ enterpriseId: v.id("Enterprise"),
656
+ groupId: v.id("Group"),
657
+ url: v.string(),
658
+ status: v.optional(vWebhookEndpointStatus),
659
+ secretHash: v.string(),
660
+ subscriptions: v.array(v.string()),
661
+ createdByUserId: v.optional(v.id("User")),
662
+ extend: v.optional(v.any()),
663
+ },
664
+ returns: v.id("EnterpriseWebhookEndpoint"),
665
+ handler: async (ctx, args) => {
666
+ return await ctx.db.insert("EnterpriseWebhookEndpoint", {
667
+ ...args,
668
+ status: args.status ?? "active",
669
+ failureCount: 0,
670
+ });
671
+ },
672
+ });
673
+
674
+ export const enterpriseWebhookEndpointList = query({
675
+ args: { enterpriseId: v.id("Enterprise") },
676
+ returns: v.array(vEnterpriseWebhookEndpointDoc),
677
+ handler: async (ctx, { enterpriseId }) => {
678
+ return await ctx.db
679
+ .query("EnterpriseWebhookEndpoint")
680
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
681
+ .collect();
682
+ },
683
+ });
684
+
685
+ export const enterpriseWebhookEndpointGet = query({
686
+ args: { endpointId: v.id("EnterpriseWebhookEndpoint") },
687
+ returns: v.union(vEnterpriseWebhookEndpointDoc, v.null()),
688
+ handler: async (ctx, { endpointId }) => {
689
+ return await ctx.db.get(endpointId);
690
+ },
691
+ });
692
+
693
+ export const enterpriseWebhookEndpointUpdate = mutation({
694
+ args: { endpointId: v.id("EnterpriseWebhookEndpoint"), data: v.any() },
695
+ returns: v.null(),
696
+ handler: async (ctx, { endpointId, data }) => {
697
+ await ctx.db.patch(endpointId, data);
698
+ return null;
699
+ },
700
+ });
701
+
702
+ export const enterpriseWebhookDeliveryEnqueue = mutation({
703
+ args: {
704
+ enterpriseId: v.id("Enterprise"),
705
+ endpointId: v.id("EnterpriseWebhookEndpoint"),
706
+ auditEventId: v.optional(v.id("EnterpriseAuditEvent")),
707
+ eventType: v.string(),
708
+ payload: v.any(),
709
+ nextAttemptAt: v.number(),
710
+ },
711
+ returns: v.id("EnterpriseWebhookDelivery"),
712
+ handler: async (ctx, args) => {
713
+ return await ctx.db.insert("EnterpriseWebhookDelivery", {
714
+ ...args,
715
+ status: "pending",
716
+ attemptCount: 0,
717
+ });
718
+ },
719
+ });
720
+
721
+ export const enterpriseWebhookDeliveryListReady = query({
722
+ args: { now: v.number(), limit: v.optional(v.number()) },
723
+ returns: v.array(vEnterpriseWebhookDeliveryDoc),
724
+ handler: async (ctx, { now, limit }) => {
725
+ return await ctx.db
726
+ .query("EnterpriseWebhookDelivery")
727
+ .withIndex("status_next_attempt_at", (idx) =>
728
+ idx.eq("status", "pending").lte("nextAttemptAt", now),
729
+ )
730
+ .take(Math.min(Math.max(limit ?? 50, 1), 100));
731
+ },
732
+ });
733
+
734
+ export const enterpriseWebhookDeliveryList = query({
735
+ args: { enterpriseId: v.id("Enterprise"), limit: v.optional(v.number()) },
736
+ returns: v.array(vEnterpriseWebhookDeliveryDoc),
737
+ handler: async (ctx, { enterpriseId, limit }) => {
738
+ return await ctx.db
739
+ .query("EnterpriseWebhookDelivery")
740
+ .withIndex("enterprise_id", (idx) => idx.eq("enterpriseId", enterpriseId))
741
+ .order("desc")
742
+ .take(Math.min(Math.max(limit ?? 50, 1), 100));
743
+ },
744
+ });
745
+
746
+ export const enterpriseWebhookDeliveryPatch = mutation({
747
+ args: { deliveryId: v.id("EnterpriseWebhookDelivery"), data: v.any() },
748
+ returns: v.null(),
749
+ handler: async (ctx, { deliveryId, data }) => {
750
+ await ctx.db.patch(deliveryId, data);
751
+ return null;
752
+ },
753
+ });